From b32449633416ca0a04499e55fc8fcb09516eb303 Mon Sep 17 00:00:00 2001 From: pepaskopec-blip Date: Fri, 9 Oct 2026 20:39:42 +0200 Subject: [PATCH] Move shared Kotlin code to android/shared, remove GTK app and old data packs Co-authored-by: Cursor --- CMakeLists.txt | 91 - .../org/maturita/maturita/AppViewModel.kt | 0 .../src}/org/maturita/maturita/Route.kt | 0 .../org/maturita/maturita/data/Answers.kt | 0 .../org/maturita/maturita/data/Content.kt | 0 .../src}/org/maturita/maturita/data/Json.kt | 0 .../maturita/maturita/data/ProgressStore.kt | 0 .../src}/org/maturita/maturita/data/Theme.kt | 0 .../org/maturita/maturita/ui/Components.kt | 0 .../org/maturita/maturita/ui/Exercises.kt | 0 .../src}/org/maturita/maturita/ui/Icons.kt | 0 .../src}/org/maturita/maturita/ui/Screens.kt | 0 build-windows.bat | 101 - data/cetba-catalog.json | 543 - data/cetba/1984.json | 421 - data/cetba/_schema.example.json | 47 - data/cetba/audience.json | 421 - data/cetba/bajecna-leta.json | 421 - data/cetba/bidnici.json | 421 - data/cetba/bila-nemoc.json | 421 - data/cetba/bylo-nas-pet.json | 421 - data/cetba/cekani-na-godota.json | 410 - data/cetba/ceske-nebe.json | 410 - data/cetba/chram-matky-bozi.json | 421 - data/cetba/dekameron.json | 410 - data/cetba/den-trifidu.json | 421 - data/cetba/denik-anny-frankove.json | 421 - data/cetba/edison.json | 410 - data/cetba/fahrenheit451.json | 421 - data/cetba/farma-zvirat.json | 421 - data/cetba/fuks.json | 474 - data/cetba/gulliverovy-cesty.json | 421 - data/cetba/hamlet.json | 421 - data/cetba/havran.json | 421 - data/cetba/hladove-hry.json | 421 - data/cetba/hlava-xxii.json | 421 - data/cetba/ivan-denisovic.json | 99 - data/cetba/jak-jsem-vyhral-valku.json | 248 - data/cetba/jana-eyrova.json | 99 - data/cetba/jekyll-hyde.json | 421 - data/cetba/jmeno-ruze.json | 99 - data/cetba/kalibuv-zlocin.json | 98 - data/cetba/kniska-karla-kryla.json | 99 - data/cetba/komu-zvoni-hrana.json | 99 - data/cetba/kral-oidipus.json | 99 - data/cetba/krysar.json | 99 - data/cetba/kulicka.json | 99 - data/cetba/kvety-zla.json | 99 - data/cetba/kytice.json | 99 - data/cetba/lakomec.json | 98 - data/cetba/lolita.json | 99 - data/cetba/maj.json | 98 - data/cetba/maly-princ.json | 98 - data/cetba/marysa.json | 98 - data/cetba/modlitba-pro-katerinu.json | 99 - data/cetba/most-kwai.json | 99 - data/cetba/na-ceste.json | 100 - data/cetba/na-zapadni-fronte.json | 100 - data/cetba/navsteva-stare-damy.json | 99 - data/cetba/nebe-nezna-vyvolenych.json | 99 - data/cetba/o-mysich-a-lidech.json | 99 - data/cetba/obraz-doriana-graye.json | 99 - data/cetba/obsluhoval-jsem.json | 99 - data/cetba/oliver-twist.json | 99 - data/cetba/ostre-sledovane-vlaky.json | 99 - data/cetba/pan-much.json | 99 - data/cetba/pan-prstenu.json | 99 - data/cetba/petr-a-lucie.json | 99 - data/cetba/poe-povidky.json | 99 - data/cetba/povidky-z-kapes.json | 334 - data/cetba/promena.json | 98 - data/cetba/pycha-a-predsudek.json | 99 - data/cetba/revizor.json | 99 - data/cetba/romeo-a-julie.json | 99 - data/cetba/romeo-julie-a-tma.json | 249 - data/cetba/rozmarne-leto.json | 399 - data/cetba/rur.json | 99 - data/cetba/ruze-pro-algernon.json | 399 - data/cetba/saturnin.json | 399 - data/cetba/sluha-dvou-panu.json | 399 - data/cetba/smrt-krasnych-srncu.json | 399 - data/cetba/sofiina-volba.json | 399 - data/cetba/stanice-zoo.json | 399 - data/cetba/stare-recke-baje.json | 399 - data/cetba/starec-a-more.json | 421 - data/cetba/svaty-xaverius.json | 421 - data/cetba/svejk.json | 100 - data/cetba/tereza-raquinova.json | 421 - data/cetba/tezka-hodina.json | 421 - data/cetba/tridni-kniha.json | 421 - data/cetba/tyrolske-elegie.json | 421 - data/cetba/valka-s-mloky.json | 421 - data/cetba/velky-cirkus.json | 421 - data/cetba/velky-gatsby.json | 421 - data/cetba/zabijak.json | 421 - data/cetba/zbabelci.json | 421 - data/cetba/zert.json | 421 - data/changelog.txt | 161 - data/macos/Graduately.entitlements | 14 - data/style.css | 1155 - data/windows/maturita.rc | 3 - run-windows.bat | 17 - scripts/bundle-macos.sh | 5 - scripts/extract-android-content.py | 1869 - scripts/gen-english.py | 2541 -- scripts/gen-german.py | 1387 - scripts/gen-it-years.py | 2472 -- scripts/gen-math.py | 2040 -- src/biologie.c | 617 - src/cetba.c | 1836 - src/cetba_book_exercises.inc | 29642 ---------------- src/cetba_book_notes.inc | 3865 -- src/cetba_catalog.inc | 98 - src/changelog.c | 234 - src/chemie.c | 604 - src/czech.c | 167 - src/english.c | 1647 - src/english_i18n.inc | 90 - src/english_lessons.inc | 1907 - src/exercise_common.c | 857 - src/exercise_u1.c | 1360 - src/exercise_u2.c | 1540 - src/exercise_u3.c | 1547 - src/fyz_year1.c | 615 - src/fyz_year2.c | 621 - src/fyz_year3.c | 618 - src/fyz_year4.c | 635 - src/fyzika.c | 720 - src/german_course.c | 234 - src/german_i18n.inc | 60 - src/german_lessons.inc | 1453 - src/globals.c | 83 - src/graduately.h | 1571 - src/hw.c | 3020 -- src/i18n.c | 2640 -- src/icons.c | 638 - src/it_year_pages.c | 2606 -- src/it_years_i18n.inc | 198 - src/lit_year1.c | 614 - src/lit_year2.c | 611 - src/lit_year3.c | 616 - src/lit_year4.c | 631 - src/literatura.c | 947 - src/macos_dock.c | 55 - src/main.c | 800 - src/mat_year0.c | 469 - src/mat_year1.c | 468 - src/mat_year2.c | 468 - src/mat_year3.c | 468 - src/mat_year4.c | 472 - src/matematika.c | 955 - src/math_check.c | 1362 - src/math_i18n.inc | 176 - src/mluvnice.c | 795 - src/navigation.c | 287 - src/net.c | 4003 --- src/obcanka.c | 2116 -- src/obcanka2.c | 1911 - src/obcanka3.c | 1910 - src/obcanka4.c | 1909 - src/priroda.c | 720 - src/progress.c | 705 - src/quizyear.c | 451 - src/roadmap.c | 409 - src/search.c | 800 - src/settings.c | 361 - src/stats.c | 471 - src/subjects.c | 309 - src/theme.c | 440 - src/unitmap.c | 410 - src/update.c | 1127 - src/util.c | 434 - 172 files changed, 124855 deletions(-) delete mode 100644 CMakeLists.txt rename android/{app/src/main/java => shared/src}/org/maturita/maturita/AppViewModel.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/Route.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/data/Answers.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/data/Content.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/data/Json.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/data/ProgressStore.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/data/Theme.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/ui/Components.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/ui/Exercises.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/ui/Icons.kt (100%) rename android/{app/src/main/java => shared/src}/org/maturita/maturita/ui/Screens.kt (100%) delete mode 100644 build-windows.bat delete mode 100644 data/cetba-catalog.json delete mode 100644 data/cetba/1984.json delete mode 100644 data/cetba/_schema.example.json delete mode 100644 data/cetba/audience.json delete mode 100644 data/cetba/bajecna-leta.json delete mode 100644 data/cetba/bidnici.json delete mode 100644 data/cetba/bila-nemoc.json delete mode 100644 data/cetba/bylo-nas-pet.json delete mode 100644 data/cetba/cekani-na-godota.json delete mode 100644 data/cetba/ceske-nebe.json delete mode 100644 data/cetba/chram-matky-bozi.json delete mode 100644 data/cetba/dekameron.json delete mode 100644 data/cetba/den-trifidu.json delete mode 100644 data/cetba/denik-anny-frankove.json delete mode 100644 data/cetba/edison.json delete mode 100644 data/cetba/fahrenheit451.json delete mode 100644 data/cetba/farma-zvirat.json delete mode 100644 data/cetba/fuks.json delete mode 100644 data/cetba/gulliverovy-cesty.json delete mode 100644 data/cetba/hamlet.json delete mode 100644 data/cetba/havran.json delete mode 100644 data/cetba/hladove-hry.json delete mode 100644 data/cetba/hlava-xxii.json delete mode 100644 data/cetba/ivan-denisovic.json delete mode 100644 data/cetba/jak-jsem-vyhral-valku.json delete mode 100644 data/cetba/jana-eyrova.json delete mode 100644 data/cetba/jekyll-hyde.json delete mode 100644 data/cetba/jmeno-ruze.json delete mode 100644 data/cetba/kalibuv-zlocin.json delete mode 100644 data/cetba/kniska-karla-kryla.json delete mode 100644 data/cetba/komu-zvoni-hrana.json delete mode 100644 data/cetba/kral-oidipus.json delete mode 100644 data/cetba/krysar.json delete mode 100644 data/cetba/kulicka.json delete mode 100644 data/cetba/kvety-zla.json delete mode 100644 data/cetba/kytice.json delete mode 100644 data/cetba/lakomec.json delete mode 100644 data/cetba/lolita.json delete mode 100644 data/cetba/maj.json delete mode 100644 data/cetba/maly-princ.json delete mode 100644 data/cetba/marysa.json delete mode 100644 data/cetba/modlitba-pro-katerinu.json delete mode 100644 data/cetba/most-kwai.json delete mode 100644 data/cetba/na-ceste.json delete mode 100644 data/cetba/na-zapadni-fronte.json delete mode 100644 data/cetba/navsteva-stare-damy.json delete mode 100644 data/cetba/nebe-nezna-vyvolenych.json delete mode 100644 data/cetba/o-mysich-a-lidech.json delete mode 100644 data/cetba/obraz-doriana-graye.json delete mode 100644 data/cetba/obsluhoval-jsem.json delete mode 100644 data/cetba/oliver-twist.json delete mode 100644 data/cetba/ostre-sledovane-vlaky.json delete mode 100644 data/cetba/pan-much.json delete mode 100644 data/cetba/pan-prstenu.json delete mode 100644 data/cetba/petr-a-lucie.json delete mode 100644 data/cetba/poe-povidky.json delete mode 100644 data/cetba/povidky-z-kapes.json delete mode 100644 data/cetba/promena.json delete mode 100644 data/cetba/pycha-a-predsudek.json delete mode 100644 data/cetba/revizor.json delete mode 100644 data/cetba/romeo-a-julie.json delete mode 100644 data/cetba/romeo-julie-a-tma.json delete mode 100644 data/cetba/rozmarne-leto.json delete mode 100644 data/cetba/rur.json delete mode 100644 data/cetba/ruze-pro-algernon.json delete mode 100644 data/cetba/saturnin.json delete mode 100644 data/cetba/sluha-dvou-panu.json delete mode 100644 data/cetba/smrt-krasnych-srncu.json delete mode 100644 data/cetba/sofiina-volba.json delete mode 100644 data/cetba/stanice-zoo.json delete mode 100644 data/cetba/stare-recke-baje.json delete mode 100644 data/cetba/starec-a-more.json delete mode 100644 data/cetba/svaty-xaverius.json delete mode 100644 data/cetba/svejk.json delete mode 100644 data/cetba/tereza-raquinova.json delete mode 100644 data/cetba/tezka-hodina.json delete mode 100644 data/cetba/tridni-kniha.json delete mode 100644 data/cetba/tyrolske-elegie.json delete mode 100644 data/cetba/valka-s-mloky.json delete mode 100644 data/cetba/velky-cirkus.json delete mode 100644 data/cetba/velky-gatsby.json delete mode 100644 data/cetba/zabijak.json delete mode 100644 data/cetba/zbabelci.json delete mode 100644 data/cetba/zert.json delete mode 100644 data/changelog.txt delete mode 100644 data/macos/Graduately.entitlements delete mode 100644 data/style.css delete mode 100644 data/windows/maturita.rc delete mode 100644 run-windows.bat delete mode 100755 scripts/bundle-macos.sh delete mode 100644 scripts/extract-android-content.py delete mode 100644 scripts/gen-english.py delete mode 100644 scripts/gen-german.py delete mode 100644 scripts/gen-it-years.py delete mode 100644 scripts/gen-math.py delete mode 100644 src/biologie.c delete mode 100644 src/cetba.c delete mode 100644 src/cetba_book_exercises.inc delete mode 100644 src/cetba_book_notes.inc delete mode 100644 src/cetba_catalog.inc delete mode 100644 src/changelog.c delete mode 100644 src/chemie.c delete mode 100644 src/czech.c delete mode 100644 src/english.c delete mode 100644 src/english_i18n.inc delete mode 100644 src/english_lessons.inc delete mode 100644 src/exercise_common.c delete mode 100644 src/exercise_u1.c delete mode 100644 src/exercise_u2.c delete mode 100644 src/exercise_u3.c delete mode 100644 src/fyz_year1.c delete mode 100644 src/fyz_year2.c delete mode 100644 src/fyz_year3.c delete mode 100644 src/fyz_year4.c delete mode 100644 src/fyzika.c delete mode 100644 src/german_course.c delete mode 100644 src/german_i18n.inc delete mode 100644 src/german_lessons.inc delete mode 100644 src/globals.c delete mode 100644 src/graduately.h delete mode 100644 src/hw.c delete mode 100644 src/i18n.c delete mode 100644 src/icons.c delete mode 100644 src/it_year_pages.c delete mode 100644 src/it_years_i18n.inc delete mode 100644 src/lit_year1.c delete mode 100644 src/lit_year2.c delete mode 100644 src/lit_year3.c delete mode 100644 src/lit_year4.c delete mode 100644 src/literatura.c delete mode 100644 src/macos_dock.c delete mode 100644 src/main.c delete mode 100644 src/mat_year0.c delete mode 100644 src/mat_year1.c delete mode 100644 src/mat_year2.c delete mode 100644 src/mat_year3.c delete mode 100644 src/mat_year4.c delete mode 100644 src/matematika.c delete mode 100644 src/math_check.c delete mode 100644 src/math_i18n.inc delete mode 100644 src/mluvnice.c delete mode 100644 src/navigation.c delete mode 100644 src/net.c delete mode 100644 src/obcanka.c delete mode 100644 src/obcanka2.c delete mode 100644 src/obcanka3.c delete mode 100644 src/obcanka4.c delete mode 100644 src/priroda.c delete mode 100644 src/progress.c delete mode 100644 src/quizyear.c delete mode 100644 src/roadmap.c delete mode 100644 src/search.c delete mode 100644 src/settings.c delete mode 100644 src/stats.c delete mode 100644 src/subjects.c delete mode 100644 src/theme.c delete mode 100644 src/unitmap.c delete mode 100644 src/update.c delete mode 100644 src/util.c diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index e64ef35..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,91 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(graduately C) - -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED ON) - -# GTK4 is found through pkg-config everywhere: Linux/macOS packages, MSYS2, -# vcpkg and the native MSVC (gvsbuild) package all ship .pc files. -if(MSVC) - find_program(PKG_CONFIG_EXECUTABLE - NAMES pkg-config pkg-config.exe pkgconf pkgconf.exe) - if(NOT PKG_CONFIG_EXECUTABLE) - message(FATAL_ERROR - "pkg-config was not found. A native GTK4 install for MSVC " - "(e.g. gvsbuild) provides it; set PKG_CONFIG_PATH to " - "/lib/pkgconfig. See README.md.") - endif() - - execute_process( - COMMAND "${PKG_CONFIG_EXECUTABLE}" --cflags gtk4 --msvc-syntax - OUTPUT_VARIABLE GTK4_CFLAGS_RAW - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE GTK4_CFLAGS_RESULT) - execute_process( - COMMAND "${PKG_CONFIG_EXECUTABLE}" --libs gtk4 --msvc-syntax - OUTPUT_VARIABLE GTK4_LIBS_RAW - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE GTK4_LIBS_RESULT) - - if(NOT GTK4_CFLAGS_RESULT EQUAL 0 OR NOT GTK4_LIBS_RESULT EQUAL 0) - message(FATAL_ERROR - "pkg-config could not find GTK4. Set PKG_CONFIG_PATH to " - "/lib/pkgconfig (for example C:\\gtk\\lib\\pkgconfig).") - endif() - - separate_arguments(GTK4_CFLAGS WINDOWS_COMMAND "${GTK4_CFLAGS_RAW}") - separate_arguments(GTK4_LIBS WINDOWS_COMMAND "${GTK4_LIBS_RAW}") -else() - find_package(PkgConfig REQUIRED) - pkg_check_modules(GTK4 REQUIRED IMPORTED_TARGET gtk4) -endif() - -file(GLOB GRADUATELY_SOURCES CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c") -if(WIN32) - add_executable(graduately WIN32 ${GRADUATELY_SOURCES} - "${CMAKE_CURRENT_SOURCE_DIR}/data/windows/maturita.rc") -else() - add_executable(graduately ${GRADUATELY_SOURCES}) -endif() - -target_include_directories(graduately PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/src") - -if(DEFINED APP_COMMIT AND NOT APP_COMMIT STREQUAL "") - target_compile_definitions(graduately PRIVATE APP_COMMIT="${APP_COMMIT}") -endif() - -if(MSVC) - target_compile_options(graduately PRIVATE ${GTK4_CFLAGS}) - target_link_options(graduately PRIVATE ${GTK4_LIBS}) - target_link_options(graduately PRIVATE /ENTRY:mainCRTStartup) - target_compile_definitions(graduately PRIVATE _CRT_SECURE_NO_WARNINGS) -else() - target_link_libraries(graduately PRIVATE PkgConfig::GTK4 m) - target_compile_options(graduately PRIVATE - -Wall -Wextra -Wno-deprecated-declarations) - if(APPLE) - target_link_libraries(graduately PRIVATE - "-framework AppKit" "-framework Foundation") - endif() -endif() - -# Runtime assets sit next to the binary after install / cmake --build. -set(ICON_512 - "${CMAKE_CURRENT_SOURCE_DIR}/data/share/icons/hicolor/512x512/apps/maturita.png") -add_custom_command(TARGET graduately POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/data/style.css - $/style.css - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/data/changelog.txt - $/changelog.txt - COMMAND ${CMAKE_COMMAND} -E make_directory - $/icons/hicolor/512x512/apps - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${ICON_512} - $/icons/hicolor/512x512/apps/maturita.png - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/data/share - $/share) diff --git a/android/app/src/main/java/org/maturita/maturita/AppViewModel.kt b/android/shared/src/org/maturita/maturita/AppViewModel.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/AppViewModel.kt rename to android/shared/src/org/maturita/maturita/AppViewModel.kt diff --git a/android/app/src/main/java/org/maturita/maturita/Route.kt b/android/shared/src/org/maturita/maturita/Route.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/Route.kt rename to android/shared/src/org/maturita/maturita/Route.kt diff --git a/android/app/src/main/java/org/maturita/maturita/data/Answers.kt b/android/shared/src/org/maturita/maturita/data/Answers.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/data/Answers.kt rename to android/shared/src/org/maturita/maturita/data/Answers.kt diff --git a/android/app/src/main/java/org/maturita/maturita/data/Content.kt b/android/shared/src/org/maturita/maturita/data/Content.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/data/Content.kt rename to android/shared/src/org/maturita/maturita/data/Content.kt diff --git a/android/app/src/main/java/org/maturita/maturita/data/Json.kt b/android/shared/src/org/maturita/maturita/data/Json.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/data/Json.kt rename to android/shared/src/org/maturita/maturita/data/Json.kt diff --git a/android/app/src/main/java/org/maturita/maturita/data/ProgressStore.kt b/android/shared/src/org/maturita/maturita/data/ProgressStore.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/data/ProgressStore.kt rename to android/shared/src/org/maturita/maturita/data/ProgressStore.kt diff --git a/android/app/src/main/java/org/maturita/maturita/data/Theme.kt b/android/shared/src/org/maturita/maturita/data/Theme.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/data/Theme.kt rename to android/shared/src/org/maturita/maturita/data/Theme.kt diff --git a/android/app/src/main/java/org/maturita/maturita/ui/Components.kt b/android/shared/src/org/maturita/maturita/ui/Components.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/ui/Components.kt rename to android/shared/src/org/maturita/maturita/ui/Components.kt diff --git a/android/app/src/main/java/org/maturita/maturita/ui/Exercises.kt b/android/shared/src/org/maturita/maturita/ui/Exercises.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/ui/Exercises.kt rename to android/shared/src/org/maturita/maturita/ui/Exercises.kt diff --git a/android/app/src/main/java/org/maturita/maturita/ui/Icons.kt b/android/shared/src/org/maturita/maturita/ui/Icons.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/ui/Icons.kt rename to android/shared/src/org/maturita/maturita/ui/Icons.kt diff --git a/android/app/src/main/java/org/maturita/maturita/ui/Screens.kt b/android/shared/src/org/maturita/maturita/ui/Screens.kt similarity index 100% rename from android/app/src/main/java/org/maturita/maturita/ui/Screens.kt rename to android/shared/src/org/maturita/maturita/ui/Screens.kt diff --git a/build-windows.bat b/build-windows.bat deleted file mode 100644 index 214e3c3..0000000 --- a/build-windows.bat +++ /dev/null @@ -1,101 +0,0 @@ -@echo off -setlocal EnableExtensions - -REM --------------------------------------------------------------------------- -REM Native Windows build with MSVC. No MSYS2 or MinGW shell required. -REM -REM Requirements: -REM * Visual Studio 2019/2022 with the "Desktop development with C++" -REM workload installed. -REM * A GTK4 build for MSVC, for example the gvsbuild prebuilt package -REM unzipped to C:\gtk (see README.md). -REM -REM If GTK lives somewhere other than C:\gtk, set GTK_ROOT first, e.g. -REM set GTK_ROOT=D:\gtk -REM --------------------------------------------------------------------------- - -if not defined GTK_ROOT set "GTK_ROOT=C:\gtk" - -REM --- 1. Locate Visual Studio and enter the 64-bit MSVC environment -------- -set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -if not exist "%VSWHERE%" ( - echo [error] vswhere.exe not found. - echo Install Visual Studio with the "Desktop development with C++" - echo workload, then run this script again. - exit /b 1 -) - -set "VSPATH=" -for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i" -if not defined VSPATH ( - echo [error] No Visual Studio C++ installation found. - exit /b 1 -) - -call "%VSPATH%\VC\Auxiliary\Build\vcvars64.bat" >nul -if errorlevel 1 ( - echo [error] Failed to initialise the MSVC environment. - exit /b 1 -) - -REM --- 2. Point the build at the GTK4 installation -------------------------- -set "PATH=%GTK_ROOT%\bin;%PATH%" -set "PKG_CONFIG_PATH=%GTK_ROOT%\lib\pkgconfig;%PKG_CONFIG_PATH%" - -set "PKG_CONFIG=pkg-config" -where pkg-config >nul 2>nul -if errorlevel 1 ( - where pkgconf >nul 2>nul - if errorlevel 1 ( - echo [error] pkg-config/pkgconf was not found. - echo Make sure GTK_ROOT points at a GTK4 install that contains - echo bin\pkg-config.exe. Current GTK_ROOT: %GTK_ROOT% - exit /b 1 - ) - set "PKG_CONFIG=pkgconf" -) - -REM --- 3. Collect the GTK4 flags in MSVC syntax ----------------------------- -set "GTK_CFLAGS=" -set "GTK_LIBS=" -for /f "usebackq delims=" %%c in (`%PKG_CONFIG% --cflags gtk4 --msvc-syntax`) do set "GTK_CFLAGS=%%c" -for /f "usebackq delims=" %%l in (`%PKG_CONFIG% --libs gtk4 --msvc-syntax`) do set "GTK_LIBS=%%l" - -if not defined GTK_CFLAGS ( - echo [error] pkg-config could not find gtk4. - echo Check that "%PKG_CONFIG_PATH%" contains gtk4.pc. - exit /b 1 -) - -if not exist "assets\app-icon.ico" ( - echo [error] assets\app-icon.ico is missing. - echo Generate it with: python scripts\gen-icons.py - exit /b 1 -) - -REM --- 4. Compile resources + sources --------------------------------------- -echo Building graduately.exe with MSVC... -if not exist build mkdir build -rc /nologo /fo build\maturita.res data\windows\maturita.rc -if errorlevel 1 ( - echo [error] Resource compile failed. - exit /b 1 -) - -cl /nologo /O2 /MD /W3 /std:c11 /I src /D_CRT_SECURE_NO_WARNINGS ^ - %GTK_CFLAGS% src\*.c build\maturita.res ^ - /Fe:graduately.exe /Fo:build\ ^ - /link /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup %GTK_LIBS% - -if errorlevel 1 ( - echo [error] Build failed. - exit /b 1 -) - -if not exist icons\hicolor\512x512\apps mkdir icons\hicolor\512x512\apps -copy /Y assets\app-icon.png icons\hicolor\512x512\apps\maturita.png >nul - -echo. -echo Built graduately.exe ^(icon embedded from assets\app-icon.ico^) -echo Run it from this terminal with: graduately.exe -echo Or use run-windows.bat / double-click graduately.exe. diff --git a/data/cetba-catalog.json b/data/cetba-catalog.json deleted file mode 100644 index da41486..0000000 --- a/data/cetba-catalog.json +++ /dev/null @@ -1,543 +0,0 @@ -[ - { - "id": "1984", - "author": "George Orwell", - "title": "1984", - "translator": "Šimečková", - "genre": "Próza", - "full": true, - "page": "cetba1984" - }, - { - "id": "fahrenheit451", - "author": "Ray Bradbury", - "title": "451 stupňů Fahrenheita", - "translator": "Nezval", - "genre": "Próza" - }, - { - "id": "audience", - "author": "Václav Havel", - "title": "Audience", - "genre": "Drama" - }, - { - "id": "bajecna-leta", - "author": "Michal Viewegh", - "title": "Báječná léta pod psa", - "genre": "Próza" - }, - { - "id": "bidnici", - "author": "Victor Hugo", - "title": "Bídníci", - "translator": "Pavlousková", - "genre": "Próza" - }, - { - "id": "bila-nemoc", - "author": "Karel Čapek", - "title": "Bílá nemoc", - "genre": "Drama" - }, - { - "id": "bylo-nas-pet", - "author": "Karel Poláček", - "title": "Bylo nás pět", - "genre": "Próza" - }, - { - "id": "cekani-na-godota", - "author": "Samuel Beckett", - "title": "Čekání na Godota", - "translator": "Ouředník", - "genre": "Drama" - }, - { - "id": "ceske-nebe", - "author": "Zdeněk Svěrák, Ladislav Smoljak", - "title": "České nebe", - "genre": "Drama" - }, - { - "id": "dekameron", - "author": "Giovanni Boccaccio", - "title": "Dekameron", - "translator": "Krátký", - "genre": "Próza" - }, - { - "id": "den-trifidu", - "author": "John Wyndham", - "title": "Den trifidů", - "translator": "Kořán", - "genre": "Próza" - }, - { - "id": "denik-anny-frankove", - "author": "Anne Franková", - "title": "Deník Anne Frankové", - "genre": "Próza" - }, - { - "id": "jekyll-hyde", - "author": "Robert Louis Stevenson", - "title": "Dr. Jekyll a Mr. Hyde", - "translator": "Kořán", - "genre": "Próza" - }, - { - "id": "edison", - "author": "Vítězslav Nezval", - "title": "Edison", - "genre": "Poezie" - }, - { - "id": "farma-zvirat", - "author": "George Orwell", - "title": "Farma zvířat", - "translator": "Gössell", - "genre": "Próza" - }, - { - "id": "gulliverovy-cesty", - "author": "Jonathan Swift", - "title": "Gulliverovy cesty", - "translator": "Skoumal", - "genre": "Próza" - }, - { - "id": "hamlet", - "author": "William Shakespeare", - "title": "Hamlet", - "translator": "Nevrla", - "genre": "Drama" - }, - { - "id": "havran", - "author": "Edgar Allan Poe", - "title": "Havran", - "genre": "Poezie" - }, - { - "id": "hladove-hry", - "author": "Suzanne Collins", - "title": "Hladové hry – I. Aréna smrti", - "translator": "Dušek", - "genre": "Próza" - }, - { - "id": "hlava-xxii", - "author": "Joseph Heller", - "title": "Hlava XXII", - "translator": "Jindra", - "genre": "Próza" - }, - { - "id": "chram-matky-bozi", - "author": "Victor Hugo", - "title": "Chrám Matky Boží", - "translator": "Tomášková", - "genre": "Próza" - }, - { - "id": "jak-jsem-vyhral-valku", - "author": "Patrick Ryan", - "title": "Jak jsem vyhrál válku", - "translator": "Vrba", - "genre": "Próza" - }, - { - "id": "jana-eyrova", - "author": "Charlotte Brontëová", - "title": "Jana Eyrová", - "translator": "Polák", - "genre": "Próza" - }, - { - "id": "ivan-denisovic", - "author": "Alexandr Solženicyn", - "title": "Jeden den Ivana Denisoviče", - "translator": "Machonin, Nováková", - "genre": "Próza" - }, - { - "id": "jmeno-ruze", - "author": "Umberto Eco", - "title": "Jméno růže", - "translator": "Frýbort", - "genre": "Próza" - }, - { - "id": "kalibuv-zlocin", - "author": "Karel Václav Rais", - "title": "Kalibův zločin", - "genre": "Próza" - }, - { - "id": "kniska-karla-kryla", - "author": "Karel Kryl", - "title": "Kníška Karla Kryla", - "genre": "Poezie" - }, - { - "id": "komu-zvoni-hrana", - "author": "Ernest Hemingway", - "title": "Komu zvoní hrana", - "translator": "Valja, Kobík", - "genre": "Próza" - }, - { - "id": "kral-oidipus", - "author": "Sofoklés", - "title": "Král Oidipus", - "translator": "Stiebitz", - "genre": "Drama" - }, - { - "id": "krysar", - "author": "Viktor Dyk", - "title": "Krysař", - "genre": "Próza" - }, - { - "id": "kulicka", - "author": "Guy de Maupassant", - "title": "Kulička", - "translator": "Guth", - "genre": "Próza" - }, - { - "id": "kvety-zla", - "author": "Charles Baudelaire", - "title": "Květy zla", - "translator": "Nezval", - "genre": "Poezie" - }, - { - "id": "kytice", - "author": "Karel Jaromír Erben", - "title": "Kytice", - "genre": "Poezie" - }, - { - "id": "lakomec", - "author": "Molière", - "title": "Lakomec", - "translator": "Mikeš", - "genre": "Drama" - }, - { - "id": "lolita", - "author": "Vladimir Nabokov", - "title": "Lolita", - "translator": "Kořínek", - "genre": "Próza" - }, - { - "id": "maj", - "author": "Karel Hynek Mácha", - "title": "Máj", - "genre": "Poezie" - }, - { - "id": "maly-princ", - "author": "Antoine de Saint-Exupéry", - "title": "Malý princ", - "translator": "Stavinohová", - "genre": "Próza" - }, - { - "id": "marysa", - "author": "Alois Mrštík, Vilém Mrštík", - "title": "Maryša", - "genre": "Drama" - }, - { - "id": "modlitba-pro-katerinu", - "author": "Arnošt Lustig", - "title": "Modlitba pro Kateřinu Horovitzovou", - "genre": "Próza" - }, - { - "id": "most-kwai", - "author": "Pierre Boulle", - "title": "Most přes řeku Kwai", - "translator": "Šup", - "genre": "Próza" - }, - { - "id": "stanice-zoo", - "author": "Christiane F.", - "title": "My děti ze stanice ZOO", - "translator": "Soukupová", - "genre": "Próza" - }, - { - "id": "na-ceste", - "author": "Jack Kerouac", - "title": "Na cestě", - "translator": "Popel", - "genre": "Próza" - }, - { - "id": "na-zapadni-fronte", - "author": "Erich Maria Remarque", - "title": "Na západní frontě klid", - "translator": "Gel", - "genre": "Próza" - }, - { - "id": "navsteva-stare-damy", - "author": "Friedrich Dürrenmatt", - "title": "Návštěva staré dámy", - "genre": "Drama" - }, - { - "id": "nebe-nezna-vyvolenych", - "author": "Erich Maria Remarque", - "title": "Nebe nezná vyvolených", - "translator": "V. a K. Holubovi", - "genre": "Próza" - }, - { - "id": "o-mysich-a-lidech", - "author": "John Steinbeck", - "title": "O myších a lidech", - "translator": "Vendyš", - "genre": "Próza" - }, - { - "id": "obraz-doriana-graye", - "author": "Oscar Wilde", - "title": "Obraz Doriana Graye", - "translator": "Novák", - "genre": "Próza" - }, - { - "id": "obsluhoval-jsem", - "author": "Bohumil Hrabal", - "title": "Obsluhoval jsem anglického krále", - "genre": "Próza" - }, - { - "id": "oliver-twist", - "author": "Charles Dickens", - "title": "Oliver Twist", - "translator": "E. a E. Tilschovi", - "genre": "Próza" - }, - { - "id": "ostre-sledovane-vlaky", - "author": "Bohumil Hrabal", - "title": "Ostře sledované vlaky", - "genre": "Próza" - }, - { - "id": "svejk", - "author": "Jaroslav Hašek", - "title": "Osudy dobrého vojáka Švejka za světové války", - "genre": "Próza" - }, - { - "id": "pan-much", - "author": "William Golding", - "title": "Pán much", - "translator": "Kovályová", - "genre": "Próza" - }, - { - "id": "pan-prstenu", - "author": "J. R. R. Tolkien", - "title": "Pán prstenů – Společenstvo prstenu", - "translator": "Pošustová", - "genre": "Próza" - }, - { - "id": "petr-a-lucie", - "author": "Romain Rolland", - "title": "Petr a Lucie", - "translator": "Zaorálek", - "genre": "Próza" - }, - { - "id": "poe-povidky", - "author": "Edgar Allan Poe", - "title": "Povídky", - "genre": "Próza" - }, - { - "id": "povidky-z-kapes", - "author": "Karel Čapek", - "title": "Povídky z jedné a druhé kapsy", - "genre": "Próza" - }, - { - "id": "promena", - "author": "Franz Kafka", - "title": "Proměna", - "genre": "Próza" - }, - { - "id": "pycha-a-predsudek", - "author": "Jane Austenová", - "title": "Pýcha a předsudek", - "translator": "Poláčková", - "genre": "Próza" - }, - { - "id": "rur", - "author": "Karel Čapek", - "title": "R. U. R.", - "genre": "Drama" - }, - { - "id": "revizor", - "author": "Nikolaj Vasiljevič Gogol", - "title": "Revizor", - "translator": "Mahler, Suchařípa, Morávková", - "genre": "Drama" - }, - { - "id": "romeo-a-julie", - "author": "William Shakespeare", - "title": "Romeo a Julie", - "translator": "Hilský", - "genre": "Drama" - }, - { - "id": "romeo-julie-a-tma", - "author": "Jan Otčenášek", - "title": "Romeo, Julie a tma", - "genre": "Próza" - }, - { - "id": "rozmarne-leto", - "author": "Vladislav Vančura", - "title": "Rozmarné léto", - "genre": "Próza" - }, - { - "id": "ruze-pro-algernon", - "author": "Daniel Keyes", - "title": "Růže pro Algernon", - "translator": "Podaný", - "genre": "Próza" - }, - { - "id": "saturnin", - "author": "Zdeněk Jirotka", - "title": "Saturnin", - "genre": "Próza" - }, - { - "id": "sluha-dvou-panu", - "author": "Carlo Goldoni", - "title": "Sluha dvou pánů", - "translator": "Bezděková", - "genre": "Drama" - }, - { - "id": "smrt-krasnych-srncu", - "author": "Ota Pavel", - "title": "Smrt krásných srnců", - "genre": "Próza" - }, - { - "id": "sofiina-volba", - "author": "William Styron", - "title": "Sofiina volba", - "translator": "Nenadál", - "genre": "Próza" - }, - { - "id": "fuks", - "author": "Ladislav Fuks", - "title": "Spalovač mrtvol", - "genre": "Próza", - "full": true, - "page": "cetbaFuks" - }, - { - "id": "stare-recke-baje", - "author": "Eduard Petiška", - "title": "Staré řecké báje a pověsti", - "genre": "Próza" - }, - { - "id": "starec-a-more", - "author": "Ernest Hemingway", - "title": "Stařec a moře", - "translator": "Vrba", - "genre": "Próza" - }, - { - "id": "svaty-xaverius", - "author": "Jakub Arbes", - "title": "Svatý Xaverius", - "genre": "Próza" - }, - { - "id": "tereza-raquinova", - "author": "Émile Zola", - "title": "Tereza Raquinová", - "genre": "Próza" - }, - { - "id": "tezka-hodina", - "author": "Jiří Wolker", - "title": "Těžká hodina", - "genre": "Poezie" - }, - { - "id": "tyrolske-elegie", - "author": "Karel Havlíček Borovský", - "title": "Tyrolské elegie", - "genre": "Poezie" - }, - { - "id": "valka-s-mloky", - "author": "Karel Čapek", - "title": "Válka s mloky", - "genre": "Próza" - }, - { - "id": "velky-cirkus", - "author": "Pierre Clostermann", - "title": "Velký cirkus", - "translator": "Jedlička", - "genre": "Próza" - }, - { - "id": "velky-gatsby", - "author": "F. Scott Fitzgerald", - "title": "Velký Gatsby", - "translator": "Dorůžka", - "genre": "Próza" - }, - { - "id": "tridni-kniha", - "author": "Ladislav Smoljak, Zdeněk Svěrák", - "title": "Vyšetřování ztráty třídní knihy", - "genre": "Drama" - }, - { - "id": "zabijak", - "author": "Émile Zola", - "title": "Zabiják", - "translator": "Kárl", - "genre": "Próza" - }, - { - "id": "zbabelci", - "author": "Josef Škvorecký", - "title": "Zbabělci", - "genre": "Próza" - }, - { - "id": "zert", - "author": "Milan Kundera", - "title": "Žert", - "genre": "Próza" - } -] diff --git a/data/cetba/1984.json b/data/cetba/1984.json deleted file mode 100644 index f0ace01..0000000 --- a/data/cetba/1984.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: George Orwell (vl. jm. Eric Arthur Blair)", - "Žánr: antiutopický (dystopický) román", - "Poprvé vydáno: 1949", - "Děj: Londýn, provincie Letopočet 1, stát Oceánie", - "Vyprávění: v er-formě, po deníkových zápiscích Winstona Smithe" - ] - }, - { - "title": "Svět a strana", - "icon": "globe", - "lines": [ - "Svět je rozdělen na tři supervelmoci: Oceánii, Eurasii a Východasii, které spolu vedou trvalou válku.", - "Vládne jediná strana (Angsoc) v čele s kultem Velkého bratra.", - "Ministerstvo pravdy – přepisuje historii a vyrábí „pravdu“.", - "Ministerstvo lásky – mučírny a likvidace nepohodlných.", - "Ministerstvo hojnosti – plánuje hospodářství a drží lidi v nedostatku.", - "Ministerstvo míru – vede válku." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Winston Smith – hlavní hrdina, přepisuje historii, touží po svobodě.", - "Julie – mladá členka strany, Winstonova tajná láska.", - "O'Brien – člen vnitřní strany, předstírá odboj a Winstona zničí.", - "Emmanuel Goldstein – nepřítel státu, údajný vůdce Bratrstva.", - "Velký bratr – symbol všemocné moci strany.", - "Pan Charrington – zdánlivý obchodník, ve skutečnosti agent." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Newspeak – uměle zjednodušovaný jazyk, který omezuje myšlení.", - "Dvojité myšlení – ochota věřit dvěma protikladným pravdám.", - "Zločin myšlení – už samotná zakázaná myšlenka.", - "Policie myšlení – tajná policie, která zatýká a mučí.", - "Bratrstvo – možná neexistující odbojová organizace.", - "Místnost 101 – nejhlubší mučírna, pro každého jeho největší strach." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je hlavní hrdina románu a co dělá?", - "options": [ - "Winston Smith – přepisuje historii na Ministerstvu pravdy", - "O'Brien – řídí Ministerstvo lásky", - "Emmanuel Goldstein – vede Bratrstvo", - "Winston Smith – velí Policii myšlení" - ], - "correct": 0, - "expl": "Winston Smith je vnější člen strany, který na Ministerstvu pravdy upravuje staré záznamy a novinové články." - }, - { - "prompt": "Ve kterém fiktivním státě se děj odehrává?", - "options": [ - "V Eurasii", - "V Oceánii", - "Ve Východasii", - "V Angsocu" - ], - "correct": 1, - "expl": "Příběh se odehrává v Oceánii, v provincii Letopočet 1 (bývalá Anglie), jejímž hlavním městem je Londýn." - }, - { - "prompt": "Co znamená slogan „VÁLKA JE MÍR, SVOBODA JE OTROCTVÍ, NEVĚDOMOST JE SÍLA“?", - "options": [ - "Jsou to tři zásady Bratrstva", - "Jsou to názvy ministerstev", - "Jde o hesla prolety", - "Jsou to paradoxní hesla, kterými strana ospravedlňuje útlak" - ], - "correct": 3, - "expl": "Strana používá dvojité myšlení: hesla znějí vznešeně, ale ve skutečnosti obhajují válku, otroctví a nevědomost." - }, - { - "prompt": "Kdo je Velký bratr a je reálnou osobou?", - "options": [ - "Skutečný vůdce Bratrstva", - "Winstonův nadřízený na ministerstvu", - "Symbol všemocné moci a kultu osobnosti; možná vůbec neexistuje", - "O'Brienův pseudonym" - ], - "correct": 2, - "expl": "Velký bratr je tvář režimu. Není jasné, zda jde o živou osobu, nebo jen o symbol, který drží strach a poslušnost." - }, - { - "prompt": "Co je Newspeak (novořeč) a proč ho strana zavádí?", - "options": [ - "Tajná řeč Bratrstva", - "Zjednodušená angličtina omezující slovní zásobu, aby nešlo vyslovit zakázané myšlenky", - "Úřední jazyk prolety", - "Šifra Policie myšlení" - ], - "correct": 1, - "expl": "Newspeak neustále ubírá slova. Když pro svobodu nebo odpor neexistuje slovo, nelze o nich ani myslet." - }, - { - "prompt": "Co je teleobrazovka (telescreen) a jak funguje?", - "options": [ - "Televize určená jen pro zábavu", - "Zařízení, které vysílá i sleduje; nelze ji úplně vypnout", - "Rozhlasová stanice", - "Počítač Ministerstva pravdy" - ], - "correct": 1, - "expl": "Telescreen funguje obousměrně – neustále sleduje občany. Vypnout lze jen zvuk, obraz běží dál." - }, - { - "prompt": "Jak se jmenují tři supervelmoci světa 1984?", - "options": [ - "Oceánie, Eurasie a Východasie", - "Oceánie, Evropa a Asie", - "Anglie, Eurasie a Ostasie", - "Oceánie, Východasie a Afrika" - ], - "correct": 0, - "expl": "Svět je rozdělen na tři státy ve věčném, ale nerozhodném konfliktu: Oceánii, Eurasii a Východasii." - }, - { - "prompt": "Čím se zabývá Ministerstvo pravdy?", - "options": [ - "Vede válku", - "Dohlíží na morálku a sňatky", - "Upravuje a přepisuje historii, noviny a archivy", - "Rozděluje potraviny" - ], - "correct": 2, - "expl": "Ministerstvo pravdy vyrábí „pravdu“ – Winston v něm přepisuje staré záznamy tak, aby vždy odpovídaly současné linii strany." - }, - { - "prompt": "K čemu slouží Ministerstvo lásky?", - "options": [ - "Zajišťuje sňatky a lásku", - "Je to budova bez oken, kde se mučí a likvidují nepřátelé strany", - "Vyrábí zbraně", - "Školí děti" - ], - "correct": 1, - "expl": "Ministerstvo lásky je opakem svého názvu – sídlí tam mučírny a nachází se v něm i obávaná místnost 101." - }, - { - "prompt": "V čem je paradox Ministerstva hojnosti?", - "options": [ - "Má na starosti hospodářství, ale ve skutečnosti drží lidi v nedostatku", - "Rozdává jídlo a zboží zdarma", - "Zajišťuje dostatek pro všechny", - "Starají se o něj prolety" - ], - "correct": 0, - "expl": "Ministerstvo hojnosti plánuje výrobu, ale ekonomika je záměrně nastavena tak, aby lidé žili v trvalém nedostatku." - }, - { - "prompt": "Co je Ministerstvo míru a čím se zabývá?", - "options": [ - "Uzavírá mírové smlouvy", - "Dojednává příměří", - "Ve skutečnosti vede válku", - "Velí Policii myšlení" - ], - "correct": 2, - "expl": "Název je přesně opačný: Ministerstvo míru řídí válku, protože trvalý válečný stav pomáhá udržet moc strany." - }, - { - "prompt": "Kdo je Julie a jaký vztah s ní Winston naváže?", - "options": [ - "Winstonova žena", - "Mladá členka strany, s níž Winston prožije tajnou milostnou aféru", - "O'Brienova asistentka", - "Proletka a obchodnice" - ], - "correct": 1, - "expl": "Julie pracuje v oddělení beletrie a naoko je vzornou členkou strany. S Winstonem vytvoří tajný milostný vztah." - }, - { - "prompt": "Proč je vztah Winstona a Julie zakázaný?", - "options": [ - "Strana zakazuje lásku a sexualitu jako zločin; vztah je navíc tajný", - "Julie je vdaná za člena vnitřní strany", - "Winston je jejím nadřízeným", - "Julie patří k proletům" - ], - "correct": 0, - "expl": "Strana potlačuje citové a sexuální vazby, protože oddanost má patřit jen straně. Tajný vztah je proto dvojnásob nebezpečný." - }, - { - "prompt": "Kdo je O'Brien a jakou roli hraje v příběhu?", - "options": [ - "Skutečný vůdce Bratrstva", - "Vysoce postavený člen vnitřní strany, který Winstona nakonec mučí a „vyléčí“", - "Winstonův přítel z dětství", - "Proletářský básník" - ], - "correct": 1, - "expl": "Winston věří, že O'Brien je odbojář. Ve skutečnosti je to věrný člen vnitřní strany, který ho dostane do místnosti 101." - }, - { - "prompt": "Co je Bratrstvo a existuje vůbec?", - "options": [ - "Skutečná armáda Oceánie", - "Náboženská organizace", - "Údajná tajná organizace odporu; není jisté, zda existuje", - "Odbory prolety" - ], - "correct": 2, - "expl": "Bratrstvo zmiňuje Goldstein i O'Brien, ale kniha nikdy nepotvrdí, že doopravdy existuje – může jít o past strany." - }, - { - "prompt": "Kdo je Emmanuel Goldstein?", - "options": [ - "Ministr pravdy", - "Oficiální nepřítel státu a údajný vůdce Bratrstva", - "Winstonův kolega", - "Velký bratrův dvojník" - ], - "correct": 1, - "expl": "Goldstein je terčem dvouminutovky nenávisti. Má ztělesňovat nepřítele, proti kterému strana sjednocuje občany." - }, - { - "prompt": "Co je dvojité myšlení (doublethink)?", - "options": [ - "Schopnost myslet ve dvou jazycích", - "Zdvojení osobnosti", - "Schopnost věřit dvěma protikladným tvrzením zároveň", - "Tajné zapisování myšlenek" - ], - "correct": 2, - "expl": "Dvojité myšlení je jádro stranické ideologie – člověk přijme i zjevné rozpory, jako „válka je mír“." - }, - { - "prompt": "Proč strana neustále přepisuje minulost?", - "options": [ - "Aby opravila chyby v archivech", - "Aby měla vždy pravdu a nepřítel jí nemohl dokázat opak", - "Aby ušetřila papír", - "Aby potěšila prolety" - ], - "correct": 1, - "expl": "Kdo ovládá minulost, ovládá i budoucnost. Přepisováním historie strana udržuje absolutní kontrolu nad pravdou." - }, - { - "prompt": "Co je zločin myšlení (thoughtcrime)?", - "options": [ - "Pouhá myšlenka nebo názor, který se nelíbí straně", - "Krádež státního majetku", - "Nelegální obchod", - "Opomenutí dvouminutovky" - ], - "correct": 0, - "expl": "Strana trestá už samotné myšlenky. Winston se proviní tím, že si do deníku napíše „Dolů s Velkým bratrem“." - }, - { - "prompt": "Kdo je pan Charrington a jaké je jeho skutečné postavení?", - "options": [ - "Winstonův přítel a majitel hospody", - "Proletářský básník", - "Zdánlivě starý majitel obchodu, ve skutečnosti agent Policie myšlení", - "Člen Bratrstva" - ], - "correct": 2, - "expl": "Charrington Winstonovi pronajme pokoj bez teleobrazovky, ale právě on nakonec oba milence udá." - }, - { - "prompt": "Co je místnost 101?", - "options": [ - "Winstonova cela na policii", - "Skladiště knih", - "Místnost, ve které každého čeká jeho největší strach", - "Zasedací místnost vnitřní strany" - ], - "correct": 2, - "expl": "Místnost 101 je vrcholný mučicí nástroj. Winstonovi v ní hrozí krysy – jeho největší fobie." - }, - { - "prompt": "Jak skončí vztah Winstona a Julie?", - "options": [ - "Utečou spolu do Eurasie", - "Vezmou se a žijí svobodně", - "Winston se stane členem Bratrstva", - "Zradí se a nakonec se přestanou milovat" - ], - "correct": 3, - "expl": "Oba jsou po mučení zlomení a vzájemně se zradí. Na konci už k sobě nic necítí." - }, - { - "prompt": "Co znamená závěrečná věta „Miloval Velkého bratra“?", - "options": [ - "Winstonův vzdor se změnil v pokornou lásku k režimu", - "Winston se stal novým vůdcem", - "Byl to jen Winstonův sen", - "Julie mu to řekla" - ], - "correct": 0, - "expl": "Winston byl vnitřně zlomen. Přestal být sám sebou a nakonec režim opravdu přijal za svůj." - }, - { - "prompt": "Které tvrzení NENÍ jedním z hlavních témat románu?", - "options": [ - "Moc a absolutní kontrola", - "Pravda a přepisování historie", - "Svoboda a identita", - "Idylický venkovský život" - ], - "correct": 3, - "expl": "1984 je temná antiutopie. Hlavními tématy jsou moc, kontrola, manipulace s pravdou a ztráta svobody, ne venkovská idyla." - }, - { - "prompt": "V jakém roce byl román 1984 poprvé vydán?", - "options": [ - "1936", - "1949", - "1954", - "1984" - ], - "correct": 1, - "expl": "Román vyšel v roce 1949; letopočet 1984 označuje blízkou budoucnost, do níž Orwell příběh zasadil." - }, - { - "prompt": "Které další Orwellovo dílo se dá s 1984 srovnat?", - "options": [ - "Farma zvířat", - "Velký Gatsby", - "Zločin a trest", - "Babička" - ], - "correct": 0, - "expl": "Obě Orwellova díla varují před totalitou. Farma zvířat ji líčí alegoricky pomocí zvířat, 1984 očima jedince." - }, - { - "prompt": "Co je „dvouminutovka nenávisti“?", - "options": [ - "Krátká každodenní akce, při níž občané společně nenávidí Goldsteina a nepřítele", - "Pravidelná modlitba ke Velkému bratrovi", - "Sportovní přestávka ve škole", - "Porada vedení ministerstva" - ], - "correct": 0, - "expl": "Slouží k uvolnění a přesměrování agrese občanů na nepřítele státu, čímž strana posiluje svou moc." - }, - { - "prompt": "Proč je podle knihy válka pro systém nezbytná?", - "options": [ - "Přináší mír a blahobyt", - "Udržuje strach, spotřebovává výrobu a zachovává chudobu i hierarchii", - "Rozvíjí vědu a techniku", - "Sjednocuje vládu s prolety" - ], - "correct": 1, - "expl": "Trvalá válka pohlcuje nadbytečnou produkci a udržuje lidi ve strachu i chudobě, takže se nemohou vzbouřit." - }, - { - "prompt": "Jaký je rozdíl mezi vnějšími členy strany a prolety?", - "options": [ - "Proleti mají více práv než členové strany", - "Vnější členové jsou dozíráni, kdežto proleti žijí v chudobě a strana o ně nestojí", - "Není mezi nimi žádný rozdíl", - "Proleti tvoří vedení strany" - ], - "correct": 1, - "expl": "Proleti tvoří asi 85 % obyvatel. Žijí v bídě a jsou považováni za neškodné, dokud si neuvědomí svou sílu." - }, - { - "prompt": "Jak strana kontroluje sexualitu a osobní vztahy?", - "options": [ - "Podporuje volnou lásku a nezávislost", - "Potlačuje lásku a sexualitu, děti vede k oddanosti straně", - "Zakazuje veškerá manželství", - "Povoluje vztahy jen s prolety" - ], - "correct": 1, - "expl": "Strana chce, aby veškerá oddanost a energie patřily jí. Proto podporuje zdrženlivost a vede děti v Antisexuální lize mládeže." - }, - { - "prompt": "Co symbolizuje papírové těžítko, které si Winston koupí?", - "options": [ - "Jeho nenávist ke Goldsteinovi", - "Kousek krásy a minulosti, kterou už nelze vrátit", - "Moc Velkého bratra", - "Lásku k Julii" - ], - "correct": 1, - "expl": "Těžítko je drobný, krásný předmět z minulosti. Pro Winstona ztělesňuje svět, který strana zničila." - }, - { - "prompt": "Jaké poselství chtěl Orwell románem nejspíš předat?", - "options": [ - "Varování před totalitou a ztrátou svobody i pravdy", - "Oslavu technického pokroku", - "Návod, jak založit stát", - "Kritiku sportu a zábavy" - ], - "correct": 0, - "expl": "1984 je varování: když lidé přestanou bránit pravdu a svobodu, mohou o ně nenávratně přijít." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Winston upravuje historii na Ministerstvu pravdy", - "Seznámí se s Julií a začnou se tajně scházet", - "Pronajme si pokoj nad obchodem pana Charringtona", - "Přečte Goldsteinovu knihu u O'Briena", - "Jsou zatčeni Policií myšlení", - "Winston se zlomí v místnosti 101" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: přepisování historie → seznámení s Julií → pronájem pokoje → četba Goldsteinovy knihy → zatčení → místnost 101." - ] -} diff --git a/data/cetba/_schema.example.json b/data/cetba/_schema.example.json deleted file mode 100644 index 2174001..0000000 --- a/data/cetba/_schema.example.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: …", - "Žánr: …", - "Poprvé vydáno: …", - "Děj / prostředí: …", - "Vyprávění / forma: …" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": ["…", "…", "…", "…", "…"] - }, - { - "title": "Postavy", - "icon": "people", - "lines": ["Jméno – popis.", "…", "…", "…", "…"] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": ["Pojem – vysvětlení.", "…", "…", "…", "…"] - } - ], - "quiz": [ - { - "prompt": "Otázka?", - "options": ["A", "B", "C", "D"], - "correct": 0, - "expl": "Krátké vysvětlení správné odpovědi." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": ["1", "2", "3", "4", "5", "6"] - } - ], - "plotMeaning": [ - "Správné pořadí: … → … → … → … → … → …." - ] -} diff --git a/data/cetba/audience.json b/data/cetba/audience.json deleted file mode 100644 index d782c26..0000000 --- a/data/cetba/audience.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Václav Havel", - "Žánr: drama (jednoaktovka, absurdní / groteskní)", - "Poprvé vydáno: 1975 (součást Vaněkovy trilogie)", - "Děj/prostředí: kancelář vedoucího skladu pivovaru", - "Vyprávění/forma: divadelní dialog, jedno dějství, jazyk moci vs. jazyk obyčejného člověka" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Dílo vzniklo v normalizačním období; metaforicky kritizuje totalitní společnost.", - "Hrdina Vaněk je bývalý spisovatel přeřazený na manuální práci.", - "Moc se projevuje v byrokracii, strachu a pokrytectví „nadřízených“.", - "Rozhovor není o práci, ale o testu loajality a ideologické poslušnosti.", - "Groteska: banální situace skrývá vážný tlak na svědomí jedince.", - "Havel rozvíjí téma „slov odpovědnosti“ a falešné ideologické fráze." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ferdinand Vaněk – bývalý spisovatel, dělník ve skladu pivovaru.", - "Vedoucí skladu (Šéf) – malý funkcionář toužící po kariéře, ideologicky nejistý.", - "Vaněkova manželka (zmíněna) – představuje tlak rodiny a strach ze ztráty výdělku.", - "Kolegové (nepřítomní) – symbol kolektivního dohledu.", - "Šéf jako typ – přizpůsobivý člověk, který opakuje fráze moci.", - "Vaněk jako typ disidenta – mlčí, ale nepodléhá." - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Audience – „audience u vedoucího“ = výslech, nátlak, pokus o spolupráci.", - "Hovory o pravdě – rozdíl mezi oficiální rétorikou a skutečným prožíváním.", - "Strach a kariéra – vedoucí se bojí, ale chce postup.", - "Práce vs. svědomí – Vaněk odmítá hrát ideologickou hru.", - "Groteska – vážné téma v banálním prostředí skladu.", - "Jazyk moci – prázdné fráze, které mají nahradit morální rozhodnutí." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je autorem hry Audience?", - "options": [ - "Jaroslav Hašek", - "Václav Havel", - "Karel Čapek", - "Ladislav Smoljak" - ], - "correct": 1, - "expl": "Audience napsal Václav Havel jako součást Vaněkovy trilogie." - }, - { - "prompt": "Jaký je žánr díla?", - "options": [ - "Epos", - "Jednoaktové drama", - "Lyrická báseň", - "Detektivní román" - ], - "correct": 1, - "expl": "Jde o jednoaktovou divadelní hru s dialogem dvou postav." - }, - { - "prompt": "Kde se děj odehrává?", - "options": [ - "Na ministerstvu", - "V kanceláři vedoucího skladu pivovaru", - "V divadle", - "V exilu" - ], - "correct": 1, - "expl": "Celá hra probíhá v kanceláři vedoucího skladu." - }, - { - "prompt": "Kdo je Ferdinand Vaněk?", - "options": [ - "Vedoucí skladu", - "Bývalý spisovatel přeřazený na manuální práci", - "Ministr", - "Hasič" - ], - "correct": 1, - "expl": "Vaněk je inteligent přeřazený do dělnické profese – alter ego Havla." - }, - { - "prompt": "Proč vedoucí Vaněka „předvolá“?", - "options": [ - "Kvůli inventuře", - "Aby ho ideologicky „ převýchovali“ a získali informace", - "Kvůli dovolené", - "Kvůli pivu zdarma" - ], - "correct": 1, - "expl": "Rozhovor je nátlak na poslušnost a spolupráci s mocí." - }, - { - "prompt": "Jak vedoucí vnímá svou pozici?", - "options": [ - "Jako mučedníka", - "Jako malého funkcionáře toužícího po kariéře", - "Jako disidenta", - "Jako umělce" - ], - "correct": 1, - "expl": "Vedoucí se přizpůsobuje systému a chce postup." - }, - { - "prompt": "Jak Vaněk reaguje na nátlak?", - "options": [ - "Okamžitě udává", - "Mlčí, ironizuje, nepodléhá", - "Odejde z práce", - "Napadne vedoucího" - ], - "correct": 1, - "expl": "Vaněk odmítá hrát hru moci, i když riskuje problémy." - }, - { - "prompt": "Co je typické pro Havlovy hry s Vaněkem?", - "options": [ - "Historický realismus 19. století", - "Groteskní situace a jazyk moci", - "Pohádková fantasy", - "Přírodní lyrika" - ], - "correct": 1, - "expl": "Havel ukazuje absurditu režimu skrze banální rozhovory." - }, - { - "prompt": "Kdy hra vznikla / poprvé vyšla?", - "options": [ - "1948", - "1975", - "1989", - "2000" - ], - "correct": 1, - "expl": "Audience patří k Vaněkově trilogii z normalizačního období (1975)." - }, - { - "prompt": "Jaké další hry tvoří Vaněkovu trilogii kromě Audience?", - "options": [ - "Hamlet a Macbeth", - "Protest a Vyrozumění", - "R.U.R. a Bílá nemoc", - "Čekání na Godota a Endgame" - ], - "correct": 1, - "expl": "Trilogie: Audience, Protest, Vyrozumění." - }, - { - "prompt": "Proč je hra „absurdní“?", - "options": [ - "Protože se dějí zázraky", - "Protože vážný nátlak probíhá v banální situaci skladu", - "Protože je bez dialogu", - "Protože je v rýmu" - ], - "correct": 1, - "expl": "Absurdita je v rozporu mezi tématem a prostředím." - }, - { - "prompt": "Co symbolizuje pivovar / sklad?", - "options": [ - "Exkluzivní elita", - "Běžné pracovní prostředí, kde se testuje loajalita", - "Církev", - "Škola" - ], - "correct": 1, - "expl": "Moc se prosazuje i v obyčejné fabrice." - }, - { - "prompt": "Jak vedoucí mluví o „pravdě“?", - "options": [ - "Jasně a otevřeně", - "Používá ideologické fráze a ospravedlňuje se", - "V latině", - "Vůbec nemluví" - ], - "correct": 1, - "expl": "Vedoucí opakuje fráze, ale neumí nést morální odpovědnost." - }, - { - "prompt": "Proč Vaněk nechce „spolupracovat“?", - "options": [ - "Neví jak", - "Odmítá kompromis se lží a strachem", - "Chce být vedoucím", - "Je mu jedno" - ], - "correct": 1, - "expl": "Hrdina volí svědomí před kariérním nebo materiálním klidem." - }, - { - "prompt": "Jaký vztah mají oba muži k alkoholu v hře?", - "options": [ - "Nepijí", - "Pivo je součástí prostředí a uvolnění napětí", - "Pijí jen Vaněk", - "Pivo zakazují" - ], - "correct": 1, - "expl": "Pivovar jako prostředí ovlivňuje tón rozhovoru." - }, - { - "prompt": "Co hrozí Vaněkovi, pokud neuspokojí vedoucího?", - "options": [ - "Pouze pokuta", - "Další perzekuce, problémy v práci i rodině", - "Okamžitá sláva", - "Povýšení" - ], - "correct": 1, - "expl": "Normalizační režim trestal odmítnutí spolupráce." - }, - { - "prompt": "Které téma Havel v Audience NEřeší primárně?", - "options": [ - "Morální odpovědnost", - "Jazyk moci", - "Kosmické cestování", - "Strach z autorit" - ], - "correct": 2, - "expl": "Hra je společenská groteska, ne sci-fi." - }, - { - "prompt": "Jak končí hra typicky v interpretaci?", - "options": [ - "Vítězstvím vedoucího", - "Bez jasného „happy endu“ – napětí a Vaněkovo trvání na svém", - "Svatbou", - "Válka" - ], - "correct": 1, - "expl": "Zůstává konflikt mezi mocí a svědomím." - }, - { - "prompt": "Proč je Audience maturitní četbou?", - "options": [ - "Kvůli pohádkovému ději", - "Ukazuje českou literaturu 20. století a disidentskou zkušenost", - "Je nejkratší kniha", - "Je bez témat" - ], - "correct": 1, - "expl": "Dílo reprezentuje Havla a období normalizace." - }, - { - "prompt": "Kdo je autorem termínu „slov odpovědnosti“ v kontextu Havla?", - "options": [ - "Shakespeare", - "Václav Havel", - "Orwell", - "Kafka" - ], - "correct": 1, - "expl": "Havel zdůrazňoval, že slova mají morální váhu." - }, - { - "prompt": "Jaký je tón dialogu?", - "options": [ - "Epický popis přírody", - "Napětí mezi frázemi moci a Vaněkovou ironií", - "Pouze monolog", - "Pouze pění" - ], - "correct": 1, - "expl": "Dialog odhaluje charakter obou postav." - }, - { - "prompt": "Vedoucí se bojí hlavně…", - "options": [ - "Přízraků", - "Ztráty postavení a problémů s nadřízenými", - "Vaněkova talentu na pivo", - "Cizinců" - ], - "correct": 1, - "expl": "Jeho kariéra závisí na ideologické spolehlivosti." - }, - { - "prompt": "Vaněk v hře představuje…", - "options": [ - "Typ spolupracovníka režimu", - "Typ člověka, který nezradí svědomí", - "Krále", - "Detektiva" - ], - "correct": 1, - "expl": "Vaněk je Havlovo alter ego disidenta." - }, - { - "prompt": "Kolik hlavních mluvících postav je v Audience?", - "options": [ - "Pět", - "Dvě", - "Deset", - "Žádná" - ], - "correct": 1, - "expl": "Dialog vedoucího a Vaněka tvoří jádro hry." - }, - { - "prompt": "Jak souvisí Audience s normalizací?", - "options": [ - "Vznikla v období po roce 1968 jako metafora tlaku režimu", - "Popisuje středověk", - "Je z roku 1848", - "Je americký western" - ], - "correct": 0, - "expl": "Hra reaguje na politickou situaci v Československu 70. let." - }, - { - "prompt": "Proč vedoucí opakuje fráze?", - "options": [ - "Nemá slovní zásobu", - "Nahrazuje nimi vlastní rozhodnutí a odpovědnost", - "Učí se latinu", - "Je básník" - ], - "correct": 1, - "expl": "Ideologický jazyk má ulevit od morální volby." - }, - { - "prompt": "Co Vaněk odmítá udělat?", - "options": [ - "Pracovat", - "Hrát roli informátora / ideologicky se „ přizpůsobit“", - "Pít pivo", - "Chodit do skladu" - ], - "correct": 1, - "expl": "Jde o odmítnutí spolupráce s mocí." - }, - { - "prompt": "Jaký literární směr je nejblíže Havlovu divadlu?", - "options": [ - "Romantismus", - "Divadlo absurdní / groteskní", - "Klasicismus", - "Naturalismus venkova" - ], - "correct": 1, - "expl": "Havel navazuje na absurdní drama, ale s českým politickým kontextem." - }, - { - "prompt": "Co je „audience“ v anglickém významu slova?", - "options": [ - "Publikum / jednání s nadřízeným", - "Hasičský sbor", - "Pivní sud", - "Soudní trest" - ], - "correct": 0, - "expl": "Název ironicky evokuje setkání, které je ve skutečnosti výslech." - }, - { - "prompt": "Která postava je víc „pro systém“?", - "options": [ - "Vaněk", - "Vedoucí skladu", - "Obě stejně", - "Ani jedna" - ], - "correct": 1, - "expl": "Vedoucí se snaží vyhovět nadřízeným." - }, - { - "prompt": "Jaké poselství je pro maturitu klíčové?", - "options": [ - "Poslušnost za každou cenu", - "Člověk může odmítnout lhát, i když za to platí", - "Práce je vždy důležitější než pravda", - "Fráze nahrazují etiku" - ], - "correct": 1, - "expl": "Hra obhajuje svědomí proti ideologickému nátlaku." - }, - { - "prompt": "V jakém žánru je Audience v katalogu maturitní četby?", - "options": [ - "Poezie", - "Drama", - "Próza", - "Epos" - ], - "correct": 1, - "expl": "V katalogu je uvedeno jako drama." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Vaněk pracuje ve skladu pivovaru jako dělník", - "Vedoucí ho předvolá na rozhovor v kanceláři", - "Vedoucí tlakem a frázemi testuje Vaněkovo přizpůsobení", - "Vaněk odmítá ideologickou spolupráci", - "Napětí mezi kariérou vedoucího a Vaněkovým svědomím roste", - "Hra končí bez smíření – moc a disident zůstávají v konfliktu" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: Vaněk ve skladu → předvolání → nátlak vedoucího → Vaněkovo odmítnutí → eskalace napětí → nevyřešený konflikt." - ] -} diff --git a/data/cetba/bajecna-leta.json b/data/cetba/bajecna-leta.json deleted file mode 100644 index ab0fd52..0000000 --- a/data/cetba/bajecna-leta.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Michal Viewegh", - "Žánr: autobiograficky laděný humoristický román", - "Poprvé vydáno: 1992", - "Děj/prostředí: dětství a dospívání v 70.–80. letech v Československu", - "Vyprávění/forma: ich-forma, groteskní humor, koláž vzpomínek" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Normalizace, šedivá všednost, ideologické fráze ve škole i doma.", - "Rodina střední třídy – tlak na slušnost, studium a „správné“ chování.", - "Kontrast mezi oficiální propagandou a soukromým životem.", - "Mladý hrdina objevuje sexualitu, alkohol, rockovou hudbu.", - "Společnost bez perspektivy, ale s černým humorem.", - "Typické vieweghovské sebeironické vyprávění." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Vypravěč / mladý Michal – pubertální hrdina, pozorovatel i aktér.", - "Rodiče – autoritativní otec, matka, generační střet.", - "Kamarádi a spolužáci – svět dospívání.", - "Učitelé – představitelé školní moci.", - "První lásky a holky – motív sebevědomí a trapasů.", - "Sousedé a příbuzní – groteskní epizody." - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Autobiografický prvek – fikce vs. vzpomínka.", - "Humor a groteska – coping mechanismus éry.", - "Puberta – tělo, stud, touha být „cool“.", - "Ideologie vs. realita – škola, pionýr, fráze.", - "Rodina – láska, nátlak, generační rozdíly.", - "Název – „léta pod psa“ = chaotické období života." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je autorem?", - "options": [ - "Viewegh", - "Poláček", - "Hašek", - "Havel" - ], - "correct": 0, - "expl": "Román napsal Michal Viewegh." - }, - { - "prompt": "Jaký je žánr?", - "options": [ - "Historický epos", - "Autobiograficky laděný humoristický román", - "Detektivka", - "Tragedie" - ], - "correct": 1, - "expl": "Dílo kombinuje vzpomínky s fikcí a humorem." - }, - { - "prompt": "Kdy kniha vyšla?", - "options": [ - "1989", - "1992", - "2005", - "1968" - ], - "correct": 1, - "expl": "Báječná léta pod psa vyšla v roce 1992." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Otec v er-formě", - "Mladý Michal v ich-formě", - "Vševěd", - "Učitel" - ], - "correct": 1, - "expl": "Vypravěč je sám hrdina jako dospívající chlapec." - }, - { - "prompt": "V jakém období děj probíhá?", - "options": [ - "První republika", - "70.–80. léta normalizace", - "Středověk", - "Budoucnost" - ], - "correct": 1, - "expl": "Děj kopíruje dětství autora v normalizačním Československu." - }, - { - "prompt": "Co znamená „léta pod psa“?", - "options": [ - "Idylické dětství", - "Chaotické, těžké období s humorem", - "Vojenská služba", - "Studium v zahraničí" - ], - "correct": 1, - "expl": "Název ironicky označuje nepříliš slavné období života." - }, - { - "prompt": "Jaký tón knihy převládá?", - "options": [ - "Tragický bez humoru", - "Groteskní humor a sebeironie", - "Epická vážnost", - "Horor" - ], - "correct": 1, - "expl": "Viewegh typicky balí bolest do humoru." - }, - { - "prompt": "Kde hrdina tráví velkou část dětství?", - "options": [ - "Na statku v Texasu", - "Ve městě, doma a ve škole", - "V klášteře", - "Na lodi" - ], - "correct": 1, - "expl": "Prostředí je běžné město a rodinný byt." - }, - { - "prompt": "Jak je v knize zobrazena škola?", - "options": [ - "Jako ráj", - "Jako místo ideologie, strachu i trapasů", - "Chybí", - "Jen univerzita" - ], - "correct": 1, - "expl": "Škola je součást normalizační výchovy." - }, - { - "prompt": "Které téma patří k dílu?", - "options": [ - "Puberta a sexualita", - "Kosmické války", - "Rytířské turnaje", - "Lovec velryb" - ], - "correct": 0, - "expl": "Dospívání je ústřední." - }, - { - "prompt": "Jak vnímá hrdina rodiče?", - "options": [ - "Nezmíní je", - "Jako autority, se kterými bojuje i je miluje", - "Jako cizince", - "Jako detektivy" - ], - "correct": 1, - "expl": "Generační konflikt je typický." - }, - { - "prompt": "Co je typické pro Vieweghovu prózu?", - "options": [ - "Středověká mluva", - "Ich-forma, autobiografické prvky, humor", - "Pouze poezie", - "Beletrie bez postav" - ], - "correct": 1, - "expl": "Autor často čerpá z vlastního života." - }, - { - "prompt": "Jak kniha reaguje na normalizaci?", - "options": [ - "Oslavuje ji", - "Ironizuje fráze a všednost režimu", - "Ignoruje politiku úplně", - "Je manifestem strany" - ], - "correct": 1, - "expl": "Politika prosvítá školou a jazykem." - }, - { - "prompt": "Která postava NENÍ typická pro děj?", - "options": [ - "Spolužák", - "Rodič", - "Mladý vypravěč", - "Král Artuš" - ], - "correct": 3, - "expl": "Děj je realisticky autobiografický." - }, - { - "prompt": "Jaký vztah má k alkoholu v dospívání?", - "options": [ - "V knize neexistuje", - "Objevuje se jako součást „dospěláckého“ světa", - "Je jen u dospělých bez komentáře", - "Je zakázaný téma" - ], - "correct": 1, - "expl": "Hrdina zkouší hranice tabu." - }, - { - "prompt": "Co hrdina často prožívá?", - "options": [ - "Stud a trapasy", - "Věčný klid", - "Nadlidské moc", - "Středověké bitvy" - ], - "correct": 0, - "expl": "Pubertální stud je častý motiv." - }, - { - "prompt": "Jak končí kniha typicky?", - "options": [ - "Svatbou v kostele", - "Pokračováním v dalších dílech / otevřeným dospíváním", - "Smrtí všech", - "Válka" - ], - "correct": 1, - "expl": "Viewegh navazuje v dalších autobiografických knihách." - }, - { - "prompt": "Proč je kniha maturitní?", - "options": [ - "Je nejkratší", - "Reprezentuje českou prózu 90. let a generaci normalizace", - "Je v angličtině", - "Nemá postavy" - ], - "correct": 1, - "expl": "Patří k čtení generace Viewegha." - }, - { - "prompt": "Jaký jazyk autor používá?", - "options": [ - "Archaičtina", - "Spisovná čeština s hovorovými prvky", - "Cizí bez překladu", - "Pouze dialekt" - ], - "correct": 1, - "expl": "Styl je srozumitelný, hovorový, vtipný." - }, - { - "prompt": "Co je groteska v knize?", - "options": [ - "Pouze hrůza", - "Nadsázka a absurdní situace z běžného života", - "Pouze poezie", - "Historická přesnost" - ], - "correct": 1, - "expl": "Groteska zvyšuje humor i pravdivost." - }, - { - "prompt": "Jaký motiv NENÍ klíčový?", - "options": [ - "Rodina", - "Škola", - "Dospívání", - "Mýtus o Atlantidě" - ], - "correct": 3, - "expl": "Atlantida v díle nefiguruje." - }, - { - "prompt": "Kdo je cílový čtenář stylu?", - "options": [ - "Pouze historici", - "Široká veřejnost, zejména mladší", - "Jen linguisté", - "Jen děti předškoláci" - ], - "correct": 1, - "expl": "Kniha je bestsellerově čtivá." - }, - { - "prompt": "Jak hrdina vnímá „cool“ svět?", - "options": [ - "Nehraje roli", - "Touží po něm, napodobuje rock, kamarády", - "Je proti hudbě", - "Je dospělý" - ], - "correct": 1, - "expl": "Teenagerská identita je důležitá." - }, - { - "prompt": "Co odlišuje Viewegha od Poláčka?", - "options": [ - "Viewegh píše 90. léta autobiografii, Poláček meziválečný humor", - "Jsou totožní", - "Poláček píše sci-fi", - "Viewegh píše drama" - ], - "correct": 0, - "expl": "Období i styl se liší." - }, - { - "prompt": "Jaká forma vyprávění?", - "options": [ - "Drama", - "Ich-forma románu", - "Epos", - "Deník bez komentáře" - ], - "correct": 1, - "expl": "Vypravěč je „já“." - }, - { - "prompt": "Které prostředí dominuje?", - "options": [ - "Pouze příroda", - "Město, byt, škola", - "Pouze fabrika", - "Pouze cirkus" - ], - "correct": 1, - "expl": "Urbanizované dětství." - }, - { - "prompt": "Jak autor pracuje s časem?", - "options": [ - "Lineárně od narození po smrt v jednom roce", - "Kapitolami, epizodami vzpomínek", - "Jen jeden den", - "Bez času" - ], - "correct": 1, - "expl": "Koláž epizod tvoří celek." - }, - { - "prompt": "Co hrdina objevuje u holky / v lásce?", - "options": [ - "Nic", - "Stud, touhu, nedorozumění", - "Jen válku", - "Jen politiku" - ], - "correct": 1, - "expl": "Milostné epizody patří k pubertě." - }, - { - "prompt": "Jaký je vztah k autoritám?", - "options": [ - "Bezvýhradná poslušnost", - "Vzdor, ironie, občasná poslušnost", - "Vždy trest", - "Autority chybí" - ], - "correct": 1, - "expl": "Typický teen vs. rodiče/učitelé." - }, - { - "prompt": "Jaké poselství lze vyčíst?", - "options": [ - "Dětství v režimu lze vyprávět s humorem i pravdou", - "Normalizace neexistovala", - "Humor je zbytečný", - "Rodina vždy škodí" - ], - "correct": 0, - "expl": "Kniha spojuje paměť generace s humorem." - }, - { - "prompt": "Kolik quiz otázek má mít maturita pack?", - "options": [ - "5", - "28–32", - "100", - "1" - ], - "correct": 1, - "expl": "Stejně jako ostatní balíčky v projektu." - }, - { - "prompt": "Který autor napsal Báječná léta pod psa?", - "options": [ - "Michal Viewegh", - "Milan Kundera", - "Karel Čapek", - "Bohumil Hrabal" - ], - "correct": 0, - "expl": "Viewegh je autorem." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Dětství vypravěče v normalizaci", - "Školní a rodinné epizody", - "Puberta, kamarádi a první lásky", - "Konfrontace s ideologií a frázemi", - "Trapasy a groteskní situace", - "Dospívání směrem k dospělosti" - ] - } - ], - "plotMeaning": [ - "Pořadí: dětství → škola a rodina → puberta → ideologie → humor z trapasů → dospívání." - ] -} diff --git a/data/cetba/bidnici.json b/data/cetba/bidnici.json deleted file mode 100644 index e3f05d6..0000000 --- a/data/cetba/bidnici.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Victor Hugo", - "Žánr: historicko-společenský román (epický)", - "Poprvé vydáno: 1862", - "Děj/prostředí: Francie, především Paříž 19. století (restaurace, revoluce)", - "Vyprávění/forma: er-forma, mnoho dějových linií, historické vsuvky" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Společnost po Napoleonovi, chudoba, sociální nespravedlnost", - "Revoluční vlny (1832 – barikády v Paříži)", - "Církev, charity, ale i tvrdý úřad a policie", - "Téma milosrdenství vs. zákon", - "Paříž jako symbol metropole dobra i zla", - "Román o spáse duše a společenské změně" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Jean Valjean – bývalý galejník, který se polepší", - "Javert – policejní inspektor, zákon bez milosrdenství", - "Fantine – matka Cosette, oběť chudoby", - "Cosette – dívka, kterou Valjean vychovává", - "Marius – mladý revolucionář, Cosettin milenec", - "Thénardierovi – lakomí, krutí hostinští" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Milosrdenství biskupa Myrela – stříbrné svícny", - "Galeje a žlutý pas – stigma ex trestance", - "Barikády 1832 – revoluce mladých", - "Sewers / stoky – únik Marius a Valjean", - "Spravedlnost vs. zákon – Javertův kolaps", - "Láska a oběť – Fantine, Valjean, Marius" - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je autorem Bídníků?", - "options": [ - "Dickens", - "Hugo", - "Zola", - "Flaubert" - ], - "correct": 1, - "expl": "Victor Hugo napsal Les Misérables (Bídníci)." - }, - { - "prompt": "Kdy román poprvé vyšel?", - "options": [ - "1789", - "1862", - "1900", - "1950" - ], - "correct": 1, - "expl": "Vydání 1862 je klíčové pro francouzskou literaturu." - }, - { - "prompt": "Kdo je Jean Valjean na začátku?", - "options": [ - "Kněz", - "Galejník pro krádež chleba", - "Král", - "Advokát" - ], - "correct": 1, - "expl": "Valjean strávil roky v galejích." - }, - { - "prompt": "Co udělá biskup Myriel?", - "options": [ - "Udá Valjeana", - "Daruje mu stříbrné svícny a zachrání ho před policií", - "Zabije Javerta", - "Pošle ho zpět do galejí" - ], - "correct": 1, - "expl": "Milosrdenství biskupa změní Valjeanův život." - }, - { - "prompt": "Proč Valjean mění identitu?", - "options": [ - "Pro zábavu", - "Aby mohl začít nový život a pomáhat druhým", - "Javert ho požádá", - "Kvůli loterii" - ], - "correct": 1, - "expl": "Nová identita umožní podnikání a charitu." - }, - { - "prompt": "Kdo je Javert?", - "options": [ - "Valjeanův přítel", - "Policejní inspektor posedlý dopadením Valjeana", - "Biskup", - "Marius" - ], - "correct": 1, - "expl": "Javert ztělesňuje zákon bez milosrdenství." - }, - { - "prompt": "Co se stane Fantine?", - "options": [ - "Stane se královnou", - "Kvůli dceři Cosette chudoba a prostituce, umírá", - "Vede revoluci", - "Je s Javertem" - ], - "correct": 1, - "expl": "Fantine je oběť společnosti." - }, - { - "prompt": "Kdo vychovává Cosette?", - "options": [ - "Thénardierovi ji mučí, pak ji vezme Valjean", - "Javert", - "Marius od narození", - "Nikdo" - ], - "correct": 0, - "expl": "Valjean Cosette vykoupí a miluje jako dcera." - }, - { - "prompt": "Kdo je Marius?", - "options": [ - "Starý hostinský", - "Mladý revolucionář, zamiluje se do Cosette", - "Biskup", - "Galejník" - ], - "correct": 1, - "expl": "Marius se účastní barikád." - }, - { - "prompt": "Kde probíhá revoluční boj?", - "options": [ - "Versailles", - "Barikády v Paříži (1832)", - "Londýn", - "Marseille" - ], - "correct": 1, - "expl": "Historická vsuvka – povstání 1832." - }, - { - "prompt": "Jak Valjean zachrání Marius?", - "options": [ - "Nechá ho na barikádě", - "Odnese ho stokami z bojiště", - "Javert pomůže", - "Marius uteče sám" - ], - "correct": 1, - "expl": "Slavná scéna v pařížských stokách." - }, - { - "prompt": "Proč Javert spáchá sebevraždu?", - "options": [ - "Valjean ho zabije", - "Nezvládne, že Valjean mu prokazuje dobro – kolaps morálky zákona", - "Marius ho obviní", - "Hlad" - ], - "correct": 1, - "expl": "Javert nemůže sladit zákon s realitou Valjeanovy goodness." - }, - { - "prompt": "Jak Valjean končí?", - "options": [ - "Na trůně", - "Umírá v klidu, Cosette a Marius mu odpouštějí", - "V galejích", - "V exilu jako zločinec" - ], - "correct": 1, - "expl": "Závěr je vyznání a smrt starého muže." - }, - { - "prompt": "Kdo jsou Thénardierovi?", - "options": [ - "Šlechtici", - "Lakomí, krutí hostinští využívající Cosette", - "Kněží", - "Učitelé" - ], - "correct": 1, - "expl": "Představují spodinu bez morálky." - }, - { - "prompt": "Jaký je hlavní konflikt Valjean vs. Javert?", - "options": [ - "Sport", - "Milosrdenství a nový život vs. nemilosrdný zákon", - "Náboženství vs. věda", - "Láska vs. hudba" - ], - "correct": 1, - "expl": "Centrální morální osa románu." - }, - { - "prompt": "Co symbolizují stříbrné svícny?", - "options": [ - "Bohatství", - "Milosrdenství a důvěru, která spouští spásu", - "Válku", - "Krádež" - ], - "correct": 1, - "expl": "Biskup dá Valjeanovi i „duši“." - }, - { - "prompt": "Jaký žánr román nejlépe vystihuje?", - "options": [ - "Pohádka", - "Historicko-společenský epický román", - "Sci-fi", - "Detektivka" - ], - "correct": 1, - "expl": "Rozsáhlý děj s historií Francie." - }, - { - "prompt": "Kde se odehrává většina děje?", - "options": [ - "Praha", - "Paříž a okolí", - "New York", - "Moskva" - ], - "correct": 1, - "expl": "Paříž je hlavní prostředí." - }, - { - "prompt": "Co Valjean dělá jako boháč?", - "options": [ - "Pouze holdí peníze", - "Vede továrnu, pomáhá chudým, stará se o Cosette", - "Stane se policistou", - "Pálí knihy" - ], - "correct": 1, - "expl": "Je dobrodinou i otcem." - }, - { - "prompt": "Kdo Éponine?", - "options": [ - "Dcera Thénardierových, miluje Marius, oběť barikád", - "Sestra Cosette", - "Javertova žena", - "Královna" - ], - "correct": 0, - "expl": "Éponine je tragická postava lásky." - }, - { - "prompt": "Proč je román maturitní?", - "options": [ - "Je nejkratší", - "Klasika světové literatury o spravedlnosti a chudobě", - "Bez témat", - "Jen poezie" - ], - "correct": 1, - "expl": "Hugo patří k kanonu." - }, - { - "prompt": "Jaký překladatel bývá uváděn v CZ maturitě?", - "options": [ - "Nezval", - "Pavlousková", - "Nevrla", - "Gössell" - ], - "correct": 1, - "expl": "V katalogu je Pavlousková." - }, - { - "prompt": "Co je „bídníci“ v titulu?", - "options": [ - "Pouze zločinci", - "Chudí a opozedníci společnosti", - "Šlechtici", - "Kněží" - ], - "correct": 1, - "expl": "Les misérables = trpící, chudí." - }, - { - "prompt": "Jak Hugo pracuje s historií?", - "options": [ - "Ignoruje ji", - "Vkládá historické kapitoly a reálné události", - "Píše budoucnost", - "Jen mýty" - ], - "correct": 1, - "expl": "Román je i historický obraz." - }, - { - "prompt": "Která postava NENÍ z Bídníků?", - "options": [ - "Valjean", - "Javert", - "Hamlet", - "Fantine" - ], - "correct": 2, - "expl": "Hamlet je Shakespeare." - }, - { - "prompt": "Co Marius neví dlouho?", - "options": [ - "Že Valjean zachránil jeho život", - "Že existuje Paříž", - "Že miluje Cosette", - "Nic" - ], - "correct": 0, - "expl": "Tajemství Valjeanovy oběti se odhalí později." - }, - { - "prompt": "Jaký motiv lásky je v díle?", - "options": [ - "Pouze komický", - "Rodičovská (Valjean–Cosette), romantická (Marius–Cosette)", - "Chybí", - "Jen platonická u Javerta" - ], - "correct": 1, - "expl": "Láska je motor obětí." - }, - { - "prompt": "Co reprezentuje barikáda?", - "options": [ - "Dovolená", - "Naděje mladých na spravedlivější svět i oběť", - "Obchod", - "Církev" - ], - "correct": 1, - "expl": "Revoluční idealismus Mariusovy generace." - }, - { - "prompt": "Proč Valjean uniká Javertovi opakovaně?", - "options": [ - "Magie", - "Identita, úkryty, milosrdenství druhých", - "Javert nechce chytit", - "Válka" - ], - "correct": 1, - "expl": "Dlouhý pronásledovací motiv." - }, - { - "prompt": "Jaké poselství je typické?", - "options": [ - "Zlo vždy vyhrává", - "I spadlý člověk může jednat morálně a měnit životy", - "Zákon je vždy spravedlivý", - "Chudoba neexistuje" - ], - "correct": 1, - "expl": "Spása skrze milosrdenství." - }, - { - "prompt": "Kolik hlavních dějových linií román spojuje?", - "options": [ - "Jednu bez vedlejších", - "Valjean, Fantine/Cosette, Marius, Javert a další", - "Jen Marius", - "Jen Javert" - ], - "correct": 1, - "expl": "Epická stavba s mnoha linemi." - }, - { - "prompt": "Jak končí vztah Cosette a Valjeana?", - "options": [ - "Cosette ho nenávidí", - "Odpustí a miluje ho jako otce", - "Valjean ji opustí navždy bez slova", - "Javert je oddá" - ], - "correct": 1, - "expl": "Emocionální závěr u lůžka Valjeana." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Valjean propuštěn z galejí a setká se s biskupem Myrelem", - "Valjean vychovává továrnu a přebírá Cosette", - "Fantine umírá, Javert pronásleduje Valjeana", - "Marius na barikádách, Valjean zachrání Marius stokami", - "Javert propadne po selhání morálky zákona", - "Valjean umírá v míru u Cosette a Marius" - ] - } - ], - "plotMeaning": [ - "Pořadí: galeje a biskup → Cosette a továrna → Fantine a pronásledování → barikády a záchrana → Javert → Valjeanova smrt." - ] -} diff --git a/data/cetba/bila-nemoc.json b/data/cetba/bila-nemoc.json deleted file mode 100644 index 3b19754..0000000 --- a/data/cetba/bila-nemoc.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Čapek", - "Žánr: politické/allegorické drama", - "Poprvé vydáno: 1937", - "Děj/prostředí: fiktivní stát, epidemie neznámé nemoci", - "Vyprávění/forma: klasické drama, dialogy, satira i tragédie" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Meziválečné napětí, hrozba fašismu a války", - "Epidemie „bílé nemoci“ – zabíjí hlavně mladé dospělé", - "Politici preferují zbrojení před léčbou", - "Společnost v strachu, hledá viníky", - "Allegorie: nemoc = morální a politická nakažlivost", - "Varování před válkou a lhostejností moci" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Dr. Galén – lékař s lékem, idealista", - "Maršál – vůdce státu, touží po válce", - "Sigmund – obchodník se zbraněmi", - "Millionáři a politici – cynismus elity", - "Chudí pacienti – oběti systému", - "Galénův otec – vědec, odkaz léku" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Bílá nemoc – neznámá epidemie, bílé skvrny na těle", - "Lék Galéna – funguje, ale není nasazen", - "Válka vs. léčba – priority moci", - "Allegorie fašismu – nakažlivá ideologie", - "Svědomí lékaře – služba lidem", - "Závěr – kolaps, varování nevyužito" - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Bílou nemoc?", - "options": [ - "Hašek", - "Čapek", - "Havel", - "Poláček" - ], - "correct": 1, - "expl": "Karel Čapek, drama z roku 1937." - }, - { - "prompt": "Jaký je žánr?", - "options": [ - "Pohádka", - "Politické drama", - "Epos", - "Opera" - ], - "correct": 1, - "expl": "Drama s allegorickým významem." - }, - { - "prompt": "Co je bílá nemoc?", - "options": [ - "Barva sněhu", - "Smrtelná epidemie s bílými skvrnami", - "Druh květiny", - "Zbran" - ], - "correct": 1, - "expl": "Nemoc je středem děje." - }, - { - "prompt": "Kdo má lék?", - "options": [ - "Maršál", - "Dr. Galén", - "Sigmund prodává", - "Nikdo" - ], - "correct": 1, - "expl": "Galén zdědí/vyvinou lék." - }, - { - "prompt": "Proč lék není hromadně nasazen?", - "options": [ - "Nefunguje", - "Moc preferuje válku a zisk ze zbrojení", - "Galén odmítá", - "Chybí voda" - ], - "correct": 1, - "expl": "Politici nechtějí „mír“ bez války." - }, - { - "prompt": "Kdo je Maršál?", - "options": [ - "Lékař", - "Vůdce státu militarista", - "Kněz", - "Učitel" - ], - "correct": 1, - "expl": "Maršál symbolizuje válečnou moc." - }, - { - "prompt": "Kdo je Sigmund?", - "options": [ - "Pacient", - "Obchodník se zbraněmi", - "Galénův bratr", - "Básník" - ], - "correct": 1, - "expl": "Zbrojař profituje z konfliktu." - }, - { - "prompt": "Jak drama reaguje na dobu?", - "options": [ - "Ignoruje politiku", - "Varuje před fašismem a válkou (kontext 30. let)", - "Popisuje středověk", - "Sci-fi bez témat" - ], - "correct": 1, - "expl": "Čapek psal v hrozící krizi." - }, - { - "prompt": "Jak Galén jedná?", - "options": [ - "Cynicky", - "Idealisticky, chce léčit", - "Jako Maršál", - "Ne léčí" - ], - "correct": 1, - "expl": "Galén je morální protiklad moci." - }, - { - "prompt": "Co symbolizuje nemoc allegoricky?", - "options": [ - "Jen medicína", - "Nakažlivé totalitní/myšlenkové nebezpečí", - "Pouze chřipka", - "Sport" - ], - "correct": 1, - "expl": "Často čteno jako metafora fašismu." - }, - { - "prompt": "Kdy hra vyšla?", - "options": [ - "1920", - "1937", - "1948", - "2000" - ], - "correct": 1, - "expl": "Rok 1937 – před válkou." - }, - { - "prompt": "Jak končí hra typicky?", - "options": [ - "Všichni uzdraveni", - "Tragicky – válka a smrt, varování marné", - "Svatba", - "Komický tanec" - ], - "correct": 1, - "expl": "Pesimistický závěr." - }, - { - "prompt": "Které téma NENÍ klíčové?", - "options": [ - "Válka vs. humanita", - "Lékařská etika", - "Kosmické cesty", - "Politický cynismus" - ], - "correct": 2, - "expl": "Děj je zemský a politický." - }, - { - "prompt": "Kdo jsou oběti?", - "options": [ - "Jen šlechtici", - "Chudí a běžní lidé, zejména mladí", - "Jen vojáci", - "Nikdo" - ], - "correct": 1, - "expl": "Nemoc zasahuje společnost." - }, - { - "prompt": "Jak Maršál vnímá nemoc?", - "options": [ - "Chce ji okamžitě vymýtit léky", - "Využívá ji pro moc a válku", - "Odchází do kláštera", - "Stává se lékařem" - ], - "correct": 1, - "expl": "Válka je pro něj důležitější." - }, - { - "prompt": "Co Galén požaduje?", - "options": [ - "Peníze za vše", - "Nasazení léku a mír", - "Válku", - "Zákaz medicíny" - ], - "correct": 1, - "expl": "Humanitní řešení." - }, - { - "prompt": "Jaký je tón hry?", - "options": [ - "Pouze veselý", - "Satirický i tragický", - "Bez dialogu", - "Pouze lyrický" - ], - "correct": 1, - "expl": "Čapek kombinuje satiru s vážností." - }, - { - "prompt": "Souvislost s R.U.R.?", - "options": [ - "Stejný autor Čapek", - "Stejný děj", - "Obě napsal Shakespeare", - "Žádná" - ], - "correct": 0, - "expl": "Čapek napsal obě dramata." - }, - { - "prompt": "Proč je Bílá nemoc maturitní?", - "options": [ - "Nejkratší", - "České meziválečné drama s aktuálními tématy", - "Bez myšlenky", - "Pouze komedie" - ], - "correct": 1, - "expl": "Patří k Čapkovu kanonu." - }, - { - "prompt": "Kdo Galénovi brání?", - "options": [ - "Pacienti", - "Politicko-ekonomická moc", - "Jeho lék", - "Učitelé" - ], - "correct": 1, - "expl": "Systém nechce „klid“." - }, - { - "prompt": "Jak se nemoc šíří?", - "options": [ - "Jen po vodě", - "Epidemicky, panika roste", - "Jen v zimě", - "Nešíří se" - ], - "correct": 1, - "expl": "Epidemie je motiv strachu." - }, - { - "prompt": "Co Millionáři v dramatu?", - "options": [ - "Léčí", - "Reprezentují elitu indiferentní nebo zainteresovanou", - "Jsou děti", - "Neexistují" - ], - "correct": 1, - "expl": "Elita je součást kritiky." - }, - { - "prompt": "Galénův otec symbolizuje…", - "options": [ - "Válku", - "Vědeckou tradici a naději léku", - "Cirkus", - "Policii" - ], - "correct": 1, - "expl": "Odkaz otce je klíč k léku." - }, - { - "prompt": "Jaký jazyk hry?", - "options": [ - "Středověký", - "Spisovný dialog, publicistický přesah", - "Cizí bez překladu", - "Pouze pění" - ], - "correct": 1, - "expl": "Typický Čapek dialog." - }, - { - "prompt": "Co je hlavní konflikt?", - "options": [ - "Láska trojúhelník", - "Humanita (léčba) vs. moc (válka)", - "Sport", - "Rodinná komedie" - ], - "correct": 1, - "expl": "Ústřední osa." - }, - { - "prompt": "Která postava je militarista?", - "options": [ - "Galén", - "Maršál", - "Galénův pacient dítě", - "Kněz" - ], - "correct": 1, - "expl": "Maršál vede stát k válce." - }, - { - "prompt": "Jak publikum vnímalo hru v 30. letech?", - "options": [ - "Jako varování před evropskou krizí", - "Jako dětskou pohádku", - "Jako historii starověku", - "Jako vědecký manuál" - ], - "correct": 0, - "expl": "Současníci vnímali politický subtext." - }, - { - "prompt": "Co se stane s Galénem?", - "options": [ - "Stane se králem", - "Je obětí systému / tragický osud (v závislosti na inscenaci textu)", - "Emigruje bohatý", - "Zničí lék" - ], - "correct": 1, - "expl": "Galén nemůže prosadit dobro." - }, - { - "prompt": "Allegorie vs. realismus?", - "options": [ - "Hra je jen realismus bez symbolu", - "Kombinuje reálnou epidemii s politickou metaforou", - "Jen pohádka", - "Jen dokument" - ], - "correct": 1, - "expl": "Dvojí rovina významu." - }, - { - "prompt": "Jaké poselství pro maturitu?", - "options": [ - "Válka je vždy dobrá", - "Lidskost a rozum musí předcházet moci a zisku", - "Nemoci neexistují", - "Lékaři jsou zbyteční" - ], - "correct": 1, - "expl": "Humanistické varování Čapka." - }, - { - "prompt": "Žánr v katalogu maturit?", - "options": [ - "Poezie", - "Drama", - "Próza", - "Epos" - ], - "correct": 1, - "expl": "Uvedeno jako drama." - }, - { - "prompt": "Kdo není autorem Bílé nemoci?", - "options": [ - "Karel Čapek", - "Josef Čapek", - "Karel Čapek napsal hru", - "Karel Čapek dramatik" - ], - "correct": 1, - "expl": "Autor je Karel, ne Josef (byť bratři)." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Vypukne bílá nemoc a panika roste", - "Galén má lék, moc váhá kvůli válce", - "Maršál a zbrojaři tlačí na konflikt", - "Galén se snaží prosadit humanitní řešení", - "Společnost a elita lék zablokují", - "Tragický závěr – válka a smrt převažují" - ] - } - ], - "plotMeaning": [ - "Pořadí: epidemie → lék Galéna → tlak moci → boj Galéna → blokace → tragédie." - ] -} diff --git a/data/cetba/bylo-nas-pet.json b/data/cetba/bylo-nas-pet.json deleted file mode 100644 index b619e56..0000000 --- a/data/cetba/bylo-nas-pet.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Poláček", - "Žánr: humoristický autobiograficky laděný román", - "Poprvé vydáno: 1926", - "Děj/prostředí: maloměsto / venkov, rodina pěti sourozenců", - "Vyprávění/forma: ich-forma (Jaromír), humorné epizody" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "První republika, idylické dětství s stínem chudoby", - "Rodina židovského původu – Poláček pracuje s humorem i identitou", - "Škola, hřiště, sousedé – uzavřený svět dětí", - "Generace rodičů vs. děti", - "Laskavý humor místo sentimentu", - "Typické poláčkovské groteskní situace" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Jaromír – nejmladší, vypravěč", - "Sourozenci: Ondřej, Hela, Jindra, dále rodina", - "Rodiče – matka, otec, autorita i teplo domova", - "Učitelé, sousedé, kněz – venkovské typy", - "Kamarádi a spolužáci", - "Pes/circus epizody dle kapitol" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Dětství – pohled dítěte na svět", - "Humor – i z chudoby a přísnosti", - "Rodina – pět dětí, sounáležitost", - "Maloměsto – komunita, klepy", - "Škola – strach, discipline, legrace", - "Poláčkův jazyk – hovorový, vtipný" - ] - } - ], - "quiz": [ - { - "prompt": "Autor Bylo nás pět?", - "options": [ - "Viewegh", - "Poláček", - "Hašek", - "Neruda" - ], - "correct": 1, - "expl": "Karel Poláček." - }, - { - "prompt": "Kdy vyšlo?", - "options": [ - "1926", - "1945", - "1990", - "1890" - ], - "correct": 0, - "expl": "Meziválečné vydání." - }, - { - "prompt": "Kolik sourozenců?", - "options": [ - "Tři", - "Pět dětí v rodině", - "Deset", - "Jedno" - ], - "correct": 1, - "expl": "Název odkazuje na pět dětí." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Otec", - "Jaromír v ich-formě", - "Učitel", - "Vševěd" - ], - "correct": 1, - "expl": "Nejmladší bratr vypravěč." - }, - { - "prompt": "Žánr?", - "options": [ - "Tragedie", - "Humoristický román o dětství", - "Sci-fi", - "Epos" - ], - "correct": 1, - "expl": "Poláček humor." - }, - { - "prompt": "Prostředí?", - "options": [ - "Pražský palác", - "Maloměsto/rodinný domov", - "Luna", - "Moře" - ], - "correct": 1, - "expl": "Venkov/město." - }, - { - "prompt": "Tón?", - "options": [ - "Bez humoru", - "Laskavý humor, groteska", - "Horor", - "Epická vážnost" - ], - "correct": 1, - "expl": "Typický Poláček." - }, - { - "prompt": "Téma rodiny?", - "options": [ - "Chybí", - "Sounáležitost, generace, chudoba i radost", - "Jen bohatství", - "Jen válka" - ], - "correct": 1, - "expl": "Rodina je střed." - }, - { - "prompt": "Škola v knize?", - "options": [ - "Neexistuje", - "Epizody strachu a legrace", - "Jen univerzita", - "Jen internát" - ], - "correct": 1, - "expl": "Školní historky." - }, - { - "prompt": "Poláček vs. Viewegh?", - "options": [ - "Poláček meziválečí, Viewegh normalizace", - "Totéž", - "Viewegh starší", - "Poláček sci-fi" - ], - "correct": 0, - "expl": "Různá éra." - }, - { - "prompt": "Jazyk?", - "options": [ - "Archaičtina", - "Hovorový humor spisovně", - "Němčina", - "Latina" - ], - "correct": 1, - "expl": "Srozumitelná čeština." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Nejdelší", - "Klasika českého humoru a dětství", - "Cizí jazyk", - "Bez postav" - ], - "correct": 1, - "expl": "Kanón české prózy." - }, - { - "prompt": "Jaromír je…", - "options": [ - "Nejstarší", - "Nejmladší vypravěč", - "Učitel", - "Cizinec" - ], - "correct": 1, - "expl": "Perspektiva nejmladšího." - }, - { - "prompt": "Postava kněze?", - "options": [ - "Typ venkovského duchovního v epizodách", - "Hlavní hrdina války", - "Neexistuje", - "Sci-fi" - ], - "correct": 0, - "expl": "Součást maloměsta." - }, - { - "prompt": "Chudoba?", - "options": [ - "Ne", - "Prosvítá humorně, ne depresivně", - "Hlavní téma hrůzy", - "Ignorována" - ], - "correct": 1, - "expl": "Poláček neidealizuje, ale nezesmutňuje." - }, - { - "prompt": "Forma?", - "options": [ - "Drama", - "Epizodický román", - "Poezie", - "Deník bez děje" - ], - "correct": 1, - "expl": "Kapitoly epizod." - }, - { - "prompt": "Co děti zažívají?", - "options": [ - "Jen politiku", - "Hry, školu, sousedské historky", - "Jen válku", - "Nic" - ], - "correct": 1, - "expl": "Dětský svět." - }, - { - "prompt": "Groteska?", - "options": [ - "Ne", - "Ano, nadsázka situací", - "Pouze tragédie", - "Pouze básně" - ], - "correct": 1, - "expl": "Poláčkův styl." - }, - { - "prompt": "Identita autora?", - "options": [ - "Poláček židovský původ – jemně v prostředí", - "Neznámá", - "Sci-fi", - "Bez vlivu" - ], - "correct": 0, - "expl": "Kontext biografie." - }, - { - "prompt": "Sourozenci Ondřej?", - "options": [ - "Nepostava", - "Starší bratr v rodině", - "Král", - "Pes" - ], - "correct": 1, - "expl": "Součást pěti." - }, - { - "prompt": "Hela?", - "options": [ - "Sestra", - "Cizí stát", - "Učitel", - "Nemoc" - ], - "correct": 0, - "expl": "Sourozenec." - }, - { - "prompt": "Motiv domova?", - "options": [ - "Silný – bezpečí i pořádek", - "Slabý", - "Neexistuje", - "Jen hotel" - ], - "correct": 0, - "expl": "Domov jako centrum." - }, - { - "prompt": "Kdo NENÍ Poláček?", - "options": [ - "Autor humoru", - "Autor Bylo nás pět", - "Hašek autor této knihy", - "Spisovatel" - ], - "correct": 2, - "expl": "Hašek psal Švejka." - }, - { - "prompt": "Vyprávěcí forma?", - "options": [ - "Er", - "Ich (Jaromír)", - "Druhá osoba", - "Bez vypravěče" - ], - "correct": 1, - "expl": "Dětské já." - }, - { - "prompt": "Cíl humoru?", - "options": [ - "Ponižovat děti", - "Humanizovat dětství a rodinu", - "Propaganda", - "Strach" - ], - "correct": 1, - "expl": "Laskavost." - }, - { - "prompt": "Epizoda s psem/cirkusem?", - "options": [ - "Typické kapitoly maloměstského života", - "Ne v knize", - "Jen ve filmu", - "Sci-fi" - ], - "correct": 0, - "expl": "Maloměstské epizody." - }, - { - "prompt": "Období děje?", - "options": [ - "Středověk", - "Meziválečí / Poláčkovo dětství", - "Budoucnost", - "Antika" - ], - "correct": 1, - "expl": "Autobiografické prvky." - }, - { - "prompt": "Proč ich-forma?", - "options": [ - "Autenticita dětského pohledu", - "Náhodou", - "Pouze u Poláčka zakázáno", - "Kvůli překladu" - ], - "correct": 0, - "expl": "Dítě vidí jinak." - }, - { - "prompt": "Konec knihy?", - "options": [ - "Epizodický, bez jedné akce", - "Jedna bitva", - "Svatba Jaromíra", - "Apokalypsa" - ], - "correct": 0, - "expl": "Koláž vzpomínek." - }, - { - "prompt": "Poselství?", - "options": [ - "Dětství a rodina stojí za humorné vyprávění", - "Rodina škodí", - "Humor je hřích", - "Děti neposlouchat" - ], - "correct": 0, - "expl": "Teplo a humor." - }, - { - "prompt": "Žánr v katalogu?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Rok vydání 1926 znamená?", - "options": [ - "Meziválečná literatura", - "Normalizace", - "Socialismus 50. let", - "Středověk" - ], - "correct": 0, - "expl": "První republika kontext." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Rodina pěti dětí v maloměstě", - "Jaromírovy školní a domácí epizody", - "Humorné situace se sousedy a učiteli", - "Sourozenecké hry a drobné konflikty", - "Rodiče udržují domov navzdory chudobě", - "Dětství jako koláž vzpomínek" - ] - } - ], - "plotMeaning": [ - "Pořadí: rodina → škola/domov → sousedé → sourozenci → rodiče → vzpomínkový celek." - ] -} diff --git a/data/cetba/cekani-na-godota.json b/data/cetba/cekani-na-godota.json deleted file mode 100644 index 86f2376..0000000 --- a/data/cetba/cekani-na-godota.json +++ /dev/null @@ -1,410 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Samuel Beckett", - "Žánr: drama absurdní", - "Poprvé vydáno: 1952 (fr. En attendant Godot)", - "Děj/prostředí: neurčená krajina, strom, silnice", - "Vyprávění/forma: dialog dvou postav, minimální děj, český překlad Ouředník" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Poválečný existencialismus, ztráta smyslu", - "Absurdita života – čekání bez výsledku", - "Bez historického konkrétna – univerzální situace", - "Chudoba, triviální rozhovory, rutina", - "Godot nepřichází – nedosažitelná naděje", - "Vliv na divadlo 20. století" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Vladimír (Didi) – rozvážnější z dvojice", - "Estragon (Gogo) – fyzicky slabší, bolesti nohou", - "Pozzo – pán, vede na provaze Lucka", - "Lucky – nosič, „myslí“ v monologu", - "Chlapec – posel od Godota, Godot nepřijde", - "Godot – nikdy se neobjeví" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Čekání – metafora lidského stavu", - "Absurdita – opakování bez pointy", - "Strom – skromná krajina, listí v druhém dějství", - "Pomoc – Didi a Gogo si navzájem (boty, jídlo)", - "Čas – věty „najednou je večer“", - "Smysl života – otázka bez odpovědi" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Beckett", - "Ionesco", - "Shakespeare", - "Čapek" - ], - "correct": 0, - "expl": "Samuel Beckett." - }, - { - "prompt": "Žánr?", - "options": [ - "Opera", - "Absurdní drama", - "Epos", - "Detektivka" - ], - "correct": 1, - "expl": "Klíčové dílo absurdního divadla." - }, - { - "prompt": "Kolik dějství?", - "options": [ - "Jedno", - "Dvě (opakující se struktura)", - "Pět", - "Deset" - ], - "correct": 1, - "expl": "Dvě dějství podobně." - }, - { - "prompt": "Kdo čeká?", - "options": [ - "Hamlet", - "Vladimír a Estragon", - "Godot sám", - "Nikdo" - ], - "correct": 1, - "expl": "Dvojice tramps." - }, - { - "prompt": "Přijde Godot?", - "options": [ - "Ano hned", - "Ne (aspoň v průběhu hry)", - "Ano v epilogu", - "Je to Estragon" - ], - "correct": 1, - "expl": "Godot je nedosažitelný." - }, - { - "prompt": "Kde se děj odehrává?", - "options": [ - "Paříž salón", - "Silnice u stromu", - "Luna", - "Praha" - ], - "correct": 1, - "expl": "Minimalistické jeviště." - }, - { - "prompt": "Kdo je Pozzo?", - "options": [ - "Bůh", - "Pán vedoucí Lucka na provaze", - "Kněz", - "Hasič" - ], - "correct": 1, - "expl": "Objeví se v obou dějstvích." - }, - { - "prompt": "Lucky?", - "options": [ - "Král", - "Nosič Pozzova, monolog", - "Godot", - "Strom" - ], - "correct": 1, - "expl": "Slavný chaotický monolog." - }, - { - "prompt": "Rok premiéry?", - "options": [ - "1850", - "1952", - "1989", - "1600" - ], - "correct": 1, - "expl": "1952 Paříž." - }, - { - "prompt": "Jazyk hry?", - "options": [ - "Bez slov", - "Triviální dialog, filozofické otázky", - "Pouze zpěv", - "Latina" - ], - "correct": 1, - "expl": "Paradox hluboké banality." - }, - { - "prompt": "Co dělají Didi a Gogo?", - "options": [ - "Válka", - "Čekají, hádají se, hraje hry", - "Pilí zlato", - "Učí školu" - ], - "correct": 1, - "expl": "Rutina čekání." - }, - { - "prompt": "Chlapec?", - "options": [ - "Přináší zprávu od Godota", - "Zabije Pozza", - "Je Godot", - "Neexistuje" - ], - "correct": 0, - "expl": "Posel." - }, - { - "prompt": "Strom v druhém dějství?", - "options": [ - "Mizí", - "Má listí – čas uběhl", - "Hoří", - "Promění se v dům" - ], - "correct": 1, - "expl": "Jediná změna prostředí." - }, - { - "prompt": "Téma absurdního divadla?", - "options": [ - "Jasný happy end", - "Smysl života nejistý, opakování", - "Historická přesnost", - "Pouze komedie slapstick" - ], - "correct": 1, - "expl": "Existenciální prázdnota." - }, - { - "prompt": "Beckett – národnost?", - "options": [ - "Irsko / psal francouzsky i anglicky", - "Jen český", - "Jen ruský", - "Jen německý" - ], - "correct": 0, - "expl": "Irský autor." - }, - { - "prompt": "Překlad maturita?", - "options": [ - "Ouředník", - "Nevrla", - "Nezval", - "Gössell" - ], - "correct": 0, - "expl": "V katalogu Ouředník." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Nejdelší", - "Zásadní drama 20. stol.", - "Bez významu", - "Pouze film" - ], - "correct": 1, - "expl": "Kanón světového divadla." - }, - { - "prompt": "Godot symbol?", - "options": [ - "Konkrétní člověk", - "Naděje/Bůh/smysl, který nepřijde", - "Strom", - "Pes" - ], - "correct": 1, - "expl": "Interpretace otevřená." - }, - { - "prompt": "Opakování dějství?", - "options": [ - "Stejná struktura – absurdita rutiny", - "Totálně jiný děj", - "Jen jedno", - "Opera" - ], - "correct": 0, - "expl": "Cyklus čekání." - }, - { - "prompt": "Estragonovy boty?", - "options": [ - "Epizoda pomoci a starosti", - "Nezmíněny", - "Hlavní zbraň", - "Godot" - ], - "correct": 0, - "expl": "Lidská péče v prázdnu." - }, - { - "prompt": "Pozzo slepne?", - "options": [ - "Ve druhém dějství – křehkost moci", - "Ne", - "Hned na začátku", - "Lucky" - ], - "correct": 0, - "expl": "Proměna postav." - }, - { - "prompt": "Monolog Luckyho?", - "options": [ - "Chaotická „věda“ a rétorika", - "Krátké ano", - "Zpěv opery", - "Mlčení" - ], - "correct": 0, - "expl": "Satira slov." - }, - { - "prompt": "Vladimír vs Estragon?", - "options": [ - "Didi víc přemýšlí, Gogo fyzicky trpí", - "Totéž", - "Jsou bratři králové", - "Nepřátelé" - ], - "correct": 0, - "expl": "Doplňují se." - }, - { - "prompt": "Konflikt?", - "options": [ - "Bitva", - "Spíš vnitřní – nuda, strach, čekání", - "Detektivní", - "Soudní" - ], - "correct": 1, - "expl": "Minimum vnějšího děje." - }, - { - "prompt": "Konec hry?", - "options": [ - "Godot přijde", - "Opět rozhodnutí odejít a zůstat čekat", - "Svatba", - "Válka" - ], - "correct": 1, - "expl": "Otevřený cyklus." - }, - { - "prompt": "Ionesco vs Beckett?", - "options": [ - "Obě absurdní drama, jiná díla", - "Totéž kniha", - "Ionesco napsal Godota", - "Beckett Revizor" - ], - "correct": 0, - "expl": "Stejný směr, jiní autoři." - }, - { - "prompt": "Co NENÍ v Godotovi?", - "options": [ - "Dialog", - "Čekání", - "Epická bitva", - "Strom" - ], - "correct": 2, - "expl": "Bez epické akce." - }, - { - "prompt": "Poselství?", - "options": [ - "Život může být čekáním bez jistoty", - "Vždy přijde spása", - "Čekání zbytečné vůbec neřešit", - "Godot je hrdina" - ], - "correct": 0, - "expl": "Existenciální otázka." - }, - { - "prompt": "Forma?", - "options": [ - "Báseň", - "Divadelní hra", - "Román", - "Esej" - ], - "correct": 1, - "expl": "Drama." - }, - { - "prompt": "Titulní jméno Godot?", - "options": [ - "Vyslovuje se, nikdo nepřichází", - "Hlavní mluvící postava", - "Strom", - "Pes" - ], - "correct": 0, - "expl": "Absence je pointa." - }, - { - "prompt": "Druhé dějství podobné prvnímu?", - "options": [ - "Ano – opakování s malými změnami", - "Ne", - "Je to operní finále", - "Je kratší o polovinu" - ], - "correct": 0, - "expl": "Struktura absurdní rutiny." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Vladimír a Estragon čekají u stromu", - "Přicházejí Pozzo a Lucky", - "Monolog a rozhovory, Godot nejde", - "Chlapec: Godot nepřijde zítra", - "Druhé dějství – opět čekání", - "Rozhodnutí odejít, ale zůstávají v cyklu" - ] - } - ], - "plotMeaning": [ - "Pořadí: čekání → Pozzo/Lucky → zpráva → druhé dějství → opakování → cyklus čekání." - ] -} diff --git a/data/cetba/ceske-nebe.json b/data/cetba/ceske-nebe.json deleted file mode 100644 index 0518cde..0000000 --- a/data/cetba/ceske-nebe.json +++ /dev/null @@ -1,410 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autoři: Zdeněk Svěrák, Ladislav Smoljak", - "Žánr: komické drama / fraška", - "Poprvé vydáno: 1976 (Divadlo Jára Cimrmana)", - "Děj/prostředí: parodické dějiny českého nebe", - "Vyprávění/forma: divadelní scény, humor, pastiše" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Normalizace – ne přímá politika, ale metafora", - "„Nebe“ jako symbol vlasti / duchovního prostoru", - "Groteskní historie od pradávna po modernu", - "Cimrmanovský styl – pseudovědecký humor", - "Satira na národní mýty a malost", - "Spolupráce Svěrák–Smoljak" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Jára Cimrman – „největší Čech“, v této hře v roli vypravěče/historika", - "Různí historičtí komici typy", - "Postavy z parodovaných dějin", - "Ensemble divadla", - "Vědci a vynálezci groteskně", - "Kolektivní humor bez jednoho hrdiny" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Parodie dějin – české nebe jako téma", - "Cimrman – fiktivní génius", - "Národní identita s nadsázkou", - "Divadelní fraška – rychlé gagy", - "Smoljak/Svěrák dialog", - "Nebe vs. realita země" - ] - } - ], - "quiz": [ - { - "prompt": "Autoři?", - "options": [ - "Svěrák a Smoljak", - "Čapek bratři", - "Shakespeare", - "Viewegh" - ], - "correct": 0, - "expl": "Dvojice autorů Cimrmanova divadla." - }, - { - "prompt": "Žánr?", - "options": [ - "Tragedie", - "Komické drama / fraška", - "Epos", - "Sci-fi" - ], - "correct": 1, - "expl": "Humor divadla Jára Cimrmana." - }, - { - "prompt": "Co je „české nebe“?", - "options": [ - "Meteorologický atlas", - "Parodické téma o české zemi a duchu", - "Bible", - "Učebnice" - ], - "correct": 1, - "expl": "Metafora vlasti v grotesce." - }, - { - "prompt": "Kdy hra vznikla?", - "options": [ - "1890", - "1976", - "2000", - "1942" - ], - "correct": 1, - "expl": "Součást Cimrmanova divadla." - }, - { - "prompt": "Jára Cimrman?", - "options": [ - "Skutečný král", - "Fiktivní český génius divadla", - "Hasič", - "Německý spisovatel" - ], - "correct": 1, - "expl": "Centrální postava značky." - }, - { - "prompt": "Styl humoru?", - "options": [ - "Bez vtipu", - "Pseudověda, paradox, groteska", - "Pouze tragédie", - "Horor" - ], - "correct": 1, - "expl": "Typické Cimrmanovo." - }, - { - "prompt": "Divadlo?", - "options": [ - "Národní bez Smoljaka", - "Divadlo Jára Cimrmana", - "Broadway", - "Antika" - ], - "correct": 1, - "expl": "Základní kontext." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Nejkratší", - "České drama konce 20. stol., kultura", - "Anglicky", - "Bez textu" - ], - "correct": 1, - "expl": "Reprezentuje českou komedii." - }, - { - "prompt": "Parodie?", - "options": [ - "Vážná historie bez nadsázky", - "Nadsázka českých dějin a mýtů", - "Jen sci-fi", - "Jen poezie" - ], - "correct": 1, - "expl": "Historie jako gag." - }, - { - "prompt": "Smoljak role?", - "options": [ - "Spoluautor", - "Nepiš", - "Shakespeare", - "Překladatel Godota" - ], - "correct": 0, - "expl": "Spolu se Svěrákm." - }, - { - "prompt": "Svěrák role?", - "options": [ - "Spoluautor", - "Victor Hugo", - "Beckett", - "Nezval" - ], - "correct": 0, - "expl": "Spoluautor." - }, - { - "prompt": "Tón?", - "options": [ - "Pouze smutek", - "Lehkost, wordplay", - "Naturalismus", - "Operní" - ], - "correct": 1, - "expl": "Komický dialog." - }, - { - "prompt": "Politický subtext?", - "options": [ - "Groteska může metaforicky reagovat na éru", - "Přímý manifest", - "Ne", - "Jen válka" - ], - "correct": 0, - "expl": "Normalizační kontext jemně." - }, - { - "prompt": "Forma?", - "options": [ - "Román", - "Divadelní hra", - "Báseň", - "Esej" - ], - "correct": 1, - "expl": "Drama v katalogu." - }, - { - "prompt": "Postavy historické?", - "options": [ - "Groteskně parodované", - "Přesně dokumentární", - "Chybí", - "Jen cizinci" - ], - "correct": 0, - "expl": "Ne učebnice." - }, - { - "prompt": "Cílové publikum?", - "options": [ - "Diváci divadla, maturanti", - "Jen děti", - "Jen vědci", - "Nikdo" - ], - "correct": 0, - "expl": "Divadelní text." - }, - { - "prompt": "Co NENÍ Cimrman?", - "options": [ - "Značka divadla", - "Fiktivní postava", - "Reálný panovník", - "Humor" - ], - "correct": 2, - "expl": "Cimrman není reálná historická osoba." - }, - { - "prompt": "České nebe vs Vyšetřování ztráty třídní knihy?", - "options": [ - "Obě Smoljak/Svěrák", - "Obě Shakespeare", - "Stejný název", - "Obě poezie" - ], - "correct": 0, - "expl": "Stejný autorský tým." - }, - { - "prompt": "Jazyk?", - "options": [ - "Středověká čeština bez humoru", - "Spisovná čeština, vtipné repliky", - "Němčina", - "Latina" - ], - "correct": 1, - "expl": "Srozumitelný humor." - }, - { - "prompt": "Hlavní děj?", - "options": [ - "Lineární válka", - "Souvislý skečový průběh parodie nebe/dějin", - "Detektivka", - "Lyrika" - ], - "correct": 1, - "expl": "Fraškovitá stavba." - }, - { - "prompt": "Smysl nebe v titulu?", - "options": [ - "Astronomie", - "Symbol vlasti a duchovního", - "Jen počasí", - "Cizina" - ], - "correct": 1, - "expl": "Metafora." - }, - { - "prompt": "Inscenace?", - "options": [ - "Původně DJC Žižkov", - "Globe London", - "Antika", - "Jen radio" - ], - "correct": 0, - "expl": "Cimrmanovo divadlo." - }, - { - "prompt": "Vztah k historii?", - "options": [ - "Respekt bez vtipu", - "Hra s historií, ne lekce", - "Přesný učebnicový text", - "Zakázaná" - ], - "correct": 1, - "expl": "Parodie." - }, - { - "prompt": "Ensemble?", - "options": [ - "Jeden herec", - "Soubor postav / herecký soubor", - "Pouze orchestr", - "Film" - ], - "correct": 1, - "expl": "Divadelní forma." - }, - { - "prompt": "Maturita – co znát?", - "options": [ - "Autory, žánr, Cimrman, parodii", - "Jen rok 1066", - "Jen anglicky", - "Nic" - ], - "correct": 0, - "expl": "Základní kontext." - }, - { - "prompt": "Groteska?", - "options": [ - "Ano", - "Ne", - "Jen tragédie", - "Jen dokument" - ], - "correct": 0, - "expl": "Cimrman styl." - }, - { - "prompt": "Konec hry?", - "options": [ - "Komické finále ve stylu souboru", - "Hamletova smrt", - "Bitva", - "Ticho" - ], - "correct": 0, - "expl": "Fraška." - }, - { - "prompt": "Poselství?", - "options": [ - "Humor o identitě bez pompy", - "Nacionalismus vážně", - "Nenávist", - "Bez témat" - ], - "correct": 0, - "expl": "Sebeironie národa." - }, - { - "prompt": "Katalog žánr?", - "options": [ - "Drama", - "Poezie", - "Próza", - "Opera" - ], - "correct": 0, - "expl": "Drama." - }, - { - "prompt": "Rok 1976?", - "options": [ - "Normalizace", - "Středověk", - "Budoucnost", - "1848" - ], - "correct": 0, - "expl": "Kontext vzniku." - }, - { - "prompt": "Typická replika styl?", - "options": [ - "Dlouhá pseudovědecká úvaha s pointou", - "Bez dialogu", - "Jen pění", - "Latinská mše" - ], - "correct": 0, - "expl": "Cimrmanovský projev." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Uvedení do parodie „českého nebe“", - "Groteskní obrazy dějin", - "Cimrmanovské výklady a gagy", - "Satira na národní mýty", - "Souborové scénky", - "Komické finále frašky" - ] - } - ], - "plotMeaning": [ - "Pořadí: úvod → parodie dějin → gagy → satira → scénky → finále." - ] -} diff --git a/data/cetba/chram-matky-bozi.json b/data/cetba/chram-matky-bozi.json deleted file mode 100644 index 7331e48..0000000 --- a/data/cetba/chram-matky-bozi.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Victor Hugo", - "Žánr: historicko-romantický román", - "Poprvé vydáno: 1831", - "Děj/prostředí: Paříž 15. století, katedrála Notre-Dame", - "Vyprávění/forma: er-forma, historické vsuvky; překlad Tomášková" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Středověk, lidová slavnost i násilí", - "Církev a městská moc", - "Outsideri společnosti", - "Architektura jako hrdina", - "Láska, žárlivost, osud", - "Romantismus 19. st. pohled na minulost" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Quasimodo – zvoník, hrbáč", - "Esmeralda – cikánská tanečnice", - "Claude Frollo – arciděkan, posedlost", - "Phoebus – kapitán, svůdník", - "Gringoire – básník", - "Jehan Frollo – bratr Claude" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Katedrála – symbol dobra a útočiště", - "Quasimodo – vnější ošklivost, vnitřní dobro", - "Esmeralda – oběť předsudků", - "Frollo – posedlost a zlo", - "Soud a poprava", - "Gotická architektura" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Hugo", - "Dickens", - "Zola", - "Flaubert" - ], - "correct": 0, - "expl": "Victor Hugo." - }, - { - "prompt": "Rok?", - "options": [ - "1831", - "1862", - "1600", - "2000" - ], - "correct": 0, - "expl": "Romantismus." - }, - { - "prompt": "Katedrála?", - "options": [ - "Notre-Dame Paříž", - "Praha", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Titul." - }, - { - "prompt": "Quasimodo?", - "options": [ - "Zvoník hrbáč", - "Kněz", - "Král", - "Ne" - ], - "correct": 0, - "expl": "Hrdina." - }, - { - "prompt": "Esmeralda?", - "options": [ - "Cikánská tanečnice", - "Kněžka", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Oběť." - }, - { - "prompt": "Frollo?", - "options": [ - "Arciděkan posedlý Esmeraldou", - "Quasimodo", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Antagonista." - }, - { - "prompt": "Phoebus?", - "options": [ - "Kapitán, svůdník", - "Zvoník", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Gringoire?", - "options": [ - "Básník, manžel Esmeraldy formálně", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Quasimodo chrání?", - "options": [ - "Esmeraldu v katedrále", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Útočiště." - }, - { - "prompt": "Konec Esmeralda?", - "options": [ - "Poprava", - "Královna", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Tragédie." - }, - { - "prompt": "Konec Quasimoda?", - "options": [ - "Umírá u Esmeraldy", - "Král", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Láska." - }, - { - "prompt": "Konec Frolla?", - "options": [ - "Smrt", - "Svatba", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Pád." - }, - { - "prompt": "Překlad?", - "options": [ - "Tomášková", - "Pavlousková", - "Nezval", - "Nevrla" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "Bídníci Hugo?", - "options": [ - "Jiný román 1862", - "Totéž", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Různá díla." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasika romantismu", - "Nejkratší", - "Bez smyslu", - "Ne" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Quasimodo", - "Esmeralda", - "Hamlet", - "Frollo" - ], - "correct": 2, - "expl": "Shakespeare." - }, - { - "prompt": "Gotika?", - "options": [ - "Architektura i atmosféra", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Cikáni?", - "options": [ - "Předsudky společnosti", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Téma." - }, - { - "prompt": "Er-forma?", - "options": [ - "Ano", - "Ich", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Paříž 15. st?", - "options": [ - "Historické pozadí", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Setting." - }, - { - "prompt": "Zvon?", - "options": [ - "Quasimodo zvoní", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Symbol." - }, - { - "prompt": "Soud Esmeralda?", - "options": [ - "Křivé obvinění", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Nespravedlnost." - }, - { - "prompt": "Phoebus žije?", - "options": [ - "Přežije cynicky", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Kontrast." - }, - { - "prompt": "Katalog?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Romantismus?", - "options": [ - "Směr autora", - "Realismus", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "19. st." - }, - { - "prompt": "Architektura?", - "options": [ - "Hugo obdiv ke katedrále", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Téma." - }, - { - "prompt": "Poselství?", - "options": [ - "Předsudky ničí, krása duše counts", - "Vzhled vše", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Humanita." - }, - { - "prompt": "Disney?", - "options": [ - "Adaptace existuje", - "Ne", - "Zakázáno", - "Ne" - ], - "correct": 0, - "expl": "Kultura." - }, - { - "prompt": "Jehan?", - "options": [ - "Bratr Frolla, piják", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Utok na katedrálu?", - "options": [ - "Quasimodo brání", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Scéna." - }, - { - "prompt": "Titul CZ?", - "options": [ - "Chrám Matky Boží", - "Bídníci", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Notre-Dame." - }, - { - "prompt": "Hugo národnost?", - "options": [ - "Francouz", - "Čech", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Francie." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Gringoire a Esmeralda ve středověké Paříži", - "Frollo se zamiluje do Esmeraldy", - "Quasimodo ji zachrání do chrámu", - "Soud a odsouzení Esmeraldy", - "Poprava a Quasimodo brání marně", - "Smrt hlavních postav u katedrály" - ] - } - ], - "plotMeaning": [ - "Pořadí: setkání → Frollo → útočiště → soud → poprava → smrt u chrámu." - ] -} diff --git a/data/cetba/dekameron.json b/data/cetba/dekameron.json deleted file mode 100644 index c002634..0000000 --- a/data/cetba/dekameron.json +++ /dev/null @@ -1,410 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Giovanni Boccaccio", - "Žánr: próza – sbírka novel (100 příběhů)", - "Poprvé vydáno: kolem 1350", - "Děj/prostředí: Florencie, morová rána, venkovský únik", - "Vyprávění/forma: rámcový příběh + jednotlivé novely, překlad Krátký" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Itálie 14. století, mor, společenská krize", - "Deset mládenců a mladenek odchází na venkov", - "Deset dní – každý den deset novel (100)", - "Světskost, humor, láska, lstivost", - "Kritika církve a měšťanů", - "Humanismus rané renesance" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Pampinea, Fiammetta, Filostrato aj. – vypravěči", - "Deset postav v rámcovém příběhu", - "Hrdinové jednotlivých novel – měšťané, kněží, milenci", - "Často chytré ženy a podvodníci", - "Rámcový narrátor kolektiv", - "Typy středověké společnosti" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Rámec – únik před morem", - "100 novel – rozmanitost života", - "Láska a erotika (místy provokativní)", - "Rozum a lest – přechytračení", - "Fortuna – štěstí/neštěstí", - "Renesanční světskost" - ] - } - ], - "quiz": [ - { - "prompt": "Autor Dekameronu?", - "options": [ - "Dante", - "Boccaccio", - "Petrarca", - "Shakespeare" - ], - "correct": 1, - "expl": "Giovanni Boccaccio." - }, - { - "prompt": "Kdy vznik?", - "options": [ - "1350 kolem", - "1800", - "1900", - "500 př. n. l." - ], - "correct": 0, - "expl": "Středověká renesance." - }, - { - "prompt": "Kolik novel?", - "options": [ - "10", - "100", - "1000", - "1" - ], - "correct": 1, - "expl": "Deset dní po deseti." - }, - { - "prompt": "Rámec?", - "options": [ - "Bitva", - "Únik Florencie před morem na venkov", - "Luna", - "Praha" - ], - "correct": 1, - "expl": "Mor jako rámec." - }, - { - "prompt": "Kolik vypravěčů v rámu?", - "options": [ - "Deset mladých", - "Jeden král", - "Sto", - "Nikdo" - ], - "correct": 0, - "expl": "5 mužů, 5 žen typicky." - }, - { - "prompt": "Žánr?", - "options": [ - "Epos", - "Sbírka novel s rámcem", - "Drama", - "Poezie" - ], - "correct": 1, - "expl": "Novelistický cyklus." - }, - { - "prompt": "Jazyk originálu?", - "options": [ - "Latina", - "Italština (vernacular)", - "Řečtina", - "Francouzština" - ], - "correct": 1, - "expl": "Vernakulární italština." - }, - { - "prompt": "Téma novel?", - "options": [ - "Pouze válka", - "Láska, lest, humor, společnost", - "Pouze náboženství", - "Pouze sci-fi" - ], - "correct": 1, - "expl": "Rozmanitost." - }, - { - "prompt": "Překlad maturita?", - "options": [ - "Krátký", - "Nezval", - "Nevrla", - "Skoumal" - ], - "correct": 0, - "expl": "V katalogu Krátký." - }, - { - "prompt": "Florencie?", - "options": [ - "Místo moru a odchodu", - "Nezmíněna", - "Pouze vesnice", - "Amerika" - ], - "correct": 0, - "expl": "Historická Florencie." - }, - { - "prompt": "Humanismus?", - "options": [ - "Světský zájem o člověka", - "Ne", - "Pouze teologie", - "Stoicismus" - ], - "correct": 0, - "expl": "Renesanční přístup." - }, - { - "prompt": "Satira?", - "options": [ - "Na kněze, měšťany, lidské slabosti", - "Ne", - "Pouze na krále", - "Zakázaná" - ], - "correct": 0, - "expl": "Často kritické." - }, - { - "prompt": "Fortuna?", - "options": [ - "Motiv štěstí/osudu v příbězích", - "Postava Godota", - "Ne", - "Jen město" - ], - "correct": 0, - "expl": "Středověký motiv." - }, - { - "prompt": "Erotika?", - "options": [ - "Součást některých novel", - "Neexistuje", - "Celá kniha bez lásky", - "Zakázáno" - ], - "correct": 0, - "expl": "Provokativní pro dobu." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasika světové prózy", - "Nejkratší", - "Bez rámce", - "Jen české" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Dante vs Boccaccio?", - "options": [ - "Obě italské, různá díla", - "Totéž", - "Boccaccio Božská komedie", - "Dante Dekameron" - ], - "correct": 0, - "expl": "Trecento literatura." - }, - { - "prompt": "Struktura dne?", - "options": [ - "10 novel denně", - "1 ročně", - "100 denně", - "0" - ], - "correct": 0, - "expl": "Deset dní." - }, - { - "prompt": "Pampinea?", - "options": [ - "Jedna z vypravěček v rámu", - "Mor", - "Město", - "Pes" - ], - "correct": 0, - "expl": "Jméno v rámu." - }, - { - "prompt": "Venkovské sídlo?", - "options": [ - "Útočiště před morem", - "Vězení", - "Boj", - "Nebe" - ], - "correct": 0, - "expl": "Kontext rámce." - }, - { - "prompt": "Novela vs román?", - "options": [ - "Kratší příběh v souboru", - "Totéž", - "Pouze báseň", - "Epos" - ], - "correct": 0, - "expl": "Forma." - }, - { - "prompt": "Kritika církve?", - "options": [ - "Ano v některých příbězích", - "Ne", - "Pouze chvála", - "Zakázáno" - ], - "correct": 0, - "expl": "Světský pohled." - }, - { - "prompt": "Renesance?", - "options": [ - "Raná renesance Itálie", - "Baroko", - "Romantismus", - "Existencialismus" - ], - "correct": 0, - "expl": "Období." - }, - { - "prompt": "Vyprávění v rámu?", - "options": [ - "Střídání vypravěčů po dnech", - "Jeden monolog", - "Bez slov", - "Opera" - ], - "correct": 0, - "expl": "Organizace." - }, - { - "prompt": "Co NENÍ Dekameron?", - "options": [ - "100 novel", - "Rámec s morem", - "Shakespearova tragédie", - "Italská próza" - ], - "correct": 2, - "expl": "Shakespeare jinak." - }, - { - "prompt": "Laskavý humor?", - "options": [ - "Často", - "Nikdy", - "Pouze horor", - "Pouze epos" - ], - "correct": 0, - "expl": "Lehkost i drsnost." - }, - { - "prompt": "Petrarca?", - "options": [ - "Současník, jiná díla", - "Autor Dekameronu", - "Čech", - "Beckett" - ], - "correct": 0, - "expl": "Kontext trecenta." - }, - { - "prompt": "Poselství?", - "options": [ - "Život je rozmanitý – příběhy mapují společnost", - "Jen mor", - "Jen válka", - "Bez smyslu" - ], - "correct": 0, - "expl": "Encyklopedie příběhů." - }, - { - "prompt": "Krátký překlad?", - "options": [ - "Český překlad v maturitě", - "Anglický autor", - "Neexistuje", - "Latina" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "Žánr katalog?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Rámec končí?", - "options": [ - "Návrat do města po moru", - "Válka", - "Apokalypsa", - "Ne" - ], - "correct": 0, - "expl": "Uzavření úniku." - }, - { - "prompt": "Typ hrdinky?", - "options": [ - "Často chytrá, aktivní žena", - "Pouze pasivní", - "Neexistuje", - "Jen král" - ], - "correct": 0, - "expl": "Renesanční typy." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Mor sužuje Florencii", - "Deset mladých odchází na venkov", - "Každý den vyprávějí novely", - "Střídání témat lásky a lsti", - "Deset dní po deseti příbězích", - "Návrat k životu po krizi" - ] - } - ], - "plotMeaning": [ - "Pořadí: mor → únik → vyprávění → témata → 100 novel v rámci → konec úniku." - ] -} diff --git a/data/cetba/den-trifidu.json b/data/cetba/den-trifidu.json deleted file mode 100644 index ad98a59..0000000 --- a/data/cetba/den-trifidu.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: John Wyndham", - "Žánr: postapokalyptický sci-fi román", - "Poprvé vydáno: 1951", - "Děj/prostředí: Británie po katastrofě, rostliny trifidy", - "Vyprávění/forma: er-forma, Bill Masen vypravěč; překlad Kořán" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Meteoritní roj oslepí většinu lidí", - "Trifidy – mobilní rostliny zabíjí slepé", - "Kolaps civilizace, boj o přežití", - "Malé komunity vs. chaos", - "Vědecké vysvětlení vs. nábožný strach", - "Otázka adaptace lidstva" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Bill Masen – biolog, přežije se zavázanýma očima", - "Josella – spisovatelka, partnerka", - "Coker – realista, organizátor", - "Colonel Jacques – vojenský vůdce", - "Děti a uprchlici", - "Trifidy jako „protivník“" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Trifidy – jedovaté lana, pohybují se", - "Slepota – masová katastrofa", - "Ostrov – únik a nový začátek", - "Sebeobrana a morálka", - "Sci-fi realismus Wyndhama", - "Příroda pomstychtivá" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Wyndham", - "Bradbury", - "Orwell", - "Collins" - ], - "correct": 0, - "expl": "John Wyndham." - }, - { - "prompt": "Rok?", - "options": [ - "1951", - "1984", - "2000", - "1890" - ], - "correct": 0, - "expl": "Poválečné sci-fi." - }, - { - "prompt": "Co jsou trifidy?", - "options": [ - "Ptáci", - "Mobilní rostliny s jedovatými lashmi", - "Lidé", - "Auta" - ], - "correct": 1, - "expl": "Uměle vyšlechtěné rostliny." - }, - { - "prompt": "Proč většina oslepne?", - "options": [ - "Válka", - "Sledování zeleného meteorického roje", - "Mor", - "Hlad" - ], - "correct": 1, - "expl": "Klíčová katastrofa." - }, - { - "prompt": "Hrdina Bill?", - "options": [ - "Biolog se zavázanýma očima v nemocnici", - "Hasič", - "Král", - "Trifid" - ], - "correct": 0, - "expl": "Přežije díky obvazům." - }, - { - "prompt": "Josella?", - "options": [ - "Partnerka, spisovatelka", - "Trifid", - "Generál", - "Neexistuje" - ], - "correct": 0, - "expl": "Důležitá postava." - }, - { - "prompt": "Coker?", - "options": [ - "Organizátor přeživších", - "Trifid", - "Dítě", - "Meteor" - ], - "correct": 0, - "expl": "Pragmatik." - }, - { - "prompt": "Kolonel?", - "options": [ - "Vojenský vůdce komunity", - "Rostlina", - "Billův bratr", - "Kněz" - ], - "correct": 0, - "expl": "Struktura moci." - }, - { - "prompt": "Žánr?", - "options": [ - "Postapokalyptické sci-fi", - "Pohádka", - "Epos", - "Lyrika" - ], - "correct": 0, - "expl": "Katastrofa + věda." - }, - { - "prompt": "Překlad?", - "options": [ - "Kořán", - "Nezval", - "Nevrla", - "Skoumal" - ], - "correct": 0, - "expl": "Katalog Kořán." - }, - { - "prompt": "Prostředí?", - "options": [ - "Británie", - "Pouze Mars", - "Praha", - "Antarktida" - ], - "correct": 0, - "expl": "Anglie." - }, - { - "prompt": "Trifidy proč nebezpečné?", - "options": [ - "Jed a pohyb", - "Jen hezké", - "Nejsou", - "Zpívají" - ], - "correct": 0, - "expl": "Zabíjejí slepé." - }, - { - "prompt": "Ostrov na konci?", - "options": [ - "Naděje na adaptaci lidstva", - "Ne v knize", - "Smrt všech", - "Trifidí království" - ], - "correct": 0, - "expl": "Finále na ostrově." - }, - { - "prompt": "Téma?", - "options": [ - "Přežití, morálka, příroda", - "Jen láska", - "Jen sport", - "Středověk" - ], - "correct": 0, - "expl": "Katastrofický román." - }, - { - "prompt": "Wyndham styl?", - "options": [ - "Realistické sci-fi", - "Pouze fantasy", - "Bez děje", - "Poezie" - ], - "correct": 0, - "expl": "„Logical disaster“." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasické sci-fi", - "Nejkratší", - "Bez témat", - "Jen film" - ], - "correct": 0, - "expl": "Kanón žánru." - }, - { - "prompt": "Bill v nemocnici?", - "options": [ - "Operace očí, bandáže zachrání zrak", - "Slepý navždy hned", - "Trifid", - "Ne" - ], - "correct": 0, - "expl": "Výchozí situace." - }, - { - "prompt": "Komunity přeživších?", - "options": [ - "Boj o jídlo, pořádek, strach", - "Raj", - "Neexistují", - "Jen armáda" - ], - "correct": 0, - "expl": "Společenský kolaps." - }, - { - "prompt": "Náboženský fanatismus?", - "options": [ - "Objevuje se u některých skupin", - "Ne", - "Celá kniha modlitby", - "Zakázáno" - ], - "correct": 0, - "expl": "Kritika reakcí." - }, - { - "prompt": "Trifidí původ?", - "options": [ - "Laboratoř / olej", - "Nebe", - "Dinosauři", - "Magie" - ], - "correct": 0, - "expl": "Světová závislost na oleji." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Meteoritní slepota", - "Trifidy", - "Hamlet", - "Přežití" - ], - "correct": 2, - "expl": "Hamlet jiné." - }, - { - "prompt": "Josella role?", - "options": [ - "Emoční partnerství s Bill", - "Generál", - "Trifid", - "Meteor" - ], - "correct": 0, - "expl": "Lidský vztah." - }, - { - "prompt": "Finále tón?", - "options": [ - "Otevřená naděje i nejistota", - "Všichni mrtví", - "Svatba", - "Komunismus" - ], - "correct": 0, - "expl": "Adaptace." - }, - { - "prompt": "Er-forma?", - "options": [ - "Bill vypravěč", - "Ich Anne", - "Vševěd", - "Bez vypravěče" - ], - "correct": 0, - "expl": "Masen vypráví." - }, - { - "prompt": "Katalog žánr?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Den trifidů titul?", - "options": [ - "První den dominance trifidů", - "Pondělí", - "Vánoce", - "Den D" - ], - "correct": 0, - "expl": "Začátek katastrofy." - }, - { - "prompt": "Slepí lidé?", - "options": [ - "Bezbranní vůči trifidům", - "Silnější", - "Neexistují", - "Vidí" - ], - "correct": 0, - "expl": "Dramatická situace." - }, - { - "prompt": "Věda v knize?", - "options": [ - "Bill biolog – racionalita", - "Ne", - "Pouze magie", - "Zakázána" - ], - "correct": 0, - "expl": "Vědecký hrdina." - }, - { - "prompt": "Poselství?", - "options": [ - "Civilizace křehká, příroda může převrátit", - "Vždy vítězí", - "Trifidi neexistují", - "Slepota výhoda" - ], - "correct": 0, - "expl": "Varování." - }, - { - "prompt": "Film?", - "options": [ - "Existují adaptace", - "Neexistuje nikdy", - "Zakázáno", - "Jen opera" - ], - "correct": 0, - "expl": "Kultovní." - }, - { - "prompt": "Kořán?", - "options": [ - "Český překladatel", - "Autor", - "Trifid", - "Postava" - ], - "correct": 0, - "expl": "Překlad." - }, - { - "prompt": "Vztah k 1984?", - "options": [ - "Jiné sci-fi, jiný autor", - "Totéž", - "Orwell Wyndham", - "Stejný děj" - ], - "correct": 0, - "expl": "Různá díla." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Zelený roj oslepí lidstvo", - "Bill Masen přežívá se zrakem", - "Chaos a trifidi zabíjejí slepé", - "Bill a Josella hledají bezpečí", - "Konflikty komunit a kolonel", - "Únik na ostrov a nejistá budoucnost" - ] - } - ], - "plotMeaning": [ - "Pořadí: slepota → Bill → trifidi → útěk → komunity → ostrov." - ] -} diff --git a/data/cetba/denik-anny-frankove.json b/data/cetba/denik-anny-frankove.json deleted file mode 100644 index 74a51c4..0000000 --- a/data/cetba/denik-anny-frankove.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Anne Franková", - "Žánr: deníková próza (memoáry)", - "Poprvé vydáno: 1947 (NL)", - "Děj/prostředí: Amsterdam, úkryt „Achterhuis“ 1942–1944", - "Vyprávění/forma: ich-forma deníkových záznamů" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Nacistická okupace, pronásledování Židů", - "Rodina Frankových v tajném bytě", - "Deník jako únik a svědectví", - "Strach z prozrazení, nejistota", - "Růst dospívající Anny", - "Tragický osud po odhalení" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Anne Franková – autorka, dospívající dívka", - "Otto Frank – otec", - "Edith Frank – matka", - "Margot – sestra", - "Van Pels/Daans – spoluúkrytí", - "Miep Gies – pomocnice" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Holocaust – genocida", - "Úkryt – izolace", - "Deník Kitty – adresát", - "Dospívání v extremu", - "Naděje vs. realita", - "Svědectví historie" - ] - } - ], - "quiz": [ - { - "prompt": "Autorka?", - "options": [ - "Anne Franková", - "Viewegh", - "Brontë", - "Collins" - ], - "correct": 0, - "expl": "Anne Franková." - }, - { - "prompt": "Forma?", - "options": [ - "Deník", - "Epos", - "Drama", - "Báseň" - ], - "correct": 0, - "expl": "Deníkové zápisy." - }, - { - "prompt": "Kde úkryt?", - "options": [ - "Amsterdam", - "Praha", - "Berlín", - "Paříž" - ], - "correct": 0, - "expl": "Nizozemsko." - }, - { - "prompt": "Období zápisů?", - "options": [ - "1942–1944", - "1914–1918", - "1989", - "1600" - ], - "correct": 0, - "expl": "Válka." - }, - { - "prompt": "Proč v úkrytu?", - "options": [ - "Pronásledování Židů", - "Dovolená", - "Sport", - "Škola" - ], - "correct": 0, - "expl": "Holocaust." - }, - { - "prompt": "Kitty?", - "options": [ - "Vymyšlená adresátka deníku", - "Sestra", - "Učitelka", - "Německá officer" - ], - "correct": 0, - "expl": "Deník píše „milé Kitty“." - }, - { - "prompt": "Otto Frank?", - "options": [ - "Otec, přežil", - "Gestapo", - "Neexistuje", - "Anne nepíše" - ], - "correct": 0, - "expl": "Jediný z rodiny v úkrytu často přežil." - }, - { - "prompt": "Margot?", - "options": [ - "Starší sestra", - "Matka", - "Trifid", - "Učitel" - ], - "correct": 0, - "expl": "Sestra Anny." - }, - { - "prompt": "Spoluúkrytí?", - "options": [ - "Van Pels (Daans v některých vydáních)", - "Nikdo", - "Jen Anne", - "Sto lidí" - ], - "correct": 0, - "expl": "Další rodina v bytě." - }, - { - "prompt": "Miep Gies?", - "options": [ - "Pomáhala potravinami", - "Gestapo", - "Anne", - "Hitler" - ], - "correct": 0, - "expl": "Ochránkyně." - }, - { - "prompt": "Tón deníku?", - "options": [ - "Osobní, dospívající, i humor", - "Pouze veselý", - "Bez emocí", - "Latina" - ], - "correct": 0, - "expl": "Autentický hlas." - }, - { - "prompt": "Odhalení?", - "options": [ - "1944, deportace", - "Nikdy", - "1940", - "1990" - ], - "correct": 0, - "expl": "Tragický zlom." - }, - { - "prompt": "Osud Anny?", - "options": [ - "Auschwitz, Belsen, smrt 1945", - "Přežila", - "Emigrace USA", - "Neznámý" - ], - "correct": 0, - "expl": "Historický fakt." - }, - { - "prompt": "Vydání deníku?", - "options": [ - "Otto po válce", - "Anne za života knižně", - "Hitler", - "Ne" - ], - "correct": 0, - "expl": "Otec vydal." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Svědectví Holocaustu", - "Nejdelší", - "Fikce", - "Bez témat" - ], - "correct": 0, - "expl": "Důležité svědectví." - }, - { - "prompt": "Ich-forma?", - "options": [ - "Anne píše o sobě", - "Er", - "Vševěd", - "Bez já" - ], - "correct": 0, - "expl": "Deník." - }, - { - "prompt": "Konflikty v úkrytu?", - "options": [ - "Těsná izolace, neshody", - "Ne", - "Válka venku ne", - "Jen sport" - ], - "correct": 0, - "expl": "Psychická zátěž." - }, - { - "prompt": "Sny Anny?", - "options": [ - "Spisovatelka, svoboda", - "Voják", - "Ne", - "Královna" - ], - "correct": 0, - "expl": "Ambice." - }, - { - "prompt": "Holocaust?", - "options": [ - "Genocida Židů", - "Sport", - "Ne", - "Pouze fikce" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Deník", - "Úkryt", - "Hamlet", - "Anne" - ], - "correct": 2, - "expl": "Hamlet drama." - }, - { - "prompt": "Jazyk originálu?", - "options": [ - "Holština / němčina verze", - "Čeština originál", - "Latina", - "Ruština" - ], - "correct": 0, - "expl": "Anne psala nizozemsky." - }, - { - "prompt": "Téma dospívání?", - "options": [ - "Tělo, láska, identita v úkrytu", - "Ne", - "Pouze politika", - "Pouze jídlo" - ], - "correct": 0, - "expl": "Dvojí rovina." - }, - { - "prompt": "Strach?", - "options": [ - "Stálý – krok, prozrazení", - "Ne", - "Jen venku", - "Neexistuje" - ], - "correct": 0, - "expl": "Atmosféra." - }, - { - "prompt": "Naděje?", - "options": [ - "Deník udržuje naději", - "Ne", - "Pouze deprese", - "Zakázáno" - ], - "correct": 0, - "expl": "Lidská síla." - }, - { - "prompt": "Katalog žánr?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Achterhuis?", - "options": [ - "Zadní dům/úkryt", - "Město", - "Loď", - "Hora" - ], - "correct": 0, - "expl": "Prostor úkrytu." - }, - { - "prompt": "Edith?", - "options": [ - "Matka Anny", - "Sestra", - "Gestapo", - "Kitty" - ], - "correct": 0, - "expl": "Rodina." - }, - { - "prompt": "Poselství?", - "options": [ - "Oběť války, hlas obyčejného dítěte", - "Válka dobrá", - "Deník zbytečný", - "Ne" - ], - "correct": 0, - "expl": "Paměť." - }, - { - "prompt": "Upravené vydání?", - "options": [ - "Různé verze textu existují", - "Ne", - "Jen fikce", - "Bez Anne" - ], - "correct": 0, - "expl": "Věda o textu." - }, - { - "prompt": "Citace slavná?", - "options": [ - "„Lidé jsou v jádru dobří“ (parafráze)", - "Bez myšlenek", - "Jen sport", - "Latina" - ], - "correct": 0, - "expl": "Známá věta." - }, - { - "prompt": "Rok 1947?", - "options": [ - "První vydání", - "Narození", - "Konec války deníku", - "1989" - ], - "correct": 0, - "expl": "Publikace." - }, - { - "prompt": "Žánr memoáry?", - "options": [ - "Autobiografický deník", - "Román", - "Epos", - "Komik" - ], - "correct": 0, - "expl": "Ne fikce." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Anne dostane deník a jde do úkrytu", - "Život v tajném bytě s rodinou", - "Konflikty, strach a dospívání", - "Záznamy o naději a realitě", - "Úkryt prozrazen 1944", - "Deportace a smrt Anny, vydání deníku otcem" - ] - } - ], - "plotMeaning": [ - "Pořadí: deník → úkryt → život v izolaci → psaní → prozrazení → osud a vydání." - ] -} diff --git a/data/cetba/edison.json b/data/cetba/edison.json deleted file mode 100644 index 9d2bf15..0000000 --- a/data/cetba/edison.json +++ /dev/null @@ -1,410 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Vítězslav Nezval", - "Žánr: poetická skladba / poema", - "Poprvé vydáno: 1927", - "Děj/prostředí: poetický portrét vynálezce T. A. Edisona", - "Vyprávění/forma: volná skladba, obrazná moderní poezie" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Poetismus – hravost, obrazy, město", - "Obdiv k technice a modernitě", - "Edison jako symbol vynálezce", - "USA / industrializace v obrazu", - "Surreální a groteskní prvky", - "Skupina Devětsil" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Thomas Alva Edison – střed básně", - "Objevitel jako mýtus", - "Nezvalův lyrický subjekt", - "Technika personifikovaná", - "Dělníci a laboratoř", - "Kolektivní obraz doby" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Poetismus – Nezval", - "Světlo – žárovka, symbol", - "Vynález – kreativita", - "Moderní civilizace", - "Hra s jazykem a obrazy", - "Oslava i ironie techniky" - ] - } - ], - "quiz": [ - { - "prompt": "Autor Edison?", - "options": [ - "Nezval", - "Seifert", - "Hrubín", - "Vrchlický" - ], - "correct": 0, - "expl": "Vítězslav Nezval." - }, - { - "prompt": "Žánr?", - "options": [ - "Poema / poezie", - "Román", - "Drama", - "Esej" - ], - "correct": 0, - "expl": "Poezie v katalogu." - }, - { - "prompt": "Rok?", - "options": [ - "1927", - "1948", - "1890", - "2000" - ], - "correct": 0, - "expl": "Meziválečí." - }, - { - "prompt": "O kom báseň?", - "options": [ - "T. A. Edison", - "Einstein", - "Beckett", - "Hugo" - ], - "correct": 0, - "expl": "Vynálezce." - }, - { - "prompt": "Směr?", - "options": [ - "Poetismus", - "Realismus 19 st", - "Romantismus", - "Socialistický" - ], - "correct": 0, - "expl": "Devětsil." - }, - { - "prompt": "Devětsil?", - "options": [ - "Umělecká skupina", - "Edison firma", - "Město", - "Postava" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Téma světla?", - "options": [ - "Žárovka, symbol poznání", - "Ne", - "Pouze tma", - "Sport" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Forma?", - "options": [ - "Volná skladba obrazů", - "Sonety striktně", - "Prozaický román", - "Drama" - ], - "correct": 0, - "expl": "Moderní poezie." - }, - { - "prompt": "Edison realita?", - "options": [ - "Historický vynálezce", - "Fiktivní", - "Nezval", - "Král" - ], - "correct": 0, - "expl": "USA vynálezce." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Česká avantgarda", - "Nejdelší", - "Bez stylu", - "Jen próza" - ], - "correct": 0, - "expl": "Nezval kanón." - }, - { - "prompt": "Poetismus charakter?", - "options": [ - "Hra, obrazy, město", - "Epická vážnost", - "Bez obrazů", - "Pouze politika" - ], - "correct": 0, - "expl": "Směr." - }, - { - "prompt": "Jazyk?", - "options": [ - "Expresivní, obrazný", - "Archaičtina", - "Latina", - "Bez metafor" - ], - "correct": 0, - "expl": "Nezval." - }, - { - "prompt": "Technika v básně?", - "options": [ - "Obdiv a poetizace", - "Ne", - "Pouze odsouzení", - "Nezmíněna" - ], - "correct": 0, - "expl": "Téma." - }, - { - "prompt": "Nezval jiná díla?", - "options": [ - "Abeceda, Valerie, atd.", - "Hamlet", - "1984", - "Dekameron" - ], - "correct": 0, - "expl": "Bohatá tvorba." - }, - { - "prompt": "Ich vs er?", - "options": [ - "Lyrický subjekt obdivuje", - "Epický román", - "Drama", - "Deník" - ], - "correct": 0, - "expl": "Lyrika." - }, - { - "prompt": "Groteska?", - "options": [ - "Poetismus ji používá", - "Ne", - "Pouze real", - "Horor" - ], - "correct": 0, - "expl": "Styl." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Poezie", - "Edison téma", - "Nezval", - "Realistický venkovský román" - ], - "correct": 3, - "expl": "Je poema." - }, - { - "prompt": "Motiv vynálezu?", - "options": [ - "Tvůrčí síla člověka", - "Ne", - "Zlo", - "Nuda" - ], - "correct": 0, - "expl": "Obdiv." - }, - { - "prompt": "Katalog žánr?", - "options": [ - "Poezie", - "Próza", - "Drama", - "Opera" - ], - "correct": 0, - "expl": "Poezie." - }, - { - "prompt": "Obrazy?", - "options": [ - "Kinematografické skoky", - "Ne", - "Jen rým", - "Proza" - ], - "correct": 0, - "expl": "Poetismus." - }, - { - "prompt": "Edison žárovka?", - "options": [ - "Symbol světla", - "Ne", - "Postava", - "Město" - ], - "correct": 0, - "expl": "Známý vynález." - }, - { - "prompt": "Meziválečí?", - "options": [ - "Kontext vzniku", - "Středověk", - "Normalizace", - "Antika" - ], - "correct": 0, - "expl": "1927." - }, - { - "prompt": "Surrealismus vliv?", - "options": [ - "Jemně v poetismu", - "Ne", - "Jen realism", - "Zakázáno" - ], - "correct": 0, - "expl": "Avantgarda." - }, - { - "prompt": "Čtení maturita?", - "options": [ - "Autor, směr, téma Edison", - "Jen rok narození Edison", - "Jen anglicky", - "Nic" - ], - "correct": 0, - "expl": "Základ." - }, - { - "prompt": "Laboratoř?", - "options": [ - "Místo tvoření v obrazu", - "Ne", - "Praha", - "Nebe" - ], - "correct": 0, - "expl": "Metafora." - }, - { - "prompt": "Poselství?", - "options": [ - "Modernita a tvůrčí energie", - "Technika zlá vždy", - "Bez smyslu", - "Antitechnika" - ], - "correct": 0, - "expl": "Obdiv k tvorbě." - }, - { - "prompt": "Délka?", - "options": [ - "Delší skladba", - "Epos 12 knih", - "Jedna slova", - "Román" - ], - "correct": 0, - "expl": "Poema." - }, - { - "prompt": "Překlad?", - "options": [ - "Originál česky Nezval", - "Anglicky autor", - "Latina", - "Ne" - ], - "correct": 0, - "expl": "Česká báseň." - }, - { - "prompt": "Seifert vs Nezval?", - "options": [ - "Obě česká poezie, jiní", - "Totéž", - "Seifert Edison", - "Nezval Švejk" - ], - "correct": 0, - "expl": "Různí." - }, - { - "prompt": "Rým?", - "options": [ - "Volná skladba – rým volný", - "Pouze blankvers", - "Bez jazyka", - "Proza" - ], - "correct": 0, - "expl": "Moderní forma." - }, - { - "prompt": "Edison firma?", - "options": [ - "Může být zmíněna obrazně", - "Hlavní děj román", - "Ne", - "Hamlet" - ], - "correct": 0, - "expl": "Kontext vynálezce." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Nezval představí Edisona jako mýtus vynálezce", - "Obrazy laboratoře a světla", - "Poetistické obrazy techniky", - "Hra jazykem a metaforami", - "Oslava tvůrčí energie", - "Finální skladba obrazů modernity" - ] - } - ], - "plotMeaning": [ - "Pořadí: mýtus Edison → světlo/laboratoř → obrazy → jazyk → tvůrčí síla → celek poemy." - ] -} diff --git a/data/cetba/fahrenheit451.json b/data/cetba/fahrenheit451.json deleted file mode 100644 index 0250066..0000000 --- a/data/cetba/fahrenheit451.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Ray Bradbury", - "Žánr: antiutopický (dystopický) sci-fi román", - "Poprvé vydáno: 1953", - "Děj/prostředí: anonymní americké město v blízké budoucnosti", - "Vyprávění/forma: er-forma, lyricky obrazný styl; český překlad Vítězslava Nezvala" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Knihy jsou zakázané; hasiči pálí knihovny a domy, ne hasí požáry.", - "Lidé tráví čas u televizních „stěn“ a rychlých, prázdných pořadů.", - "Samostatné myšlení je podezřelé; společnost preferuje rychlou zábavu před hloubkou.", - "V pozadí hrozí válka; město působí sterilně a agresivně.", - "Odboj tvoří skrytí čtenáři a „pamatovači“, kteří uchovávají texty v paměti.", - "Román varuje před cenzurou, konformitou a odpoutáním od literatury." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Guy Montag – hasič, který přestane věřit systému pálení knih.", - "Clarisse McClellan – zvědavá dívka, probudí v Montagovi otázky.", - "Mildred Montagová – Guyova žena, závislá na televizi a prášcích.", - "Kapitán Beatty – šéf hasičů, vzdělaný obhájce ničení knih.", - "Profesor Faber – bývalý učitel, Montagův tajný rádce.", - "Granger – vůdce komunity pamatovačů literatury." - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "451 °F – symbol teploty hoření papíru a ničení knih.", - "Televizní stěny – náhrada skutečného života a dialogu.", - "Mechanický pes – technologie sledování a likvidace nepohodlných.", - "Oheň – nejdřív ničení, později i obnova (fénix).", - "Paměť – literatura přežívá v lidech, když zmizí knihy.", - "Svoboda myšlení – hlavní téma odporu proti režimu." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je hlavní hrdina a jaké má povolání?", - "options": [ - "Guy Montag – hasič pálící knihy", - "Beatty – spisovatel", - "Faber – politik", - "Granger – televizní režisér" - ], - "correct": 0, - "expl": "Montag pracuje v hasičské jednotce, která místo hašení požárů ničí knihy." - }, - { - "prompt": "Co znamená titulní „451 stupňů Fahrenheita“ v kontextu románu?", - "options": [ - "Teplota varu vody", - "Údajná teplota hoření knižního papíru", - "Rychlost hasičského vozu", - "Kód tajné policie" - ], - "correct": 1, - "expl": "Bradbury používá číslo jako symbol ničení literatury ohněm." - }, - { - "prompt": "Kdo poprvé naruší Montagovu spokojenost s režimem?", - "options": [ - "Mildred", - "Clarisse McClellan", - "Beatty", - "Granger" - ], - "correct": 1, - "expl": "Clarisse klade otázky o štěstí, přírodě a smyslu života." - }, - { - "prompt": "Jak žije Mildred Montagová?", - "options": [ - "Jako odbojářka se skrytými knihami", - "Pasivně u televizních stěn a prášků", - "Jako učitelka literatury", - "Jako velitelka hasičů" - ], - "correct": 1, - "expl": "Mildred je otupělá masovou zábavou a nevnímá hlubší vztah k Guyovi." - }, - { - "prompt": "Proč podle Beattyho společnost knihy zakázala?", - "options": [ - "Kvůli nedostatku papíru", - "Aby lidé nemysleli samostatně a byli spokojení", - "Protože knihy jsou drahé", - "Kvůli náboženským důvodům" - ], - "correct": 1, - "expl": "Beatty tvrdí, že knihy kazí „klid“ tím, že nutí přemýšlet a polemizovat." - }, - { - "prompt": "Kdo je profesor Faber?", - "options": [ - "Velitel hasičů", - "Bývalý učitel, který Montagovi pomáhá", - "Montagův švagr", - "Autor zakázaných románů v tisku" - ], - "correct": 1, - "expl": "Faber Montaga vede k čtení a přes sluchátko ho podporuje v krizi." - }, - { - "prompt": "Co je mechanický pes v románu?", - "options": [ - "Mildredin domácí mazlíček", - "Robotický lovec stíhající režimem označené osoby", - "Hasičské auto", - "Postava dětského pořadu" - ], - "correct": 1, - "expl": "Mechanický pes je nástroj strachu; později stíhá i Montaga." - }, - { - "prompt": "Co Montag udělá s kapitánem Beattym při zatýkání?", - "options": [ - "Přesvědčí ho ke čtení", - "Spálí ho proudem plamenometu", - "Uteče s ním z města", - "Udá ho policii" - ], - "correct": 1, - "expl": "Po Beattyho provokacích Montag obrátí oheň proti svému nadřízenému." - }, - { - "prompt": "Kdo jsou „pamatovači“ na konci románu?", - "options": [ - "Hasiči v důchodu", - "Lidé, kteří si pamatují knihy nazpaměť", - "Televizní herci", - "Vojáci v zákopu" - ], - "correct": 1, - "expl": "Skupina kolem Grangera uchovává literární texty v paměti jako most k budoucnosti." - }, - { - "prompt": "Jaký symbol nese oheň v průběhu příběhu?", - "options": [ - "Pouze ničení", - "Nejdřív ničení, později i možnost obnovy (metafora fénixe)", - "Jen romantická láska", - "Výhradně válka" - ], - "correct": 1, - "expl": "Montag přechází od pálení knih k vnímání ohně jako zdroje tepla i nového začátku." - }, - { - "prompt": "Jak Mildred reaguje na Montagovo skryté čtení?", - "options": [ - "Podporuje ho", - "Je vyděšená a raději knihy nechce vidět", - "Okamžitě utíká k hasičům", - "Začne psát vlastní deník" - ], - "correct": 1, - "expl": "Mildred se bojí následků a zůstává věrná konzumnímu životnímu stylu." - }, - { - "prompt": "Co se stane s Montagovou domácností?", - "options": [ - "Stane se útočištěm odboje", - "Beatty nechá Montaga sám spálit jeho dům s knihami", - "Mildred ji prodá", - "Faber v ní otevře knihovnu" - ], - "correct": 1, - "expl": "Beatty nutí Montaga zničit vlastní domov jako veřejnou lekci poslušnosti." - }, - { - "prompt": "Proč Montag utíká k řece?", - "options": [ - "Chce najít Clarisse", - "Uteče před mechanickým psem a pronásledováním", - "Jde k Beattymu na večeři", - "Hledá televizní studio" - ], - "correct": 1, - "expl": "Po zabití Beattyho musí opustit město a skrýt se před technologií i lidmi." - }, - { - "prompt": "Jakou roli hraje televize ve společnosti románu?", - "options": [ - "Vzdělává občany", - "Nahrazuje knihy, dialog a kritické myšlení", - "Slouží jen hasičům", - "Vysílá výhradně zprávy o válce" - ], - "correct": 1, - "expl": "Interaktivní stěny a rychlé pořady udržují lidi pasivní a spokojené." - }, - { - "prompt": "Které téma román NEZdůrazňuje?", - "options": [ - "Cenzura", - "Nebezpečí konzumní zábavy", - "Idylický venkovský realism 19. století", - "Odpor jednotlivce" - ], - "correct": 2, - "expl": "Jde o dystopii o knihách a médiích, ne o historický venkovský román." - }, - { - "prompt": "V jakém roce román poprvé vyšel?", - "options": [ - "1949", - "1953", - "1968", - "1984" - ], - "correct": 1, - "expl": "451 stupňů Fahrenheita vyšlo v roce 1953 a patří k klasice antiutopie." - }, - { - "prompt": "Jaký vztah měl Bradbury k televizi podle kontextu díla?", - "options": [ - "Bezvýhradně ji oslavoval", - "Varoval před jejím návykovým vlivem na kulturu", - "Ignoroval ji", - "Považoval ji za náhradu školy" - ], - "correct": 1, - "expl": "Román kritizuje pasivní sledování obrazovek místo čtení a rozhovoru." - }, - { - "prompt": "Co Montag ukradne u staré ženy s knihami?", - "options": [ - "Televizní ovladač", - "Kniha (biblický text)", - "Plamenomet", - "Mechanický pes" - ], - "correct": 1, - "expl": "Montag si nechá knihu, i když vidí, jak žena raději zemře v plamenech než knihy vydá." - }, - { - "prompt": "Proč je scéna se starou ženou důležitá?", - "options": [ - "Ukazuje lehkost smrti", - "Montag chápe, že knihy mají pro lidi hodnotu života", - "Beatty se stane hrdinou", - "Mildred se obrátí" - ], - "correct": 1, - "expl": "Obětí ženy v plamenech Montag poprvé silně pocítí absurditu pálení knih." - }, - { - "prompt": "Jak Faber pomáhá Montagovi během pronásledování?", - "options": [ - "Letí s ním vrtulníkem", - "Komunikuje přes miniaturní sluchátko v uchu", - "Zastřelí mechanického psa", - "Spálí Beattyho knihovnu" - ], - "correct": 1, - "expl": "Faber ho radí na dálku, dokud Montag neunikne z města." - }, - { - "prompt": "Co se stane s městem na konci?", - "options": [ - "Slaví mír", - "Je zničeno leteckým útokem", - "Stane se knihovnou", - "Zmizí televize" - ], - "correct": 1, - "expl": "Válka na pozadí exploduje; město letecky zničí, zatímco Montag je mimo." - }, - { - "prompt": "Jak Granger vnímá budoucnost po zkáze?", - "options": [ - "Bez naděje", - "Jako šanci znovu budovat kulturu z paměti", - "Jako konec světa bez smyslu", - "Jako vítězství hasičů" - ], - "correct": 1, - "expl": "Pamatovači přirovnávají obnovu k fénixovi – z popela může vyrůst nové." - }, - { - "prompt": "Která postava představuje konformitu nejvíc?", - "options": [ - "Clarisse", - "Mildred", - "Granger", - "Faber" - ], - "correct": 1, - "expl": "Mildred je vzor občana spokojeného s prázdnou zábavou." - }, - { - "prompt": "Která postava ztělesňuje vzdělaný cynismus moci?", - "options": [ - "Faber", - "Beatty", - "Clarisse", - "Granger" - ], - "correct": 1, - "expl": "Beatty cituje literaturu, ale obhajuje její ničení." - }, - { - "prompt": "Jaký žánr nejlépe vystihuje román?", - "options": [ - "Antiutopický sci-fi román", - "Historický epos", - "Detektivka", - "Pastorální idyla" - ], - "correct": 0, - "expl": "Děj v budoucnosti kritizuje společnost a technologie – typická antiutopie." - }, - { - "prompt": "Co Montag dělá na začátku knihy profesně?", - "options": [ - "Učí na gymnáziu", - "Pálí knihy jako hasič", - "Píše pro televizi", - "Vyrábí mechanické psy" - ], - "correct": 1, - "expl": "Úvodní scény ukazují rutinní pálení knih." - }, - { - "prompt": "Proč je Clarisse „nebezpečná“ pro systém?", - "options": [ - "Je bohatá", - "Ptá se na zakázané otázky a myslí jinak", - "Je hasička", - "Píše knihy" - ], - "correct": 1, - "expl": "Její zvědavost a pomalost odporují konzumnímu tempu společnosti." - }, - { - "prompt": "Jaký význam má řeka v závěru?", - "options": [ - "Hranice státu", - "Cesta úniku a symbol očištění", - "Místo pálení knih", - "Beattyho hrob" - ], - "correct": 1, - "expl": "Montag se v řece skrývá před psem a přechází k novému životu." - }, - { - "prompt": "Kdo v románu představuje most mezi starou kulturou a odbojem?", - "options": [ - "Beatty", - "Faber", - "Mildred", - "Mechanický pes" - ], - "correct": 1, - "expl": "Faber zná knihy, ale dlouho se bál jednat – Montaga k akci povzbudí." - }, - { - "prompt": "Jaké poselství je pro maturitu nejdůležitější?", - "options": [ - "Knihy lze nahradit televizí", - "Svoboda myšlení a kultura se brání i za cenu rizika", - "Hasiči by měli pálit domy", - "Válka je lepší než čtení" - ], - "correct": 1, - "expl": "Román obhajuje literaturu a kritické myšlení proti cenzuře a pasivitě." - }, - { - "prompt": "Jaký český překladatel je u díla tradičně uváděn v maturitních seznamech?", - "options": [ - "Gössell", - "Nezval", - "Skoumal", - "Nevrla" - ], - "correct": 1, - "expl": "V katalogu maturitní četby je u díla uveden překlad Vítězslava Nezvala." - }, - { - "prompt": "Co následuje po Montagově připojení k pamatovačům?", - "options": [ - "Návrat k Mildred", - "Pohled na zkázu města a naděje v obnovu", - "Beattyho rehabilitace", - "Zákaz paměti" - ], - "correct": 1, - "expl": "Závěr spojuje zkázu s možností nového začátku skrze paměť a knihy." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Montag rutinně pálí knihy jako hasič", - "Clarisse ho přiměje pochybovat o systému", - "Montag schovává knihy a hledá radu u Fabera", - "Beatty nechá Montaga spálit vlastní dům", - "Montag zabije Beattyho a utíká z města", - "Připojí se k pamatovačům a vidí zkázu města" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: rutinní pálení → Clarisse a pochybnosti → knihy a Faber → spálení domu → útěk a Beatty → pamatovači a zkáza města." - ] -} diff --git a/data/cetba/farma-zvirat.json b/data/cetba/farma-zvirat.json deleted file mode 100644 index 3f5073c..0000000 --- a/data/cetba/farma-zvirat.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: George Orwell", - "Žánr: alegorická antiutopická novela", - "Poprvé vydáno: 1945", - "Děj/prostředí: farma Manor, zvířecí revoluce", - "Vyprávění/forma: er-forma, alegorie na SSSR; překlad Gössell" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Vzpoura proti panu Jonesovi", - "Pravidla Animalismu", - "Postupná moc prasat", - "Propaganda Squealer", - "Pracovní útlak ostatních", - "Proměna v totalitu" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Napoleon – prase, diktátor", - "Snowball – prase, rival", - "Boxer – kůň, „I will work harder“", - "Squealer – prase, propaganda", - "Old Major – prase, vize revoluce", - "Benjamin – osel, skeptic" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Alegorie – revoluce 1917", - "Pravidla sedm – mění se", - "„Všichni zvířata rovna“", - "Chytrá prasata vs. dělníci", - "Boxer – oběť systému", - "Lidská tvář prasat" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Orwell", - "Bradbury", - "Havel", - "Swift" - ], - "correct": 0, - "expl": "George Orwell." - }, - { - "prompt": "Rok?", - "options": [ - "1945", - "1984", - "1953", - "1862" - ], - "correct": 0, - "expl": "Po válce." - }, - { - "prompt": "Alegorie?", - "options": [ - "Sovětská revoluce a Stalin", - "Středověk", - "USA", - "Ne" - ], - "correct": 0, - "expl": "Zvířata = lidé." - }, - { - "prompt": "Old Major?", - "options": [ - "Vize revoluce", - "Diktátor", - "Jones", - "Kůň" - ], - "correct": 0, - "expl": "Marx/Lenin obraz." - }, - { - "prompt": "Jones?", - "options": [ - "Původní pán farmy", - "Prase", - "Kůň", - "Ne" - ], - "correct": 0, - "expl": "Czar/kapitalista." - }, - { - "prompt": "Napoleon vs Snowball?", - "options": [ - "Rivalové mezi prasaty", - "Bratři v klidu", - "Ne", - "Lidé" - ], - "correct": 0, - "expl": "Stalin/Trockij obraz." - }, - { - "prompt": "Squealer?", - "options": [ - "Propaganda", - "Kůň", - "Jones", - "Ne" - ], - "correct": 0, - "expl": "Překrucuje pravdu." - }, - { - "prompt": "Boxer?", - "options": [ - "Obětavý kůň, prodán jatky", - "Prase", - "Pes", - "Ne" - ], - "correct": 0, - "expl": "Proletariát." - }, - { - "prompt": "Pravidla?", - "options": [ - "Postupně měněna prasaty", - "Ne", - "Stálá", - "Jen jedno" - ], - "correct": 0, - "expl": "Manipulace." - }, - { - "prompt": "Benjamin?", - "options": [ - "Cynický osel", - "Optimista", - "Diktátor", - "Ne" - ], - "correct": 0, - "expl": "Skeptik." - }, - { - "prompt": "Konec?", - "options": [ - "Prasata jako lidé u stolu", - "Raj", - "Jones vrácen", - "Ne" - ], - "correct": 0, - "expl": "Totalita." - }, - { - "prompt": "Žánr?", - "options": [ - "Alegorická antiutopie", - "Pohádka bez významu", - "Epos", - "Lyrika" - ], - "correct": 0, - "expl": "Satira." - }, - { - "prompt": "Překlad?", - "options": [ - "Gössell", - "Nezval", - "Kořán", - "Nevrla" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "1984 vs Farma?", - "options": [ - "Orwell obě, jiné téma", - "Bradbury", - "Stejný děj", - "Ne" - ], - "correct": 0, - "expl": "Dva romány." - }, - { - "prompt": "Animalismus?", - "options": [ - "Ideologie revoluce", - "Náboženství", - "Ne", - "Sport" - ], - "correct": 0, - "expl": "Ideologie." - }, - { - "prompt": "Větrný mlýn?", - "options": [ - "Snowballův plán, Napoleon zničí", - "Ne", - "Jones", - "Nebe" - ], - "correct": 0, - "expl": "Industrializace." - }, - { - "prompt": "Psí garda?", - "options": [ - "Napoleonova stráž", - "Ne", - "Boxer", - "Ne" - ], - "correct": 0, - "expl": "Represe." - }, - { - "prompt": "Milk and apples?", - "options": [ - "Prasata si přisvojí", - "Ne", - "Všichni", - "Zakázáno" - ], - "correct": 0, - "expl": "Privilegia elity." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasika alegorie", - "Nejkratší", - "Bez smyslu", - "Jen film" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Napoleon", - "Boxer", - "Hamlet", - "Squealer" - ], - "correct": 2, - "expl": "Shakespeare." - }, - { - "prompt": "Er-forma?", - "options": [ - "Ano", - "Ich Anne", - "Drama", - "Ne" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Satira?", - "options": [ - "Ano politická", - "Ne", - "Pouze pohádka", - "Horor" - ], - "correct": 0, - "expl": "Orwell." - }, - { - "prompt": "Boxer motto?", - "options": [ - "Budu tvrději pracovat", - "Ne", - "Válka", - "Spím" - ], - "correct": 0, - "expl": "Známá věta." - }, - { - "prompt": "Jatky?", - "options": [ - "Boxer prodán", - "Raj", - "Ne", - "Snowball" - ], - "correct": 0, - "expl": "Zrada." - }, - { - "prompt": "Lidská tvář?", - "options": [ - "Závěrečná scéna", - "Ne", - "Jones", - "Ne" - ], - "correct": 0, - "expl": "Pointa." - }, - { - "prompt": "Všichni rovni?", - "options": [ - "Slogan zneužitý", - "Ne", - "Vždy platí", - "Ne" - ], - "correct": 0, - "expl": "Paradox." - }, - { - "prompt": "Moses vrabec?", - "options": [ - "Příběh Cukrové hory – opium", - "Ne", - "Hrdina", - "Ne" - ], - "correct": 0, - "expl": "Náboženství." - }, - { - "prompt": "Poselství?", - "options": [ - "Revolution může zkazit", - "Revolution vždy dobrá", - "Ne", - "Zvířata ne" - ], - "correct": 0, - "expl": "Varování." - }, - { - "prompt": "Katalog?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Farm Manor?", - "options": [ - "Původní název", - "Ne", - "Praha", - "Ne" - ], - "correct": 0, - "expl": "Anglie." - }, - { - "prompt": "Orwell jméno?", - "options": [ - "Eric Blair", - "Nezval", - "Hugo", - "Ne" - ], - "correct": 0, - "expl": "Skutečné jméno." - }, - { - "prompt": "Battle of Cowshed?", - "options": [ - "Obrana farmy", - "Ne", - "Boxer", - "Ne" - ], - "correct": 0, - "expl": "Válka." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Old Major vyzve ke vzpouře", - "Jones svržen, Animalismus", - "Snowball a Napoleon soupeří", - "Napoleon se zmocní moci", - "Útlak, propaganda, Boxer jatky", - "Prasata nelze od lidí rozeznat" - ] - } - ], - "plotMeaning": [ - "Pořadí: vize → revoluce → rivalita → diktatura → útlak → zrada ideálů." - ] -} diff --git a/data/cetba/fuks.json b/data/cetba/fuks.json deleted file mode 100644 index ece502e..0000000 --- a/data/cetba/fuks.json +++ /dev/null @@ -1,474 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Ladislav Fuks (1923–1994)", - "Žánr: psychologický román s prvky grotesky a hororu", - "Poprvé vydáno: 1967", - "Děj: Praha v době protektorátu (konec 30. let)", - "Vyprávění: ich-forma – vypráví sám pan Kopfrkingl" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Děj se odehrává v protektorátu Čechy a Morava za nastupujícího nacismu.", - "Atmosféru tvoří strach, přizpůsobování a touha zalíbit se moci.", - "Krematorium je symbolem smrti a odlidštění.", - "Antisemitismus a árijská ideologie postupně prostupují společnost.", - "Obyčejný úředník se mění v nástroj zla." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Pan Kopfrkingl – zaměstnanec krematoria, vypravěč a vrah své rodiny.", - "Lakmé – jeho žena, židovského původu.", - "Zina a Mil – jeho děti.", - "Willi Reinke – Němec, který Kopfrkingla přivede k nacismu.", - "Dr. Bettelheim – lékař, s nímž Kopfrkingl rozmlouvá o smrti." - ] - }, - { - "title": "Klíčové motivy", - "icon": "bulb", - "lines": [ - "Krematorium – symbol smrti a zvrácené „očisty“.", - "Kniha mrtvých – tibetský text, který si Kopfrkingl překrucuje.", - "Reinkarnace a „osvobození“ – záminka pro vraždy.", - "Masky a přetvářka – zlo se tváří jako zdvořilost a řád.", - "Groteska a černý humor – hrůza podaná klidným, slavnostním tónem.", - "Voda a Vltava – motiv smrti a plynutí." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je hlavní postava románu a jaké je jeho povolání?", - "options": [ - "Pan Kopfrkingl – zaměstnanec krematoria", - "Willi Reinke – nacistický důstojník", - "Dr. Bettelheim – psychiatr", - "Pan Kopfrkingl – ředitel školy" - ], - "correct": 0, - "expl": "Hlavní postavou je pan Kopfrkingl, spořádaný zaměstnanec krematoria, který svou práci vnímá jako poslání." - }, - { - "prompt": "V jakém prostředí pan Kopfrkingl pracuje?", - "options": [ - "V nemocnici", - "V krematoriu", - "V divadle", - "Ve škole" - ], - "correct": 1, - "expl": "Kopfrkingl pracuje v krematoriu, kde má na starosti zpopelňování zemřelých." - }, - { - "prompt": "V jaké historické době se děj románu odehrává?", - "options": [ - "Za první republiky", - "Za protektorátu Čechy a Morava (před a během 2. světové války)", - "Po roce 1989", - "V 19. století" - ], - "correct": 1, - "expl": "Román se odehrává v době nastupujícího nacismu a protektorátu, který umožňuje Kopfrkinglovu proměnu." - }, - { - "prompt": "Jak se proměňuje hlavní hrdina v průběhu příběhu?", - "options": [ - "Z laskavého spořádaného muže v chladnokrevného vraha a fanatika", - "Z vraha v kajícníka", - "Z chudáka v boháče", - "Vůbec se nemění" - ], - "correct": 0, - "expl": "Kopfrkingl se postupně mění v člověka, který vraždí své blízké a ospravedlňuje to vyšším dobrem." - }, - { - "prompt": "Jaký je vztah pana Kopfrkingla k jeho rodině na začátku knihy?", - "options": [ - "Nenávidí je", - "Je starostlivý, zdvořilý a především spořádaný", - "S rodinou se nezná", - "Týrá je" - ], - "correct": 1, - "expl": "Na začátku působí jako vzorný manžel a otec, posedlý řádem a zdvořilostí." - }, - { - "prompt": "Jak se jmenuje manželka pana Kopfrkingla a jaký je jejich vztah?", - "options": [ - "Marie – milují se", - "Lakmé – formálně zdvořilý, chladný vztah", - "Zina – nenávidí se", - "Julie – jsou rozvedení" - ], - "correct": 1, - "expl": "Manželka se jmenuje Lakmé. Jejich vztah je spíš zdvořilá forma než opravdová láska." - }, - { - "prompt": "Jaký je vztah pana Kopfrkingla k dětem, Zině a Mílovi?", - "options": [ - "Miluje je víc než sebe", - "Chová se k nim odtažitě, jako k součásti řádu", - "Nevidí je", - "Jsou adoptované" - ], - "correct": 1, - "expl": "K dětem je odměřený; vnímá je spíš jako součást svého spořádaného světa než jako milované bytosti." - }, - { - "prompt": "Kdo je Willi Reinke a jakou roli hraje v proměně hlavního hrdiny?", - "options": [ - "Soused z krematoria", - "Německý úředník a bývalý voják, který Kopfrkingla ovlivní", - "Kopfrkinglův bratr", - "Lékař v nemocnici" - ], - "correct": 1, - "expl": "Reinke je Němec, který v Kopfrkinglovi probudí touhu po árijském původu a kariéře." - }, - { - "prompt": "Jak Willi Reinke ovlivňuje Kopfrkinglovo smýšlení?", - "options": [ - "Přesvědčí ho, aby se přidal k nacistům a byl „lepší“", - "Nabádá ho k odchodu do zahraničí", - "Učí ho tibetštinu", - "Nijak ho neovlivní" - ], - "correct": 0, - "expl": "Reinke v něm posiluje antisemitismus a touhu po moci a uznání v novém režimu." - }, - { - "prompt": "Jaký je Kopfrkinglův vztah ke krematoriu a smrti obecně?", - "options": [ - "Bojí se jich", - "Má je rád, kremaci vnímá jako krásný obřad osvobození", - "Nechce tam pracovat", - "Je mu to lhostejné" - ], - "correct": 1, - "expl": "Smrt a kremace jsou pro něj estetickým a filozofickým rituálem, ne něčím hrůzným." - }, - { - "prompt": "Jak pan Kopfrkingl vnímá a popisuje proces kremace?", - "options": [ - "Jako nutné zlo", - "Jako vznešený, očistný obřad, o kterém rád mluví", - "Jako hroznou povinnost", - "Nikdy o něm nemluví" - ], - "correct": 1, - "expl": "Kopfrkingl o kremaci hovoří básnivě a s nadšením, což ostře kontrastuje s hrůzou jeho činů." - }, - { - "prompt": "Jaká je symbolika krematoria v celém románu?", - "options": [ - "Symbol naděje", - "Smrt, odlidštění a zvrácená ideologie, která z lidí dělá jen těla", - "Symbol lásky", - "Symbol mládí" - ], - "correct": 1, - "expl": "Krematorium je ústředním symbolem – odhaluje chladnou mašinerii smrti, do níž se ideologie snaží proměnit člověka." - }, - { - "prompt": "Co symbolizuje Kopfrkinglova záliba v tibetské Knize mrtvých?", - "options": [ - "Jeho touhu po vědění a zvrácenou víru ve vlastní výjimečnost", - "Historický zájem o Asii", - "Strach ze smrti", - "Lásku k manželce" - ], - "correct": 0, - "expl": "Kopfrkingl si z ní vybírá jen to, co se hodí k ospravedlnění jeho činů a jeho pocitu vyvolenosti." - }, - { - "prompt": "Jak se v knize projevuje motiv buddhismu a reinkarnace?", - "options": [ - "Kopfrkingl jimi ospravedlňuje smrt jako „osvobození duše“", - "Postavy se modlí k Bohu", - "Nikde se neobjevuje", - "Je to hlavní téma manželky" - ], - "correct": 0, - "expl": "Reinkarnace a „osvobození od utrpení“ se v jeho mysli zvrhávají v právo zabíjet." - }, - { - "prompt": "Jak Kopfrkingl zneužívá filozofické a náboženské myšlenky?", - "options": [ - "Ospravedlňuje jimi vlastní vraždy jako službu vyššímu dobru", - "Pomáhá jimi druhým", - "Odmítá je", - "Používá je jen v práci" - ], - "correct": 0, - "expl": "Z vznešených idejí si staví masku, za kterou skrývá krutost a touhu po moci." - }, - { - "prompt": "Jak se postupně mění Kopfrkinglova mluva a způsob vyjadřování?", - "options": [ - "Začíná mluvit vulgárně", - "Mění se v patetickou, ráznou řeč plnou frází o řádu a osvobození", - "Přestane mluvit", - "Od začátku mluví jen německy" - ], - "correct": 1, - "expl": "Jeho zdvořilá mluvnost se postupně mění v ideologické fráze a bezcitný patos." - }, - { - "prompt": "Jaké opakující se fráze nebo návyky pana Kopfrkingla si všímáš?", - "options": [ - "Neustále se ptá na počasí", - "Opakuje „to je takové“, „vidíte“ a lpí na zdvořilosti", - "Zpívá si", - "Mluví jen o jídle" - ], - "correct": 1, - "expl": "Opakující se fráze a zdvořilostní obraty vytvářejí rytmus, který je čím dál tím děsivější." - }, - { - "prompt": "Jaký je vypravěčský styl románu (ich-forma, er-forma)?", - "options": [ - "Er-forma bez vnitřního světa", - "Ich-forma – vypráví sám Kopfrkingl", - "Deníková forma", - "Forma dopisů" - ], - "correct": 1, - "expl": "Ich-forma je klíčová: čtenář sleduje svět zkreslený Kopfrkinglovou myslí a sám postupně propadá jeho logice." - }, - { - "prompt": "Jak se v knize projevuje černý humor a groteska?", - "options": [ - "Vážné scény jsou líčeny s odstupem a absurditou", - "Kniha je čistě vážná", - "Humor je jediný žánr", - "V knize se neprojevuje" - ], - "correct": 0, - "expl": "Groteskní kontrast mezi slavnostním vyprávěním a hrůzou vytváří mrazivý černý humor." - }, - { - "prompt": "Jak kontrastuje banalita každodenního života s hrůzností činů?", - "options": [ - "Vůbec nesouvisí", - "Všední detaily a zdvořilost činí hrůzu ještě děsivější", - "Hrůza je potlačena", - "Den je popsán jen jednou" - ], - "correct": 1, - "expl": "Fuks zesiluje otřes tím, že vraždění je popisováno stejně klidně jako ranní káva nebo kremace." - }, - { - "prompt": "Jak se v knize projevuje antisemitismus?", - "options": [ - "Od začátku otevřeně", - "Postupně, nejdřív v náznacích a vlivem Reinkeho", - "Nikdy", - "Jen mimochodem v závěru" - ], - "correct": 1, - "expl": "Kopfrkinglův antisemitismus se rodí pozvolna a je živen dobovou atmosférou i Reinkem." - }, - { - "prompt": "Jak nacistická ideologie postupně prostupuje Kopfrkinglovo myšlení?", - "options": [ - "Odmítá ji", - "Přijímá ji jako vyšší řád a ospravedlnění vlastní výjimečnosti", - "Nerozumí jí", - "Zajímá ho jen hudba" - ], - "correct": 1, - "expl": "Ideologie se mu stává nástrojem kariéry i vnitřním ospravedlněním vražd." - }, - { - "prompt": "Jak se mění Kopfrkinglův vztah k manželce kvůli jejímu původu?", - "options": [ - "Začne ji milovat víc", - "Odcizí se jí, protože je židovského původu", - "Nijak se nemění", - "Odstěhují se od sebe" - ], - "correct": 1, - "expl": "Kvůli jejímu původu ji přestane vnímat jako rovnocennou a nakonec ji zabije." - }, - { - "prompt": "Co se stane s Kopfrkinglovou rodinou ve druhé polovině románu?", - "options": [ - "Odstěhují se", - "Kopfrkingl svou ženu i děti zabije", - "Všichni přežijí", - "Zachrání je Reinke" - ], - "correct": 1, - "expl": "Pod vlivem ideologie Kopfrkingl vyvraždí vlastní rodinu a považuje to za „osvobození“." - }, - { - "prompt": "Jak Kopfrkingl zdůvodňuje vraždu vlastní ženy?", - "options": [ - "Zlobila se na něj", - "Že je židovského původu a překáží jeho kariéře", - "Že ho podváděla", - "Nijak ji nezdůvodňuje" - ], - "correct": 1, - "expl": "Svou ženu zabije mimo jiné proto, že je židovského původu, tedy „méněcenná“ pro nový režim." - }, - { - "prompt": "Jakým způsobem Kopfrkingl vraždí své blízké?", - "options": [ - "Ve zlosti a afektu", - "Chladně a s pocitem, že je „osvobozuje od utrpení“", - "Omylem", - "Na příkaz úřadů" - ], - "correct": 1, - "expl": "Vraždí klidně, jako by vykonával bohulibý úkon, a svou krutost si vykládá jako soucit." - }, - { - "prompt": "Jak souvisí přesvědčení o „osvobození“ s jeho vražednými činy?", - "options": [ - "Dává mu zdání vyššího smyslu, kterým si vraždy ospravedlňuje", - "Nemá s nimi nic společného", - "Brání mu v zabíjení", - "Je to jen náhodná fráze" - ], - "correct": 0, - "expl": "Zvrácená víra v osvobození od utrpení mu slouží jako mravní alibi pro vraždy." - }, - { - "prompt": "Jaký je vztah pana Kopfrkingla k postavě Dr. Bettelheima?", - "options": [ - "Obdivuje ho a rád s ním mluví", - "Nenávidí ho", - "Nikdy se nepotkají", - "Je to jeho nadřízený" - ], - "correct": 0, - "expl": "S doktorem Bettelheimem vede Kopfrkingl své „filozofické“ rozhovory o smrti a lidskosti." - }, - { - "prompt": "Jak se mění společenské postavení pana Kopfrkingla v době okupace?", - "options": [ - "Upadá", - "Stoupá – díky režimu a touze po árijském původu", - "Nemění se", - "Odchází do penze" - ], - "correct": 1, - "expl": "Spolu s nacistickou mocí roste i Kopfrkinglova kariéra a sebevědomí." - }, - { - "prompt": "Jaký je symbolický význam jména Kopfrkingl?", - "options": [ - "Zdánlivě úřednické, ale zní hrozivě – naznačuje zvrácenost", - "Je to běžné české jméno", - "Znamená „laskavý“", - "Je to pseudonym" - ], - "correct": 0, - "expl": "Zvukomalebné jméno působí úředně a zároveň hrozivě, což podtrhuje dvojí tvář postavy." - }, - { - "prompt": "Jak funguje motiv masek, divadla a přetvářky?", - "options": [ - "Postavy nosí masky dobroty, pod nimiž se skrývá krutost", - "V knize jsou jen skutečné divadelní masky", - "Motiv se neobjevuje", - "Masky symbolizují lásku" - ], - "correct": 0, - "expl": "Přetvářka a předstíraná spořádanost jsou ústřední – zlo se tváří jako slušnost." - }, - { - "prompt": "Jaký je vztah mezi soukromým a kolektivním šílenstvím doby?", - "options": [ - "Kopfrkinglovo osobní šílenství roste spolu s ideologií doby", - "Nijak nesouvisí", - "Doba je klidná a šťastná", - "Lidé režim jednomyslně odmítají" - ], - "correct": 0, - "expl": "Fuks ukazuje, jak se individuální porucha napojí na kolektivní ideologii a čerpá z ní sílu." - }, - { - "prompt": "Jak končí román a co se stane s panem Kopfrkinglem na konci?", - "options": [ - "Uteče do zahraničí", - "Je zatčen a zničen", - "Stane se hrdinou", - "Věří, že je vtělením Dalajlámy, a zůstává zaslepený" - ], - "correct": 3, - "expl": "Kopfrkinglova zaslepenost vrcholí přesvědčením o vlastní božskosti; jeho zvrácená víra ho neopouští." - }, - { - "prompt": "Jak je Spalovač mrtvol adaptován filmově?", - "options": [ - "Film Juraje Herze je vizuálně expresivní a patří k vrcholům české kinematografie", - "Byl zfilmován jen v zahraničí", - "Film neexistuje", - "Vznikl jako animovaný seriál" - ], - "correct": 0, - "expl": "Známá filmová verze je od režiséra Juraje Herze z roku 1968." - }, - { - "prompt": "Které další dílo Ladislava Fukse se dá srovnat s touto knihou?", - "options": [ - "Pan Theodor Mundstock nebo Myši Natálie Mooshabrové", - "Farma zvířat", - "R.U.R.", - "Babička" - ], - "correct": 0, - "expl": "Fuks se opakovaně zabýval osudem židovských postav a atmosférou strachu; srovnat lze např. Pana Theodora Mundstocka." - }, - { - "prompt": "Jaká jsou hlavní témata románu?", - "options": [ - "Moc, manipulace, ideologie, násilí a přetvářka", - "Láska a dobrodružství", - "Sport a přátelství", - "Příroda a vesmír" - ], - "correct": 0, - "expl": "Kniha zkoumá, jak se obyčejný člověk přizpůsobí zlu a stane se jeho nástrojem." - }, - { - "prompt": "Jaké poselství podle tebe chtěl Ladislav Fuks knihou předat?", - "options": [ - "Varování před manipulací a tím, jak se zlo rodí z banality a lhostejnosti", - "Oslavu války", - "Návod k podnikání", - "Kritiku školství" - ], - "correct": 0, - "expl": "Fuks ukazuje, že hrůza může vzniknout z poslušnosti a touhy být „lepší“ než ostatní." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Kopfrkingl je spořádaným zaměstnancem krematoria", - "Seznámí se s Willim Reinkem", - "Začne věřit v árijskou nadřazenost", - "Postupně se odcizí své rodině", - "Zabije ženu a děti jako „osvobození“", - "Na konci se považuje za vtělení Dalajlámy" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: spořádaný úředník → setkání s Reinkem → árijská ideologie → odcizení rodině → vraždy → přesvědčení o vlastní božskosti." - ] -} diff --git a/data/cetba/gulliverovy-cesty.json b/data/cetba/gulliverovy-cesty.json deleted file mode 100644 index 744ff13..0000000 --- a/data/cetba/gulliverovy-cesty.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Jonathan Swift", - "Žánr: satirická novela / cestopis", - "Poprvé vydáno: 1726", - "Děj/prostředí: čtyři cesty Gullivera do fantastických zemí", - "Vyprávění/forma: ich-forma Gulliver; překlad Skoumal" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Anglie 18. století, osvícenství", - "Satira na politiku, vědu, válku", - "Lilliput – malí, politika", - "Brobdingnag – obři, perspektiva", - "Laputa – věda odtržená", - "Houyhnhnmové – koně rozumní" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Lemuel Gulliver – cestovatel, vypravěč", - "Lilliputié – malí lidé", - "Brobdingnaci – obři", - "Houyhnhnmové a Yahoové", - "Král Brobdingnagu", - "Kapitán a rodina Gulliver" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Satira – nadsázka společnosti", - "Relativita velikosti", - "Válka o vejce (Lilliput)", - "Rozum vs. bestialita (Yahoo)", - "Cestopis jako forma", - "Swiftova kritika Evropy" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Swift", - "Defoe", - "Orwell", - "Hugo" - ], - "correct": 0, - "expl": "Jonathan Swift." - }, - { - "prompt": "Rok?", - "options": [ - "1726", - "1984", - "1600", - "1900" - ], - "correct": 0, - "expl": "18. století." - }, - { - "prompt": "Kolik cest?", - "options": [ - "Čtyři", - "Jedna", - "Deset", - "Sto" - ], - "correct": 0, - "expl": "Struktura knihy." - }, - { - "prompt": "Lilliput?", - "options": [ - "Země malých", - "Obři", - "Koně", - "Nebe" - ], - "correct": 0, - "expl": "První cesta." - }, - { - "prompt": "Brobdingnag?", - "options": [ - "Země obřů", - "Malí", - "Luna", - "Praha" - ], - "correct": 0, - "expl": "Druhá cesta." - }, - { - "prompt": "Laputa?", - "options": [ - "Létající ostrov vědců", - "Ne", - "Jatky", - "Ne" - ], - "correct": 0, - "expl": "Třetí cesta." - }, - { - "prompt": "Houyhnhnm?", - "options": [ - "Rozumní koně", - "Yahoové", - "Lilliputi", - "Ne" - ], - "correct": 0, - "expl": "Čtvrtá cesta." - }, - { - "prompt": "Yahoo?", - "options": [ - "Bestiální lidé", - "Koně", - "Králové", - "Ne" - ], - "correct": 0, - "expl": "Satira lidstva." - }, - { - "prompt": "Satira?", - "options": [ - "Ano hlavní", - "Ne", - "Pouze pohádka", - "Horor" - ], - "correct": 0, - "expl": "Swift." - }, - { - "prompt": "Překlad?", - "options": [ - "Skoumal", - "Nezval", - "Kořán", - "Nevrla" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "Ich-forma?", - "options": [ - "Gulliver vypravěč", - "Er", - "Bez já", - "Drama" - ], - "correct": 0, - "expl": "Cestopis." - }, - { - "prompt": "Vejce válka?", - "options": [ - "Lilliput satira", - "Ne", - "Brobdingnag", - "Ne" - ], - "correct": 0, - "expl": "Politické spory." - }, - { - "prompt": "Gulliver konec?", - "options": [ - "Odcizen od lidí po cestě 4", - "Král", - "Ne", - "Raj" - ], - "correct": 0, - "expl": "Tragi-komický." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasika satiry", - "Nejkratší", - "Bez smyslu", - "Jen film" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Osvícenství?", - "options": [ - "Kontext kritiky", - "Středověk", - "Ne", - "Budoucnost" - ], - "correct": 0, - "expl": "18. st." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Gulliver", - "Lilliput", - "Hamlet", - "Yahoo" - ], - "correct": 2, - "expl": "Shakespeare." - }, - { - "prompt": "Brobdingnag král?", - "options": [ - "Kritizuje Evropu", - "Ne", - "Malý", - "Ne" - ], - "correct": 0, - "expl": "Perspektiva." - }, - { - "prompt": "Relativita?", - "options": [ - "Velikost mění pohled", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Swift Ir?", - "options": [ - "Irský satirik", - "Čech", - "Němec", - "Ne" - ], - "correct": 0, - "expl": "Anglicky psal." - }, - { - "prompt": "Cestopis forma?", - "options": [ - "Fiktivní cestopis", - "Epos", - "Drama", - "Lyrika" - ], - "correct": 0, - "expl": "Žánr." - }, - { - "prompt": "Laputa věda?", - "options": [ - "Odtržená absurdní", - "Ne", - "Užitečná", - "Ne" - ], - "correct": 0, - "expl": "Satira vědy." - }, - { - "prompt": "Houyhnhnm společnost?", - "options": [ - "Rozumnější než lidé", - "Ne", - "Yahoo", - "Ne" - ], - "correct": 0, - "expl": "Inverze." - }, - { - "prompt": "Gulliver rodina?", - "options": [ - "Po návratu cizí", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Závěr." - }, - { - "prompt": "Katalog?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Politická satira?", - "options": [ - "Ano", - "Ne", - "Pouze láska", - "Sport" - ], - "correct": 0, - "expl": "Swift." - }, - { - "prompt": "První cesta délka?", - "options": [ - "Jedna část knihy", - "Celá kniha", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Struktura." - }, - { - "prompt": "Velikost Gulliver v Lilliput?", - "options": [ - "Obří", - "Malý", - "Stejný", - "Ne" - ], - "correct": 0, - "expl": "Relativita." - }, - { - "prompt": "Velikost v Brobdingnag?", - "options": [ - "Malý", - "Obří", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Opak." - }, - { - "prompt": "Poselství?", - "options": [ - "Kritika lidské pýchy a společnosti", - "Lidé dokonalí", - "Ne", - "Válka dobrá" - ], - "correct": 0, - "expl": "Satira." - }, - { - "prompt": "Adaptace?", - "options": [ - "Filmy, zkrácené verze", - "Ne", - "Zakázáno", - "Ne" - ], - "correct": 0, - "expl": "Kultovní." - }, - { - "prompt": "Skoumal?", - "options": [ - "Překladatel", - "Gulliver", - "Swift", - "Ne" - ], - "correct": 0, - "expl": "CZ." - }, - { - "prompt": "Defoe Robinson?", - "options": [ - "Jiný autor cest", - "Swift Robinson", - "Totéž", - "Ne" - ], - "correct": 0, - "expl": "Rozdíl." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Gulliver ztroskotá u Lilliputu", - "Cesta mezi obry Brobdingnagu", - "Létající ostrov Laputa", - "Země Houyhnhnmů a Yahoů", - "Gulliver zidealizuje koně", - "Návrut a odcizení od lidí" - ] - } - ], - "plotMeaning": [ - "Pořadí: Lilliput → Brobdingnag → Laputa → Houyhnhnm → idealizace → návrat." - ] -} diff --git a/data/cetba/hamlet.json b/data/cetba/hamlet.json deleted file mode 100644 index 7bb6355..0000000 --- a/data/cetba/hamlet.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: William Shakespeare", - "Žánr: tragédie (drama)", - "Poprvé vydáno: kolem 1601", - "Děj/prostředí: dánský hrad Elsinore", - "Vyprávění/forma: divadelní hra, blankvers; překlad Nevrla" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Předstírané šílenství, intriky", - "Duch krále, pomsta", - "Politika Claudius, Gertrude", - "Filosofické monology", - "Smrt a morálka", - "Renesanční individualismus" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Hamlet – princ, pomstychtivý", - "Claudius – strýc, vrah krále", - "Gertrude – matka", - "Polonius – rádce", - "Ophelia – dcera Polonia", - "Horatio – Hamletův přítel" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "„Být či nebýt“", - "Duch otce", - "Předstírané šílenství", - "Pomsta a odklad", - "Opeliina smrt", - "Finále – duel, jed, smrt" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Shakespeare", - "Molière", - "Beckett", - "Goethe" - ], - "correct": 0, - "expl": "William Shakespeare." - }, - { - "prompt": "Žánr?", - "options": [ - "Tragédie", - "Komedie", - "Epos", - "Báseň" - ], - "correct": 0, - "expl": "Drama." - }, - { - "prompt": "Kde děj?", - "options": [ - "Elsinore, Dánsko", - "Praha", - "Řím", - "Londýn" - ], - "correct": 0, - "expl": "Hrad." - }, - { - "prompt": "Hamlet?", - "options": [ - "Princ pomstychtivý", - "Král", - "Klaun", - "Ne" - ], - "correct": 0, - "expl": "Hrdina." - }, - { - "prompt": "Claudius?", - "options": [ - "Vrah otce, nový král", - "Hamlet", - "Horatio", - "Ne" - ], - "correct": 0, - "expl": "Antagonista." - }, - { - "prompt": "Duch?", - "options": [ - "Volá k pomstě", - "Ne", - "Ophelia", - "Ne" - ], - "correct": 0, - "expl": "Začátek akce." - }, - { - "prompt": "Ophelia?", - "options": [ - "Zblázní se, utopí", - "Královna", - "Vrah", - "Ne" - ], - "correct": 0, - "expl": "Tragédie." - }, - { - "prompt": "Polonius?", - "options": [ - "Rádce, zabit Hamletem", - "Král", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Intriky." - }, - { - "prompt": "Horatio?", - "options": [ - "Věrný přítel", - "Vrah", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Svědek." - }, - { - "prompt": "Být či nebýt?", - "options": [ - "Monolog o existenci", - "Ne", - "Konec", - "Ne" - ], - "correct": 0, - "expl": "Slavný monolog." - }, - { - "prompt": "Předstírané šílenství?", - "options": [ - "Hamletova taktika", - "Ne", - "Ophelia", - "Ne" - ], - "correct": 0, - "expl": "Strategie." - }, - { - "prompt": "Laertes?", - "options": [ - "Bratr Ophelie, duel", - "Král", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Souboj." - }, - { - "prompt": "Gertrude?", - "options": [ - "Matka, provdá se za Claudius", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Rodina." - }, - { - "prompt": "Rok?", - "options": [ - "Kolem 1601", - "1989", - "500", - "2000" - ], - "correct": 0, - "expl": "Renesance." - }, - { - "prompt": "Překlad?", - "options": [ - "Nevrla", - "Hilský", - "Nezval", - "Kořán" - ], - "correct": 0, - "expl": "Katalog Nevrla." - }, - { - "prompt": "Konec?", - "options": [ - "Hamlet, Claudius, Gertrude mrtví", - "Svatba", - "Raj", - "Ne" - ], - "correct": 0, - "expl": "Krvavé finále." - }, - { - "prompt": "Představení hry?", - "options": [ - "Past na Claudia", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Odhalení viny." - }, - { - "prompt": "Yorick?", - "options": [ - "Lebka klauna – memento mori", - "Král", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Symbol." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Největší tragédie", - "Nejkratší", - "Bez smyslu", - "Jen film" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Hamlet", - "Claudius", - "Romeo hlavní zde", - "Ophelia" - ], - "correct": 2, - "expl": "Romeo jiná hra." - }, - { - "prompt": "Blankvers?", - "options": [ - "Ne rýmovaný verš", - "Proza", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Forma." - }, - { - "prompt": "Rosenkranz a Guildenstern?", - "options": [ - "Vyslanci, zahynou", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Intriky." - }, - { - "prompt": "Norwegian Fortinbras?", - "options": [ - "Nástup moci na konci", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Politika." - }, - { - "prompt": "Téma pomsty?", - "options": [ - "Centrální", - "Ne", - "Sport", - "Ne" - ], - "correct": 0, - "expl": "Osud." - }, - { - "prompt": "Filozofie?", - "options": [ - "Hamlet přemýšlí", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Renesance." - }, - { - "prompt": "Katalog?", - "options": [ - "Drama", - "Próza", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Drama." - }, - { - "prompt": "Shakespeare jazyk?", - "options": [ - "Anglicky", - "Česky originál", - "Latina", - "Ne" - ], - "correct": 0, - "expl": "Originál." - }, - { - "prompt": "Divadlo Globe?", - "options": [ - "Kontext", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Elisabethan." - }, - { - "prompt": "Poselství?", - "options": [ - "Mstivost a nejistota vedou ke zkáze", - "Pomsta vždy dobrá", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Tragédie." - }, - { - "prompt": "Hilský?", - "options": [ - "Jiný překlad Shakespeare", - "Hamlet autor", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Romeo Hilský." - }, - { - "prompt": "Ofélie květiny?", - "options": [ - "Symbol šílenství", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Scéna." - }, - { - "prompt": "Jed?", - "options": [ - "Claudius otráví meč i víno", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Finále." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Duch vyzve Hamleta k pomstě", - "Hamlet předstírá šílenství a váhá", - "Past divadelní hrou", - "Hamlet zabije Polonia", - "Ophelia umírá, Hamlet se vrací", - "Duel a smrt hlavních postav" - ] - } - ], - "plotMeaning": [ - "Pořadí: duch → šílenství → hra v hře → Polonius → Ophelia → finální masakr." - ] -} diff --git a/data/cetba/havran.json b/data/cetba/havran.json deleted file mode 100644 index 260291b..0000000 --- a/data/cetba/havran.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Edgar Allan Poe", - "Žánr: balada / lyricko-epická báseň", - "Poprvé vydáno: 1845", - "Děj/prostředí: půlnoční komnata, mluvčí a havran", - "Vyprávění/forma: ich-forma, rým, refrain „Nevermore“" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Gotická atmosféra, tma, prosinec", - "Smrt milované Lenore", - "Mystický havran na bustě Pallas", - "Psychický rozpad vypravěče", - "Symbolika noční můry", - "Americká romantika" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Vypravěč – sám, truchlící", - "Havran – mluví jediné slovo", - "Lenore – mrtvá milovaná (zmínka)", - "Pallas – busta bohyně", - "Anděl / démon symbolicky", - "Nepřítomní hosté" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Nevermore – refrén beznaděje", - "Havran – paměť, zlo", - "Lenore – ztracená láska", - "Půlnoc – hranice života/smrti", - "Gotický interiér", - "Opakující se struktura strof" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Poe", - "Whitman", - "Orwell", - "Nezval" - ], - "correct": 0, - "expl": "Edgar Allan Poe." - }, - { - "prompt": "Rok?", - "options": [ - "1845", - "1600", - "1920", - "2000" - ], - "correct": 0, - "expl": "19. století." - }, - { - "prompt": "Žánr?", - "options": [ - "Balada / báseň", - "Román", - "Drama", - "Esej" - ], - "correct": 0, - "expl": "Poezie." - }, - { - "prompt": "Refrén?", - "options": [ - "Nevermore (Nikdy více)", - "To be", - "451", - "Godot" - ], - "correct": 0, - "expl": "Havran opakuje." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Truchlící muž ich", - "Havran ich", - "Lenore", - "Vševěd" - ], - "correct": 0, - "expl": "Subjekt." - }, - { - "prompt": "Lenore?", - "options": [ - "Mrtvá milovaná", - "Havran", - "Královna", - "Ne" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Kdy děj?", - "options": [ - "Půlnoc, prosinec", - "Poledne", - "Léto", - "Ne" - ], - "correct": 0, - "expl": "Atmosféra." - }, - { - "prompt": "Havran kde?", - "options": [ - "Na bustě Pallas", - "V lese", - "V moři", - "Ne" - ], - "correct": 0, - "expl": "Obraz." - }, - { - "prompt": "Pallas?", - "options": [ - "Busta bohyně moudrosti", - "Město", - "Lenore", - "Ne" - ], - "correct": 0, - "expl": "Symbol." - }, - { - "prompt": "Tón?", - "options": [ - "Temný, melancholický", - "Veselý", - "Komický", - "Ne" - ], - "correct": 0, - "expl": "Gotika." - }, - { - "prompt": "Struktura?", - "options": [ - "Strofy s refrénem", - "Proza", - "Drama", - "Ne" - ], - "correct": 0, - "expl": "Forma." - }, - { - "prompt": "Vypravěč stav?", - "options": [ - "Klesá do beznaděje", - "Radost", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Psychika." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasika poezie", - "Nejdelší román", - "Bez smyslu", - "Jen film" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Gotika?", - "options": [ - "Ano", - "Ne", - "Realismus", - "Ne" - ], - "correct": 0, - "expl": "Směr." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Havran", - "Lenore", - "Hamlet celá hra", - "Nevermore" - ], - "correct": 2, - "expl": "Hamlet drama." - }, - { - "prompt": "Poe národnost?", - "options": [ - "Americký", - "Český", - "Irský", - "Ne" - ], - "correct": 0, - "expl": "USA." - }, - { - "prompt": "Katalog?", - "options": [ - "Poezie", - "Próza", - "Drama", - "Opera" - ], - "correct": 0, - "expl": "Poezie." - }, - { - "prompt": "Havran symbol?", - "options": [ - "Vzpomínka, zlo, bezmoc", - "Ne", - "Láska", - "Ne" - ], - "correct": 0, - "expl": "Interpretace." - }, - { - "prompt": "Otázky vypravěče?", - "options": [ - "Na havrana o Lenore a smyslu", - "Ne", - "Sport", - "Ne" - ], - "correct": 0, - "expl": "Dialog." - }, - { - "prompt": "Konec?", - "options": [ - "Vypravěč v beznaději", - "Svatba", - "Raj", - "Ne" - ], - "correct": 0, - "expl": "Tma." - }, - { - "prompt": "Rým?", - "options": [ - "Použit", - "Ne", - "Proza", - "Ne" - ], - "correct": 0, - "expl": "Balada." - }, - { - "prompt": "December?", - "options": [ - "Zmíněno – zima", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Atmosféra." - }, - { - "prompt": "Tapeta?", - "options": [ - "Gotický pokoj", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Prostředí." - }, - { - "prompt": "Anděl Lenore?", - "options": [ - "Vypravěč se ptá", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Strofa." - }, - { - "prompt": "Poselství?", - "options": [ - "Ztráta a beznaděj lze vyjádřit symbolem", - "Radost", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Téma." - }, - { - "prompt": "Poe jiná díla?", - "options": [ - "Jiná básně, povídky", - "Hamlet", - "1984", - "Ne" - ], - "correct": 0, - "expl": "Autor." - }, - { - "prompt": "Mluví havran víc?", - "options": [ - "Jen Nevermore", - "Dlouhé monology", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Refrén." - }, - { - "prompt": "Ich-forma?", - "options": [ - "Ano", - "Er", - "Bez já", - "Ne" - ], - "correct": 0, - "expl": "Lyrika." - }, - { - "prompt": "Balada charakter?", - "options": [ - "Příběh + lyrické", - "Epos", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Žánr." - }, - { - "prompt": "Čtení maturita?", - "options": [ - "Autor, refrén, symbolika", - "Jen překlad", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Základ." - }, - { - "prompt": "Knocking?", - "options": [ - "Zpočátku klepání", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Začátek." - }, - { - "prompt": "Bust?", - "options": [ - "Socha Pallas", - "Lenore", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Detail." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Vypravěč truchlí v půlnočním pokoji", - "Klepání a příchod havrana", - "Havran usedne na bustu Pallas", - "Vypravěč klade otázky o Lenore", - "Havran opakuje Nevermore", - "Beznaděj vypravěče roste do konce" - ] - } - ], - "plotMeaning": [ - "Pořadí: truchlení → klepání → havran → otázky → refrén → beznaděj." - ] -} diff --git a/data/cetba/hladove-hry.json b/data/cetba/hladove-hry.json deleted file mode 100644 index ec0421c..0000000 --- a/data/cetba/hladove-hry.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Suzanne Collins", - "Žánr: dystopický young adult román", - "Poprvé vydáno: 2008 (I. Aréna smrti)", - "Děj/prostředí: Panem, Kapitol, aréna", - "Vyprávění/forma: ich-forma Katniss; překlad Dušek" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Postapokalyptický stát Panem", - "Kapitol vládne 12 okresům", - "Hladové hry – televizní boj na smrt", - "Chudoba okresů vs. luxus Kapitolu", - "Rebelii potlačují", - "Survival a mediální show" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Katniss Everdeen – vypravěčka, lovkyně", - "Peeta Mellark – spoluhráč z Pece", - "Gale – přítel z Distraktu 12", - "Haymitch – vítěz, mentor", - "Effie Trinket – escort", - "Cinna – stylista" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Aréna – bojiště", - "Sponzoři – pomoc diváků", - "Předstíraná láska", - "Mockingjay symbol", - "Tribut – tributář", - "Odpor proti Kapitolu" - ] - } - ], - "quiz": [ - { - "prompt": "Autorka?", - "options": [ - "Collins", - "Rowling", - "Orwell", - "Viewegh" - ], - "correct": 0, - "expl": "Suzanne Collins." - }, - { - "prompt": "Rok?", - "options": [ - "2008", - "1984", - "1950", - "1862" - ], - "correct": 0, - "expl": "První díl." - }, - { - "prompt": "Panem?", - "options": [ - "Dystopický stát", - "Praha", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Prostředí." - }, - { - "prompt": "Katniss?", - "options": [ - "Hrdinka z Distraktu 12", - "Kapitol", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Ich." - }, - { - "prompt": "Peeta?", - "options": [ - "Chlapec z Pece, péká chleba", - "Kapitol", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Partner." - }, - { - "prompt": "Hladové hry?", - "options": [ - "Boj na smrt na TV", - "Sport", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Koncept." - }, - { - "prompt": "12 okresů?", - "options": [ - "Pod Kapitolem", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Struktura." - }, - { - "prompt": "Haymitch?", - "options": [ - "Mentor, vítěz", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Mockingjay pin?", - "options": [ - "Symbol od Madge/symbol odporu", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Předstíraná láska?", - "options": [ - "Strategie v aréně", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Peeta+Katniss." - }, - { - "prompt": "Gale?", - "options": [ - "Přítel doma", - "Kapitol", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Love triangle." - }, - { - "prompt": "Effie?", - "options": [ - "Escort Kapitolu", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Cinna?", - "options": [ - "Stylista Katniss", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Podpora." - }, - { - "prompt": "Překlad?", - "options": [ - "Dušek", - "Nezval", - "Kořán", - "Nevrla" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "Žánr?", - "options": [ - "Dystopický YA román", - "Epos", - "Drama", - "Lyrika" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Aréna I. díl?", - "options": [ - "Lesní aréna", - "Moře", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Boj." - }, - { - "prompt": "Rue?", - "options": [ - "Tribut z 11, smrt", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Emoce." - }, - { - "prompt": "Kapitol?", - "options": [ - "Bohaté centrum", - "Chudé", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Moc." - }, - { - "prompt": "Vítězství I. díl?", - "options": [ - "Katniss a Peeta oba", - "Jen Gale", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Pravidlo změněno." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Moderní dystopie", - "Nejstarší", - "Bez témat", - "Ne" - ], - "correct": 0, - "expl": "Čtení." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Katniss", - "Peeta", - "Hamlet", - "Haymitch" - ], - "correct": 2, - "expl": "Shakespeare." - }, - { - "prompt": "Téma média?", - "options": [ - "Hry jako show", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Kritika." - }, - { - "prompt": "Lov?", - "options": [ - "Katniss dovednost", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Přežití." - }, - { - "prompt": "Prim?", - "options": [ - "Mladší sestra", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Do volunteer?", - "options": [ - "Katniss místo Prim", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Začátek." - }, - { - "prompt": "Sponzoři?", - "options": [ - "Posílají dárky", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Pravidla." - }, - { - "prompt": "Katalog titul?", - "options": [ - "Hladové hry – I. Aréna smrti", - "1984", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "Poselství?", - "options": [ - "Moc a zábava z utrpení jsou nebezpečné", - "Hry dobré", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Dystopie." - }, - { - "prompt": "Snow president?", - "options": [ - "Vůdce Kapitolu", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Antagonista." - }, - { - "prompt": "Berries?", - "options": [ - "Finále – hrozba sebevraždy", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Vítězství." - }, - { - "prompt": "Ich-forma?", - "options": [ - "Katniss", - "Er", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Vypravěč." - }, - { - "prompt": "Trilogie?", - "options": [ - "3 knihy celkem", - "1", - "10", - "Ne" - ], - "correct": 0, - "expl": "Série." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Katniss se přihlásí místo Prim", - "Příprava v Kapitolu a trénink", - "Vstup do arény Hladových her", - "Boj o přežití a smrt Rue", - "Strategie s Peetou a sponzory", - "Vítězství obou a provokace Kapitolu" - ] - } - ], - "plotMeaning": [ - "Pořadí: dobrovolnice → Kapitol → aréna → přežití → Peeta → vítězství." - ] -} diff --git a/data/cetba/hlava-xxii.json b/data/cetba/hlava-xxii.json deleted file mode 100644 index 8264073..0000000 --- a/data/cetba/hlava-xxii.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Joseph Heller", - "Žánr: anti válečný / absurdní román", - "Poprvé vydáno: 1961", - "Děj/prostředí: WWII, letecká základna Pianosa", - "Vyprávění/forma: er-forma, nelineární, ironie; překlad Jindra" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Druhá světová válka – absurdita", - "Byrokracie armády", - "Opakující se nálety", - "Catch-22 logická past", - "Smrt Yossarianových přátel", - "Touha desertovat" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Yossarian – bombardér, chce přežít", - "Colonel Cathcart – eskaluje nálety", - "Milieu Minderbinder – obchodník M&M", - "Doc Daneeka – „mrtvý“ doktor", - "Nately – mladý pilot", - "Snowden – smrt v letadle" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Catch-22 – past pravidel", - "Absurdita války", - "Obchod s válkou (M&M)", - "Snowden „Au chaud“", - "Přežít vs. povinnost", - "Černý humor" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Heller", - "Remarque", - "Hemingway", - "Orwell" - ], - "correct": 0, - "expl": "Joseph Heller." - }, - { - "prompt": "Rok?", - "options": [ - "1961", - "1945", - "1984", - "2000" - ], - "correct": 0, - "expl": "Poválečný román." - }, - { - "prompt": "Yossarian?", - "options": [ - "Bombardér toužící utéct", - "Generál", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Hrdina." - }, - { - "prompt": "Catch-22?", - "options": [ - "Pravidlová past – nemůžeš být prohlážen bláznem", - "Letadlo", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Titul." - }, - { - "prompt": "Válka?", - "options": [ - "WWII", - "Vietnam", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Pianosa?", - "options": [ - "Italská základna fikce", - "Praha", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Místo." - }, - { - "prompt": "M&M?", - "options": [ - "Milieu prodává na černém trhu", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Cathcart?", - "options": [ - "Zvyšuje nálety", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Důstojník." - }, - { - "prompt": "Snowden?", - "options": [ - "Smrt odhalí absurditu", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Scéna." - }, - { - "prompt": "Doc Daneeka?", - "options": [ - "„Mrtvý“ na papíře", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Byrokracie." - }, - { - "prompt": "Žánr?", - "options": [ - "Anti válečný absurdní román", - "Pohádka", - "Epos", - "Lyrika" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Překlad?", - "options": [ - "Jindra", - "Nezval", - "Dušek", - "Nevrla" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "Nelineární?", - "options": [ - "Ano čas skáče", - "Ne", - "Lineární", - "Ne" - ], - "correct": 0, - "expl": "Forma." - }, - { - "prompt": "Humor?", - "options": [ - "Černý ironický", - "Ne", - "Slapstick", - "Ne" - ], - "correct": 0, - "expl": "Styl." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasika 20. stol.", - "Nejkratší", - "Bez smyslu", - "Ne" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Yossarian", - "Catch-22", - "Hamlet", - "M&M" - ], - "correct": 2, - "expl": "Shakespeare." - }, - { - "prompt": "Remarque vs Heller?", - "options": [ - "Obě válka, jiný styl", - "Totéž", - "Remarque Catch", - "Ne" - ], - "correct": 0, - "expl": "Různí." - }, - { - "prompt": "Nately?", - "options": [ - "Zamilovaný, tragicky", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Nálety?", - "options": [ - "Opakující se nebezpečné", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Desertace?", - "options": [ - "Yossarian chce", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Cíl." - }, - { - "prompt": "Er-forma?", - "options": [ - "Ano", - "Ich Katniss", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Absurdita?", - "options": [ - "Byrokracie války", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Téma." - }, - { - "prompt": "Katalog?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "22?", - "options": [ - "Číslo v pasti", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Titul." - }, - { - "prompt": "Snowden v letadle?", - "options": [ - "Krvavá smrt", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Trauma." - }, - { - "prompt": "Otrava?", - "options": [ - "Yossarian v nemocnici", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Epizody." - }, - { - "prompt": "Poselství?", - "options": [ - "Válka a byrokracie jsou absurdní", - "Válka slavná", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Anti válka." - }, - { - "prompt": "Série?", - "options": [ - "Jedna kniha (+ sequel)", - "10", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Hlava XXII." - }, - { - "prompt": "Ironie?", - "options": [ - "Hlavní prostředek", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Styl." - }, - { - "prompt": "Jindra?", - "options": [ - "Překladatel", - "Yossarian", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "CZ." - }, - { - "prompt": "Konec?", - "options": [ - "Yossarian se rozhodne utéct", - "Válka slaví", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Únik." - }, - { - "prompt": "Letectvo?", - "options": [ - "Bombardéry", - "Ne", - "Ne", - "Ne" - ], - "correct": 0, - "expl": "Armáda." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Yossarian na základně Pianosa", - "Opakované nebezpečné nálety", - "Catch-22 blokuje prohlášení blázna", - "Smrt přátel včetně Snowdena", - "Byrokratické absurdity a M&M", - "Rozhodnutí utéct z armády" - ] - } - ], - "plotMeaning": [ - "Pořadí: základna → nálety → Catch-22 → smrti → absurdita → útěk." - ] -} diff --git a/data/cetba/ivan-denisovic.json b/data/cetba/ivan-denisovic.json deleted file mode 100644 index b40db0e..0000000 --- a/data/cetba/ivan-denisovic.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Alexandr Solovjov (Solženicyn), 1918–2008", - "Žánr: realistická próza, gulagovská novela", - "Poprvé vydáno: 1962 (časopis Nový svět)", - "Děj / prostředí: Sibiř, tábor SHIZ-84, leden 1951", - "Vyprávění / forma: er-forma, chronika jednoho dne vězně" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Stalinismus: trest za drobné „zločiny“, systém gulagů a nútěné práce.", - "Den vězně je řízen rozkazem, kamerou strachu a bojem o přežití.", - "Tábor není místo mučení popsaného naturalisticky, ale každodenní útlak.", - "Solidarita, lstivost i malé vítězství (jídlo, teplo) mají obrovskou cenu.", - "Novela otevřela v SSSR diskusi o gulagu; autor později dostal Nobelovu cenu.", - "Titulní hrdina je „obyčejný“ Rus, ne hrdina ideologie." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ivan Denisovič Šuchov – dělník, trest 10 let, zkušený táborový vězeň.", - "Tiurin – velitel brigády, tvrdý, ale brání svou partu.", - "Fetiukov – vězeň, který se plazí před mocí, končí v kobce.", - "Buynovsky – bývalý námořní důstojník, idealista, bitý dozorci.", - "Alyoška – baptistický vězeň, víra a pokora.", - "Der – dozorce, symbol bezcitné moci tábora." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Gulag – systém sovětských pracovních táborů.", - "Jeden den – forma zdůrazňující monotónnost i tíhu času.", - "Brigáda – skupina vězňů, základ přežití a solidarity.", - "Kobka – trestová cela, hrozba pro každého.", - "Dignita v nouzi – Šuchov si zachovává lidskost v detailech.", - "Alyoškova víra – kontrast k ateistické moci i k pragmatismu." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Jeden den Ivana Denisoviče?", "options": ["Dostojevskij", "Alexandr Solovjov (Solženicyn)", "Tolstoj", "Bulgakov"], "correct": 1, "expl": "Solženicyn román publikoval v roce 1962; sám strávil roky v táborech."}, - {"prompt": "Jaký časový rozsah děj pokrývá?", "options": ["Celý život hrdiny", "Jeden den v táboře", "Jeden rok", "24 hodin v Moskvě"], "correct": 1, "expl": "Forma jednoho dne zvýrazňuje opakující se útlak i drobné radosti."}, - {"prompt": "Kde se děj odehrává?", "options": ["V Moskvě", "V pracovním táboře SHIZ-84 na Sibiři", "V Paříži", "Na frontě 2. sv. války"], "correct": 1, "expl": "Tábor v mrazivém lednu 1951 je hlavním prostředím."}, - {"prompt": "Za co je Šuchov v táboře?", "options": ["Za vraždu", "Za údajnou spolupráci s Němci (desertérství)", "Za krádež banky", "Za protisovětskou agitaci"], "correct": 1, "expl": "Šuchov byl odsouzen na 10 let; obvinění je typické pro dobu represí."}, - {"prompt": "Kdo vede Šuchovovu brigádu?", "options": ["Der", "Tiurin", "Fetiukov", "Stalin"], "correct": 1, "expl": "Tiurin je zkušený velitel, který umí jednat s dozory i chránit muže."}, - {"prompt": "Co je hlavní prací brigády v popisovaný den?", "options": ["Těžba uhlí v dole", "Stavba zdi v mrazu", "Pěstování brambor", "Výroba zbraní"], "correct": 1, "expl": "Vězni staví zeď z cihel; práce venku v mrazu je fyzicky krutá."}, - {"prompt": "Proč je pro Šuchova důležité jídlo?", "options": ["Je gurmán", "Kalorie znamenají přežití; každá lžíce má cenu", "Chce vařit pro dozory", "Nesmí jíst"], "correct": 1, "expl": "Táborový denní režim stojí na hladu a boji o porci."}, - {"prompt": "Kdo je Fetiukov a jak končí?", "options": ["Velitel tábora", "Vězeň, který se plazí; skončí v kobce", "Kněz", "Šuchovův bratr"], "correct": 1, "expl": "Fetiukov lichotí moci, ale stejně je potrestán – systém je nelítostný."}, - {"prompt": "Co symbolizuje Alyoška baptista?", "options": ["Zradu", "Víru a vnitřní svobodu uprostřed útlaku", "Bohatství", "Dozor"], "correct": 1, "expl": "Alyoška nachází smysl v modlitbě a morálce, ne v systému."}, - {"prompt": "Jak Šuchov zachází s cihlami a prací?", "options": ["Pracuje nedbalě", "Pečlivě, s hrdostí řemeslníka – zachovává důstojnost", "Odmítá pracovat", "Kradne cihly"], "correct": 1, "expl": "Kvalitní práce je forma sebeúcty v degradujících podmínkách."}, - {"prompt": "Co je kobka v táboře?", "options": ["Restaurace", "Trestová cela v mrazu", "Knihovna", "Nemocnice"], "correct": 1, "expl": "Hrozba kobky udržuje strach; Fetiukov ji za den navštíví."}, - {"prompt": "Proč román vyvolal senzaci v SSSR?", "options": ["Byl první schválenou prózou o gulagu", "Byl komiksovou adaptací", "Popisoval budoucnost", "Nebyl vůbec publikován"], "correct": 0, "expl": "Chruščovova otopa umožnila publikaci; téma bylo dříve tabu."}, - {"prompt": "Jaký je tón vyprávění?", "options": ["Patetický heroismus", "Střízlivý, věcný, bez zbytečné patetiky", "Groteskní komedie", "Pohádkový"], "correct": 1, "expl": "Solženicyn popisuje fakta chladně; emoce vyrůstají z detailů."}, - {"prompt": "Co Šuchov považuje na konci dne?", "options": ["Za nejhorší den života", "Za téměř šťastný den – přežil, jedl, pracoval", "Za den svatby", "Za den propuštění"], "correct": 1, "expl": "Závěrečná ironie: v táboře stačí malé věci k pocitu „štěstí“."}, - {"prompt": "Kdo je Der?", "options": ["Vězeň", "Dozorce, představitel moci", "Lékař", "Tiurinův bratr"], "correct": 1, "expl": "Der reprezentuje bezcitnou administrativu trestu."}, - {"prompt": "Jaký žánr nejlépe vystihuje dílo?", "options": ["Sci-fi", "Realistická gulagovská novela", "Romantický epos", "Detektivka"], "correct": 1, "expl": "Dílo dokumentuje zkušenost tábora realistickou formou."}, - {"prompt": "Co je brigáda v táboře?", "options": ["Politická strana", "Pracovní skupina vězňů pod velitelem", "Rodina dozorců", "Církevní společenství"], "correct": 1, "expl": "Solidarita v brigádě může zlepšit šanci na přežití."}, - {"prompt": "Proč Buynovsky trpí?", "options": ["Je nemocný", "Konfrontuje dozory jako bývalý důstojník", "Je dítě", "Neumí pracovat"], "correct": 1, "expl": "Jeho hrdost a vzdělání ho v systému tábora trestají."}, - {"prompt": "Jak román vztahuje k totalitě?", "options": ["Totalitu oslavuje", "Ukazuje dehumanizaci a strach v každodennosti", "Nezmiňuje politiku", "Popisuje jen přírodu"], "correct": 1, "expl": "Tábor je mikrokosmos stalinistického útlaku."}, - {"prompt": "Kdy autor sám strávil v táborech?", "options": ["Nikdy", "Po 2. sv. válce (kritika Stalina v dopise)", "Za carismu", "V 90. letech"], "correct": 1, "expl": "Solženicyn byl odsouzen za kritiku režimu; psal z vlastní zkušenosti."}, - {"prompt": "Co Šuchov dělá s chlebem a porcí?", "options": ["Vyhazuje je", "Šetří, plánuje, chrání před krádeží", "Dává dozorcům", "Nejí"], "correct": 1, "expl": "Jídlo je táborová měna i symbol přežití."}, - {"prompt": "Jaký význam má mrazivé počasí?", "options": ["Jen kulisa", "Další nepřítel vězňů, zvyšuje fyzické utrpení", "Nezmiňuje se", "Slouží k odpočinku"], "correct": 1, "expl": "Mráz při práci na zdi je součástí trestu."}, - {"prompt": "Která postava reprezentuje „plazení se“?", "options": ["Tiurin", "Fetiukov", "Šuchov", "Alyoška"], "correct": 1, "expl": "Fetiukov lichotí a ponižuje se, stejně ale neunikne trestu."}, - {"prompt": "Co znamená „dignita v nouzi“ u Šuchova?", "options": ["Povýšení do dozoru", "Lidskost v detailech – práce, pořádek, slušnost", "Vzdor v podobě vraždy", "Úplná apatie"], "correct": 1, "expl": "Šuchov si udržuje sebeúctu, i když systém ji ničí."}, - {"prompt": "Jaký Nobelův význam má Solženicyn?", "options": ["Za poezii", "Za literaturu (1970)", "Za mír 2000", "Nedostal Nobelovu cenu"], "correct": 1, "expl": "Nobelova cena za literaturu 1970; autor ji přijal až 1974."}, - {"prompt": "Proč forma „jednoho dne“ funguje?", "options": ["Den je nudný bez děje", "Opakuje se každý den; jeden den ukazuje celý mechanismus útlaku", "Den je fiktivní", "Den trvá rok"], "correct": 1, "expl": "Monotónnost je horší než jednorázová katastrofa."}, - {"prompt": "Co NENÍ typické pro román?", "options": ["Popis práce a jídla", "Naturalistické popisy mučíren", "Postavy vězňů", "Mrazivé počasí"], "correct": 1, "expl": "Dílo spíše věcně popisuje každodennost než explicitní mučení."}, - {"prompt": "Jak Tiurin pomáhá brigádě?", "options": ["Zrazuje ji", "Vyjednává materiál, chrání muže před zbytečnými tresty", "Nevede ji", "Prodává je"], "correct": 1, "expl": "Tiurin je praktický vůdce v nelidském systému."}, - {"prompt": "Jaký je vztah Šuchova k Alyoškovi?", "options": ["Nenávist", "Respekt k víře, i když sám není věřící", "Sourozenec", "Dozor"], "correct": 1, "expl": "Na konci dne si Šuchov vyslechne Alyoškovo slovo o smyslu."}, - {"prompt": "Jaké poselství román přináší?", "options": ["Tábor je dobrodružství", "I v totálním systému záleží na lidskosti, solidaritě a vnitřní svobodě", "Vězni si zaslouží trest", "Práce není důležitá"], "correct": 1, "expl": "Malé vítězství a morálka jsou formou odporu proti dehumanizaci."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Ranní budíček a kontrola v barracích", - "Šuchov bojuje o jídlo a teplo", - "Brigáda odchází stavět zeď v mrazu", - "Tiurin vyjednává cihly a chrání partu", - "Fetiukov končí v kobce; Buynovsky je bit", - "Večer: Šuchov považuje den za téměř dobrý" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: ráno v táboře → jídlo a příprava → práce na zdi → vedení Tiurina → tresty → večerní reflexe Šuchova." - ] -} diff --git a/data/cetba/jak-jsem-vyhral-valku.json b/data/cetba/jak-jsem-vyhral-valku.json deleted file mode 100644 index 14b983d..0000000 --- a/data/cetba/jak-jsem-vyhral-valku.json +++ /dev/null @@ -1,248 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Patrick Ryan (1925–1989), irský spisovatel", - "Žánr: satirický válečný román, černá komedie", - "Poprvé vydáno: 1963", - "Děj / prostředí: 2. světová válka, britská armáda (Evropa, severní Afrika)", - "Vyprávění / forma: ich-forma, vypravěč poručík Ernest Goodbody" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Román paroduje válečné memoáry a heroické mýty o druhé světové válce.", - "Goodbody věří v řád, čest a smysl války; realita je chaos a absurdita.", - "Jednotka plní nesmyslné rozkazy, trpí nekompetencí velení i vlastní naivitou.", - "Satira míří na vojenskou hierarchii, byrokracii a propagandistický jazyk.", - "Film Mikea Nicholse (1967) s Johnem Lennonem dílo zpopularizoval.", - "Tón je ironický: čtenář vidí pravdu, kterou vypravěč nechápe." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ernest Goodbody – naivní poručík, vypravěč, přesvědčen, že válku „vyhrál“.", - "Clapper – cynický seržant, praktický protiklad Goodbodyho idealismu.", - "Spool, Dooley, další vojáci – absurdní situace fronty a týlu.", - "Nadřízení důstojníci – často neschopní, kariérističtí nebo groteskní.", - "Goodbody jako antihrdina – „vítěz“ bez schopností i sebeironie." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Satira války – výsměch slavnostním válečným příběhům.", - "Nespolehlivý vypravěč – Goodbody popisuje realitu zkresleně.", - "Černý humor – smrt a tragédie podány s nadhledem.", - "Absurdita rozkazů – vojenský systém funguje proti logice.", - "Ironie titulu – válku nikdo nevyhrál, natož Goodbody.", - "Antimilitarismus – skryté poselství proti glorifikaci války." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je autorem románu Jak jsem vyhrál válku?", - "options": ["Joseph Heller", "Patrick Ryan", "Ernest Hemingway", "Kurt Vonnegut"], - "correct": 1, - "expl": "Román napsal irský spisovatel Patrick Ryan; vyšel v roce 1963." - }, - { - "prompt": "Kdo vypráví příběh a jakou hodnost má?", - "options": ["Seržant Clapper", "Poručík Ernest Goodbody", "Generál britské armády", "Vojín Spool"], - "correct": 1, - "expl": "Vypravěčem je poručík Goodbody v ich-formě; jeho naivita je klíčem k satiře." - }, - { - "prompt": "Jaký žánr román reprezentuje?", - "options": ["Historický epos", "Satirický válečný román / černá komedie", "Detektivka", "Romantický milostný příběh"], - "correct": 1, - "expl": "Dílo paroduje válečné memoáry a používá ironii i černý humor." - }, - { - "prompt": "V jakém období se děj odehrává?", - "options": ["1. světová válka", "2. světová válka", "Válka ve Vietnamu", "Fiktivní budoucnost"], - "correct": 1, - "expl": "Děj sleduje britskou armádu během druhé světové války." - }, - { - "prompt": "Proč je Goodbody typickým antihrdinou?", - "options": ["Je statečný a skromný", "Je naivní, neschopný a nechápe absurditu kolem sebe", "Je zrádce", "Je generál bez chyb"], - "correct": 1, - "expl": "Goodbody věří vlastnímu idealismu, zatímco čtenář vidí jeho směšnost i nekompetenci." - }, - { - "prompt": "Jakou roli hraje seržant Clapper?", - "options": ["Romantický partner", "Cynický protiklad naivního Goodbodyho", "Německý zajatec", "Válečný correspondent"], - "correct": 1, - "expl": "Clapper reprezentuje praktický, skeptický pohled na válku oproti Goodbodyho iluzím." - }, - { - "prompt": "Co satira v románu nejčastěji kritizuje?", - "options": ["Sport a zábavu", "Heroické mýty, hierarchii a absurditu vojenského systému", "Venkovský život", "Školství"], - "correct": 1, - "expl": "Ryan vystavuje posměchu slavnostní válečné rétoriky a neschopnosti velení." - }, - { - "prompt": "Jak funguje ironie titulu Jak jsem vyhrál válku?", - "options": ["Goodbody skutečně porazil Němce sám", "Titul je vážný hold hrdinovi", "Vypravěč si myslí, že válku vyhrál, ale čtenář ví, že jde o absurditu", "Jde o dokumentární reportáž"], - "correct": 2, - "expl": "Goodbody prezentuje chaos jako vítězství; titul je satirický kontrast k realitě." - }, - { - "prompt": "Který režisér zfilmoval román a kdy?", - "options": ["Stanley Kubrick, 1964", "Mike Nichols, 1967", "Steven Spielberg, 1998", "Roman Polanski, 1971"], - "correct": 1, - "expl": "Film z roku 1967 režíroval Mike Nichols; v roli Musgravea účinkoval i John Lennon." - }, - { - "prompt": "Co je typické pro vyprávění v ich-formě u Goodbodyho?", - "options": ["Objektivní chronika bez komentáře", "Vypravěč sám nechápe, jak směšný je", "Pohled třetí osoby vševědoucí", "Střídání deníkových zápisů mnoha hrdinů"], - "correct": 1, - "expl": "Goodbody popisuje události vážně a idealisticky; ironii vytváří odstup mezi ním a čtenářem." - }, - { - "prompt": "Jaký tón převládá v románu?", - "options": ["Patetický heroismus", "Ironický a černohumorý", "Lyricismus a nostalgie", "Horor bez komentáře"], - "correct": 1, - "expl": "Tragické situace jsou často podány s nadhledem a výsměchem." - }, - { - "prompt": "S jakým americkým románem se dílo často srovnává?", - "options": ["Starý muž a moře", "Chaplinova válka", "Chytil-22 (Catch-22)", "Bílá vrána"], - "correct": 2, - "expl": "Obě díla satiricky zpracovávají absurditu moderní války (Ryan 1963, Heller 1961)." - }, - { - "prompt": "Co Goodbody typicky zdůrazňuje ve svých výkladech?", - "options": ["Bezútěšnou realitu fronty", "Řád, čest a smysl vojenské služby", "Nenávist ke všem nadřízeným", "Desertérství"], - "correct": 1, - "expl": "Jeho idealismus kontrastuje s chaosem, který popisuje." - }, - { - "prompt": "Jak román vztahuje k propagandě?", - "options": ["Propagandu oslavuje", "Ukazuje, jak naivní víra v oficiální rétoriku odporuje zkušenosti", "Nezmiňuje ji", "Popisuje jen německou propagandu"], - "correct": 1, - "expl": "Goodbody přebírá klíčová slova o čestné válce; satira je demaskuje." - }, - { - "prompt": "Kde román nejčastěji situuje děj?", - "options": ["Jen v Londýně", "V prostředí britské armády v Evropě a severní Africe", "Pouze v Pacifiku", "V budoucní koloni Marsu"], - "correct": 1, - "expl": "Děj sleduje pohyby jednotky v rámci válečných operací mimo Velkou Británii." - }, - { - "prompt": "Co je „černý humor“ v kontextu díla?", - "options": ["Vtipy bez souvislosti s dějem", "Komický odstup od tragických situací", "Pouze slovní hříčky", "Dětská komedie"], - "correct": 1, - "expl": "Smrt a absurdita jsou podány tak, že vyvolávají smích i pohoršení zároveň." - }, - { - "prompt": "Proč čtenář nedůvěřuje Goodbodyho hodnocení situací?", - "options": ["Goodbody lže vědomě", "Je nekompetentní a slepý k vlastním chybám", "Příběh nemá vypravěče", "Jde o pohádku"], - "correct": 1, - "expl": "Nespolehlivý vypravěč je základ satirického efektu." - }, - { - "prompt": "Jak v románu působí vojenská hierarchie?", - "options": ["Jako dokonalý meritokratický systém", "Jako zdroj absurdit a neschopnosti", "Vůbec se neobjevuje", "Jako romantická idealizace"], - "correct": 1, - "expl": "Velení a byrokracie často zhoršují situaci jednotky." - }, - { - "prompt": "Kdo z následujících patří k Goodbodyho jednotce?", - "options": ["Winston Smith", "Spool", "Jay Gatsby", "Heathcliff"], - "correct": 1, - "expl": "Spool je jedním z vojáků v absurdních situacích oddílu." - }, - { - "prompt": "Jaké poselství lze z románu vyčíst?", - "options": ["Válka je slavná a smysluplná", "Glorifikace války je nebezpečná iluze", "Vojáci jsou vždy hrdinové", "Satira je bez myšlenky"], - "correct": 1, - "expl": "Dílo varuje před naivním přijímáním válečných mýtů." - }, - { - "prompt": "V jakém jazyce původně román vyšel?", - "options": ["Česky", "Anglicky", "Německy", "Francouzsky"], - "correct": 1, - "expl": "Patrick Ryan psal anglicky; český překlad nese titul Jak jsem vyhrál válku." - }, - { - "prompt": "Co charakterizuje Goodbodyho styl vyprávění?", - "options": ["Vědecká přesnost", "Oficiální, sebejistý tón důstojníka", "Pouze dialogy bez komentáře", "Básnická próza"], - "correct": 1, - "expl": "Goodbody mluví jako někdo, kdo věří vlastní důležitosti a správnosti." - }, - { - "prompt": "Jak filmová adaptace ovlivnila povědomí o knize?", - "options": ["Knihu zcela potlačila", "Pomohla dílo prosadit i mimo literární kruhy", "Změnila žánr na horor", "Natáčela se před vydáním knihy"], - "correct": 1, - "expl": "Film z konce 60. let s hvězdným obsazením zvýšil popularitu románu." - }, - { - "prompt": "Co je typické pro válečné rozkazy v díle?", - "options": ["Vždy logické a účinné", "Často nesmyslné nebo kontraproduktivní", "Nejsou zmíněny", "Vydává je jen Goodbody"], - "correct": 1, - "expl": "Absurdita rozkazů ilustruje ztrátu smyslu války v praxi." - }, - { - "prompt": "Jaký kontrast tvoří jádro komiky románu?", - "options": ["Bohatí vs. chudí", "Goodbodyho idealismus vs. chaotická realita", "Město vs. venkov", "Muži vs. ženy bez válečného kontextu"], - "correct": 1, - "expl": "Rozdíl mezi tím, co Goodbody tvrdí, a tím, co se děje, je zdrojem satiry." - }, - { - "prompt": "Proč se román hodí k maturitní četbě?", - "options": ["Je jen dětskou knihou", "Spojuje historický kontext 2. sv. války s žánrem satiry a vyprávění", "Neobsahuje postavy", "Je encyklopedie zbraní"], - "correct": 1, - "expl": "Učí číst ironii, nespolehlivého vypravěče a historicko-společenský kontext." - }, - { - "prompt": "Jak Ryan pracuje s válečným hrdinstvím?", - "options": ["Oslavuje je bez výhrad", "Demaskuje ho jako prázdnou frázi", "Ignoruje frontu", "Popisuje jen námořnictvo"], - "correct": 1, - "expl": "Hrdinské selfi Goodbodyho je parodií tradičních válečných autobiografií." - }, - { - "prompt": "Co znamená „antimilitarismus“ v interpretaci knihy?", - "options": ["Oslava armády", "Kritika války a její glorifikace", "Neutralita bez názoru", "Propagace zbraní"], - "correct": 1, - "expl": "Satira podkopává důvody chválit válku jako morální nebo smysluplnou." - }, - { - "prompt": "Které téma NENÍ středem románu?", - "options": ["Absurdita války", "Naivita vypravěče", "Viktorianská společenská etiketa na venkově", "Vojenská hierarchie"], - "correct": 2, - "expl": "Román je válečná satira, ne venkovský společenský román 19. století." - }, - { - "prompt": "Jak končí dojem z Goodbodyho „vítězství“?", - "options": ["Čtenář i vypravěč sdílejí hrdinský pocit", "Čtenář chápe, že „vítězství“ je iluze vypravěče", "Goodbody odhalí, že celou dobu lhal", "Válka se v knize vůbec nekončí popisem"], - "correct": 1, - "expl": "Závěrečný efekt stojí na ironii mezi Goodbodyho sebevědomím a realitou války." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Goodbody nastupuje do služby jako naivní poručík", - "Jednotka plní absurdní rozkazy na frontě", - "Clapper a vojáci reagují cynicky na chaos", - "Operace se hroutí kvůli nekompetenci velení", - "Goodbody přesto hodnotí dění jako úspěch", - "Vypravěč tvrdí, že válku „vyhrál“" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: nástup poručíka → absurdní rozkazy → cynická reakce jednotky → neúspěch operací → Goodbodyův klamný optimismus → ironický titul o vítězství." - ] -} diff --git a/data/cetba/jana-eyrova.json b/data/cetba/jana-eyrova.json deleted file mode 100644 index 4ee222f..0000000 --- a/data/cetba/jana-eyrova.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Charlotte Brontëová (1816–1855), anglická spisovatelka", - "Žánr: romantický / viktoriánský román, bildungsroman", - "Poprvé vydáno: 1847", - "Děj / prostředí: Anglie 19. století (sirotčinec, Thornfield, močály)", - "Vyprávění / forma: ich-forma, retrospektivní vyprávění Jane Eyreové" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Viktoriánská společnost: rigidní třídní a genderové normy, náboženská morálka.", - "Jane jako sirotek a guvernantka stojí na okraji společnosti bez majetku.", - "Román spojuje milostný příběh s otázkami svobody, důstojnosti a integrity.", - "Gotické prvky: Thornfield, tajemné zvuky, požár, temná minulost Rochesterova.", - "Brontëová kritizuje pokrytectví „slušné“ společnosti a útlak žen.", - "Happy end je podmíněn morální rovnováhou, ne jen vášní." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Jane Eyre – sirotka, guvernantka, hledá lásku i nezávislost.", - "Edward Rochester – majitel Thornfieldu, komplikovaná minulost, manželství s Berthou.", - "Bertha Mason – „bláznivá“ manželka v ústraní, gotický symbol útlaku.", - "St. John Rivers – chladný duchovní, nabízí Jane sňatek bez lásky.", - "Helen Burns, paní Reed, Bessie – dětství v Gateshead a Lowood.", - "Adèle – Rochesterova chráněnka, důvod Janeina pobytu v Thornfieldu." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Bildungsroman – dospívání a formování charakteru Jane.", - "Gotický román – tajemno Thornfieldu a Bertha Masonové.", - "Svoboda a rovnost – Jane odmítá být Rochesterovou milenkou.", - "Náboženská morálka – kontrast Heleniny pokory a Janeiny vůle.", - "Sociální třída – guvernantka mezi služkami a pány.", - "Požár Thornfieldu – katarsis a nový začátek vztahu." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Jana Eyrovou a kdy román poprvé vyšel?", "options": ["Emily Brontëová, 1846", "Charlotte Brontëová, 1847", "Jane Austenová, 1815", "Mary Shelley, 1818"], "correct": 1, "expl": "Román vydala Charlotte Brontëová v roce 1847 pod pseudonymem Currer Bell."}, - {"prompt": "Kdo vypráví příběh?", "options": ["Edward Rochester", "Jane Eyreová v ich-formě", "Vševědoucí vypravěč", "St. John Rivers"], "correct": 1, "expl": "Jane retrospektivně vypráví svůj život od dětství po sňatek."}, - {"prompt": "Kde Jane strádá v dětství u příbuzných?", "options": ["Thornfield", "Gateshead Hall", "Lowood", "Moor House"], "correct": 1, "expl": "U paní Reedové v Gateshead je Jane ponižována a vyloučena."}, - {"prompt": "Jak se jmenuje škola, kam Jane posílají?", "options": ["Lowood Institution", "Hogwarts", "Thornfield Academy", "Rivers College"], "correct": 0, "expl": "V Lowood zažívá tvrdé podmínky, ale poznává Helen Burns."}, - {"prompt": "Kdo je Helen Burns?", "options": ["Rochesterova manželka", "Janeina přítelkyně z Lowood, vzor pokory", "Guvernantka Adèle", "Sestra St. Johna"], "correct": 1, "expl": "Helen učí Jane snášet utrpení s křesťanskou pokorou; brzy umírá na tuberkulózu."}, - {"prompt": "Jakou funkci má Jane v Thornfieldu?", "options": ["Ekonomka", "Guvernantka Adèle", "Kuchařka", "Učitelka v sirotčinci"], "correct": 1, "expl": "Rochester ji najímá jako vychovatelku své francouzské chráněnky Adèle."}, - {"prompt": "Co Jane opakovaně slyší v Thornfieldu v noci?", "options": ["Zvony kostela", "Tajemné smíchání a zvuky z místnosti v patře", "Lovec na jeleny", "Piano Berthy"], "correct": 1, "expl": "Gotický prvek: zvuky pocházejí od Berthy Masonové, uvězněné manželky."}, - {"prompt": "Kdo je Bertha Mason?", "options": ["Janeina sestra", "Rochesterova právní manželka, drží se v ústraní", "Paní Reedová", "Služka Grace Poole"], "correct": 1, "expl": "Rochester ji tají; její existence brání Janeinu sňatku."}, - {"prompt": "Co se stane v den svatby Jane a Rochestera?", "options": ["Obřad proběhne bez problémů", "Právník odhalí, že Rochester je již ženatý", "Jane uteče bez vysvětlení", "Thornfield shoří"], "correct": 1, "expl": "Mason prozradí manželství s Berthou; obřad je zastaven."}, - {"prompt": "Proč Jane opouští Thornfield po odhalení?", "options": ["Chce bohatství jinde", "Dodržuje morálku a odmítá být milenkou", "Nenávidí Adèle", "Rochester ji vyhodí"], "correct": 1, "expl": "Jane trvá na rovnosti a čistém svědomí, i když miluje Rochester."}, - {"prompt": "Kdo Jane po cestě zachrání a kam ji vezou?", "options": ["Rochester do Londýna", "St. John Rivers a sestry do Moor House", "Paní Reed do Gateshead", "Mason do Jamajky"], "correct": 1, "expl": "Diana, Mary a St. John ji najdou vyčerpanou u dveří."}, - {"prompt": "Jaký vztah k Jane má St. John Rivers?", "options": ["Nabízí sňatek bez lásky jako misijní partnerku", "Je její biologický otec", "Chce ji vydat za Masona", "Je Rochesterův bratr"], "correct": 0, "expl": "St. John je asketický duchovní; Jane odmítá chladný sňatek z povinnosti."}, - {"prompt": "Co Jane dědí po strýci Johnu?", "options": ["Thornfield", "20000 liber", "Nic", "Lowood"], "correct": 1, "expl": "Dědictví ji finančně osvobodí a umožní rozdělit peníze se sourozenci Riversovými."}, - {"prompt": "Co se stane s Thornfieldem?", "options": ["Bertha ho zapálí; Rochester oslepne a zmrzačí se", "Zůstane nedotčen", "Koupí ho St. John", "Jane ho prodá"], "correct": 0, "expl": "Požár zabije Berthu; Rochester při záchraně služebnictva utrpí zranění."}, - {"prompt": "Jak román končí?", "options": ["Jane zůstane sama", "Jane se vrací k Rochesterovi a berou se", "Jane odjíždí s St. Johnem do Indie", "Rochester umírá"], "correct": 1, "expl": "Jane nachází Rochester v Ferndean; sňatek je rovnocenný a morálně čistý."}, - {"prompt": "Jaký žánrový prvek představuje dětství a cesta k dospělosti Jane?", "options": ["Detektivka", "Bildungsroman", "Epos", "Utopie"], "correct": 1, "expl": "Román sleduje formování charakteru a svědomí hrdinky."}, - {"prompt": "Co symbolizuje Bertha Mason v interpretacích?", "options": ["Jen náhodná postava", "Potlačenou ženskou vzpouru a temnou stránku viktoriánské reality", "Janeinu sestru dvojče", "Anděla strážného"], "correct": 1, "expl": "Bertha je často čtena jako gotický symbol útlaku a zla v domácnosti."}, - {"prompt": "Jak Jane reaguje na Rochesterovu nabídku milenectví?", "options": ["Přijme ji", "Odmítne a odchází", "Požádá o rozvod", "Zavolá policii"], "correct": 1, "expl": "Jane nechce žít v nelegálním vztahu, i za cenu utrpení."}, - {"prompt": "Kdo je Adèle?", "options": ["Berthina sestra", "Rochesterova chráněnka, pupil Jane", "Služka Grace", "Dcera St. Johna"], "correct": 1, "expl": "Adèle je důvod Janeina zaměstnání; Rochester tvrdí, že není jeho dcera."}, - {"prompt": "Jaký je vztah Jane k náboženství?", "options": ["Bezvýhradně přijímá St. Johnův asketismus", "Hledá vlastní morální kompas mezi pokorou a vůlí", "Je ateistka bez etiky", "Nenávidí křesťanství"], "correct": 1, "expl": "Jane odmítá extrémní sebeobětování St. Johna, ale ctí svědomí a spravedlnost."}, - {"prompt": "Proč je Jane důležitá pro feministickou literaturu?", "options": ["Je pasivní hrdinka", "Požaduje rovnost, nezávislost a respekt v lásce", "Odmítá vzdělání", "Je jen ozdobou boháče"], "correct": 1, "expl": "Její věta o rovnosti duší je klíčová pro interpretaci románu."}, - {"prompt": "Kdo je paní Reed?", "options": ["Janeina teta, která ji od malička nemiluje", "Rochesterova sestra", "Učitelka v Lowood", "Berthina matka"], "correct": 0, "expl": "Na smrtelné posteli se paní Reed částečně kají a přiznává vinu."}, - {"prompt": "Co Jane vidí v červeném pokoji v Gateshead?", "options": ["Pouze nábytek", "Místo, kde strádá a má děsivé vize", "Třídu s dětmi", "Knihovnu Rochesterovu"], "correct": 1, "expl": "Červený pokoj je děsivým symbolem dětství a vyloučení."}, - {"prompt": "Jak Rochester poprvé potká Jane?", "options": ["Na plese v Londýně", "Když spadne z koně na močálech", "V kostele", "V Lowood"], "correct": 1, "expl": "Setkání na cestě k Thornfieldu je typické romantické „známení“."}, - {"prompt": "Které prostředí NENÍ v románu výrazně zastoupeno?", "options": ["Sirotčinec a škola", "Thornfield a močály", "Pařížský salon 18. století", "Ferndean po požáru"], "correct": 2, "expl": "Děj je situován do anglického venkova a domů 19. století."}, - {"prompt": "Co znamená gotický prvek v Thornfieldu?", "options": ["Realistický popis bez napětí", "Tajemno, hrozba a temná minulost rodiny", "Komický prvek bez významu", "Pouze popis architektury"], "correct": 1, "expl": "Tajná manželka, požár a noční zvuky budují napětí a symboliku."}, - {"prompt": "Proč Jane odmítne St. Johnův sňatek?", "options": ["Nemá peníze", "Necítí lásku a nechce být jen nástrojem mise", "Miluje Masona", "St. John je ženatý"], "correct": 1, "expl": "Jane chce manželství z city, ne jen službu a oběť."}, - {"prompt": "Jak se mění Rochester na konci?", "options": ["Je bohatší než dříve", "Je slepý a závislý; vztah s Jane je vyrovnanější", "Stává se knězem", "Odjíždí do Indie"], "correct": 1, "expl": "Fyzická zranitelnost Rochesterovi srovnává pozici s Janinou."}, - {"prompt": "Jaký je hlavní konflikt románu?", "options": ["Válka o trůn", "Láska a morálka vs. společenské a právní překážky", "Honba za pokladem", "Vědecký experiment"], "correct": 1, "expl": "Jane musí sladit vášeň, svědomí a touhu po nezávislosti."}, - {"prompt": "Které tvrzení o románu je správné?", "options": ["Jane končí jako Rochesterova milenka", "Jane zůstává věrná svým zásadám a dosahuje šťastného konce", "Rochester se nikdy neožení", "Bertha je vymyšlená Jane"], "correct": 1, "expl": "Finální sňatek je odměnou za morální integritu hrdinky."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Dětství u paní Reedové a škola Lowood", - "Jane nastupuje jako guvernantka do Thornfieldu", - "Láska k Rochesterovi a příprava svatby", - "Odhalení manželství s Berthou Masonovou", - "Jane odchází a najde útočiště u Riversů", - "Návrat k osleplému Rochesterovi a sňatek" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: dětství a Lowood → Thornfield a láska → zmařená svatba → odchod → Rivers a dědictví → požár a šťastný konec u Ferndean." - ] -} diff --git a/data/cetba/jekyll-hyde.json b/data/cetba/jekyll-hyde.json deleted file mode 100644 index 2c3cf4b..0000000 --- a/data/cetba/jekyll-hyde.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Robert Louis Stevenson", - "Žánr: hororová / psychologická novela", - "Poprvé vydáno: 1886", - "Děj/prostředí: Londýn, viktoriánská Anglie", - "Vyprávění/forma: er-forma, právník Utterson jako rámcový pozorovatel; překlad Kořán" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Viktoriánská moralita a pokrytectví", - "Rozdělená osobnost – věda vs. etika", - "Londýn mlhový, noční násilí", - "Právo a pověst společnosti", - "Lekce o nezkrotné touze", - "Gotický horor" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Dr. Henry Jekyll – uznávaný vědec", - "Mr. Edward Hyde – ztělesnění zla a touhy", - "Gabriel John Utterson – advokát, vyšetřuje", - "Dr. Hastie Lanyon – kolega, šok z pravdy", - "Poole – sluha Jekyllův", - "Sir Danvers Carew – oběť Hyde" - ] - }, - { - "title": "Klíčové pojmy a motivy", - "icon": "bulb", - "lines": [ - "Lekce / sérum – proměna", - "Dvojí identita – dobro vs. zlo", - "Hyde – menší, primitivní, násilný", - "Uttersonův výslech – detektivní linie", - "Dopisy Lanyon a Jekyll – vysvětlení", - "Sebedestrukce Jekylla" - ] - } - ], - "quiz": [ - { - "prompt": "Autor?", - "options": [ - "Stevenson", - "Poe", - "Wilde", - "Swift" - ], - "correct": 0, - "expl": "R. L. Stevenson." - }, - { - "prompt": "Rok?", - "options": [ - "1886", - "1950", - "1600", - "2000" - ], - "correct": 0, - "expl": "Viktoriánská literatura." - }, - { - "prompt": "Hyde?", - "options": [ - "Zločinná alter ego Jekylla", - "Utterson", - "Lékař", - "Král" - ], - "correct": 0, - "expl": "Protipól." - }, - { - "prompt": "Jekyll?", - "options": [ - "Vědec experimentující se sebou", - "Hyde vždy", - "Detektiv", - "Ne" - ], - "correct": 0, - "expl": "Hrdina/tragičnost." - }, - { - "prompt": "Utterson?", - "options": [ - "Advokát vyšetřující Hyde", - "Hyde", - "Oběť", - "Sluha" - ], - "correct": 0, - "expl": "Rámcová postava." - }, - { - "prompt": "Lanyon?", - "options": [ - "Kolega, zemře šokem", - "Hyde", - "Policie", - "Ne" - ], - "correct": 0, - "expl": "Svědek pravdy." - }, - { - "prompt": "Carew?", - "options": [ - "Zavražděn Hyde", - "Utterson", - "Jekyll vždy", - "Ne" - ], - "correct": 0, - "expl": "Noční vražda." - }, - { - "prompt": "Lekce?", - "options": [ - "Mění Jekyll na Hyde", - "Léčí mor", - "Ne", - "Jen víno" - ], - "correct": 0, - "expl": "Klíč experimentu." - }, - { - "prompt": "Prostředí?", - "options": [ - "Londýn", - "Praha", - "Skotsko venkov", - "Mars" - ], - "correct": 0, - "expl": "Město." - }, - { - "prompt": "Žánr?", - "options": [ - "Horor/psychologická novela", - "Pohádka", - "Epos", - "Komik" - ], - "correct": 0, - "expl": "Gotika." - }, - { - "prompt": "Překlad?", - "options": [ - "Kořán", - "Nezval", - "Nevrla", - "Gössell" - ], - "correct": 0, - "expl": "Katalog." - }, - { - "prompt": "Proč maturitní?", - "options": [ - "Klasika o dvojí identitě", - "Nejkratší", - "Bez témat", - "Jen film" - ], - "correct": 0, - "expl": "Kanón." - }, - { - "prompt": "Moralita?", - "options": [ - "Věda bez etiky vede ke zkáze", - "Věda vždy dobrá", - "Ne", - "Hyde hrdina" - ], - "correct": 0, - "expl": "Poselství." - }, - { - "prompt": "Hyde vzhled?", - "options": [ - "Odpudivý, zvířecký", - "Krásný", - "Ne", - "Stejný jako Jekyll" - ], - "correct": 0, - "expl": "Symbol zla." - }, - { - "prompt": "Jekyll končí?", - "options": [ - "Sebevražda jako Hyde v laboratoři", - "Svatba", - "Král", - "Utterson" - ], - "correct": 0, - "expl": "Tragédie." - }, - { - "prompt": "Utterson čte?", - "options": [ - "Dopisy Lanyon a Jekyll", - "Deník Anne", - "Bible", - "Nic" - ], - "correct": 0, - "expl": "Vysvětlení." - }, - { - "prompt": "Poole?", - "options": [ - "Sluha znepokojený laboratoří", - "Hyde", - "Policista", - "Ne" - ], - "correct": 0, - "expl": "Domácí." - }, - { - "prompt": "Téma dvojí identity?", - "options": [ - "Centrální", - "Ne", - "Pouze sport", - "Pouze láska" - ], - "correct": 0, - "expl": "Jádro." - }, - { - "prompt": "Victoriánská doba?", - "options": [ - "Pokrytectví a moralita", - "Ne", - "Antika", - "Budoucnost" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Hyde", - "Jekyll", - "Hamlet", - "Utterson" - ], - "correct": 2, - "expl": "Shakespeare." - }, - { - "prompt": "Er-forma?", - "options": [ - "Utterson a vypravěč", - "Jen ich Anne", - "Bez vypravěče", - "Drama" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Novela délka?", - "options": [ - "Kratší próza", - "Epos", - "1000 stran", - "Báseň" - ], - "correct": 0, - "expl": "Novela." - }, - { - "prompt": "Gotický prvek?", - "options": [ - "Mlha, násilí, tajemno", - "Ne", - "Pouze komedie", - "Opera" - ], - "correct": 0, - "expl": "Atmosféra." - }, - { - "prompt": "Hyde bez Jekyll?", - "options": [ - "Ne, jsou spojeni", - "Ano navždy", - "Neexistuje", - "Utterson" - ], - "correct": 0, - "expl": "Identita." - }, - { - "prompt": "Experiment motiv?", - "options": [ - "Odpoutat zlo od dobrého já", - "Bohatství", - "Sport", - "Ne" - ], - "correct": 0, - "expl": "Vědecká pýcha." - }, - { - "prompt": "Poselství?", - "options": [ - "Člověk nese zlo v sobě", - "Zlo neexistuje", - "Hyde je vzor", - "Věda bez hranic je vždy dobrá" - ], - "correct": 0, - "expl": "Etické varování." - }, - { - "prompt": "Katalog?", - "options": [ - "Próza", - "Drama", - "Poezie", - "Opera" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Stevenson národnost?", - "options": [ - "Skotský autor", - "Český", - "Francouz", - "Němec" - ], - "correct": 0, - "expl": "Skotsko." - }, - { - "prompt": "Carew vražda?", - "options": [ - "Hyde klackem", - "Utterson", - "Nehoda", - "Ne" - ], - "correct": 0, - "expl": "Brutální." - }, - { - "prompt": "Jekyll dopis?", - "options": [ - "Vysvětluje pravdu Uttersonovi", - "Ne", - "Hyde píše", - "Gestapo" - ], - "correct": 0, - "expl": "Závěrečné odhalení." - }, - { - "prompt": "Adaptace?", - "options": [ - "Mnoho filmů", - "Ne", - "Zakázáno", - "Jen opera" - ], - "correct": 0, - "expl": "Kultovní." - }, - { - "prompt": "Kořán?", - "options": [ - "Překladatel", - "Hyde", - "Autor", - "Utterson" - ], - "correct": 0, - "expl": "CZ překlad." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Utterson zjišťuje podivného Hyde", - "Hyde zavraždí Carewa", - "Utterson pátrá u Jekyll", - "Lanyon šok a smrt", - "Poole volá Uttersona – chaos v domě", - "Jekyllův dopis a smrt – odhalení identity" - ] - } - ], - "plotMeaning": [ - "Pořadí: Hyde na scéně → vražda → pátrání → Lanyon → laboratoř → dopis a konec." - ] -} diff --git a/data/cetba/jmeno-ruze.json b/data/cetba/jmeno-ruze.json deleted file mode 100644 index 5d157c0..0000000 --- a/data/cetba/jmeno-ruze.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Umberto Eco (1932–2016), italský sémiotik a spisovatel", - "Žánr: historická detektivka, postmoderní román", - "Poprvé vydáno: 1980 (Il nome della rosa)", - "Děj / prostředí: benediktinský klášter v severní Itálii, rok 1327", - "Vyprávění / forma: vzpomínka mnicha Adsona z Melku, er-forma" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Středověk: spor o chudobu (františkáni vs. papežský dvůr), inkvizice.", - "Klášter jako uzavřený svět knih, moci, tajemství a vražd.", - "Labyrint knihovny symbolizuje nebezpečí zakázaného vědění.", - "Eco kombinuje detektivku s filosofií, teologií a historií.", - "Film Jean-Jacques Annauda (1986) se Seanem Connerym.", - "Titulní růže – nejasný symbol krásy, tajemství a smrti." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "William z Baskervillu – františkán, logik, vzor Sherlocka Holmese.", - "Adso z Melku – mladý benediktin, vypravěč, Williamův učedník.", - "Jorge z Burgosu – slepý mnich, fanatik proti smíchu a heretickým knihám.", - "Opat Abo – vůdce kláštera, skrývá politické intriky.", - "Salvatore a Remigio – postavy zločinu a minulosti heresie.", - "Dívka z vesnice – Adsova krátká láska, symbol světa mimo klášter." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Detektivní pátrání – série vražd kolem knihovny.", - "Labyrint knihovny – geometrie tajemství a moci.", - "Smích – Jorge považuje komedii Aristotelovu za nebezpečnou.", - "Heretické spisy – boj o to, co smí být čteno.", - "Sémiotika – Eco pracuje se znameními a výklady.", - "Požár kláštera – zničení knih i pravdy." - ] - } - ], - "quiz": [ - {"prompt": "Kdo je autorem Jména růže?", "options": ["Dan Brown", "Umberto Eco", "Dante Alighieri", "Italo Calvino"], "correct": 1, "expl": "Eco vydal román v roce 1980; je to jeho první bestseller."}, - {"prompt": "Kdy a kde se děj odehrává?", "options": ["1327, benediktinský klášter v Itálii", "1789, Paříž", "2000, Řím", "1066, Anglie"], "correct": 0, "expl": "Děj je v době středověkých sporů o moc církve a chudobu."}, - {"prompt": "Kdo vypráví příběh?", "options": ["William z Baskervillu", "Starý Adso z Melku vzpomíná na mládí", "Opat Abo", "Jorge z Burgosu"], "correct": 1, "expl": "Adso jako stařec zapisuje události z roku 1327."}, - {"prompt": "Kdo je William z Baskervillu?", "options": ["Opat", "Františkánský mnich a logik, detektiv", "Templář", "Vesnický kovář"], "correct": 1, "expl": "William připomíná Sherlocka Holmese – dedukce a pozorování."}, - {"prompt": "Proč William přijede do kláštera?", "options": ["Za lovem", "Jako vyslanec při jednání o chudobě františkánů", "Za trestem", "Kvůli svatbě"], "correct": 1, "expl": "Politicko-církevní jednání je rámec pro detektivní děj."}, - {"prompt": "Co se děje v klášteře?", "options": ["Nic neobvyklého", "Série záhadných smrtí mnichů", "Pouze stavba katedrály", "Válka s Turky"], "correct": 1, "expl": "Vraždy souvisejí s knihovnou a zakázanými texty."}, - {"prompt": "Co je klíčové místo tajemství?", "options": ["Kuchyně", "Labyrint klášterní knihovny", "Hřbitov ve městě", "Vinný sklep bez knih"], "correct": 1, "expl": "Knihovna je geometricky složitá a střežená."}, - {"prompt": "Kdo je Jorge z Burgosu?", "options": ["Mladý novic", "Slepý stařec, fanatický odpůrce nebezpečných knih", "Williamův bratr", "Král"], "correct": 1, "expl": "Jorge zastupuje extrémní cenzuru a strach ze vědění."}, - {"prompt": "Proč je nebezpečná kniha o smíchu?", "options": ["Je prázdná", "Jorge ji považuje za heretickou; Aristotelova komedie", "Je v němčině", "Je příliš krátká"], "correct": 1, "expl": "Motiv druhé knihy Poetiky – smích podkopává autoritu."}, - {"prompt": "Jak vraždy souvisí s knihami?", "options": ["Vůbec", "Oběti četly nebo hledaly zakázaný spis", "Knihy jsou jen kulisa", "Vraždí dozorce"], "correct": 1, "expl": "Detektivní linka vede ke knihovně a k cenzurovanému textu."}, - {"prompt": "Kdo je Adsova dívka z vesnice?", "options": ["Opatova sestra", "Prostá dívka, symbol světa mimo klášter", "Inkvisitorka", "Rytířka"], "correct": 1, "expl": "Krátký milostný epizod ukazuje Adsovi jiný život než mnich."}, - {"prompt": "Jak román končí?", "options": ["Svatba v klášteře", "Požár kláštera; knihovna i mnoho knih zahyne", "William se stane papežem", "Klášter zůstane nedotčen"], "correct": 1, "expl": "Zničení knihovny je tragickým vrcholem."}, - {"prompt": "Jaký žánr dominuje?", "options": ["Sci-fi", "Historická detektivka s filosofickými rovinami", "Milostný román bez děje", "Bajka"], "correct": 1, "expl": "Eco míchá detektivku, historii a reflexi nad interpretací."}, - {"prompt": "Co znamená název Jméno růže?", "options": ["Jasný symbol v textu", "Záměrně nejednoznačný symbol – krása, tajemství, smrt", "Jméno vraha", "Název kláštera"], "correct": 1, "expl": "Eco říká, že růže je tajemství bez jedné definice."}, - {"prompt": "Kdo režíroval známou filmovou adaptaci?", "options": ["Spielberg", "Jean-Jacques Annaud", "Fellini", "Kubrick"], "correct": 1, "expl": "Film z roku 1986; Williama hraje Sean Connery."}, - {"prompt": "Jak William řeší záhady?", "options": ["Náhodou", "Logikou, pozorováním a znalostí středověku", "Magickými formulí", "Pouze modlitbou"], "correct": 1, "expl": "Dedukční metoda je vědomá narážka na detektivní literaturu."}, - {"prompt": "Co je inkvizice v kontextu děje?", "options": ["Sport", "Církevní soud proti heretikům", "Klášterní kuchyně", "Knihovní systém"], "correct": 1, "expl": "Bernard Gui a strach z kacířství prostupují atmosférou."}, - {"prompt": "Které téma Eco zdůrazňuje?", "options": ["Nebezpečí cenzury a fanatismu", "Oslava války", "Moderní technologie", "Sport"], "correct": 0, "expl": "Boj o knihy je bojem o moc nad myšlením."}, - {"prompt": "Kdo je Salvatore?", "options": ["Opat", "Postava mluvící smíšenými jazyky, spojená se zločinem", "Williamův učitel", "Rytíř bez role"], "correct": 1, "expl": "Salvatore patří k postavám temné minulosti kláštera."}, - {"prompt": "Proč je román postmoderní?", "options": ["Ignoruje historii", "Hrá si s intertextem, výkladem a nejistotou významu", "Je bez děje", "Má jen obrázky"], "correct": 1, "expl": "Eco jako sémiotik pracuje s vrstvami významů a citacemi."}, - {"prompt": "Jaký vztah má Adso k Williamovi?", "options": ["Nepřítel", "Učedník a vypravěč, obdivuje mistra", "Bratr", "Dozorce"], "correct": 1, "expl": "Adso učí se pozorovat svět i víru."}, - {"prompt": "Co reprezentuje labyrint?", "options": ["Jen architekturu", "Složitost poznání a nebezpečí hledání pravdy", "Dětskou hru", "Zahradu"], "correct": 1, "expl": "Vstup do knihovny je metaforou nebezpečného vědění."}, - {"prompt": "Který spor prostupuje klášterem?", "options": ["Fotbal vs. hokej", "Chudoba a moc františkánů vs. papežský dvůr", "Válka se Vikingy", "Rozvod krále"], "correct": 1, "expl": "Historický rámec 1327 vysvětluje přítomnost William a Bernarda."}, - {"prompt": "Proč maturanti čtou Jméno růže?", "options": ["Je nejkratší kniha", "Spojuje děj, historii, detektivku a filosofické otázky", "Nemá postavy", "Je učebnice chemie"], "correct": 1, "expl": "Román učí číst vrstevnatě a historicky."}, - {"prompt": "Jak William reaguje na Jorgeho fanatismus?", "options": ["Souhlasí", "Odhaluje logicky souvislosti zločinů", "Utíká hned první den", "Stane se opatem"], "correct": 1, "expl": "William demaskuje pachatele dedukcí."}, - {"prompt": "Co Adso na konci lituje?", "options": ["Že neviděl růži", "Ztráty knih, mistra i mládí v klášteře", "Že se nestal králem", "Že nehrál fotbal"], "correct": 1, "expl": "Vzpomínka je smutná i poučná – vědění může zahynout."}, - {"prompt": "Který prvek NENÍ typický pro román?", "options": ["Středověké prostředí", "Vesmírné lodě", "Knihovna", "Inkvisice"], "correct": 1, "expl": "Děj je pevně středověký, bez sci-fi."}, - {"prompt": "Jak Eco pracuje s intertextem?", "options": ["Citace Bible, Aristotela, středověkých pramenů", "Nepoužívá reference", "Jen moderní pop", "Jen české písně"], "correct": 0, "expl": "Román je plný odkazů na teologii, filosofii a literaturu."}, - {"prompt": "Kdo je Remigio?", "options": ["Opat", "Mnich s temnou minulostí heretického bratrstva", "Adsova matka", "Papež"], "correct": 1, "expl": "Remigio je zapleten do zločinů a strachu z odhalení."}, - {"prompt": "Jaké poselství lze vyčíst z požáru?", "options": ["Knihy jsou zbytečné", "Fanatismus a tajemství ničí i to, co chtěly chránit", "Oheň je náhodný", "Požár ničí jen jídlo"], "correct": 1, "expl": "Klášter a knihovna hoří – knowledge a moc končí v popelu."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "William a Adso přijíždějí do kláštera", - "Začínají umírat mniši za záhadných okolností", - "Pátrání vede do labyrintu knihovny", - "Odhalí se souvislost se zakázanou knihou o smíchu", - "Jorge a konflikt o cenzuru vyústí v tragédii", - "Požár zničí klášter; Adso vzpomíná po letech" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: příjezd → vraždy → knihovna → Aristotelova komedie → Jorge → požár a vzpomínka Adsova." - ] -} diff --git a/data/cetba/kalibuv-zlocin.json b/data/cetba/kalibuv-zlocin.json deleted file mode 100644 index ba2f74a..0000000 --- a/data/cetba/kalibuv-zlocin.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Václav Rais (1857–1926), český realista", - "Žánr: venkovský realistický román, tragédie", - "Poprvé vydáno: 1892", - "Děj / prostředí: podkrkonošská vesnice, chalupa Kalibů", - "Vyprávění / forma: er-forma, psychologický realismus" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Konec 19. století: tvrdý venkovský život, majetek a rodinné vazby.", - "Chalupa je centrem konfliktu mezi Kalibou, druhou ženou a synem.", - "Rais zobrazuje venkov bez idealizace – chudoba, sobectví, tlak okolí.", - "Tragédie vyrůstá z postupného útlaku Frantíka a slabosti otce.", - "Motiv macechy Karly je klasický, ale zasazený do českého prostředí.", - "Zločin otce je vyústění dlouholetého napětí, ne náhlý impulz bez příčiny." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Vojtěch Kaliba – slabý hospodář, dobrácký, ale neschopný bránit syna.", - "Karla – druhá manželka, panovačná, týrá Frantíka, chce mít moc v domě.", - "Frantík – syn z prvního manželství, oběť macechy, touží po spravedlnosti.", - "Babka – Kalibova matka, chrání vnuka před Karlou.", - "Vesnice – svědek rodinného konfliktu a morálního soudku." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Realismus – věrný obraz venkova a psychologie.", - "Macecha – Karla jako zdroj útlaku.", - "Majetek a chalupa – ekonomický základ rodinného sporu.", - "Generační konflikt – babička, otec, syn proti Karlě.", - "Zločin z bezmoci – Kaliba ubije Frantíka v afektu.", - "Tragédie – nevyhnutelný pád rodiny." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Kalibův zločin?", "options": ["Němcová", "Karel Václav Rais", "Nezval", "Hašek"], "correct": 1, "expl": "Rais patří k vrcholu české realistické prózy konce 19. století."}, - {"prompt": "Kde se děj odehrává?", "options": ["Praha", "Podkrkonoší, chalupa Kalibů", "Morava", "Slovensko"], "correct": 1, "expl": "Horské prostředí ovlivňuje charakter postav i atmosféru."}, - {"prompt": "Kdo je Frantík?", "options": ["Kalibův syn z prvního manželství", "Sousedův syn", "Kněz", "Karlův bratr"], "correct": 0, "expl": "Frantík je obětí Karlina týrání a Kalibovy slabosti."}, - {"prompt": "Jaká je Karla?", "options": ["Laskavá macecha", "Sobecká, panovačná druhá žena", "Cizí panna", "Učitelka"], "correct": 1, "expl": "Karla chce ovládat domácnost a odstranit Frantíka z cesty."}, - {"prompt": "Kdo brání Frantíkovi nejvíc?", "options": ["Karla", "Babka (Kalibova matka)", "Kněz", "Starosta"], "correct": 1, "expl": "Babička je jediná, kdo Frantíka aktivně chrání."}, - {"prompt": "Proč je Kaliba tragická postava?", "options": ["Je zlý tyran od začátku", "Je dobrácký, ale slabý – neubrání syna", "Je bohatý magnát", "Je cizinec"], "correct": 1, "expl": "Jeho selhání jako otce vede k nejhoršímu činu."}, - {"prompt": "Jak román končí?", "options": ["Svatbou Frantíka", "Kaliba v afektu syna ubije; tragédie rodiny", "Karla odchází bohatá", "Frantík dědí statek"], "correct": 1, "expl": "Zločin je vrchol dlouhodobého napětí v chalupě."}, - {"prompt": "Jaký žánr dílo reprezentuje?", "options": ["Sci-fi", "Venkovský realistický román / tragédie", "Bajka", "Detektivka"], "correct": 1, "expl": "Rais popisuje reálné venkovské poměry a psychologii."}, - {"prompt": "Co je hlavním zdrojem konfliktu?", "options": ["Válka", "Majetek, moc v domácnosti a vztah macechy k synovi", "Magie", "Politika"], "correct": 1, "expl": "Chalupa a sňatek Karly spouštějí boj o místo ve vztahu."}, - {"prompt": "Kdy román poprvé vyšel?", "options": ["1892", "1948", "2001", "1850"], "correct": 0, "expl": "Vydání spadá do období českého realismu."}, - {"prompt": "Jak Rais vykresluje venkov?", "options": ["Idylicky bez problémů", "Realisticky – chudoba, tvrdost, morální tlak", "Jako město", "Jako poušť"], "correct": 1, "expl": "Venkov není ráj; je prostředím sociálního a rodinného napětí."}, - {"prompt": "Proč Frantík trpí?", "options": ["Je nemocný", "Karla ho ponižuje, otec nezasáhne dostatečně", "Je v exilu", "Je bohatý"], "correct": 1, "expl": "Systematický útlak v domácnosti je jádrem děje."}, - {"prompt": "Co symbolizuje chalupa?", "options": ["Cizí zem", "Rodinný majetek a uzavřený svět konfliktu", "Škola", "Kostel"], "correct": 1, "expl": "V chalupě se soustřeďuje veškeré napětí rodiny."}, - {"prompt": "Jaký vztah mají Kaliba a Karla?", "options": ["Manželé; Karla dominuje", "Sourozenci", "Nepřátelé bez sňatku", "Strýc a neteř"], "correct": 0, "expl": "Kaliba si Karlu vzal jako druhou manželku po smrti první ženy."}, - {"prompt": "Co je typické pro Raisovu prózu?", "options": ["Fantastické prvky", "Psychologický realismus a venkovské prostředí", "Sci-fi", "Pouze poezie"], "correct": 1, "expl": "Rais je známý realistickými venkovskými romány."}, - {"prompt": "Proč je titul Kalibův zločin?", "options": ["Zločin spáchá Frantík", "Hlavní viníkem finálního násilí je otec Kaliba", "Zločin spáchá babka", "Jde o krádež krav"], "correct": 1, "expl": "Titul ukazuje na otce, který sáhne k nejhoršímu činu."}, - {"prompt": "Jak vesnice reaguje na rodinu?", "options": ["Ignoruje ji", "Je svědkem a morálním soudem venkovské komunity", "Odchází z kraje", "Staví divadlo"], "correct": 1, "expl": "Společenský tlak okolí je součástí realismu."}, - {"prompt": "Které téma NENÍ středem románu?", "options": ["Rodinný útlak", "Macecha a syn", "Vesmírná kolonizace", "Slabost otce"], "correct": 2, "expl": "Dílo je uzavřené venkovské drama 19. století."}, - {"prompt": "Jak lze označit Frantíka?", "options": ["Antihrdina zla", "Oběť a postava vyvolávající soucit", "Komik", "Vesnický boháč"], "correct": 1, "expl": "Čtenář sleduje jeho trápení a touhu po spravedlnosti."}, - {"prompt": "Co předchází zločinu?", "options": ["Okamžitá radost", "Dlouhodobé napětí, hádky a útlak", "Válka", "Povodeň bez děje"], "correct": 1, "expl": "Tragédie je logickým vyústěním situace v chalupě."}, - {"prompt": "Jak Rais pracuje s jazykem?", "options": ["Archaičtina bez smyslu", "Spisovná čeština s prvky venkovského prostředí", "Cizím jazykem", "Pouze dialogy anglicky"], "correct": 1, "expl": "Jazyk odpovídá realistickému stylu doby."}, - {"prompt": "Proč je dílo v maturitní četbě?", "options": ["Je nejkratší", "Ukázka českého realismu a rodinné tragédie", "Je komiks", "Nemá děj"], "correct": 1, "expl": "Učí číst psychologii postav a historický kontext venkova."}, - {"prompt": "Kdo je Vojtěch Kaliba?", "options": ["Syn Frantík", "Hospodář, otec Frantíka, manžel Karly", "Soudce", "Učitel"], "correct": 1, "expl": "Kaliba je středem morálního pádu příběhu."}, - {"prompt": "Jaký motiv sdílí s jinými realistickými díly?", "options": ["Kritika městské elity bez venkova", "Tvrdý život venkovského obyvatelstva", "Pouze humor", "Fantasy"], "correct": 1, "expl": "Rais navazuje na tradici zobrazování venkova (V.M. Karel, Němcová v jiném tónu)." }, - {"prompt": "Co Kaliba typicky neumí?", "options": ["Orat", "Postavit se rozhodně Karlě ve prospěch syna", "Vařit", "Spát"], "correct": 1, "expl": "Jeho slabost je klíčová pro vývoj tragédie."}, - {"prompt": "Jaký osud čeká rodinu po zločinu?", "options": ["Šťastný návrat normy", "Morální a právní následky tragédie", "Emigrace do Ameriky", "Svatba Frantíka"], "correct": 1, "expl": "Zločin ničí rodinu – realistický důsledek násilí."}, - {"prompt": "Která postava reprezentuje starší generaci ochrany?", "options": ["Karla", "Babka", "Frantík", "Soused"], "correct": 1, "expl": "Babka stojí proti Karlě v ochraně vnuka."}, - {"prompt": "Co je afekt u Kaliby?", "options": ["Plánovaná vražda", "Náhlé emoční vypětí vedoucí k ubíjení syna", "Radost", "Spánek"], "correct": 1, "expl": "Zločin není chladně promyšlený, ale výbuch bezmoci."}, - {"prompt": "Jaký kontrast tvoří jádro díla?", "options": ["Bohatí vs. chudí ve městě", "Dobráckost otce vs. strašný čin proti synovi", "Moře vs. hory bez děje", "Humor vs. humor"], "correct": 1, "expl": "Kontrast zvyšuje tragický efekt."}, - {"prompt": "Co čtenář má cítit vůči Frantíkovi?", "options": ["Opovržení", "Soucit a pochopení jeho beznaděje", "Smích", "Nezájem"], "correct": 1, "expl": "Frantík je emocionálním středem čtenářské reakce."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Kaliba žije s druhou ženou Karlou a synem Frantíkem", - "Karla týrá Frantíka; babka ho brání", - "Napětí v chalupě roste; otec je pasivní", - "Frantík se vzepře nebo konflikt vyhrotí", - "Kaliba v afektu syna ubije", - "Rodina čelí tragickému následku zločinu" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: rodina na chalupě → útlak Frantíka → eskalace → vyhrocení → zločin otce → tragický konec." - ] -} diff --git a/data/cetba/kniska-karla-kryla.json b/data/cetba/kniska-karla-kryla.json deleted file mode 100644 index 0e2436c..0000000 --- a/data/cetba/kniska-karla-kryla.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Kryl (1944–1994), písničkář a básník", - "Žánr: protestní poezie, autorská píseň, sbírka textů", - "Poprvé vydáno: 1972 (exil; texty z přelomu 60./70. let)", - "Děj / prostředí: Československo po srpnu 1968, normalizace, emigrace", - "Vyprávění / forma: lyrické básně a písně, metafora, ironie, refrén" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Po okupaci vojsky Varšavské smlouvy následuje normalizace a cenzura.", - "Kryl emigruje; písně kolují jako samizdat a symbol odporu.", - "Kníška sbírá texty propojující poezii s protest songem.", - "Motivy: svoboda, zrada, pokrytectví moci, vina mlčení.", - "Jazyk je úderný, obrazný, s biblickými a pohádkovými narážkami.", - "Dílo patří k pilířům české protestní kultury 20. století." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Básnický subjekt – hlas svědka a moralisty proti moci.", - "Bratříčku (Bratříčku, zavírej vrátka) – oslovení národa, varování.", - "Král a blázen – alegorie moci a pravdy (např. píseň Král a klaun).", - "Anděl / ďábel – dobro a zlo v politice i v člověku.", - "Emigrant – ztráta domova, vina vyhnanství.", - "Dav mlčících – kolektivní strach a kompromis." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Protest song – píseň jako nástroj odporu.", - "Alegorie – skryté politické významy v obrazech.", - "Normalizace – doba po 1968, proti ní Kryl brojí.", - "Emigrace – ztráta domova i možnosti mluvit doma.", - "Ironie – rozbití oficiální rétoriky.", - "Morální odpovědnost – kdo mlčí, také nese vinu." - ] - } - ], - "quiz": [ - {"prompt": "Kdo je autorem Kníšky?", "options": ["Halík", "Karel Kryl", "Hrabal", "Okudař"], "correct": 1, "expl": "Kryl je autorem textů i skladatel písní; Kníška je sbírka jeho poezie."}, - {"prompt": "V jakém historickém kontextu texty vznikají?", "options": ["První republika bez krizí", "Po srpnu 1968 a normalizaci", "Středověk", "Rok 1989 jen"], "correct": 1, "expl": "Krylovy texty reagují na okupaci a potlačení svobody."}, - {"prompt": "Jaký žánr Kníška reprezentuje?", "options": ["Román", "Protestní poezie a písně", "Drama", "Encyklopedie"], "correct": 1, "expl": "Jde o lyrické texty určené i ke zpěvu."}, - {"prompt": "Proč Kryl emigroval?", "options": ["Za obchodem", "Kvůli represím a nemožnosti svobodně tvořit", "Za sportem", "Bez důvodu"], "correct": 1, "expl": "Po okupaci emigroval do Německa; písně zůstaly symbolem odporu doma."}, - {"prompt": "Co znamená píseň Bratříčku, zavírej vrátka?", "options": ["Výzva k zábavě", "Varování před nebezpečím a zradou", "Popis přírody", "Návod na vaření"], "correct": 1, "expl": "Bratříčku oslovuje národ a varuje před odevzdáním svobody."}, - {"prompt": "Jak Kryl pracuje s metaforou?", "options": ["Vůbec", "Politické dění vyjadřuje obrazy (král, blázen, zima)", "Pouze přímou reportáží", "Jen cizím jazykem"], "correct": 1, "expl": "Alegorie umožňuje obcházet cenzuru a mluvit k čtenáři i posluchači."}, - {"prompt": "Co je samizdat v kontextu Kryla?", "options": ["Oficiální tisk", "Nepovolené šíření textů mimo cenzuru", "Film", "Rozhlas státu"], "correct": 1, "expl": "Písně a texty kolovaly neoficiálně v normalizaci."}, - {"prompt": "Jaký tón převládá?", "options": ["Bezbřehý optimismus", "Ironie, bolest, morální naléhavost", "Pouze humor bez smyslu", "Prázdná popisnost"], "correct": 1, "expl": "Kryl spojuje osobní i kolektivní zklamání s nadějí na svědomí."}, - {"prompt": "Kdo je „král“ v písních?", "options": ["Historická postava bez významu", "Alegorie moci, často groteskní a pokrytecké", "Dítě", "Sportovec"], "correct": 1, "expl": "Král symbolizuje režim nebo autoritu, která zklame."}, - {"prompt": "Proč maturita zahrnuje Kníšku?", "options": ["Je nejdelší román", "Ukazuje poezii 20. stol. v politickém kontextu", "Nemá význam", "Je v angličtině"], "correct": 1, "expl": "Učí číst lyrický text v souvislosti s dějinami."}, - {"prompt": "Co je normalizace?", "options": ["Období svobody 1968", "Upevnění komunistické moci po okupaci 1968", "První světová válka", "Sametová revoluce"], "correct": 1, "expl": "Normalizace potlačila reformy Pražského jara."}, - {"prompt": "Jak Kryl vnímá mlčení lidí?", "options": ["Chválí ho", "Vnímá ho jako morální selhání", "Nezmiňuje", "Považuje za hrdinství"], "correct": 1, "expl": "Motiv viny davu a kompromisu se opakuje."}, - {"prompt": "Kdy Kryl zemřel?", "options": ["1994", "1968", "2005", "1848"], "correct": 0, "expl": "Karel Kryl zemřel v roce 1994; po listopadu 89 se vrátil do veřejného života."}, - {"prompt": "Jak se liší píseň a báseň v Kníšce?", "options": ["Písně mají refrén a hudební formu", "Nic se neliší", "Básně jsou jen pro děti", "Písně nemají text"], "correct": 0, "expl": "Mnoho textů známe i z Krylova zpěvu s kytarou."}, - {"prompt": "Co symbolizuje zima nebo tma v textech?", "options": ["Jen počasí", "Temnota doby, strach, útlak", "Radost", "Léto"], "correct": 1, "expl": "Obrazné prostředí odpovídá politické situaci."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Svoboda a útlak", "Emigrace", "Vesmírné války", "Ironie vůči moci"], "correct": 2, "expl": "Kryl píše o české realitě 20. století, ne sci-fi."}, - {"prompt": "Co je protest song?", "options": ["Píseň oslavující moc", "Hudební projev odporu nebo kritiky", "Jen instrumentál", "Anthem sportu"], "correct": 1, "expl": "Kryl je v Česku symbolem autorské protestní písně."}, - {"prompt": "Jak čtenář chápe alegorii Král a klaun?", "options": ["Jako groteskní obraz moci a pravdy", "Jako cookbook", "Bez významu", "Jako vědecký článek"], "correct": 0, "expl": "Postavy stojí pro reálné politické vztahy."}, - {"prompt": "Proč exilové vydání 1972?", "options": ["Kryl nemohl oficiálně publikovat v normalizaci", "Kniha byla zakázaná jen v Německu", "Neexistuje", "Bylo to dětské vydání"], "correct": 0, "expl": "V totalitě vyšly texty v zahraničí nebo samizdatově."}, - {"prompt": "Jaký nástroj Kryl typicky doprovází?", "options": ["Kytara", "Harfa bez hlasu", "Jen klavír klasické", "Žádný"], "correct": 0, "expl": "Kryl je známý jako kytarista a zpěvák."}, - {"prompt": "Co znamená morální odpovědnost v textech?", "options": ["Každý nese díl viny za stav společnosti", "Nikdo není odpovědný", "Jen vláda USA", "Jen církev"], "correct": 0, "expl": "Kryl apeluje na svědomí jednotlivce i národa."}, - {"prompt": "Jak pracuje s biblickými narážkami?", "options": ["Vůbec", "Obrazy dobra, zla a křižovatky osudu", "Jen jako encyklopedie", "Jako vtip bez smyslu"], "correct": 1, "expl": "Biblické motivy zvyšují váhu morálních otázek."}, - {"prompt": "Co je typické pro jazyk Kníšky?", "options": ["Úderné, obrazné, s refrénem", "Suchý úřední styl", "Pouze archaismy", "Anglicky"], "correct": 0, "expl": "Lyrika je hutná a zapamatovatelná."}, - {"prompt": "Jak reaguje na srpnovou okupaci 1968?", "options": ["Ignoruje", "Texty reflektují zradu, bolest a ztrátu naděje jara", "Oslavuje okupaci", "Píše jen o lásce"], "correct": 1, "expl": "Okupace je východiskem protestního tónu sbírky."}, - {"prompt": "Kdo je adresátem „bratříčku“?", "options": ["Jeden bratr v rodině", "Symbolicky národ, blízký člověk, varovaný před nebezpečím", "Cizinec", "Král"], "correct": 1, "expl": "Oslovení je intimní i kolektivní."}, - {"prompt": "Proč jsou texty stále aktuální?", "options": ["Mluví o univerzální svobodě a svědomí", "Jsou zastaralé", "Nejsou čitelné", "Jsou jen hudební"], "correct": 0, "expl": "Otázky moci a odvahy mluvit platí i mimo 70. léta."}, - {"prompt": "Co NENÍ charakteristika Kryla?", "options": ["Protest", "Emigrace", "Oficiální pochvala normalizace", "Ironie"], "correct": 2, "expl": "Kryl normalizaci kritizoval, ne oslavoval."}, - {"prompt": "Jak vnímat emigranta v písních?", "options": ["Postavu bez emocí", "Člověka v konfliktu domov–svoboda–vina", "Vždy boháče", "Vždy zrádce"], "correct": 1, "expl": "Exil je v Krylových textech bolestný i morálně složitý."}, - {"prompt": "Co spojuje Kníšku s další českou lyricou 20. stol.?", "options": ["Nic", "Tradici disidentské a protestní kultury", "Pouze humor", "Pouze sci-fi"], "correct": 1, "expl": "Kryl stojí vedle Hrabala, Holanů apod. v jiných žánrech, ale v politické lyrice je ikonou."}, - {"prompt": "Jaký efekt má refrén v písních?", "options": ["Ztěžuje čtení", "Upevňuje poselství a zapamatovatelnost", "Nemá funkci", "Je jen v angličtině"], "correct": 1, "expl": "Opakování (např. varování) je hudebně i významově klíčové."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Pražské jaro a naděje na svobodu", - "Okupace vojsky a konec reform", - "Kryl emigruje; texty kolují v samizdatu", - "Kníška v exilu sbírá protestní poezii", - "Písně varují před mlčením a zradou", - "Dílo zůstává symbolem morálního odporu" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: jaro 68 → okupace → exil → sbírka → varování v textech → trvalý význam protestní kultury." - ] -} diff --git a/data/cetba/komu-zvoni-hrana.json b/data/cetba/komu-zvoni-hrana.json deleted file mode 100644 index 77547a5..0000000 --- a/data/cetba/komu-zvoni-hrana.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Ernest Hemingway (1899–1961), americký spisovatel", - "Žánr: válečný román, moderní próza", - "Poprvé vydáno: 1940", - "Děj / prostředí: španělská občanská válka 1937, hora Guadarrama", - "Vyprávění / forma: er-forma, střídmý „hemingwayovský“ styl" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Občanská válka: republikáni vs. frankisté, mezinárodní brigády.", - "Robert Jordan je americký dobrovolník na straně republiky.", - "Úkol: odpálit most a zdržet fašistický postup.", - "Hora, jeskyně, partizáni – intimní svět uprostřed kruté války.", - "Titul cituje Donne: „Nikdo není sám o sobě ostrov… proto komu zvoní hrana, zvoní i tobě.“", - "Láska k Marii a smysl smrti v boji za svobodu." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Robert Jordan – americký dynamitář, intelektuál v uniformě.", - "Maria – mladá dívka osvobozená republikány, Jordanova láska.", - "Pablo – vůdce partyzánů, chladný realista, bojí se rizika.", - "Pilar – Pablova žena, silná, věrná republice.", - "Anselmo – starý průvodce, morální svědomí party.", - "El Sordo – vůdce další skupiny, statečný, padne v boji." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Most – symbol úkolu i oběti pro větší věc.", - "Solidarita – smrt jednoho se týká všech (Donne).", - "Hemingwayův styl – krátké věty, málo adjektiv, „iceberg“.", - "Občanská válka ve Španělsku – boj demokracie vs. fašismus.", - "Láska v době války – Maria jako naděje a křehkost.", - "Povinnost vs. strach – Jordanův vnitřní konflikt." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Komu zvoní hrana?", "options": ["Faulkner", "Ernest Hemingway", "Steinbeck", "Fitzgerald"], "correct": 1, "expl": "Román vyšel v roce 1940; Hemingway sledoval válku jako novinář."}, - {"prompt": "Kdy a kde se děj odehrává?", "options": ["Španělská občanská válka, hory u Madridu", "2. sv. válka v Normandii", "Vietnam", "První sv. válka v Itálii"], "correct": 0, "expl": "Děj je v roce 1937 v oblasti Guadarrama."}, - {"prompt": "Kdo je Robert Jordan?", "options": ["Frankistický generál", "Americký dobrovolník, expert na demolice", "Španělský kněz", "Novinář bez úkolu"], "correct": 1, "expl": "Jordan má za úkol odpálit most."}, - {"prompt": "Co znamená titul románu?", "options": ["Popis kostela", "Citát Donne: smrt každého se týká všech", "Jméno mostu", "Název písně bez významu"], "correct": 1, "expl": "Titul vyjadřuje solidaritu a lidskou propojenost."}, - {"prompt": "Kdo je Maria?", "options": ["Jordanova láska, oběť války", "Frankistická špionka", "Generálka", "Jordanova sestra"], "correct": 0, "expl": "Maria prožila traumu; v Jordanovi nachází lásku."}, - {"prompt": "Jaký je vztah Pabla a Pilar?", "options": ["Sourozenci", "Manželé; Pablo je vůdce, Pilar silnější morálně", "Nepřátelé bez vazby", "Důstojníci"], "correct": 1, "expl": "Pablo postupně couvá z boje; Pilar drží partu."}, - {"prompt": "Co má Jordan udělat?", "options": ["Postavit most", "Odpálit most za úsvitu", "Ukrást letadlo", "Podepsat mír"], "correct": 1, "expl": "Most má zdržet fašistický postup během útoku."}, - {"prompt": "Proč je úkol riskantní?", "options": ["Nikdo nehlídá", "Partyzáni jsou rozdělení, Pablo sabotuje, nepřítel blízko", "Jordan je nemocný", "Most neexistuje"], "correct": 1, "expl": "Vnitřní rozpory party zvyšují nebezpečí."}, - {"prompt": "Kdo je Anselmo?", "options": ["Starý průvodce, ctí morálku války", "Fašista", "Jordanův bratr z USA", "Pilot"], "correct": 0, "expl": "Anselmo pomáhá Jordanovi a trpí kvůli zabíjení."}, - {"prompt": "Co se stane El Sordovi?", "options": ["Stane se králem", "Je obklíčen a padne v boji", "Emigruje", "Zradí republiku"], "correct": 1, "expl": "El Sordo a jeho muži umírají hrdinsky na kopci."}, - {"prompt": "Jak Jordan končí?", "options": ["Svatba v Madridu", "Zraněn u mostu; zůstává, aby zdržel nepřítele", "Utíká do USA", "Stává se generálem"], "correct": 1, "expl": "Finální oběť je morální i praktická."}, - {"prompt": "Jaký styl je typický pro Hemingwaye?", "options": ["Dlouhé patetické věty", "Střídmý jazyk, dialog, „iceberg“ – hodně pod hladinou", "Pouze poezie", "Groteskní humor"], "correct": 1, "expl": "Emoce jsou často pod textem, ne v patosu."}, - {"prompt": "Na čí straně Jordan bojuje?", "options": ["Frankisté", "Republikáni / demokratická strana", "Neutralita", "Nacisté Německa"], "correct": 1, "expl": "Jordan je v mezinárodní brigádě na straně republiky."}, - {"prompt": "Proč Pablo ukradne výbušniny?", "options": ["Chce zmařit nebezpečný útok a zachránit partu", "Chce být bohatý", "Na příkaz Jordana", "Pro zábavu"], "correct": 0, "expl": "Pablo jedná sobecky z strachu o přežití."}, - {"prompt": "Co symbolizuje most?", "options": ["Jen stavba", "Spojení úkolu, oběti a vojenského plánu", "Kostel", "Hranice bez děje"], "correct": 1, "expl": "Most je středem napětí celého románu."}, - {"prompt": "Jaký je význam lásky Jordan–Maria?", "options": ["Bez vlivu na děj", "Dává Jordanovi lidský smysl i bolest ztráty", "Komický prvek", "Past od fašistů"], "correct": 1, "expl": "Láska kontrastuje s brutalitou války."}, - {"prompt": "Kdo režíroval slavnou filmovou adaptaci?", "options": ["Sam Wood (1943)", "Spielberg", "Kubrick", "Nolan"], "correct": 0, "expl": "Film z 40. let s Gary Cooperem a Ingrid Bergmanovou."}, - {"prompt": "Co je mezinárodní brigáda?", "options": ["Frankistická armáda", "Dobrovolníci z ciziny bojující za republiku", "Nevládní organizace dnes", "Pouze španělští kněží"], "correct": 1, "expl": "Jordan reprezentuje cizince v španělské válce."}, - {"prompt": "Proč maturanti čtou román?", "options": ["Je nejkratší", "Spojuje válku, etiku, styl modernismu a historii Španělska", "Nemá postavy", "Je komiks"], "correct": 1, "expl": "Dílo je klíčové pro Hemingwaye i 20. století."}, - {"prompt": "Jak Pilar vnímá Pabla?", "options": ["Obdivuje jeho statečnost vždy", "Kritizuje jeho zbabělost, ale zůstává v partě", "Nezná ho", "Je to cizinec"], "correct": 1, "expl": "Pilar je duší party; Pablo je její protiklad."}, - {"prompt": "Co Jordan cítí k zabíjení?", "options": ["Radost", "Morální tíhu; válka není abstraktní", "Nic", "Pouze nudu"], "correct": 1, "expl": "Jordan přemýšlí o smrti i když plní rozkaz."}, - {"prompt": "Které téma NENÍ středem?", "options": ["Oběť pro věc", "Solidarita", "Vesmírná kolonizace", "Láska ve válce"], "correct": 2, "expl": "Román je realistická válečná próza."}, - {"prompt": "Kde party zimuje?", "options": ["V jeskyni v horách", "V Paříži", "Na lodi", "V paláci"], "correct": 0, "expl": "Jeskyně je útočiště i místem intimity a plánů."}, - {"prompt": "Co se stane s výbušninami po Pablově krádeži?", "options": ["Jordan získá náhradu a plán pokračuje", "Úkol končí hned", "Frankisté je najdou", "Maria je odpálí"], "correct": 0, "expl": "Parta získá materiál zpět (Pablo částečně pomůže)." }, - {"prompt": "Jaký význam má smrt El Sorda pro děj?", "options": ["Žádný", "Ukazuje neúprosnost války a cenu odporu", "Komický", "Znamená konec války"], "correct": 1, "expl": "Scéna na kopci je vrchol tragismu."}, - {"prompt": "Co Jordan přemýšlí o otci?", "options": ["Otec byl republikán", "Otec se střelil; Jordan řeší sebevraždu a smysl", "Otec byl král", "Nezmiňuje otce"], "correct": 1, "expl": "Rodinná minulost ovlivňuje Jordanův pohled na smrt."}, - {"prompt": "Proč „komu zvoní hrana“ v maturitní interpretaci?", "options": ["Jen o kostelech", "O tom, že smrt a osud jednoho se dotýkají celku", "O hudbě", "O mostě"], "correct": 1, "expl": "Donneova myšlenka propojuje hrdiny s lidstvem."}, - {"prompt": "Jak Hemingway vykresluje fašisty?", "options": ["Jako abstraktní nepřítele války", "Jako konkrétní vojenskou hrozbu bez patosu", "Jako kamarády", "Vůbec"], "correct": 1, "expl": "Nepřítel je reálný, válka je konkrétní."}, - {"prompt": "Co Maria symbolizuje?", "options": ["Obnovu života a naděje po zlu", "Jen špionáž", "Bohatství", "Válku"], "correct": 0, "expl": "Maria je zraněná, ale milující protiváha války."}, - {"prompt": "Jaký je hlavní konflikt románu?", "options": ["Sportovní soutěž", "Plnění nebezpečného úkolu vs. lidský vztah a strach", "Soudní proces", "Detektivní hádanka bez války"], "correct": 1, "expl": "Jordan musí sladit povinnost, lásku a smrt."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Jordan se připojí k partyzánům v horách", - "Seznámí se s Marií a plánuje odpálení mostu", - "Pablo ukradne výbušniny; napětí v partě", - "El Sordo padne v boji s fašisty", - "Jordan odpálí most, ale je zraněn", - "Zůstává na místě, aby zdržel nepřítele" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: příjezd k partě → láska a plán → sabotáž Pabla → smrt El Sorda → most → Jordanova oběť." - ] -} diff --git a/data/cetba/kral-oidipus.json b/data/cetba/kral-oidipus.json deleted file mode 100644 index 5b907cf..0000000 --- a/data/cetba/kral-oidipus.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Sofokles (cca 496–406 př. n. l.), athénský tragik", - "Žánr: antická tragédie", - "Poprvé vydáno / uvedeno: kolem 429 př. n. l. (Athény)", - "Děj / prostředí: Théby, mýtus o králi Oidipovi", - "Vyprávění / forma: dramatická forma, jednota času a místa, chór" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Antické Théby trpí morem; lidé hledají viníka.", - "Král Oidipus slíbil vysvobodit město od prokletí.", - "Tragédie stojí na neznalosti vlastní identity a osudu.", - "Bohové a věštba – člověk nemůže uniknout tomu, co je mu souzeno.", - "Jednota času, místa a děje – klasická pravidla antické tragédie.", - "Téma: poznání sebe sama stojí život i důstojnost." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Oidipus – král Théb, statečný, ale slepý k pravdě o sobě.", - "Iokasté – Oidipova manželka, ve skutečnosti matka.", - "Kréón – Iokastin bratr, racionální, obviňovaný z intrik.", - "Tiresias – slepý vědec, vidí pravdu dříve než král.", - "Posel z Korintu, pastýř – odhalují minulost Oidipa.", - "Chór thébských stařců – komentuje děj a morálku." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Věštba – Oidipus zabije otce a ožení se s matkou.", - "Hamartia – tragická chyba v pýše a netrpělivosti.", - "Anagnórisis – poznání pravdy o zločinech.", - "Peripetie – obrat od slávy k pádu.", - "Katarze – očista diváka strachem a soucitem.", - "Oidipovský komplex (Freud) – odvozený pojem, ne u Sofokla." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Krále Oidipa?", "options": ["Euripides", "Sofokles", "Aischylos", "Homér"], "correct": 1, "expl": "Sofokles je jeden ze tří velkých athénských tragiků."}, - {"prompt": "Kde se děj odehrává?", "options": ["Sparta", "Théby", "Athény", "Troja"], "correct": 1, "expl": "Théby jsou postiženy morem a prokletím."}, - {"prompt": "Jaký problém trápí Théby na začátku?", "options": ["Válka s Persy", "Mor a neznámý viník zločinu", "Hladomor bez moru", "Povodeň"], "correct": 1, "expl": "Lidé žádají Oidipa, aby město zachránil."}, - {"prompt": "Co slíbil Oidipus občanům?", "options": ["Nové hradby", "Najde viníka vraždy krále Láia a město vysvobodí", "Odejde do exilu hned", "Zruší bohy"], "correct": 1, "expl": "Král se zavazuje trestat vraha bývalého krále."}, - {"prompt": "Kdo je Tiresias?", "options": ["Vrah", "Slepý větec, který zná pravdu", "Oidipův syn", "Cizí voják"], "correct": 1, "expl": "Tiresias odhalí, že viníkem je sám Oidipus."}, - {"prompt": "Proč Oidipus nejdřív Tiresia neposlouchá?", "options": ["Je hluchý", "Pýcha – odmítá obvinění", "Spí", "Tiresias nemluví"], "correct": 1, "expl": "Oidipus je netrpělivý a arogantní vůči věštci."}, - {"prompt": "Koho Oidipus obviní z intriky?", "options": ["Kréóna", "Chór", "Posla", "Sama sebe"], "correct": 0, "expl": "Domnívá se, že Kréón usiluje o trůn."}, - {"prompt": "Co odhalí posel z Korintu?", "options": ["Oidipus není syn korintského krále Polyba", "Oidipus je bůh", "Iokasté je cizinka", "More skončilo"], "correct": 0, "expl": "Oidipus byl adoptován; začne pátrat po pravých rodičích."}, - {"prompt": "Kdo byl Laios?", "options": ["Oidipův syn", "Bývalý král Théb, Oidipův biologický otec", "Kréónův otec", "Pastýř bez role"], "correct": 1, "expl": "Věštba předpověděla, že syn Láia zabije otce."}, - {"prompt": "Co Oidipus udělal na křižovatce?", "options": ["Pomohl starci", "V afektu zabil cestovatele (Láia)", "Koupil koně", "Modlil se"], "correct": 1, "expl": "Neznal otce; spor o průjezd vedl k vraždě."}, - {"prompt": "Kdo je Sfinga v mýtu?", "options": ["Had", "Bytost s hádankou; Oidipus ji porazil", "Kréónova žena", "Chór"], "correct": 1, "expl": "Vítězství nad Sfingou učinilo Oidipa králem."}, - {"prompt": "Kdo se stane Oidipovou manželkou?", "options": ["Antigona", "Iokasté – vlastní matka", "Cizí princezna", "Tiresias"], "correct": 1, "expl": "Oidipus se oženil s vdovou po Láiovi, aniž znal vztah."}, - {"prompt": "Co je anagnórisis?", "options": ["Hudba chóru", "Poznání pravdy hrdinou", "Vstup na jeviště", "Konec hry"], "correct": 1, "expl": "Oidipus pochopí, že splnil věštbu."}, - {"prompt": "Jak Iokasté reaguje na podezření?", "options": ["Radost", "Popírá, pak spáchá sebevraždu", "Utíká do Korintu", "Zabije Oidipa"], "correct": 1, "expl": "Iokasté chápe dřív a nevydrží pravdu."}, - {"prompt": "Co Oidipus udělá po poznání?", "options": ["Oslaví svatbu", "Vydloubne si oči a žádá vyhnanství", "Stane se bohem", "Obviní chór"], "correct": 1, "expl": "Symbolické potrestání – viděl, ale neviděl pravdu."}, - {"prompt": "Kdo převezme moc na konci?", "options": ["Kréón", "Oidipus navždy", "Tiresias", "Laios"], "correct": 0, "expl": "Kréón zůstává jako vládce; Oidipus odchází."}, - {"prompt": "Co je hamartia u Oidipa?", "options": ["Nemoc", "Tragická chyba – pýcha, netrpělivost, touha po pravdě bez snášení", "Línost", "Zrada Kréóna"], "correct": 1, "expl": "Hrdina není zlý, ale má tragickou vadu charakteru."}, - {"prompt": "Jaký význam má chór?", "options": ["Komický intermezzo", "Komentuje děj a reakce obce", "Hraje hlavní roli", "Neobjevuje se"], "correct": 1, "expl": "Chór thébských stařců vyjadřuje city města."}, - {"prompt": "Co je katarze?", "options": ["Smích diváka", "Očistný efekt strachu a soucitu", "Hudba bez děje", "Scéna bez významu"], "correct": 1, "expl": "Aristoteles tragédii vysvětluje právě katarzí."}, - {"prompt": "Proč nelze věštbě uniknout?", "options": ["Bohové a osud jsou silnější než lidské plány", "Věštba je vtip", "Oidipus neposlouchal", "Laios žije"], "correct": 0, "expl": "Tragédie ukazuje osudovost mýtu."}, - {"prompt": "Které pravidlo antické tragédie dodržuje hra?", "options": ["Jednota času, místa a děje", "Pět dějství bez pravidel", "Pouze komické prvky", "Bez chóru"], "correct": 0, "expl": "Děj se soustředí na den odhalení v Thébách."}, - {"prompt": "Co znamená „oidipovský komplex“ u Freuda?", "options": ["Sofoklovo pojmenování", "Moderní psychoanalytický pojem odvozený od mýtu, ne od Sofokla", "Chór", "Věštba"], "correct": 1, "expl": "Freud použil jméno; antická hra má jiný kontext."}, - {"prompt": "Kdo zabil Sfingu?", "options": ["Kréón", "Oidipus správnou hádankou", "Iokasté", "Posel"], "correct": 1, "expl": "Vítězství nad Sfingou přineslo korunu."}, - {"prompt": "Proč Oidipus pátrá po vrahovi Láia?", "options": ["Neví, že hledá sám sebe", "Ví od začátku", "Na příkaz Kréóna bez důvodu", "Kvůli pokladu"], "correct": 0, "expl": "Ironie tragédie – trestá sám sebe."}, - {"prompt": "Jaký kontrast tvoří Oidipus?", "options": ["Bohatý vs. chudý", "Vidí svět, ale ne pravdu o sobě; pak slepý, ale chápe", "Mladý vs. starý bez významu", "Muž vs. žena bez děje"], "correct": 1, "expl": "Motiv slepota–vidění je klíčový."}, - {"prompt": "Které tvrzení o Iokasté je správné?", "options": ["Je Oidipova dcera", "Je Oidipova matka i manželka", "Je Kréónova dcera bez vztahu", "Je bohyně"], "correct": 1, "expl": "Incest je jádrem odhalení."}, - {"prompt": "Co je peripetie?", "options": ["Obrat osudu hrdiny od štěstí k neštěstí", "Úvod hry", "Píseň chóru", "Smích"], "correct": 0, "expl": "Od slavného krále k prokletému vyhnanci."}, - {"prompt": "Proč maturita zahrnuje Krále Oidipa?", "options": ["Je nejnovější román", "Základ tragédie, mýtu a dramaturgie", "Je komiks", "Bez významu"], "correct": 1, "expl": "Učí strukturu tragédie a antické mytologie."}, - {"prompt": "Jak končí Oidipus v této hře?", "options": ["Na trůnu navždy", "Odchází do vyhnanství, zničen poznáním", "Svatba s novou ženou", "Vítězí nad bohy"], "correct": 1, "expl": "Finále je pokání a vyhnanství (pokračuje v Oidipovi v Kolónu)." }, - {"prompt": "Jaké poselství tragédie nese?", "options": ["Člověk musí poznat sám sebe, i za cenu bolesti", "Pýcha vždy vyhrává", "Bohové neexistují", "Lži jsou lepší"], "correct": 0, "expl": "Poznání pravdy je morální i existenciální nutnost."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Théby trpí morem; Oidipus slíbí najít viníka", - "Tiresias obviní Oidipa; král to odmítá", - "Posel a pastýř odhalí Oidipovu minulost", - "Oidipus pozná, že zabil otce a vzal si matku", - "Iokasté spáchá sebevraždu", - "Oidipus oslepí sám sebe a odchází do vyhnanství" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: mor a slib → Tiresias → odhalení rodu → anagnórisis → smrt Iokasté → sebeztrestání a exil." - ] -} diff --git a/data/cetba/krysar.json b/data/cetba/krysar.json deleted file mode 100644 index 7ae31cf..0000000 --- a/data/cetba/krysar.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Viktor Dyk (1877–1931), český básník a prozaik", - "Žánr: novela, lyrizovaná próza, alegorie", - "Poprvé vydáno: 1915", - "Děj / prostředí: město Hameln (porýnská legenda o krysaři)", - "Vyprávění / forma: er-forma, rytmická prósa, refrénovité opakování" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Dyk zpracovává středověkou německou pověst o krysaři z Hameln.", - "Vznik za 1. světové války; čte se i jako alegorie zrady a odplaty.", - "Měšťané jsou sobečtí, pokrytečtí, nedodrží slovo.", - "Krysař je cizinec – umělec, milenec i mstitel.", - "Láska ke Kristýnce je osobní rovina vedle viny města.", - "Jazyk je téměř básnický; opakují se klíčové věty a obrazy." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Krysař – cizinec s píšťalou, zbaví město krys, mstí se za zradu.", - "Kristýnka – dívka, kterou Krysař miluje.", - "Sepp Jörgen – rybář, prostý a věrný, přežije katastrofu.", - "Měšťané a konšelé – sobečtí, odmítnou zaplatit dohodnutou odměnu.", - "Agnes – matka Kristýnky, svět měšťanské morálky.", - "Bonifác – rival, představitel průměrnosti a závisti." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Píšťala – nástroj moci, svodu i trestu.", - "Zrada slova – město nezaplatí slíbenou cenu.", - "Alegorie – měšťanská malost a kolektivní vina.", - "Láska a smrt – vztah ke Kristýnce končí tragicky.", - "Cizinec – věčný outsider, který odhalí morálku společnosti.", - "Právo na odplatu – etický i právní dluh města." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Krysaře?", "options": ["Neruda", "Viktor Dyk", "Hašek", "Čapek"], "correct": 1, "expl": "Dyk vydal novelu v roce 1915; patří k české moderně."}, - {"prompt": "Na jaké legendě novela staví?", "options": ["O Vlastovi", "O krysaři z Hameln", "O Ikarovi", "O Golemovi"], "correct": 1, "expl": "Porýnská pověst o muži, který odvedl děti píšťalou."}, - {"prompt": "Kdo je hlavní hrdina?", "options": ["Sepp Jörgen", "Krysař – cizinec s píšťalou", "Bonifác", "Konšel"], "correct": 1, "expl": "Krysař přichází do města a řeší problém krys."}, - {"prompt": "Proč město Krysaře najme?", "options": ["Kvůli povodni", "Město sužují krysy", "Chce tanec", "Hledá krále"], "correct": 1, "expl": "Krysy ohrožují obyvatele; Krysař slíbí pomoc."}, - {"prompt": "Co měšťané udělají po vyhnání krys?", "options": ["Zaplatí slíbenou odměnu", "Odmítnou zaplatit dohodnutou cenu", "Odejdou z města", "Postaví sochu"], "correct": 1, "expl": "Zrada slova spouští pomstu."}, - {"prompt": "Koho Krysař miluje?", "options": ["Agnes", "Kristýnku", "Vdovu konšela", "Nikoho"], "correct": 1, "expl": "Láska ke Kristýnce je intimní linie novely."}, - {"prompt": "Kdo je Sepp Jörgen?", "options": ["Krysařův nepřítel", "Prostý rybář, věrný a přeživší", "Král", "Krysa"], "correct": 1, "expl": "Sepp představuje jiný, ne měšťanský svět."}, - {"prompt": "Jak Krysař pomstí zradu?", "options": ["Soudní žalobou", "Píšťalou odvede děti z města", "Spálí radnici", "Odejde bez reakce"], "correct": 1, "expl": "Legendární scéna odchodu dětí za pišťalou."}, - {"prompt": "Proč je novela alegorická?", "options": ["Popisuje jen historii", "Měšťanská zrada a odplata vypovídá o morálce společnosti", "Je bez významu", "Je učebnice chemie"], "correct": 1, "expl": "Dyk čte legendu i v kontextu války a pokrytectví."}, - {"prompt": "Jaký je styl Dykovy prózy?", "options": ["Úřední report", "Lyrizovaná, rytmická prósa s refrény", "Sci-fi", "Detektivka"], "correct": 1, "expl": "Text působí téměř jako báseň v próze."}, - {"prompt": "Co symbolizuje píšťala?", "options": ["Jen hudební nástroj", "Moc nad lidmi – nejdřív krysy, pak děti", "Kříž", "Mince"], "correct": 1, "expl": "Píšťala je nástroj svodu i trestu."}, - {"prompt": "Kdy novela vznikla?", "options": ["1915", "1848", "1989", "2000"], "correct": 0, "expl": "Vznik v první světové válce ovlivňuje alegorické čtení."}, - {"prompt": "Kdo jsou měšťané v díle?", "options": ["Idealní občané", "Sobečtí, nedodrží slovo", "Vojáci", "Cizinci"], "correct": 1, "expl": "Kolektivní vina města je jádrem."}, - {"prompt": "Jak končí vztah Krysař–Kristýnka?", "options": ["Svatbou", "Tragicky – láska se mísí s osudem pomsty", "Bez kontaktu", "Komedií"], "correct": 1, "expl": "Osobní i kolektivní tragédie se proplétají."}, - {"prompt": "Kde se děj odehrává?", "options": ["Praha", "Hameln (Hamelyn)", "Vídeň", "Paříž"], "correct": 1, "expl": "Německé město v legendě i u Dyka."}, - {"prompt": "Proč je Krysař cizinec?", "options": ["Bez důvodu", "Outsider odhaluje morálku uzavřené komunity", "Je místní kněz", "Je král"], "correct": 1, "expl": "Přichází zvenku a mění osud města."}, - {"prompt": "Co je tématem zrady?", "options": ["Politická jen v moderně", "Porušení daného slova a smlouvy", "Zrada v kartách", "Sport"], "correct": 1, "expl": "Město nezaplatí – morální i smluvní porušení."}, - {"prompt": "Který prvek NENÍ typický?", "options": ["Legenda", "Lyrizace", "Vesmírná válka", "Alegorie"], "correct": 2, "expl": "Novela je komorní legendární příběh."}, - {"prompt": "Jak Dyk pracuje s opakováním?", "options": ["Refrénovité motivy a věty", "Nepoužívá", "Jen v angličtině", "Nahodile"], "correct": 0, "expl": "Opakování zvyšuje rytmus a napětí."}, - {"prompt": "Kdo je Bonifác?", "options": ["Rival, měšťanská postava", "Krysa", "Rybář", "Vdova"], "correct": 0, "expl": "Bonifác patří k městskému prostředí a rivalitám."}, - {"prompt": "Proč maturita zahrnuje Krysaře?", "options": ["Nejdelší román", "Ukázka moderní lyrizované prózy a alegorie", "Bez stylu", "Jen historie"], "correct": 1, "expl": "Učí číst legendu i symboliku."}, - {"prompt": "Co znamená kolektivní vina?", "options": ["Vina jednoho vojáka", "Celé město nesou odpovědnost za zradu", "Vina Krysaře", "Bez viny"], "correct": 1, "expl": "Měšťané jednají společně proti Krysařovi."}, - {"prompt": "Jaký kontrast tvoří Sepp Jörgen?", "options": ["Měšťan vs. prostý člověk mimo pokrytectví", "Bohatý vs. chudý bez morálky", "Dítě vs. dospělý", "Válka vs. mír bez děje"], "correct": 0, "expl": "Rybář představuje jinou hodnotovou osu."}, - {"prompt": "Co je er-forma v novelě?", "options": ["Vypravěč „on“", "Vypravěč neviditelný, děj sledujeme zvenku er-formou Dykova stylu", "Dyk používá vypravěče třetí osoby s lyrickým nádechem", "Jen dialogy"], "correct": 2, "expl": "Novela je psána er-formou s poetickým jazykem."}, - {"prompt": "Jak interpretovat novelu ve válce 1914–18?", "options": ["Ignorovat kontext", "Zrada slibů může odkazovat na politickou zradu a malost", "Jen dětská pohádka", "Reklama"], "correct": 1, "expl": "Contemporary readers viděli paralely s válkou."}, - {"prompt": "Kdo přežije katastrofu dětí?", "options": ["Všichni měšťané", "Sepp Jörgen a dospělí; děti odcházejí", "Nikdo", "Jen Krysař"], "correct": 1, "expl": "Legenda: děti mizí; dospělí zůstávají s vinou."}, - {"prompt": "Co je právo na odměnu?", "options": ["Krysař nemá nárok", "Etický dluh města za vykonanou službu", "Jen daň", "Pokuta"], "correct": 1, "expl": "Nezaplacení je start pomsty."}, - {"prompt": "Jaký žánr nejlépe sedí?", "options": ["Novela / lyrizovaná próza", "Epos", "Sci-fi", "Učebnice"], "correct": 0, "expl": "Krátké hutné dílo s poetickým jazykem."}, - {"prompt": "Co čtenář cítí vůči městu?", "options": ["Obdiv", "Odsudek pokrytectví", "Nezájem", "Smích bez děje"], "correct": 1, "expl": "Měšťané si zaslouží morální soud."}, - {"prompt": "Jaké poselství novela nese?", "options": ["Slovo a smlouva mají cenu; zrada se mstí", "Krysy jsou roztomilé", "Cizinci jsou vždy zlí", "Láska vždy vyhrává"], "correct": 0, "expl": "Dyk varuje před malostí a nečestností."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Krysař přichází do Hamelnu a slíbí vyhnat krysy", - "Píšťalou vyžene krysy z města", - "Měšťané odmítnou zaplatit dohodnutou odměnu", - "Krysař miluje Kristýnku; město ho zradí", - "Krysař znovu hraje na píšťalu – odvádí děti", - "Město zůstává s vinou a tragickým následkem" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: příchod → vyhnání krys → nezaplacení → láska a zrada → odchod dětí → vina města." - ] -} diff --git a/data/cetba/kulicka.json b/data/cetba/kulicka.json deleted file mode 100644 index ff1b972..0000000 --- a/data/cetba/kulicka.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Guy de Maupassant (1850–1893), francouzský spisovatel", - "Žánr: realistická / naturalistická novela", - "Poprvé vydáno: 1880 (Večery na Médanu)", - "Děj / prostředí: Francie po prusko-francouzské válce, ústup z Rouenu", - "Vyprávění / forma: er-forma, ironický vypravěč, pointa" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Po porážce 1870/71: okupace, panika měšťanů, útěk z Rouenu.", - "Maupassant demaskuje pokrytectví „slušné“ společnosti.", - "Hrdinkou je prostitutka Elisabeth Roussetová – Kulička.", - "Morálka elity je pokrytecká: využijí ji, pak ji pohrdají.", - "Novela patří k vrcholům francouzského realismu 19. století.", - "Pointa je krutá – Kulička pláče, měšťané jedí a zpívají." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Kulička (Elisabeth Roussetová) – prostitutka s upřímným charakterem.", - "Měšťané ve voze – obchodníci, šlechtici, demokrat, manželský pár.", - "Jeptišky – reprezentují náboženskou morálku, jedí Kuliččiny sendviče.", - "Pruský důstojník – žádá Kuliččinu „společnost“ za propuštění.", - "Loiseau – obchodník, nejvíc pokrytecký a posměšný.", - "Comtesse de Bréville – šlechtická dáma v hypocrisii." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Pokrytectví – měšťané odsuzují, ale potřebují Kuličku.", - "Vlastenectví vs. sobectví – vlastenecké řeči kryjí strach.", - "Oběť – Kulička se obětuje pro ostatní.", - "Ironie – vypravěč odhaluje pravý charakter „slušných“.", - "Naturalismus – sociální a biologické determinace.", - "Pointa – ostrý závěr novelly." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Kuličku?", "options": ["Zola", "Guy de Maupassant", "Flaubert", "Hugo"], "correct": 1, "expl": "Maupassant patří k mistrem francouzské novely."}, - {"prompt": "Kdy a kde se děj odehrává?", "options": ["Po válce 1870/71, cesta z Rouenu", "Za revoluce 1789", "V 21. století", "V Itálii"], "correct": 0, "expl": "Měšťané utíkají z okupovaného Rouenu."}, - {"prompt": "Kdo je Kulička?", "options": ["Kněžka", "Prostitutka Elisabeth Roussetová", "Generálka", "Učitelka"], "correct": 1, "expl": "Kulička je přezdívka podle postavy."}, - {"prompt": "Proč cestují ve voze?", "options": ["Na dovolenou", "Utíkají před okupací do Havra", "Na svatbu", "Do Paříže za móou"], "correct": 1, "expl": "Společná cesta spojuje různé společenské vrstvy."}, - {"prompt": "Co brání voze v odjezdu?", "options": ["Pruský důstojník nepropustí bez „ústupku“ Kuličky", "Kolo", "Sníh", "Stávka"], "correct": 0, "expl": "Důstojník chce noc s Kuličkou."}, - {"prompt": "Jak se měšťané chovají na začátku k Kuličce?", "options": ["S úctou", "Pohrdavě, nechtějí sedět vedle „ nízké “ ženy", "Neznají ji", "Obdivují ji"], "correct": 1, "expl": "Společenská předsudek je silný."}, - {"prompt": "Proč nakonec tlačí na Kuličku?", "options": ["Aby vařila", "Aby šla k důstojníkovi a umožnila odjezd", "Aby platila", "Aby zpívala"], "correct": 1, "expl": "Vlastní zájem přebije morální řeči."}, - {"prompt": "Co udělá Kulička?", "options": ["Odmítne navždy", "Obětuje se pro ostatní a jde k Prusům", "Utéká sama", "Zavolá policii"], "correct": 1, "expl": "Je statečnější než „slušní“ cestující."}, - {"prompt": "Jak měšťané reagují po odjezdu?", "options": ["Děkují s úctou", "Jedí a opět ji pohrdají, posmívají se", "Pláčou", "Vrací peníze"], "correct": 1, "expl": "Pointa odhaluje jejich pokrytectví."}, - {"prompt": "Jaký žánr novela reprezentuje?", "options": ["Realismus / naturalismus", "Fantasy", "Sci-fi", "Epos"], "correct": 0, "expl": "Maupassant realisticky kritizuje společnost."}, - {"prompt": "Co je ironie v díle?", "options": ["Kulička je nejhorší", "Nej„morálnější“ v chování je prostitutka", "Prusové jsou hrdinové", "Jeptišky jsou bohaté"], "correct": 1, "expl": "Obrácení hodnot je jádrem novely."}, - {"prompt": "Kdo jsou jeptišky ve voze?", "options": ["Vojáci", "Náboženské sestry, také jedou z města", "Pruské špionky", "Rodina Kuličky"], "correct": 1, "expl": "Jedí Kuliččiny sendviče, ale nepodpoří ji morálně."}, - {"prompt": "Co symbolizuje společná jízda?", "options": ["Uzavřený mikrokosmos francouzské společnosti", "Sport", "Náhodu", "Vesmír"], "correct": 0, "expl": "Voze je jevištěm sociální kritiky."}, - {"prompt": "Jak Maupassant pracuje s pointou?", "options": ["Bez závěru", "Ostrý závěr demaskuje postavy", "Pouze happy end", "Nevysvětlí"], "correct": 1, "expl": "Závěrečná scéna s jídlem a posměchem je slavná."}, - {"prompt": "Kdo je Loiseau?", "options": ["Pruský důstojník", "Obchodník, typ pokrytce", "Kuliččin otec", "Kočí"], "correct": 1, "expl": "Loiseau je jedním z nejposměšnějších měšťanů."}, - {"prompt": "Proč maturita zahrnuje Kuličku?", "options": ["Nejdelší román", "Ukázka novely, ironie a společenské kritiky", "Bez děje", "Komiks"], "correct": 1, "expl": "Krátké dílo s velkým významem."}, - {"prompt": "Co je vlastenectví ve voze?", "options": ["Upřímná oběť", "Často rétorika maskující strach a sobectví", "Nezmiňuje se", "Pouze u Kuličky falešné"], "correct": 1, "expl": "Měšťané mluví o vlasti, ale chtějí jen uniknout."}, - {"prompt": "Které téma NENÍ středem?", "options": ["Pokrytectví", "Oběť prostitutky", "Vesmírná kolonizace", "Válka a okupace"], "correct": 2, "expl": "Novela je sociální satira 19. století."}, - {"prompt": "Jak vypravěč hodnotí Kuličku?", "options": ["Objektivně s ironií vůči ostatním", "Nenávidí ji", "Je to Kulička", "Bez postoje"], "correct": 0, "expl": "Er-forma odhaluje pokrytectví elity."}, - {"prompt": "Co Kulička přinese do vozu?", "options": ["Jídlo – sendviče sdílené s jeptiškami", "Zbraně", "Pruskou uniformu", "Nic"], "correct": 0, "expl": "Jídlo je detail ukazující její štědrost."}, - {"prompt": "Jak končí novela emocionálně?", "options": ["Kulička slaví", "Kulička pláče; ostatní jedí a posmívají se", "Všichni se usmíří", "Prusové vítězí"], "correct": 1, "expl": "Krutá pointa zvyšuje sociální kritiku."}, - {"prompt": "Kde poprvé vyšla Kulička?", "options": ["Ve sbírce Večery na Médanu (1880)", "V Lidových novinách 2000", "V antice", "V angličtině 1700"], "correct": 0, "expl": "Maupassant debutoval v této sbírce s Zolou."}, - {"prompt": "Co je naturalistický prvek?", "options": ["Důraz na prostředí, třídu a determinaci chování", "Magie", "Bohové", "Pouze humor"], "correct": 0, "expl": "Společenské postavení formuje jednání postav."}, - {"prompt": "Proč odmítá Kulička nejdřív důstojníka?", "options": ["Vlastenecký postoj – nechce spát s okupantem", "Nemá čas", "Miluje Loiseaua", "Je nemocná"], "correct": 0, "expl": "Její hrdost je silnější než u ostatních."}, - {"prompt": "Co měšťané dělají, když tlačí na Kuličku?", "options": ["Modlí se s ní", "Manipulují – morální nátlak pro vlastní prospěch", "Platí jí", "Jedou pěšky"], "correct": 1, "expl": "Hypocrisie vrcholí společným nátlakem."}, - {"prompt": "Jaký kontrast tvoří jádro novely?", "options": ["Bohatí vs. chudí bez morálky", "Prostitutka s ctností vs. „ctnostní“ měšťané bez morálky", "Muži vs. ženy bez války", "Prus vs. Francie bez lidí"], "correct": 1, "expl": "Obrácení etických rolí je klíčové."}, - {"prompt": "Kdo je Comtesse de Bréville?", "options": ["Šlechtice ve voze", "Kulička", "Kočí", "Pruská generálka"], "correct": 0, "expl": "Patří k elitě, která Kuličku opovrhuje."}, - {"prompt": "Co znamená oběť Kuličky?", "options": ["Nic", "Zachrání cestu ostatním, ale nikdo jí neděkuje", "Zradí vlast", "Získá titul"], "correct": 1, "expl": "Oběť je společensky neoceněná."}, - {"prompt": "Jak Maupassant ovlivnil prózu?", "options": ["Krátká novela s pointou – vzor pro realismus", "Vynalezl sci-fi", "Psal jen poezii", "Bez vlivu"], "correct": 0, "expl": "Kulička je učebnicový příklad novely."}, - {"prompt": "Jaké poselství novela nese?", "options": ["Společenská morálka bývá pokrytecká", "Prostituce je vždy špatná", "Válka je dobrá", "Elita je vždy spravedlivá"], "correct": 0, "expl": "Maupassant demaskuje falešné mravní kategorie."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Měšťané a Kulička nastupují do vozu z Rouenu", - "Pruský důstojník zadrží odjezd", - "Kulička odmítá důstojníka; ostatní ji pohrdají", - "Hlad a strach rostou ve voze", - "Kulička obětuje se pro ostatní", - "Po odjezdu ji měšťané opět opovrhují a posmívají se" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: společná cesta → zadržení → pohrdání → nátlak → oběť → krutá pointa s pokrytectvím." - ] -} diff --git a/data/cetba/kvety-zla.json b/data/cetba/kvety-zla.json deleted file mode 100644 index b3f261f..0000000 --- a/data/cetba/kvety-zla.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Charles Baudelaire (1821–1867), francouzský básník", - "Žánr: moderní poezie, symbolistická sbírka", - "Poprvé vydáno: 1857 (soud za nemravnost)", - "Děj / prostředí: moderní město (Paříž), vnitřní svět básníka", - "Vyprávění / forma: lyrické básně, cykly (např. Spleen, Víno, Květy zla)" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Druhá polovina 19. století: industrializace, městská anonymita, krize víry.", - "Baudelaire vytváří „moderní“ estetiku krásy v ošklivém a hříšném.", - "Sbírka byla stíhána za obscénnost – symbol vzdoru proti puritanismu.", - "Motivy: smrt, smyslnost, nuda (spleen), umění, démonismus.", - "Vliv na symbolismus a moderní evropskou poezii.", - "Albatros, Holka s košíkem – ikonické básně cyklu." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Básnický subjekt – flanér, vnímavý k městu i temnotě duše.", - "Ženy – milenky, coury, matky – objekty i symboly touhy a bolesti.", - "Démon / ďábel – vnitřní pokušení a krása zla.", - "Umělec – albatros, vězeň snů (básně o tvorbě).", - "Dav a město – anonymní moderní prostředí.", - "Stvořitel a stvoření – teologické pochybnosti." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Spleen – nuda, melancholie, existenciální prázdnota.", - "Symbolismus – obraz nese víc významů (květy = krása i hřích).", - "Krása v modernitě – estetika i v odpudivém.", - "Flanér – chodec městem, pozorovatel.", - "Synestézie – smysly se prolínají (hudba–barva).", - "Cyklus básní – tematické celky ve sbírce." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Květy zla?", "options": ["Verlaine", "Charles Baudelaire", "Rimbaud", "Hugo"], "correct": 1, "expl": "Baudelaire vydal sbírku v roce 1857."}, - {"prompt": "Proč byla sbírka senzační i soudní?", "options": ["Byla příliš krátká", "Obvinění z nemravnosti a obscénnosti", "Byla v latině", "Nebyla publikována"], "correct": 1, "expl": "Soud přispěl k slávě sbírky."}, - {"prompt": "Co znamená „spleen“ u Baudelaira?", "options": ["Radost", "Melancholie, nuda, existenciální tíha", "Hlad", "Válka"], "correct": 1, "expl": "Spleen je klíčový motiv moderní duše."}, - {"prompt": "Jaký je vztah krásy a zla v titulu?", "options": ["Zlo je ošklivé vždy", "Krása může vyrůstat i z hříchu a temnoty", "Titul nemá význam", "Jde o zahradnictví"], "correct": 1, "expl": "Baudelaire estetizuje i temné stránky života."}, - {"prompt": "Kdo je flanér?", "options": ["Voják", "Pozorovatel města, chodec moderní metropole", "Kněz", "Král"], "correct": 1, "expl": "Flanér prochází Paříží a sbírá dojmy."}, - {"prompt": "Co symbolizuje báseň Albatros?", "options": ["Sport", "Umělce na souši – nemohoucího mimo svůj živel", "Válku", "Jídlo"], "correct": 1, "expl": "Albatros na palubě je groteskní; ve vzduchu krásný."}, - {"prompt": "Jaký žánr sbírka reprezentuje?", "options": ["Epos", "Moderní lyrická poezie / symbolism", "Drama", "Román"], "correct": 1, "expl": "Květy zla jsou vrchol francouzské moderny."}, - {"prompt": "Kde se básně nejčastěji odehrávají?", "options": ["Venkov bez města", "Moderní město, ulice, vnitřní svět", "Vesmír", "Středověký hrad"], "correct": 1, "expl": "Paříž a psychika jsou dvě scény."}, - {"prompt": "Co je synestézie v poezii?", "options": ["Gramatická chyba", "Propojení smyslů v obrazech", "Rým bez významu", "Proza"], "correct": 1, "expl": "Baudelaire slučuje barvy, vůně a zvuky."}, - {"prompt": "Proč maturita zahrnuje Květy zla?", "options": ["Nejdelší román", "Základ moderní poezie a symbolu", "Bez významu", "Jen historie"], "correct": 1, "expl": "Učí číst symbol a moderní lyriku."}, - {"prompt": "Jak Baudelaire vnímá ženu v cyklech?", "options": ["Jen idealizace", "Směs touhy, bolesti, hříchu a krásy", "Bez zmínky", "Pouze matka"], "correct": 1, "expl": "Ženské figury jsou složité symboly."}, - {"prompt": "Co je démonismus?", "options": ["Náboženská oslava", "Přitažlivost zla a temných sil", "Věda", "Sport"], "correct": 1, "expl": "Baudelaire zkoumá pokušení a hřích."}, - {"prompt": "Který básník patří ke stejné tradici?", "options": ["Homér", "Verlaine, Mallarmé (symbolisté)", "Hašek", "Rais"], "correct": 1, "expl": "Baudelaire předchází francouzský symbolism."}, - {"prompt": "Co znamená cyklus ve sbírce?", "options": ["Náhodný soubor", "Tematicky spojené básně (Spleen, Víno…)", "Jeden epos", "Drama"], "correct": 1, "expl": "Sbírka má vnitřní strukturu."}, - {"prompt": "Jaký je vztah k náboženství?", "options": ["Jednoduchá víra", "Pochybnost, konflikt víry a hříchu", "Bez tématu", "Pouze modlitby"], "correct": 1, "expl": "Moderní krize víry prostupuje lyrikou."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Spleen", "Město", "Vesmírné operace", "Smyslnost"], "correct": 2, "expl": "Baudelaire píše o moderním člověku, ne sci-fi."}, - {"prompt": "Co je „krása v modernitě“?", "options": ["Jen antické ideály", "Hledání estetického i v odpudivém a obyčejném", "Odmítání umění", "Pouze příroda"], "correct": 1, "expl": "Baudelaire reformuluje estetiku 19. století."}, - {"prompt": "Jak sbírka ovlivnila Evropu?", "options": ["Vůbec", "Vzor pro symbolismus a moderní poezii", "Zakázala poezii", "Jen Francii bez vlivu"], "correct": 1, "expl": "Vliv na Mallarmého, Verlaine, i českou modernu."}, - {"prompt": "Co je báseň Holka s košíkem?", "options": ["Politický manifest", "Obraz mladé dělnice – krása v prostém", "Epos", "Vtip"], "correct": 1, "expl": "Typický baudelaireovský obraz moderního města."}, - {"prompt": "Jaký jazyk básně používají?", "options": ["Pouze archaismy", "Hutné obrazy, rytmus, symbol", "Úřední styl", "Bez metafor"], "correct": 1, "expl": "Jazyk je koncentrovaný a obrazný."}, - {"prompt": "Proč „květy“ a „zlo“ v titulu?", "options": ["Paradox krásy v hříchu a temnotě", "Zahradnický katalog", "Náhodný název", "Jméno postavy"], "correct": 0, "expl": "Titul shrnuje estetiku sbírky."}, - {"prompt": "Kdy Baudelaire žil?", "options": ["1821–1867", "1900–1950", "1600–1650", "1990–2020"], "correct": 0, "expl": "Patří k druhé polovině 19. století."}, - {"prompt": "Co čtenář cítí u motivu smrti?", "options": ["Nic", "Tíhu, tajemství, někdy i krásu", "Pouze smích", "Sport"], "correct": 1, "expl": "Smrt je častý lyrický motiv."}, - {"prompt": "Jak číst symbol ve sbírce?", "options": ["Jen doslovně", "Obraz má víc vrstev (city, společnost, víra)", "Ignorovat", "Jako matematiku"], "correct": 1, "expl": "Symbolismus vyžaduje interpretaci."}, - {"prompt": "Co je moderní metropole pro Baudelaira?", "options": ["Ráj", "Prostor anonymity, vzrušení i spleenu", "Venkov", "Klášter"], "correct": 1, "expl": "Město formuje moderní vnímání."}, - {"prompt": "Jaký vztah má sbírka k umění?", "options": ["Umění není téma", "Básně o tvorbě, umělci, albatrosovi", "Jen malířství bez poezie", "Zákaz umění"], "correct": 1, "expl": "Reflexe umění je součástí cyklu."}, - {"prompt": "Proč byl soud důležitý?", "options": ["Zničil básníka", "Přitáhl pozornost k nové estetice", "Bez efektu", "Vynesl trest smrti"], "correct": 1, "expl": "Skandál pomohl prosadit moderní poezii."}, - {"prompt": "Co NENÍ charakteristika Květů zla?", "options": ["Symbol", "Spleen", "Realistický venkovský román bez poezie", "Město"], "correct": 2, "expl": "Jde o lyrickou sbírku, ne prózu."}, - {"prompt": "Jak Baudelaire pracuje s vínem?", "options": ["Cyklus Víno – únik, inspirace, iluze", "Nezmiňuje", "Pouze reklama", "Jako jediné téma"], "correct": 0, "expl": "Víno je symbol i v cyklech sbírky."}, - {"prompt": "Jaké poselství sbírka má pro čtenáře?", "options": ["Moderní člověk prožívá krásu i temnotu současně", "Poezie je zbytečná", "Vraťte se do středověku", "Jen morální poučka"], "correct": 0, "expl": "Květy zla otevírají moderní vnímání světa."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Baudelaire sbírá básně moderního města a duše", - "Vydání 1857 a skandál soudní", - "Cyklus Spleen vyjadřuje melancholii", - "Obrazy žen, umění a démonismu", - "Symbol krásy v temnotě (Květy zla)", - "Trvalý vliv na symbolismus a moderní poezii" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: tvorba sbírky → skandál → spleen a cykly → témata → estetika titulu → literární odkaz." - ] -} diff --git a/data/cetba/kytice.json b/data/cetba/kytice.json deleted file mode 100644 index b3e8951..0000000 --- a/data/cetba/kytice.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Jaromír Erben (1811–1870)", - "Žánr: baladická sbírka, lidová epika v básnické formě", - "Poprvé vydáno: 1853 (druhé, rozšířené vydání)", - "Děj / prostředí: česká krajina, lidové pověsti a mýty", - "Vyprávění / forma: balady ve slavném verši, morální poučka" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Romantismus a národní obrození: sběr lidové slovesnosti.", - "Erben převyprávěl pověsti s jednotnou morální a estetickou vizí.", - "Motivy: vina, trest, mateřství, smrt, příroda, křesťanská etika.", - "Prolínání reality a nadpřirozena (polednice, vodníci, liška Bystrouška).", - "Jazyk je hudební, rytmický, s refrénem a dialogy.", - "Kytice je vrcholem české baladické tradice." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Postavy z balad – matky, děti, milenci, královny (Vrba, Polednice…).", - "Vodník – děsivý pán vod, bere děti i dospělé.", - "Liška Bystrouška – chytrá, v baladě Svatební košile vítězí.", - "Karel a děti – Kytice obsahuje tragické rodinné osudy.", - "Polednice – trestá děti na poli v poledne.", - "Morana – personifikace smrti/zimy v baladě." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Balada – dramatický děj, tragický konec, poučka.", - "Lidová slovesnost – Erben přetváří lidové pověsti.", - "Motivem viny a odplaty – často porušení zákazu.", - "Nadpřirozeno – vodníci, polednice, kouzla.", - "Morální poučka – závěrečné poučení čtenáři.", - "Slavný verš – rytmus a refrény (např. Vrbo, rosteš…)." - ] - } - ], - "quiz": [ - {"prompt": "Kdo sestavil Kytici?", "options": ["Neruda", "Karel Jaromír Erben", "Nezval", "Vrchlický"], "correct": 1, "expl": "Erben vydal sbírku balad v polovině 19. století."}, - {"prompt": "Jaký žánr Kytice reprezentuje?", "options": ["Román", "Baladická sbírka", "Drama", "Encyklopedie"], "correct": 1, "expl": "Jednotlivé balady jsou samostatné příběhy."}, - {"prompt": "Co je typické pro baladu?", "options": ["Dlouhý klidný popis", "Dramatický děj, tragédie, morální poučka", "Sci-fi", "Bez rýmu"], "correct": 1, "expl": "Balada má napětí a často krutý konec."}, - {"prompt": "O čem je balada Vodník?", "options": ["O rybáři bez děje", "O vodníkovi, který bere lidi do vody", "O válce", "O Praze"], "correct": 1, "expl": "Vodník je klasická postava lidové pověry."}, - {"prompt": "Co dělá Polednice?", "options": ["Vaří oběd", "Trestá děti, které jsou na poli v poledne", "Učí v škole", "Staví most"], "correct": 1, "expl": "Balada Polednice varuje před poledním horkem a neposlušností."}, - {"prompt": "Která balada obsahuje lišku Bystroušku?", "options": ["Vrba", "Svatební košile", "Morana", "Lilie"], "correct": 1, "expl": "Liška pomáhá proti vodníkovi v této baladě."}, - {"prompt": "Co je morální poučka?", "options": ["Závěrečné poučení pro čtenáře", "Titul knihy", "Jméno postavy", "Refrén bez smyslu"], "correct": 0, "expl": "Erben často uzavírá baladu poučkou."}, - {"prompt": "Proč Erben upravoval lidové pověsti?", "options": ["Náhodně", "Sjednotil je poeticky a morálně pro sbírku", "Z ničil", "Přeložil z angličtiny"], "correct": 1, "expl": "Erben je umělecky přetvořil, ne jen zapsal."}, - {"prompt": "Jaký verš je typický?", "options": ["Slavný verš s rytmem a refrénem", "Proza", "Blank verse anglicky", "Bez verše"], "correct": 0, "expl": "Hudebnost jazyka je charakteristická."}, - {"prompt": "O čem je balada Vrba?", "options": ["O matce a dětech u vrbového proutí", "O králi", "O vesmíru", "O sportu"], "correct": 0, "expl": "Vrba je známá refrénovitá balada o rodině."}, - {"prompt": "Kdy vyšla Kytice poprvé v podstatě v dnešní podobě?", "options": ["1853", "2000", "1700", "1920"], "correct": 0, "expl": "Druhé vydání 1853 obsahuje většinu balad."}, - {"prompt": "Jaký literární směr Erben reprezentuje?", "options": ["Realismus bez romantismu", "Romantismus a národní obrození", "Sci-fi", "Postmoderna"], "correct": 1, "expl": "Erben navazuje na lidovou tradici v romantické poezii."}, - {"prompt": "Co je nadpřirozeno v Kytici?", "options": ["Nic", "Vodníci, polednice, kouzla, smrt personifikovaná", "Jen technologie", "Vesmír"], "correct": 1, "expl": "Lidová víra prostupuje baladami."}, - {"prompt": "Proč maturita zahrnuje Kytici?", "options": ["Nejdelší román", "Základ české balady a lidové tradice", "Bez významu", "Jen anglicky"], "correct": 1, "expl": "Učí baladu, verš a interpretaci lidových motivů."}, - {"prompt": "Co je balada Morana?", "options": ["O jarní bohyni smrti/zimy", "O autu", "O Praze", "O škole"], "correct": 0, "expl": "Morana je personifikace konce zimy / smrti."}, - {"prompt": "Jak Erben pracuje s přírodou?", "options": ["Ignoruje", "Příroda je živá, symbolická, někdy hrozící", "Jen město", "Bez obrazů"], "correct": 1, "expl": "Krajina je součástí děsu i krásy."}, - {"prompt": "Které téma se opakuje?", "options": ["Vina a trest", "Vesmírné lety", "Politika 21. století", "Sport"], "correct": 0, "expl": "Porušení zákazu často vede k tragédii."}, - {"prompt": "Co je balada Lilie?", "options": ["Milostná idyla bez smrti", "Příběh s motivem hřbitova a mrtvých", "Komická hra", "Epos"], "correct": 1, "expl": "Lilie patří k temnějším baladám sbírky."}, - {"prompt": "Kdo je Erben mimo Kytice?", "options": ["Sběratel lidových písní, historik, publicista", "Jen malíř", "Politik bez literatury", "Cizinec"], "correct": 0, "expl": "Erben byl významná osobnost obrození."}, - {"prompt": "Jaký kontrast tvoří Svatební košile?", "options": ["Vodník vs. chytrá liška", "Bohatí vs. chudí bez děje", "Válka vs. mír", "Praha vs. Brno"], "correct": 0, "expl": "Liška Bystrouška přechytračí vodníka."}, - {"prompt": "Co znamená refrén ve Vrbě?", "options": ["Opakování zvyšuje napětí a hudebnost", "Chyba tisku", "Anglický text", "Bez významu"], "correct": 0, "expl": "Refrén je součást baladické formy."}, - {"prompt": "Který prvek NENÍ typický?", "options": ["Tragický konec", "Poučka", "Vesmírná opera", "Nadpřirozeno"], "correct": 2, "expl": "Kytice je lidová a krajinná poezie."}, - {"prompt": "Jak číst baladu Zlatý kolovrat?", "options": ["Jako pohádku bez násilí", "Tragický příběh s trestem za zločin", "Sci-fi", "Reportáž"], "correct": 1, "expl": "Balada obsahuje kruté motivy lidové pověsti."}, - {"prompt": "Co spojuje Kytici s národním obrozením?", "options": ["Cizí jazyk", "České motivy, identita, lidová tradice", "Bez národního významu", "Pouze němčina"], "correct": 1, "expl": "Sbírka je kulturním symbolem národa."}, - {"prompt": "Jak Erben uzavírá balady?", "options": ["Bez závěru", "Morální poučkou nebo pointou", "Reklamou", "Anglicky"], "correct": 1, "expl": "Poučka vysvětluje etický význam."}, - {"prompt": "Co je balada Holoubek?", "options": ["Milostná píseň s tragickým rozměrem", "Učebnice", "Román", "Fejeton"], "correct": 0, "expl": "Holoubek patří k známým baladám Kytice."}, - {"prompt": "Jaký vztah má dítě k dospělým v baladách?", "options": ["Vždy poslušné bez děje", "Neposlušnost často vede k trestu", "Bez dětí", "Jen komedie"], "correct": 1, "expl": "Varování rodičům a dětem je časté."}, - {"prompt": "Proč jsou balady stále živé?", "options": ["Univerzální motivy strachu, viny, lásky", "Zastaralé", "Nečitelné", "Bez jazyka"], "correct": 0, "expl": "Erbenova forma je nadčasová."}, - {"prompt": "Co je slavný verš?", "options": ["Rytmická forma vhodná pro recitaci a píseň", "Prozaický odstavec", "Anglický sonet", "Bez rytmu"], "correct": 0, "expl": "Verš podporuje hudebnost Kytice."}, - {"prompt": "Jaké poselství Kytice často nese?", "options": ["Respektuj zákony přírody a morálky, jinak hrozí trest", "Vše je dovoleno", "Pouze humor", "Bez etiky"], "correct": 0, "expl": "Balady varují před pýchou, neposlušností a zlem."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Erben sbírá a upravuje lidové pověsti", - "Skládá balady do sbírky Kytice", - "Postavy poruší zákaz nebo pád do hříchu", - "Nadpřirozeno nebo osud trestá viníky", - "Tragický konec balady", - "Morální poučka pro čtenáře" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: inspirace lidovou tradicí → sbírka → vina → trest → tragédie → poučka (typická struktura erbenovské balady)." - ] -} diff --git a/data/cetba/lakomec.json b/data/cetba/lakomec.json deleted file mode 100644 index 3b3c514..0000000 --- a/data/cetba/lakomec.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Molière (Jean-Baptiste Poquelin, 1622–1673)", - "Žánr: divadelní komedie (komedie charakterů)", - "Poprvé vydáno / uvedeno: 1668", - "Děj / prostředí: pařížská měšťanská domácnost 17. století", - "Vyprávění / forma: drama, pětiaktová komedie, rýmovaná próza" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Klasicismus: pravidla jednoty, jasné typy postav, satira mravů.", - "Molière kritizuje lakotu, pokrytectví a měšťanskou chamtivost.", - "Harapagon je extrémní typ – komedie charakterů.", - "Rodina vs. otec: děti chtějí lásku, otec šetří i na štěstí.", - "Komedie končí happy endem – typické pro Molièra.", - "Hra je stále nejhranější francouzskou komedií." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Harapagon – lakomec, otec, posedlý penězi.", - "Elise – Harapagonova dcera, miluje Valéra.", - "Cléante – Harapagonův syn, miluje Marianu.", - "Valér – sluha, miluje Elise, chytrý manipulátor.", - "Marianna – mladá dívka, objekt Harapagonových i Cléantových sňatků.", - "Frosina – matchmaker, využívá Harapagonovu lakotu." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Komedie charakterů – jedna dominantní vlastnost (lakota).", - "Satira – výsměch mravům a společnosti.", - "Truhla s pokladem – Harapagonova posedlost.", - "Sňatky za peníze – konflikt generací.", - "Happy end – odhalení, smíření, svatby.", - "Valérova lst – sluha jako komický intrikán." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Lakomce?", "options": ["Racine", "Molière", "Corneille", "Hugo"], "correct": 1, "expl": "Molière uvedl hru v roce 1668."}, - {"prompt": "Jaký typ komedie to je?", "options": ["Komedie charakterů", "Tragedie", "Opera", "Epos"], "correct": 0, "expl": "Harapagon ztělesňuje extrémní lakotu."}, - {"prompt": "Kdo je Harapagon?", "options": ["Král", "Lakomý otec posedlý penězi", "Voják", "Kněz"], "correct": 1, "expl": "Titulní postava je synonymem pro lakotu."}, - {"prompt": "Co Harapagon nejvíc miluje?", "options": ["Děti", "Truhlu s penězi", "Umění", "Přírodu"], "correct": 1, "expl": "Peníze jsou nad rodinou i láskou."}, - {"prompt": "Koho miluje Elise?", "options": ["Harapagona", "Valéra", "Cléanta", "Marianu"], "correct": 1, "expl": "Valér je sluha, ale i milenec Elise."}, - {"prompt": "Koho miluje Cléante?", "options": ["Frosinu", "Marianu", "Elise", "Harapagona"], "correct": 1, "expl": "Syn chce sňatek s Marianou."}, - {"prompt": "Co Harapagon plánuje s Marianou?", "options": ["Oženit se s ní sám", "Poslat ji do kláštera", "Prodat dům", "Nic"], "correct": 0, "expl": "Starý lakomec chce mladou manželku."}, - {"prompt": "Kdo je Frosina?", "options": ["Služka", "Prostřednice sňatků využívající lakotu", "Královna", "Dcera"], "correct": 1, "expl": "Frosina manipuluje Harapagonem."}, - {"prompt": "Co se stane s truhlou?", "options": ["Zmizí", "Harapagon ji ztratí, pak ji najdou – vrchol komiky", "Spálí ji", "Dá ji chudým"], "correct": 1, "expl": "Scéna s ukradenou truhlou je slavná."}, - {"prompt": "Jak hra končí?", "options": ["Tragedií", "Happy endem – svatby, návrat peněz", "Harapagon umírá", "Válka"], "correct": 1, "expl": "Molièrovy komedie často končí smířením."}, - {"prompt": "Jaký je Valér?", "options": ["Hloupý sluha", "Chytrý, lstivý milenec Elise", "Král v převleku", "Harapagonův bratr"], "correct": 1, "expl": "Valér ovládá situaci v domě."}, - {"prompt": "Proč maturita zahrnuje Lakomce?", "options": ["Nejdelší román", "Klasická komedie, satira, drama", "Bez děje", "Sci-fi"], "correct": 1, "expl": "Učí strukturu komedie a charakterového typu."}, - {"prompt": "Kdy Molière žil?", "options": ["17. století", "19. století", "Antika", "21. století"], "correct": 0, "expl": "Molière působil za Ludvíka XIV."}, - {"prompt": "Co satira kritizuje?", "options": ["Lakotu a měšťanské mravy", "Vesmír", "Sport", "Pouze krále"], "correct": 0, "expl": "Harapagon je groteskní exemplum lakotce."}, - {"prompt": "Kolik aktů má hra?", "options": ["Pět", "Jeden", "Deset", "Dva"], "correct": 0, "expl": "Klasická pětaktová struktura."}, - {"prompt": "Které téma NENÍ středem?", "options": ["Peníze vs. láska", "Sňatky dětí", "Vesmírná válka", "Rodinný konflikt"], "correct": 2, "expl": "Hra je komedie o měšťanské domácnosti."}, - {"prompt": "Co Harapagon šetří?", "options": ["Na vše – jídlo, svatbu, štěstí dětí", "Nic", "Jen na knihy", "Jen na krále"], "correct": 0, "expl": "Lakota proniká celým životem."}, - {"prompt": "Jak funguje komedie charakterů?", "options": ["Postava má jednu přehnanou vlastnost", "Bez postav", "Jen akce", "Tragedie"], "correct": 0, "expl": "Harapagon = lakota v extrému."}, - {"prompt": "Kdo ukradne truhlu (v ději)?", "options": ["Harapagon sám ji „ztratí“ – komplikovaná intrika", "Král", "Marianna", "Nikdo"], "correct": 0, "expl": "Ztráta pokladu vyvolá groteskní scénu."}, - {"prompt": "Jaký jazyk hra používá?", "options": ["Rýmovaná próza (veršovaná próza)", "Pouze proza", "Latin", "Bez textu"], "correct": 0, "expl": "Molière používá alexandríny v próze."}, - {"prompt": "Co chtějí děti od otce?", "options": ["Pouze peníze", "Svolení ke sňatkům z lásky", "Vypovězení", "Trůn"], "correct": 1, "expl": "Generační konflikt je motor děje."}, - {"prompt": "Kdo je Anselme na konci?", "options": ["Postava odhalená jako Valérova rodina – řeší sňatky", "Vrah", "Cizinec bez role", "Harapagon"], "correct": 0, "expl": "Zápletky se rozuzlí identitou Anselma."}, - {"prompt": "Proč je Lakomec stále populární?", "options": ["Univerzální humor a typ lakotce", "Zastaralý", "Bez humoru", "Jen ve Francii"], "correct": 0, "expl": "Chamtivost je věčné téma."}, - {"prompt": "Jak Molière pracuje s happy endem?", "options": ["Vše se vyřeší sňatky a smířením", "Všichni umřou", "Bez závěru", "Válka"], "correct": 0, "expl": "Klasická komická katarze."}, - {"prompt": "Co je matchmaker Frosina?", "options": ["Prostřednice sňatků", "Voják", "Lakomec", "Král"], "correct": 0, "expl": "Využívá Harapagonovy touhy."}, - {"prompt": "Jaký kontrast tvoří jádro hry?", "options": ["Láska mladých vs. lakota starého otce", "Moře vs. hory", "Válka vs. mír bez rodiny", "Praha vs. Brno"], "correct": 0, "expl": "Peníze vs. city je hlavní osa."}, - {"prompt": "Kde se děj odehrává?", "options": ["Paříž, měšťanský dům", "Venkov bez domu", "Londýn", "Praha"], "correct": 0, "expl": "Měšťanské prostředí 17. století."}, - {"prompt": "Co Harapagon odmítá platit?", "options": ["Vše možné – i sluhy, hostinu, svatbu", "Nic", "Jen daně", "Jen králi"], "correct": 0, "expl": "Šetří na každém kroku."}, - {"prompt": "Jaké poselství hra nese?", "options": ["Lakota ničí rodinu i štěstí", "Šetři vždy", "Peníze jsou vše", "Bez morálky"], "correct": 0, "expl": "Satira varuje před extrémní chamtivostí."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Harapagon vládne domu lakotou", - "Děti chtějí sňatky z lásky", - "Harapagon touží po Marianně a penězích", - "Ztráta truhly a komické pátrání", - "Odhalení identit a intrik (Valér, Anselme)", - "Happy end – svatby a smíření" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: lakota otce → konflikt s dětmi → Harapagon a Marianna → truhla → rozuzlení → svatby." - ] -} diff --git a/data/cetba/lolita.json b/data/cetba/lolita.json deleted file mode 100644 index 62412bd..0000000 --- a/data/cetba/lolita.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Vladimir Nabokov (1899–1977), rusko-americký spisovatel", - "Žánr: moderní román, kontroverzní próza", - "Poprvé vydáno: 1955 (Paříž, Olympia Press)", - "Děj / prostředí: USA 40.–50. léta, cesty po amerických silnicích", - "Vyprávění / forma: ich-forma, Humbertův deník / vzpomínka" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Román je psán jako Humbertův „svědectví“ – nespolehlivý vypravěč.", - "Lolita (Dolores Haze) je dívka; Humbert je dospělý s obsesí.", - "Kniha vyvolala skandál – etika, cenzura, interpretace.", - "Nabokov pracuje s jazykem, ironií, literárními aluzemi.", - "Road movie struktura – pronásledování, Quilty, útěk.", - "Tragický konec – Lolita umírá, Humbert vězí." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Humbert Humbert – vypravěč, intelektuál, pedofilní obsese.", - "Dolores Haze (Lolita) – dívka, oběť manipulace.", - "Charlotte Haze – Lolitiná matka, Humbert si ji chce vzít.", - "Clare Quilty – spisovatel, stínový protihráč, únos Lolity.", - "Annabel Leigh – Humbertova dětská láska (motiv vzpomínky).", - "Rita – žena po Lolité na cestách." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Nespolehlivý vypravěč – Humbert ospravedlňuje sebe.", - "Obsese a manipulace – moc dospělého nad dítětem.", - "Estetizace jazyka vs. morální hrůza – Nabokovova ironie.", - "Road novel – cesty po Americe.", - "Citace Poe, literatura – intertext.", - "Etická kontroverze – čtení jako demaskace, ne oslava." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Lolitu?", "options": ["Kafka", "Vladimir Nabokov", "Orwell", "Hemingway"], "correct": 1, "expl": "Nabokov román dokončil v americkém exilu."}, - {"prompt": "Kdo vypráví příběh?", "options": ["Lolita", "Humbert Humbert", "Quilty", "Charlotte"], "correct": 1, "expl": "Humbert píše svou verzi pro soudní proces."}, - {"prompt": "Jak se jmenuje dívka a její přezdívka?", "options": ["Dolores Haze – Lolita", "Jane Eyre", "Maria", "Anna Karenina"], "correct": 0, "expl": "Lolita je Humbertova přezdívka pro Dolores."}, - {"prompt": "Kde Humbert poprvé potká Lolitu?", "options": ["V Ramsdale u Hazových", "V Paříži", "V Rusku", "V Londýně"], "correct": 0, "expl": "Humbert bydlí u rodiny Haze."}, - {"prompt": "Co udělá Humbert s Charlotte?", "options": ["Ožení se s ní, aby byl blízko Lolité", "Zabije ji hned", "Ignoruje", "Prodá dům"], "correct": 0, "expl": "Sňatek je součást manipulace."}, - {"prompt": "Jak Charlotte umírá?", "options": ["Autonehoda po odhalení Humbertových dopisů", "Stářím", "Válka", "Quilty"], "correct": 0, "expl": "Charlotte běží před autem po bouřce."}, - {"prompt": "Kdo je Clare Quilty?", "options": ["Policista", "Spisovatel, stínový rival, únosce", "Lolitin otec", "Humbertův bratr"], "correct": 1, "expl": "Quilty pronásleduje pár a Lolitu si vezme."}, - {"prompt": "Jaký je vztah Humbert–Lolita?", "options": ["Rovnocenná láska", "Manipulace dospělého a oběť", "Otcovský bez problému", "Sourozenci"], "correct": 1, "expl": "Román demaskuje Humbertovu rétoriku."}, - {"prompt": "Proč je Humbert nespolehlivý vypravěč?", "options": ["Lže a estetizuje zločin", "Mluví pravdu vždy", "Nemluví", "Je dítě"], "correct": 0, "expl": "Čtenář musí číst proti vypravěči."}, - {"prompt": "Jak končí Lolita?", "options": ["Šťastně s Humbertem", "Dolores umírá po těžkém životě; Humbert zabije Quiltyho", "Quilty vyhrává svatbou", "Všichni se smíří"], "correct": 1, "expl": "Tragický konec oběti i vypravěče."}, - {"prompt": "Kdy román vyšel?", "options": ["1955", "1847", "2000", "1914"], "correct": 0, "expl": "První vydání v Paříži u Olympia Press."}, - {"prompt": "Jaký žánr román reprezentuje?", "options": ["Moderní/controverzní román, road novel", "Pohádka", "Epos", "Učebnice"], "correct": 0, "expl": "Spojuje cestu, psychologii a jazykovou hru."}, - {"prompt": "Co je Annabel Leigh?", "options": ["Humbertova dětská láska (aluzce na Poe)", "Lolitiná sestra", "Quiltyho manželka", "Auto"], "correct": 0, "expl": "Motiv ztracené dětské lásky vysvětluje obsesi."}, - {"prompt": "Proč maturita zahrnuje Lolitu?", "options": ["Bez kontroverze", "Moderní próza, vypravěč, etika čtení", "Nejkratší", "Jen humor"], "correct": 1, "expl": "Učí kriticky číst nespolehlivého vypravěče."}, - {"prompt": "Které téma je středem?", "options": ["Manipulace a moc", "Vesmírná válka", "Venkovský realismus", "Antická tragédie"], "correct": 0, "expl": "Děj staví na Humbertově kontrole nad dívkou."}, - {"prompt": "Jak Nabokov pracuje s jazykem?", "options": ["Chudý styl", "Bohatý, hříčkový, anglicky s wordplay", "Bez stylu", "Pouze česky"], "correct": 1, "expl": "Jazyk je součást estetiky i ironie."}, - {"prompt": "Co NENÍ typické?", "options": ["Cesty po USA", "Skandální téma", "Středověký rytíř", "Quilty"], "correct": 2, "expl": "Děj je moderní americký."}, - {"prompt": "Kdo je Rita?", "options": ["Žena po Lolité na cestách", "Lolita", "Soudkyně", "Učitelka"], "correct": 0, "expl": "Humbert s Ritou cestuje po ztrátě Lolity."}, - {"prompt": "Jak číst román eticky?", "options": ["Oslavovat Humberta", "Vidět oběť a demaskovat vypravěčovu rétoriku", "Ignorovat Lolitu", "Jen disney"], "correct": 1, "expl": "Interpretace zdůrazňuje Dolores, ne romantizaci."}, - {"prompt": "Co Humbert dělá Quiltymu na konci?", "options": ["Odpustí", "Zastřelí ho", "Ožení se s ním", "Ignoruje"], "correct": 1, "expl": "Vrchní scéna je groteskní konfrontace."}, - {"prompt": "Jaký film režíroval Kubrick?", "options": ["Lolita (1962)", "1984", "Barry Lyndon", "Shining"], "correct": 0, "expl": "Kubrick natočil adaptaci v roce 1962."}, - {"prompt": "Co je road novel struktura?", "options": ["Cesty autem po Americe", "Jen jeden dům", "Vesmír", "Antika"], "correct": 0, "expl": "Motel, silnice, útěk před společností."}, - {"prompt": "Proč byl román cenzurován?", "options": ["Obsah pedofilie a morální kontroverze", "Příliš krátký", "Bez jazyka", "V latině"], "correct": 0, "expl": "Mnoho zemí knihu zpočátku odmítlo."}, - {"prompt": "Kdo je obětí v interpretaci?", "options": ["Humbert", "Dolores Haze", "Quilty", "Charlotte"], "correct": 1, "expl": "Moderní čtení zdůrazňuje Lolitu jako oběť."}, - {"prompt": "Co je intertext u Nabokova?", "options": ["Reference na Poe, literaturu", "Bez referencí", "Jen Bible", "Sport"], "correct": 0, "expl": "Annabel Leigh odkazuje na Poeovu báseň."}, - {"prompt": "Jak Humbert ospravedlňuje činy?", "options": ["Krásnou řečí a literárními aluzemi", "Přiznáním viny bez slov", "Mlčením", "Bez slov"], "correct": 0, "expl": "Rétorika je součástí manipulace."}, - {"prompt": "Kde Humbert končí?", "options": ["Ve vězení, píše deník", "Na trůně", "V exilu bohatý", "U Lolity šťastný"], "correct": 0, "expl": "Vyprávění je z vězení před soudem."}, - {"prompt": "Jaký kontrast Nabokov vytváří?", "options": ["Krásný jazyk vs. morálně otřesný obsah", "Bez kontrastu", "Jen humor", "Jen válka"], "correct": 0, "expl": "Estetika vs. etika je klíč interpretace."}, - {"prompt": "Co Dolores dělá po útěku od Humberta?", "options": ["Žije s Quiltym, později těžký osud, manžel Dick", "Stane se královnou", "Vraždí", "Nic"], "correct": 0, "expl": "Lolitain dospělý osud je tragický."}, - {"prompt": "Jaké poselství lze vyčíst při kritickém čtení?", "options": ["Glorifikace zločinu", "Varování před manipulací a nespolehlivým vypravěčem", "Bez významu", "Oslava dětství"], "correct": 1, "expl": "Román je literární, ne morální apologie Humberta."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Humbert přijde do Ramsdale k Hazovým", - "Sňatek s Charlotte; Lolita v jeho moci", - "Charlotteina smrt; cesty s Lolitou", - "Quilty Lolitu odvede", - "Humbert hledá Lolitu; najde ji těhotnou a chudou", - "Zabije Quiltyho; píše deník ve vězení" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: Ramsdale → Charlotte → cesty → Quilty → setkání s Dolores → Quiltyho smrt a deník." - ] -} diff --git a/data/cetba/maj.json b/data/cetba/maj.json deleted file mode 100644 index b6e62e0..0000000 --- a/data/cetba/maj.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Hynek Mácha (1810–1836)", - "Žánr: lyricko-epická skladba, romantická báseň", - "Poprvé vydáno: 1836 (posmrtně)", - "Děj / prostředí: jezero, hrad, krajina kolem Doksy, 19. století", - "Vyprávění / forma: veršovaná skladba, er-forma vypravěče + lyrické vložky" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Český romantismus: cit, příroda, osud, vina, krása a smrt.", - "Máj je vrchol české romantické poezie – hudební, obrazná skladba.", - "Děj: Jarmila se utopí, Vilém vrazí, poprava, vězeň, vandrák.", - "Příroda reaguje na zločin (bouře, hrom) – personifikace.", - "Intertext: Byron, Shelley, slovanský romantismus.", - "Máj jako symbol lásky, jara i smrti." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Vilém – vězeň, vrah otce Jarmiliného, milenec Jarmily.", - "Jarmila – milenka, utopí se v jezeře.", - "Hajný – otec Jarmily, Vilém ho zabil v afektu.", - "Vězeň ve vězení – Vilém, lyrické monology.", - "Vandrák – putující poutník, komentář k osudu.", - "Sbor jeskyň – personifikovaná příroda." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Romantismus – cit, osud, příroda, vina.", - "Lyricko-epická skladba – děj + lyrické pasáže.", - "Máj – symbol jara, lásky, obnovy i smrti.", - "Vina a trest – poprava, vězení.", - "Personifikace přírody – hrom, jezero, kraj.", - "Intercalare – lyrické vložky (např. vězeň, vandrák)." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Máj?", "options": ["Erben", "Karel Hynek Mácha", "Neruda", "Vrchlický"], "correct": 1, "expl": "Mácha dokončil skladbu krátce před smrtí v roce 1836."}, - {"prompt": "Jaký žánr Máj reprezentuje?", "options": ["Realistický román", "Lyricko-epická romantická skladba", "Drama", "Encyklopedie"], "correct": 1, "expl": "Máj je básnické dílo s dějem i lyrickými částmi."}, - {"prompt": "Kdo je Vilém?", "options": ["Král", "Vězeň, milenec Jarmily, zabil jejího otce", "Hajný", "Vandrák"], "correct": 1, "expl": "Vilém je hlavní postava tragického děje."}, - {"prompt": "Co udělá Jarmila?", "options": ["Utíká s Vilémem", "Utopí se v jezeře", "Zabije Viléma", "Stane se královnou"], "correct": 1, "expl": "Jarmila volí smrt po Vilémově zločinu."}, - {"prompt": "Proč Vilém zabil hajného?", "options": ["V afektu – otec Jarmily bránil lásce", "Pro peníze", "Na rozkaz", "Náhodou bez důvodu"], "correct": 0, "expl": "Vilém reaguje na konflikt s otcem milenky."}, - {"prompt": "Jak Vilém končí?", "options": ["Svatba", "Poprava (šibenice)", "Exil", "Trůn"], "correct": 1, "expl": "Trest za vraždu je poprava."}, - {"prompt": "Kdo je vandrák?", "options": ["Putující postava s lyrickými komentáři", "Vilém po útěku", "Hajný", "Bůh"], "correct": 0, "expl": "Vandrák propojuje osudy a přírodu."}, - {"prompt": "Co symbolizuje máj?", "options": ["Jen měsíc", "Jaro, láska, krása, ale i smrt a osud", "Válka", "Město"], "correct": 1, "expl": "Titulní symbol prostupuje skladbou."}, - {"prompt": "Jak příroda reaguje na zločin?", "options": ["Ignoruje", "Bouře, hrom, personifikace", "Slunce bez změny", "Jen sníh"], "correct": 1, "expl": "Romantická personifikace krajiny."}, - {"prompt": "Kdy Máj vyšel?", "options": ["1836", "1850", "2000", "1700"], "correct": 0, "expl": "Posmrtné vydání téhož roku jako Máchaova smrt."}, - {"prompt": "Jaký směr Mácha reprezentuje?", "options": ["Realismus", "Romantismus", "Naturalismus", "Postmoderna"], "correct": 1, "expl": "Máj je vrchol českého romantismu."}, - {"prompt": "Co je intercalare?", "options": ["Lyrická vložka ve skladbě", "Postava", "Kapitola románu", "Refrén bez smyslu"], "correct": 0, "expl": "Vložky vězeň, vandrák přerušují děj."}, - {"prompt": "Kde se děj částečně odehrává?", "options": ["Krajina kolem Doksy a jezera", "Praha bez přírody", "Moře", "Vesmír"], "correct": 0, "expl": "Mácha inspirován krajinou Máchova jezera."}, - {"prompt": "Proč maturita zahrnuje Máj?", "options": ["Nejdelší román", "Základ českého romantismu a verše", "Bez významu", "Proza"], "correct": 1, "expl": "Učí skladbu, symbol a romantické motivy."}, - {"prompt": "Které téma je středem?", "options": ["Láska, vina, trest, smrt", "Sport", "Politika 21. stol.", "Vesmír"], "correct": 0, "expl": "Tragický milostný příběh s trestem."}, - {"prompt": "Kdo je hajný?", "options": ["Otec Jarmily, oběť Viléma", "Vilém", "Vandrák", "Král"], "correct": 0, "expl": "Hajný brání vztahu dcery s Vilémem."}, - {"prompt": "Jak Mácha pracuje s jazykem?", "options": ["Hudební verš, obrazy, personifikace", "Úřední styl", "Proza", "Anglicky"], "correct": 0, "expl": "Skladba je známá rytmem a obrazností."}, - {"prompt": "Co je lyricko-epická skladba?", "options": ["Spojení epického děje a lyrických pasáží", "Jen epos", "Jen epigram", "Drama"], "correct": 0, "expl": "Máj má děj i lyrické monology."}, - {"prompt": "Který prvek NENÍ typický?", "options": ["Příroda", "Osud", "Sci-fi vesmír", "Vina"], "correct": 2, "expl": "Máj je romantická krajina a cit."}, - {"prompt": "Jak končí Jarmila?", "options": ["Šťastně", "Smrt v jezeře", "Svatba s hajným", "Exil"], "correct": 1, "expl": "Tragický konec milenky."}, - {"prompt": "Co vězeň ve vězení dělá?", "options": ["Lyrické úvahy o osudu", "Sport", "Vládne", "Vaří"], "correct": 0, "expl": "Vilém jako vězeň medituje nad životem."}, - {"prompt": "Jaký vliv má Máj na českou literaturu?", "options": ["Ikona romantismu", "Bez vlivu", "Jen pro děti", "Zakázaný"], "correct": 0, "expl": "Nejznámější česká báseň."}, - {"prompt": "Co je sbor jeskyň?", "options": ["Personifikovaná příroda", "Divadlo", "Armáda", "Město"], "correct": 0, "expl": "Romantický obraz přírody."}, - {"prompt": "Kdy Mácha zemřel?", "options": ["1836 (mladý)", "1900", "1950", "2000"], "correct": 0, "expl": "Mácha zemřel velmi mladý."}, - {"prompt": "Jaký kontrast tvoří skladba?", "options": ["Krása máje vs. smrt a trest", "Humor vs. humor", "Město vs. město", "Bez kontrastu"], "correct": 0, "expl": "Láska a krása kontrastují s vraždou a šibenicí."}, - {"prompt": "Co je romantický osud?", "options": ["Postavy nemohou uniknout následkům činů", "Happy end vždy", "Bez děje", "Komický"], "correct": 0, "expl": "Vilém platí za zločin."}, - {"prompt": "Jak číst personifikaci?", "options": ["Příroda odráží city a morálku", "Bez významu", "Jen věda", "Sport"], "correct": 0, "expl": "Krajina je účastníkem děje."}, - {"prompt": "Která postava NENÍ v Máji?", "options": ["Vilém", "Jarmila", "Harapagon", "Vandrák"], "correct": 2, "expl": "Harapagon je Molière."}, - {"prompt": "Jaké poselství skladba nese?", "options": ["Láska a krása jsou křehké; vina má cenu", "Vražda bez následků", "Pouze humor", "Bez etiky"], "correct": 0, "expl": "Romantická tragédie varuje před násilím."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Vilém miluje Jarmilu; konflikt s hajným", - "Vilém zabije hajného", - "Jarmila se utopí v jezeře", - "Vilém je chycen a ve vězení", - "Poprava na šibenici", - "Vandrák a příroda uzavírají meditaci nad osudem" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: láska a konflikt → vražda → Jarmilina smrt → vězení → poprava → lyrický epilog vandrat a přírody." - ] -} diff --git a/data/cetba/maly-princ.json b/data/cetba/maly-princ.json deleted file mode 100644 index 1e03bed..0000000 --- a/data/cetba/maly-princ.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Antoine de Saint-Exupéry (1900–1944), francouzský spisovatel a pilot", - "Žánr: philosophická pohádka / alegorická novela", - "Poprvé vydáno: 1943", - "Děj / prostředí: poušť, asteroid B-612, různé „planetky“", - "Vyprávění / forma: ich-forma pilota, ilustrace autora" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Vznik za 2. světové války – téma smyslu, přátelství, odpovědnosti.", - "Malý princ cestuje planetami – satira dospělých (král, vain man, geographer).", - "Liška učí: „Ochoč si mě a budeš jedinečný.“", - "Růže na asteroidu – láska a odpovědnost.", - "Had a návrat – tajemství smrti / odchodu.", - "Kniha je nejpreloženější francouzskou knihou." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Malý princ – dítě z asteroidu B-612, hledá smysl.", - "Pilot – vypravěč, havaroval v poušti.", - "Růže – náročná, princ ji miluje a opouští.", - "Liška – moudrá, učí vztahy a odpovědnost.", - "Had – symbol odchodu, pomáhá princi.", - "Dospělí na planetách – král, domýšlivec, pijan, lampář, geograf." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "„Co je důležité, oči nevidí.“ – podstata vs. vzhled.", - "Ochočení – vztah dává věcem jedinečnost.", - "Odpovědnost za růži – péče o to, co milujeme.", - "Satira dospělých – prázdné profese a moc.", - "Poušť – setkání pilota a prince.", - "Alegorie – dětská pohádka pro dospělé." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Malého prince?", "options": ["Camus", "Saint-Exupéry", "Sartre", "Proust"], "correct": 1, "expl": "Saint-Exupéry knihu napsal v exilu v USA."}, - {"prompt": "Kdo vypráví příběh?", "options": ["Malý princ sám bez dospělého", "Pilot havarovaný v poušti", "Liška", "Král"], "correct": 1, "expl": "Pilot vzpomíná na setkání s princem."}, - {"prompt": "Odkud Malý princ pochází?", "options": ["Z Paříže", "Z asteroidu B-612", "Z Marsu", "Z Egypta"], "correct": 1, "expl": "Malá planetka s růží a sopkami."}, - {"prompt": "Co učí liška?", "options": ["Letět", "Ochočení a odpovědnost za vztah", "Vařit", "Válku"], "correct": 1, "expl": "Slavná scéna ochočení na Zemi."}, - {"prompt": "Co znamená „co je důležité, oči nevidí“?", "options": ["Vidění je zbytečné", "Podstata věcí je skrytá – láska, vztah", "Jen fyzika", "Bez významu"], "correct": 1, "expl": "Princ chápe po odchodu od lišky."}, - {"prompt": "Proč princ opustil růži?", "options": ["Nerozuměl jí a chtěl poznat svět", "Nenáviděl ji", "Král nařídil", "Bez důvodu"], "correct": 0, "expl": "Růže byla náročná; princ lituje později."}, - {"prompt": "Kdo je lampář?", "options": ["Postava na planetce – absurdita dospělých povinností", "Pilot", "Had", "Vlk"], "correct": 0, "expl": "Lampář zapíná a vypíná lampu – satira."}, - {"prompt": "Kdy kniha vyšla?", "options": ["1943", "1850", "2000", "1789"], "correct": 0, "expl": "Vydání během 2. světové války."}, - {"prompt": "Jaký žánr kniha reprezentuje?", "options": ["Philosophická pohádka / alegorie", "Detektivka", "Epos", "Učebnice"], "correct": 0, "expl": "Děti i dospělí čtou různé vrstvy."}, - {"prompt": "Co dělá had?", "options": ["Pomáhá princi vrátit se (k odchodu)", "Kouše pilota", "Staví most", "Učí matematiku"], "correct": 0, "expl": "Had symbolizuje návrat „domů“."}, - {"prompt": "Proč maturita zahrnuje Malého prince?", "options": ["Nejdelší román", "Alegorie, styl, filosofické otázky", "Bez významu", "Jen pro malé děti"], "correct": 1, "expl": "Učí číst symbol a satiru dospělých."}, - {"prompt": "Kdo ilustroval knihu?", "options": ["Autor sám", "Picasso", "Bez obrázků", "Dalí"], "correct": 0, "expl": "Saint-Exupéry kreslil prince."}, - {"prompt": "Co satirují planety?", "options": ["Dospělé profese a marnost moci", "Pouze děti", "Sport", "Vesmír bez smyslu"], "correct": 0, "expl": "Král, domýšlivec, pijan atd."}, - {"prompt": "Které téma NENÍ středem?", "options": ["Přátelství a smysl", "Odpovědnost", "Vesmírná válka flotil", "Láska k růži"], "correct": 2, "expl": "Kniha není sci-fi o válkách."}, - {"prompt": "Kde se pilot a princ setkají?", "options": ["V poušti po havárii", "V Paříži", "Na lodi", "V lese"], "correct": 0, "expl": "Sahara je místo setkání."}, - {"prompt": "Co je odpovědnost za růži?", "options": ["Péče o to, co jsme si vybrali milovat", "Zahodit růži", "Ignorovat", "Prodat"], "correct": 0, "expl": "Princ pochopí až po lišce."}, - {"prompt": "Jak autor zemřel?", "options": ["Za 2. sv. války jako pilot", "Stářím 2000", "V poušti knihou", "Neznámo"], "correct": 0, "expl": "Saint-Exupéry zmizel při letu 1944."}, - {"prompt": "Co je geograf?", "options": ["Zapisuje řeky, ale nevidí svět", "Pilot", "Princ", "Had"], "correct": 0, "expl": "Další typ dospělého bez zkušenosti."}, - {"prompt": "Jak končí princ?", "options": ["Odchází (had); tělo zmizí, pilot smutní", "Zůstává s pilotem navždy", "Stává se králem", "Vládne Zemi"], "correct": 0, "expl": "Závěr je tajemný a smutný."}, - {"prompt": "Proč je kniha pro dospělé?", "options": ["Alegorie smyslu života", "Pouze obrázky", "Bez textu", "Jen strach"], "correct": 0, "expl": "Filosofické otázky pod povrchem pohádky."}, - {"prompt": "Co je domýšlivec?", "options": ["Postava toužící po obdivu", "Liška", "Růže", "Pilot"], "correct": 0, "expl": "Satira marnivosti."}, - {"prompt": "Jaký jazyk kniha používá?", "options": ["Jednoduchý, poetický, dialogy", "Úřední", "Bez dialogů", "Latin"], "correct": 0, "expl": "Přístupné dětem i hluboké."}, - {"prompt": "Co pilot kreslí?", "options": ["Boa constrictor a beránek (had a krabička)", "Auto", "Mapu", "Nic"], "correct": 0, "expl": "Začátek knihy – kresba beránka v krabici."}, - {"prompt": "Kdo je král?", "options": ["Vládne všemu, ale sám na planetě", "Princ", "Liška", "Had"], "correct": 0, "expl": "Absurdita moci bez poddaných."}, - {"prompt": "Jaký symbol je růže?", "options": ["Láska, křehkost, odpovědnost", "Válka", "Peníze", "Sport"], "correct": 0, "expl": "Princ se učí milovat a pečovat."}, - {"prompt": "Co znamená B-612?", "options": ["Číslo asteroidu prince", "Letadlo", "Kód války", "Město"], "correct": 0, "expl": "Malá planeta je domovem."}, - {"prompt": "Jak číst satiru dospělých?", "options": ["Kritika prázdných rolí a zapomínání na podstatu", "Oslava moci", "Bez významu", "Jen děti"], "correct": 0, "expl": "Princ vidí svět očima dítěte."}, - {"prompt": "Proč je liška důležitá?", "options": ["Učí vztah a jedinečnost", "Zabíjí prince", "Bez role", "Pilot"], "correct": 0, "expl": "Klíčová scéna ochočení."}, - {"prompt": "Jaké poselství kniha nese?", "options": ["Hledej smysl, pečuj o vztazích, nejeď jen na vzhled", "Moc je vše", "Dospělí jsou vždy moudří", "Bez morálky"], "correct": 0, "expl": "Pohádka pro reflexi života."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Pilot havaruje v poušti", - "Setkání s Malým princem z B-612", - "Princ vypráví o růži a cestách mezi planetami", - "Na Zemi potká lišku a pochopí ochočení", - "Návrat k pilotovi; odpovědnost za růži", - "Princ odchází s hadem; pilot postrádá přítele" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: havárie → setkání → planety a růže → liška → poušť → odchod prince." - ] -} diff --git a/data/cetba/marysa.json b/data/cetba/marysa.json deleted file mode 100644 index 30b01c2..0000000 --- a/data/cetba/marysa.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Alois a Vilém Mrštíkové (1854–1932 / 1863–1912)", - "Žánr: realistické drama, venkovská tragédie", - "Poprvé vydáno / uvedeno: 1894", - "Děj / prostředí: moravský venkov, hospoda, dvorec", - "Vyprávění / forma: divadelní hra, dialogy, venkovská mluva" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Konec 19. století: venkov, společenské poměry, soudní proces.", - "Maryša – mladá vdova, týraná tchyní a okolím.", - "Láska k Filipovi kontrastuje s tlakem na sňatek s Vávrou.", - "Realistické drama bez patosu – sociální a morální konflikt.", - "Proces s Maryšou – oběť systému a pomluv.", - "Mrštíkové patří k vrcholu české realistické dramaturgie." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Maryša – mladá vdova, statečná, oběť pomluv a tchyně.", - "Filip – milenec Maryši, sedlák.", - "Vávra – bohatý sedlák, touží po Maryši a statku.", - "Maryšina tchyně – krutá, panovačná, ničí snahu vdovy.", - "Metoděj – kněz, morální autorita.", - "Sedláci a vesnice – soud a společenský tlak." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Realistické drama – všední konflikt bez idealizace.", - "Vdovství a majetek – ekonomický tlak na Maryšu.", - "Pomluva a soud – společenské odsouzení.", - "Venkovská mluva – autenticita dialogů.", - "Generační a rodinný útlak – tchyně.", - "Tragédie oběti – Maryša prohrává s systémem." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Maryšu?", "options": ["Čapek", "Alois a Vilém Mrštíkové", "Nemcová", "Hašek"], "correct": 1, "expl": "Bratři Mrštíkové uvedli hru v roce 1894."}, - {"prompt": "Jaký žánr Maryša reprezentuje?", "options": ["Realistické drama", "Opera", "Epos", "Sci-fi"], "correct": 0, "expl": "Hra je dialogová venkovská tragédie."}, - {"prompt": "Kdo je Maryša?", "options": ["Mladá vdova na venkově", "Královna", "Učitelka", "Voják"], "correct": 0, "expl": "Titulní hrdinka je v konfliktu s okolím."}, - {"prompt": "Koho miluje Maryša?", "options": ["Vávru", "Filipa", "Metoděje", "Tchyni"], "correct": 1, "expl": "Filip je její milenec."}, - {"prompt": "Kdo chce Maryšu za ženu?", "options": ["Filip", "Vávra – bohatý sedlák", "Kněz", "Soudce"], "correct": 1, "expl": "Vávra touží po ní i po statku."}, - {"prompt": "Kdo Maryšu nejvíc týrá?", "options": ["Filip", "Tchyně", "Metoděj", "Vesnice bez nikoho"], "correct": 1, "expl": "Tchyně je krutá a panovačná."}, - {"prompt": "Co je středem konfliktu?", "options": ["Válka", "Láska, majetek, pomluvy, soud", "Vesmír", "Sport"], "correct": 1, "expl": "Venkovský sociální drama."}, - {"prompt": "Kde se děj odehrává?", "options": ["Moravský venkov", "Praha", "Moře", "Paříž"], "correct": 0, "expl": "Prostředí hospody a dvora."}, - {"prompt": "Jak hra končí?", "options": ["Happy end svatbou", "Tragicky – Maryša je zničena procesem a okolím", "Vávra vítězí šťastně", "Filip král"], "correct": 1, "expl": "Oběť prohrává s pomluvami a systémem."}, - {"prompt": "Kdo je Metoděj?", "options": ["Kněz", "Sedlák Vávra", "Soudce", "Tchyně"], "correct": 0, "expl": "Kněz reprezentuje morální rovinu."}, - {"prompt": "Proč maturita zahrnuje Maryšu?", "options": ["Nejdelší román", "České realistické drama a venkov", "Bez děje", "Komiks"], "correct": 1, "expl": "Učí drama, dialog a sociální kontext."}, - {"prompt": "Co je venkovská mluva?", "options": ["Autentické dialogy moravského venkova", "Anglicky", "Bez dialogů", "Latin"], "correct": 0, "expl": "Mrštíkové pracují s nářečím."}, - {"prompt": "Které téma NENÍ středem?", "options": ["Vdovství", "Pomluva", "Vesmírná flotila", "Majetek"], "correct": 2, "expl": "Hra je realistická venkovská."}, - {"prompt": "Co Vávra představuje?", "options": ["Chudobu", "Bohatství a tlak na sňatek", "Kněze", "Dítě"], "correct": 1, "expl": "Ekonomický motiv sňatku."}, - {"prompt": "Jak Mrštíkové vykreslují vesnici?", "options": ["Realisticky – pomluvy, soud", "Idylicky", "Bez lidí", "Futuristicky"], "correct": 0, "expl": "Společenská kritika venkova."}, - {"prompt": "Kdy hra vznikla?", "options": ["1894", "2000", "1700", "1948"], "correct": 0, "expl": "Konec 19. století."}, - {"prompt": "Co je proces v hře?", "options": ["Soudní líčení s Maryšou", "Sport", "Svatba", "Válka"], "correct": 0, "expl": "Společenské odsouzení vrcholí soudem."}, - {"prompt": "Jaký vztah má Filip k Maryši?", "options": ["Láska, ale slabší než tlak okolí", "Nenávist", "Sourozenec", "Kněz"], "correct": 0, "expl": "Láska nestačí proti systému."}, - {"prompt": "Proč je Maryša obětí?", "options": ["Systém pomluv, tchyně a majetku ji zničí", "Vlastní volba bez tlaku", "Válka", "Magie"], "correct": 0, "expl": "Tragédie bez viny hrdinky."}, - {"prompt": "Co je realistické drama?", "options": ["Každodenní konflikt bez nadpřirozena", "Pohádka", "Epos", "Opera"], "correct": 0, "expl": "Mrštíkové zobrazují reálný venkov."}, - {"prompt": "Kdo jsou autoři – vztah?", "options": ["Bratři", "Otec a syn", "Cizinci", "Jeden autor"], "correct": 0, "expl": "Alois a Vilém Mrštíkové."}, - {"prompt": "Jaký kontrast tvoří jádro?", "options": ["Láska Maryši–Filip vs. tlak Vávry a tchyně", "Moře vs. hory", "Praha vs. Brno", "Humor vs. humor"], "correct": 0, "expl": "Osobní city vs. sociální moc."}, - {"prompt": "Co symbolizuje majetek?", "options": ["Tlak na vdovu", "Nic", "Vesmír", "Sport"], "correct": 0, "expl": "Statky a sňatky řídí osudy."}, - {"prompt": "Jak končí Vávra?", "options": ["Není absolutní vítěz – morálně problematický", "Král", "Emigrace", "Neznámo"], "correct": 0, "expl": "Interpretace ukazuje prázdnotu „vítězství“."}, - {"prompt": "Proč je tchyně důležitá?", "options": ["Zdroj útlaku v domě", "Pomáhá Maryši", "Neobjevuje se", "Královna"], "correct": 0, "expl": "Rodinný tyran."}, - {"prompt": "Jaká je role kněze?", "options": ["Moralita a soud společnosti", "Voják", "Milující", "Soudce sám"], "correct": 0, "expl": "Metoděj komentuje morálku."}, - {"prompt": "Co NENÍ charakteristika hry?", "options": ["Dialog", "Venkov", "Vesmírná opera", "Tragédie"], "correct": 2, "expl": "Maryša je uzavřené venkovské drama."}, - {"prompt": "Jak čtenář vnímá Maryšu?", "options": ["Soucit k oběti", "Opovržení", "Smích", "Nezájem"], "correct": 0, "expl": "Hrdinka evokuje empatii."}, - {"prompt": "Jaké poselství hra nese?", "options": ["Společnost může zničit jedince pomluvou a tlakem", "Venkov je ráj", "Bohatství šťastí", "Bez etiky"], "correct": 0, "expl": "Realistická kritika morálky venkova."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Maryša jako vdova pod tlakem tchyně", - "Láska k Filipovi; Vávra usiluje o sňatek", - "Konflikt na venkově a v hospodě", - "Pomluvy a společenské odsouzení", - "Soudní proces s Maryšou", - "Tragický konec – Maryša prohrává" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: vdovství a útlak → Filip a Vávra → konflikt → pomluvy → soud → tragédie Maryši." - ] -} diff --git a/data/cetba/modlitba-pro-katerinu.json b/data/cetba/modlitba-pro-katerinu.json deleted file mode 100644 index cee93ff..0000000 --- a/data/cetba/modlitba-pro-katerinu.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: František Halas (1901–1949), český básník", - "Žánr: moderní poezie, básnická skladba / cyklus", - "Poprvé vydáno: 1939 (Modlitba pro Katherinu Horovitzovou)", - "Děj / prostředí: 2. světová válka, okupace, koncentrační tábor (motiv)", - "Vyprávění / forma: volný verš, lyrický monolog, reflexe" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Vznik na počátku okupace – strach, útlak, lidská křehkost.", - "Inspirace románem Arnošta Lustiga o Katherině Horovitzové.", - "Halas modlí za oběť i za lidskost uprostřed nelidskosti.", - "Motivy: víra, naděje, bolest, smrt, odpovědnost básníka.", - "Patří k vrcholu české válečné lyriky.", - "Jazyk je intimní, naléhavý, bez patetického klišé." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Básnický subjekt – hlas modlícího se svědka.", - "Katherina Horovitzová – oběť holocaustu, addresát modlitby.", - "Oběti tábora – kolektivní tvář utrpení.", - "Bůh / addresát modlitby – vztah víry v krizi.", - "Okupanti – nepřítomní, ale pociťovaní v strachu.", - "Čtenář – svědek morální výzvy." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Modlitba – forma i obsah – apel na smysl a milosrdenství.", - "Holocaust – genocida, Katherina jako konkrétní jméno.", - "Válečná lyrika – reakce na 2. světovou válku.", - "Oběť – individualizace utrpení jednoho člověka.", - "Naděje vs. beznaděj – napětí skladby.", - "Etická odpovědnost umělce – mluvit za ty, kdo nemohou." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Modlitbu pro Katherinu Horovitzovou?", "options": ["Seifert", "František Halas", "Holan", "Nezval"], "correct": 1, "expl": "Halas vydal skladbu v roce 1939."}, - {"prompt": "Kdy báseň vznikla?", "options": ["1939 – začátek okupace", "1989", "1848", "2000"], "correct": 0, "expl": "Reaguje na válečnou situaci Čech a Moravy."}, - {"prompt": "Kdo je Katherina Horovitzová?", "options": ["Postava z Lustigova románu, oběť holocaustu", "Královna", "Halasova sestra", "Vymyšlená bez kontextu"], "correct": 0, "expl": "Halas reaguje na Lustigův příběh."}, - {"prompt": "Jaký žánr dílo reprezentuje?", "options": ["Válečná lyrika / modlitební skladba", "Román", "Komedie", "Epos"], "correct": 0, "expl": "Lyrika s modlitební formou."}, - {"prompt": "Proč „modlitba“ v titulu?", "options": ["Apel na Boha i lidskost za oběť", "Katolická mše text", "Bez významu", "Vtip"], "correct": 0, "expl": "Modlitba je forma i morální výzva."}, - {"prompt": "Jaký kontext 2. sv. války?", "options": ["Okupace, tábory, genocida", "Mír", "První republika bez krize", "Vesmír"], "correct": 0, "expl": "Báseň vzniká v době nacistické hrozby."}, - {"prompt": "Co je typické pro Halasovu lyriku?", "options": ["Intimní, naléhavý jazyk", "Suchý humor", "Sci-fi", "Bez emocí"], "correct": 0, "expl": "Halas patří k lyrickým modernistům."}, - {"prompt": "Proč maturita zahrnuje skladbu?", "options": ["Nejdelší román", "Válečná poezie a etická reflexe", "Bez významu", "Jen humor"], "correct": 1, "expl": "Učí číst lyriku v historickém kontextu."}, - {"prompt": "Kdo je Arnošt Lustig v souvislosti?", "options": ["Autor románu inspirujícího Halase", "Básník Modlitby", "Okupant", "Král"], "correct": 0, "expl": "Lustig psal o Katherině Horovitzové."}, - {"prompt": "Co básnický subjekt dělá?", "options": ["Modlí se / apeluje za oběť", "Válku oslavuje", "Vaří", "Sportuje"], "correct": 0, "expl": "Hlas básníka je svědectvím."}, - {"prompt": "Jaký tón převládá?", "options": ["Vážný, bolestný, někdy nadějný", "Komický", "Bezbřehý optimismus", "Prázdný"], "correct": 0, "expl": "Válečná lyrika bez kýče."}, - {"prompt": "Co je holocaust v kontextu?", "options": ["Genocida Židů", "Sport", "Povodeň", "Revolution 1989"], "correct": 0, "expl": "Katherina reprezentuje oběti."}, - {"prompt": "Které téma NENÍ středem?", "options": ["Oběť", "Válka", "Vesmírná kolonizace", "Modlitba"], "correct": 2, "expl": "Skladba je válečná lyrika."}, - {"prompt": "Jak Halas individualizuje utrpení?", "options": ["Jménem konkrétní ženy", "Bez jmen", "Jen statistiky", "Humorem"], "correct": 0, "expl": "Konkrétní jméno zvyšuje sílu."}, - {"prompt": "Co je etická odpovědnost umělce?", "options": ["Mluvit za oběti", "Mlčet", "Oslavovat moc", "Bez etiky"], "correct": 0, "expl": "Básník je svědek doby."}, - {"prompt": "Jaký verš Halas používá?", "options": ["Volný verš moderní lyriky", "Antický hexametr", "Proza", "Bez verše"], "correct": 0, "expl": "Moderní forma odpovídá obsahu."}, - {"prompt": "Kdy Halas zemřel?", "options": ["1949", "1939", "2000", "1890"], "correct": 0, "expl": "Halas patří k meziválečné generaci."}, - {"prompt": "Co je naděje v modlitbě?", "options": ["Tenká, ale přítomná – víra v lidskost", "Absentní vždy", "Jen politika", "Sport"], "correct": 0, "expl": "Napětí mezi bezmocí a apellem."}, - {"prompt": "Jak číst skladbu historicky?", "options": ["V kontextu okupace a holocaustu", "Bez kontextu", "Jako pohádku", "Jako sci-fi"], "correct": 0, "expl": "Historie je klíč interpretace."}, - {"prompt": "Co NENÍ charakteristika Halase?", "options": ["Lyrika", "Válečné téma", "Groteskní humor bez vážnosti", "Modernismus"], "correct": 2, "expl": "Modlitba je vážná skladba."}, - {"prompt": "Proč konkrétní jméno v titulu?", "options": ["Oběť není anonymní statistika", "Náhodné", "Reklama", "Město"], "correct": 0, "expl": "Individualizace zvyšuje etický tlak."}, - {"prompt": "Jak skladba souvisí s Prokletým věkem?", "options": ["Halas je autorem obou", "Bez souvislosti", "Stejný autor Lustig", "Opera"], "correct": 0, "expl": "Halas napsal i Prokletý věk – válečná lyrika."}, - {"prompt": "Co je addresát modlitby?", "options": ["Bůh / transcendentní instance i čtenář", "Jen sportovec", "Nikdo", "Okupant"], "correct": 0, "expl": "Modlitba směřuje nad člověka."}, - {"prompt": "Jaký kontrast skladba nese?", "options": ["Modlitba za život vs. realita smrti", "Humor vs. humor", "Město vs. město", "Bez kontrastu"], "correct": 0, "expl": "Napětí víry a hrůzy."}, - {"prompt": "Co čtenář má cítit?", "options": ["Soucit a morální odpovědnost", "Smích", "Nezájem", "Pouze strach bez smyslu"], "correct": 0, "expl": "Lyrika apeluje na svědomí."}, - {"prompt": "Kde Halas patří v literatuře?", "options": ["Česká meziválečná moderna", "Baroko", "Antika", "Bez období"], "correct": 0, "expl": "Spolu s Seifertem, Holanem apod."}, - {"prompt": "Proč „Horovitzová“?", "options": ["Identita oběti holocaustu", "Náhodné jméno", "Město", "Růže"], "correct": 0, "expl": "Židovská oběť v kontextu genocidy."}, - {"prompt": "Jak skladba končí emocionálně?", "options": ["Naléhavost modlitby trvá", "Radostná párty", "Bez emocí", "Reklama"], "correct": 0, "expl": "Otevřený apel, ne uzavřený happy end."}, - {"prompt": "Co je válečná lyrika?", "options": ["Poezie reagující na válku a útlak", "Jen romantismus", "Sport", "Epos"], "correct": 0, "expl": "Modlitba je typická ukázka."}, - {"prompt": "Jaké poselství skladba nese?", "options": ["Pamatuj na oběti, nestrác humanitu v době zla", "Válka je slavná", "Oběti jsou čísla", "Bez morálky"], "correct": 0, "expl": "Etický apel Halasovy poezie."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Okupace a hrůza 2. světové války", - "Halas čte příběh Katheriny Horovitzové", - "Básník promlouvá modlitbou k oběti", - "Apel na Boha a lidskost", - "Individualizace utrpení jednoho jména", - "Výzva čtenáři neztratit morální compass" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: válečný kontext → inspirace → modlitba → apel → jméno oběti → etické poselství." - ] -} diff --git a/data/cetba/most-kwai.json b/data/cetba/most-kwai.json deleted file mode 100644 index 48bdaa9..0000000 --- a/data/cetba/most-kwai.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Pierre Boulle (1912–1994), francouzský spisovatel", - "Žánr: válečný román, antiwar novela", - "Poprvé vydáno: 1952 (Le Pont de la Rivière Kwai)", - "Děj / prostředí: Burma Railway, 2. světová válka, thajsko-barmská džungle", - "Vyprávění / forma: er-forma, střídání perspektiv (Britové, Japonci)" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Japonci nutí zajatce stavět most přes řeku Kwai.", - "Colonel Nicholson – posedlost „správným“ mostem pro armádu.", - "Shears – americký důstojník, útěk, sabotáž.", - "Konflikt: vojenská hrdost vs. realita války a smrti.", - "Slavný film Davida Leana (1957) s Alec Guinnessem.", - "Most je symbol absurdity války a kolaborace s nepřítelem." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Colonel Nicholson – britský důstojník, staví most pro Japonce z hrdosti.", - "Shears (Warden ve filmu) – únik, návrat se sabotážním týmem.", - "Colonel Saito – japonský velitel tábora.", - "Major Clipton – britský lékař, vidí absurditu.", - "Joyce – mladý důstojník v sabotážním týmu.", - "Zajatci – oběti práce na „železniční smrti“." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Burma Railway – brutální stavba, tisíce mrtvých.", - "Most Kwai – symbol kolaborace a šílenství.", - "Vojenská čest vs. loajalita – Nicholsonův paradox.", - "Sabotáž – Shearsův tým má most zničit.", - "Antiwar – válka degraduje morálku.", - "Film vs. kniha – podobné, ale rozdíly v detailu." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Most přes řeku Kwai?", "options": ["Hemingway", "Pierre Boulle", "Remarque", "Orwell"], "correct": 1, "expl": "Boulle vydal román v roce 1952."}, - {"prompt": "Kde se děj odehrává?", "options": ["Francie", "Barmská/thajská džungle – Burma Railway", "Pacifik", "Londýn"], "correct": 1, "expl": "Zajatci staví železnici pro Japonce."}, - {"prompt": "Kdo je Colonel Nicholson?", "options": ["Japonský generál", "Britský důstojník posedlý stavbou mostu", "Americký Shears", "Lékař"], "correct": 1, "expl": "Nicholson chce „pořádný“ most pro britskou armádu."}, - {"prompt": "Proč Nicholson staví most pro nepřítele?", "options": ["Zrada", "Hrdost, disciplína, iluze že most bude britský", "Náhodou", "Bez důvodu"], "correct": 1, "expl": "Paradox – pomáhá okupantům z pocitu česti."}, - {"prompt": "Kdo je Shears?", "options": ["Zajatec, utekl, účastní se sabotáže", "Japonský velitel", "Nicholson", "Most"], "correct": 0, "expl": "Shears reprezentuje praktický odpor."}, - {"prompt": "Co má sabotážní tým udělat?", "options": ["Postavit most", "Zničit most", "Ukrást vlak", "Podepsat mír"], "correct": 1, "expl": "Most má padnout před použitím."}, - {"prompt": "Kdo je Saito?", "options": ["Japonský velitel tábora", "Brit", "Shears", "Lékař"], "correct": 0, "expl": "Saito tlačí na dokončení mostu."}, - {"prompt": "Jak román/film končí?", "options": ["Most stojí navždy slavně", "Most exploduje; Nicholson padne v absurditě", "Mír", "Shears král"], "correct": 1, "expl": "Sabotáž a Nicholsonův zlom."}, - {"prompt": "Kdy vyšel román?", "options": ["1952", "1940", "2000", "1890"], "correct": 0, "expl": "Po 2. světové válce."}, - {"prompt": "Jaký žánr?", "options": ["Válečný / antiwar román", "Pohádka", "Detektivka", "Sci-fi"], "correct": 0, "expl": "Kritika absurdity války."}, - {"prompt": "Proč maturita zahrnuje dílo?", "options": ["Nejkratší", "2. sv. válka, etika, kolaborace", "Bez děje", "Komiks"], "correct": 1, "expl": "Učí historii a morální paradox."}, - {"prompt": "Co je Burma Railway?", "options": ["Železnice stavěná zajatci za okupace", "Metro v Londýně", "Vesmír", "Most v Praze"], "correct": 0, "expl": "Tisíce zajatců zemřelo."}, - {"prompt": "Kdo režíroval slavný film?", "options": ["David Lean", "Spielberg", "Kubrick", "Nolan"], "correct": 0, "expl": "Film 1957 získal Oscary."}, - {"prompt": "Co je Clipton?", "options": ["Lékař kritizující Nicholsona", "Most", "Shears", "Saito"], "correct": 0, "expl": "Clipton vidí šílenství situace."}, - {"prompt": "Které téma NENÍ středem?", "options": ["Vojenská hrdost", "Sabotáž", "Vesmírná válka", "Zajatecký tábor"], "correct": 2, "expl": "Děj je v jihovýchodní Asii 2. sv. války."}, - {"prompt": "Co symbolizuje most?", "options": ["Absurdita pomoci nepříteli", "Láska", "Mír", "Sport"], "correct": 0, "expl": "Most = morální kolaps Nicholsona."}, - {"prompt": "Jak Boulle pracuje s perspektivou?", "options": ["Britové i Japonci", "Jen Japonci", "Bez postav", "Jen Shears"], "correct": 0, "expl": "Román střídá pohledy."}, - {"prompt": "Proč je Nicholson tragický?", "options": ["Má čest, ale slouží nepříteli", "Je zločinec od začátku", "Komik", "Dítě"], "correct": 0, "expl": "Tragédie dobré intence."}, - {"prompt": "Co Shears představuje?", "options": ["Přežití a praktický odpor", "Kolaboraci", "Kněze", "Most"], "correct": 0, "expl": "Utíká a vrací se ničit."}, - {"prompt": "Jaký kontrast tvoří jádro?", "options": ["Stavba vs. sabotáž mostu", "Moře vs. hory", "Praha vs. Brno", "Humor"], "correct": 0, "expl": "Nicholson vs. Shears."}, - {"prompt": "Co je antiwar poselství?", "options": ["Válka ničí rozum a morálku", "Válka slavná", "Bez poselství", "Propaganda"], "correct": 0, "expl": "Most ukazuje degradaci."}, - {"prompt": "Kdo hraje Nicholsona ve filmu?", "options": ["Alec Guinness", "Connery", "Cooper", "Brando"], "correct": 0, "expl": "Guinness – ikonická role."}, - {"prompt": "Co je železniční smrt?", "options": ["Přezdívka brutalitě stavby", "Vlak", "Film", "Komiks"], "correct": 0, "expl": "Extrémní úmrtnost zajatců."}, - {"prompt": "Jak Nicholson reaguje na sabotáž?", "options": ["V finále zasáhne proti – tragický zlom", "Pomůže hned", "Spí", "Utíká"], "correct": 0, "expl": "Umírá u vlastního díla."}, - {"prompt": "Proč Boulle psal francouzsky?", "options": ["Francouzský autor", "Anglicky jen", "Česky", "Německy"], "correct": 0, "expl": "Boulle je francouzský spisovatel."}, - {"prompt": "Co Joyce dělá?", "options": ["Součást sabotážního týmu", "Velitel Japonců", "Nicholsonova žena", "Most"], "correct": 0, "expl": "Mladý důstojník v akci."}, - {"prompt": "Jak číst kolaboraci?", "options": ["Ne vždy zrada – i iluze a hrdost", "Vždy zlo", "Vždy dobro", "Bez významu"], "correct": 0, "expl": "Nicholson není karikatura zla."}, - {"prompt": "Co NENÍ charakteristika?", "options": ["Válka", "Most", "Pohádkový happy end", "Tábor"], "correct": 2, "expl": "Dílo je vážné antiwar."}, - {"prompt": "Jaký historický fakt stojí za dějem?", "options": ["Stavba železnice zajatci v Asii", "Normandie", "Pearl Harbor", "Berlín"], "correct": 0, "expl": "Burma Railway je reálná."}, - {"prompt": "Jaké poselství román nese?", "options": ["Válečná hrdost může vést k absurdní sebedestrukci", "Stavět mosty pro nepřítele", "Bez morálky", "Jen akce"], "correct": 0, "expl": "Varování před slepou disciplínou."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Britští zajatci v táboře u Kwai", - "Nicholson organizuje stavbu mostu", - "Shears utekne a vrací se se sabotážním týmem", - "Most se blíží k dokončení", - "Sabotážní akce proti mostu", - "Most padne; Nicholson umírá v paradoxu hrdosti" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: tábor → stavba → Shears → dokončování → sabotáž → zničení mostu a Nicholsonův konec." - ] -} diff --git a/data/cetba/na-ceste.json b/data/cetba/na-ceste.json deleted file mode 100644 index 311977d..0000000 --- a/data/cetba/na-ceste.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Jack Kerouac (vl. jm. Jean-Louis Lebris de Kérouac)", - "Žánr: román beat generation; autobiografické rysy", - "Poprvé vydáno: 1957 (anglicky On the Road; česky Na cestě)", - "Děj: opakované cesty po Spojených státech a do Mexika", - "Vyprávění: ich-forma; spontánní próza inspirovaná jazzem" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Poválečná Amerika 40. a 50. let: konformita, spotřební společnost, studená válka.", - "Beat generation odmítá materialismus a hledá autentický život.", - "Silnice, auta a vlaky jsou symbolem svobody i neklidu.", - "Jazz, noční bary, drogy a sex patří k beatnickému stylu.", - "Cesta je zároveň únikem i hledáním smyslu – často bez pevné kotvy.", - "Kerouac zachycuje rytmus života rychlým, neupraveným stylem." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Sal Paradise – vypravěč, spisovatel, hledá zkušenost (Kerouac).", - "Dean Moriarty – neklidný, charismatický motor cest (Neal Cassady).", - "Marylou – Deanova mladá partnerka.", - "Camille / Galatea – další ženy v Deanově nestálém životě.", - "Carlo Marx, Old Bull Lee – přátelé z beat scény (Ginsberg, Burroughs).", - "Amerika – prostor nekonečných cest a setkání." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Beat generation – kulturní hnutí mladých umělců po válce.", - "Spontánní próza – rychlý proud řeči bez klasické kompozice.", - "Cesta – metafora svobody, touhy i vyčerpání.", - "Jazz – rytmus textu i životního stylu.", - "Konformita vs. autenticita – hlavní konflikt.", - "IT – beatnické slovo pro extatický okamžik plnosti." - ] - } - ], - "quiz": [ - {"prompt": "Kdo je autorem románu Na cestě?", "options": ["Allen Ginsberg", "Jack Kerouac", "William S. Burroughs", "Ernest Hemingway"], "correct": 1, "expl": "Román napsal Jack Kerouac; vyšel v roce 1957 a stal se manifestem beat generation."}, - {"prompt": "Jak se jmenuje anglický originál knihy?", "options": ["The Road", "On the Road", "Down the Road", "Off the Road"], "correct": 1, "expl": "Originální název je On the Road – „na cestě“, v pohybu."}, - {"prompt": "Kdo je vypravěč příběhu?", "options": ["Dean Moriarty", "Sal Paradise", "Carlo Marx", "Old Bull Lee"], "correct": 1, "expl": "Sal Paradise vypráví v ich-formě o svých cestách a o Deanovi."}, - {"prompt": "Na koho reálně naráží postava Deana Moriartyho?", "options": ["Na Neal Cassadyho", "Na Ernesta Hemingwaye", "Na F. S. Fitzgeralda", "Na Jacka Londona"], "correct": 0, "expl": "Dean Moriarty je literární obraz Neal Cassadyho, Kerouacova přítele a vzoru neklidu."}, - {"prompt": "Jaké hnutí román nejvíc reprezentuje?", "options": ["Romantismus", "Beat generation", "Socialistický realismus", "Existencialismus Sartreův"], "correct": 1, "expl": "Na cestě je klíčovým textem beat generation – odmítání konformity a hledání života."}, - {"prompt": "Co je „spontánní próza“ v Kerouacově pojetí?", "options": ["Přesně strukturovaný epos", "Rychlý, rytmický proud řeči blízký jazzu", "Úřední styl", "Pouze dialogy"], "correct": 1, "expl": "Kerouac psal rychle, s jazzovým rytmem; vzdává se klasické pevné kompozice."}, - {"prompt": "Jakou roli hraje jazz v románu?", "options": ["Jen kulisa bez významu", "Rytmus života, hudby i stylu vyprávění", "Symbol války", "Náboženský obřad"], "correct": 1, "expl": "Jazz ovlivňuje beatnický život i Kerouacovu prózu – rychlost, improvizace, extáze."}, - {"prompt": "Proti čemu beatnici v románu nejvíc vystupují?", "options": ["Proti cestování", "Proti konformní poválečné společnosti a prázdnému materialismu", "Proti demokracii", "Proti literatuře"], "correct": 1, "expl": "Hrdinové utíkají před nudou, kariérou a „normálním“ životem bez autenticity."}, - {"prompt": "Co je typickým prostorem děje?", "options": ["Pouze jeden byt v New Yorku", "Silnice, auta, vlaky a města USA (a cesta do Mexika)", "Středověký hrad", "Vesnická idyla"], "correct": 1, "expl": "Chronotopem románu je cesta – Amerika jako nekonečná silnice a setkání."}, - {"prompt": "Jaký vztah mají Sal a Dean?", "options": ["Jsou bratři", "Sal obdivuje Deana, Dean je hybatelem neklidných cest", "Jsou nepřátelé", "Dean je Salův učitel latině"], "correct": 1, "expl": "Sal je pozorovatel a společník; Dean přitahuje svou energií, ale také ničí vztahy kolem sebe."}, - {"prompt": "Jak Dean Moriarty obvykle jedná k ženám?", "options": ["Je věrný jedné partnerce", "Je vášnivý, ale nestálý a často opouští rodiny", "Ženy v románu vůbec nejsou", "Je asketa"], "correct": 1, "expl": "Dean prožívá intenzivní vztahy s Marylou, Camille a dalšími, ale nedokáže zůstat."}, - {"prompt": "Kdo je Carlo Marx v románu?", "options": ["Policista", "Beatnický básník, obraz Allena Ginsberga", "Deanův otec", "Mexický farmář"], "correct": 1, "expl": "Carlo Marx představuje Ginsberga – intelektuála a básníka z beat scény."}, - {"prompt": "Kdo je Old Bull Lee?", "options": ["Námořní kapitán", "Literární obraz Williama S. Burroughse", "Salův strýc", "Kněz"], "correct": 1, "expl": "Old Bull Lee je Kerouacova verze Burroughse – excentrický spisovatel na jihu USA."}, - {"prompt": "Proč Sal opakovaně vyráží na cestu?", "options": ["Kvůli vojenské službě", "Hledá zkušenost, extázi a autentický život", "Je to trest soudu", "Musí doručovat poštu"], "correct": 1, "expl": "Sal touží po „IT“ – okamžiku, kdy život dává smysl; cesta je jeho metoda hledání."}, - {"prompt": "Jak román obvykle končí jednotlivé etapy cest?", "options": ["Vždy šťastným sňatkem", "Vyčerpáním, rozchody a návratem k psaní či klidu", "Vítězstvím ve válce", "Dědictvím milionů"], "correct": 1, "expl": "Za extází cesty přichází únava, prázdné noci a vystřízlivění – svoboda má cenu."}, - {"prompt": "Kam Sal s Deanem mimo USA také cestují?", "options": ["Do Antarktidy", "Do Mexika (a další cesty po Americe)", "Do Marsu", "Pouze do Kanady"], "correct": 1, "expl": "Mezi významné úseky patří jízda do Mexika – jiná kultura, drogy, pocit svobody."}, - {"prompt": "Co znamená beatnické „IT“?", "options": ["Iniciály autora", "Extatický okamžik plnosti a pravdy", "Název auta", "Zkratka pro cenzuru"], "correct": 1, "expl": "„IT“ je stav, kdy člověk prožije život naplno – jazz, noc, řeč, extáze."}, - {"prompt": "Jaký je vztah románu k autobiografii?", "options": ["Čistá fantasy bez reálií", "Silně autobiografický – postavy odpovídají reálným beatníkům", "Historický román o středověku", "Detektivka"], "correct": 1, "expl": "Kerouac zpracoval skutečné cesty a přátele; román je fikcionalizovaným deníkem."}, - {"prompt": "Které téma NENÍ pro Na cestě typické?", "options": ["Touha po svobodě", "Přátelství a neklid", "Kritika prázdné konformity", "Středověké rytířské turnaje"], "correct": 3, "expl": "Román je o moderní Americe a beatnících, ne o rytířském středověku."}, - {"prompt": "Jak Sal vydělává na živobytí (mimo cesty)?", "options": ["Jako spisovatel a občas brigádník", "Jako soudce", "Jako farář", "Jako astronaut"], "correct": 0, "expl": "Sal píše a občas pracuje; cesty financuje různými krátkodobými příjmy."}, - {"prompt": "Proč je Dean pro ostatní tak přitažlivý?", "options": ["Má neomezené bohatství", "Je plný energie, spontánnosti a radosti z okamžiku", "Je nejlepší student na univerzitě", "Je generál armády"], "correct": 1, "expl": "Dean žije rychle, mluví zmateně ale vášnivě a láme pravidla – fascinuje i ničí."}, - {"prompt": "Jaký stín má beatnická svoboda v románu?", "options": ["Žádný – vše je idyla", "Vyčerpání, osamění, rozpad vztahů a deprese", "Vězení za jazz", "Ztráta paměti"], "correct": 1, "expl": "Neustálý pohyb nevyplní vždy prázdnotu; hrdinové často končí u únavy a smutku."}, - {"prompt": "V jakém roce román poprvé vyšel?", "options": ["1929", "1957", "1984", "2001"], "correct": 1, "expl": "Kniha vyšla v roce 1957 a rychle ovlivnila americkou kulturu."}, - {"prompt": "Jaký jazykový styl je typický?", "options": ["Strohé věty bez emocí", "Dlouhé věty, slang, rytmus mluvené řeči", "Středověká čeština", "Pouze rýmované verše"], "correct": 1, "expl": "Kerouac napodobuje mluvený jazyk, jazzový flow a rychlé sledy obrazů."}, - {"prompt": "Co je hlavní strukturou románu?", "options": ["Jeden den v jedné místnosti", "Série cest a setkání bez klasické zápletky", "Přesný detektivní úkol", "Epos o jedné bitvě"], "correct": 1, "expl": "Román nemá tradiční děj; skládá se z epizod na cestách."}, - {"prompt": "Jaký význam má přátelství Sal–Dean?", "options": ["Jen náhodné setkání", "Jádro románu – inspirace, svoboda i zklamání", "Obchodní partnerství", "Vztah učitele a žáka v latině"], "correct": 1, "expl": "Sal bez Deana necestuje stejně; Dean je symbolem i problémem beatnického života."}, - {"prompt": "Proč je Na cestě důležitá pro maturitu?", "options": ["Je technický manuál", "Ukazuje beat generation, styl i témata poválečné Ameriky", "Je encyklopedie rostlin", "Je zákoník"], "correct": 1, "expl": "U maturity jde o autora, kontext, postavy, styl spontánní prózy a témata svobody."}, - {"prompt": "Které město je častým výchozím bodem Salových cest?", "options": ["New York", "Praha", "Paříž", "Tokio"], "correct": 0, "expl": "Sal žije mezi New Yorkem a cestami po zbytku USA; město je start i návrat."}, - {"prompt": "Jak Dean často financuje svůj neklid?", "options": ["Krádeže bank", "Krátké práce, přátelé, manželky, auta", "Výhra v loterii pokaždé", "Státní dotace na poezii"], "correct": 1, "expl": "Dean žije od ruky k ruce – auta, práce, vztahy; stabilní kariéru nemá."}, - {"prompt": "Co Kerouac románem nejspíš vyjadřuje?", "options": ["Oslavu konformity", "Touhu po autentickém životě a varování před prázdnou svobodou", "Návod na daňové úniky", "Historii antiky"], "correct": 1, "expl": "Román slaví cestu a okamžik, ale ukazuje i vyhoření a nenasytnost pohybu."}, - {"prompt": "Která postava nepatří k beat scéně v románu?", "options": ["Sal Paradise", "Dean Moriarty", "Carlo Marx", "Napoleon Bonaparte"], "correct": 3, "expl": "Napoleon v románu nevystupuje; ostatní jména patří ke Kerouacově beatnické partě."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Sal potká Deana Moriartyho a obdivuje jeho energii", - "Společně vyrážejí na první velké cesty po Americe", - "Noční jízdy, jazz, bary a vztahy s ženami", - "Cesta do Mexika a další opakované výjezdy", - "Deanův neklid ničí vztahy, Sal se unavuje", - "Sal se vrací k psaní a bilancuje cesty" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: setkání s Deanem → první cesty → jazz a vztahy → Mexiko a další jízdy → vyčerpání → návrat a bilance." - ] -} diff --git a/data/cetba/na-zapadni-fronte.json b/data/cetba/na-zapadni-fronte.json deleted file mode 100644 index a0eabaa..0000000 --- a/data/cetba/na-zapadni-fronte.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Erich Maria Remarque", - "Žánr: protiválečný román; generační próza", - "Poprvé vydáno: 1929 (německy Im Westen nichts Neues)", - "Děj: západní fronta 1. světové války, německá armáda", - "Vyprávění: ich-forma Paula Bäumera" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "1. světová válka: zákopy, dělostřelectvo, plyn, strojová válka.", - "Mladí dobrovolníci byli sváděni učiteli k „slavnému boji za vlast“.", - "Fronta ničí tělo i duši; smrt je všední a bezcílná.", - "Domov už nechápe zkušenost vojáků – propast generací.", - "Kamarádství ve squatu je jedinou oporou proti absurditě.", - "Remarque míří proti romantizaci války." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Paul Bäumer – vypravěč, student proměněný v cynického vojáka.", - "Stanislaus Katczinsky (Kat) – čtyřicátník, mazaný kamarád.", - "Albert Kropp, Müller, Leer, Tjaden – spolužáci z třídy.", - "Kantorek – učitel, který je nabádal k odchodu na frontu.", - "Himmelstoss – tyranský cvičitel, později zocelený frontou.", - "Francouzský voják Gérard Duval – Paul ho zabije v zákopu." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Ztráta generace – mladí zničeni dřív, než začnou žít.", - "Zákop – symbol odlidštění a strachu.", - "Kamarádství – sdílení chleba, krytí, smích.", - "Propaganda vs. realita – Kantorek a fronta.", - "Odcizení od civilního světa – domov je cizí.", - "Antiválečné poselství – válka nemá smysl." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Na západní frontě klid?", "options": ["Thomas Mann", "Erich Maria Remarque", "Franz Kafka", "Ernest Hemingway"], "correct": 1, "expl": "Autorem je Erich Maria Remarque; román vyšel v roce 1929."}, - {"prompt": "Kdo vypravuje příběh?", "options": ["Kantorek", "Paul Bäumer", "Kat", "Generál"], "correct": 1, "expl": "Paul Bäumer vypráví v ich-formě o frontě a o sobě."}, - {"prompt": "Kde se děj odehrává?", "options": ["Na východní frontě za 2. světové", "Na západní frontě 1. světové války", "V Praze za protektorátu", "Ve Vietnamu"], "correct": 1, "expl": "Román sleduje německé vojáky na západní frontě první světové války."}, - {"prompt": "Kdo je Kat?", "options": ["Paulův učitel", "Zkušený starší kamarád ve squatu", "Francouzský generál", "Paulova sestra"], "correct": 1, "expl": "Katczinsky je mazaný čtyřicátník, který pomáhá přežít a udržuje morálku."}, - {"prompt": "Jak Paul a spolužáci přišli k armádě?", "options": ["Byli verbováni násilím", "Nechali se strhnout Kantorekovou propagandou", "Byli odsouzeni soudem", "Byli cizinci"], "correct": 1, "expl": "Učitel Kantorek je nabádal k dobrovolnému odchodu – „železný mladý muž“."}, - {"prompt": "Co symbolizuje Kantorek?", "options": ["Moudrého mentora", "Válečnou propagandu a lži z domova", "Lékařskou etiku", "Náboženský mír"], "correct": 1, "expl": "Kantorek reprezentuje romantizaci války, kterou fronta vyvrací."}, - {"prompt": "Jak Paul vnímá Himmelstosse na začátku?", "options": ["Jako hrdinu", "Jako tyrana ve výcviku", "Jako otce", "Jako lékaře"], "correct": 1, "expl": "Himmelstoss šikanuje rekruty; později fronta i jeho mění."}, - {"prompt": "Co se stane Kemmerichovi?", "options": ["Stane se generálem", "Umírá po amputaci; Paul je u něj", "Desertuje", "Síní Nobelovu cenu"], "correct": 1, "expl": "Kemmerichova smrt je jedna z prvních tvrdých lekcí – boty přejdou Müllerovi."}, - {"prompt": "Proč Müller chce Kemmerichovy boty?", "options": ["Sbírá umění", "Na frontě je praktické vybavení důležitější než sentiment", "Je obchodník", "Nenávidí Kemmericha"], "correct": 1, "expl": "Román ukazuje, jak válka redukuje vztahy na přežití a věci."}, - {"prompt": "Co Paul prožije v zákopu s francouzským vojákem?", "options": ["Šachovou partii", "Zabije Duvala a lituje – vidí v něm člověka, ne nepřítele", "Svatbu", "Kněžské vysvěcení"], "correct": 1, "expl": "Scéna s Duvelem zhumanizuje „nepřítele“ a zdůrazní absurditu války."}, - {"prompt": "Jak Paul reaguje na návštěvu domova?", "options": ["Cítí se jako hrdina", "Cítí se cizí; civilisté nechápou frontu", "Zůstane navždy doma", "Stane se ministrem"], "correct": 1, "expl": "Matka, otcové, učitelé žijí v jiném světě – Paul už mezi nimi nepatří."}, - {"prompt": "Co je hlavní hodnotou ve squatu?", "options": ["Kariéra", "Kamarádství a solidarita", "Sběr medailí", "Psaní básní pro tisk"], "correct": 1, "expl": "Vojáci si dělí jídlo, kryjí se a vydrží jen díky sobě navzájem."}, - {"prompt": "Jak končí Kat?", "options": ["Generál armády", "Umírá – Paul ho nese a přitom Kat dostává střelu do hlavy", "Emigruje do USA", "Stane se učitelem"], "correct": 1, "expl": "Smrt Kata je pro Paula zlom – ztrácí poslední pevnou oporu."}, - {"prompt": "Jaký je původní německý název a co znamená?", "options": ["Im Osten alles Neu", "Im Westen nichts Neues – na západě nic nového", "Kein Krieg", "Der Frieden"], "correct": 1, "expl": "Vojenská zpráva hlásí klid – ironie vůči masovému mýlu o velkých zprávách z fronty."}, - {"prompt": "Jak zemře Paul Bäumer?", "options": ["Ve stáří doma", "Krátce před koncem války – klidně, téměř bez bolesti", "V duelu", "V letecké nehodě jako pilot"], "correct": 1, "expl": "Paul padne v říjnu 1918; report zní, že na západě není nic nového."}, - {"prompt": "Které téma román nejvíc zdůrazňuje?", "options": ["Slávu války", "Zničení mladé generace a nesmysl války", "Růst hospodářství", "Středověké rytířství"], "correct": 1, "expl": "Remarque ukazuje fyzické i psychické zničení a prázdnotu válečných hesel."}, - {"prompt": "Co je typickým prostředím děje?", "options": ["Salóny a plesy", "Zákopy, dělostřelectvo, plynové útoky", "Univerzitní kampus", "Moře a piráti"], "correct": 1, "expl": "Chronotopem je fronta – bláto, kryty, hlod, strach."}, - {"prompt": "Jak román líčí autoritu armády?", "options": ["Jako vždy spravedlivou", "Jako součást systému, který žere lidi", "Jako neexistující", "Jako komedii bez násilí"], "correct": 1, "expl": "Disciplína, šikana i absurdita rozkazů patří k obrazu války."}, - {"prompt": "Proč Paul nemůže „normálně“ studovat?", "options": ["Nemá peníze", "Válka ho odtrhla od mládí a znalostí", "Je v exilu", "Je slepý od narození"], "correct": 1, "expl": "Paul říká, že jeho generace stojí před propastí – válka jim vzala budoucnost."}, - {"prompt": "Co znamená „ztráta generace“?", "options": ["Emigrace do Ameriky", "Mladí muži zničeni dřív, než stihnou dospět do života", "Ztráta knih", "Demografický baby boom"], "correct": 1, "expl": "Termín popisuje trauma 1. světové války – mrtví i psychicky zlomení."}, - {"prompt": "Jak je zobrazeno násilí?", "options": ["Romanticky", "Věcně, drsně, bez glorifikace", "Jen jako metafora", "Vůbec se neobjevuje"], "correct": 1, "expl": "Remarque popisuje zranění, strach a smrt matter-of-fact stylem."}, - {"prompt": "Kdo je Tjaden?", "options": ["Paulův spolužák a voják ve squatu", "Ruský car", "Lékař", "Novinář"], "correct": 0, "expl": "Tjaden patří k Paulově partě – typický „malý“ voják fronty."}, - {"prompt": "Proč je román důležitý pro maturitu?", "options": ["Je učebnicí chemie", "Ukazuje 1. světovou válku, ich-formu a antiválečná témata", "Je právní kód", "Je atlas"], "correct": 1, "expl": "U maturity: autor, kontext, postavy, vypravěč, témata a jazyk."}, - {"prompt": "Jaký vztah mají vojáci k rozkazům?", "options": ["Vždy je chápou jako smysluplné", "Často vidí absurditu, ale poslušnost je nutná k přežití", "Vždy desertují", "Rozkazy neexistují"], "correct": 1, "expl": "Paul poslouchá, ale uvnitř ví, že mnoho bojů nemá logiku."}, - {"prompt": "Co Paul cítí k lidem doma, kteří válku oslavují?", "options": ["Obdiv", "Hořkost a vztek – nechápou realitu", "Lhostejnost bez emocí", "Radost"], "correct": 1, "expl": "Kantorek a podobní mluví o cti, zatímco vojáci umírají v blátě."}, - {"prompt": "Jaký je styl vyprávění?", "options": ["Epický vypravěč bez já", "Ich-forma, přímá zkušenost Paula", "Dopisový deník cizí osoby", "Drama bez prózy"], "correct": 1, "expl": "Paulův hlas dává románu autenticitu a subjektivní tíhu."}, - {"prompt": "Které tvrzení o Müllerovi je správné?", "options": ["Je Paulův učitel", "Je spolužák; praktický, chce Kemmerichovy boty", "Je francouzský špion", "Je námořník"], "correct": 1, "expl": "Müller reprezentuje tvrdost fronty – přežití je důležitější než sentiment."}, - {"prompt": "Co není typické pro Remarqueův obraz fronty?", "options": ["Strach a únava", "Kamarádství", "Glorifikace hrdinských bitev bez krve", "Smrt kamarádů"], "correct": 2, "expl": "Román právě boj proti slavnostnímu obrazu války."}, - {"prompt": "Kdy román poprvé vyšel?", "options": ["1914", "1929", "1945", "2000"], "correct": 1, "expl": "Vydání 1929 – meziválečí reakce na trauma 1. světové války."}, - {"prompt": "Jaký význam má závěr s Paulovou smrtí?", "options": ["Válka je vítězstvím", "Jednotlivec je obětí systému; zpráva o „klidu“ je krutá ironie", "Paul se stane legendou", "Válka pokračuje věčně v textu"], "correct": 1, "expl": "Paul umírá těsně před koncem – osobní ztráta vs. anonymní válečná zpráva."}, - {"prompt": "Která postava NEPATŘÍ k Paulově partě?", "options": ["Kat", "Kropp", "Kantorek jako voják v partě", "Tjaden"], "correct": 2, "expl": "Kantorek zůstává doma jako symbol propagandy, ne bojuje v jejich squatu."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Kantorek nabádá mladíky k odchodu na frontu", - "Výcvik u Himmelstosse a první ztráty (Kemmerich)", - "Život ve squatu, Kat jako opora", - "Paul zabije francouzského vojáka Duvala", - "Návštěva domova a odcizení", - "Smrt Kata a Paulova smrt krátce před koncem války" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: propaganda → výcvik a ztráty → fronta s Katem → Duval → domov → smrt Kata a Paula." - ] -} diff --git a/data/cetba/navsteva-stare-damy.json b/data/cetba/navsteva-stare-damy.json deleted file mode 100644 index 9c8ee1e..0000000 --- a/data/cetba/navsteva-stare-damy.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Friedrich Dürrenmatt", - "Žánr: tragická komedie / drama", - "Poprvé vydáno: 1956 (Die Physiker – ne, to je jiné; Návštěva 1956)", - "Děj: městečko Güllen, miliardářka Claire Zachanassian", - "Vyprávění: drama ve třech dějstvích" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Poválečné / moderní Evropa – chudoba provincie vs. bohatství.", - "Güllen upadá, obyvatelé touží po penězích.", - "Claire nabídne miliardu za smrt Alfreda Illa.", - "Morálka vs. materiální zkaženost.", - "Tragikomický tón – smích i hrůza.", - "Téma: vina, pomsta, kolektivní zločin." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Claire Zachanassian – miliardářka, kdysi opuštěná Illem.", - "Alfred Ill – majitel obchodu, „respektovaný“ občan.", - "Starosta – mluví o cti, pak kapituluje.", - "Učitel – nejprve protestuje, pak mlčí.", - "Doktoři a občané Güllenu – kolektivní viník.", - "Slepí muži Klodi a Lobi – Claireini pomocníci." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Miliarda – cena morálky města.", - "Pomsta – Claire chce Illovu smrt, ne peníze pro sebe.", - "Kolektivní vina – všichni koupí luxus na dluh.", - "Tragikomedie – groteskní situace.", - "Güllen – symbol zkažené společnosti.", - "Justice – Ill zemře „soudem“ obce." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Návštěvu staré dámy?", "options": ["Brecht", "Friedrich Dürrenmatt", "Goethe", "Kafka"], "correct": 1, "expl": "Švýcarský dramatik; hra 1956."}, - {"prompt": "Jak se jmenuje městečko?", "options": ["Güllen", "Verona", "Praha", "Gütersloh"], "correct": 0, "expl": "Fiktivní Güllen je v zoufalé ekonomické situaci."}, - {"prompt": "Kdo přijede jako miliardářka?", "options": ["Claire Zachanassian", "Lady Catherine", "Helena Glory", "Julie"], "correct": 0, "expl": "Claire se vrací po letech jako neuvěřitelně bohatá."}, - {"prompt": "Kdo je Alfred Ill?", "options": ["Starosta", "Obchodník, bývalý Clairein milenec", "Kněz", "Robot"], "correct": 1, "expl": "Ill kdysi zradil Claire – nyní je terč pomsty."}, - {"prompt": "Co Claire nabídne městu?", "options": ["Miliardu, pokud Ill zemře", "Bezplatnou školu", "Armádu", "Nic"], "correct": 0, "expl": "Podmínka je Illova smrt – obec má rozhodnout."}, - {"prompt": "Proč Claire nenávidí Illa?", "options": ["Kdysi ji opustil a zničil reputaci (s falešnými svědky)", "Ill ji okradl o dům", "Ill je cizinec", "Bez důvodu"], "correct": 0, "expl": "Mladá Claire byla ponižována – Ill zaplatil svědky."}, - {"prompt": "Jak reagují občané zpočátku?", "options": ["Odmítnou peníze", "Protestují morálně, ale brzy kupují na dluh", "Utečou", "Zavraždí Claire"], "correct": 1, "expl": "Hypokrizie – nejdřív cti, pak nákupy na úvěr."}, - {"prompt": "Kdo Ill varuje?", "options": ["Nikdo", "Ill sám cítí, že město ho obětuje", "Claire", "Císař"], "correct": 1, "expl": "Ill postupně chápe, že Güllen ho odsoudí."}, - {"prompt": "Jak Ill zemře?", "options": ["Přirozeně ve spánku", "Obec ho odsoudí a zabije (justiční fraška)", "V autonehodě", "Na frontě"], "correct": 1, "expl": "Město formálně „soudí“ a popraví Illa pro miliardu."}, - {"prompt": "Jaký je žánr?", "options": ["Tragikomedie / drama", "Pohádka", "Sci-fi román", "Epos"], "correct": 0, "expl": "Dürrenmatt mísí grotesku, humor a tragédii."}, - {"prompt": "Co symbolizují nákupy občanů?", "options": ["Prospěch za cenu morálky", "Dobročinnost", "Sport", "Vědu"], "correct": 0, "expl": "Každý si koupí na dluh – už přijal Illovu smrt."}, - {"prompt": "Kdo jsou Klodi a Lobi?", "options": ["Claireini slepí pomocníci", "Illovi synové", "Starostovi psi", "Lékaři"], "correct": 0, "expl": "Groteskní postavy Claireina doprovodu."}, - {"prompt": "Proč je hra důležitá pro maturitu?", "options": ["Učí chemii", "Dürrenmatt, morálka, pomsta, tragikomedie", "Je mapa", "Je cookbook"], "correct": 1, "expl": "U maturity: děj, postavy, témata kolektivní viny."}, - {"prompt": "Kdy hra vznikla?", "options": ["1956", "1836", "1595", "2020"], "correct": 0, "expl": "Poválečná reflexe bohatství a morálky."}, - {"prompt": "Jak starosta mluví o cti?", "options": ["Zpočátku odmítá, pak mlčí a přijme", "Vždy odmítá", "Je Illův bratr", "Neexistuje"], "correct": 0, "expl": "Politik typicky capituluje před penězi."}, - {"prompt": "Co učitel ztělesňuje?", "options": ["Intelektuální protest, který selže", "Vítězství morálky", "Válku", "Roboty"], "correct": 0, "expl": "Učitel chápe problém, ale neodolá systému."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Pomsta", "Kolektivní vina", "Vesmírná válka robotů", "Materiální zkaženost"], "correct": 2, "expl": "Roboti nejsou téma Dürrenmattovy hry."}, - {"prompt": "Proč Claire nepotřebuje peníze?", "options": ["Už je nejbohatší – jde o pomstu", "Je chudá", "Je dítě", "Peníze neexistují"], "correct": 0, "expl": "Nabízí miliardu městu, ne sobě – chce spravedlnost."}, - {"prompt": "Jak končí hra?", "options": ["Ill přežije", "Ill je mrtvý, město bohatne – morální prohra", "Güllen shoří", "Claire se provdá za Illa"], "correct": 1, "expl": "Tragikomická pointa – ekonomický „ráj“ na vraždě."}, - {"prompt": "Kde Dürrenmatt pochází / působí?", "options": ["Švýcarsko", "Rusko", "Česko", "Japonsko"], "correct": 0, "expl": "Friedrich Dürrenmatt je švýcarský autor."}, - {"prompt": "Co je groteska v Návštěvě?", "options": ["Absurdní poměr ceny a morálky", "Pouze romantika", "Realismus bez humoru", "Pohádka pro děti"], "correct": 0, "expl": "Miliarda za život – groteskní obchod."}, - {"prompt": "Kdo je Ill v obci?", "options": ["Respektovaný občan, kandidát na starostu", "Cizinec", "Dítě", "Kněz"], "correct": 0, "expl": "Právě jeho „cti“ je obětováno."}, - {"prompt": "Jak občané ospravedlňují zločin?", "options": ["Ekonomickou nouzí a kolektivním rozhodnutím", "Náboženstvím", "Válka", "Náhodou"], "correct": 0, "expl": "Chudoba Güllenu je Dürrenmattova motivace."}, - {"prompt": "Která postava NENÍ v Návštěvě?", "options": ["Claire", "Ill", "Švejk", "Starosta"], "correct": 2, "expl": "Švejk je Haškův hrdina."}, - {"prompt": "Kolik dějství má hra?", "options": ["3", "5", "1", "12"], "correct": 0, "expl": "Klasická třídělná dramatická stavba."}, - {"prompt": "Co Ill cítí v průběhu hry?", "options": ["Stále větší osamění a strach", "Radost", "Nic", "Vítězství"], "correct": 0, "expl": "Ill ví, že město už rozhodlo."}, - {"prompt": "Jaký kontrast hra vystavuje?", "options": ["Chudoba vs. miliarda; morálka vs. peníze", "Moře vs. hory", "Den vs. noc", "Práce vs. lenost"], "correct": 0, "expl": "Základní konflikt Návštěvy staré dámy."}, - {"prompt": "Proč je Ill „starý“ v titulku?", "options": ["Claire je starší dáma vracející se pomstít mladistvé křivdě", "Ill je stařec", "Titul ne souvisí", "Jde o babičku Illa"], "correct": 0, "expl": "Návštěva bohaté starší ženy mění osud města."}, - {"prompt": "Které dílo NENÍ Dürrenmattovo?", "options": ["Návštěva staré dámy", "Fyzici", "R.U.R.", "Ministryně"], "correct": 2, "expl": "R.U.R. napsal Karel Čapek."}, - {"prompt": "Jaký morální test hra klade?", "options": ["Zda společnost prodá život za peníze", "Zda umíte plavat", "Zda znáte latinu", "Zda vaříte"], "correct": 0, "expl": "Güllen selže – universalní varování."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Claire Zachanassian přijede do Güllenu", - "Nabídne miliardu za Illovu smrt", - "Občané protestují, ale začnou nakupovat na dluh", - "Ill chápe, že je odsouzen", - "Město Illa formálně odsoudí", - "Ill zemře, Güllen dostane miliardu" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: příjezd Claire → nabídka → nákupy → Illův strach → soud → smrt a peníze." - ] -} diff --git a/data/cetba/nebe-nezna-vyvolenych.json b/data/cetba/nebe-nezna-vyvolenych.json deleted file mode 100644 index df9bc91..0000000 --- a/data/cetba/nebe-nezna-vyvolenych.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Erich Maria Remarque", - "Žánr: román; emigrantská / láskyplná próza", - "Poprvé vydáno: 1961 (Der Himmel kennt keine Günstlinge)", - "Děj: 2. světová válka, emigranti v Paříži a okolí", - "Vyprávění: er-forma; prožitkový styl" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "2. světová válka – útěk před nacismem, bezdomoví.", - "Paříž emigrantů, strach z gestapa a udání.", - "Láska v nestabilitě – Joan a Ravic.", - "Lékař bez papírů, ilegální praxe.", - "Humanismus vs. totalita.", - "Téma: osud, náhoda, křehkost štěstí." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ravic – německý emigrant, lékař v ilegalitě.", - "Joan Madou – jeho milovaná, křehká osud.", - "Boris Morosow – Ravicův přítel, společník osudu.", - "Policejní komisař – hrozba zatčení.", - "Emigrantská komunita – sdílený strach.", - "Bezdorf – místo Ravicova úkrytu (v díle)." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Emigrace – základní situace hrdinů.", - "Bezpapírovost – bezpráví a nejistota.", - "Láska ve válce – krátké štěstí.", - "Osud – nebe nezná vyvolené (titul).", - "Lékařská etika – Ravic pomáhá i v ilegalitě.", - "Tragický konec – Joanina smrt." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Nebe nezná vyvolených?", "options": ["Erich Maria Remarque", "Hemingway", "Hrabal", "Kafka"], "correct": 0, "expl": "Remarque po válce a emigrantských tématech."}, - {"prompt": "Kdy román vyšel?", "options": ["1961", "1929", "1945", "2000"], "correct": 0, "expl": "Německy Der Himmel kennt keine Günstlinge."}, - {"prompt": "Kdo je Ravic?", "options": ["Německý emigrant a lékař", "Francouzský generál", "Nacista", "Dítě"], "correct": 0, "expl": "Ravic uprchl před režimem a pracuje v Paříži ilegálně."}, - {"prompt": "Kdo je Joan Madou?", "options": ["Ravicova milovaná", "Gestapanka", "Královna", "Učitelka"], "correct": 0, "expl": "Joan je křehká postava lásky ve válce."}, - {"prompt": "Kde se děj převážně odehrává?", "options": ["Paříž a okolí emigrace", "Praha 1348", "Verona", "Moskva"], "correct": 0, "expl": "Emigrantská Paříž za 2. světové války."}, - {"prompt": "Co znamená titul?", "options": ["Bohatí vyhrávají", "Osud nešetří nikoho – nebe nemá oblíbence", "Nebe je modré", "Titul bez významu"], "correct": 1, "expl": "I láska a dobré úmysly končí tragicky."}, - {"prompt": "Jaký je vztah k Na západní frontě klid?", "options": ["Stejný autor – válka a ztráta", "Stejný děj", "Kafka napsal oba", "Bez souvislosti"], "correct": 0, "expl": "Remarque pokračuje v humanistických válečných tématech."}, - {"prompt": "Proč je Ravic v nebezpečí?", "options": ["Emigrant bez dokladů, hrozí gestapo", "Je bohatý", "Je král", "Je na dovolené"], "correct": 0, "expl": "Bezpapírovost znamená neustálý strach."}, - {"prompt": "Kdo je Boris Morosow?", "options": ["Ravicův přítel v emigraci", "Nacista", "Joanin bratr", "Robot"], "correct": 0, "expl": "Boris sdílí osud uprchlíků."}, - {"prompt": "Jak román končí pro Joan?", "options": ["Šťastně v Americe", "Tragicky umírá", "Stane se lékařkou", "Vdá se za jiného"], "correct": 1, "expl": "Tragický konec potvrzuje titul – osud nešetří."}, - {"prompt": "Jaký je hlavní konflikt?", "options": ["Láska a přežití vs. válka a pronásledování", "Sport", "Robotí vzpoura", "Středověké turnaje"], "correct": 0, "expl": "Emigranti hledají lidskost uprostřed války."}, - {"prompt": "Proč je román důležitý pro maturitu?", "options": ["Učí chemii", "Remarque, 2. sv. válka, emigrace, láska, osud", "Je atlas", "Je cookbook"], "correct": 1, "expl": "U maturity: autor, postavy, témata, kontext."}, - {"prompt": "Jak Ravic pomáhá lidem?", "options": ["Jako lékař i v ilegalitě", "Jako generál", "Jako kněz", "Nepomáhá"], "correct": 0, "expl": "Lékařská etika přetrvává navzdory riziku."}, - {"prompt": "Co je typické pro Remarqueův styl?", "options": ["Prožitková ich/er próza, jednoduchost a cit", "Pouze humor Haška", "Drama Shakespeara", "Sci-fi"], "correct": 0, "expl": "Remarque píše srozumitelně o těžkých tématech."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Emigrace", "Láska", "Vzpoura robotů R.U.R.", "Válka"], "correct": 2, "expl": "Roboti nepatří k Remarqueovi."}, - {"prompt": "Co hrozí emigrantům?", "options": ["Zatčení, udání, deportace", "Pouze daň", "Sport", "Nic"], "correct": 0, "expl": "Gestapo a kolaborace – stálý strach."}, - {"prompt": "Jaký je vztah Ravic–Joan?", "options": ["Láska v nestabilním světě", "Sourozenci", "Nepřátelé", "Učitel–žák"], "correct": 0, "expl": "Krátké štěstí uprostřed nejistoty."}, - {"prompt": "Která postava NENÍ v románu?", "options": ["Ravic", "Joan", "Paul Bäumer jako hlavní hrdina tohoto románu", "Boris"], "correct": 2, "expl": "Paul Bäumer je hrdina Na západní frontě klid."}, - {"prompt": "Co symbolizuje „vyvolení“ v titulku?", "options": ["Iluzi, že osud někoho chrání", "Sportovní tým", "Náboženský řád", "Banku"], "correct": 0, "expl": "Nikdo není chráněn – ani milenci."}, - {"prompt": "Jaká válka formuje děj?", "options": ["2. světová", "Thirty years war only", "Antická", "Budoucí sci-fi"], "correct": 0, "expl": "Nacismus a emigrace jsou klíčové."}, - {"prompt": "Kde Remarque často situoval emigranty?", "options": ["Západní Evropa (Paříž)", "Antarktida", "Měsíc", "Pouze Berlín"], "correct": 0, "expl": "Paříž je centrum exilu v románu."}, - {"prompt": "Jaký tón má závěr?", "options": ["Tragický", "Čistá komedie", "Beletrie pro děti", "Technický manuál"], "correct": 0, "expl": "Remarque neustále balancuje naději a ztrátu."}, - {"prompt": "Co je „bezpapírovost“?", "options": ["Stav ilegality bez ochrany státu", "Bohatství", "Vojenský řád", "Umění"], "correct": 0, "expl": "Bez dokladů jsi vydán na milost okolností."}, - {"prompt": "Které dílo NENÍ Remarqueovo?", "options": ["Nebe nezná vyvolených", "Na západní frontě klid", "Proměna", "Tři kamarádi"], "correct": 2, "expl": "Proměnu napsal Kafka."}, - {"prompt": "Jak vyprávění funguje?", "options": ["Er-forma, soustředěná na prožitky", "Drama pěti dějství", "Epos", "Pouze dopisy"], "correct": 0, "expl": "Remarque využívá klasickou prózu."}, - {"prompt": "Proč Joan patří k „křehkým“ postavám?", "options": ["Osud ji zasáhne tvrdě navzdory lásce", "Je nezranitelná", "Je robot", "Je generál"], "correct": 0, "expl": "Joan ztělesňuje zranitelnost ve válce."}, - {"prompt": "Co emigrantská komunita sdílí?", "options": ["Strach, pomoc, osud", "Pouze bohatství", "Válku proti robotům", "Sport"], "correct": 0, "expl": "Solidarita i zrada – reálný exil."}, - {"prompt": "Jaký humanismus Remarque prosazuje?", "options": ["Soucit s oběťmi války a pronásledování", "Válka je sláva", "Pouze moc", "Technokracie"], "correct": 0, "expl": "Lidé na útěku zůstávají lidmi."}, - {"prompt": "Které období autor prožil?", "options": ["1. i 2. světová válka, emigrace", "Středověk", "Antika", "Jen 21. století"], "correct": 0, "expl": "Remarque znal válku i exil z vlastní zkušenosti."}, - {"prompt": "Co čtenář má po dočtení cítit?", "options": ["Váhu osudu a křehkosti míru", "Pouze smích", "Návod na daň", "Nic"], "correct": 0, "expl": "Román je varování i elegie."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Ravic jako emigrant v Paříži", - "Seznámení s Joan a láska", - "Ilegální lékařská pomoc a strach z gestapa", - "Přátelství s Borisem, útěky a úkryty", - "Krátké štěstí milenců", - "Tragický osud Joan – nebe nešetří" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: exil → láska → ilegalita → přátelství → štěstí → tragický konec." - ] -} diff --git a/data/cetba/o-mysich-a-lidech.json b/data/cetba/o-mysich-a-lidech.json deleted file mode 100644 index 018d7de..0000000 --- a/data/cetba/o-mysich-a-lidech.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: John Steinbeck", - "Žánr: novela / sociální próza", - "Poprvé vydáno: 1937", - "Děj: Kalifornie za Velké krize, ranch a chudí dělníci", - "Vyprávění: er-forma; realistický, soucitný styl" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Velká krize 30. let – chudoba, tuláci, práce na rancích.", - "Sen o vlastní půdě – „farma s králíky“.", - "Osamělost a přátelství mužů bez rodin.", - "Sociální bezpráví vůči slabším (Curleyova žena, Crooks).", - "Násilí a nešťastná náhoda ničí sen.", - "Téma: sen, přátelství, osamělost, lidskost." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "George Milton – chytrý, opatruje Lennieho.", - "Lennie Small – silný, mentálně neschopný, miluje zvířata.", - "Curley – syn majitele, agresivní.", - "Curleyova žena – osamělá, nešťastná.", - "Crooks – černý stableman, vyloučený.", - "Candy – starý dělník se psem." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Sen o farmě – naděje a útěk.", - "Přátelství George–Lennie – ochrana slabšího.", - "Osamělost – ranch bez vazeb.", - "Neschopnost Lennie – tragický prvek.", - "Zabití psa / králíka – předznamenání konce.", - "Georgeovo rozhodnutí – milosrdná střela." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal O myších a lidech?", "options": ["Hemingway", "John Steinbeck", "Fitzgerald", "Twain"], "correct": 1, "expl": "Steinbeck, 1937 – klasika americké sociální prózy."}, - {"prompt": "Kdo je Lennie Small?", "options": ["Silný muž s mentálním postižením", "Majitel ranch", "Kněz", "Detektiv"], "correct": 0, "expl": "Lennie je fyzicky silný, ale důvěřivý a neschopný."}, - {"prompt": "Kdo je George?", "options": ["Lennieho ochránce a přítel", "Curley", "Šerif", "Lékař"], "correct": 0, "expl": "George Lennie vede a chrání ho."}, - {"prompt": "O jaký sen usilují?", "options": ["Vlastní farma a „žít ze své půdy“", "Let do vesmíru", "Královský trůn", "Robotí továrna"], "correct": 0, "expl": "Sen o králících a soběstačnosti."}, - {"prompt": "Proč Lennie miluje měkké zvířata?", "options": ["Rád je hladí, ale neovládá sílu", "Nenávidí zvířata", "Je veterinář", "Je alergický"], "correct": 0, "expl": "Nešťastně zabíjí myši i psa – sila bez kontroly."}, - {"prompt": "Kdo je Curley?", "options": ["Agresivní syn majitele ranch", "Lennieho bratr", "Učitel", "Emigrant"], "correct": 0, "expl": "Curley provokuje Lennieho."}, - {"prompt": "Co se stane Curleyově ruce?", "options": ["Lennie ji zlomí v sebeobraně", "Spadne z koně", "Amputace v nemocnici", "Nic"], "correct": 0, "expl": "Lennie v panice zmačká Curleyovu ruku."}, - {"prompt": "Kdo je Crooks?", "options": ["Černý stableman vyloučený rasismem", "Majitel", "Curley", "George"], "correct": 0, "expl": "Crooks žije sám v stáji – téma osamělosti."}, - {"prompt": "Kdo je Candy?", "options": ["Starý dělník se starým psem", "Dítě", "Curleyova žena", "Kněz"], "correct": 0, "expl": "Carlson Candyho psa zastřelí – předobraz konce."}, - {"prompt": "Proč Carlson zastřelí Candyho psa?", "options": ["Je starý a trpí – „milosrdné“ zabití", "Pes kousl", "Pes byl bohatý", "Na rozkaz"], "correct": 0, "expl": "Scéna předznamenává Georgeovo rozhodnutí."}, - {"prompt": "Co Lennie udělá Curleyově ženě?", "options": ["Omylem ji zabije při hladění vlasů", "Ožení se s ní", "Uteče s ní", "Nic"], "correct": 0, "expl": "Tragická náhoda – Lennie nechápe sílu."}, - {"prompt": "Jak George končí s Lenniem?", "options": ["Zastřelí ho milosrdně, než ho lynch mob", "Opustí ho", "Pošle do vězení", "Neudělá nic"], "correct": 0, "expl": "George zabije Lennie sám – akt lásky a bolesti."}, - {"prompt": "Kdy román vyšel?", "options": ["1937", "1957", "1915", "2005"], "correct": 0, "expl": "Období Velké krize."}, - {"prompt": "Kde se děj odehrává?", "options": ["Kalifornie, ranch", "Praha", "Verona", "Sibiř"], "correct": 0, "expl": "Migrantní dělníci na farmě."}, - {"prompt": "Jaký je hlavní konflikt?", "options": ["Sen vs. realita; Lennieho neschopnost", "Válka robotů", "Královský spor", "Detektivka"], "correct": 0, "expl": "Přátelství a sen narazí na tragédii."}, - {"prompt": "Proč je román důležitý pro maturitu?", "options": ["Učí chemii", "Steinbeck, Velká krize, postavy, sen, tragédie", "Je atlas", "Je cookbook"], "correct": 1, "expl": "U maturity: autor, postavy, témata osamělosti."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Osamělost", "Přátelství", "Vzpoura robotů", "Sen o farmě"], "correct": 2, "expl": "Roboti nejsou Steinbeck."}, - {"prompt": "Co znamená název (od Burns)?", "options": ["Plány myší i lidí často zmaří osud", "Myši vládnou světu", "Lidé jsou myši", "Bez významu"], "correct": 0, "expl": "Parafráze básně – křehkost plánů."}, - {"prompt": "Jak Curleyova žena trpí?", "options": ["Osamělostí na ranchi", "Bohatstvím", "Mocí", "Nic"], "correct": 0, "expl": "Chce mluvit, sní o slávě – tragická postava."}, - {"prompt": "Kdo je Slim?", "options": ["Respektovaný dělník na ranchi", "Majitel banky", "Nacista", "Dítě"], "correct": 0, "expl": "Slim chápe Georgeovo rozhodnutí na konci."}, - {"prompt": "Jaký je styl Steinbecka?", "options": ["Realismus, soucit, jednoduchost", "Groteska Haška", "Sci-fi", "Epos"], "correct": 0, "expl": "Steinbeck píše o chudých s empatií."}, - {"prompt": "Která postava NENÍ v románu?", "options": ["Lennie", "George", "Winston Smith", "Candy"], "correct": 2, "expl": "Winston je z 1984."}, - {"prompt": "Proč George s Lenniem cestuje?", "options": ["Hledají práci jako migranti", "Jsou králové", "Studují", "Jsou na dovolené"], "correct": 0, "expl": "Velká krize – tuláci od ranch k ranchi."}, - {"prompt": "Co Lennie opakuje?", "options": ["Georgeovy instrukce a sen o farmě", "Latinské modlitby", "Rozkazy Curleye", "Nic"], "correct": 0, "expl": "Lennie se učí, co dělat „když se něco stane“."}, - {"prompt": "Jak končí sen o farmě?", "options": ["Ztroskotá – Lennie i sen mrtví", "Uskuteční se", "Koupí město", "Stane se sci-fi"], "correct": 0, "expl": "Tragédie – sen zůstane nedosažitelný."}, - {"prompt": "Které dílo NENÍ Steinbeckovo?", "options": ["O myších a lidech", "Na východ od ráje", "Grapes of Wrath (Hrozny hněvu)", "Revizor"], "correct": 3, "expl": "Revizor je Gogol."}, - {"prompt": "Co představuje psí zabití?", "options": ["Předfiguraci milosrdného zabití Lennieho", "Komediální vtip", "Sport", "Náboženský obřad"], "correct": 0, "expl": "Steinbeck připravuje čtenáře na konec."}, - {"prompt": "Jaký je vztah k Velké krizi?", "options": ["Román zobrazuje chudobu a migraci", "Ignoruje ekonomiku", "Je fantasy", "Je středověk"], "correct": 0, "expl": "Kontext 30. let je klíčový."}, - {"prompt": "Proč George neuteče s Lenniem?", "options": ["Ví, že Lennie opakovat chybu – musí jednat", "Nemá nohy", "Je bohatý", "Lennie je generál"], "correct": 0, "expl": "George přijme zodpovědnost – tragický akt."}, - {"prompt": "Jaký pocit zanechá závěr?", "options": ["Soucit a bolest", "Čistou radost", "Smích bez důvodu", "Nic"], "correct": 0, "expl": "Klasická americká tragédie chudých."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "George a Lennie přijdou na ranch", - "Sen o farmě, setkání s Curleyem", - "Lennie zlomí Curleyovu ruku", - "Carlson zastřelí Candyho psa", - "Lennie zabije Curleyovu ženu", - "George Lennie milosrdně zastřelí" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: ranch → konflikt s Curleyem → ruka → pes → smrt ženy → milosrdná střela." - ] -} diff --git a/data/cetba/obraz-doriana-graye.json b/data/cetba/obraz-doriana-graye.json deleted file mode 100644 index a83b063..0000000 --- a/data/cetba/obraz-doriana-graye.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Oscar Wilde", - "Žánr: philosophický / gotický román", - "Poprvé vydáno: 1890 (revidováno 1891)", - "Děj: Londýn fin de siècle, společnost a moralita", - "Vyprávění: er-forma; epigramy, estetika" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Victoriánská Anglie – puritanismus vs. estetismus.", - "Umění pro umění, hedonismus lorda Henryho.", - "Dvojí život Doriana – krása navenek, shniloba v obraze.", - "Skandály, opium, vražda – morální pokles.", - "Gotický prvek: portrét nesoucí viny.", - "Téma: krása, morálka, vina, umění." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Dorian Gray – mladík neuvěřitelné krásy.", - "Basil Hallward – malíř, autor portrétu.", - "Lord Henry Wotton – cynický hedonista, vpliv.", - "Sibyl Vane – herečka, Dorianova první oběť.", - "James Vane – Sibylin bratr, pomsta.", - "Portrét – zrcadlo Dorianovy duše." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Portrét – nese stárnutí a zločiny místo Doriana.", - "Estetismus – krása nad morálkou (Henry).", - "Hedonismus – hledání rozkoší.", - "Dvojí život – společenská maska.", - "Zrcadlo / obraz – symbol viny.", - "Závěr – Dorian bodne portrét, umírá sám." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Obraz Doriana Graye?", "options": ["Dickens", "Oscar Wilde", "Austen", "Brontë"], "correct": 1, "expl": "Wilde, irský autor, estet a dramatik."}, - {"prompt": "Co je zvláštní na Dorianově portrétu?", "options": ["Stárne a kazí se místo Doriana", "Je prázdný", "Mění autora", "Je fotografie"], "correct": 0, "expl": "Dorian zůstává mladý, vina se hromadí v obraze."}, - {"prompt": "Kdo portrét maluje?", "options": ["Basil Hallward", "Lord Henry", "Sibyl", "James"], "correct": 0, "expl": "Basil obdivuje Dorianovu krásu."}, - {"prompt": "Kdo Doriana morally kazí?", "options": ["Lord Henry Wotton", "Basil", "Sibyl", "Kněz"], "correct": 0, "expl": "Henry hlásá hedonismus a cynismus."}, - {"prompt": "Kdo je Sibyl Vane?", "options": ["Herečka, kterou Dorian zničí", "Malířka", "Královna", "Basilova sestra"], "correct": 0, "expl": "Dorian ji opustí – ona spáchá sebevraždu."}, - {"prompt": "Co Dorian přeje u portrétu?", "options": ["Aby stárl obraz místo něj", "Aby zmizel", "Aby byl bohatý", "Aby byl král"], "correct": 0, "expl": "Faustovská touha – splní se groteskně."}, - {"prompt": "Jak Dorian skrývá stárnutí?", "options": ["Portrét schovává v pokoji", "Operace", "Kouzlo bez obrazu", "Ne skrývá"], "correct": 0, "expl": "Obraz je tajné zrcadlo duše."}, - {"prompt": "Co se stane Basilovi?", "options": ["Dorian ho zavraždí", "Basil se stane králem", "Emigruje", "Nic"], "correct": 0, "expl": "Basil konfrontuje Doriana – Dorian ho zabije."}, - {"prompt": "Kdo hledá pomstu?", "options": ["James Vane, bratr Sibylin", "Lord Henry", "Basil", "Sibyl"], "correct": 0, "expl": "James pronásleduje Doriana."}, - {"prompt": "Jak román končí?", "options": ["Dorian bodne portrét a sám zemře stařec", "Šťastná svatba", "Dorian vládne", "Obraz zmizí"], "correct": 0, "expl": "Katharsis – vina se vrátí na Doriana."}, - {"prompt": "Jaký je žánr?", "options": ["Philosophický/gotický román", "Válečný román", "Sci-fi", "Bajka"], "correct": 0, "expl": "Gotický prvek portrétu + estetická filozofie."}, - {"prompt": "Co znamená estetismus?", "options": ["Umění a krása jako nejvyšší hodnota", "Válka", "Robotika", "Asketa"], "correct": 0, "expl": "Wilde a Henry ztělesňují „umění pro umění“."}, - {"prompt": "Proč je kniha důležitá pro maturitu?", "options": ["Učí chemii", "Wilde, symbolika portrétu, morálka, estetika", "Je atlas", "Je cookbook"], "correct": 1, "expl": "U maturity: autor, postavy, symboly, témata."}, - {"prompt": "Kdy román poprvé vyšel?", "options": ["1890/1891", "1929", "2000", "1595"], "correct": 0, "expl": "Victoriánská éra, skandál kvůli morálce."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Krása a vina", "Portrét jako zrcadlo", "Vzpoura robotů", "Hedonismus"], "correct": 2, "expl": "Roboti nejsou Wilde."}, - {"prompt": "Jak lord Henry mluví?", "options": ["Epigramy, paradox, cynismus", "Prostě bez stylu", "Jen latinsky", "Německy"], "correct": 0, "expl": "Wildeovy aforismy jsou slavné."}, - {"prompt": "Co Dorian sbírá?", "options": ["Morální prach – skandály, zločiny", "Známky", "Roboty", "Mapy"], "correct": 0, "expl": "Hedonismus vede k degeneraci."}, - {"prompt": "Kdo je James Vane?", "options": ["Sibylin bratr", "Malíř", "Lord", "Basil"], "correct": 0, "expl": "Pomsta za sestru."}, - {"prompt": "Jaký kontrast román staví?", "options": ["Krása navenek vs. hnus duše", "Moře vs. hory", "Den vs. noc", "Práce vs. lenost"], "correct": 0, "expl": "Základní gothic premise."}, - {"prompt": "Která postava NENÍ v románu?", "options": ["Dorian", "Henry", "Elizabeth Bennet", "Basil"], "correct": 2, "expl": "Elizabeth je Austenová."}, - {"prompt": "Co symbolizuje opium?", "options": ["Únik a morální propad", "Sport", "Věda", "Náboženský rituál"], "correct": 0, "expl": "Dorian hledá rozkoše v temnotě."}, - {"prompt": "Jak Wilde kritizuje společnost?", "options": ["Přes hypokrizii a estetickou masku", "Oslavou války", "Bez myšlenky", "Pouze humorem Haška"], "correct": 0, "expl": "Victoriánská puritánství vs. skrytá shniloba."}, - {"prompt": "Které dílo NENÍ Wildovo?", "options": ["Obraz Doriana Graye", "How I Became a Happy Ghost – ne; Importance of Being Earnest", "Revizor", "Ballad of Reading Gaol"], "correct": 2, "expl": "Revizor je Gogol."}, - {"prompt": "Proč Basil umírá?", "options": ["Konfrontuje Doriana s pravdou o portrétu", "Náhodou", "Válka", "Starost"], "correct": 0, "expl": "Dorian zabije svědka své duše."}, - {"prompt": "Jak vypadá Dorian navenek roky?", "options": ["Stále mladý a krásný", "Okamžitě starý", "Jako dítě", "Jako zvíře"], "correct": 0, "expl": "Zatímco obraz nesou věk a viny."}, - {"prompt": "Co čtenář má pochopit z konce?", "options": ["Vina se nedá věčně přenést na obraz", "Krása vítězí vždy", "Umění je zbytečné", "Nic"], "correct": 0, "expl": "Moralita se vrátí – Dorian platí."}, - {"prompt": "Jaký je vztah Basil–Dorian?", "options": ["Basil obdivuje, Dorian zrazuje", "Nepřátelé od začátku", "Bratři", "Učitel latiny"], "correct": 0, "expl": "Basilova láska ke kráse končí tragicky."}, - {"prompt": "Kde se děj odehrává?", "options": ["Londýn a okolí", "Praha", "Verona", "Sibiř"], "correct": 0, "expl": "Společenský život victoriánské metropole."}, - {"prompt": "Co je gotický prvek?", "options": ["Prokletý portrét a tajemný pokoj", "Robot", "Válka", "Komunismus"], "correct": 0, "expl": "Gotika: nadprirodzeno, vina, hrůza."}, - {"prompt": "Jak Wilde v románu pracuje s estetikou?", "options": ["Klade krásu a umění proti morálce a pokání", "Odmítá umění úplně", "Píše jen učebnici", "Popisuje pouze válku"], "correct": 0, "expl": "Lord Henry a Dorian ztělesňují estetismus – cena je morální shniloba."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Basil maluje portrét, Dorian se setká s lordem Henrym", - "Dorian přeje, aby stárl obraz místo něj", - "Vztah se Sibyl Vane a její smrt", - "Dorian žije hedonisticky, obraz se kazí", - "Dorian zavraždí Basila", - "Dorian bodne portrét a sám zemře" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: portrét a Henry → přání → Sibyl → degenerace → vražda Basila → konec s portrétem." - ] -} diff --git a/data/cetba/obsluhoval-jsem.json b/data/cetba/obsluhoval-jsem.json deleted file mode 100644 index c521d6f..0000000 --- a/data/cetba/obsluhoval-jsem.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Bohumil Hrabal", - "Žánr: román / novela s pikareskními rysy", - "Poprvé vydáno: 1971 (česky; různá vydání)", - "Děj: 20. století očima číšníka Dita", - "Vyprávění: ich-forma; hrabalovská řeč, groteska" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Od první republiky přes protektorát po poválečný socialismus.", - "Hotely a hostince jako jeviště dějin shora.", - "Ditie touží po uznání a „velikosti“.", - "Komplice s mocí, trest, normalizace.", - "Groteska mísí smích s tragédií.", - "Téma: malý člověk, dějiny, vinna, touha." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ditě (Jan Ditie) – vypravěč, číšník.", - "Líza – láska, spojená s Ditieho vzestupem.", - "Hoteloví hosté – politici, Němci, elita.", - "Tichý Šimon – poválečný soudce Ditieho osudu.", - "Protektorátní moc – pokušení kolaborace.", - "Dítě (syn) – naděje a ztráta." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Pohled zdola – servis vidí moc zblízka.", - "Touha po velikosti – Ditieho motor.", - "Kolaborace – servírování mocným.", - "Groteska – Hrabalův humor i děs.", - "Hotel – mikrokosmos století.", - "Soud / Tichý Šimon – morální bilance." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Obsluhoval jsem anglického krále?", "options": ["Hašek", "Bohumil Hrabal", "Kundera", "Neruda"], "correct": 1, "expl": "Hrabal, 1971 – jedna z maturitních četeb."}, - {"prompt": "Kdo vypravuje?", "options": ["Jan Ditě, číšník", "Anglický král", "Švejk", "Kafka"], "correct": 0, "expl": "Ich-forma Ditieho vzpomínek."}, - {"prompt": "Proč je v názvu „anglický král“?", "options": ["Ditie obsluhuje i symboly moci (včetně exilového krále)", "Děj je jen v Anglii", "Ditie je král", "Bez souvislosti"], "correct": 0, "expl": "Ironický titul – servírování mocných v historii."}, - {"prompt": "Jaké období román pokrývá?", "options": ["20. století v Čechách", "Středověk", "Antika", "Budoucnost"], "correct": 0, "expl": "Republika, protektorát, poválečí režimy."}, - {"prompt": "Co Ditie nejvíc touží?", "options": ["Po uznání a velikosti", "Po klidu v klášteře", "Po válce", "Po robotice"], "correct": 0, "expl": "Malý člověk chce být viděn a důležitý."}, - {"prompt": "Kdo je Líza?", "options": ["Ditieho milovaná", "Německá generálka", "Učitelka", "Robot"], "correct": 0, "expl": "Líza je spojena s Ditieho životem a vinou."}, - {"prompt": "Jaký je Hrabalův styl?", "options": ["Dlouhé věty, groteska, humor", "Strohý realismus bez obrazů", "Hexametr", "Drama"], "correct": 0, "expl": "Typická hrabalovská poetika."}, - {"prompt": "Kde Ditie pracuje?", "options": ["V hotelech a hostincích", "V dole", "Na moři", "V klášteře"], "correct": 0, "expl": "Číšnická dráha = pohled zdola."}, - {"prompt": "Co je kolaborace v románu?", "options": ["Služba mocným v protektorátu", "Sport", "Věda", "Nemoc"], "correct": 0, "expl": "Ditie se potácí mezi přežitím a morálkou."}, - {"prompt": "Kdo je Tichý Šimon?", "options": ["Poválečný soudce Ditieho", "Král", "Německý generál", "Dítě"], "correct": 0, "expl": "Symbol účtování po válce."}, - {"prompt": "Jak román pracuje s dějinami?", "options": ["Anekdoticky z perspektivy servisu", "Ignoruje je", "Jen učebnicově", "Sci-fi"], "correct": 0, "expl": "Velké dějiny v malých hotelových scénách."}, - {"prompt": "Proč je kniha důležitá pro maturitu?", "options": ["Učí chemii", "Hrabal, 20. stol., ich-forma, groteska, témata", "Je atlas", "Je cookbook"], "correct": 1, "expl": "U maturity: autor, kontext, Ditie, styl."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Touha po uznání", "Dějiny zdola", "Vzpoura robotů R.U.R.", "Vinna"], "correct": 2, "expl": "Roboti nejsou Hrabal."}, - {"prompt": "Co je groteska u Hrabala?", "options": ["Smích vedle hrůzy", "Pouze pohádka", "Bez humoru", "Jen válka"], "correct": 0, "expl": "Typický Hrabalův mix."}, - {"prompt": "Jak Ditie vzpomíná?", "options": ["Ve vzpomínkách číšníka na konci života", "Jako dítě", "Jako robot", "Bez já"], "correct": 0, "expl": "Retrospektivní ich-forma."}, - {"prompt": "Která postava NENÍ Hrabalova?", "options": ["Ditě", "Miloš Hrma", "Líza", "Tichý Šimon"], "correct": 1, "expl": "Miloš Hrma je z Ostře sledovaných vlaků."}, - {"prompt": "Co symbolizuje hotel?", "options": ["Jeviště setkání s mocí", "Vězení", "Kostel", "Lesk bez významu"], "correct": 0, "expl": "Místo, kde malý člověk servíruje velkým."}, - {"prompt": "Jak končí Ditieho touha po velikosti?", "options": ["Ironicky a tragicky – malost zůstane", "Stane se králem", "Vítězí vždy", "Bez pointy"], "correct": 0, "expl": "Hrabal demaskuje iluzi slávy."}, - {"prompt": "Kdy román vyšel?", "options": ["1971", "1921", "1890", "2015"], "correct": 0, "expl": "Poválečná reflexe v normalizační době."}, - {"prompt": "Co je pikareskní rys?", "options": ["Putování a epizody „lišáka“", "Epos", "Tragedie", "Lyrika"], "correct": 0, "expl": "Ditie prochází místy a režimy."}, - {"prompt": "Jaký vztah k protektorátu?", "options": ["Moralní krize servírování okupantům", "Ignorace", "Pouze hrdinství", "Sci-fi"], "correct": 0, "expl": "Kolaborace jako téma."}, - {"prompt": "Které dílo NENÍ Hrabalovo?", "options": ["Obsluhoval jsem anglického krále", "Ostře sledované vlaky", "Revizor", "Příliš hlučná samota"], "correct": 2, "expl": "Revizor je Gogol."}, - {"prompt": "Proč ich-forma?", "options": ["Subjektivní vinna a vzpomínka", "Objektivní učebnice", "Bez vypravěče", "Drama"], "correct": 0, "expl": "Ditie sám bilancuje život."}, - {"prompt": "Co Ditie „obsluhuje“ metaforicky?", "options": ["Moc a dějiny bez vlastní velikosti", "Pouze jídlo", "Roboty", "Hvězdy"], "correct": 0, "expl": "Servis = podřízenost vůči moci."}, - {"prompt": "Jak Hrabal líčí malého člověka?", "options": ["S humorem i soucitem", "S nenávistí", "Bez charakteru", "Jako hrdinu války"], "correct": 0, "expl": "Typický Hrabalův přístup."}, - {"prompt": "Co je motiv syna / dítěte?", "options": ["Naděje a ztráta v Ditieho životě", "Robot", "Král", "Učitel"], "correct": 0, "expl": "Osobní rovina vedle historické."}, - {"prompt": "Jaký kontrast Hrabal používá?", "options": ["Velké dějiny vs. hotelový servis", "Moře vs. hory", "Den vs. noc", "Práce vs. lenost"], "correct": 0, "expl": "Základní poetika knihy."}, - {"prompt": "Kde se děj odehrává?", "options": ["Čechy (hotely, okolí)", "Verona", "Londýn celý román", "Mars"], "correct": 0, "expl": "České dějiny 20. století."}, - {"prompt": "Co čtenář má po dočtení?", "options": ["Pochopení Hrabalovy grotesky a historie zdola", "Návod na servis", "Chemii", "Nic"], "correct": 0, "expl": "Maturitní cíl – kontext a témata."}, - {"prompt": "Jak Ditie vnímá sebe?", "options": ["Chce být velký, často je směšný", "Vždy hrdina", "Robot", "Císař"], "correct": 0, "expl": "Tragičnost i komika ega."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Mladý Ditě začíná jako číšník", - "Vzestup v hotelech, setkání s mocí", - "Protektorát – obsluha okupantů", - "Líza a osobní i politické krize", - "Poválečné soudy a Tichý Šimon", - "Bilance života malého člověka" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: začátky → vzestup → protektorát → Líza → soud → bilance." - ] -} diff --git a/data/cetba/oliver-twist.json b/data/cetba/oliver-twist.json deleted file mode 100644 index df04b7c..0000000 --- a/data/cetba/oliver-twist.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Charles Dickens", - "Žánr: sociální román", - "Poprvé vydáno: 1837–1839 (seriálově)", - "Děj: Londýn 19. století, chudoba a kriminality", - "Vyprávění: er-forma; realistický, sentimentální styl" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Victoriánská Anglie – chudobinci, sirotčince.", - "Kriminalita, gangy, Faginova dílna.", - "Sociální kritika třídní nespravedlnosti.", - "Oliver jako symbol nevinnosti.", - "Od sirotčince k pravdě o původu.", - "Téma: chudoba, spravedlnost, identita." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Oliver Twist – sirotek, dobré srdce.", - "Fagin – starý Žid, vede gang zlodějů.", - "Bill Sikes – brutální lupič.", - "Nancy – oběť, pomáhá Oliverovi.", - "Pan Brownlow – dobrodinec.", - "Monks – Oliverův nevlastní bratr." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Sirotčinec – krutost systému.", - "„Prosím, pane, chci ještě“ – slavná scéna.", - "Gang – Fagin, Sikes, Artful Dodger.", - "Dědictví – tajemství Oliverova původu.", - "Nancy – oběť i statečnost.", - "Happy-end – spravedlnost pro Olivera." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Oliver Twist?", "options": ["Austen", "Charles Dickens", "Wilde", "Brontë"], "correct": 1, "expl": "Dickens, 1837–1839 – sociální román."}, - {"prompt": "Kdo je Oliver?", "options": ["Sirotek v Londýně", "Král", "Generál", "Robot"], "correct": 0, "expl": "Hrdina nevinnosti v chudobě."}, - {"prompt": "Co Oliver řekne v sirotčinci?", "options": ["Prosím, pane, chci ještě (jídla)", "Chci válku", "Jsem král", "Nic"], "correct": 0, "expl": "Slavná scéna trestu za prosbu."}, - {"prompt": "Kdo je Fagin?", "options": ["Vůdce gangu zlodějů", "Kněz", "Oliverův otec", "Lékař"], "correct": 0, "expl": "Vychovává děti ke krádežím."}, - {"prompt": "Kdo je Bill Sikes?", "options": ["Brutální lupič", "Učitel", "Brownlow", "Dodger"], "correct": 0, "expl": "Násilník, partner Nancy."}, - {"prompt": "Kdo je Nancy?", "options": ["Dívka z gangu, pomůže Oliverovi", "Královna", "Faginova sestra", "Učitelka"], "correct": 0, "expl": "Tragická postava – zradí gang, zaplatí životem."}, - {"prompt": "Kdo je pan Brownlow?", "options": ["Dobrodinec, který Olivera zachrání", "Fagin", "Sikes", "Monks"], "correct": 0, "expl": "Symbol dobra střední třídy."}, - {"prompt": "Kdo je Monks?", "options": ["Oliverův nevlastní bratr, chce ho zničit", "Kněz", "Dodger", "Brownlow"], "correct": 0, "expl": "Intriky kvůli dědictví."}, - {"prompt": "Kdo je Artful Dodger?", "options": ["Šikovný mladý zloděj ve Faginově gangu", "Policista", "Král", "Lékař"], "correct": 0, "expl": "Vede Olivera do kriminality."}, - {"prompt": "Jak končí Oliver?", "options": ["Šťastně u Brownlowa, pravda o původu", "Vězení", "Smrt", "Gang navždy"], "correct": 0, "expl": "Dickensovský happy-end spravedlnosti."}, - {"prompt": "Jaký je hlavní konflikt?", "options": ["Nevinnost vs. chudoba a kriminalita", "Robotí válka", "Středověk", "Detektivka bez sociálního"], "correct": 0, "expl": "Sociální román 19. století."}, - {"prompt": "Proč maturita?", "options": ["Dickens, sociální kritika, postavy", "Chemie", "Atlas", "Cookbook"], "correct": 0, "expl": "Klasická světová literatura."}, - {"prompt": "Kde děj?", "options": ["Londýn", "Praha", "Verona", "Paříž"], "correct": 0, "expl": "Victoriánský Londýn."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Chudoba", "Gang", "Vzpoura robotů", "Identita"], "correct": 2, "expl": "Čapek roboti ne."}, - {"prompt": "Co Dickens kritizuje?", "options": ["Sirotčince a chudobu", "Sport", "Hudbu", "Vědu"], "correct": 0, "expl": "Sociální nespravedlnost."}, - {"prompt": "Co se stane Nancy?", "options": ["Sikes ji zabije", "Stane se královnou", "Emigruje", "Nic"], "correct": 0, "expl": "Tragédie za pomoc Oliverovi."}, - {"prompt": "Která postava NENÍ v románu?", "options": ["Fagin", "Oliver", "Elizabeth Bennet", "Sikes"], "correct": 2, "expl": "Austenová."}, - {"prompt": "Jaký styl Dickens?", "options": ["Realismus, sentiment, humor", "Sci-fi", "Epos", "Drama antické"], "correct": 0, "expl": "Typický Dickens."}, - {"prompt": "Co je Oliverův původ?", "options": ["Tajemství bohaté rodiny – odhaleno", "Vždy chudý bez vysvětlení", "Robot", "Cizinec"], "correct": 0, "expl": "Intriky Monse."}, - {"prompt": "Kdy vyšel román?", "options": ["1837–1839", "1929", "2000", "1595"], "correct": 0, "expl": "Seriálové vydávání."}, - {"prompt": "Které dílo NENÍ Dickens?", "options": ["Oliver Twist", "David Copperfield", "Revizor", "Great Expectations"], "correct": 2, "expl": "Gogol."}, - {"prompt": "Proč Oliver unikne Faginovi?", "options": ["Brownlow a Nancy pomáhají", "Sám je generál", "Kouzlo", "Nikdy neunikne"], "correct": 0, "expl": "Boj dobra a zla."}, - {"prompt": "Co je victoriánská kritika?", "options": ["Odhalení chudoby pod průmyslem", "Oslava války", "Sci-fi", "Bez tématu"], "correct": 0, "expl": "Kontext 19. stol."}, - {"prompt": "Jak Fagin končí?", "options": ["Poprava – trest za zločin", "Král", "Bohatý", "Emigrace"], "correct": 0, "expl": "Dickensův morální soud."}, - {"prompt": "Co symbolizuje Oliver?", "options": ["Nevinnost v špinavém světě", "Válka", "Robot", "Nemoc"], "correct": 0, "expl": "Centrální metafora."}, - {"prompt": "Jak vyprávění?", "options": ["Er-forma", "Ich Oliver", "Drama", "Lyrika"], "correct": 0, "expl": "Klasický roman."}, - {"prompt": "Co je Dodger?", "options": ["Mladý zloděj", "Pes", "Král", "Učitel"], "correct": 0, "expl": "Artful = vychytralý."}, - {"prompt": "Jaký tón?", "options": ["Sociální kritika + sentiment", "Pouze horor", "Beletrie bez emocí", "Učebnice"], "correct": 0, "expl": "Dickens mísí slzy a humor."}, - {"prompt": "Proč sirotčinec?", "options": ["Ukazuje krutost vůči dětem", "Idyla", "Sport", "Věda"], "correct": 0, "expl": "Úvodní instituce zla."}, - {"prompt": "Co čtenář po dočtení?", "options": ["Chápe Dickensovu sociální linii", "Chemii", "Nic", "Mapu"], "correct": 0, "expl": "Maturitní cíl."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Oliver v sirotčinci a prosba o jídlo", - "Útěk do Londýna, Faginův gang", - "Brownlow Olivera zachrání", - "Nancy pomáhá, Sikes ji zabije", - "Odhalení Monsových intrik", - "Oliverův happy-end a identita" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: sirotčinec → gang → Brownlow → Nancy → Monks → happy-end." - ] -} diff --git a/data/cetba/ostre-sledovane-vlaky.json b/data/cetba/ostre-sledovane-vlaky.json deleted file mode 100644 index 319ebc8..0000000 --- a/data/cetba/ostre-sledovane-vlaky.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Bohumil Hrabal", - "Žánr: novela; válečná groteska", - "Poprvé vydáno: 1965", - "Děj: malá stanice v protektorátu", - "Vyprávění: ich-forma Miloše Hrmy" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Protektorát Čechy a Morava – okupace, železnice.", - "Vlaky vezou zbraně – ostře sledované.", - "Sexuální nejistota a dospívání vs. válka.", - "Humor, razítka, absurdita.", - "Malý čin odboje na konci.", - "Téma: iniciace, zbabělost, odvaha." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Miloš Hrma – mladý výpravčí, vypravěč.", - "Výpravčí Hubička – svůdník, razítka na Zdeničce.", - "Zdenička – telegrafistka.", - "Přednosta stanice – holubi, autorita.", - "Virginia / Viktoria Freie – zasvěcení Miloše.", - "Němečtí důstojníci – moc okupace." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Iniciace – sexuální i odbojová.", - "Razítka – groteskní erotický motiv.", - "Ostře sledovaný vlak – cíl sabotáže.", - "Sebevražedný pokus – Milošův stud.", - "Groteska – smích a smrt.", - "Český malý hrdinství – ironie." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Ostře sledované vlaky?", "options": ["Hašek", "Bohumil Hrabal", "Remarque", "Kafka"], "correct": 1, "expl": "Hrabal, 1965 – film J. Menzela (1966)."}, - {"prompt": "Kdo vypravuje?", "options": ["Miloš Hrma", "Hubička", "Švejk", "Ditě"], "correct": 0, "expl": "Ich-forma mladého výpravčího."}, - {"prompt": "Kdy a kde děj?", "options": ["Protektorát, malá železniční stanice", "1. sv. válka fronta", "Regency Anglie", "Verona"], "correct": 0, "expl": "Okupace a železnice."}, - {"prompt": "Co jsou „ostře sledované vlaky“?", "options": ["Vlaky se zbraněmi pro frontu", "Turistické vlaky", "Vlaky do školy", "Metro"], "correct": 0, "expl": "Němci hlídají dopravu materiálu."}, - {"prompt": "Kdo je Hubička?", "options": ["Starší výpravčí, svůdník", "Generál", "Kněz", "Dítě"], "correct": 0, "expl": "Hubička razítkuje tělo telegrafistky."}, - {"prompt": "Co je groteskní scéna s razítky?", "options": ["Hubička obtiskne razítka na Zdeniččino tělo", "Vlaky explodují", "Miloš se stane králem", "Nic"], "correct": 0, "expl": "Typická hrabalovská groteska."}, - {"prompt": "Proč Miloš pokusí sebe zabít?", "options": ["Sexuální selhání a stud", "Válka skončila", "Rád", "Na rozkaz"], "correct": 0, "expl": "Trauma dospívání ve válce."}, - {"prompt": "Kdo Miloše „zasvětí“?", "options": ["Virginia / Viktoria Freie", "Zdenička", "Hubička", "Přednosta"], "correct": 0, "expl": "Sexuální iniciace před finále."}, - {"prompt": "Jak končí novela?", "options": ["Miloš se vrhne pod vlak (sabotáž/akt)", "Svatba", "Mír 1945 slavnostně", "Miloš emigruje"], "correct": 0, "expl": "Malý čin odboje – kontroverzní hrdinství."}, - {"prompt": "Jaký je tón?", "options": ["Groteska, humor, smrt", "Pouze idyla", "Epos", "Učebnice"], "correct": 0, "expl": "Hrabal mísí erotiku, smích a válku."}, - {"prompt": "Kdo je přednosta?", "options": ["Vedoucí stanice, holubi", "Německý generál", "Milošův otec", "Robot"], "correct": 0, "expl": "Komická autorita stanice."}, - {"prompt": "Proč maturita?", "options": ["Hrabal, protektorát, groteska, film", "Chemie", "Atlas", "Cookbook"], "correct": 0, "expl": "Klasická česká maturitní četba."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Iniciace", "Válka", "Robotí vzpoura", "Odboj"], "correct": 2, "expl": "R.U.R. je jiné dílo."}, - {"prompt": "Jaký film vznikl?", "options": ["J. Menzel, Oscar 1967", "Disney", "Bez filmu", "Hollywood 2020"], "correct": 0, "expl": "Slavná adaptace Hrabal–Menzel."}, - {"prompt": "Co je Zdenička?", "options": ["Telegrafistka", "Generálka", "Královna", "Učitelka"], "correct": 0, "expl": "Objekt Hubičkova žertu."}, - {"prompt": "Jak Miloš vnímá válku?", "options": ["Přes osobní tělo a malou stanici", "Jako generál", "Ignoruje", "Sci-fi"], "correct": 0, "expl": "Mikrokosmos okupace."}, - {"prompt": "Která postava NENÍ v novelě?", "options": ["Miloš", "Hubička", "Josef Švejk jako výpravčí", "Přednosta"], "correct": 2, "expl": "Švejk je Hašek."}, - {"prompt": "Co je ich-forma?", "options": ["Vypráví Miloš", "Er bez já", "Drama", "Epos"], "correct": 0, "expl": "Subjektivní pohled mladíka."}, - {"prompt": "Jaký kontrast Hrabal staví?", "options": ["Sex a smrt / válka", "Moře hory", "Den noc", "Práce lenost"], "correct": 0, "expl": "Základ grotesky."}, - {"prompt": "Kdy vyšlo?", "options": ["1965", "1921", "1890", "2010"], "correct": 0, "expl": "Před pražským jarem."}, - {"prompt": "Co symbolizuje vlak?", "options": ["Válku a cíl činu", "Pouze dopravu", "Lásku", "Nemoc"], "correct": 0, "expl": "Finále na kolejích."}, - {"prompt": "Které dílo NENÍ Hrabal?", "options": ["Ostře sledované vlaky", "Obsluhoval jsem anglického krále", "Proměna", "Příliš hlučná samota"], "correct": 2, "expl": "Kafka."}, - {"prompt": "Jak německá moc vystupuje?", "options": ["Okupanti na stanici", "Nepřítomní", "Přátelé", "Děti"], "correct": 0, "expl": "Kontext protektorátu."}, - {"prompt": "Co je „malé hrdinství“?", "options": ["Ironický čin obyčejného mladíka", "Generál vítězí", "Bez činu", "Robot"], "correct": 0, "expl": "Hrabal demýtizuje velké hrdiny."}, - {"prompt": "Proč groteska?", "options": ["Válka je absurdní – smích i hrůza", "Bez důvodu", "Pohádka", "Reklama"], "correct": 0, "expl": "Hrabalova poetika."}, - {"prompt": "Jaký věk má Miloš?", "options": ["Mladý dospívající", "Stařec", "Dítě 5 let", "Generál"], "correct": 0, "expl": "Iniciační věk."}, - {"prompt": "Co předchází finále?", "options": ["Zkušenost s Virginii", "Svatba", "Mír", "Exil"], "correct": 0, "expl": "Sexuální dospělost před činem."}, - {"prompt": "Jak čtenář chápe závěr?", "options": ["Odvaha i absurdita malého činu", "Čisté vítězství", "Komise bez významu", "Nic"], "correct": 0, "expl": "Otevřená interpretace odboje."}, - {"prompt": "Kde stanice?", "options": ["České okolí (fiktivní stanice)", "Paříž", "Sibiř", "Afrika"], "correct": 0, "expl": "Protektorátní krajina."}, - {"prompt": "Co NENÍ motiv?", "options": ["Razítka", "Vlaky", "Středověké turnaje", "Stud"], "correct": 2, "expl": "Turnaje nepatří sem."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Miloš nastoupí na stanici", - "Hubička a razítka, groteska", - "Milošův stud a pokus o sebevraždu", - "Léčení a setkání s Virginii", - "Sexuální iniciace", - "Miloš a vlak – ostře sledovaný čin" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: stanice → Hubička → pokus → Virginie → iniciace → vlak." - ] -} diff --git a/data/cetba/pan-much.json b/data/cetba/pan-much.json deleted file mode 100644 index a71eda1..0000000 --- a/data/cetba/pan-much.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: William Golding", - "Žánr: alegorický román", - "Poprvé vydáno: 1954", - "Děj: opuštěný ostrov po nehodě letadla", - "Vyprávění: er-forma; symbolický realismus" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Poválečná doba – chlapci bez dospělých.", - "Pokus o řád vs. divokost.", - "Strach z „bestie“ – projekce zla.", - "Oheň jako záchrana i ničení.", - "Pád civilizace na ostrově.", - "Téma: lidská přirozenost, moc, strach." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ralph – vůdce demokracie, lastura.", - "Jack – vůdce lovců, tyranie.", - "Piggy – rozum, brýle.", - "Simon – introvert, pravda o bestii.", - "Roger – krutost bez hranic.", - "Námořní důstojník – návrat civilizace." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Lastura – volba, řád.", - "Oheň – signál vs. les v plamenech.", - "Bestie – strach uvnitř lidí.", - "Brýle – věda, rozum (Piggy).", - "Malování tváří – maska divokosti.", - "Pán much – prase hlava na kůlu." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Pána much?", "options": ["Orwell", "William Golding", "Hemingway", "Twain"], "correct": 1, "expl": "Lord of the Flies, 1954."}, - {"prompt": "Kdo je Ralph?", "options": ["Zvolený vůdce, lastura", "Lovec", "Kněz", "Učitel"], "correct": 0, "expl": "Snaží se udržet oheň a pravidla."}, - {"prompt": "Kdo je Jack?", "options": ["Vůdce lovců, tyran", "Ralphův bratr", "Piggy", "Simon"], "correct": 0, "expl": "Rozštěpuje skupinu."}, - {"prompt": "Kdo je Piggy?", "options": ["Inteligentní, brýle", "Generál", "Pilot", "Dospělý"], "correct": 0, "expl": "Symbol rozumu – tragicky zabit."}, - {"prompt": "Co je lastura?", "options": ["Symbol moci a řeči na shromáždění", "Zbraň", "Loď", "Jídlo"], "correct": 0, "expl": "Kdo drží lasturu, mluví."}, - {"prompt": "Co je „bestie“?", "options": ["Strach a zlo v lidech, ne zvíře", "Skutečný drak", "Loď", "Piggy"], "correct": 0, "expl": "Simon to pochopí jako projekci."}, - {"prompt": "Co se stane Simonovi?", "options": ["Zabit v transu jako „bestie“", "Král", "Uteče", "Lékař"], "correct": 0, "expl": "Lynč v nočním šílenství."}, - {"prompt": "Co je pán much?", "options": ["Prase hlava na kůlu – symbol zla", "Ralph", "Loď", "Lastura"], "correct": 0, "expl": "Titulní obraz degenerace."}, - {"prompt": "Jak končí Ralph?", "options": ["Zachráněn námořníkem, pláč", "Král ostrova", "Smrt", "S Jackem spřátelen"], "correct": 0, "expl": "Návrat civilizace – uvědomění zla."}, - {"prompt": "Jaký je žánr?", "options": ["Alegorický román", "Válečný", "Sci-fi roboti", "Bajka"], "correct": 0, "expl": "Alegorie lidské přirozenosti."}, - {"prompt": "Proč maturita?", "options": ["Symboly, postavy, témata moci", "Chemie", "Atlas", "Cookbook"], "correct": 0, "expl": "Častá maturitní četba."}, - {"prompt": "Co oheň?", "options": ["Záchrana i ničení lesa", "Bez významu", "Jen hra", "Nemoc"], "correct": 0, "expl": "Jack nechá hasnout signál."}, - {"prompt": "Kdo je Roger?", "options": ["Krutý chlapec", "Mírotvorce", "Pilot", "Kněz"], "correct": 0, "expl": "Překračuje morální hranice."}, - {"prompt": "Které téma NENÍ?", "options": ["Moc", "Strach", "Robotí vzpoura", "Civilizace vs. divokost"], "correct": 2, "expl": "R.U.R. jiné."}, - {"prompt": "Kdy vyšlo?", "options": ["1954", "1929", "1836", "2001"], "correct": 0, "expl": "Poválečná reflexe."}, - {"prompt": "Která postava NENÍ?", "options": ["Ralph", "Jack", "Švejk", "Piggy"], "correct": 2, "expl": "Hašek."}, - {"prompt": "Co brýle?", "options": ["Oheň z brýlí – věda", "Móda", "Hra", "Nic"], "correct": 0, "expl": "Piggy bez brýlí bezmocný."}, - {"prompt": "Jak Jack maluje tváře?", "options": ["Maska divokosti a násilí", "Sport", "Nemoc", "Bez významu"], "correct": 0, "expl": "Symbol odpoutání od morálky."}, - {"prompt": "Které dílo NENÍ Golding?", "options": ["Pán much", "1984", "Inheritors", "Pincher Martin"], "correct": 1, "expl": "Orwell."}, - {"prompt": "Co alegorie?", "options": ["Ostrov = společnost bez moci", "Historický dokument", "Bez významu", "Cookbook"], "correct": 0, "expl": "Chlapci = lidstvo."}, - {"prompt": "Proč letadlo?", "options": ["Válka – chlapci uvízli", "Turistika", "Sci-fi", "Bez kontextu"], "correct": 0, "expl": "Evakuace, nehoda."}, - {"prompt": "Co Piggyho smrt?", "options": ["Pád civilizace na ostrově", "Komise", "Radost", "Nic"], "correct": 0, "expl": "Roger zabije kamenem."}, - {"prompt": "Jak vyprávění?", "options": ["Er-forma", "Ich Ralph", "Drama", "Lyrika"], "correct": 0, "expl": "Klasický roman."}, - {"prompt": "Co námořní důstojník?", "options": ["Návrat adult civilizace", "Bestie", "Jack", "Piggy"], "correct": 0, "expl": "Ironický konec – dospělí také válčí."}, - {"prompt": "Jaký konflikt Ralph–Jack?", "options": ["Řád vs. lov a moc", "Láska", "Sport", "Jazyk"], "correct": 0, "expl": "Demokracie vs. tyranie."}, - {"prompt": "Co Simon dělá?", "options": ["Hledá pravdu o bestii", "Generál", "Pilot", "Učitel"], "correct": 0, "expl": "Mystik, oběť davu."}, - {"prompt": "Jaký tón?", "options": ["Temný realismus, alegorie", "Pouze komedie", "Idyla", "Učebnice"], "correct": 0, "expl": "Golding varuje před zlem v lidech."}, - {"prompt": "Proč „muchy“?", "options": ["Hniloba prase hlavy", "Sport", "Láska", "Nemoc"], "correct": 0, "expl": "Obraz morálního rozkladu."}, - {"prompt": "Co čtenář po dočtení?", "options": ["Chápe symboliku a téma zla", "Chemii", "Nic", "Mapu"], "correct": 0, "expl": "Maturitní interpretace."}, - {"prompt": "Kde děj?", "options": ["Tropický ostrov", "Praha", "Londýn", "Verona"], "correct": 0, "expl": "Izolovaný mikrokosmos."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Chlapci uvízli na ostrově, Ralph vůdce", - "Oheň a pravidla vs. Jackovi lovci", - "Strach z bestie roste", - "Simon zabit, Piggy zabit", - "Jack přebírá moc, hon na Ralpha", - "Záchrana námořníkem" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: ostrov → oheň vs. lov → bestie → Simon a Piggy → hon → námořník." - ] -} diff --git a/data/cetba/pan-prstenu.json b/data/cetba/pan-prstenu.json deleted file mode 100644 index bb6f765..0000000 --- a/data/cetba/pan-prstenu.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: John Ronald Reuel Tolkien", - "Žánr: epická fantasy (román)", - "Poprvé vydáno: 1954–1955 (trilogie)", - "Děj: Středozem, válka proti Sauronovi", - "Vyprávění: er-forma; mýtus, epos" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Fiktivní Středozem – Třetí věk.", - "Prsten moci – Sauron, Mordor.", - "Společenstvo – putování k Hoře osudu.", - "Témata: moc korumpuje, přátelství, oběť.", - "Hobití kraj vs. temnota.", - "Kulturní fenomén fantasy." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Frodo Pytlík – nositel Prstenu.", - "Sam – věrný společník.", - "Gandalf – čaroděj, mentor.", - "Aragorn – dědic Gondoru.", - "Gollum/Smeagol – posedlost Prstenem.", - "Společenstvo – Legolas, Gimli, Boromir…" - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Jeden prsten – moc Saurona.", - "Společenstvo prstenu – výprava.", - "Hora osudu – zničit Prsten.", - "Mordor – říše zla.", - "Hobit – malý hrdina.", - "Moc korumpuje – Boromir, Gollum." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Pána prstenů?", "options": ["C. S. Lewis", "J. R. R. Tolkien", "Rowling", "Martin"], "correct": 1, "expl": "Tolkien, 1954–55 – zakladatel moderní fantasy."}, - {"prompt": "Kdo nese Prsten?", "options": ["Frodo Pytlík", "Gandalf", "Sauron", "Aragorn"], "correct": 0, "expl": "Hobit Frodo je zvolen nositelem."}, - {"prompt": "Co je cíl výpravy?", "options": ["Zničit Prsten v Hoře osudu", "Ukrást Prsten Sauronovi navždy", "Prodat Prsten", "Schovat v Kraji"], "correct": 0, "expl": "Jediná cesta zničit Saurona."}, - {"prompt": "Kdo je Sam?", "options": ["Frodův věrný společník", "Čaroděj", "Ork", "Král"], "correct": 0, "expl": "Sam podporuje Froda až do Mordoru."}, - {"prompt": "Kdo je Gandalf?", "options": ["Istari, čaroděj, mentor", "Hobit", "Trpaslík", "Ent"], "correct": 0, "expl": "Gandalf organizuje Společenstvo."}, - {"prompt": "Kdo je Gollum?", "options": ["Smeagol, posedlý Prstenem", "Král Gondoru", "Elf", "Ent"], "correct": 0, "expl": "Prsten ho zničil – guide i hrozba."}, - {"prompt": "Co je Společenstvo?", "options": ["Skupina na zničení Prstenu", "Armáda Saurona", "Hospoda", "Škola"], "correct": 0, "expl": "Různé rasy – elf, trpaslík, lidé, hobiti."}, - {"prompt": "Kde Frodo bydlí?", "options": ["Kraj (Shire)", "Mordor", "Rivendell navždy", "Moria"], "correct": 0, "expl": "Hobití kraj – idyla vs. temnota."}, - {"prompt": "Kdo je Sauron?", "options": ["Temný pán Mordoru", "Hobit", "Král Rohanu", "Ent"], "correct": 0, "expl": "Vládce Prstenu moci."}, - {"prompt": "Co Boromir?", "options": ["Touží po Prstenu, zradí, pokání", "Vždy zlý", "Hobit", "Elf"], "correct": 0, "expl": "Moc korumpuje i dobré."}, - {"prompt": "Kdo je Aragorn?", "options": ["Dědic trůnu Gondoru", "Ork", "Gollum", "Sam"], "correct": 0, "expl": "Strider – král v návratu."}, - {"prompt": "Jak končí Prsten?", "options": ["Zničen v Hoře osudu (Gollum pád)", "Sauron nosí navždy", "Frodo vládne", "Zmizí"], "correct": 0, "expl": "Gollum ukousne prst – pád do lávy."}, - {"prompt": "Proč maturita?", "options": ["Fantasy epos, postavy, témata moci", "Chemie", "Atlas", "Cookbook"], "correct": 0, "expl": "Často zkrácená maturitní verze."}, - {"prompt": "Které téma NENÍ?", "options": ["Přátelství", "Moc", "Robotí R.U.R.", "Oběť"], "correct": 2, "expl": "Čapek."}, - {"prompt": "Co Mordor?", "options": ["Sauronova říše", "Hobití kraj", "Rivendell", "Londýn"], "correct": 0, "expl": "Cíl výpravy."}, - {"prompt": "Kdy vyšlo?", "options": ["1954–1955", "1929", "1836", "2010"], "correct": 0, "expl": "Poválečná fantasy."}, - {"prompt": "Která postava NENÍ?", "options": ["Frodo", "Gandalf", "Elizabeth Bennet", "Aragorn"], "correct": 2, "expl": "Austen."}, - {"prompt": "Co Hobit?", "options": ["Malý lid milující mír", "Ork", "Ent", "Balrog"], "correct": 0, "expl": "Frodo a Sam jsou hobiti."}, - {"prompt": "Které dílo NENÍ Tolkien?", "options": ["Pán prstenů", "Hobit", "Revizor", "Silmarillion"], "correct": 2, "expl": "Gogol."}, - {"prompt": "Co Hora osudu?", "options": ["Sammath Naur – zničení Prstenu", "Hobití kopec", "Věž", "Hospoda"], "correct": 0, "expl": "V Mordoru."}, - {"prompt": "Jak vyprávění?", "options": ["Er-forma epos", "Ich Frodo celé", "Drama", "Lyrika"], "correct": 0, "expl": "Epický roman."}, - {"prompt": "Co elf Legolas a trpaslík Gimli?", "options": ["Členové Společenstva", "Orkové", "Sauronovi", "Hobiti"], "correct": 0, "expl": "Symbol smíření ras."}, - {"prompt": "Proč Frodo odchází na konci?", "options": ["Rány Prstenu – odplutí do Undying Lands", "Král", "Smrt v boji", "Zůstane v Kraji"], "correct": 0, "expl": "Epilog – oběť nositele."}, - {"prompt": "Co „Jeden prsten“?", "options": ["Věta Sauronovy moci", "Sport", "Jídlo", "Mapa"], "correct": 0, "expl": "Slavný verš Prstenu."}, - {"prompt": "Jaký konflikt?", "options": ["Dobro vs. Sauron, pokušení moci", "Láska Romeo", "Revizor", "Švejk"], "correct": 0, "expl": "Základ fantasy eposu."}, - {"prompt": "Co Rivendell?", "options": ["Elfí útočiště Elronda", "Mordor", "Kraj", "Moria"], "correct": 0, "expl": "Zde vzniká Společenstvo."}, - {"prompt": "Co Moria?", "options": ["Trpasličí doly, Balrog", "Hobití kraj", "Mordor", "Rohan"], "correct": 0, "expl": "Gandalf pád s Balrogem."}, - {"prompt": "Jaký tón?", "options": ["Epická fantasy, mýtus", "Realismus Dickens", "Groteska Hrabal", "Satira"], "correct": 0, "expl": "Tolkien buduje svět."}, - {"prompt": "Co čtenář po dočtení?", "options": ["Chápe postavy, Prsten, témata", "Chemii", "Nic", "Mapu ČR"], "correct": 0, "expl": "Maturitní přehled."}, - {"prompt": "Kdo režíroval slavný film?", "options": ["Peter Jackson (2001–2003)", "Menzel", "Disney", "N/A 1920"], "correct": 0, "expl": "Kulturní doplněk k maturitě."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Frodo zdědí Prsten, odchod z Kraje", - "Společenstvo v Rivendell", - "Cesta – Moria, rozpad společenstva", - "Frodo a Sam k Mordoru", - "Gollum vede, pokušení moci", - "Prsten zničen v Hoře osudu" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: Kraj → Společenstvo → cesta → Frodo a Sam → Gollum → Hora osudu." - ] -} diff --git a/data/cetba/petr-a-lucie.json b/data/cetba/petr-a-lucie.json deleted file mode 100644 index ddeb656..0000000 --- a/data/cetba/petr-a-lucie.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Vítězslav Nezval", - "Žánr: poetický / poetistický román", - "Poprvé vydáno: 1929", - "Děj: Praha 20. let, láska Petra a Lucie", - "Vyprávění: er-forma; poetistická obraznost, hra" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Poetismus – radost ze života, město, metafora.", - "Praha jako poetistické jeviště.", - "Láska jako hra a sen.", - "Citlivost vs. realita (nemoc, smrt).", - "Nezval a Devětsil – avantgarda.", - "Téma: láska, mládí, křehkost, obraz." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Petr – mladý muž, zamilovaný.", - "Lucie – dívka, partnerka, křehká.", - "Praha – město procházek a snů.", - "Rodina / okolí – realita.", - "Poetistický svět – barvy, hra.", - "Osud – Luciina nemoc a konec." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Poetismus – avantgardní směr 20. let.", - "Láska jako hra – lehkost i hloubka.", - "Praha – poetistický prostor.", - "Obraz a metafora – Nezvalův styl.", - "Tragický konec – Luciina smrt.", - "Cit – romantika moderní formy." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Petra a Lucii?", "options": ["Seifert", "Vítězslav Nezval", "Hrabal", "Neruda"], "correct": 1, "expl": "Nezval, 1929 – vrchol poetistické prózy."}, - {"prompt": "Jaký směr román reprezentuje?", "options": ["Poetismus", "Socialistický realismus", "Romantismus Erben", "Beat generation"], "correct": 0, "expl": "Česká avantgarda 20. let."}, - {"prompt": "Kde se děj odehrává?", "options": ["Praha", "Verona", "Londýn", "Mordor"], "correct": 0, "expl": "Město procházek a metafor."}, - {"prompt": "Kdo jsou hlavní hrdinové?", "options": ["Petr a Lucie", "Romeo a Julie", "Frodo a Sam", "Švejk a Lukáš"], "correct": 0, "expl": "Mladí milenci v poetistické Praze."}, - {"prompt": "Jaký je tón začátku?", "options": ["Radost, hra, obrazy", "Válka", "Groteska Haška", "Sci-fi"], "correct": 0, "expl": "Poetismus slaví život a město."}, - {"prompt": "Jak končí Lucie?", "options": ["Umírá (nemoc) – tragický konec", "Královna", "Emigrace", "Svatba bez smutku"], "correct": 0, "expl": "Idyla praskne realitou."}, - {"prompt": "Co je poetismus?", "options": ["Avantgarda – radost, metafora, město", "Válka", "Realismus 19. stol.", "Robotika"], "correct": 0, "expl": "Devětsil, Nezval, Teige…"}, - {"prompt": "Proč maturita?", "options": ["Nezval, poetismus, Praha, styl", "Chemie", "Atlas", "Cookbook"], "correct": 0, "expl": "Česká maturitní četba."}, - {"prompt": "Jaký styl Nezval?", "options": ["Poetické obrazy, hra se slovy", "Strohý realismus", "Hexametr antický", "Drama"], "correct": 0, "expl": "Próza i poezie splývají."}, - {"prompt": "Které téma NENÍ?", "options": ["Láska", "Město", "Robotí vzpoura", "Mládí"], "correct": 2, "expl": "R.U.R."}, - {"prompt": "Kdy vyšlo?", "options": ["1929", "1957", "1890", "2010"], "correct": 0, "expl": "Meziválečí avantgarda."}, - {"prompt": "Kdo Nezval?", "options": ["Devětsil, surrealismus později", "Hašek Švejk", "Kafka", "Gogol"], "correct": 0, "expl": "Klíčová osobnost avantgardy."}, - {"prompt": "Jak vyprávění?", "options": ["Er-forma poetistická", "Ich Petr celé", "Drama", "Epos"], "correct": 0, "expl": "Lyrizovaná próza."}, - {"prompt": "Co Praha v románu?", "options": ["Prostor snů a procházek", "Pouze mapa", "Vězení", "Vesnice"], "correct": 0, "expl": "Poetistické město."}, - {"prompt": "Která postava NENÍ?", "options": ["Petr", "Lucie", "Winston Smith", "—"], "correct": 2, "expl": "Orwell."}, - {"prompt": "Jaký kontrast?", "options": ["Poetistická radost vs. smrt", "Moře hory", "Den noc", "Práce lenost"], "correct": 0, "expl": "Křehkost štěstí."}, - {"prompt": "Které dílo NENÍ Nezval?", "options": ["Petr a Lucie", "Akrobat", "Revizor", "Poetistické manifesty"], "correct": 2, "expl": "Gogol."}, - {"prompt": "Co láska v románu?", "options": ["Hra, sen, cit", "Politika", "Válka", "Obchod"], "correct": 0, "expl": "Centrum poetismu."}, - {"prompt": "Proč tragický konec?", "options": ["Realita nemoci vs. idyla", "Válka", "Náhodná věta", "Bez důvodu"], "correct": 0, "expl": "Nezval neničí iluzi."}, - {"prompt": "Co Devětsil?", "options": ["Umělecká skupina avantgardy", "Armáda", "Banka", "Kostel"], "correct": 0, "expl": "Kontext Nezvala."}, - {"prompt": "Jaký jazyk?", "options": ["Bohaté metafory, obrazy", "Úřední", "Latina", "Argot"], "correct": 0, "expl": "Poetistická próza."}, - {"prompt": "Co Petr prožívá?", "options": ["Lásku a ztrátu Lucie", "Válku", "Roboty", "Král"], "correct": 0, "expl": "Hrdina citu."}, - {"prompt": "Jak román vnímat u maturity?", "options": ["Autor, směr, děj, styl, témata", "Jen datum", "Jen mapa", "Ignorovat"], "correct": 0, "expl": "Komplexní četba."}, - {"prompt": "Co NENÍ poetismus?", "options": ["Radost z obrazu a města", "Věčná válka", "Hra", "Avantgarda"], "correct": 1, "expl": "Poetismus je radostný."}, - {"prompt": "Kdo surrealismus u Nezvala?", "options": ["Pozdější fáze tvorby", "Neexistuje", "Jen Švejk", "Jen Kafka"], "correct": 0, "expl": "Po poetismu surrealismus."}, - {"prompt": "Co Lucie symbolizuje?", "options": ["Křehké mládí a krása", "Moc", "Robot", "Válka"], "correct": 0, "expl": "Oběť času a nemoci."}, - {"prompt": "Jaký věk autor?", "options": ["Meziválečná generace", "Středověk", "Antika", "21. stol."], "correct": 0, "expl": "1900–1958 Nezval."}, - {"prompt": "Co čtenář po dočtení?", "options": ["Chápe poetismus a Nezvala", "Chemii", "Nic", "Mapu"], "correct": 0, "expl": "Maturitní cíl."}, - {"prompt": "Který pár je z Nezvala?", "options": ["Petr a Lucie", "Romeo a Julie", "Elizabeth a Darcy", "Frodo a Sam"], "correct": 0, "expl": "Titulní hrdinové."}, - {"prompt": "Proč „poetický román“?", "options": ["Próza s poetickými prostředky a obrazností", "Pouze verše", "Učebnice", "Zákoník"], "correct": 0, "expl": "Lyrizace prózy – obrazy, metafora, rytmus vět."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Petr a Lucie se seznámí v Praze", - "Procházky, radost a poetistické obrazy", - "Láska roste – hra a sen", - "Prozaická realita – nemoc Lucie", - "Petr prožívá ztrátu", - "Tragický konec – Lucie umírá" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: seznámení → radost → láska → nemoc → ztráta → smrt Lucie." - ] -} diff --git a/data/cetba/poe-povidky.json b/data/cetba/poe-povidky.json deleted file mode 100644 index c6c3f29..0000000 --- a/data/cetba/poe-povidky.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Edgar Allan Poe", - "Žánr: horor, detektivka, groteska (povídky)", - "Poprvé vydáno: různá vydání 19. století", - "Děj: povídky – temná psychika, tajemno", - "Vyprávění: ich/er forma; gotický styl" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Americká romantika 19. století – gotika.", - "Hrůza, vina, monomanie.", - "Detektivní logika (Dupin).", - "Symbolismus (Havran).", - "Smrt, hrobky, mučení.", - "Téma: psychika, strach, rozum vs. šílenství." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Vypravěč Havran – truchlící muž.", - "Dupin – detektiv (Povídky o skandálu…).", - "Montresor – vrah v Amontillado.", - "Fortunato – oběť.", - "Roderick Usher – poslední z rodu.", - "Beruška – srdce v povídce." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Gotický horor – hrad, hrob, tma.", - "Detektivní povídka – logika Dupina.", - "Monomanie – posedlost.", - "Symbol – havran „Nevermore“.", - "Princip jednoty účinku – Poe estetika.", - "Psychologický horor." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Havrana a další povídky?", "options": ["Dickens", "Edgar Allan Poe", "Twain", "Hemingway"], "correct": 1, "expl": "Poe – zakladatel detektivky a hororu."}, - {"prompt": "Co opakuje havran v básni?", "options": ["Nevermore (Už nikdy)", "Hello", "War", "Love"], "correct": 0, "expl": "Jediné slovo – symbol věčného smutku."}, - {"prompt": "O čem je Havran?", "options": ["Truchlení za Lenore", "Válka", "Robot", "Svatba"], "correct": 0, "expl": "Gotická báseň v komnatě."}, - {"prompt": "Kdo je Dupin?", "options": ["Detektiv v povídkách", "Vrah", "Král", "Havran"], "correct": 0, "expl": "Předchůdce Sherlocka Holmese."}, - {"prompt": "O čem je Amontillado?", "options": ["Pomsta zazděním ve sklepě", "Láska", "Detektivka na lodi", "Sci-fi"], "correct": 0, "expl": "Montresor zabije Fortunata."}, - {"prompt": "O čem je Srdce prozrazuje?", "options": ["Vrah slyší bušení srdce pod podlahou", "Láska", "Válka", "Cookbook"], "correct": 0, "expl": "Psychologický horor viny."}, - {"prompt": "O čem je Jáma a kyvadlo?", "options": ["Mučení inkvizicí", "Svatba", "Detektivka", "Komise"], "correct": 0, "expl": "Strach a smrt."}, - {"prompt": "O čem je Fall of the House of Usher?", "options": ["Rod Usherů a zhroucení domu", "Švejk", "Praha", "Robot"], "correct": 0, "expl": "Gotický dům = rod."}, - {"prompt": "Jaký je Poe styl?", "options": ["Gotika, psychologie, napětí", "Realismus Dickens", "Poetismus", "Hašek"], "correct": 0, "expl": "Temnota a logika."}, - {"prompt": "Proč maturita?", "options": ["Havran, horor, detektivka, symboly", "Chemie", "Atlas", "Cookbook"], "correct": 0, "expl": "Světová maturitní četba."}, - {"prompt": "Které téma NENÍ?", "options": ["Strach", "Vina", "Robotí R.U.R.", "Monomanie"], "correct": 2, "expl": "Čapek."}, - {"prompt": "Co „princip jednoty účinku“?", "options": ["Poe estetika – jeden dojem v díle", "Válka", "Cookbook", "Mapa"], "correct": 0, "expl": "Krátká forma, silný efekt."}, - {"prompt": "Kdy Poe žil?", "options": ["1809–1849", "1929", "2000", "1595"], "correct": 0, "expl": "19. století USA."}, - {"prompt": "Která postava NENÍ Poe?", "options": ["Dupin", "Montresor", "Elizabeth Bennet", "Usher"], "correct": 2, "expl": "Austen."}, - {"prompt": "Co gotika u Poe?", "options": ["Tma, hrob, hrůza", "Komise", "Idyla", "Sport"], "correct": 0, "expl": "Základ hororu."}, - {"prompt": "Které dílo NENÍ Poe?", "options": ["Havran", "Amontillado", "Revizor", "Beruška"], "correct": 2, "expl": "Gogol."}, - {"prompt": "Jak Havran končí?", "options": ["Pták zůstává, beznaděj", "Svatba", "Vítězství", "Pták letí"], "correct": 0, "expl": "Stín na duši."}, - {"prompt": "Co detektivní povídka Poe?", "options": ["Logika, deduction", "Pouze magie", "Válka", "Cookbook"], "correct": 0, "expl": "Dupin řeší zločin."}, - {"prompt": "Jaký jazyk Havran?", "options": ["Rytmická báseň, gotická", "Prozaický zákoník", "Dialog divadla", "Hašek"], "correct": 0, "expl": "Lyrika + horor."}, - {"prompt": "Co monomanie?", "options": ["Posedlost jednou myšlenkou", "Láska", "Sport", "Mír"], "correct": 0, "expl": "Vrah v Srdci prozrazuje."}, - {"prompt": "Kde Poe působil?", "options": ["USA", "Čechy", "Rusko", "Antika"], "correct": 0, "expl": "Americký autor."}, - {"prompt": "Co čtenář u maturity?", "options": ["Zná Havrana, horor, detektivku", "Jen mapu", "Chemii", "Nic"], "correct": 0, "expl": "Výběr povídek."}, - {"prompt": "Co Lenore?", "options": ["Mrtvá milovaná v Havranovi", "Detektiv", "Král", "Robot"], "correct": 0, "expl": "Důvod smutku."}, - {"prompt": "Jaký kontrast Poe?", "options": ["Rozum vs. šílenství", "Moře hory", "Den noc", "Práce lenost"], "correct": 0, "expl": "Psychika na hranici."}, - {"prompt": "Co Fortunato?", "options": ["Oběť v Amontillado", "Detektiv", "Havran", "Král"], "correct": 0, "expl": "Opilý, zazděný."}, - {"prompt": "Proč povídky?", "options": ["Krátká forma, silný účinek", "Bez důvodu", "Jen básně", "Jen román"], "correct": 0, "expl": "Poe mistr povídky."}, - {"prompt": "Co symbol havran?", "options": ["Smrt, beznaděj", "Láska", "Mír", "Bohatství"], "correct": 0, "expl": "Černý pták."}, - {"prompt": "Jak vyprávění hororu?", "options": ["Často ich-forma vina", "Epos", "Bez já", "Drama"], "correct": 0, "expl": "Subjektivní strach."}, - {"prompt": "Co NENÍ Poe povídka?", "options": ["Havran (báseň)", "Amontillado", "Oliver Twist", "Usher"], "correct": 2, "expl": "Dickens román."}, - {"prompt": "Jaký tón?", "options": ["Temnota, napětí", "Pouze komedie", "Idyla", "Učebnice"], "correct": 0, "expl": "Gotický horor."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Havran: muž truchlí za Lenore", - "Pták přiletí do komnaty", - "Otázky a odpověď „Nevermore“", - "Narůstající zoufalství", - "Stín ptáka nad duší", - "Beznaděj bez útěchy" - ] - } - ], - "plotMeaning": [ - "Správné pořadí (Havran): smutek → přílet → Nevermore → zoufalství → stín → beznaděj." - ] -} diff --git a/data/cetba/povidky-z-kapes.json b/data/cetba/povidky-z-kapes.json deleted file mode 100644 index 27b308d..0000000 --- a/data/cetba/povidky-z-kapes.json +++ /dev/null @@ -1,334 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Čapek (1890–1938)", - "Žánr: detektivní a humoristické povídky (parodie žánru)", - "Poprvé vydáno: 1929 (z jedné kapsy) a 1932 (z druhé kapsy)", - "Děj: jednotlivé krátké případy; rámec vyprávění u stolu v kavárně", - "Forma: povídkový cyklus – přátelé si vyprávějí „historky z kapes“" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "První republika – pražská kavárenská společnost, inteligence.", - "Čapek si hraje s detektivkou: logika vs. náhoda a lidský detail.", - "Humor, humanismus, skepse vůči „stoprocentní“ dedukci.", - "Detektivní linie (komisař Mejzlík) paroduje sherlockovský styl.", - "Vyprávění ve společnosti jako rámec – každá povídka samostatný příběh.", - "Typická pointa: překvapení, vtip, malý lidský motiv rozhodne víc než rozum." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Vypravěči u stolu – rámec sbírky, přátelé v kavárně.", - "Policejní komisař Mejzlík – detektiv s přehnanou logikou.", - "Pachatelé, svědci a oběti – střídají se v jednotlivých povídkách.", - "Postavy z povídek jako Modrá chrysantéma, Levkoj, Uspání aj.", - "Čtenář – spoluřeší záhadu, Čapek ho často přechytračí.", - "Autorův ironický hlas – přítomný v komentáři k detektivce." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Parodie detektivky – Čapek demýtizuje geniálního detektiva.", - "Náhoda vs. logika – pravda bývá banálnější než dedukce.", - "Humanismus – zájem o obyčejného člověka, ne jen zločin.", - "Kavárenský rámec – sbližuje vypravěče i čtenáře.", - "Povídka z kapsy – drobný, vtipný příběh k „vytáhnutí“ u stolu.", - "Dvě kapsy – dva svazky, stejný princip, jiné miniaturky." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Povídky z jedné a druhé kapsy?", - "options": ["Jaroslav Hašek", "Karel Čapek", "Franz Kafka", "Bohumil Hrabal"], - "correct": 1, - "expl": "Autorem je Karel Čapek; první svazek vyšel 1929, druhý 1932." - }, - { - "prompt": "Jaký je základní žánr souboru?", - "options": ["Historický epos", "Detektivní a humoristické povídky", "Lyrická skladba", "Tragédie"], - "correct": 1, - "expl": "Čapek kombinuje detektivní zápletku s humorem a parodií." - }, - { - "prompt": "Jak jsou povídky rámovány?", - "options": ["Deníkem jednoho hrdiny", "Vyprávěním přátel u stolu v kavárně", "Úředním protokolem", "Hexametrem"], - "correct": 1, - "expl": "Rámec tvoří společnost, která si předává krátké historky." - }, - { - "prompt": "Proč název „z kapes“?", - "options": [ - "Jde výhradně o krádeže kapesníků", - "Jde o drobné příběhy, které si lze „vytáhnout z kapsy“ u stolu", - "Autor psal jen v kapse kabátu", - "Jde o učebnici šití" - ], - "correct": 1, - "expl": "Metafora malých, unosných povídek vhodných k vyprávění." - }, - { - "prompt": "Co Čapek u detektivek často zpochybňuje?", - "options": [ - "Existenci kaváren", - "Všemocnost čisté logiky a dedukce", - "Pravopis", - "Existenci Prahy" - ], - "correct": 1, - "expl": "Příběhy ukazují, že náhoda a lidský detail často překonají „geniální“ rozum." - }, - { - "prompt": "Kdo je komisař Mejzlík?", - "options": [ - "Hlavní hrdina všech povídek bez výjimky", - "Detektiv v detektivních povídkách cyklu, parodie sherlockovského typu", - "Čapekův bratr", - "Postava z R.U.R." - ], - "correct": 1, - "expl": "Mejzlík reprezentuje přehnanou logiku, kterou Čapek ironizuje." - }, - { - "prompt": "Která povídka patří k známým z kapsy?", - "options": ["Modrá chrysantéma", "Havran", "Babička", "Hamlet"], - "correct": 0, - "expl": "Modrá chrysantéma je jedna z proslulých detektivních miniatur." - }, - { - "prompt": "Jaký je typický tón sbírky?", - "options": ["Pouze tragický patos", "Humoristický, bystrý, ironický", "Pouze horor", "Úřednický bez emocí"], - "correct": 1, - "expl": "Typický je čapkovský humor a nadhled nad žánrem." - }, - { - "prompt": "Kdy vyšly oba svazky zhruba?", - "options": ["1836 a 1840", "1929 a 1932", "2001 a 2005", "1415 a 1420"], - "correct": 1, - "expl": "Obě kapsy vznikly v meziválečné prvorepublikové době." - }, - { - "prompt": "Co je typické pro pointu povídky?", - "options": [ - "Žádné vyřešení", - "Překvapení, vtip nebo banální lidský detail", - "Pouze matematický důkaz bez vtipu", - "Povinný sňatek" - ], - "correct": 1, - "expl": "Čapek rád obrátí očekávání čtenáře v závěru." - }, - { - "prompt": "Jak souvisí sbírka s ostatním Čapkovým dílem?", - "options": [ - "Nesouvisí vůbec", - "Humanismus, hra s žánrem, ironie – stejný duch jako u jiných próz", - "Je to jen překlad Twaina", - "Je to pokračování R.U.R." - ], - "correct": 1, - "expl": "Čapek znovu spojuje zábavu s myšlenkou o člověku a společnosti." - }, - { - "prompt": "Co čtenář při čtení typicky dělá?", - "options": [ - "Jen počítá stránky", - "Spoluuhádá záhadu a nechá se překvapit pointou", - "Učí se latinku", - "Ignoruje děj" - ], - "correct": 1, - "expl": "Detektivní linka zve k aktivnímu čtení, parodie ho pak přechytračí." - }, - { - "prompt": "Které prostředí rámce převažuje?", - "options": ["Venkov 19. století", "Praha první republiky – kavárna, společnost", "Vesmír", "Středověký hrad"], - "correct": 1, - "expl": "Rámec odpovídá pražské meziválečné inteligenci." - }, - { - "prompt": "Co NENÍ charakteristika cyklu?", - "options": ["Humor", "Parodie detektivky", "Jediný souvislý román o jedné rodině", "Krátká forma"], - "correct": 2, - "expl": "Jde o soubor samostatných povídek spojených rámcem." - }, - { - "prompt": "Jak Čapek vnímá detektivní žánr?", - "options": [ - "Bezvýhradně ho opakuje", - "Hraje si s ním, demýtizuje geniálního detektiva", - "Zakazuje záhady", - "Píše jen dokumenty" - ], - "correct": 1, - "expl": "Mejzlík a pointy ukazují limity „stoprocentní“ logiky." - }, - { - "prompt": "Které dílo NENÍ Čapek?", - "options": ["Povídky z kapes", "R.U.R.", "Revizor", "Válka s mloky"], - "correct": 2, - "expl": "Revizor je Gogolova komedie." - }, - { - "prompt": "Kolik „kapes“ má plný název díla?", - "options": ["Jednu", "Dvě – z jedné a z druhé kapsy", "Deset", "Žádnou"], - "correct": 1, - "expl": "Maturitní četba zahrnuje oba svazky." - }, - { - "prompt": "Co je Levkoj v kontextu sbírky?", - "options": [ - "Postava z R.U.R.", - "Název jedné z povídek v cyklu", - "Čapekův bratr", - "Detektivní pes" - ], - "correct": 1, - "expl": "Levkoj patří k známým povídkám z kapsy." - }, - { - "prompt": "Jaký kontrast tvoří jádro detektivních povídek?", - "options": [ - "Moře vs. hory", - "Chladná dedukce vs. náhoda a lidskost", - "Praha vs. Brno", - "Den vs. noc bez významu" - ], - "correct": 1, - "expl": "Čapek staví proti sobě rozum a obyčejnou realitu." - }, - { - "prompt": "Proč je dílo v maturitní četbě?", - "options": [ - "Je nejkratší kniha v knihovně", - "Čapek, parodie, forma povídky, humanismus", - "Bez témat a postav", - "Je to atlas" - ], - "correct": 1, - "expl": "U maturity se ptá na autora, rámec, žánr a typické povídky." - }, - { - "prompt": "Kdo NENÍ typická postava kapsy?", - "options": ["Komisař Mejzlík", "Vypravěč u stolu", "Frodo Pytlík", "Pachatel v minipříběhu"], - "correct": 2, - "expl": "Frodo je z Tolkienova eposu." - }, - { - "prompt": "Co znamená humanismus u Čapka zde?", - "options": [ - "Zájem o obyčejného člověka, soucit, nadhled", - "Popírání humoru", - "Jen politická propaganda", - "Odmítání prózy" - ], - "correct": 0, - "expl": "I v detektivce jde o lidi, ne jen o rébus." - }, - { - "prompt": "Jaká forma vyprávění v jednotlivých povídkách?", - "options": [ - "Výhradně divadelní dialog bez vypravěče", - "Krátká próza, často ich- nebo er-forma v rámci vyprávění u stolu", - "Pouze sonety", - "Operní libreto" - ], - "correct": 1, - "expl": "Každá miniatura má klasickou povídkovou stavbu." - }, - { - "prompt": "Co je Uspání v kontextu díla?", - "options": [ - "Povídka z druhé kapsy", - "Čapekův dramatický spis", - "Název kavárny", - "Postava z Bílé nemoci" - ], - "correct": 0, - "expl": "Uspání patří k povídkám druhého svazku." - }, - { - "prompt": "Jaký vztah má sbírka k Sherlocku Holmesovi?", - "options": [ - "Žádný – Čapek neznal detektivky", - "Parodický – ironizuje dedukci a „geniální“ detektiva", - "Holmes je hlavní hrdina", - "Jde o Holmesův deník" - ], - "correct": 1, - "expl": "Mejzlík a pointy reagují na konvence žánru." - }, - { - "prompt": "Které téma NENÍ typické?", - "options": ["Náhoda a omyl", "Lidská povaha v malém", "Vzpoura robotů", "Ironie vůči jistotám"], - "correct": 2, - "expl": "Robotí vzpoura patří k R.U.R." - }, - { - "prompt": "Co je hlavní kouzlo formátu?", - "options": [ - "Extrémní délka románu", - "Krátkost, vtip, nápad, překvapivá pointa", - "Bez děje", - "Pouze popis krajiny" - ], - "correct": 1, - "expl": "Povídka z kapsy má být lehká a zapamatovatelná." - }, - { - "prompt": "Jak maturita obvykle testuje dílo?", - "options": [ - "Jen rok narození autora", - "Autor, rámec, žánr, Mejzlík, známé povídky, témata", - "Jen počet stran", - "Jen cizí jazyk originálu" - ], - "correct": 1, - "expl": "Čeká se přehled o cyklu a charakteristice Čapkovy parodie." - }, - { - "prompt": "Který autor je současník Čapka v české próze?", - "options": ["Bohumil Hrabal (jiná generace)", "Karel Čapek sám", "Homér", "Dante"], - "correct": 0, - "expl": "Hrabal patří později; u maturity jde o meziválečný Čapek." - }, - { - "prompt": "Jaký závěr lze vyvodit z celého cyklu?", - "options": [ - "Logika vždy zvítězí nad náhodou", - "Pravda bývá prozaická; humor a humanismus jsou důležité", - "Detektivka je nevhodný žánr", - "Kavárny je třeba zakázat" - ], - "correct": 1, - "expl": "Čapek oslavuje bystrost, ale i lidskost a nadhled." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Přátelé sedí u stolu v kavárně", - "Jeden vypravěč přednese detektivní historku", - "Nabízejí se stopy a logické úvahy", - "Zvrat – náhoda nebo banální detail", - "Pointa povídky", - "Společnost reaguje humorem a pokračuje vyprávěním" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: kavárenský rámec → přednes povídky → stopy a dedukce → zvrat → pointa → reakce společnosti." - ] -} diff --git a/data/cetba/promena.json b/data/cetba/promena.json deleted file mode 100644 index e00acd5..0000000 --- a/data/cetba/promena.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Franz Kafka", - "Žánr: novela; absurdní / existenciální próza", - "Poprvé vydáno: 1915", - "Děj: byt rodiny Samsových v moderním městě", - "Vyprávění: er-forma; věcný chladný styl vs. hrůza proměny" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Počátek 20. století: rodina, práce, byrokracie jako povinnost.", - "Gregor je obchodní cestující a živitel – hodnota člověka = užitečnost.", - "Po proměně v hmyz se stává přítěží a objektem odporu.", - "Měšťanský byt je klec i jeviště rodinné krize.", - "Podnájemníci zhorší tlak na rodinu.", - "Téma: odcizení, vina, dehumanizace." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Gregor Samsa – obchodní cestující proměněný v hmyz.", - "Grete – sestra; nejprve pečuje, později odmítá.", - "Otec – autoritativní, násilný (jablko).", - "Matka – soucit i strach.", - "Podnájemníci – cizí soudci „ostudy“.", - "Prokurista – symbol práce a tlaku." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Proměna – ztráta lidské podoby i společenského místa.", - "Odcizení – cizí sobě i rodině.", - "Užitečnost – člověk = výdělek.", - "Jablko – zranění od otce, symbol viny.", - "Pokoj – izolace za dveřmi.", - "Smrt Gregora – „úleva“ pro rodinu." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Proměnu?", "options": ["Franz Kafka", "Jaroslav Hašek", "Karel Čapek", "Erich Maria Remarque"], "correct": 0, "expl": "Novela je jedním z nejznámějších Kafkových textů; vyšla 1915."}, - {"prompt": "Co se stane Gregorovi Samsovi na začátku?", "options": ["Vyhrá loterii", "Probudí se proměněný v obrovského hmyz", "Odjede do války", "Stane se králem"], "correct": 1, "expl": "Slavná úvodní věta líčí bizarní proměnu bez vysvětlení."}, - {"prompt": "Jaké povolání má Gregor před proměnou?", "options": ["Lékař", "Obchodní cestující", "Učitel", "Kněz"], "correct": 1, "expl": "Gregor dře pro rodinu jako obchodník – práce ho vyčerpává."}, - {"prompt": "Kdo je Grete?", "options": ["Gregorova manželka", "Gregorova sestra", "Sousedka", "Prokuristka"], "correct": 1, "expl": "Grete se nejprve stará o bratra, později ho odmítá."}, - {"prompt": "Proč je Gregor pro rodinu důležitý (před proměnou)?", "options": ["Je slavný herec", "Je hlavní živitel rodiny", "Je politik", "Je dědic hradu"], "correct": 1, "expl": "Rodina je na jeho platu závislá – otec, matka, sestra."}, - {"prompt": "Jak reaguje otec na Gregora-hmyz?", "options": ["Objímá ho", "Násilně ho zaplaší – mimo jiné jablko", "Ignoruje navždy", "Pošle ho do školy"], "correct": 1, "expl": "Otec představuje autoritu a hrubou sílu vůči „nestvůře“."}, - {"prompt": "Co symbolizuje jablko zabodnuté do Gregora?", "options": ["Lásku", "Otcovské násilí, vinu a odcizení", "Svatou hostii", "Sport"], "correct": 1, "expl": "Jablko zraní Gregora a dlouho v něm zůstává – obraz odcizení."}, - {"prompt": "Jak se mění vztah Grete k Gregorovi?", "options": ["Vždy milující", "Od péče k odmítnutí a požadavku „se zbavit ho“", "Grete se promění v hmyz", "Grete odejde do kláštera hned"], "correct": 1, "expl": "Grete na konci prosí rodiče, aby se Gregora zbavili."}, - {"prompt": "Kdo jsou podnájemníci?", "options": ["Gregorovi přátelé", "Cizí lidé v bytě, kteří zhorší finanční tlak", "Policisté", "Lékaři"], "correct": 1, "expl": "Podnájemníci jsou svědky „ostudy“ a urychlí krizi."}, - {"prompt": "Jaký je styl vyprávění?", "options": ["Rychlý humor Haška", "Er-forma, věcný tón u absurdní události", "Pouze dialogy divadla", "Epický zpěv"], "correct": 1, "expl": "Kafka kontrastuje chladný jazyk s hrůzou situace."}, - {"prompt": "Kde Gregor většinou pobývá?", "options": ["Na ulici", "Ve svém pokoji, často za zavřenými dveřmi", "V lese", "Na moři"], "correct": 1, "expl": "Izolace v pokoji zdůrazňuje odcizení od rodiny."}, - {"prompt": "Jak Gregor umírá?", "options": ["Na popravišti", "Sám, vyčerpán – rodina cítí úlevu", "V boji", "V autonehodě"], "correct": 1, "expl": "Po smrti rodina plánuje světlejší budoucnost – krutá ironie."}, - {"prompt": "Co je hlavní téma Proměny?", "options": ["Válečná sláva", "Odcizení, užitečnost člověka a rozpad rodinných vazeb", "Růst tržní ekonomiky", "Středověké rytířství"], "correct": 1, "expl": "Gregor je milován, dokud vydělává; jako hmyz je odpad."}, - {"prompt": "Proč Gregor nemůže hned jít do práce?", "options": ["Proměna v hmyz", "Je na dovolené", "Je bohatý", "Je v jiné zemi"], "correct": 0, "expl": "Právě proměna spouští konflikt s prokuristou a rodinou."}, - {"prompt": "Kdo přichází do bytu jako reprezentant práce?", "options": ["Prokurista", "Švejk", "Romeo", "Domin"], "correct": 0, "expl": "Prokurista je tlak firmy – Gregor musí vysvětlovat absenci."}, - {"prompt": "Jak matka reaguje na Gregora?", "options": ["Vždy klidně objímá", "Rozpolcená – soucit i strach, omdlévání", "Nikdy se o něj nezajímá", "Stane se hmyzem"], "correct": 1, "expl": "Matka trpí mezi synem a realitou bytu."}, - {"prompt": "Co znamená kafkaovský svět?", "options": ["Idyla", "Absurdita, vina bez důvodu, byrokratický tlak", "Pouze komedie", "Historický dokument"], "correct": 1, "expl": "Proměna je ukázkou existenciální absurdity bez vysvětlení."}, - {"prompt": "Jak rodina končí po Gregorově smrti?", "options": ["Truchlí navždy", "Plánuje světlou budoucnost (s výhledem na sestřin sňatek)", "Emigruje", "Zbankrotuje"], "correct": 1, "expl": "Závěr je ironický – Gregorova smrt uvolní cestu „normálnímu“ životu."}, - {"prompt": "Který prvek NENÍ v Proměně typický?", "options": ["Rodinný byt", "Proměna těla", "Vysvětlení příčiny proměny vědou", "Odcizení"], "correct": 2, "expl": "Kafka příčinu nevysvětluje – to je součást absurdity."}, - {"prompt": "Jak Gregor slyší hudbu (housle)?", "options": ["Nesnáší ji", "Grete hraje – Gregor je dojat, lidskost v něm rezonuje", "Je hluchý", "Hudba nefiguruje"], "correct": 1, "expl": "Scéna s houslemi ukazuje zbytky Gregorovy citlivosti."}, - {"prompt": "Proč je novela důležitá pro maturitu?", "options": ["Učí účetnictví", "Kafka, symbolika, témata, styl – klasika světové literatury", "Je atlas", "Je cookbook"], "correct": 1, "expl": "U maturity: autor, děj, postavy, symboly, témata odcizení."}, - {"prompt": "V jakém roce vyšla Proměna?", "options": ["1915", "1929", "1949", "2005"], "correct": 0, "expl": "Text vznikl v Kafkově tvůrčím období první světové války."}, - {"prompt": "Která věta patří k úvodu Proměny?", "options": ["Call me Ishmael", "Jednoho rána, když se ze spánku probudil, proměnil se Gregor Samsa v obrovského brouka", "Vánoce nebyly bílé", "Dvě ulice Prahy"], "correct": 1, "expl": "Slavný začátek v českých překladech obvykle „hmyz/brouk“."}, - {"prompt": "Jaká forma vyprávění je v Proměně?", "options": ["Ich-forma", "Er-forma (třetí osoba)", "Drama", "Epistolární"], "correct": 1, "expl": "Kafka vypráví o Gregorovi v třetí osobě – er-forma."}, - {"prompt": "Co podnájemníci dělají při hře na housle?", "options": ["Tleskají", "Projevují netrpělivost – Gregor chce Grete bránit", "Odejdou hned první den", "Stanou se hmyzem"], "correct": 1, "expl": "Konflikt vyhrotí Gregorovo vyloupení z pokoje."}, - {"prompt": "Jak otec vypadá po Gregorově proměně?", "options": ["Mladne", "Zpočátku zlomený, později energický při potrestání Gregora", "Zmizí", "Je v nemocnici"], "correct": 1, "expl": "Otec se znovu postaví do role autority."}, - {"prompt": "Které téma souvisí s prací?", "options": ["Gregor = hodnota jen jako výdělek", "Gregor je nezaměstnaný od narození", "Práce nefiguruje", "Gregor je král"], "correct": 0, "expl": "Když nemůže pracovat, rodina ho vnímá jako břemeno."}, - {"prompt": "Jaký žánr je Proměna?", "options": ["Novela / absurdní próza", "Historický román", "Bajka o zvířatech", "Učebnice"], "correct": 0, "expl": "Krátký prózní útvar s fantastickým prvkem – novela."}, - {"prompt": "Co NENÍ postava Proměny?", "options": ["Grete", "Otec", "Winston Smith", "Matka"], "correct": 2, "expl": "Winston Smith je z Orwellova 1984, ne z Kafky."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Gregor se probudí proměněný v hmyz", - "Prokurista a rodina zjišťují, že nemůže do práce", - "Grete pečuje, Gregor je izolován v pokoji", - "Otec zraní Gregora jablkem", - "Podnájemníci a hádky – Gregor vyloupen", - "Gregor umírá, rodina plánuje nový začátek" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: proměna → tlak práce → péče Grete → jablko → podnájemníci → smrt a „úleva“ rodiny." - ] -} diff --git a/data/cetba/pycha-a-predsudek.json b/data/cetba/pycha-a-predsudek.json deleted file mode 100644 index 05e6d47..0000000 --- a/data/cetba/pycha-a-predsudek.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Jane Austenová", - "Žánr: společenský / láskopisný román", - "Poprvé vydáno: 1813", - "Děj: anglická venkovská šlechta, rodina Bennettových", - "Vyprávění: er-forma; ironický vypravěč" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Regency Anglie – třída, sňatek, majetek, mravy.", - "Ženy často závislé na dobré partii.", - "Společenské plesy, návštěvy, pomluvy.", - "Pýcha a předsudek brání Elizabeth a Darcymu.", - "Austen ironicky kritizuje společnost.", - "Téma: láska, sebe poznání, třída." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Elizabeth Bennet – bystrá hrdinka, odmítá předsudky.", - "Fitzwilliam Darcy – bohatý aristokrat, zpočátku haughty.", - "Jane Bennet – Elizabethina sestra, laskavá.", - "Charles Bingley – Darcyho přítel, miluje Jane.", - "Pan Wickham – okouzlující, ale nepoctivý.", - "Paní Bennet – matka tlačící na sňatky." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Pýcha – Darcyho povýšenost.", - "Předsudek – Elizabethino souzení.", - "Sňatek – ekonomická i emocionální otázka.", - "Třída – bohatství a společenské postavení.", - "Ironie – Austenův styl.", - "Dopis – Darcy vysvětluje Wickhamovu minulost." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Pýchu a předsudek?", "options": ["Charlotte Brontëová", "Jane Austenová", "George Eliot", "Virginia Woolfová"], "correct": 1, "expl": "Román vyšel 1813 a je Austenovou nejznámější prózou."}, - {"prompt": "Kolik sester má rodina Bennetů (dcer)?", "options": ["2", "5", "10", "1"], "correct": 1, "expl": "Pět sester – Elizabeth, Jane, Mary, Kitty, Lydia."}, - {"prompt": "Kdo je Elizabeth Bennet?", "options": ["Nejstarší sestra", "Druhá nejstarší, bystrá hrdinka románu", "Služka", "Vévodkyně"], "correct": 1, "expl": "Elizabeth je inteligentní a ironická protagonista."}, - {"prompt": "Kdo je Fitzwilliam Darcy?", "options": ["Chudý kněz", "Bohatý aristokrat, Bingleyho přítel", "Wickhamův otec", "Farmář"], "correct": 1, "expl": "Darcy působí na Elizabeth povýšeně – pýcha."}, - {"prompt": "Kdo je Charles Bingley?", "options": ["Elizabethin strýc", "Bohatý muž, který miluje Jane", "Vrah", "Král"], "correct": 1, "expl": "Bingley pronajme Netherfield a zamiluje se do Jane."}, - {"prompt": "Proč Darcy zpočátku odjede a oddálí Bingleyho?", "options": ["Myslí si, že Jane nemiluje Bingleyho a rodina není vhodná", "Nemá peníze", "Je nemocný", "Nenávidí Anglii"], "correct": 0, "expl": "Darcy jedná z pýchy a „ochrany“ přítele."}, - {"prompt": "Kdo je George Wickham?", "options": ["Darcymu důvěryhodný důstojník", "Okouzlující důstojník s temnou minulostí vůči Darcymu", "Kněz", "Lékař"], "correct": 1, "expl": "Wickham lže o Darcym – Elizabeth uvěří předsudku."}, - {"prompt": "Co Elizabeth odmítne od Darcyho?", "options": ["První nabídku k sňatku – uražena jeho způsobem", "Dědictví", "Dům", "Knihu"], "correct": 0, "expl": "Slavná scéna – Darcy se nabídne hrdě, Elizabeth odmítne."}, - {"prompt": "Co změní Elizabethin názor na Darcyho?", "options": ["Dopis vysvětlující Wickhamovu minulost a Darcyho činy", "Peníze", "Hrozba", "Kouzlo"], "correct": 0, "expl": "Po dopise Elizabeth přehodnotí předsudky."}, - {"prompt": "Co udělá Lydia?", "options": ["Uteče s Wickhamem – skandál rodiny", "Stane se královnou", "Založí školu", "Odejde do kláštera"], "correct": 0, "expl": "Lydiin útěk ohrozí pověst celé rodiny."}, - {"prompt": "Kdo pomůže Wickhamovu sňatku s Lydií?", "options": ["Darcy (tajně)", "Elizabeth", "Paní Bennet", "Wickham sám"], "correct": 0, "expl": "Darcy platí a jedná – projev dobrého srdce."}, - {"prompt": "Jak román končí?", "options": ["Elizabeth a Darcy se vezmou, Bingley a Jane také", "Všichni zůstanou sami", "Elizabeth uteče", "Darcy zbankrotuje"], "correct": 0, "expl": "Klasický happy-end po sebepoznání."}, - {"prompt": "Jaký je styl Austenové?", "options": ["Ironický společenský realismus", "Gotický horor", "Sci-fi", "Epos"], "correct": 0, "expl": "Jemná ironie vůči společnosti a postavám."}, - {"prompt": "Proč paní Bennet tlačí na sňatky?", "options": ["Majetek rodiny přejde synovi – dcery potřebují partii", "Nenávidí děti", "Je královna", "Zákaz práce"], "correct": 0, "expl": "Ekonomická realita regency – sňatek jako jistota."}, - {"prompt": "Kde se Bingley poprvé objeví?", "options": ["Netherfield – sousedství Bennetů", "Paříž", "Verona", "Praha"], "correct": 0, "expl": "Pronajatý statek spustí děj a plesy."}, - {"prompt": "Kdo je pan Collins?", "options": ["Mrzký dědic statku, nabádá k sňatku", "Darcy", "Wickham", "Bingley"], "correct": 0, "expl": "Collins je komická postava servility vůči Lady Catherine."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Pýcha a předsudek", "Sňatek a třída", "Vzpoura robotů", "Sebepoznání"], "correct": 2, "expl": "Roboti jsou z R.U.R., ne od Austenové."}, - {"prompt": "Proč je román důležitý pro maturitu?", "options": ["Učí chemii", "Austen, společnost, postavy, ironie, sňatek", "Je atlas", "Je zákoník"], "correct": 1, "expl": "U maturity: autor, děj, Elizabeth vs. Darcy, témata."}, - {"prompt": "Kdy román vyšel?", "options": ["1813", "1929", "1595", "2001"], "correct": 0, "expl": "Regency období, počátek 19. století."}, - {"prompt": "Jak Elizabeth vidí Darcyho na začátku?", "options": ["Okamžitě ideální", "Povýšeného a nepříjemného – předsudek", "Jako chudého", "Jako dítě"], "correct": 1, "expl": "První dojem u plesu formuje její názor."}, - {"prompt": "Kdo je Lady Catherine de Bourgh?", "options": ["Darcyho příbuzná, autoritativní patronka", "Elizabethina sestra", "Wickhamova manželka", "Služka"], "correct": 0, "expl": "Lady Catherine představuje starou aristokracii."}, - {"prompt": "Co je Netherfield?", "options": ["Statek, který Bingley pronajme", "Léčebna", "Vězení", "Loď"], "correct": 0, "expl": "Místo setkání společnosti a začátku lásky Jane."}, - {"prompt": "Jaký vztah mají Jane a Bingley?", "options": ["Nenávist", "Jemná vzájemná láska", "Sourozenec", "Učitel–žák"], "correct": 1, "expl": "Jane a Bingley jsou kontrast k Elizabeth–Darcy konfliktu."}, - {"prompt": "Co znamená název?", "options": ["Darcyho pýcha a Elizabethin předsudek brání lásce", "Pouze válka", "Pouze počasí", "Geografie"], "correct": 0, "expl": "Obě vlastnosti se musí překonat."}, - {"prompt": "Která postava NENÍ Bennetová?", "options": ["Elizabeth", "Jane", "Emma Woodhouse", "Lydia"], "correct": 2, "expl": "Emma je hrdinka jiného Austenova románu."}, - {"prompt": "Jak vyprávění funguje?", "options": ["Er-forma s ironickým odstupem", "Ich-forma Elizabeth", "Drama", "Epos"], "correct": 0, "expl": "Vypravěč často sdílí Elizabethin pohled, ale s ironií."}, - {"prompt": "Proč Darcy pomůže s Lydií?", "options": ["Láska k Elizabeth a pocit odpovědnosti", "Nenávidí Wickhama jen ze sportu", "Zákaz", "Náhodou"], "correct": 0, "expl": "Darcy jedná diskrétně – charakter se ukáže činy."}, - {"prompt": "Které dílo NENÍ Austenovo?", "options": ["Pýcha a předsudek", "Emma", "Na západní frontě klid", "Mansfieldské panství"], "correct": 2, "expl": "Remarque napsal válečný román."}, - {"prompt": "Jak Elizabeth reaguje na druhou Darcyho nabídku?", "options": ["Přijme – po změně obou", "Odmítne navždy", "Uteče", "Pošle Wickhama"], "correct": 0, "expl": "Oba se poučili – sňatek z lásky."}, - {"prompt": "Jak Austen ironicky líčí paní Bennet?", "options": ["Jako hysterickou matku fixovanou na sňatky dcer", "Jako vzornou vědkyni", "Jako válečnou hrdinku", "Jako královnu"], "correct": 0, "expl": "Paní Bennet komicky tlačí na vdání, protože ekonomicky jinou jistotu nemá."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Bingley přijede do Netherfield, ples a setkání", - "Elizabeth soudí Darcyho pýchou, Wickham lže", - "Darcy se nabídne – Elizabeth odmítne", - "Darcyho dopis a nové pochopení", - "Lydia uteče s Wickhamem, Darcy pomůže", - "Elizabeth a Darcy se sblíží a vezmou se" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: Bingley a ples → předsudky → první nabídka → dopis → Lydia → happy-end." - ] -} diff --git a/data/cetba/revizor.json b/data/cetba/revizor.json deleted file mode 100644 index 25e0bc5..0000000 --- a/data/cetba/revizor.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Nikolaj Vasiljevič Gogol", - "Žánr: satirická komedie (drama)", - "Poprvé vydáno: 1836 (premiéra v Petrohradě)", - "Děj: malé provinční městečko, záměna identity", - "Vyprávění: drama, 5 dějství" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Carské Rusko 19. století – korupce úřadů.", - "Městská rada žije strachem z kontroly z Petrohradu.", - "Úplatky, lži a strach z revizora.", - "Chudý úředník Chlestakov využije omyl.", - "Satira na moc, lakotu a servilitu.", - "Známá replika: „Na co se díváte? Je to revizor!“" - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Chlestakov – chudý úředník přijatý za revizora.", - "Anton Antonovič Skvoznik-Dmuchanovskij – městský hlava.", - "Bobčinskij a Dobčinskij – statkáři, donáší o „revizorovi“.", - "Osip – Chlestakovův sluha.", - "Artěmij Filippovič Zemljanika – správce nemocnice.", - "Korobkin, Rastakovski – úředníci." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Revizor – kontrolor ze Sankt Petěrburgu; objekt strachu.", - "Záměna identity – komický i morální jádro.", - "Korupce – úřady nabízejí úplatky.", - "Satira – smích odhaluje hnijící systém.", - "Provincie vs. centrum – moc a strach.", - "Mlčení na konci – „prijímají revizora“ (skutečného)." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Revizora?", "options": ["Puškin", "Gogol", "Tolstoj", "Dostojevskij"], "correct": 1, "expl": "Nikolaj Vasiljevič Gogol; premiéra 1836."}, - {"prompt": "Jaký je žánr Revizora?", "options": ["Satirická komedie", "Historický román", "Epos", "Lyrika"], "correct": 0, "expl": "Jde o divadelní satiru na ruskou byrokracii."}, - {"prompt": "Proč se úředníci v městě vyděsí?", "options": ["Přijde povodeň", "Myslí si, že přijel revizor incognito", "Vypukne válka", "Zavřou divadlo"], "correct": 1, "expl": "Bobčinskij a Dobčinskij vidí Chlestakova v hospodě a šíří paniku."}, - {"prompt": "Kdo je Chlestakov?", "options": ["Skutečný revizor", "Chudý úředník, kterého berou za revizora", "Císař", "Generál"], "correct": 1, "expl": "Chlestakov využije omyl a nechá se obsypat penězi."}, - {"prompt": "Kdo jsou Bobčinskij a Dobčinskij?", "options": ["Revizoři", "Statkáři, kteří donesou zprávu o „revizorovi“", "Chlestakovovi rodiče", "Cizinci z Francie"], "correct": 1, "expl": "Dvojice komických statkářů spustí záměnu."}, - {"prompt": "Kdo je Skvoznik-Dmuchanovskij?", "options": ["Městský hlava (gorodničij)", "Chlestakovův sluha", "Kuchař", "Kněz"], "correct": 0, "expl": "Anton Antonovič vede radu a nejvíc se bál kontroly."}, - {"prompt": "Jak Chlestakov reaguje na pocty?", "options": ["Uteče hned", "Přijímá úplatky, pije a chvástá se", "Obviní všechny z vraždy", "Odevzdá majetek chudým"], "correct": 1, "expl": "Chlestakov rychle pochopí situaci a zneužije ji."}, - {"prompt": "Kdo je Osip?", "options": ["Sluha Chlestakova", "Revizor", "Císař", "Lékař"], "correct": 0, "expl": "Osip je praktický sluha, který situaci také využívá."}, - {"prompt": "Co úředníci nabízejí „revizorovi“?", "options": ["Jen květiny", "Peníze, dary, servilitu – úplatky", "Nic", "Jen modlitby"], "correct": 1, "expl": "Satira na korupci – každý uplatí revizora."}, - {"prompt": "Jak Chlestakov opouští město?", "options": ["V koze", "Po dopise a vydírání – odjede s penězi", "Jako císař", "Nikdy neodejde"], "correct": 1, "expl": "Chlestakov napíše urážlivý dopis a zmizí."}, - {"prompt": "Jak hra končí?", "options": ["Chlestakov se stane hlavou", "Přijde skutečný revizor – ticho a strach", "Všichni se smějí", "Město shoří"], "correct": 1, "expl": "Posel oznámí příjezd skutečného revizora – pointa."}, - {"prompt": "Kde se děj odehrává?", "options": ["Petrohrad", "Malé provinční rusko městečko", "Paříž", "Praha"], "correct": 1, "expl": "Provincie je typickým prostředím gogolovské satiry."}, - {"prompt": "Co je hlavní komický mechanismus?", "options": ["Nedorozumění identity", "Magie", "Vesmírná válka", "Detektivní stopa"], "correct": 0, "expl": "Chudý úředník = revizor – záměna identit."}, - {"prompt": "Proč je Revizor důležitý pro maturitu?", "options": ["Učí chemii", "Gogol, satira, korupce, forma komedie", "Je atlas", "Je kuchařka"], "correct": 1, "expl": "U maturity: autor, děj, postavy, satira, závěr."}, - {"prompt": "Kdy hra premiérovala?", "options": ["1836", "1918", "1945", "2000"], "correct": 0, "expl": "Premiéra 1836 v Petrohradě."}, - {"prompt": "Která postava NENÍ v Revizorovi?", "options": ["Chlestakov", "Skvoznik-Dmuchanovskij", "Hamlet", "Bobčinskij"], "correct": 2, "expl": "Hamlet je Shakespeare, ne Gogol."}, - {"prompt": "Co satira kritizuje?", "options": ["Korupci a servilitu úřadů", "Pouze počasí", "Sport", "Hudbu"], "correct": 0, "expl": "Gogol vystaví na posměch ruskou byrokracii."}, - {"prompt": "Kdo je Zemljanika?", "options": ["Správce nemocnice", "Císař", "Chlestakovova žena", "Revizor"], "correct": 0, "expl": "Další úředník, který se snaží uplatit „revizora“."}, - {"prompt": "Jaký je tón hry?", "options": ["Satirická komedie s absurdní pointou", "Pouze tragédie", "Lyrika", "Horor"], "correct": 0, "expl": "Smích a groteskní situace vedou k mravenčímu závěru."}, - {"prompt": "Co znamená strach z revizora?", "options": ["Strach z kontroly moci shora", "Strach z bouře", "Strach z lásky", "Strach z hudby"], "correct": 0, "expl": "Úředníci vědí, že by kontrola odhalila jejich hříchy."}, - {"prompt": "Proč Chlestakov píše urážlivý dopis?", "options": ["Je opilý a drzý – satirická scéna", "Je to revizor", "Neví psát", "Je to milostný dopis"], "correct": 0, "expl": "Chlestakov se chvástá a uráží město."}, - {"prompt": "Kolik dějství má Revizor?", "options": ["3", "5", "12", "1"], "correct": 1, "expl": "Gogolova komedie má pět dějství."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Korupce", "Záměna identity", "Vesmírná sci-fi", "Strach z moci"], "correct": 2, "expl": "Revizor je realistická satira 19. století."}, - {"prompt": "Kdo donese zprávu o muži v hospodě?", "options": ["Bobčinskij a Dobčinskij", "Císař", "Julie", "Švejk"], "correct": 0, "expl": "Právě oni spustí lavinu omylů."}, - {"prompt": "Jak reaguje městská rada na „revizora“?", "options": ["Ignoruje ho", "Servilně ho hostí a uplatí", "Zavře hradby", "Odešle do exilu"], "correct": 1, "expl": "Všichni se snaží zalíbit a uplatit."}, - {"prompt": "Co Gogol ukazuje o morálce úředníků?", "options": ["Jsou vzorní", "Jsou korupční a zbabělí", "Jsou svatí", "Neexistují"], "correct": 1, "expl": "Satira odhaluje hnijící provincii."}, - {"prompt": "Jaký jazyk / prostředí?", "options": ["Carské Rusko, úřednický svět", "Antika", "Budoucnost", "Amerika"], "correct": 0, "expl": "Kontext je ruská provincie 19. století."}, - {"prompt": "Proč je závěr efektní?", "options": ["Je tichý – skutečný revizor už je tu", "Všichni tančí", "Chlestakov se vrátí jako král", "Nic se nestane"], "correct": 0, "expl": "Po komedii přijde tvrdá realita kontroly."}, - {"prompt": "Kdo je Chlestakov v profesi?", "options": ["Chudý petrohradský úředník", "Generál", "Lékař", "Učitel"], "correct": 0, "expl": "Není bohatý – právě proto je komické, že ho berou za mocného."}, - {"prompt": "Které dílo NENÍ Gogolovo?", "options": ["Revizor", "Mrtvé duše", "Na západní frontě klid", "Nos"], "correct": 2, "expl": "Remarque napsal Na západní frontě klid."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Bobčinskij a Dobčinskij vidí Chlestakova v hospodě", - "Město panikaří – myslí si, že je to revizor", - "Chlestakova vítají, uplatí a hostí", - "Chlestakov se chvástá a přijímá dary", - "Odjede s penězi a napíše urážlivý dopis", - "Přijede oznámení o skutečném revizorovi" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: zpráva statkářů → panika → uctívání Chlestakova → chvástání → odjezd → skutečný revizor." - ] -} diff --git a/data/cetba/romeo-a-julie.json b/data/cetba/romeo-a-julie.json deleted file mode 100644 index cf1dc22..0000000 --- a/data/cetba/romeo-a-julie.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: William Shakespeare", - "Žánr: tragédie (drama)", - "Poprvé vydáno: kolem 1595 (tištěno později)", - "Děj: Verona, spor rodu Montecchi a Capuletů", - "Vyprávění: drama v pěti dějstvích, dialogy a monology" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Renesanční Verona – rodové nenávisti a souboje.", - "Láska Romeo a Julie vs. rodinný konflikt.", - "Osud, náhoda a unáhlená rozhodnutí.", - "Mladí proti starším (Romeo, Julie vs. rodiče).", - "Jazyk: básnický, metaforický, kontrastní.", - "Téma: láska, nenávist, smrt, smíření rodů." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Romeo Montecchi – vášnivý mladík, zamilovaný do Julie.", - "Julie Capulet – mladá dívka, statečnější než okolí.", - "Mercutio – Romeův přítel, vtipný, zabit Tybaltem.", - "Tybalt – Julin sestřenec, hašteřivý, zabije Mercutia.", - "Friar Laurence – františkán, sňatku a lektvaru.", - "Nurse – chůva, Julii blízká." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Tragédie – pád hlavních hrdinů.", - "Nenávist rodů – Montecchi vs. Capuletové.", - "Osud (fate) – hvězdy, předtuchy.", - "Lektvar – falešná smrt Julie.", - "Balcony scene – slavný milenecký dialog.", - "Smíření – rodové usmíření až po smrti milenců." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Roméa a Julii?", "options": ["Molière", "William Shakespeare", "Goethe", "Dante"], "correct": 1, "expl": "Tragédie je jedním z nejznámějších Shakespeareových dramat."}, - {"prompt": "Kde se děj odehrává?", "options": ["Paříž", "Verona", "Londýn", "Praha"], "correct": 1, "expl": "Shakespeare zasadil příběh do italské Verony."}, - {"prompt": "Mezi kterými rody zuří spor?", "options": ["Montecchi a Capuletové", "Medici a Borgiové", "Habsburkové a Přemyslovci", "Starkové a Lannisteři"], "correct": 0, "expl": "Rodová nenávist je motor tragédie."}, - {"prompt": "Kdo je Romeo na začátku zamilovaný?", "options": ["Do Julie hned", "Do Rosaline", "Do Nurse", "Do Mercutia"], "correct": 1, "expl": "Romeo nejprve touží po Rosaline, pak potká Julii."}, - {"prompt": "Kde se Romeo a Julie poprvé setkají?", "options": ["Na balu u Capuletů", "V klášteře", "Na popravišti", "Na lodi"], "correct": 0, "expl": "Romeo přijde maskovaně na Capuletův večírek."}, - {"prompt": "Kdo je Mercutio?", "options": ["Romeův přítel, vtipný a impulzivní", "Julin otec", "Kněz", "Revizor"], "correct": 0, "expl": "Mercutio je často považován za nejživější postavu hry."}, - {"prompt": "Kdo zabije Mercutia?", "options": ["Romeo", "Tybalt", "Julie", "Nurse"], "correct": 1, "expl": "Tybalt v souboji zabije Mercutia – zlom děje."}, - {"prompt": "Co Romeo udělá poté?", "options": ["Uteče do exilu bez pomsty", "Zabije Tybalta a musí uprchnout z Verony", "Ožení se s Rosaline", "Stane se knězem"], "correct": 1, "expl": "Romeova pomsta vede k vyhnanství."}, - {"prompt": "Kdo sjedná tajný sňatek?", "options": ["Friar Laurence", "Tybalt", "Mercutio", "Chlestakov"], "correct": 0, "expl": "Františkán doufá, že sňatkem ukončí spor rodů."}, - {"prompt": "Kdo je Nurse?", "options": ["Julie chůva a důvěrnice", "Romeova matka", "Královna", "Vražedkyně"], "correct": 0, "expl": "Chůva pomáhá Julii s tajnou láskou."}, - {"prompt": "Proč má Julie brát lektvar?", "options": ["Aby usnula jako mrtvá a vyhnula se sňatku s Parisem", "Aby zabila Romea", "Aby získala moc", "Aby cestovala"], "correct": 0, "expl": "Friar Laurence plánuje falešnou smrt a sjednocení s Romeem."}, - {"prompt": "Proč Romeo bere jed?", "options": ["Myslí si, že Julie je mrtvá", "Je to trest soudu", "Nurse mu ho dá", "Chce spát"], "correct": 0, "expl": "Romeo se dozví o Julii smrti a v hrobce se zabije."}, - {"prompt": "Jak Julie umírá?", "options": ["V souboji", "Probodne se Romeovým dýkem v hrobce", "Od lektvaru navždy", "Stářím"], "correct": 1, "expl": "Julie se probudí, vidí mrtvého Romea a zabije se."}, - {"prompt": "Jak hra končí pro rody?", "options": ["Válka pokračuje", "Rodiče se usmíří nad těly milenců", "Montecchi vyhrají", "Capuletové zmizí"], "correct": 1, "expl": "Tragédie vede k poměření síly a smíření."}, - {"prompt": "Jaký je žánr?", "options": ["Komedie", "Tragédie", "Pohádka", "Učebnice"], "correct": 1, "expl": "Oba hlavní hrdinové umírají – klasická tragédie."}, - {"prompt": "Co je slavná „balkónová scéna“?", "options": ["Romeo a Julie vyznávají lásku", "Souboj Tybalta", "Svatba", "Poprava"], "correct": 0, "expl": "Julie na balkóně, Romeo dole – ikonický dialog."}, - {"prompt": "Kdo je Paris?", "options": ["Nápadník Julie, kterého rodina preferuje", "Romeův bratr", "Král Verony", "Mercutio"], "correct": 0, "expl": "Rodiče chtějí Julii provdat za Paris."}, - {"prompt": "Která replika patří k hře?", "options": ["Být či nebýt", "Romeo, Romeo, proč jsi Romeo?", "Vánoce nebyly bílé", "Vlk, vlko!"], "correct": 1, "expl": "Julie lamentuje nad Romeovým jménem a rodem."}, - {"prompt": "Proč je hra důležitá pro maturitu?", "options": ["Učí účetnictví", "Shakespeare, tragédie, postavy, jazyk, témata", "Je mapa", "Je cookbook"], "correct": 1, "expl": "U maturity: děj, postavy, citace, tragédie, láska a konflikt."}, - {"prompt": "Kdo je Tybalt?", "options": ["Julin sestřenec, hašteřivý duelant", "Kněz", "Romeův otec", "Chůva"], "correct": 0, "expl": "Tybalt nenávidí Montecchi a provokuje souboj."}, - {"prompt": "Co znamená téma osudu?", "options": ["Postavy vnímají hvězdy a předtuchy", "Nic", "Pouze komedie", "Ekonomika"], "correct": 0, "expl": "Shakespeare pracuje s pocitem nevyhnutelnosti."}, - {"prompt": "Kolik dějství má hra?", "options": ["5", "3", "12", "1"], "correct": 0, "expl": "Klasická pětaktová struktura tragédie."}, - {"prompt": "Která postava NENÍ v Roméovi a Julii?", "options": ["Mercutio", "Tybalt", "Othello", "Nurse"], "correct": 2, "expl": "Othello je jiné Shakespeareovo drama."}, - {"prompt": "Jaký kontrast hra zdůrazňuje?", "options": ["Láska vs. rodová nenávist", "Práce vs. lenost", "Věda vs. víra", "Moře vs. hory"], "correct": 0, "expl": "Osobní cit stojí proti kolektivní nenávisti."}, - {"prompt": "Proč Friar Laurence plán selže?", "options": ["Nedorozumění, zpoždění zprávy, unáhlení Romea", "Julie nechce Romea", "Tybalt přežije", "Verona neexistuje"], "correct": 0, "expl": "Tragédie je i o náhodě – dopis k Romeo nedorazí včas."}, - {"prompt": "Kdy vznikla hra?", "options": ["Kolem 1595 (renesance)", "1850", "1920", "Antika"], "correct": 0, "expl": "Shakespeare píše na konci 16. století."}, - {"prompt": "Kdo je Benvolio?", "options": ["Romeův příbuzný, snaží se mířit konflikty", "Julin otec", "Vrah", "Císař"], "correct": 0, "expl": "Benvolio je klidnější protiklad Tybaltovi."}, - {"prompt": "Které tvrzení je správné?", "options": ["Julie je mladší než okolí často předpokládá – ale statečná", "Julie je královna", "Romeo nikdy nemiluje", "Hra končí svatbou"], "correct": 0, "expl": "Julie roste v odvaze – od balkónu po rozhodnutí o lektvaru."}, - {"prompt": "Co NENÍ typické téma?", "options": ["Láska", "Nenávist rodů", "Industrializace robotů", "Smrt milenců"], "correct": 2, "expl": "Roboti patří k R.U.R., ne k Shakespeareovi."}, - {"prompt": "Jaký jazyk Shakespeare používá?", "options": ["Básnický dialog, metafora, rytmus", "Pouze próza bez obrazů", "Češtinu", "Latinské legrámy"], "correct": 0, "expl": "Tragédie kombinuje verš a prózu, bohaté obrazy."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Romeo potká Julii na Capuletově večírku", - "Tajný sňatek u Friar Laurence", - "Tybalt zabije Mercutia, Romeo zabije Tybalta", - "Romeo v exile, plán s lektvarem", - "Julie „umírá“, Romeo se zabije v hrobce", - "Julie se probudí a umírá – rody se usmíří" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: setkání → sňatek → souboj a vyhnanství → lektvar → Romeo v hrobce → Julie a smíření rodů." - ] -} diff --git a/data/cetba/romeo-julie-a-tma.json b/data/cetba/romeo-julie-a-tma.json deleted file mode 100644 index af83a1e..0000000 --- a/data/cetba/romeo-julie-a-tma.json +++ /dev/null @@ -1,249 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Jan Otčenášek (1924–1979)", - "Žánr: novela, milostný příběh za okupace", - "Poprvé vydáno: 1962", - "Děj: Praha za protektorátu, léta 1941–1942", - "Vyprávění: er-forma, soustředěný děj kolem Pavla a Ester" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Německá okupace, pronásledování Židů, transporty do Terezína.", - "Škola funguje pod dohledem, ale studenti čtou i zakázané texty.", - "Skrývání pronásledovaných je trestné; každý soused může udat.", - "Láska mezi Čechem a Židovkou je vystavena strachu i smrti.", - "Paralela s Shakespearovým Romeem a Julií – milenci proti světu.", - "Tma v názvu = okupace, tajnost i nejistota osudu." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Pavel – gymnazista, zamiluje se do Ester, statečný až do konce.", - "Ester – židovská dívka v utajení u rodiny Sedlákových.", - "Hanka Sedláková – spolužačka, pomáhá skrývat Ester.", - "Petr – Pavlův strýc, účastník odboje, varuje před nebezpečím.", - "Pavelův otec – realista, bojí se následků pro syna i rodinu.", - "Učitelé a spolužáci – rámec školního světa za okupace." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Okupace – totalitní režim, který ničí lidské vztahy.", - "Utajení – Ester žije „v temnu“, bez oficiální identity.", - "Milostná paralela – Romeo a Julie v pražské podobě.", - "Oběť a statečnost – Pavel volí lásku před bezpečím.", - "Transport – symbol konečné ztráty naděje na společný život.", - "Etické dilema rodin – pomoc vs. strach z udání." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo je autorem novely Romeo, Julie a tma?", - "options": ["Jan Skácel", "Jan Otčenášek", "Arnošt Lustig", "Jiří Wolker"], - "correct": 1, - "expl": "Novelu napsal Jan Otčenášek; vyšla v roce 1962." - }, - { - "prompt": "V jakém období se děj odehrává?", - "options": ["První republika 1920", "Protektorát Čechy a Morava, léta 1941–1942", "Poválečná normalizace", "Listopad 1989"], - "correct": 1, - "expl": "Děj je zasazen do okupované Prahy krátce po vypuknutí války." - }, - { - "prompt": "Kdo je Ester?", - "options": ["Pavlova sestra", "Židovská dívka skrývaná u Sedlákových", "Učitelka němčiny", "Německá studentka"], - "correct": 1, - "expl": "Ester je pronásledovaná Židovka, která žije v utajení u Hanky Sedlákové." - }, - { - "prompt": "Kdo je hlavní hrdina a jaký je jeho věk?", - "options": ["Petr – dospělý odbojář", "Pavel – student gymnázia", "Major Hugo – voják", "Strýc Sedlák – lékař"], - "correct": 1, - "expl": "Pavel je mladý gymnazista, který prožívá první vážnou lásku." - }, - { - "prompt": "Proč je vztah Pavla a Ester nebezpečný?", - "options": ["Rodiče nesouhlasí se sňatkem", "Ester je v utajení a kontakt s ní ohrožuje všechny", "Pavel je vdaný", "Škola zakazuje chození"], - "correct": 1, - "expl": "Každé setkání s ukrytou Židovkou může vést k zatčení a transportu." - }, - { - "prompt": "Na co odkazuje název Romeo, Julie a tma?", - "options": ["Na operu v Národním divadle", "Na milostný příběh proti nepřátelskému světu za okupace", "Na básnickou sbírku Wolkerovu", "Na film z roku 1968"], - "correct": 1, - "expl": "Otčenášek přenáší motiv zakázané lásky do podmínek holocaustu." - }, - { - "prompt": "Kde se Pavel s Ester tajně schází?", - "options": ["Na Václavském náměstí", "V bytě Sedlákových / u okna (paralela s balkonem)", "V Terezíně", "Na venkově u strýce"], - "correct": 1, - "expl": "Schůzky probíhají skrytě v domě, kde Ester bydlí; evokuje to slavnou scénu Shakespeara." - }, - { - "prompt": "Jakou roli hraje Petr?", - "options": ["Německý důstojník", "Pavlova strýc, zapojený do odboje", "Hankin otec", "Rabín"], - "correct": 1, - "expl": "Petr reprezentuje odpor proti okupaci a varuje Pavla před lehkomyslností." - }, - { - "prompt": "Co se stalo s Esterinou rodinou?", - "options": ["Emigrovala do USA", "Byla deportována / zlikvidována nacisty", "Přestěhovala se na venkov legálně", "Přešla na křesťanství a byla ušetřena"], - "correct": 1, - "expl": "Ester je jedna z mála přeživších z rodiny; ostatní padli oběť persekuci." - }, - { - "prompt": "Jak reaguje Pavelův otec na synovu lásku?", - "options": ["Radostně ji podporuje", "Bojí se následků a chce syna ochránit", "Udá syna gestapu", "Neřeší to"], - "correct": 1, - "expl": "Otec chápe nebezpečí okupace a snaží se Pavla držet stranou rizika." - }, - { - "prompt": "Jaký literární text ve škole připomíná vztah hrdinů?", - "options": ["Babička", "Romeo a Julie", "Kytice", "1984"], - "correct": 1, - "expl": "Shakespearova tragédie slouží jako přímý vzor i kontrast k pražskému ději." - }, - { - "prompt": "Co symbolizuje „tma“ v názvu?", - "options": ["Jen noční schůzky", "Okupaci, strach, utajení i bezperspektivnost", "Výpadek elektřiny", "Zimní období"], - "correct": 1, - "expl": "Tma znamená temnou dobu dějin i nejistotu milenců." - }, - { - "prompt": "Jak Hanka pomáhá Ester?", - "options": ["Získá pro ni falešné doklady sama", "Skrývá ji doma a tají před okolím", "Provda ji Němcům", "Posílá ji do Švýcarska"], - "correct": 1, - "expl": "Rodina Sedlákových riskuje trest, když u sebe drží pronásledovanou dívku." - }, - { - "prompt": "Jaký je hlavní konflikt novely?", - "options": ["Třídní boj dělníků", "Láska a lidskost vs. rasistický totalitní režim", "Sportovní rivalita", "Náboženská reformace"], - "correct": 1, - "expl": "Osobní vztah naráží na politiku genocidy a strach z udání." - }, - { - "prompt": "Jaký žánr dílo nejlépe vystihuje?", - "options": ["Sci-fi novela", "Milostná novela s válečným a existenčním pozadím", "Detektivka", "Satirická groteska"], - "correct": 1, - "expl": "Jádrem je milostný příběh zasazený do doby holocaustu." - }, - { - "prompt": "Proč Pavel riskuje setkávání s Ester?", - "options": ["Kvůli penězům", "Z lásky a přesvědčení, že lidskost má smysl", "Na příkaz školy", "Aby získal vyznamenání"], - "correct": 1, - "expl": "Pavel jedná z citu i morální povinnosti vůči pronásledované." - }, - { - "prompt": "Co hrozí rodině, která skrývá Žida?", - "options": ["Jen pokuta", "Zatčení, koncentrák nebo poprava", "Přestup na jinou školu", "Nic – bylo to běžné"], - "correct": 1, - "expl": "Pomoc pronásledovaným byla za okupace trestná smrtí." - }, - { - "prompt": "Jak novela končí pro Pavla?", - "options": ["Emigruje do Anglie", "Umírá při pokusu zachránit / následovat Ester", "Žení se s Hankou", "Stává se knězem"], - "correct": 1, - "expl": "Pavel zvolí osud milenky a platí za to životem – tragický závěr." - }, - { - "prompt": "Co se stane s Ester na konci?", - "options": ["Přežije v ilegalitě", "Je odvedena transportem (Terezín)", "Vdá se za Němce", "Odjede s Pavlem"], - "correct": 1, - "expl": "Utajení selže; Ester je chycena perzekučním mechanismem." - }, - { - "prompt": "Které téma v díle NENÍ dominantní?", - "options": ["Láska za války", "Oběť a odvaha", "Rasismus a genocida", "Humor sitcomu z 90. let"], - "correct": 3, - "expl": "Novela je vážná, tragická; nejde o komediální formu." - }, - { - "prompt": "Jak je vyprávění pojaté?", - "options": ["Deníkové zápisky Ester", "Er-forma soustředěná na Pavla", "Epická báseň", "Drama s replikami"], - "correct": 1, - "expl": "Vypravěč sleduje hlavně Pavlovy prožitky a rozhodnutí." - }, - { - "prompt": "Proč je školní prostředí důležité?", - "options": ["Ukazuje normální život mládí v nenormální době", "Je to sci-fi laboratoř", "Slouží jen jako kulisa bez významu", "Popisuje výuku latině"], - "correct": 0, - "expl": "Gymnázium zdůrazňuje kontrast mezi mládím a okupačním terorem." - }, - { - "prompt": "Jaký vztah má novela k české literatuře 60. let?", - "options": ["Patří k reflexi holocaustu a morálky za války", "Je čistě experimentální text", "Je překlad z ruštiny", "Je dětská knížka"], - "correct": 0, - "expl": "Otčenášek přispěl k vážné próze o druhé světové válce." - }, - { - "prompt": "Co znamená motiv okna / balkonu?", - "options": ["Reklamu na okna", "Naději na setkání a paralelu s Julií", "Pohled do Terezína", "Vězení"], - "correct": 1, - "expl": "Okno umožňuje tajné schůzky a odkazuje ke Shakespearovi." - }, - { - "prompt": "Kdo je Hanka vůči Ester?", - "options": ["Sestra", "Spolužačka a ochránkyně v domě", "Gestapák v přestrojení", "Učitelka"], - "correct": 1, - "expl": "Hanka je blízká Ester i Pavlovi a stojí mezi nimi a nebezpečím." - }, - { - "prompt": "Jak funguje strach z udání v díle?", - "options": ["Vůbec se neobjevuje", "Prolíná rodinnými hádkami i rozhodnutími postav", "Je jen v epilogu", "Týká se jen Němců"], - "correct": 1, - "expl": "Atmosféra podezíravosti ovlivňuje každý krok hrdinů." - }, - { - "prompt": "Jaký rozdíl je mezi Pavlem a Julií z Shakespeara?", - "options": ["Pavel je dospělý král", "Pavel jedná v reálné totalitní hrozící smrti milionů", "Pavel nemiluje", "Pavel je Němec"], - "correct": 1, - "expl": "Historický kontext genocidy zvyšuje sázky oproti renesanční tragédii." - }, - { - "prompt": "Proč Otčenášek volil milostnou formu?", - "options": ["Aby čtenáře citově vtáhl do osudu jednotlivců", "Aby napsal učebnici dějepisu", "Aby parodoval romantiku", "Aby vydal cookbook"], - "correct": 0, - "expl": "Osobní příběh zosobňuje oběť holocaustu lépe než statistika." - }, - { - "prompt": "Jaké poselství dílo nejspíš nese?", - "options": ["Lidskost má cenu i za cenu největšího rizika", "Válka je hra", "Láska vždy končí svatbou", "Okupace neexistovala"], - "correct": 0, - "expl": "Pavel a Ester ukazují morální volbu tváří v tvář zlu." - }, - { - "prompt": "Která postava reprezentuje aktivní odpor?", - "options": ["Pavelův otec jako gestapák", "Strýc Petr", "Hankin pes", "Německý turista"], - "correct": 1, - "expl": "Petr je vázán na odbojové prostředí a realitu nebezpečí." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Pavel na gymnáziu za okupace čte Romea a Julii", - "Seznámí se s Ester skrytou u Sedlákových", - "Navazují tajný milostný vztah u okna", - "Petr a rodina varují před rostoucím nebezpečím", - "Ester je prozrazena a odvedena transportem", - "Pavel ji následuje a umírá" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: škola a Shakespear → seznámení s Ester → tajná láska → varování → transport → Pavlova smrt." - ] -} diff --git a/data/cetba/rozmarne-leto.json b/data/cetba/rozmarne-leto.json deleted file mode 100644 index bc0ad5a..0000000 --- a/data/cetba/rozmarne-leto.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Vladislav Vančura (1891–1942)", - "Žánr: poetická novela, groteska", - "Poprvé vydáno: 1926", - "Děj: léto na venkově u Rybníka, maloměstské prostředí", - "Vyprávění: er-forma, lyrický jazyk, koláž výjevů" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Meziválečné Československo, idylické léto plné humoru i tísně.", - "Tři muži – major Hugo, vědec Roch, malíř Hampl – sdílejí dovolenou.", - "Společenské rozdíly, místní pomluvy a letní nálada.", - "Vančura mísí poetiku s groteskními situacemi.", - "Příroda a rybník jako kulisa i symbol klidu.", - "Léto je „rozmarné“ – lehké, ale i nečekaně tragické." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Major Hugo – bývalý důstojník, energický organizátor léta.", - "Roch – vědec, vzdělanec, často terč posměchu.", - "Hampl – malíř, pozorovatel, mírný ironik.", - "Pepča – mladá dívka, oběť utopení.", - "Místní obyvatelé – soudkyňa, farář, sousedé.", - "Tři přátelé tvoří komické i napjaté trojúhelníky." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Groteska – nadsázka, absurdní detaily.", - "Poetika – obrazný, rytmický jazyk Vančury.", - "Léto jako rámec – svoboda vs. společenská klace.", - "Smrt Pepči – náhlý stín v rozmarném ději.", - "Pomluvy – maloměstská morálka.", - "Přátelství tří mužů – generační a charakterový kontrast." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Rozmarné léto?", - "options": [ - "Karel Čapek", - "Vladislav Vančura", - "Ota Pavel", - "Jan Neruda" - ], - "correct": 1, - "expl": "Autorem je Vančura, dílo vyšlo 1926." - }, - { - "prompt": "Kde se děj zčásti odehrává?", - "options": [ - "Pražský hrad", - "Venkov u rybníka / maloměstí", - "Tatra", - "Paříž" - ], - "correct": 1, - "expl": "Léto tráví hrdinové na venkově u vody." - }, - { - "prompt": "Kdo je major Hugo?", - "options": [ - "Kněz", - "Bývalý důstojník, jeden ze tří přátel", - "Rybář Pepča", - "Německý turista" - ], - "correct": 1, - "expl": "Hugo je vitální organizátor prázdnin." - }, - { - "prompt": "Kým je Roch?", - "options": [ - "Malíř", - "Vědec a intelektuál mezi přáteli", - "Soudce", - "Poštmistr" - ], - "correct": 1, - "expl": "Roch představuje vědeckou, někdy směšnou erudici." - }, - { - "prompt": "Co dělá Hampl?", - "options": [ - "Učí dějepis", - "Malíř, pozorovatel děje", - "Lovec", - "Lékař" - ], - "correct": 1, - "expl": "Hampl maluje a komentuje dění." - }, - { - "prompt": "Jaký žánr dílo nejlépe vystihuje?", - "options": [ - "Sci-fi", - "Poetická novela s groteskou", - "Detektivka", - "Epická báseň" - ], - "correct": 1, - "expl": "Vančura kombinuje lyriku a humor." - }, - { - "prompt": "Co se stane Pepči?", - "options": [ - "Vdá se za Huga", - "Utone v rybníce", - "Odchází do Prahy", - "Stane se malířkou" - ], - "correct": 1, - "expl": "Tragické utopení naruší idylu léta." - }, - { - "prompt": "Proč je léto „rozmarné“?", - "options": [ - "Je zima", - "Kolísá mezi lehkostí, humorem a smutnými zvraty", - "Trvá jeden den", - "Je to sci-fi" - ], - "correct": 1, - "expl": "Nálada se mění od radosti k tragédii." - }, - { - "prompt": "Jaký jazyk je typický pro Vančuru?", - "options": [ - "Úřednický", - "Poetický, obrazný, kolážovitý", - "Archaičtina bez obrazů", - "Anglický slang" - ], - "correct": 1, - "expl": "Styl je výrazově bohatý a hudební." - }, - { - "prompt": "Kdo je soudkyně v díle?", - "options": [ - "Pepčina matka", - "Místní autorita, která soudí pomluvy", - "Hugova sestra", - "Rochova žena" - ], - "correct": 1, - "expl": "Soudkyně zosobňuje maloměstskou morálku." - }, - { - "prompt": "Jaký vztah mají tři muži?", - "options": [ - "Jsou bratři", - "Přátelé na prázdninách s rozdílnými charaktery", - "Nepřátelé", - "Spolupracovníci továrny" - ], - "correct": 1, - "expl": "Jejich interakce tvoří jádro humoru." - }, - { - "prompt": "Co symbolizuje rybník?", - "options": [ - "Průmysl", - "Léto, odpočinek, ale i nebezpečí vody", - "Válka", - "Škola" - ], - "correct": 1, - "expl": "Rybník je centrum dění i místo tragédie." - }, - { - "prompt": "Jak končí Rochova anabáze?", - "options": [ - "Stane se králem", - "Je vykázán / opouští místo po konfliktech", - "Zůstane navždy", - "Oženě se s Pepčou" - ], - "correct": 1, - "expl": "Roch musí odejít – jeden z groteskních vrcholů." - }, - { - "prompt": "Které téma v díle najdeme?", - "options": [ - "Kosmické války", - "Maloměstské pomluvy a letní nálada", - "Detektivní vyšetřování v Praze", - "Hladové hry" - ], - "correct": 1, - "expl": "Dílo je zrcadlem provinčního světa." - }, - { - "prompt": "Vančura patří do které literární skupiny?", - "options": [ - "Realismus 19. století", - "Avantgarda (Devětsil)", - "Romantismus", - "Normalizace" - ], - "correct": 1, - "expl": "Vančura byl výrazná avantgardní osobnost." - }, - { - "prompt": "Jak je vyprávění pojaté?", - "options": [ - "Drama s replikami", - "Er-forma s lyrickými odbočkami", - "Deník", - "Scénář filmu" - ], - "correct": 1, - "expl": "Vypravěč vytváří obrazné výjevy." - }, - { - "prompt": "Co je groteska v Rozmarném létě?", - "options": [ - "Pouze realismus", - "Nadsazené, absurdní situace v komickém světle", - "Horor bez humoru", - "Historický dokument" - ], - "correct": 1, - "expl": "Humor vychází z kontrastů a detailů." - }, - { - "prompt": "Proč se Roch stává terčem posměchu?", - "options": [ - "Je bohatý", - "Je pedantský vědec v lehkém letním světě", - "Je dítě", - "Je Němec" - ], - "correct": 1, - "expl": "Jeho vědeckost naráží na prázdninovou atmosféru." - }, - { - "prompt": "Jaká je role faráře / místních?", - "options": [ - "Vedou válku", - "Dotvářejí obraz maloměsta", - "Jsou hlavní hrdinové", - "Neobjevují se" - ], - "correct": 1, - "expl": "Podpůrné postavy vytvářejí prostředí." - }, - { - "prompt": "Jaký kontrast dílo nabízí?", - "options": [ - "Léto vs. smrt", - "Pouze humor", - "Pouze politika", - "Sci-fi vs. western" - ], - "correct": 0, - "expl": "Idyla léta je narušena Pepčinou smrtí." - }, - { - "prompt": "Kdy Vančura zemřel?", - "options": [ - "1926", - "1942 (poprava nacisty)", - "1989", - "1891" - ], - "correct": 1, - "expl": "Spisovatel padl za protinacistický odpor." - }, - { - "prompt": "Co NENÍ typické pro Vančurův styl?", - "options": [ - "Koláž", - "Lyrická próza", - "Suchý úřednický jazyk bez obrazů", - "Groteska" - ], - "correct": 2, - "expl": "Vančura je naopak obrazný a poetický." - }, - { - "prompt": "Jak major Hugo jedná?", - "options": [ - "Pasivně", - "Energicky, organizuje, rozhoduje", - "Jako kněz", - "Jako dítě" - ], - "correct": 1, - "expl": "Hugo táhne děj svou aktivitou." - }, - { - "prompt": "Proč je dílo vhodné k maturitě?", - "options": [ - "Krátké, bohaté na styl a témata", - "Je učebnice", - "Je komiks", - "Nemá děj" - ], - "correct": 0, - "expl": "Ukazuje avantgardní prózu i společenský obraz." - }, - { - "prompt": "Jaký vztah k přírodě dílo má?", - "options": [ - "Příroda chybí", - "Příroda je lyricky vykreslena", - "Jen město", - "Pouze továrna" - ], - "correct": 1, - "expl": "Krajina je součástí poetiky." - }, - { - "prompt": "Co následuje po Pepčině smrti?", - "options": [ - "Válka světová hned", - "Tíživější tón, rozchod letní idyly", - "Svatba", - "Nic se nemění" - ], - "correct": 1, - "expl": "Tragédie změní náladu knihy." - }, - { - "prompt": "Která postava maluje?", - "options": [ - "Roch", - "Hampl", - "Hugo", - "Pepča" - ], - "correct": 1, - "expl": "Hampl je malíř." - }, - { - "prompt": "Jak se dílo liší od realistické novely?", - "options": [ - "Experimentuje s jazykem a groteskou", - "Je to přesný reportážní zápis", - "Je to báseň v jedné větě", - "Je to drama" - ], - "correct": 0, - "expl": "Vančura je avantgardní autor." - }, - { - "prompt": "Jaký je vztah k humoru?", - "options": [ - "Humor chybí", - "Humor je důležitý, i když je děj tragický", - "Pouze slovní hříčka bez děje", - "Jen slapstick" - ], - "correct": 1, - "expl": "Komické scény koexistují se smutnými." - }, - { - "prompt": "Co znamená „rozmarné“ v kontextu postav?", - "options": [ - "Vědecká přesnost", - "Náladovost, lehkost, občasná lehkomyslnost", - "Vojenská disciplína", - "Náboženská zbožnost" - ], - "correct": 1, - "expl": "Léto uvolňuje pravidla a rozproudí vášně i konflikty." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Tři přátelé přijedou na léto k rybníku", - "Probíhají komické konflikty (Roch vs. okolí)", - "Léto plné pomluv, lázní a radovánek", - "Pepča se utopí v rybníce", - "Roch je vykázán z místa", - "Léto končí, idyla je narušena" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: příjezd → konflikty → letní dění → utopení Pepči → odchod Rocha → konec léta." - ] -} diff --git a/data/cetba/rur.json b/data/cetba/rur.json deleted file mode 100644 index b9db7ed..0000000 --- a/data/cetba/rur.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Čapek", - "Žánr: drama (sci-fi); 3 dějství + předehra", - "Poprvé vydáno: 1920 (premiéra 1921, Národní divadlo)", - "Děj: továrna Rossum's Universal Robots na ostrově", - "Vyprávění: dramatická forma, dialogy" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Meziválečí: obavy z techniky, průmyslu a dehumanizace.", - "Slovo „robot“ (od robota = dřina) zavedli bratři Čapkové.", - "Roboti nahrazují lidi v práci i ve válce – lidé leniví.", - "Vzpoura robotů vyhubí lidstvo.", - "Zůstane Alquist a na konci naděje v robotí dvojici.", - "Téma: zodpovědnost vědy, lidskost, práce rukama." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Harry Domin – ředitel R. U. R.", - "Helena Gloryová – idealistka, dcera prezidenta.", - "Dr. Gall – upravuje roboty, dává jim city.", - "Alquist – stavitel, jediný, kdo ještě pracuje rukama.", - "Busman – obchodní ředitel, myslí na zisk.", - "Primus a Helena (roboti) – nový pár na konci." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Robot – umělý dělník; později s duší.", - "R. U. R. – Rossum's Universal Robots.", - "Továrna – hubris vědy a kapitalismu.", - "Vzpoura – důsledek vykořisťování.", - "Lidskost – láska, soucit, manuální práce.", - "Naděje – roboti Primus a Helena milují se." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal R.U.R.?", "options": ["Jaroslav Hašek", "Karel Čapek", "Alois Jirásek", "Franz Kafka"], "correct": 1, "expl": "Drama napsal Karel Čapek; premiéra 1921."}, - {"prompt": "Co znamená zkratka R.U.R.?", "options": ["Rossum's Universal Robots", "Republika umělých robotů", "Rudá uniforma robotů", "Rakouské ústřední rozhlas"], "correct": 0, "expl": "Název továrny Rossum's Universal Robots."}, - {"prompt": "Kdo slovo „robot“ prosadil do světových jazyků?", "options": ["Karel Čapek s bratrem Josefem", "Hašek", "Kafka", "Shakespeare"], "correct": 0, "expl": "Josef Čapek navrhl slovo robot od robota (dřina)."}, - {"prompt": "Kdo je Harry Domin?", "options": ["Robot", "Ředitel továrny", "Prezident státu", "Kněz"], "correct": 1, "expl": "Domin řídí R.U.R. a věří v moc techniky."}, - {"prompt": "Proč přijede Helena Gloryová?", "options": ["Koupit roboty pro válku", "Jako idealistka chce roboty „osvobodit“", "Je lékařka", "Je učitelka"], "correct": 1, "expl": "Helena brojí proti zneužití robotů – humanitní motiv."}, - {"prompt": "Co udělá dr. Gall?", "options": ["Zničí továrnu", "Upraví roboty tak, aby měli city a duši", "Stane se prezidentem", "Odejde do kláštera"], "correct": 1, "expl": "Gallova změna urychlí vzpouru – roboti cítí bolest a hněv."}, - {"prompt": "Kdo je Alquist?", "options": ["Obchodník", "Stavitel – jediný člověk, který ještě dře rukama", "Robot", "Novinář"], "correct": 1, "expl": "Alquist přežije jako symbol manuální práce a lidskosti."}, - {"prompt": "Jak skončí lidstvo v dramatu?", "options": ["Vítězí nad roboty", "Roboti vyhubí lidi (kromě Alquista)", "Emigruje na Mars", "Nikdy neumírá"], "correct": 1, "expl": "Vzpoura robotů je apokalypsa – zůstane jen Alquist."}, - {"prompt": "Kdo je Busman?", "options": ["Robot", "Obchodní ředitel – myslí na zisk", "Helenin otec", "Voják"], "correct": 1, "expl": "Busman reprezentuje kapitalistickou logiku prodeje robotů."}, - {"prompt": "Jak drama končí?", "options": ["Všichni lidé se vrátí", "Alquist objeví lásku robotů Primuse a Heleny – naděje na nový začátek", "Roboti se vypnou navždy", "Továrna exploduje bez pointy"], "correct": 1, "expl": "Robotí pár miluje se – možná nová „lidskost“."}, - {"prompt": "Jaký je žánr R.U.R.?", "options": ["Lyrika", "Drama / sci-fi", "Román", "Epos"], "correct": 1, "expl": "Jde o divadelní hru s futuristickým tématem."}, - {"prompt": "Proč lidé v dramatu leniví?", "options": ["Roboti dělají veškerou práci", "Jsou nemocní", "Zákaz práce", "Jsou na dovolené"], "correct": 0, "expl": "Závislost na robotech oslabí lidstvo – varování Čapka."}, - {"prompt": "Co je hlavní varování hry?", "options": ["Nechat vědu bez etiky a člověka bez práce", "Nepoužívat elektřinu", "Zakázat divadlo", "Vypěstovat více brambor"], "correct": 0, "expl": "Čapek varuje před mechanizací života a ztrátou lidskosti."}, - {"prompt": "Kdy byla premiéra?", "options": ["1914", "1921", "1948", "1989"], "correct": 1, "expl": "Premiéra v Národním divadle 1921."}, - {"prompt": "Kdo je Rossum v názvu?", "options": ["Vynálezce robotů (legenda firmy)", "Robot Primus", "Helenin bratr", "Císař"], "correct": 0, "expl": "Old Rossum – vědec, od něj odvozeno jméno továrny."}, - {"prompt": "Proč roboti povstávají?", "options": ["Náhodou", "Kvůli bolesti, vykořisťování a Gallovým úpravám", "Na rozkaz Domin", "Kvůli počasí"], "correct": 1, "expl": "Roboti získají duši a odmítají být otroky."}, - {"prompt": "Která postava je idealistka?", "options": ["Helena Gloryová", "Busman", "Domin", "Alquist"], "correct": 0, "expl": "Helena přijede bránit roboty – etický hlas."}, - {"prompt": "Co je typické pro Čapkovo drama?", "options": ["Filozofické otázky v moderní formě", "Pouze historická kronika", "Beletrie bez dialogu", "Pouze komedie bez myšlenky"], "correct": 0, "expl": "Čapek spojuje zábavu s varováním před technikou."}, - {"prompt": "Které téma NENÍ v R.U.R.?", "options": ["Vzpoura robotů", "Lidskost a láska", "Středověké rytířství", "Zodpovědnost vědy"], "correct": 2, "expl": "Hra je futuristická, ne rytířská."}, - {"prompt": "Kdo přežije mezi lidmi?", "options": ["Domin", "Busman", "Alquist", "Helena Gloryová (člověk)"], "correct": 2, "expl": "Alquist zůstane jako poslední člověk pracující rukama."}, - {"prompt": "Jak se jmenují roboti v závěrečné naději?", "options": ["Primus a Helena (robot)", "Romeo a Julie", "Švejk a Lukáš", "Napoleon a Boxer"], "correct": 0, "expl": "Robot Primus a robotka Helena se milují – nový začátek."}, - {"prompt": "Proč je R.U.R. důležité pro maturitu?", "options": ["Je mapa", "Čapek, robot, témata, forma dramatu", "Je cookbook", "Je zákoník"], "correct": 1, "expl": "U maturity: autor, děj, postavy, slovo robot, témata."}, - {"prompt": "Kde se děj odehrává?", "options": ["V továrně na roboty (ostrov)", "V Praze na Václaváku", "Ve středověku", "Na Měsíci"], "correct": 0, "expl": "Ostrovní továrna R.U.R. je jeviště děje."}, - {"prompt": "Co prodává R.U.R.?", "options": ["Knihy", "Umělé dělníky – roboty", "Potraviny", "Auta"], "correct": 1, "expl": "Roboti slouží průmyslu i armádám po světě."}, - {"prompt": "Jaký vztah má Domin k Heleně?", "options": ["Vezme si ji", "Nepozná ji", "Je to robot", "Je to sestra"], "correct": 0, "expl": "Domin a Helena se sblíží – lidský vztah vedle robotů."}, - {"prompt": "Co Gallova změna způsobí?", "options": ["Roboti jsou šťastnější otroci", "Roboti cítí a vzpourou se", "Roboti zmizí", "Lidé pracují víc"], "correct": 1, "expl": "Duše robotů je katalyzátor revolty."}, - {"prompt": "Které dílo NENÍ Čapkovo?", "options": ["R.U.R.", "Válka s mloky", "Osudy dobrého vojáka Švejka", "Bílá nemoc"], "correct": 2, "expl": "Švejka napsal Hašek."}, - {"prompt": "Jaký je tón závěru?", "options": ["Čistá apokalypsa bez naděje", "Tragédie s glorií naděje v lásce robotů", "Pouze fraška", "Historický dokument"], "correct": 1, "expl": "Čapek končí optimistickým gestem – život pokračuje."}, - {"prompt": "Kdo myslí hlavně na obchod?", "options": ["Busman", "Alquist", "Helena", "Primus"], "correct": 0, "expl": "Busman počítá zisk z prodeje robotů."}, - {"prompt": "Co znamená „lidskost“ v R.U.R.?", "options": ["Pouze biologie", "Práce, soucit, láska – ne jen efektivita", "Válka", "Lenost"], "correct": 1, "expl": "Alquist a závěr ukazují, co přežije beyond techniky."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Helena přijede do továrny R.U.R.", - "Domin ukazuje výrobu robotů a svět obchodu", - "Gall upraví roboty – získají city", - "Vzpoura robotů a vyhubení lidí", - "Zůstane Alquist jako poslední člověk", - "Láska robotů Primuse a Heleny – naděje" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: Helena v továrně → obchod s roboty → Gallova úprava → vzpoura → Alquist → Primus a Helena." - ] -} diff --git a/data/cetba/ruze-pro-algernon.json b/data/cetba/ruze-pro-algernon.json deleted file mode 100644 index a90c8a7..0000000 --- a/data/cetba/ruze-pro-algernon.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Daniel Keyes (1927–2014)", - "Žánr: sci-fi novela / psychologická próza", - "Poprvé vydáno: 1966 (novela; povídka 1959)", - "Děj: USA, vědecký experiment na inteligenci", - "Forma: deníkové zápisy Charlieho Gordona" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Společnost hodnotí inteligenci jako měřítko lidské hodnoty.", - "Vědecký experiment na mozku – etické otázky.", - "Charlie začíná jako mentálně postižený, stává se géniem.", - "Osamělost inteligentního člověka mezi bývalými přáteli.", - "Algernon – laboratorní myš jako zrcadlo Charlieho osudu.", - "Příběh varuje před arogancí vědy i lidské krutosti." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Charlie Gordon – hlavní hrdina, autora deníku.", - "Algernon – myš, první úspěšný experiment.", - "Dr. Strauss a profesor Nemur – vědci.", - "Alice Kinnian – učitelka, Charlieho opora.", - "Rose Gordon – matka, traumatický vztah k synovi.", - "Kolegové z pekárny – dříve se smějí, později se bojí." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Deník – forma ukazuje vývoj jazyka a myšlení.", - "IQ vs. emoční inteligence – Charlie sílí, ale trpí.", - "Algernonův pokles – předzvěst Charlieho konce.", - "Květy pro Algernona – soucit a vděčnost.", - "Etika experimentu – souhlas a informovanost.", - "Osamělost – cena rychlého vědeckého pokroku." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Růži pro Algernona?", - "options": [ - "Isaac Asimov", - "Daniel Keyes", - "Ray Bradbury", - "Orwell" - ], - "correct": 1, - "expl": "Autorem je Daniel Keyes." - }, - { - "prompt": "Jakou formu má novela?", - "options": [ - "Drama", - "Deníkové zápisy Charlieho", - "Epická báseň", - "Dopisy" - ], - "correct": 1, - "expl": "Text simuluje Charlieho rostoucí jazykové i myšlenkové schopnosti." - }, - { - "prompt": "Kdo je Algernon?", - "options": [ - "Pes", - "Laboratorní myš", - "Charlieův bratr", - "Profesor" - ], - "correct": 1, - "expl": "Myš prošla stejnou operací jako Charlie." - }, - { - "prompt": "Kde Charlie pracuje na začátku?", - "options": [ - "V bance", - "V pekárně", - "Na univerzitě", - "V nemocnici" - ], - "correct": 1, - "expl": "Kolegové se mu smějí, ale nechává si to líbit." - }, - { - "prompt": "Co vědci Charlieovi slibují?", - "options": [ - "Zázračnou dietu", - "Operaci zvýšení inteligence", - "Cestu na Měsíc", - "Sňatek" - ], - "correct": 1, - "expl": "Experiment má zvýšit IQ." - }, - { - "prompt": "Kdo je Alice Kinnian?", - "options": [ - "Vědkyně", - "Učitelka dospělých, podporuje Charlieho", - "Charlieho sestra", - "Sestra Nemura" - ], - "correct": 1, - "expl": "Alice je etickou oporou příběhu." - }, - { - "prompt": "Co se děje s Charlieho IQ po operaci?", - "options": [ - "Klesá hned", - "Rychle roste na génius", - "Nemění se", - "Klesá na nulu" - ], - "correct": 1, - "expl": "Charlie začne chápat svět i minulost bolestně jasně." - }, - { - "prompt": "Proč se kolegové z pekárny od Charlieho vzdalují?", - "options": [ - "Bojí se jeho inteligence a cizího", - "Dostal funkci ředitele", - "Odešel do vězení", - "Ne – stále ho milují" - ], - "correct": 0, - "expl": "Charlie už mezi nimi nemá místo." - }, - { - "prompt": "Co odhalí vzpomínky na matku?", - "options": [ - "Lásku bez podmínek", - "Trauma, stud a odmítání postiženého syna", - "Emigraci", - "Nobelovu cenu" - ], - "correct": 1, - "expl": "Rodinná minulost bolí." - }, - { - "prompt": "Co se stane s Algernonem?", - "options": [ - "Žije navěky", - "Inteligence klesá a myš umírá", - "Uteče", - "Stane se člověkem" - ], - "correct": 1, - "expl": "Pokles předpovídá Charlieův osud." - }, - { - "prompt": "Jak Charlie reaguje na Algernonovu smrt?", - "options": [ - "Radost", - "Položí květiny – odtud název", - "Zapomene", - "Zničí laboratoř" - ], - "correct": 1, - "expl": "Soucit s myší je vrchol jeho humanity." - }, - { - "prompt": "Proč Charlie konfliktuje s Nemurem?", - "options": [ - "Kvůli fotbalu", - "Vědec je arogantní, Charlie vidí chyby experimentu", - "Kvůli jídlu", - "Kvůli manželce" - ], - "correct": 1, - "expl": "Charlie chápe vědu hlouběji než tvůrce experimentu." - }, - { - "prompt": "Jak se mění Charlieův jazyk v deníku?", - "options": [ - "Beze změny", - "Od pravopisných chyb k vědecké přesnosti a zpět", - "Do latině", - "Do němčiny" - ], - "correct": 1, - "expl": "Jazyk je měřítkem inteligence." - }, - { - "prompt": "Jak skončí Charlie?", - "options": [ - "Je prezident", - "Inteligence klesá, vrací se do pekárny, umírá v ústavu", - "Emigruje", - "Ožení se a žije šťastně" - ], - "correct": 1, - "expl": "Tragický pád po vrcholu." - }, - { - "prompt": "Co téma etiky zdůrazňuje?", - "options": [ - "Experiment bez rizika je v pořádku", - "Lidský život není jen IQ", - "Věda je vždy zlá", - "Deník je neetický" - ], - "correct": 1, - "expl": "Keyes kritizuje redukci člověka na číslo." - }, - { - "prompt": "Který žánr sedí nejlépe?", - "options": [ - "Sci-fi s psychologickým jádrem", - "Historický román", - "Pohádka", - "Detektivka" - ], - "correct": 0, - "expl": "Vědecký základ + hluboká psychologie." - }, - { - "prompt": "Proč Charlie miloval učení už jako postižený?", - "options": [ - "Ne – nenáviděl", - "Toužil být chytřejší a „normální“", - "Chtěl být bohatý", - "Musel na rozkaz" - ], - "correct": 1, - "expl": "Motivace je touha po přijetí." - }, - { - "prompt": "Co znamená „normální“ pro Charlieho?", - "options": [ - "Být bohatý", - "Být přijat společností jako rovnocenný", - "Být slavný", - "Nečíst" - ], - "correct": 1, - "expl": "Společenské normy jsou klíčové." - }, - { - "prompt": "Jaký vztah k Alice?", - "options": [ - "Nikdy se nevidí", - "Láska, která komplikuje Charlieho proměnu", - "Sourozenci", - "Nepřátelé" - ], - "correct": 1, - "expl": "Alice miluje Charlieho jako člověka, ne jen IQ." - }, - { - "prompt": "Co Charlie objeví o „inteligentních“?", - "options": [ - "Jsou vždy milí", - "Mohou být stejně krutí a osamělí", - "Neexistují", - "Jsou všichni vědci" - ], - "correct": 1, - "expl": "Vysoké IQ neřeší morálku." - }, - { - "prompt": "Kde se vrací na konci?", - "options": [ - "Do vesmíru", - "Do pekárny / ústavu", - "Do školy", - "Do vězení" - ], - "correct": 1, - "expl": "Kruhový návrat k počátku." - }, - { - "prompt": "Jaký film/novela ocenění?", - "options": [ - "Ignorováno", - "Nezískala Nobelovu cenu, ale je světově známá", - "Pouze v ČR", - "Jen divadlo" - ], - "correct": 1, - "expl": "Dílo je klasikou světové literatury." - }, - { - "prompt": "Co NENÍ hlavní téma?", - "options": [ - "Inteligence a identita", - "Etika vědy", - "Soucit", - "Kosmické války" - ], - "correct": 3, - "expl": "Děj je psychologický, ne space opera." - }, - { - "prompt": "Proč deník funguje jako forma?", - "options": [ - "Čtenář vidí proměnu zevnitř", - "Je to úřední protokol", - "Je to poezie", - "Je to horor" - ], - "correct": 0, - "expl": "Subjektivní záznam je autentický." - }, - { - "prompt": "Kdo se směje na začátku?", - "options": [ - "Charlie sám", - "Kolegové z pekárny", - "Nikdo", - "Algernon" - ], - "correct": 1, - "expl": "Charlie nerozumí posměchu plně." - }, - { - "prompt": "Co Charlie chápe po operaci o posměchu?", - "options": [ - "Nic", - "Bolest a ponižování minulosti", - "Je to lichotka", - "Je to věda" - ], - "correct": 1, - "expl": "Vhled bolí víc než nevědomost." - }, - { - "prompt": "Jaký symbol mají květiny?", - "options": [ - "Vítězství", - "Úcta k malému tvorovi a vlastnímu úpadku", - "Svatba", - "Válka" - ], - "correct": 1, - "expl": "Růže pro Algernona = soucit." - }, - { - "prompt": "Jaký je tón závěru?", - "options": [ - "Čistá radost", - "Tragický, dojemný", - "Komický bez smutku", - "Ironický satira" - ], - "correct": 1, - "expl": "Charlie se vrací k mentálnímu stavu a umírá osamělý." - }, - { - "prompt": "Co Keyes kritizuje?", - "options": [ - "Pekárny", - "Přehnanou důvěru ve vědu bez humanity", - "Deníky", - "Myši" - ], - "correct": 1, - "expl": "Experiment má cenu v lidských životech." - }, - { - "prompt": "Kolik otázek má maturitní test z knihy typicky?", - "options": [ - "0", - "Desítky faktů o ději, postavách, tématech", - "Jen autor", - "Jen rok" - ], - "correct": 1, - "expl": "Dílo je bohaté na postavy a témata." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Charlie pracuje v pekárně a píše deník", - "Podstoupí operaci zvýšení inteligence", - "IQ roste, odhalí bolest minulosti", - "Algernonova inteligence klesá a myš umírá", - "Charlie chápe vlastní úpadek", - "Vrací se k původnímu stavu a umírá" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: pekárna → operace → vzestup → Algernon → úpadek → návrat a smrt." - ] -} diff --git a/data/cetba/saturnin.json b/data/cetba/saturnin.json deleted file mode 100644 index 794a159..0000000 --- a/data/cetba/saturnin.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Zdeněk Jirotka (1911–2003)", - "Žánr: humoristická novela", - "Poprvé vydáno: 1942", - "Děj: pražská rodina a sluha Saturnin", - "Vyprávění: ich-forma vypravěče (syn rodiny)" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Meziválečná / válečná Praha v lehkém, absurdním světle.", - "Saturnin dělá „všechno jinak“ a rozpoutá chaos.", - "Sousedé, teta a učitel doplňují komické situace.", - "Humor z nedorozumění a vynalézavosti.", - "Rodina se Saturninem musí řešit nečekané problémy.", - "Kniha je cult classic české humoristické prózy." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Saturnin – tajemný, vynalézavý sluha, původ nejasný.", - "Vypravěč – mladý člen rodiny, pozorovatel.", - "Teta – bystrá, často v konfliktu se Saturninem.", - "Pan učitel – pedantský, terč satiry.", - "Sousedé – další zdroj komických situací.", - "Milouš – postava spojená s dětmi / lumpárnami." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Sluha jako motor děje – Saturnin řídí absurditu.", - "Humor nedorozumění – místo logiky kreativní výmluvy.", - "Pražské prostředí – byt, sousedé, škola.", - "Lumpárny – dětské/nezbedné akce.", - "Rodinná idyla narušená sluhou.", - "Jazyk – hovorové, živé dialogy." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Saturnina?", - "options": [ - "Čapek", - "Zdeněk Jirotka", - "Hašek", - "Němcová" - ], - "correct": 1, - "expl": "Autorem je Jirotka, kniha 1942." - }, - { - "prompt": "Kdo je Saturnin?", - "options": [ - "Pes", - "Sluha s neobvyklými nápady", - "Učitel", - "Policista" - ], - "correct": 1, - "expl": "Saturnin je hlavní komická postava." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Saturnin", - "Člen rodiny (syn)", - "Teta", - "Učitel" - ], - "correct": 1, - "expl": "Ich-forma mladého vypravěče." - }, - { - "prompt": "Jaký je žánr?", - "options": [ - "Tragedie", - "Humoristická novela", - "Sci-fi", - "Básnická skladba" - ], - "correct": 1, - "expl": "Dílo je komické od začátku do konce." - }, - { - "prompt": "Kde se děj odehrává?", - "options": [ - "Venkov", - "Praha – rodinný byt a okolí", - "Moře", - "Amerika" - ], - "correct": 1, - "expl": "Pražské prostředí je typické." - }, - { - "prompt": "Jak Saturnin řeší problémy?", - "options": [ - "Vždy logicky", - "Vynalézavě, často absurdně", - "Vůbec", - "Volá policii" - ], - "correct": 1, - "expl": "Jeho metody jsou zdrojem humoru." - }, - { - "prompt": "Kdo je teta?", - "options": [ - "Saturninova manželka", - "Příbuzná v domě, komické konflikty", - "Učitelka", - "Sousedka bez role" - ], - "correct": 1, - "expl": "Teta často stojí proti Saturninovi." - }, - { - "prompt": "Co je pan učitel?", - "options": [ - "Hrdina bez humoru", - "Pedantská postava, terč satiry", - "Saturninův bratr", - "Němec" - ], - "correct": 1, - "expl": "Učitel představuje malichernou autoritu." - }, - { - "prompt": "Jaký humor převažuje?", - "options": [ - "Černý bez radosti", - "Situační a slovní", - "Horor", - "Politická satira bez vtipu" - ], - "correct": 1, - "expl": "Nedorozumění a dialogy jsou klíč." - }, - { - "prompt": "Proč je Saturnin tajemný?", - "options": [ - "Je špion", - "Jeho minulost a motivy jsou nejasné", - "Je duch", - "Je robot" - ], - "correct": 1, - "expl": "Autor nechává prostor pro dohady." - }, - { - "prompt": "Co jsou lumpárny?", - "options": [ - "Vážné zločiny", - "Nezbednosti / žertíky", - "Vědecké experimenty", - "Válka" - ], - "correct": 1, - "expl": "Součást humoru a dětského světa." - }, - { - "prompt": "Kdy kniha vyšla?", - "options": [ - "1942", - "1890", - "2005", - "1968" - ], - "correct": 0, - "expl": "Saturnin vyšel za války." - }, - { - "prompt": "Má kniha pokračování?", - "options": [ - "Ne, nikdy", - "Ano, další díly o Saturninovi", - "Je to trilogie Tolkinova", - "Je to drama" - ], - "correct": 1, - "expl": "Jirotka Saturnina rozvinul v dalších knihách." - }, - { - "prompt": "Jak reaguje rodina na Saturnina?", - "options": [ - "Okamžitě ho vyhodí", - "Kombinace obdivu, vzteku a závislosti", - "Neznají ho", - "Udají ho" - ], - "correct": 1, - "expl": "Saturnin je nepostradatelný i nebezpečný." - }, - { - "prompt": "Co NENÍ typické?", - "options": [ - "Lehký tón", - "Absurdní situace", - "Stálá politická allegorie jako u 1984", - "Dialogy" - ], - "correct": 2, - "expl": "Saturnin je především humor, ne dystopie." - }, - { - "prompt": "Jaká role mají sousedé?", - "options": [ - "Žádná", - "Přidávají komické konflikty", - "Vedou válku", - "Jsou detektivové" - ], - "correct": 1, - "expl": "Sousedské vztahy rozproudí děj." - }, - { - "prompt": "Proč je dílo populární u maturit?", - "options": [ - "Krátké, čtivé, jasné postavy", - "Bez děje", - "Jen poezie", - "Cizí jazyk" - ], - "correct": 0, - "expl": "Snadno se shrnuje děj i humor." - }, - { - "prompt": "Jaký je vztah vypravěče a Saturnina?", - "options": [ - "Nenávist", - "Fascinace a spolupráce v lumpárnách", - "Manželé", - "Učitel–žák" - ], - "correct": 1, - "expl": "Vypravěč Saturnina často obdivuje." - }, - { - "prompt": "Co Saturnin „umí“ nejlépe?", - "options": [ - "Mlčet", - "Vymýšlet nečekaná řešení", - "Vařit jen polévku", - "Létat" - ], - "correct": 1, - "expl": "Je mistr improvizace." - }, - { - "prompt": "Jak končí většina epizod?", - "options": [ - "Tragedií", - "Rozuzlením komického chaosu", - "Válka", - "Transport" - ], - "correct": 1, - "expl": "Formát je episodický humor." - }, - { - "prompt": "Který autor je blízký žánrem?", - "options": [ - "Jirotka – humor próza", - "Shakespeare – tragédie", - "Borovský – elegie", - "Vančura – groteska bez humoru" - ], - "correct": 0, - "expl": "Jirotka je klasik českého humoru." - }, - { - "prompt": "Co znamená jméno Saturnin?", - "options": [ - "Náhodné", - "Evokuje starověk / tajemno (ironicky)", - "Německý generál", - "Pes" - ], - "correct": 1, - "expl": "Jméno dodává postavě patos i komiku." - }, - { - "prompt": "Jaký jazyk?", - "options": [ - "Archaičtina", - "Spisovná čeština s hovorovými prvky", - "Angličtina", - "Latině" - ], - "correct": 1, - "expl": "Čtivé, přirozené dialogy." - }, - { - "prompt": "Je Saturnin zlý?", - "options": [ - "Ano, vrah", - "Ne – spíš rošťák a vynálezce chaosu", - "Anděl", - "Historická postava" - ], - "correct": 1, - "expl": "Je sympatický provokatér." - }, - { - "prompt": "Co děti v knize?", - "options": [ - "Neexistují", - "Účastní se lumpáren", - "Vedou válku", - "Jsou dospělí" - ], - "correct": 1, - "expl": "Dětský svět doplňuje humor." - }, - { - "prompt": "Hlavní konflikt?", - "options": [ - "Saturnin vs. pořádek domácnosti", - "Napoleon vs. Wellington", - "Věda vs. víra", - "Detektiv vs. vrah" - ], - "correct": 0, - "expl": "Sluha bourá klid rodiny." - }, - { - "prompt": "Tón knihy?", - "options": [ - "Depresivní", - "Optimistický humor", - "Naturalismus", - "Epický smutek" - ], - "correct": 1, - "expl": "Čtenář se má bavit." - }, - { - "prompt": "Adaptace?", - "options": [ - "Film/seriál v ČR známé", - "Nikdy", - "Opera Wagner", - "Balet" - ], - "correct": 0, - "expl": "Saturnin je známý i z obrazovky." - }, - { - "prompt": "Co si odnést k maturitě?", - "options": [ - "Postavy, humor, typ sluhy v literatuře", - "Jen rok vydání", - "Jen Praha mapa", - "Nic" - ], - "correct": 0, - "expl": "Dílo je o charakteru Saturnina a stylu." - }, - { - "prompt": "Saturnin pracuje pro?", - "options": [ - "Císaře", - "Pražskou rodinu", - "Školu", - "Cirkus" - ], - "correct": 1, - "expl": "Rodinný sluha je jádro děje." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Rodina najme sluhu Saturnina", - "Saturnin rozpoutá lumpárny a chaos", - "Konflikty s tetou a učitelem", - "Sousedé řeší absurdní situace", - "Saturnin vše „vyřeší“ po svém", - "Klid je jen na chvíli – humor pokračuje" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: nástup Saturnina → lumpárny → konflikty → sousedé → improvizované řešení → pokračující chaos." - ] -} diff --git a/data/cetba/sluha-dvou-panu.json b/data/cetba/sluha-dvou-panu.json deleted file mode 100644 index ff79b6c..0000000 --- a/data/cetba/sluha-dvou-panu.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Carlo Goldoni (1707–1793)", - "Žánr: komedie dell'arte / prozaické drama", - "Poprvé uvedeno: 1746 (revize)", - "Děj: Benátky, sluha slouží dvěma pánům", - "Forma: divadelní hra – dialogy, komické záměny" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Italská komedie dell'arte – typové postavy, improvizace.", - "Sluha Truffaldino slouží současně dvěma pánům.", - "Záměny dopisů, peněz a identit.", - "Láska služebných párů vs. třídní bariéry.", - "Goldoni reformuje dell'arte směrem k psanému textu.", - "Rychlé tempo, fyzický humor, happy end." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Truffaldino – lstivý sluha, slouží Beatrice i Florindovi.", - "Beatrice – dívka v mužském převleku hledá milého.", - "Florindo – benátský milovník Beatrice.", - "Pantalone – lakomý stařec, typ dell'arte.", - "Brighella – hospodský, pomáhá záměnám.", - "Smeraldina – služka, Truffaldinova milá." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Commedia dell'arte – masky, typy, slapstick.", - "Dvojí služba – jádro komického konfliktu.", - "Převlek – Beatrice jako „pan Federigo“.", - "Záměny dopisů a zavazadel.", - "Služební láska – Truffaldino a Smeraldina.", - "Goldoni – literární komedie místo čisté improvizace." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Sluhu dvou pánů?", - "options": [ - "Molière", - "Carlo Goldoni", - "Shakespeare", - "Gogol" - ], - "correct": 1, - "expl": "Goldoni je italský autor komedií." - }, - { - "prompt": "Jak se jmenuje sluha?", - "options": [ - "Figaro", - "Truffaldino", - "Saturnin", - "Svejk" - ], - "correct": 1, - "expl": "Truffaldino je hlavní komická postava." - }, - { - "prompt": "Kolik pánů slouží?", - "options": [ - "Jeden", - "Dva současně (tajně)", - "Deset", - "Žádného" - ], - "correct": 1, - "expl": "Dvojí služba je zdroj záměn." - }, - { - "prompt": "Kdo je Beatrice?", - "options": [ - "Služka bez role", - "Dívka v převleku muže hledající Florinda", - "Pantalonova žena", - "Královna" - ], - "correct": 1, - "expl": "Beatrice hraje roli Federiga." - }, - { - "prompt": "Kdo je Florindo?", - "options": [ - "Sluha", - "Milovník Beatrice", - "Doktor", - "Vojevoda" - ], - "correct": 1, - "expl": "Florindo je jeden z „pánů“." - }, - { - "prompt": "Co je commedia dell'arte?", - "options": [ - "Tragedie", - "Italská komedie s typovými postavami", - "Opera", - "Epos" - ], - "correct": 1, - "expl": "Tradice Arlecchina, Pantalone atd." - }, - { - "prompt": "Kdo je Pantalone?", - "options": [ - "Mladý hrdina", - "Lakomý stařec, typ dell'arte", - "Sluha", - "Kněz" - ], - "correct": 1, - "expl": "Pantalone je klasická maska." - }, - { - "prompt": "Kdo je Brighella?", - "options": [ - "Hospodský pomáhající záměnám", - "Král", - "Beatricin otec v převleku", - "Němec" - ], - "correct": 0, - "expl": "Brighella organizuje část komplikací." - }, - { - "prompt": "Kdo je Smeraldina?", - "options": [ - "Služka, milá Truffaldina", - "Beatrice", - "Vdova", - "Učitelka" - ], - "correct": 0, - "expl": "Služební pár kontrastuje k šlechtě." - }, - { - "prompt": "Proč Truffaldino slouží dvěma?", - "options": [ - "Chce být bohatý – dvojí plat", - "Nevědomky / lstivě", - "Na rozkaz císaře", - "Kvůli pomstě" - ], - "correct": 1, - "expl": "Chce profit, riskuje odhalení." - }, - { - "prompt": "Co se zaměňuje?", - "options": [ - "Jen jídlo", - "Dopisy, zavazadla, peníze", - "Nic", - "Jen domy" - ], - "correct": 1, - "expl": "Záměny pohánějí děj." - }, - { - "prompt": "Jak končí hra?", - "options": [ - "Všichni umírají", - "Rozuzlení, sňatky, happy end", - "Válka", - "Transport" - ], - "correct": 1, - "expl": "Klasická komedie končí sblížením." - }, - { - "prompt": "Kde se děj odehrává?", - "options": [ - "Praha", - "Benátky", - "Moskva", - "Londýn" - ], - "correct": 1, - "expl": "Benátské prostředí." - }, - { - "prompt": "Goldoni reformoval?", - "options": [ - "Tragedii", - "Dell'arte směrem k psané komedii", - "Operu", - "Epos" - ], - "correct": 1, - "expl": "Goldoni stabilizoval text hry." - }, - { - "prompt": "Jaký humor?", - "options": [ - "Pouze slovní", - "Situační, fyzický, záměny", - "Horor", - "Bez humoru" - ], - "correct": 1, - "expl": "Rychlé komické situace." - }, - { - "prompt": "Beatrice proč v převleku?", - "options": [ - "Sport", - "Hledá Florinda a cestuje bezpečně", - "Je to trest", - "Neví" - ], - "correct": 1, - "expl": "Převlek je motor děje." - }, - { - "prompt": "Truffaldino a Smeraldina?", - "options": [ - "Nepřátelé", - "Milenci ze služebnictva", - "Sourozenci", - "Pantalone" - ], - "correct": 1, - "expl": "Paralelní milostná linka." - }, - { - "prompt": "Co hrozí při odhalení?", - "options": [ - "Vtip končí", - "Truffaldino může být potrestán / komické chaosy", - "Nic", - "Válka" - ], - "correct": 1, - "expl": "Hrozba odhalení drží napětí." - }, - { - "prompt": "Typ hry pro maturitu?", - "options": [ - "Drama – komedie", - "Lyrika", - "Epika bez dialogů", - "Pohádka" - ], - "correct": 0, - "expl": "Jde o divadelní text." - }, - { - "prompt": "Kdo je Arlecchino v tradici?", - "options": [ - "Předchůdce sluhy/loutny", - "Král", - "Vědec", - "Kněz" - ], - "correct": 0, - "expl": "Truffaldino vychází z typu sluhy." - }, - { - "prompt": "Proč služba dvěma pánům vtipná?", - "options": [ - "Logická", - "Obě strany chtějí jídlo/dopisy ve stejný čas", - "Bez děje", - "Tragická" - ], - "correct": 1, - "expl": "Fyzický komický stres." - }, - { - "prompt": "Goldoni žil kdy?", - "options": [ - "18. století", - "20. století", - "Antika", - "21. století" - ], - "correct": 0, - "expl": "Goldoni 1707–1793." - }, - { - "prompt": "Hlavní téma?", - "options": [ - "Válka", - "Láska, lstivost, třídní hra", - "Věda", - "Detektivka" - ], - "correct": 1, - "expl": "Komedie lásky a identit." - }, - { - "prompt": "Pantalone je typicky?", - "options": [ - "Mladý milovník", - "Lakomý stařec", - "Sluha", - "Voják" - ], - "correct": 1, - "expl": "Ekonomický humor." - }, - { - "prompt": "Co NENÍ v dell'arte?", - "options": [ - "Typové postavy", - "Improvizace tradice", - "Vždy tragický konec", - "Masky" - ], - "correct": 2, - "expl": "Komedie končí obvykle happy endem." - }, - { - "prompt": "Florindo a Beatrice na konci?", - "options": [ - "Rozchod", - "Spojení / sňatek", - "Smrt", - "Emigrace" - ], - "correct": 1, - "expl": "Milenci se najdou." - }, - { - "prompt": "Truffaldino na konci?", - "options": [ - "Oběsí se", - "Obvykle vítězí lstí, získá Smeraldinu", - "Zmizí", - "Stane se králem" - ], - "correct": 1, - "expl": "Sluha často „vyhrává“ komedii." - }, - { - "prompt": "Proč maturita?", - "options": [ - "Klasická komedie, jasná struktura", - "Bez postav", - "Jen poezie", - "Cizí bez překladu" - ], - "correct": 0, - "expl": "České překlady jsou standardem." - }, - { - "prompt": "Jaký rytmus hry?", - "options": [ - "Pomalý", - "Rychlý, gradace záměn", - "Bez děje", - "Epický" - ], - "correct": 1, - "expl": "Komedie graduje ke koci." - }, - { - "prompt": "Co čtenář/ divák sleduje?", - "options": [ - "Chemii", - "Sled záměn kvůli dvojí službě", - "Válku", - "Básně" - ], - "correct": 1, - "expl": "Mechanismus dvou pánů je jádro." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Truffaldino najme službu u prvního pána", - "Tajně slouží i druhému", - "Beatrice v převleku hledá Florinda", - "Záměny dopisů a jídla", - "Hrozí odhalení dvojí služby", - "Happy end – páry spolu, chaos rozuzlen" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: první pán → druhý pán → převlek Beatrice → záměny → hrozba odhalení → happy end." - ] -} diff --git a/data/cetba/smrt-krasnych-srncu.json b/data/cetba/smrt-krasnych-srncu.json deleted file mode 100644 index 66cb855..0000000 --- a/data/cetba/smrt-krasnych-srncu.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Ota Pavel (1930–1973)", - "Žánr: autobiografické povídky / humoristická próza", - "Poprvé vydáno: 1971", - "Děj: vzpomínky na dětství a válku (Příbramsko)", - "Forma: soubor povídek spojených rodinou a přírodou" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Dětství v rodině holiče a rybářských vášní.", - "Protektorát – otec v koncentračním táboře.", - "Příroda, rybaření, sport jako únik i radost.", - "Humor i smutek v paměti na válku.", - "Motiv otce – silný, trpící, milovaný.", - "Titulní povídka o srnách a poválečném lovu." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ota (vypravěč) – chlapec, pozorovatel.", - "Otec – holič, rybář, sportovec, v táboře.", - "Maminka – drží rodinu.", - "Bratři – Antonín, Jiří.", - "Srnec / zvěř – symbol krásy i ztráty.", - "Místní rybáři a sousedé." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Autobiografismus – Pavel píše z vlastní paměti.", - "Rybaření – metafora trpělivosti a štěstí.", - "Koncentrační tábor otce – stín války.", - "Humor dětství – nevinnost vs. realita.", - "Příroda – les, rybníky, srnci.", - "Titul – smrt krásných tvorů, poválečná doba." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Smrt krásných srnců?", - "options": [ - "Vančura", - "Ota Pavel", - "Hrabal", - "Němcová" - ], - "correct": 1, - "expl": "Ota Pavel, vydání 1971." - }, - { - "prompt": "Jaká forma díla?", - "options": [ - "Jedna novela", - "Soubor autobiografických povídek", - "Drama", - "Básnická skladba" - ], - "correct": 1, - "expl": "Kniha je soubor povídek." - }, - { - "prompt": "Kde dětství probíhá?", - "options": [ - "Praha centrum", - "Příbramsko / okolí", - "Siberie", - "Itálie" - ], - "correct": 1, - "expl": "Pavel vyrůstal v tomto kraji." - }, - { - "prompt": "Čím je otec známý?", - "options": [ - "Učitelem", - "Holičem, rybářem, sportovcem", - "Knězem", - "Politiem" - ], - "correct": 1, - "expl": "Otec je ústřední postava vzpomínek." - }, - { - "prompt": "Co prožívá otec za války?", - "options": [ - "Dovolenou", - "Koncentrační tábor", - "Ministerskou funkci", - "Emigraci" - ], - "correct": 1, - "expl": "Tábor je traumatická linka." - }, - { - "prompt": "Co znamená titulní povídka?", - "options": [ - "Lovecký zážitek po válce – smrt srn", - "Smrt ryb", - "Smrt ve městě", - "Sci-fi" - ], - "correct": 0, - "expl": "Srnci symbolizují krásu zničenou." - }, - { - "prompt": "Jaký tón převažuje?", - "options": [ - "Humor i dojetí", - "Pouze horor", - "Bez emocí", - "Politický manifest" - ], - "correct": 0, - "expl": "Pavel mísí vtip a smutek." - }, - { - "prompt": "Rybaření v knize?", - "options": [ - "Chybí", - "Důležitý motiv radosti a vztahu s otcem", - "Jen sport pro armádu", - "Zakázané" - ], - "correct": 1, - "expl": "Ryby a voda jsou obrazem svobody." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Otec", - "Ota Pavel jako vzpomínající", - "Němec", - "Učitel" - ], - "correct": 1, - "expl": "Autobiografický vypravěč." - }, - { - "prompt": "Proč je dílo v maturitě?", - "options": [ - "Česká próza 20. st., paměť války", - "Bez témat", - "Jen humor bez hloubky", - "Cizí jazyk" - ], - "correct": 0, - "expl": "Spojuje válku, rodinu, přírodu." - }, - { - "prompt": "Jak matka funguje?", - "options": [ - "Bez role", - "Drží rodinu při otci v táboře", - "Je Němka", - "Je lovec" - ], - "correct": 1, - "expl": "Matka je opora domácnosti." - }, - { - "prompt": "Bratři v knize?", - "options": [ - "Neexistují", - "Antonín, Jiří – součást rodiny", - "Jen cizinci", - "Vědci" - ], - "correct": 1, - "expl": "Rodinné vztahy jsou důležité." - }, - { - "prompt": "Příroda je?", - "options": [ - "Nepřítel", - "Útočiště a radost dětství", - "Jen kulisa", - "Město" - ], - "correct": 1, - "expl": "Les a voda kontrastují s válkou." - }, - { - "prompt": "Humor Pavla?", - "options": [ - "Chybí", - "Dětský pohled, groteskní detaily", - "Pouze slovní hříčka", - "Nadávky" - ], - "correct": 1, - "expl": "Humor je laskavý i hořký." - }, - { - "prompt": "Kdy Pavel zemřel?", - "options": [ - "1973", - "1990", - "1950", - "2000" - ], - "correct": 0, - "expl": "Spisovatel zemřel relativně mladý." - }, - { - "prompt": "Co NENÍ téma?", - "options": [ - "Válka a tábor", - "Rodina", - "Rybaření", - "Kosmické kolonie" - ], - "correct": 3, - "expl": "Dílo je zakořeněné v českém venkově." - }, - { - "prompt": "Otec se vrací z tábora?", - "options": [ - "Ano, rodina to prožívá", - "Ne, nikdy", - "Je to fikce bez války", - "Emigruje" - ], - "correct": 0, - "expl": "Návrat otce je silný moment." - }, - { - "prompt": "Jazyk Pavla?", - "options": [ - "Úřednický", - "Hovorový, živý, obrazný", - "Archaičtina", - "Angličtina" - ], - "correct": 1, - "expl": "Pavel píše s nadhledem." - }, - { - "prompt": "Další kniha Pavla?", - "options": [ - "Zlatí úhoři", - "1984", - "Babička", - "Kytice" - ], - "correct": 0, - "expl": "Zlatí úhoři navazují na rybářské motivy." - }, - { - "prompt": "Proč „krásní“ srnci?", - "options": [ - "Oškliví", - "Krása zvěře kontrastuje s její smrtí", - "Ironie bez smyslu", - "Reklama" - ], - "correct": 1, - "expl": "Titul zdůrazňuje ztrátu krásy." - }, - { - "prompt": "Dětský vypravěč?", - "options": [ - "Vidí svět nevině i s bolestí", - "Je dospělý generál", - "Je Němec", - "Nevidí válku" - ], - "correct": 0, - "expl": "Dětská perspektiva je typická." - }, - { - "prompt": "Sport u Pavla?", - "options": [ - "Hokej, fotbal vzpomínky", - "Jen šachy", - "Nic", - "Pouze box" - ], - "correct": 0, - "expl": "Otec sportuje, syn obdivuje." - }, - { - "prompt": "Kniha vyšla za?", - "options": [ - "Normalizace 1971", - "1890", - "2010", - "1940" - ], - "correct": 0, - "expl": "Vydání v 70. letech." - }, - { - "prompt": "Emoce čtenáře?", - "options": [ - "Smích i dojetí", - "Pouze nuda", - "Strach horor", - "Bez reakce" - ], - "correct": 0, - "expl": "Pavel je mistr nálady." - }, - { - "prompt": "Vztah k Hrabalovi?", - "options": [ - "Oba humor + všednost", - "Identičtí", - "Bez paralely", - "Hrabal napsal srnce" - ], - "correct": 0, - "expl": "Generačně blízcí, různý styl." - }, - { - "prompt": "Lovecký motiv?", - "options": [ - "Etika lovu po válce", - "Vesmír", - "Politika strany", - "Škola" - ], - "correct": 0, - "expl": "Titulní povídka reflektuje poválečný lov." - }, - { - "prompt": "Co si pamatovat o otci?", - "options": [ - "Slaboch", - "Silná, tragická, obdivuhodná postava", - "Villain", - "Cizinec" - ], - "correct": 1, - "expl": "Otec je hrdina vzpomínek." - }, - { - "prompt": "Proč autobiografie?", - "options": [ - "Autenticita paměti", - "Fikce bez základu", - "Překlad", - "Sborová poezie" - ], - "correct": 0, - "expl": "Vychází z Pavlova života." - }, - { - "prompt": "Krátce: jádro knihy?", - "options": [ - "Rodina, válka, příroda, humor", - "Detektivka", - "Sci-fi", - "Opera" - ], - "correct": 0, - "expl": "To jsou hlavní osy." - }, - { - "prompt": "Pavel byl také?", - "options": [ - "Fotbalový komentátor / novinář", - "Král", - "Německý spisovatel", - "Malíř" - ], - "correct": 0, - "expl": "Pavel pracoval v médiích." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Dětství Oty a rodina holiče", - "Rybaření, sport, radosti", - "Otec odveden do tábora", - "Matka drží domácnost", - "Otec se vrací, válka končí", - "Titulní lov – smrt krásných srnců" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: dětství → radosti → tábor → doma bez otce → návrat → povídka o srncích." - ] -} diff --git a/data/cetba/sofiina-volba.json b/data/cetba/sofiina-volba.json deleted file mode 100644 index 8c35c73..0000000 --- a/data/cetba/sofiina-volba.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: William Styron (1925–2006)", - "Žánr: psychologický román", - "Poprvé vydáno: 1979", - "Děj: USA po 2. sv. válce, vzpomínky na holocaust", - "Vyprávění: er-forma – Stingo, mladý spisovatel" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Postava Sophie Zawistowska – polská přeživší Auschwitz.", - "Tajemství „Sofiina volba“ – které dítě poslat na smrt.", - "Vztah Sophie a Nathan Landau – vášnivý, destruktivní.", - "Téma viny, traumatu a antisemitismu v Americe.", - "Gradace k odhalení Sophieina rozhodnutí.", - "Silný etický a historický dopad." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Stingo – mladý jižanský spisovatel, vypravěč.", - "Sophie Zawistowska – krásná Polka, traumatizovaná.", - "Nathan Landau – geniální, schizofrenní milenec.", - "Jan a Eva – Sophieina děti v koncentráku.", - "Dr. Blackstock / doktoři – okrajové postavy.", - "Spolubydlící v Brooklynu." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Sofiina volba – morální dilema v Auschwitzi.", - "Trauma – noční můry, alkohol, sebepoškozování.", - "Nathan – láska a smrtelné nebezpečí.", - "Holocaust – flashbacky do Polska.", - "Vina přeživšího – proč právě já?", - "Americký South vs. evropská minulost." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Sofiinu volbu?", - "options": [ - "Hemingway", - "William Styron", - "Styron není – Keyes", - "Kundera" - ], - "correct": 1, - "expl": "Styron, román 1979." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Sophie", - "Stingo – mladý spisovatel", - "Nathan", - "Němec" - ], - "correct": 1, - "expl": "Stingo je svědek příběhu Sophie." - }, - { - "prompt": "Kdo je Sophie?", - "options": [ - "Američanka", - "Polská přeživší holocaustu", - "Německá voják", - "Učitelka" - ], - "correct": 1, - "expl": "Sophie prošla koncentráky." - }, - { - "prompt": "Kdo je Nathan?", - "options": [ - "Sophiein stabilní manžel", - "Vášnivý, psychicky nemocný milenec", - "Stingův otec", - "Rabín" - ], - "correct": 1, - "expl": "Nathan je geniální i nebezpečný." - }, - { - "prompt": "Co znamená „Sofiina volba“?", - "options": [ - "Výběr školy", - "Rozhodnutí, které dítě nechat žít v Auschwitzi", - "Volby prezidenta", - "Výběr jídla" - ], - "correct": 1, - "expl": "Sophie musela zvolit mezi Janem a Evou." - }, - { - "prompt": "Kde žijí v USA?", - "options": [ - "Brooklyn", - "Praha", - "Paříž", - "Siberie" - ], - "correct": 0, - "expl": "Poválečný New York / Brooklyn." - }, - { - "prompt": "Jak končí Sophie?", - "options": [ - "Šťastně", - "S Nathanem sebevraždou", - "Emigrace", - "S Stingem" - ], - "correct": 1, - "expl": "Tragický konec milenců." - }, - { - "prompt": "Proč Sophie trpí?", - "options": [ - "Bez důvodu", - "Vina z holocaustu a volby", - "Jen láska", - "Sport" - ], - "correct": 1, - "expl": "Trauma ji ničí." - }, - { - "prompt": "Co Stingo dělá?", - "options": [ - "Píše, pozoruje pár", - "Vede Auschwitz", - "Je doktor", - "Je dítě" - ], - "correct": 0, - "expl": "Mladý autor hledá materiál i lásku." - }, - { - "prompt": "Jaký žánr?", - "options": [ - "Psychologický román s historickým flashbackem", - "Pohádka", - "Sci-fi", - "Komedie" - ], - "correct": 0, - "expl": "Spojení lásky a holocaustu." - }, - { - "prompt": "Děti Sophie?", - "options": [ - "Jan a Eva", - "Tom a Jerry", - "Nick a Daisy", - "Žádné" - ], - "correct": 0, - "expl": "Obě padly oběti režimu." - }, - { - "prompt": "Nathanova nemoc?", - "options": [ - "Schizofrenie / psychóza", - "Chřipka", - "Slepota", - "Bez nemoci" - ], - "correct": 0, - "expl": "Jeho chování je nepředvídatelné." - }, - { - "prompt": "Proč je dílo kontroverzní?", - "options": [ - "Lehkost", - "Zobrazuje extrémní etické dilema", - "Bez holocaustu", - "Komiks" - ], - "correct": 1, - "expl": "Volba matky je otřesná." - }, - { - "prompt": "Flashbacky kam?", - "options": [ - "Do Polska / Auschwitz", - "Do Marsu", - "Do středověku", - "Nikam" - ], - "correct": 0, - "expl": "Minulost vysvětluje přítomnost." - }, - { - "prompt": "Téma viny?", - "options": [ - "Chybí", - "Přeživší cítí vinu za volby", - "Jen politika", - "Sport" - ], - "correct": 1, - "expl": "Sophie nemůže odpustit sobě." - }, - { - "prompt": "Film?", - "options": [ - "Natáčen s Meryl Streep", - "Neexistuje", - "Cartoon", - "Silent" - ], - "correct": 0, - "expl": "Film 1982, oscarové role." - }, - { - "prompt": "Stingo pochází?", - "options": [ - "Z amerického Jihu", - "Z Čech", - "Z Německa", - "Z Marsu" - ], - "correct": 0, - "expl": "Jižanské kořeny vypravěče." - }, - { - "prompt": "Co NENÍ téma?", - "options": [ - "Holocaust", - "Láska a destrukce", - "Trauma", - "Kosmické války" - ], - "correct": 3, - "expl": "Děj je realistický." - }, - { - "prompt": "Sophie na začátku?", - "options": [ - "Šťastná bez minulosti", - "Krásná, tajemná, traumatizovaná", - "Dítě", - "Generál" - ], - "correct": 1, - "expl": "Stingo je okouzlen." - }, - { - "prompt": "Proč maturita?", - "options": [ - "Etické otázky, historie, postavy", - "Jen milostná novela bez hloubky", - "Bez děje", - "Jen autor" - ], - "correct": 0, - "expl": "Dílo je náročné na rozbor." - }, - { - "prompt": "Jak Styron líčí holocaust?", - "options": [ - "Legračně", - "Přes Sophieiny vzpomínky – osobně", - "Bez detailů", - "Jen statistika" - ], - "correct": 1, - "expl": "Individuální osud." - }, - { - "prompt": "Co následuje po odhalení volby?", - "options": [ - "Nic", - "Hlubší pochopení Sophieina pádu", - "Svatba", - "Válka" - ], - "correct": 1, - "expl": "Climax vysvětluje psychiku." - }, - { - "prompt": "Nathan Sophie?", - "options": [ - "Nenávidí", - "Miluje vášnivě i tyransky", - "Nezná", - "Je bratr" - ], - "correct": 1, - "expl": "Vztah je toxický." - }, - { - "prompt": "Alkohol u Sophie?", - "options": [ - "Nepije", - "Utišuje trauma", - "Jen voda", - "Povinnost" - ], - "correct": 1, - "expl": "Sebedestrukce." - }, - { - "prompt": "Poselství?", - "options": [ - "Etické limity nelze zjednodušit", - "Holocaust nebyl", - "Láska vše vyřeší", - "Volba neexistuje" - ], - "correct": 0, - "expl": "Román ukazuje nemožná rozhodnutí." - }, - { - "prompt": "Kdy vyšlo?", - "options": [ - "1979", - "1942", - "2000", - "1890" - ], - "correct": 0, - "expl": "Konec 70. let." - }, - { - "prompt": "Překlad v ČR?", - "options": [ - "Nenadál aj.", - "Bez překladu", - "Shakespeare", - "Hašek" - ], - "correct": 0, - "expl": "České vydání známé." - }, - { - "prompt": "Stingo a Sophie?", - "options": [ - "Stingo ji miluje, ona volí Nathana", - "Sňatek", - "Sourozenci", - "Nic" - ], - "correct": 0, - "expl": "Neukojená láska vypravěče." - }, - { - "prompt": "Struktura?", - "options": [ - "Současnost + retrospektivy", - "Jen básně", - "Drama jedné scény", - "Epos" - ], - "correct": 0, - "expl": "Střídání časů." - }, - { - "prompt": "Proč „volba“ otřásá?", - "options": [ - "Malicherná", - "Matka rozhoduje o životě dítěte", - "Vtip", - "Sport" - ], - "correct": 1, - "expl": "Nejtěžší morální situace." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Stingo pozná Sophie a Nathana", - "Vztah páru je vášnivý a nebezpečný", - "Sophie vypráví o válce a Auschwitzi", - "Odhalí se Sofiina volba mezi dětmi", - "Trauma a Nathanova nemoc eskalují", - "Sophie a Nathan spáchají sebevraždu" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: seznámení → milostný trojúhelník → flashbacky → volba → eskalace → sebevražda." - ] -} diff --git a/data/cetba/stanice-zoo.json b/data/cetba/stanice-zoo.json deleted file mode 100644 index 185b6b6..0000000 --- a/data/cetba/stanice-zoo.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Christiane F. (Christiane Felscherinow; zaznamenali Kai Hermann a Horst Rieck)", - "Žánr: dokumentární próza / autentická zpověď", - "Poprvé vydáno: 1978 (Wir Kinder vom Bahnhof Zoo); česky My děti ze stanice ZOO", - "Děj / prostředí: Západní Berlín 70. let – stanice Zoo, drogová scéna", - "Vyprávění / forma: ich-forma Christiane, reportážní styl založený na rozhovorech" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Západní Berlín 70. let: subkultura, heroin, prostitutce mladistvých.", - "Kniha vznikla z novinářských rozhovorů s Christiane Felscherinow.", - "Ukazuje propad od dětství a večírků k závislosti.", - "Stanice Zoo je centrem drogové scény a obchodu s tělem.", - "Text varuje před drogami skrze svědectví, bez pohádkového moralizování.", - "Patří k nejznámějším dokumentárním příběhům o závislosti dospívajících." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Christiane F. – vypravěčka, dospívající dívka závislá na heroinu.", - "Detlef – Christianin přítel, také závislý.", - "Matka Christiane – snaží se dceru zachránit, často bezmocně.", - "Kamarádi z party scény – vstupní brána k drogám.", - "Dealeři a klienti – součást ekonomie stanice Zoo.", - "Sociální pracovníci / policie – instituce na okraji příběhu." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Závislost – fyzické i sociální otroctví heroinu.", - "Stanice Zoo – symbol úpadku a trhu s drogami.", - "Prostituce – prostředek získání peněz na dávku.", - "Dokumentárnost – autentické svědectví, ne fikční „hrdinství“.", - "Dospívání – ztráta dětství v subkultuře.", - "Bezmoc okolí – rodina a instituce nestíhají pomáhat." - ] - } - ], - "quiz": [ - { - "prompt": "O čem kniha My děti ze stanice ZOO především vypovídá?", - "options": [ - "O válečném hrdinství", - "O drogové závislosti dospívajících v Berlíně", - "O středověké legendě", - "O venkovské idyle" - ], - "correct": 1, - "expl": "Jde o svědectví o heroinové scéně Západního Berlína 70. let." - }, - { - "prompt": "Kdo je Christiane F.?", - "options": [ - "Fiktivní detektivka", - "Skutečná dívka, jejíž zpověď kniha zaznamenává", - "Policistka na stanici Zoo", - "Autorka sci-fi románů" - ], - "correct": 1, - "expl": "Christiane Felscherinow vypráví vlastní zkušenost; text vznikl z rozhovorů." - }, - { - "prompt": "Kde se děj především odehrává?", - "options": [ - "V Praze 90. let", - "V Západním Berlíně 70. let kolem stanice Zoo", - "V New Yorku za prohibice", - "V Paříži za komuny" - ], - "correct": 1, - "expl": "Centrem je drogová scéna kolem berlínského Bahnhof Zoo." - }, - { - "prompt": "Jak kniha vznikla?", - "options": [ - "Jako čistá fikce bez předlohy", - "Z novinářských rozhovorů s Christiane", - "Jako deník napsaný ve vězení", - "Jako básnická sbírka" - ], - "correct": 1, - "expl": "Kai Hermann a Horst Rieck zaznamenali její výpověď reportážním stylem." - }, - { - "prompt": "Kdo je Detlef?", - "options": [ - "Christianeina matka", - "Její přítel, také závislý", - "Dealer s heroinem", - "Sociální pracovník" - ], - "correct": 1, - "expl": "Detlef patří k nejbližším osobám v příběhu závislosti." - }, - { - "prompt": "Čím se Christiane často živí, aby měla na dávku?", - "options": [ - "Prací v knihovně", - "Prostitucí", - "Studiem medicíny", - "Prodejem obrazů" - ], - "correct": 1, - "expl": "Text ukazuje, jak závislost vede k prostituci mladistvých." - }, - { - "prompt": "Jaká droga je v knize ústřední?", - "options": [ - "Alkohol", - "Heroin", - "Nikotin", - "Kofein" - ], - "correct": 1, - "expl": "Příběh sleduje propad do heroinové závislosti." - }, - { - "prompt": "Jaký je žánr knihy?", - "options": [ - "Rytířský román", - "Dokumentární próza / autentická zpověď", - "Antická tragédie", - "Science fiction" - ], - "correct": 1, - "expl": "Nejde o klasickou fikci, ale o svědectví založené na rozhovorech." - }, - { - "prompt": "Co symbolizuje stanice Zoo?", - "options": [ - "Školní úspěch", - "Centrum drogové scény a úpadku", - "Turistickou atrakci bez stinné stránky", - "Sídlo vlády" - ], - "correct": 1, - "expl": "Bahnhof Zoo je místem obchodu s drogami i tělem." - }, - { - "prompt": "Jak kniha působí na čtenáře především?", - "options": [ - "Jako návod k užívání drog", - "Jako varovné svědectví o závislosti", - "Jako komedie o dospívání", - "Jako detektivka s happy endem" - ], - "correct": 1, - "expl": "Síla textu je v autenticitě a v zobrazení propadu bez zkrášlení." - }, - { - "prompt": "Jaká je role matky v příběhu?", - "options": [ - "Je hlavní dealerkou", - "Snaží se dceru zachránit, ale často je bezmocná", - "O dceru nestojí", - "Vede drogový gang" - ], - "correct": 1, - "expl": "Rodina vidí problém, ale systém i závislost ji přerůstají." - }, - { - "prompt": "Proč text není „hrdinský“ příběh o překonání?", - "options": [ - "Protože Christiane vyhrává olympiádu", - "Protože ukazuje realitu závislosti bez romantizace", - "Protože chybí postavy", - "Protože je to jen seznam vtipů" - ], - "correct": 1, - "expl": "Dokumentárnost odmítá falešné happy endy a heroizaci." - }, - { - "prompt": "Která formulace nejlépe vystihuje vyprávění?", - "options": [ - "Er-forma vševědoucího historika", - "Ich-forma Christiane v reportážním stylu", - "Veršovaná epopej", - "Soubor sonetů" - ], - "correct": 1, - "expl": "Čtenář slyší její hlas; novináři text sestavili z rozhovorů." - }, - { - "prompt": "Co kniha ukazuje o institucích (škola, policie, sociální péče)?", - "options": [ - "Všechny problémy okamžitě vyřeší", - "Často nestíhají nebo zasahují pozdě", - "Neexistují", - "Jsou hlavními dealery" - ], - "correct": 1, - "expl": "Instituce jsou přítomné, ale závislost a scéna je přerůstají." - }, - { - "prompt": "Jak začíná Christianina cesta k drogám typicky v knize?", - "options": [ - "Povinnou školní praxí v nemocnici", - "Přes party scénu, kamarády a experimentování", - "Studiem teologie", - "Prací v bance" - ], - "correct": 1, - "expl": "Propad jde od subkultury a experimentů k heroinu." - }, - { - "prompt": "Proč je kniha stále čtená ve škole / k maturitě?", - "options": [ - "Protože je krátká pohádka", - "Protože otevírá témata závislosti, dospívání a společnosti", - "Protože nemá žádný obsah", - "Protože je to jen cestopis" - ], - "correct": 1, - "expl": "Nabízí silné společenské svědectví a látku k diskusi." - }, - { - "prompt": "Co znamená „dokumentárnost“ u této knihy?", - "options": [ - "Že jde o soudní spis bez příběhu", - "Že staví na autentické výpovědi a faktech ze života", - "Že nemá žádné postavy", - "Že je to výhradně fikční fantasy" - ], - "correct": 1, - "expl": "Autenticita je základní rys žánru i účinku textu." - }, - { - "prompt": "Jak text zachází s moralizováním?", - "options": [ - "Káže dlouhé kázání bez příběhu", - "Varuje především skrze konkrétní svědectví, ne skrze pohádku", - "Vyzdvihuje drogy jako řešení", - "Ignoruje důsledky" - ], - "correct": 1, - "expl": "Síla je v ukázání důsledků, ne v abstraktním kázání." - }, - { - "prompt": "Kdo knihu „napsal“ ve smyslu literární podoby?", - "options": [ - "Jen anonymní dav", - "Christiane vypráví; Hermann a Rieck text zaznamenali a sestavili", - "Jen Tennessee Williams", - "Jen Karel Čapek" - ], - "correct": 1, - "expl": "Jde o spolupráci svědkyně a novinářů." - }, - { - "prompt": "Co je typickým důsledkem závislosti v knize?", - "options": [ - "Okamžité zbohatnutí bez rizika", - "Ztráta zdraví, vztahů a bezpečného dětství", - "Zisk Nobelovy ceny", - "Přestěhování na farmu bez problémů" - ], - "correct": 1, - "expl": "Text ukazuje totální rozklad běžného života." - }, - { - "prompt": "Proč název odkazuje na stanici ZOO?", - "options": [ - "Protože kniha je o zvířatech v kleci doslova", - "Protože Bahnhof Zoo je klíčové místo scény, o níž Christiane mluví", - "Protože jde o průvodce zoo", - "Protože se odehrává jen v Praze" - ], - "correct": 1, - "expl": "Stanice je reálným i symbolickým centrem příběhu." - }, - { - "prompt": "Jaká je perspektiva vyprávění vůči drogové scéně?", - "options": [ - "Zvenčí jako suchá statistika bez lidí", - "Zevnitř – očima dospívající závislé", - "Jen z pohledu policie", - "Jen z pohledu dealerů jako hrdinů" - ], - "correct": 1, - "expl": "Ich-forma dává intimní a šokující pohled zevnitř." - }, - { - "prompt": "Která teze je s knihou v souladu?", - "options": [ - "Závislost je jen „špatná nálada“", - "Závislost ničí tělo, vztahy i budoucnost", - "Drogová scéna je bezpečná zábava", - "Prostituce s drogami nesouvisí" - ], - "correct": 1, - "expl": "Celý text je litanií důsledků závislosti." - }, - { - "prompt": "Jak kniha pracuje s časem dospívání?", - "options": [ - "Ukazuje spokojené stáří důchodců", - "Ukazuje zkrácené / ztracené dětství a dospívání", - "Ignoruje věk postav", - "Odehrává se jen ve školní lavici bez konfliktů" - ], - "correct": 1, - "expl": "Christiane a její okolí přicházejí o běžné dospívání." - }, - { - "prompt": "Co je „scéna“ v kontextu knihy?", - "options": [ - "Divadelní představení ve Národním", - "Sociální prostředí party, drog a stanice Zoo", - "Sportovní turnaj", - "Školní sbor" - ], - "correct": 1, - "expl": "Scéna označuje subkulturu, v níž se Christiane pohybuje." - }, - { - "prompt": "Proč je Detlef důležitý pro motivaci děje?", - "options": [ - "Je učitelem matematiky", - "Vztah s ním je součástí společného propadu do závislosti", - "Je prezidentem", - "V knize se nevyskytuje" - ], - "correct": 1, - "expl": "Partnerský vztah je svázán se společným užíváním a přežitím." - }, - { - "prompt": "Která formulace nejlépe vystihuje společenský rozměr knihy?", - "options": [ - "Jde jen o soukromý deníček bez kontextu", - "Osobní zpověď odhaluje širší problém města a doby", - "Jde o receptář kuchyně", - "Jde o portréty panovníků" - ], - "correct": 1, - "expl": "Individuální osud ukazují jako symptom společenské krize." - }, - { - "prompt": "Jaký je typický vztah Christiane k „normálnímu“ světu (škola, domov)?", - "options": [ - "Bezproblémové začlenění", - "Narůstající odcizení a konflikty", - "Vede školu jako ředitelka", - "Nezná domov ani školu" - ], - "correct": 1, - "expl": "Závislost ji odděluje od běžných jistot dospívání." - }, - { - "prompt": "Proč text není fantasy ani alegorie o zvířatech?", - "options": [ - "Protože Zoo je jen metafora bez reality", - "Protože jde o reálné svědectví z berlínské drogové scény", - "Protože autor neexistuje", - "Protože kniha nemá děj" - ], - "correct": 1, - "expl": "Nepleťte si ji se Skleněnou zoologickou zahradou T. Williamse ani s bajkou." - }, - { - "prompt": "Co by měl čtenář pochopit jako hlavní varování?", - "options": [ - "Že drogy jsou vždy neškodná zábava", - "Že závislost rychle ovládne život a okolí často nestíhá pomoci", - "Že stačí jedna party bez následků", - "Že instituce vždy zachrání každého včas" - ], - "correct": 1, - "expl": "Kniha ukazuje, jak rychle a totálně závislost přeroste člověka i pomoc okolí." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Christiane vyrůstá a vstupuje do berlínské party scény", - "Začne experimentovat s drogami a propadá heroinu", - "S Detlefem sdílí závislost a život kolem stanice Zoo", - "Prostitucí a krádežemi shání peníze na dávky", - "Rodina a instituce se snaží zasáhnout, často bezmocně", - "Svědectví ukazuje následky závislosti bez zkrášlení" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: vstup do scény → heroin → vztah a Zoo → shánění dávek → zásahy okolí → svědectví o důsledcích." - ] -} diff --git a/data/cetba/stare-recke-baje.json b/data/cetba/stare-recke-baje.json deleted file mode 100644 index a945a9d..0000000 --- a/data/cetba/stare-recke-baje.json +++ /dev/null @@ -1,399 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Eduard Petiška (1924–1987)", - "Žánr: moderní zpracování mýtů", - "Poprvé vydáno: 1959 (sbírka)", - "Děj: antické řecké mýty a pověsti", - "Forma: prózaické převyprávění pro mládež" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Od stvoření světa po hrdinské mýty.", - "Olympští bohové – Zeus, Héra, Poseidon…", - "Hrdinové – Herakles, Odysseus, Perseus.", - "Vysvětlení přírodních jevů a morálních lekcí.", - "Petiška modernizuje jazyk, zachovává jádro.", - "Základ antické kultury pro maturitu." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Zeus – vládce bohů.", - "Héra – manželka, žárlivost.", - "Prométheus – oheň pro lidi, trest.", - "Herakles – dvanáct úkolů.", - "Odysseus – cesta domů z Troje.", - "Perseus, Theseus, Orfeus aj." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Mýtus – posvátný příběh vysvětlující svět.", - "Hubris – pýcha trestaná bohy.", - "Moira – osud.", - "Hrdinské cesty – zkoušky charakteru.", - "Bohové antropomorfní – lidské vášně.", - "Petiška – srozumitelné vyprávění." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo sestavil Staré řecké báje (české vydání)?", - "options": [ - "Homér", - "Eduard Petiška", - "Neruda", - "Čapek" - ], - "correct": 1, - "expl": "Petiška moderně převyprávěl mýty." - }, - { - "prompt": "Jaká forma?", - "options": [ - "Původní řecká tragédie", - "Prozaické převyprávění mýtů", - "Sci-fi", - "Opera" - ], - "correct": 1, - "expl": "Pro mládež a školy." - }, - { - "prompt": "Kdo vládne bohům?", - "options": [ - "Poseidon", - "Zeus", - "Hádés", - "Apollo" - ], - "correct": 1, - "expl": "Zeus je nejvyšší." - }, - { - "prompt": "Co udělal Prométheus?", - "options": [ - "Zničil svět", - "Daroval lidem oheň", - "Vybudoval Prahu", - "Napsal Bibli" - ], - "correct": 1, - "expl": "Za to byl potrestán." - }, - { - "prompt": "Herakles je známý?", - "options": [ - "Dvanácti úkoly", - "Jedinou písničkou", - "Bez činů", - "Jako král Čech" - ], - "correct": 0, - "expl": "Labours of Heracles." - }, - { - "prompt": "Odysseus?", - "options": [ - "Cesta z Troje domů na Ithaku", - "Byl v Praze", - "Nemý", - "Bůh" - ], - "correct": 0, - "expl": "Odysseia motiv." - }, - { - "prompt": "Perseus?", - "options": [ - "Zabil Medúzu", - "Vynalezl kolo", - "Byl sluha", - "Němec" - ], - "correct": 0, - "expl": "Hrdina s hlavou Medúzy." - }, - { - "prompt": "Theseus?", - "options": [ - "Minotaur v labyrintu", - "Americký sen", - "Box", - "Kněz" - ], - "correct": 0, - "expl": "Krétský mýtus." - }, - { - "prompt": "Orfeus?", - "options": [ - "Sestoupil do podsvětí za Eurydikou", - "Válka", - "Fotbal", - "Bez hudby" - ], - "correct": 0, - "expl": "Mýtus o lásce a hudbě." - }, - { - "prompt": "Hádés?", - "options": [ - "Podsvětí", - "Moře", - "Nebe", - "Škola" - ], - "correct": 0, - "expl": "Realm of dead." - }, - { - "prompt": "Poseidon?", - "options": [ - "Moře a zemětřesení", - "Oheň", - "Válka", - "Láska" - ], - "correct": 0, - "expl": "Bůh moře." - }, - { - "prompt": "Hubris znamená?", - "options": [ - "Pokoru", - "Pýchu trestanou bohy", - "Lásku", - "Mír" - ], - "correct": 1, - "expl": "Časté téma mýtů." - }, - { - "prompt": "Proč mýty vznikaly?", - "options": [ - "Vysvětlení světa a morálky", - "Reklama", - "Sport", - "Bez důvodu" - ], - "correct": 0, - "expl": "Funkce mýtu." - }, - { - "prompt": "Petiška styl?", - "options": [ - "Srozumitelný moderní jazyk", - "Archaičtina bez smyslu", - "Angličtina", - "Šifra" - ], - "correct": 0, - "expl": "Přístupné mládeži." - }, - { - "prompt": "Troja v mýtech?", - "options": [ - "Válka o Helenu", - "Česká vesnice", - "Sci-fi", - "Neexistuje" - ], - "correct": 0, - "expl": "Ilias souvislost." - }, - { - "prompt": "Pandora?", - "options": [ - "Otevřela skříňku zla", - "Královna Prahy", - "Sluha", - "Němka" - ], - "correct": 0, - "expl": "Mýtus o zlu ve světě." - }, - { - "prompt": "Narcis?", - "options": [ - "Zamilovaný do vlastního odrazu", - "Generál", - "Rybář", - "Učitel" - ], - "correct": 0, - "expl": "Slovo narcismus." - }, - { - "prompt": "Sisyfos?", - "options": [ - "Trest – valit kámen", - "Král štěstí", - "Bůh", - "Dítě" - ], - "correct": 0, - "expl": "Absurdní trest." - }, - { - "prompt": "Antické bohyně?", - "options": [ - "Athéna – moudrost", - "Jen muži", - "Bez jmen", - "Pouze Héra" - ], - "correct": 0, - "expl": "Bohové i bohyně." - }, - { - "prompt": "Co NENÍ v sbírce?", - "options": [ - "Řecké mýty", - "Antická hrdinství", - "České pohádky Boženy Němcové jako jádro", - "Bohové" - ], - "correct": 2, - "expl": "Jde o řeckou mytologii." - }, - { - "prompt": "Eurynomé / stvoření?", - "options": [ - "Kosmogonické mýty na začátku", - "Chybí", - "Jen válka", - "Jen comedy" - ], - "correct": 0, - "expl": "Od chaosu k bohům." - }, - { - "prompt": "Maturita – proč?", - "options": [ - "Základ evropské kultury", - "Bez významu", - "Jen jména", - "Jen mapa" - ], - "correct": 0, - "expl": "Odkaz na antiku." - }, - { - "prompt": "Ikaros?", - "options": [ - "Let voskových křídel – pád", - "Vítězství", - "Mořeplavec bez pádu", - "Kněz" - ], - "correct": 0, - "expl": "Varování před pýchou." - }, - { - "prompt": "Afrodita?", - "options": [ - "Láska a krása", - "Válka", - "Moudrost", - "Lovec" - ], - "correct": 0, - "expl": "Bohyně." - }, - { - "prompt": "Dionýsos?", - "options": [ - "Víno, extáze", - "Moře", - "Podsvětí", - "Kování" - ], - "correct": 0, - "expl": "Bůh." - }, - { - "prompt": "Téma osudu?", - "options": [ - "Moira – nevyhnutelné", - "Neexistuje", - "Jen sci-fi", - "Jen humor" - ], - "correct": 0, - "expl": "Řekové věřili v osud." - }, - { - "prompt": "Petiška profese?", - "options": [ - "Spisovatel, dramatik", - "Německý voják", - "Sportovec", - "Malíř" - ], - "correct": 0, - "expl": "Český autor." - }, - { - "prompt": "Medúza?", - "options": [ - "Z oka petrifikace", - "Anděl", - "Učitelka", - "Rybářka" - ], - "correct": 0, - "expl": "Perseus ji porazil." - }, - { - "prompt": "Pro mládež?", - "options": [ - "Ano, čtivé převyprávění", - "Ne, jen pro vědce", - "Bez textu", - "Jen obrazky" - ], - "correct": 0, - "expl": "Školní klasika." - }, - { - "prompt": "Hlavní hodnota?", - "options": [ - "Poznání antické mytologie", - "Návod na vaření", - "Geografie USA", - "Programování" - ], - "correct": 0, - "expl": "Kulturní přehled." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Mýty o vzniku světa a bohů", - "Příběhy Prométhea a pokušení lidí", - "Hrdinské úkoly (Herakles, Perseus)", - "Odysseova cesta a válka u Troje", - "Láska, hubris a tresty bohů", - "Soubor mýtů jako obraz řecké mysli" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: kosmogonie → bohové → hrdinské mýty → Odysseus/Troja → morální lekce → kulturní celek." - ] -} diff --git a/data/cetba/starec-a-more.json b/data/cetba/starec-a-more.json deleted file mode 100644 index 078371a..0000000 --- a/data/cetba/starec-a-more.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Ernest Hemingway (1899–1961)", - "Žánr: novela", - "Poprvé vydáno: 1952", - "Děj: kubánský rybář Santiago a moře", - "Vyprávění: er-forma, středně objektivní styl" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Santiago – starý rybář v smůle.", - "Souboj s obří marlinou na otevřeném moři.", - "Téma houževnatosti, důstojnosti, osamění.", - "Hemingwayův „kód hrdiny“ – čest i v porážce.", - "Shoři – chlapec, který rybáře miluje.", - "Symbolika moře, lva ze snů." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Santiago – stařec, rybář.", - "Manolin (Shoři) – mladý pomocník.", - "Marlin – obří ryba, soupeř.", - "Žraloci – ničí úlovek.", - "Rybáři v přístavu – komunita.", - "Moře – pole i protivník." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Kód hrdiny – statečnost tváří v tvář porážce.", - "Marlin – krása, síla, respekt.", - "Žraloci – nevyhnutelná ztráta.", - "Lvi ve snu – mládí a síla.", - "Osamění – starý muž na moři.", - "„Člověk není stvořen pro porážku“." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Stařce a moře?", - "options": [ - "Fitzgerald", - "Ernest Hemingway", - "Melville", - "Styron" - ], - "correct": 1, - "expl": "Hemingway, 1952." - }, - { - "prompt": "Kdo je Santiago?", - "options": [ - "Mladý pirát", - "Starý kubánský rybář", - "Učitel", - "Němec" - ], - "correct": 1, - "expl": "Hlavní hrdina." - }, - { - "prompt": "Kolik dní bez úlovku?", - "options": [ - "84 dní smůly", - "1 den", - "1000", - "0" - ], - "correct": 0, - "expl": "Dlouhá série neúspěchu." - }, - { - "prompt": "Kdo je Manolin?", - "options": [ - "Chlapec, který se stará o Santiaga", - "Žralok", - "Marlin", - "Král" - ], - "correct": 0, - "expl": "Shoři / Manolin." - }, - { - "prompt": "Co Santiago chytí?", - "options": [ - "Sardinky", - "Obří marlina", - "Krab", - "Nic" - ], - "correct": 1, - "expl": "Souboj trvá dny." - }, - { - "prompt": "Kde probíhá souboj?", - "options": [ - "Na moři daleko od břehu", - "V lese", - "V Praze", - "Na souši" - ], - "correct": 0, - "expl": "Otevřené moře." - }, - { - "prompt": "Co marlin symbolizuje?", - "options": [ - "Pouze jídlo", - "Krásu, sílu, respekt hrdiny", - "Zlo", - "Boha" - ], - "correct": 1, - "expl": "Santiago marlina obdivuje." - }, - { - "prompt": "Co zničí úlovek?", - "options": [ - "Bouře", - "Žraloci", - "Policie", - "Manolin" - ], - "correct": 1, - "expl": "Cestou zpět žraloci." - }, - { - "prompt": "Jak Santiago končí?", - "options": [ - "Vítězí bohatý", - "Přiveze jen kostru – morální vítězství", - "Umírá moře", - "Emigruje" - ], - "correct": 1, - "expl": "Fyzická porážka, duch statečný." - }, - { - "prompt": "Nobelova cena?", - "options": [ - "Hemingway ji dostal mj. za toto dílo", - "Nikdy", - "Melville", - "Keyes" - ], - "correct": 0, - "expl": "1954 Nobel." - }, - { - "prompt": "Fráze o porážce?", - "options": [ - "Člověk může být zničen, ale ne poražen", - "Válka je mír", - "Bůh mrtvý", - "Bez fráze" - ], - "correct": 0, - "expl": "Klíčové poselství." - }, - { - "prompt": "Lvi ve snu?", - "options": [ - "Symbol mládí Afriky / síly", - "Realita", - "Nepřítel", - "Žraloci" - ], - "correct": 0, - "expl": "Santiago o nich sní." - }, - { - "prompt": "Styl Hemingwaye?", - "options": [ - "Krátké věty, málo adjektiv", - "Dlouhé periodické věty", - "Verš", - "Drama" - ], - "correct": 0, - "expl": "Iceberg theory." - }, - { - "prompt": "Délka?", - "options": [ - "Novela – kratší než román", - "Epos", - "Báseň", - "Trilogie" - ], - "correct": 0, - "expl": "Kompaktní dílo." - }, - { - "prompt": "Kubánské prostředí?", - "options": [ - "Havana, rybářská vesnice", - "New York", - "Paříž", - "Siberie" - ], - "correct": 0, - "expl": "Karibik." - }, - { - "prompt": "Manolin na konci?", - "options": [ - "Plánuje znovu rybařit se Santiagem", - "Zapomene", - "Umírá", - "Odchází" - ], - "correct": 0, - "expl": "Naděje v generaci." - }, - { - "prompt": "Téma osamění?", - "options": [ - "Ano, stařec sám na moři", - "Ne", - "Jen komedie", - "Jen politika" - ], - "correct": 0, - "expl": "Existenciální osamění." - }, - { - "prompt": "Co NENÍ téma?", - "options": [ - "Houževnatost", - "Důstojnost", - "Kosmické války", - "Respekt k přírodě" - ], - "correct": 2, - "expl": "Realistická novela." - }, - { - "prompt": "Marlin vs Santiago?", - "options": [ - "Respekt soupeřů", - "Nenávist", - "Bez boje", - "Marlin vyhrává bohatství" - ], - "correct": 0, - "expl": "Rytířský souboj." - }, - { - "prompt": "Kostra ryby?", - "options": [ - "Ukazuje v přístavu – směs obdivu a smutku", - "Spálí se", - "Neexistuje", - "Jí se celá" - ], - "correct": 0, - "expl": "Symbol vítězství i ztráty." - }, - { - "prompt": "Hemingway život?", - "options": [ - "1899–1961, dobrodruh", - "2000", - "1700", - "Čech" - ], - "correct": 0, - "expl": "Americký autor." - }, - { - "prompt": "Překlad Vrba?", - "options": [ - "Český překlad známý", - "Neexistuje", - "Anglicky jen", - "Německy" - ], - "correct": 0, - "expl": "Maturitní seznam." - }, - { - "prompt": "Věk Santiaga?", - "options": [ - "Stařec – osmdesátky", - "Dítě", - "Dvacet", - "Sto padesát" - ], - "correct": 0, - "expl": "Titul." - }, - { - "prompt": "Návnada?", - "options": [ - "Sardinky, chytrost", - "Pouze síla", - "Magie", - "Nic" - ], - "correct": 0, - "expl": "Rybařské detaily." - }, - { - "prompt": "Bolest?", - "options": [ - "Santiago trpí, ale pokračuje", - "Bez bolesti", - "Komediální", - "Bez děje" - ], - "correct": 0, - "expl": "Fyzické vypětí." - }, - { - "prompt": "Náboženské prvky?", - "options": [ - "Kříž, bolest – možná paralely", - "Kázání", - "Bez ničeho", - "Opera" - ], - "correct": 0, - "expl": "Interpretace křesťanská." - }, - { - "prompt": "Pro maturitu?", - "options": [ - "Symbolika, styl, témata", - "Jen mapa", - "Jen autor rok", - "Nic" - ], - "correct": 0, - "expl": "Klasická maturitní četba." - }, - { - "prompt": "Hemingway válka?", - "options": [ - "1. sv. válka, novinář", - "Nebyl", - "Jen učitel", - "Král" - ], - "correct": 0, - "expl": "Zkušenost ovlivnila psaní." - }, - { - "prompt": "Tón závěru?", - "options": [ - "Hořkosladký – porážka i důstojnost", - "Čistá radost", - "Horor", - "Satira" - ], - "correct": 0, - "expl": "Tragédie i vítězství ducha." - }, - { - "prompt": "Co si Santiago říká?", - "options": [ - "Motivuje se sám – dialog", - "Mlčí vždy", - "Zpívá operu", - "Modlí se jen" - ], - "correct": 0, - "expl": "Vnitřní monolog." - }, - { - "prompt": "Proč Manolin nemůže chodit s Santiagem rybařit?", - "options": [ - "Rodiče ho přesvědčili, že Santiago je smolař", - "Santiago ho zakázal", - "Manolin je nemocný", - "Zákaz státu" - ], - "correct": 0, - "expl": "Chlapec by chtěl, ale rodina preferuje úspěšnější rybáře po sérii neúspěchů." - }, - { - "prompt": "Jak rybáři reagují na kostru marlina?", - "options": [ - "S úctou k Santiagově výkonu, i když z masa nic nezbylo", - "S opovržením bez výjimky", - "Vůbec ji nevidí", - "Spálí ji hned" - ], - "correct": 0, - "expl": "Kostra dokazuje, že marlina skutečně chytil – směs obdivu a soucitu." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Santiago má dlouhou smůlu", - "Vyplouvá daleko na moře", - "Chytí obřího marlina", - "Třídenní souboj a vítězství", - "Žraloci sežerou maso cestou", - "Vrátí se s kostrou – Manolin u něj zůstane" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: smůla → vyplutí → marlin → souboj → žraloci → návrat a kostra." - ] -} diff --git a/data/cetba/svaty-xaverius.json b/data/cetba/svaty-xaverius.json deleted file mode 100644 index 450bdeb..0000000 --- a/data/cetba/svaty-xaverius.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Jakub Arbes (1840–1914)", - "Žánr: historicko-romantický román", - "Poprvé vydáno: 1869 (román)", - "Děj: 16.–17. st., cesty sv. Františka Xaverského", - "Forma: epická próza s romantickými prvky" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "František Xaverský – jezuitský misionář v Asii.", - "Arbes kombinuje historii, dobrodružství a idealismus.", - "Romantický hrdina šíří křesťanství.", - "Exotické prostředí – Indie, Japonsko, Maluku.", - "Vzory českého romantismu a pokrokové myšlenky.", - "Dílo je méně čtené, ale maturitní klasika." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "František Xaverský – hlavní hrdina, světec.", - "Ignác z Loyoly – zakladatel jezuitů.", - "Místní vládci a obyvatelé Asie.", - "Arbesův vypravěčský styl – barvitý.", - "Nepřátelé víry – pronásledování.", - "Společníci misie." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Misionářství – šíření víry v exotickém světě.", - "Romantismus – idealizace, dobrodružství.", - "Historická postava – reálný Xaverský (1506–1552).", - "Kulturní střet Evropy a Asie.", - "Oběť a oddanost – světectví.", - "Arbes – pokrokový publicista." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Svatého Xaveria?", - "options": [ - "Jirásek", - "Jakub Arbes", - "Neruda", - "Čapek" - ], - "correct": 1, - "expl": "Arbes, romantický autor." - }, - { - "prompt": "O kom román je?", - "options": [ - "O Napoleonovi", - "O sv. Františku Xaverském", - "O Svejkovi", - "O Gatsby" - ], - "correct": 1, - "expl": "Jezuitský misionář." - }, - { - "prompt": "Kdy Xaverský žil?", - "options": [ - "16. století (1506–1552)", - "20. st.", - "Antika", - "1990" - ], - "correct": 0, - "expl": "Historická postava." - }, - { - "prompt": "Kde působil?", - "options": [ - "Asie – Indie, Japonsko, Moluky", - "Pouze Praha", - "USA", - "Antarktida" - ], - "correct": 0, - "expl": "Misijní cesty." - }, - { - "prompt": "Žánr?", - "options": [ - "Historicko-romantický román", - "Sci-fi", - "Detektivka", - "Báseň" - ], - "correct": 0, - "expl": "Romantická epika." - }, - { - "prompt": "Arbes patří kam?", - "options": [ - "Český romantismus / realizmus přechod", - "Devětsil", - "Baroko", - "Postmoderna" - ], - "correct": 0, - "expl": "19. století." - }, - { - "prompt": "Ignác z Loyoly?", - "options": [ - "Zakladatel jezuitů, Xaveriův druh", - "Král", - "Němec", - "Rybář" - ], - "correct": 0, - "expl": "Spoluzakladatel řádu." - }, - { - "prompt": "Hlavní motiv?", - "options": [ - "Misionářská oddanost a dobrodružství", - "Lov srn", - "Detektivka", - "Komunismus" - ], - "correct": 0, - "expl": "Víra a cesty." - }, - { - "prompt": "Styl Arbesa?", - "options": [ - "Barvitý, romantický", - "Suchý úřednický", - "Bez obrazů", - "Pouze dialog" - ], - "correct": 0, - "expl": "Typický romantismus." - }, - { - "prompt": "Proč „svatý“?", - "options": [ - "Xaverský byl kanonizován", - "Fikce", - "Ironie", - "Bez důvodu" - ], - "correct": 0, - "expl": "Církevní světec." - }, - { - "prompt": "Kulturní střet?", - "options": [ - "Evropa vs. asijské kultury", - "Ne", - "Jen Praha", - "Jen sport" - ], - "correct": 0, - "expl": "Misie naráží na zvyky." - }, - { - "prompt": "Arbes jinak?", - "options": [ - "Publicista, pokrokové názory", - "Němec", - "Bez tvorby", - "Komik" - ], - "correct": 0, - "expl": "Aktivní v publicistice." - }, - { - "prompt": "Kdy vyšel román?", - "options": [ - "1869", - "1950", - "2000", - "1700" - ], - "correct": 0, - "expl": "19. st." - }, - { - "prompt": "Co NENÍ v díle?", - "options": [ - "Exotické cesty", - "Idealizace hrdiny", - "Pouze pražská realistická vesnice bez děje", - "Náboženské motivy" - ], - "correct": 2, - "expl": "Děj je exotický." - }, - { - "prompt": "Xaverský zemřel?", - "options": [ - "Na ostrově Sancian / v misii", - "V Praze hradě", - "V USA", - "Neumírá" - ], - "correct": 0, - "expl": "Historický konec." - }, - { - "prompt": "Romantický hrdina?", - "options": [ - "Obětuje se pro ideál", - "Cynik", - "Villain", - "Dítě" - ], - "correct": 0, - "expl": "Idealizovaná postava." - }, - { - "prompt": "Maturita – proč?", - "options": [ - "Česká romantická próza, historie", - "Bez významu", - "Jen jméno", - "Komiks" - ], - "correct": 0, - "expl": "Součást přehledu." - }, - { - "prompt": "Jezuité?", - "options": [ - "Řád, misie, vzdělání", - "Sportovní klub", - "Německá armáda", - "Bez role" - ], - "correct": 0, - "expl": "Kontext víry." - }, - { - "prompt": "Tón?", - "options": [ - "Dobrodružný i idealistický", - "Pouze komedie", - "Horor", - "Bez děje" - ], - "correct": 0, - "expl": "Romantická adventura." - }, - { - "prompt": "Arbes vs Jirásek?", - "options": [ - "Arbes romantik, Jirásek jiný styl", - "Totéž", - "Arbes není Čech", - "Jirásek napsal Xaveria" - ], - "correct": 0, - "expl": "Různí autoři." - }, - { - "prompt": "Pronásledování?", - "options": [ - "Misie naráží na nebezpečí", - "Neexistuje", - "Jen v Praze", - "Jen humor" - ], - "correct": 0, - "expl": "Konflikty na cestách." - }, - { - "prompt": "Historická přesnost?", - "options": [ - "Román idealizuje, ne učebnice", - "Dokument", - "Sci-fi", - "Bez děje" - ], - "correct": 0, - "expl": "Fikce s historickým jádrem." - }, - { - "prompt": "Hlavní poselství?", - "options": [ - "Oběť pro víru a lidstvo", - "Materialismus", - "Válka je dobrá", - "Bez morálky" - ], - "correct": 0, - "expl": "Etický ideal." - }, - { - "prompt": "Vyprávění?", - "options": [ - "Epická próza třetí osoba", - "Deník", - "Drama", - "Elegie" - ], - "correct": 0, - "expl": "Román." - }, - { - "prompt": "Exotika?", - "options": [ - "Barví prostředí", - "Chybí", - "Jen Praha", - "Jen moře u Kub" - ], - "correct": 0, - "expl": "Asie je klíčová." - }, - { - "prompt": "Kanonicita?", - "options": [ - "Xaverský uctíván církví", - "Ne", - "Vymyšlený", - "Antihero" - ], - "correct": 0, - "expl": "Světec." - }, - { - "prompt": "Délka?", - "options": [ - "Román", - "Jedna báseň", - "Bez textu", - "Pouze titul" - ], - "correct": 0, - "expl": "Epická rozsah." - }, - { - "prompt": "Arbes zemřel?", - "options": [ - "1914", - "2000", - "1800", - "1990" - ], - "correct": 0, - "expl": "Přelom 19./20. st." - }, - { - "prompt": "Souvislost s Kolakovicem?", - "options": [ - "Arbes psal i jiné romantické prózy", - "Ne", - "Stejná kniha", - "Bez" - ], - "correct": 0, - "expl": "Arbesova tvorba je širší." - }, - { - "prompt": "Čtenář si odnese?", - "options": [ - "Obraz misijní epochy a romantismu", - "Návod Excel", - "Mapu USA", - "Recept" - ], - "correct": 0, - "expl": "Kulturní a literární." - }, - { - "prompt": "S kým je Xaverský úzce spojen v historii jezuitů?", - "options": [ - "S Ignácem z Loyoly", - "S Napoleonem", - "S Havlíčkem", - "S Gatsbym" - ], - "correct": 0, - "expl": "Ignác z Loyoly byl spoluzakladatel řádu a Xaveriův blízký spolupracovník." - }, - { - "prompt": "Jak Arbes v románu pracuje s historickou postavou?", - "options": [ - "Idealizuje ji v duchu romantismu, ne jako suchou kroniku", - "Píše jen encyklopedii bez děje", - "Záměrně popírá existenci světce", - "Převádí ji do sci-fi" - ], - "correct": 0, - "expl": "Jde o romantickou fikci inspirovanou reálným misionářem." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Xaverský vstupuje do jezuitů", - "Vydává se na misie do Asie", - "Kazí, léčí, navazuje kontakty", - "Naráží na kulturní a náboženské bariéry", - "Pokračuje v oběti a cestách", - "Umírá v misijní službě – světectví" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: jezuita → cesta do Asie → kázání → překážky → oběť → smrt světce." - ] -} diff --git a/data/cetba/svejk.json b/data/cetba/svejk.json deleted file mode 100644 index 0159329..0000000 --- a/data/cetba/svejk.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Jaroslav Hašek", - "Žánr: satirický pikareskní román; humor, anekdota", - "Poprvé vydáno: 1921–1923 (nedokončeno – autor zemřel 1923)", - "Děj: Rakousko-Uhersko za 1. světové války, cesta Josefa Švejka do armády", - "Vyprávění: er-forma; řetězec historek, dialogů a absurdních situací" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "1. světová válka a rozpadající se monarchie – absurdita rozkazů.", - "Armáda a byrokracie jako mašinerie hlouposti.", - "Český malý člověk přežívá lstí, „švejkováním“ a předstíranou naivitou.", - "Satira na vlastenectví, církev, špionáž a válečnou propagandu.", - "Praha, Budějovice, fronta – putování systémem.", - "Humor jako obrana proti nesmyslu moci." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Josef Švejk – dobrý voják, blbost jako strategie.", - "Nadporučík Lukáš – pán Švejka, často v nesnázích.", - "Polní kurát Otto Katz – pijan, hráč, „patriot“.", - "Poručík Dub – kariérista, donašeč, nenávidí Čechy.", - "Policejní rada Bretschneider – provokatér v hospodách.", - "Majitel císařských lázní Müller – další z autorit." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Švejkování – ironická poslušnost, přetvářka hloupého.", - "Anekdota – stavební jednotka textu.", - "Byrokracie – úřady, armáda, nesmyslné formuláře.", - "Satira – smích vede k odhalení absurdity.", - "Válka – nonsens, ne hrdinský epos.", - "Hospoda U kalicha – prostor lidové moudrosti." - ] - } - ], - "quiz": [ - {"prompt": "Kdo napsal Osudy dobrého vojáka Švejka za světové války?", "options": ["Karel Čapek", "Jaroslav Hašek", "Bohumil Hrabal", "Franz Kafka"], "correct": 1, "expl": "Autorem je Jaroslav Hašek; román zůstal nedokončený jeho smrtí v roce 1923."}, - {"prompt": "Proč je román nedokončený?", "options": ["Autor ho záměrně nechal otevřený", "Hašek zemřel dřív, než stihl dílo dokončit", "Zákaz cenzury", "Chybí poslední kapitola v tiskárně"], "correct": 1, "expl": "Hašek zemřel v roce 1923; kniha končí uprostřed Švejkova putování."}, - {"prompt": "Kdo je hlavní hrdina?", "options": ["Nadporučík Lukáš", "Josef Švejk", "Poručík Dub", "Bretschneider"], "correct": 1, "expl": "Josef Švejk je „dobrý voják“, který absurdní svět boří zdánlivou hloupostí."}, - {"prompt": "Co je Švejkování?", "options": ["Vojenská disciplína", "Předstíraná naivita a poslušnost, která systém rozbíjí", "Pouze alkoholismus", "Vlastenecká propaganda"], "correct": 1, "expl": "Švejk plní rozkazy tak, že je jejich absurdita zřejmá – chytrá maska hloupého."}, - {"prompt": "Kdo je nadporučík Lukáš?", "options": ["Švejkův nadřízený a pán", "Rakouský císař", "Lékař", "Novinář"], "correct": 0, "expl": "Lukáš Švejka „vlastní“ a často trpí důsledky jeho historek."}, - {"prompt": "Proč Švejk skončí v blázinci na začátku?", "options": ["Zlodějna", "Kvůli absurdním odpovědím na vojenské otázky – simuluje nebo projevuje blbost", "Vražda", "Desertace"], "correct": 1, "expl": "Scéna s rakouskými vs. ruskými monarchy satiricky ukazuje Švejkův „pacifismus“."}, - {"prompt": "Kdo je policejní rada Bretschneider?", "options": ["Švejkův kamarád", "Provokatér, který v hospodách vylákává „velezrady“", "Kněz", "Generál"], "correct": 1, "expl": "Bretschneider sbírá důkazy proti hostům – satira na politickou policii."}, - {"prompt": "Kdo je poručík Dub?", "options": ["Maďarský patriot a donašeč", "Švejkův bratr", "Lékař", "Císař"], "correct": 0, "expl": "Dub je kariérista, nenávidí Čechy a rád udává – karikatura vlastence."}, - {"prompt": "Jaký je vztah románu k 1. světové válce?", "options": ["Oslavuje hrdinství", "Satiricky ukazuje absurditu a nesmysl války", "Ignoruje válku", "Je pohádkou"], "correct": 1, "expl": "Hašek míří proti romantizaci války a monarchie."}, - {"prompt": "Kde Švejk často vypráví historky?", "options": ["V kosmu", "V hospodě, na marši, u autorit", "Jen v kostele", "Jen na soudu"], "correct": 1, "expl": "Dialog a anekdota jsou jádrem stylu – Švejk mluví a tím rozbíjí moc."}, - {"prompt": "Kdo je polní kurát Otto Katz?", "options": ["Asketa", "Pijan, hráč, „patriot“ s pochybnou minulostí", "Generál", "Dítě"], "correct": 1, "expl": "Katz satiricky zobrazuje církev a vlastenectví v armádě."}, - {"prompt": "Jaký stát je prostředím děje?", "options": ["Československo 1938", "Rakousko-Uhersko za 1. světové války", "Sovětský svaz", "Napoleonská Francie"], "correct": 1, "expl": "Švejk slouží císařské armádě – český malý člověk v mocnostech monarchie."}, - {"prompt": "Co je typickým stavebním prvkem textu?", "options": ["Jeden souvislý thriller", "Anekdota za anekdotou, odbočky a dialogy", "Epický hexametr", "Drama bez prózy"], "correct": 1, "expl": "Pikareskní forma – epizody a historky místo klasické zápletky."}, - {"prompt": "Proč Švejk nosí vozík s invalidou?", "options": ["Je trest", "Satirická epizoda – služba a absurdita", "Je to sport", "Je generál"], "correct": 1, "expl": "Mnoho epizod zesměšňuje vojenskou službu a nařízení."}, - {"prompt": "Jak Hašek líčí českého vojáka?", "options": ["Jako slavného hrdinu", "Jako chytrého přeživšího v absurdním systému", "Jako zrádce vždy", "Jako neviditelného"], "correct": 1, "expl": "Švejk reprezentuje českou zkušenost v cizí armádě – humor a odpor."}, - {"prompt": "Které téma NENÍ typické?", "options": ["Satira na byrokracii", "Válečný nonsens", "Absolutní vážnost hrdinských eposů bez ironie", "Hospodské historky"], "correct": 2, "expl": "Román je antihrdinský a komický, ne slavnostní epos."}, - {"prompt": "Jaký význam má humor v románu?", "options": ["Jen zábava bez myšlenky", "Odhaluje absurditu moci a války", "Obhajuje válku", "Nahrazuje děj úplně"], "correct": 1, "expl": "Smích je u Haška zbraní – čtenář vidí nesmysl systému."}, - {"prompt": "Kdo je Švejkův „nepřítel“ mezi důstojníky?", "options": ["Lukáš vždy", "Často Dub a různé kariéristy", "Nikdo", "Jen císař osobně"], "correct": 1, "expl": "Dub a podobní reprezentují malichernou moc a donášení."}, - {"prompt": "Co symbolizuje hospoda U kalicha?", "options": ["Místo exekuce", "Prostor lidové selské moudrosti a ironie", "Banka", "Škola"], "correct": 1, "expl": "Hospoda je kontrast k úředním a vojenským institucím."}, - {"prompt": "Jak Švejk reaguje na rozkazy?", "options": ["Vždy desertuje", "Poslušně je plní, ale způsobem, který odhalí absurditu", "Ignoruje je úplně", "Píše básně"], "correct": 1, "expl": "Zdánlivá poslušnost je forma odporu – jádro švejkování."}, - {"prompt": "Proč je román důležitý pro maturitu?", "options": ["Je chemická tabulka", "Česká klasika: satira, válka, styl anekdot, Švejk", "Je mapa Evropy", "Je zákoník"], "correct": 1, "expl": "U maturity: Hašek, kontext 1. sv. války, postavy, humor, švejkování."}, - {"prompt": "Kdy román vycházel?", "options": ["1890", "1921–1923", "1968", "2010"], "correct": 1, "expl": "První díly za Haškova života, dokončení zabránila smrt."}, - {"prompt": "Jaký je vztah k autobiografii?", "options": ["Hašek sám znal armádu a absurditu války – silné autobiografické rysy", "Čistá sci-fi", "Antická legenda", "Beletrie bez reálií"], "correct": 0, "expl": "Hašek prošel armádou a světem hospod – zkušenost v textu cítit."}, - {"prompt": "Co je pikareskní román?", "options": ["Román o jednom dni", "Putování rošťáka/lišáka epizodami", "Lyrika", "Tragedie"], "correct": 1, "expl": "Švejk prochází místy a situacemi, sbírá historky."}, - {"prompt": "Která postava je provokatér?", "options": ["Bretschneider", "Švejk", "Lukáš", "Katz"], "correct": 0, "expl": "Policejní rada Bretschneider vylákává výroky pro represi."}, - {"prompt": "Jak končí dílo v originálu?", "options": ["Švejk vítězí nad válkou", "Nedokončené – Švejk stále na cestě / ve válce", "Svatba", "Mír 1918 slavnostně"], "correct": 1, "expl": "Nedokončenost patří k osudu knihy – válka a putování pokračují."}, - {"prompt": "Co satiricky zobrazuje postava Katze?", "options": ["Církev a vlastenectví v armádě", "Vědu", "Sport", "Školství"], "correct": 0, "expl": "Polní kurát Katz je komická figura faráře-vojáka."}, - {"prompt": "Jaký jazyk je typický?", "options": ["Knihovní archaismus", "Hovorová čeština, argot, dialog", "Latina celá kniha", "Angličtina"], "correct": 1, "expl": "Hašek používá živou mluvu, hospodské výrazy a ironii."}, - {"prompt": "Které tvrzení o Lukášovi je správné?", "options": ["Je Švejkův nadřízený, často trpí důsledky Švejkových akcí", "Je císař", "Je vždy klidný a bohatý", "Nepozná Švejka"], "correct": 0, "expl": "Lukáš je „pán“ Švejka v systému služby – komický pár."}, - {"prompt": "Co Hašek kritizuje nejvíc?", "options": ["Pouze počasí", "Válku, monarchii, byrokracii a falešné vlastenectví", "Pouze zemědělství", "Sport"], "correct": 1, "expl": "Satira míří na mocenské struktury a válečný nonsens."}, - {"prompt": "Které dílo NENÍ Haškovo?", "options": ["Osudy dobrého vojáka Švejka", "Povídky z kapes", "Ostro sledované vlaky", "Dobrý voják Švejk – divadlo"], "correct": 2, "expl": "Ostře sledované vlaky napsal Bohumil Hrabal, ne Hašek."} - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Švejk a absurdní výslech – cesta do blázince", - "Hospoda, Bretschneider a Švejkův návrat k službě", - "Švejk u nadporučíka Lukáše v Praze", - "Cesta do Budějovic a další epizody na cestě", - "Služba u polního kuráta Katze a fronta", - "Putování pokračuje – román zůstává nedokončen" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: blázinec → hospoda a služba → Lukáš → cesta na jih → Katz a fronta → nedokončené putování." - ] -} diff --git a/data/cetba/tereza-raquinova.json b/data/cetba/tereza-raquinova.json deleted file mode 100644 index 852580e..0000000 --- a/data/cetba/tereza-raquinova.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Émile Zola (1840–1902)", - "Žánr: naturalistický román", - "Poprvé vydáno: 1867", - "Děj: Paříž, obchod s galanterii u Seiny", - "Vyprávění: er-forma, determinismus, psychologický tlak" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Tereza žije s manželstvím s chromým Camillem a tchyní.", - "Milostná aféra s Laurentem – společný zločin.", - "Utopení Camilla – vina a noční můry.", - "Sňatek Terezy a Laurenta – peklo místo štěstí.", - "Mamka Raquinová – němá svědkyně.", - "Naturalismus – prostředí a pudy řídí osud." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Thérèse Raquin – hlavní hrdinka, utlačovaná, vášnivá.", - "Camille Raquin – nemotorný, slabý manžel.", - "Laurent – Laurentova touha po Tereze, lenoch.", - "Madame Raquin – matka Camilla, majitelka obchodu.", - "Michaud, Grivet – pravidelní hosté domu.", - "Policie / soud – hrozba odhalení." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Naturalismus – člověk produkt dědičnosti a prostředí.", - "Criminelles trio – vražda z vášně.", - "Vina – halucinace mrtvého Camilla.", - "Mamka jako soudce – němý výčitka.", - "Seina – místo vraždy.", - "Determinismus – nelze uniknout následkům." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Terezu Raquinovou?", - "options": [ - "Hugo", - "Émile Zola", - "Flaubert", - "Maupassant" - ], - "correct": 1, - "expl": "Zola, naturalista." - }, - { - "prompt": "Kde děj?", - "options": [ - "Paříž, obchod u Seiny", - "Praha", - "Londýn", - "Venkov" - ], - "correct": 0, - "expl": "Městské prostředí." - }, - { - "prompt": "Kdo je Tereza?", - "options": [ - "Vdova po Camillovi na konci začátku", - "Manželka Camilla, milenka Laurenta", - "Policistka", - "Němka" - ], - "correct": 1, - "expl": "Ústřední postava." - }, - { - "prompt": "Camille?", - "options": [ - "Atlet", - "Slabý, chromý manžel", - "Detektiv", - "Král" - ], - "correct": 1, - "expl": "Oběť vraždy." - }, - { - "prompt": "Laurent?", - "options": [ - "Camillův přítel, milenec Terezy", - "Kněz", - "Dítě", - "Učitel" - ], - "correct": 0, - "expl": "Spoluviník." - }, - { - "prompt": "Jak Camille zemře?", - "options": [ - "Utopení při „hře“ u Seiny", - "Stářím", - "Válka", - "Nehoda auta" - ], - "correct": 0, - "expl": "Plánovaná vražda." - }, - { - "prompt": "Co po vraždě?", - "options": [ - "Klid", - "Vina, noční můry, nenávist", - "Bohatství bez problémů", - "Emigrace" - ], - "correct": 1, - "expl": "Manželé si ničí život." - }, - { - "prompt": "Madame Raquin?", - "options": [ - "Němá po mrtvici, svědkyně", - "Mrtvá hned", - "Vrah", - "Nevidí" - ], - "correct": 0, - "expl": "Děsivý svědek." - }, - { - "prompt": "Naturalismus?", - "options": [ - "Člověk určen prostředím a pudy", - "Pouze pohádka", - "Sci-fi", - "Bez teorie" - ], - "correct": 0, - "expl": "Zolův program." - }, - { - "prompt": "Jak končí?", - "options": [ - "Svatba dětí", - "Tereza a Laurent se zabijí / double suicide", - "Detektiv vyřeší", - "Camille žije" - ], - "correct": 1, - "expl": "Tragický konec." - }, - { - "prompt": "Žánr?", - "options": [ - "Naturalistický román", - "Komedie", - "Epos", - "Bajka" - ], - "correct": 0, - "expl": "Francouzský naturalismus." - }, - { - "prompt": "Proč sňatek T+L?", - "options": [ - "Láska", - "Chce získat dědictví / udržet aféru", - "Rozkaz matky", - "Nevědomky" - ], - "correct": 1, - "expl": "Praktický i vášnivý motiv." - }, - { - "prompt": "Hosté u mamky?", - "options": [ - "Pravidelná hra domina", - "Nikdo", - "Válka", - "Cirkus" - ], - "correct": 0, - "expl": "Rámec všednosti." - }, - { - "prompt": "Vina se projeví?", - "options": [ - "Halucinace Camilla", - "Ne", - "Jen radost", - "Sport" - ], - "correct": 0, - "expl": "Psychologický tlak." - }, - { - "prompt": "Zola patří?", - "options": [ - "Naturalisté", - "Romantici 18. st.", - "Beat generation", - "Česká avantgarda" - ], - "correct": 0, - "expl": "École naturaliste." - }, - { - "prompt": "Co NENÍ téma?", - "options": [ - "Vášeň a zločin", - "Vina", - "Determinismus", - "Kosmické války" - ], - "correct": 3, - "expl": "Realistický pařížský děj." - }, - { - "prompt": "Rok vydání?", - "options": [ - "1867", - "1990", - "1700", - "2005" - ], - "correct": 0, - "expl": "19. století." - }, - { - "prompt": "Seina?", - "options": [ - "Scéna vraždy", - "Nepodstatná", - "Hrad", - "Les" - ], - "correct": 0, - "expl": "Řeka." - }, - { - "prompt": "Tereza dětství?", - "options": [ - "Vychována u Raquinových", - "Sirotek u tety", - "Královna", - "Němec" - ], - "correct": 0, - "expl": "Utlačovaná pozice." - }, - { - "prompt": "Laurent před aférou?", - "options": [ - "Lenoch, malíř amatér", - "Generál", - "Kněz", - "Dítě" - ], - "correct": 0, - "expl": "Společenský typ." - }, - { - "prompt": "Maturita?", - "options": [ - "Naturalismus, psychologie viny", - "Bez významu", - "Jen jména", - "Komiks" - ], - "correct": 0, - "expl": "Klasická francouzská próza." - }, - { - "prompt": "Tón?", - "options": [ - "Temný, deterministický", - "Lehká komedie", - "Pohádka", - "Satira bez vážnosti" - ], - "correct": 0, - "expl": "Tragédie vášně." - }, - { - "prompt": "Camillova matka po mrtvici?", - "options": [ - "Ochrnutí, komunikace obtížná", - "Tančí", - "Mluví víc", - "Odchází" - ], - "correct": 0, - "expl": "Němý soudce." - }, - { - "prompt": "Policie?", - "options": [ - "Hrozí odhalení, napětí", - "Neexistuje", - "Hned zatýká", - "Komedie" - ], - "correct": 0, - "expl": "Detektivní prvek." - }, - { - "prompt": "Vztah T+L po svatbě?", - "options": [ - "Nenávist, mutual destruction", - "Idyla", - "Rozchod klidný", - "Děti" - ], - "correct": 0, - "expl": "Peklo manželství." - }, - { - "prompt": "Zola jiné dílo?", - "options": [ - "Nana, Germinal", - "1984", - "Gatsby", - "Saturnin" - ], - "correct": 0, - "expl": "Součást cyklu Rougon-Macquart." - }, - { - "prompt": "Determinismus znamená?", - "options": [ - "Osud formován prostředím", - "Svoboda bez limitů", - "Náhoda bez důsledků", - "Magie" - ], - "correct": 0, - "expl": "Naturalistická idea." - }, - { - "prompt": "Proč utopení?", - "options": [ - "Vypadá jako nehoda", - "Nemožné", - "Camille plavce", - "Na souši" - ], - "correct": 0, - "expl": "Lehké alibi." - }, - { - "prompt": "Čtenář cítí?", - "options": [ - "Tlak viny a dusno", - "Pouze smích", - "Nic", - "Jen radost" - ], - "correct": 0, - "expl": "Psychologický horor." - }, - { - "prompt": "Titulní postava?", - "options": [ - "Thérèse Raquin", - "Madame Bovary", - "Julie", - "Ester" - ], - "correct": 0, - "expl": "Jméno v titulu." - }, - { - "prompt": "Proč se Tereza a Laurent po vraždě nenávidí?", - "options": [ - "Vina je dusí – obviňují se a ničí aféru", - "Camille je stále naživu", - "Matka je proti", - "Policie je okamžitě zatýká" - ], - "correct": 0, - "expl": "Zločin je spojil, ale psychický tlak je rozdělí." - }, - { - "prompt": "Jakou roli hraje pravidelná hra domina u Raquinových?", - "options": [ - "Zdůrazňuje všednost, která kontrastuje s vášní a zločinem", - "Je hlavním motivem vraždy", - "Neobjevuje se v díle", - "Slouží jen jako komická epizoda bez významu" - ], - "correct": 0, - "expl": "Monotónní večery ukazují útlak a rutinu před explozí vášně." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Tereza žije utlačeně s Camillem", - "Aféra s Laurentem", - "Vražda Camilla u Seiny", - "Sňatek viníků", - "Vina a halucinace", - "Sebevražda / zhoubný konec" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: útlak → aféra → vražda → svatba → vina → sebevražda." - ] -} diff --git a/data/cetba/tezka-hodina.json b/data/cetba/tezka-hodina.json deleted file mode 100644 index 3dbaf2c..0000000 --- a/data/cetba/tezka-hodina.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Jiří Wolker (1900–1924)", - "Žánr: lyrická poezie, proletářská", - "Poprvé vydáno: 1922", - "Děj: reflexe války, revoluce, sociální bídy", - "Forma: básnické sbírky – volný verš i rým" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Wolker – mladý komunistický básník.", - "Těžká hodina – metafora krizových momentů.", - "Témata: chudoba, válka, naděje proletariátu.", - "Influence symbolistů i moderny.", - "Předčasná smrt – tuberkulóza.", - "Sbírka Host do domu souvisí s tvorbou." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Jiří Wolker – básník, publicista.", - "Proletář / dělník v básních.", - "Matka, děti, chudina – postavy lyriky.", - "Revolutionary naděje – budoucnost.", - "Příroda jako kontrast městu.", - "Symbolická hodina zkoušky." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Proletářská poezie – třídní solidarita.", - "Těžká hodina – čas zkoušky, bolesti.", - "Válka – zklamání, utrpení.", - "Naděje – světlá budoucnost.", - "Symbolismus – obrazy, metafory.", - "Mladá smrt autora – mýtus." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Těžkou hodinu?", - "options": [ - "Seifert", - "Jiří Wolker", - "Havlíček", - "Neruda" - ], - "correct": 1, - "expl": "Wolker, 1922." - }, - { - "prompt": "Jaká forma?", - "options": [ - "Próza", - "Lyric poetry – sbírka", - "Drama", - "Epos" - ], - "correct": 1, - "expl": "Básnická sbírka." - }, - { - "prompt": "Wolker žil?", - "options": [ - "1900–1924", - "1890–1940", - "2000", - "1850" - ], - "correct": 0, - "expl": "Krátký život." - }, - { - "prompt": "Těžká hodina znamená?", - "options": [ - "Lehký večer", - "Krizový okamžik, bolest, zkoušku", - "Svatba", - "Dovolenou" - ], - "correct": 1, - "expl": "Metafora titulu." - }, - { - "prompt": "Hlavní témata?", - "options": [ - "Chudoba, válka, naděje", - "Sci-fi", - "Lov srn", - "Detektivka" - ], - "correct": 0, - "expl": "Proletářská lyrika." - }, - { - "prompt": "Wolker politicky?", - "options": [ - "Levicový, komunistické sympatie", - "Monarchista", - "Bez názorů", - "Cizí" - ], - "correct": 0, - "expl": "Revolutionary básník." - }, - { - "prompt": "Host do domu?", - "options": [ - "Další Wolkerova sbírka", - "Román", - "Film", - "Hra Goldoniho" - ], - "correct": 0, - "expl": "Související tvorba." - }, - { - "prompt": "Styl?", - "options": [ - "Volný verš, obraznost, emoce", - "Strofický epic", - "Proza dialog", - "Bez metafor" - ], - "correct": 0, - "expl": "Moderní lyrika." - }, - { - "prompt": "Proletář v básních?", - "options": [ - "Hrdina dělnické třídy", - "Nepřítel", - "Neexistuje", - "Král" - ], - "correct": 0, - "expl": "Třídní témata." - }, - { - "prompt": "Válka?", - "options": [ - "Zklamání, utrpení", - "Slavnost", - "Chybí", - "Vtip" - ], - "correct": 0, - "expl": "1. sv. válka ovlivnila generaci." - }, - { - "prompt": "Naděje?", - "options": [ - "Světlá budoucnost pro lid", - "Bez naděje", - "Pouze smutek", - "Emigrace" - ], - "correct": 0, - "expl": "Optimismus v těžké hodině." - }, - { - "prompt": "Wolker zemřel na?", - "options": [ - "Tuberkulózu", - "Válku v bitvě", - "Stáří", - "Autonehodu" - ], - "correct": 0, - "expl": "Mladá smrt." - }, - { - "prompt": "Generace?", - "options": [ - "Meziválečná avantgarda / levicová mládež", - "Baroko", - "2000", - "Středověk" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Co NENÍ typické?", - "options": [ - "Sociální témata", - "Emoce", - "Lyrika", - "Naturalistický román o vraždě" - ], - "correct": 3, - "expl": "Wolker je básník." - }, - { - "prompt": "Báseň a obraz?", - "options": [ - "Vizuální metafory", - "Bez obrazů", - "Jen próza", - "Jen humor" - ], - "correct": 0, - "expl": "Symbolistické prvky." - }, - { - "prompt": "Maturita?", - "options": [ - "Témata, verš, autor", - "Jen rok", - "Mapa", - "Bez" - ], - "correct": 0, - "expl": "Poezie na seznamu." - }, - { - "prompt": "Čeština?", - "options": [ - "Spisovná, citlivá", - "Angličtina", - "Archaičtina bez smyslu", - "Němčina" - ], - "correct": 0, - "expl": "Wolkerova čeština." - }, - { - "prompt": "Influence?", - "options": [ - "Symbolismus, moderna", - "Antický epos", - "Bez", - "Hollywood" - ], - "correct": 0, - "expl": "Literární tradice." - }, - { - "prompt": "Tón sbírky?", - "options": [ - "Vážný, nadějí prodchnutý", - "Pure comedy", - "Horor", - "Bez emocí" - ], - "correct": 0, - "expl": "Krizové chvíle." - }, - { - "prompt": "Dělník?", - "options": [ - "Solidarita, úcta", - "Posměch", - "Neexistuje", - "Villain" - ], - "correct": 0, - "expl": "Proletářská poezie." - }, - { - "prompt": "Příroda?", - "options": [ - "Kontrast k městu/chudobě", - "Chybí", - "Jen vesmír", - "Jen moře" - ], - "correct": 0, - "expl": "Lyricismus." - }, - { - "prompt": "Wolker a Wolkerova ulice?", - "options": [ - "Praha pamatuje", - "Ne", - "Berlin", - "Nic" - ], - "correct": 0, - "expl": "Kult autora." - }, - { - "prompt": "Revolution?", - "options": [ - "Naděje v lepší společnost", - "Proti", - "Bez", - "Jen válka" - ], - "correct": 0, - "expl": "Ideály." - }, - { - "prompt": "Krátce: proč číst?", - "options": [ - "Pochopit meziválečnou levicovou lyriku", - "Návod k jídlu", - "Geografie", - "Sport" - ], - "correct": 0, - "expl": "Literární historie." - }, - { - "prompt": "Verš?", - "options": [ - "Volný i tradiční prvky", - "Jen rýmovaný sonet", - "Proza", - "Bez" - ], - "correct": 0, - "expl": "Flexibilní forma." - }, - { - "prompt": "Emoce?", - "options": [ - "Empatie k chudým", - "Chlad", - "Bez", - "Ironie sitcom" - ], - "correct": 0, - "expl": "Humanismus." - }, - { - "prompt": "Současníci?", - "options": [ - "Seifert, Nezval – jinak", - "Shakespeare", - "Keyes", - "Jirotka" - ], - "correct": 0, - "expl": "Česká poezie 20. st." - }, - { - "prompt": "Titulní metafora?", - "options": [ - "Hodina zkoušky života", - "Hodiny na věži", - "Školní hodina", - "Bez" - ], - "correct": 0, - "expl": "Symbol." - }, - { - "prompt": "Publikum?", - "options": [ - "Čtenář hledající smysl v bídě", - "Jen děti", - "Jen vědci", - "Bez" - ], - "correct": 0, - "expl": "Engaged poetry." - }, - { - "prompt": "Wolker věk smrti?", - "options": [ - "24 let", - "80", - "50", - "10" - ], - "correct": 0, - "expl": "Mladý autor." - }, - { - "prompt": "Jak souvisí Těžká hodina s Wolkerovou sbírkou Host do domu?", - "options": [ - "Jsou to blízké etapy jeho krátké tvorby – obě patří k maturitnímu přehledu", - "Host do domu je próza o mlokách", - "Nejsou nijak spojeny", - "Host do domu napsal Neruda" - ], - "correct": 0, - "expl": "Wolker je autorem obou básnických sbírek z raného 20. století." - }, - { - "prompt": "Proč je Wolker důležitý pro českou meziválečnou literaturu?", - "options": [ - "Spojuje cit, obraznost a levicové sociální téma v mladém věku", - "Psal jen německy", - "Nebyl publikován", - "Patří k baroku" - ], - "correct": 0, - "expl": "Krátký život, silná lyrika a angažovanost z něj dělají symbol generace." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Wolker vnímá bídu a válku", - "Přichází těžké hodiny zkoušky", - "Básně líčí proletářský život", - "Objevuje se naděje v solidaritě", - "Lyrika spojuje osobní a kolektivní", - "Světlo na konci těžké hodiny" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: bída/válka → krize → proletář → naděje → lyrička syntéza → perspektiva." - ] -} diff --git a/data/cetba/tridni-kniha.json b/data/cetba/tridni-kniha.json deleted file mode 100644 index 3039db9..0000000 --- a/data/cetba/tridni-kniha.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autoři: Ladislav Smoljak, Zdeněk Svěrák (Divadlo Járy Cimrmana)", - "Žánr: divadelní komedie", - "Poprvé uvedeno: 1967 (Cimrmanovo divadlo)", - "Děj: škola, vyšetřování zmizelé třídní knihy", - "Forma: dialogy, absurdní vyšetřování" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Parodie detektivky v učitelské sborovně.", - "Třídní kniha – symbol školního řádu.", - "Cimrmanovský humor – malichernost vs. velkolepost.", - "Učitelé jako podezřelí i vyšetřovatelé.", - "Satira byrokracie a autority.", - "Jazykové hříčky Smoljaka a Svěráka." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ředitel školy – vede vyšetřování.", - "Učitel Nechleb aj. – komické figury.", - "Učitelé sborovny – rivalita.", - "Jára Cimrman – rámec divadla (mýtus).", - "Žáci – nepřítomní, ale důvod knihy.", - "Vyšetřovatelé absurdní logiky." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Třídní kniha – záznam žáků, předmět sporu.", - "Parodie krimi – ztráta knihy jako zločin.", - "Cimrmanologie – fiktivní věda.", - "Sborovna – uzavřený svět.", - "Humor hlášek – jazyková komika.", - "Byrokracie – pravidlo nad smysl." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal hru?", - "options": [ - "Goldoni", - "Smoljak a Svěrák", - "Čapek", - "Vrchlický" - ], - "correct": 1, - "expl": "Cimrmanovo divadlo." - }, - { - "prompt": "Titul hry?", - "options": [ - "Vyšetřování ztráty třídní knihy", - "Sluha dvou pánů", - "Revizor", - "R.U.R." - ], - "correct": 0, - "expl": "Maturitní název." - }, - { - "prompt": "Kde děj?", - "options": [ - "Škola – sborovna", - "Moře", - "RAF", - "Terezín" - ], - "correct": 0, - "expl": "Školní prostředí." - }, - { - "prompt": "Co zmizelo?", - "options": [ - "Třídní kniha", - "Gatsby", - "Marlin", - "Mloci" - ], - "correct": 0, - "expl": "Předmět vyšetřování." - }, - { - "prompt": "Žánr?", - "options": [ - "Komedie / parodie", - "Tragedie", - "Epos", - "Lyrika" - ], - "correct": 0, - "expl": "Humor." - }, - { - "prompt": "Cimrman?", - "options": [ - "Fiktivní génius divadla", - "Reálný učitel", - "Němec", - "Pilot" - ], - "correct": 0, - "expl": "Značka divadla." - }, - { - "prompt": "Humor?", - "options": [ - "Absurdní vyšetřování", - "Horor", - "Bez", - "Pure romance" - ], - "correct": 0, - "expl": "Parodie." - }, - { - "prompt": "Učitel Nechleb?", - "options": [ - "Postava z Cimrmanových her", - "Gatsby", - "Winston", - "Bez" - ], - "correct": 0, - "expl": "Komická figura." - }, - { - "prompt": "Satira?", - "options": [ - "Byrokracie, škola", - "Bez", - "Jen moře", - "Válka" - ], - "correct": 0, - "expl": "Společenská." - }, - { - "prompt": "Rok uvedení?", - "options": [ - "1967", - "1925", - "1869", - "2000" - ], - "correct": 0, - "expl": "Divadlo." - }, - { - "prompt": "Forma?", - "options": [ - "Divadelní dialogy", - "Román", - "Báseň", - "Memoáry" - ], - "correct": 0, - "expl": "Drama." - }, - { - "prompt": "Proč maturita?", - "options": [ - "Česká divadelní komedie", - "Bez", - "Jen mapa", - "Komiks" - ], - "correct": 0, - "expl": "Kultura." - }, - { - "prompt": "Třídní kniha symbol?", - "options": [ - "Řád, evidence, malichernost", - "Láska", - "Válka", - "Bez" - ], - "correct": 0, - "expl": "Škola." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Komedie", - "Parodie", - "Škola", - "Seriózní naturalistický román Zola" - ], - "correct": 3, - "expl": "Jiný žánr." - }, - { - "prompt": "Smoljak Svěrák?", - "options": [ - "Autorská dvojice", - "Piloti", - "Němci", - "Bez" - ], - "correct": 0, - "expl": "Cimrman." - }, - { - "prompt": "Vyšetřování?", - "options": [ - "Přehnané, detektivní parodie", - "Real NYPD", - "Bez", - "Sci-fi" - ], - "correct": 0, - "expl": "Komický děj." - }, - { - "prompt": "Publikum?", - "options": [ - "Směje se absurditě", - "Pláče", - "Bez", - "Spí" - ], - "correct": 0, - "expl": "Divadlo." - }, - { - "prompt": "Jazyk?", - "options": [ - "Hovorný, hříčky", - "Archaičtina", - "Angličtina", - "Bez" - ], - "correct": 0, - "expl": "Svěrák/Smoljak." - }, - { - "prompt": "Žáci?", - "options": [ - "Důvod existence knihy", - "Hrdinové bez školy", - "Ne", - "Piloti" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Sborovna?", - "options": [ - "Místo děje", - "Moře", - "RAF", - "Bez" - ], - "correct": 0, - "expl": "Prostor." - }, - { - "prompt": "Další Cimrman?", - "options": [ - "Hospoda na mýtince aj.", - "Gatsby", - "1984", - "Bez" - ], - "correct": 0, - "expl": "Divadlo." - }, - { - "prompt": "Tón?", - "options": [ - "Lehký, absurdní", - "Tragický", - "Horor", - "Bez" - ], - "correct": 0, - "expl": "Komedie." - }, - { - "prompt": "Autorita ředitele?", - "options": [ - "Parodována", - "Bez", - "Vždy moudrá", - "Bez" - ], - "correct": 0, - "expl": "Satira." - }, - { - "prompt": "Detektivka prvky?", - "options": [ - "Podezření, výslech", - "Bez", - "Jen láska", - "Válka" - ], - "correct": 0, - "expl": "Parodie." - }, - { - "prompt": "Česká kultura?", - "options": [ - "Ikona", - "Neznámé", - "Bez", - "Německé" - ], - "correct": 0, - "expl": "Populární." - }, - { - "prompt": "Hra vs román?", - "options": [ - "Text pro divadlo", - "Epos", - "Bez", - "Lyrika" - ], - "correct": 0, - "expl": "Drama." - }, - { - "prompt": "Malichernost?", - "options": [ - "Velká věc z maličkosti", - "Bez", - "Válka", - "Bez" - ], - "correct": 0, - "expl": "Humor." - }, - { - "prompt": "Cimrman žil?", - "options": [ - "Fiktivně – vtip", - "2000", - "1890 real", - "Bez" - ], - "correct": 0, - "expl": "Mýtus." - }, - { - "prompt": "Maturita tip?", - "options": [ - "Děj, humor, smysl parodie", - "Jen rok", - "Bez", - "Mapa" - ], - "correct": 0, - "expl": "Interpretace." - }, - { - "prompt": "Závěr hry?", - "options": [ - "Rozuzlení komické", - "Všichni mrtví tragicky", - "Bez", - "Válka" - ], - "correct": 0, - "expl": "Komedie." - }, - { - "prompt": "O co jde v ději Třídní knihy?", - "options": [ - "O absurdní vyšetřování ztráty třídní knihy ve škole", - "O válku s mloky", - "O rybaření na Kubě", - "O jazz v Náchodsku" - ], - "correct": 0, - "expl": "Ztráta knihy spustí groteskní školní „vyšetřování“." - }, - { - "prompt": "Jaký humor je typický pro Třídní knihu?", - "options": [ - "Situační absurdita, byrokracie a jazykové hříčky", - "Naturalistický determinismus", - "Gotický horor", - "Epická báseň" - ], - "correct": 0, - "expl": "Smoljak–Svěrák pracují s pravidly, která přerostou smysl." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Zmizí třídní kniha", - "Ředitel zahájí vyšetřování", - "Učitelé jsou vyslýcháni", - "Absurdní důkazy a pomluvy", - "Cimrmanovské vysvětlení", - "Případ se uzavře komicky" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: ztráta knihy → vyšetřování → výslechy → absurdita → vysvětlení → konec." - ] -} diff --git a/data/cetba/tyrolske-elegie.json b/data/cetba/tyrolske-elegie.json deleted file mode 100644 index 5355b87..0000000 --- a/data/cetba/tyrolske-elegie.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Havlíček Borovský (1821–1856)", - "Žánr: satirická politická poezie", - "Poprvé vydáno: 1855 (Tábor)", - "Děj: reakce na potlačení revoluce 1848–49", - "Forma: elegie – ironické, kritické básně" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Havlíček – publicista, satirik, národní buditel.", - "Tyrolské elegie – posměch Rakousku po revoluci.", - "Napoleon III., Habsburkové, reakce.", - "Exil v Brixenu / Tyrolsko – autobiografický rámec.", - "Jazyk – hovorový, ironický, úderný.", - "Věznění a cenzura – Havlíček jako symbol odporu." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Karel Havlíček Borovský – básník, novinář.", - "Císař František Josef – terč satiry.", - "Rakouská monarchie – útlak.", - "Český národ – addresát naděje.", - "Napoleon III. – politické aluze.", - "Satirické personifikace." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Satira – výsměch moci.", - "Elegie – ironicky pojatý žánr.", - "Revolution 1848 – zmařená naděje.", - "Exil – zkušenost autora.", - "Národní obrození – kontext.", - "Publicistická funkce poezie." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Tyrolské elegie?", - "options": [ - "Neruda", - "Karel Havlíček Borovský", - "Wolker", - "Vrchlický" - ], - "correct": 1, - "expl": "Havlíček, 1855." - }, - { - "prompt": "Proč „tyrolské“?", - "options": [ - "Vznik v souvislosti s Havlíčkovým pobytem v Tyrolsku / Brixen", - "Popis hor bez politiky", - "Německá opera", - "Sport" - ], - "correct": 0, - "expl": "Autobiografický rámec." - }, - { - "prompt": "Hlavní funkce?", - "options": [ - "Satira Rakouska a reakce", - "Láska k přírodě bez politiky", - "Sci-fi", - "Cookbook" - ], - "correct": 0, - "expl": "Politická poezie." - }, - { - "prompt": "1848?", - "options": [ - "Revolution potlačena – téma elegií", - "Nezmíněno", - "Rok smrti Wolker", - "2000" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Havlíček profese?", - "options": [ - "Novinář, satirik, básník", - "Holič", - "Pilot", - "Malíř" - ], - "correct": 0, - "expl": "Publicista." - }, - { - "prompt": "Forma?", - "options": [ - "Satirické elegie", - "Realistický román", - "Drama", - "Epos" - ], - "correct": 0, - "expl": "Lyric satire." - }, - { - "prompt": "Jazyk?", - "options": [ - "Ironický, hovorový, úderný", - "Archaičtina bez smyslu", - "Angličtina", - "Bez humoru" - ], - "correct": 0, - "expl": "Typický Havlíček." - }, - { - "prompt": "Císař?", - "options": [ - "Habsburská monarchie kritizována", - "Chválen bez ironie", - "Neexistuje", - "Americký" - ], - "correct": 0, - "expl": "Politická kritika." - }, - { - "prompt": "Havlíček zemřel?", - "options": [ - "1856", - "1924", - "2000", - "1700" - ], - "correct": 0, - "expl": "Krátce po elegiích." - }, - { - "prompt": "Vězení / cenzura?", - "options": [ - "Havlíček perzekvován", - "Ne", - "Vítěz", - "Bez" - ], - "correct": 0, - "expl": "Symbol odporu." - }, - { - "prompt": "Napoleon III.?", - "options": [ - "Politické aluze v elegiích", - "Hlavní hrdina románu", - "Ne", - "Český král" - ], - "correct": 0, - "expl": "Evropská politika." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Satira", - "Politika", - "Národní téma", - "Bezmyšlenkovitá poprvky bez kontextu" - ], - "correct": 3, - "expl": "Elegie jsou politické." - }, - { - "prompt": "Maturita?", - "options": [ - "Kontext obrození, satira", - "Jen mapa Tyrol", - "Bez", - "Komiks" - ], - "correct": 0, - "expl": "Klasická česká poezie." - }, - { - "prompt": "Elegie obvykle?", - "options": [ - "Smutek – Havlíček ironizuje žánr", - "Vždy svatba", - "Vždy sci-fi", - "Bez" - ], - "correct": 0, - "expl": "Inverze žánru." - }, - { - "prompt": "Čtenář?", - "options": [ - "Má znát historii 1848", - "Bez znalosti", - "Jen děti", - "Cizinci bez překladu" - ], - "correct": 0, - "expl": "Historický kontext." - }, - { - "prompt": "Národní buditel?", - "options": [ - "Ano", - "Ne", - "Němec", - "Bez role" - ], - "correct": 0, - "expl": "Havlíček v kánonu." - }, - { - "prompt": "Kde vycházely?", - "options": [ - "Tábor / ilegální tisk", - "New York", - "Moskva", - "Bez" - ], - "correct": 0, - "expl": "České vydání." - }, - { - "prompt": "Tón?", - "options": [ - "Ironický, kritický", - "Sladký bez obsahu", - "Horor", - "Bez" - ], - "correct": 0, - "expl": "Satirický." - }, - { - "prompt": "Havlíček a Borová?", - "options": [ - "Pseudonym / místo", - "Cizí země", - "Postava", - "Opera" - ], - "correct": 0, - "expl": "Autorovo jméno." - }, - { - "prompt": "Vztah k Vrchlickému?", - "options": [ - "Jiná generace a styl", - "Totéž", - "Vrchlický napsal elegie", - "Bez" - ], - "correct": 0, - "expl": "Různí básníci." - }, - { - "prompt": "Cíl satiry?", - "options": [ - "Reakční moc, absurdita", - "Chudí", - "Příroda", - "Sport" - ], - "correct": 0, - "expl": "Politická moc." - }, - { - "prompt": "Proč maturita?", - "options": [ - "Základ české satiry a obrození", - "Bez", - "Jen Tyrolsko mapa", - "Jen rok" - ], - "correct": 0, - "expl": "Kulturní memory." - }, - { - "prompt": "Básnický prostředek?", - "options": [ - "Ironie, personifikace", - "Bez", - "Jen rým", - "Proza" - ], - "correct": 0, - "expl": "Satirické figury." - }, - { - "prompt": "Havlíček legacy?", - "options": [ - "Symbol svobody slova", - "Zapomenut", - "Němec", - "Bez" - ], - "correct": 0, - "expl": "Národní autor." - }, - { - "prompt": "Revolution naděje?", - "options": [ - "Zklamání → satira", - "Splněno", - "Ne", - "2000" - ], - "correct": 0, - "expl": "Motivace elegií." - }, - { - "prompt": "Publikum 19. st.?", - "options": [ - "Čtenáři Národních listů aj.", - "Bez", - "Jen císař", - "Hollywood" - ], - "correct": 0, - "expl": "Publicistická síť." - }, - { - "prompt": "Překlad?", - "options": [ - "Originál česky", - "Anglicky jen", - "Bez", - "Latině" - ], - "correct": 0, - "expl": "Česká klasika." - }, - { - "prompt": "Počet elegií?", - "options": [ - "Cyklus básní (známý soubor)", - "Jedna věta", - "Román", - "Bez" - ], - "correct": 0, - "expl": "Sbírka." - }, - { - "prompt": "Vzdělání maturanta?", - "options": [ - "Historie 1848, satira", - "Jen biologie", - "Bez", - "Sport" - ], - "correct": 0, - "expl": "Interdisciplinární." - }, - { - "prompt": "Havlíček smrt?", - "options": [ - "Tuberkulóza / vyčerpání", - "Poprava elegií", - "2000", - "Neumírá" - ], - "correct": 0, - "expl": "Tragický konec autora." - }, - { - "prompt": "K čemu Havlíček Tyrolské elegie využívá?", - "options": [ - "K satirické a osobní reflexi exilu, politiky i národní situace", - "K popisu rybaření", - "K návodu na zeměměřičství", - "K psaní detektivky" - ], - "correct": 0, - "expl": "Elegie jsou politicko-lyrickou zbraní v době cenzury." - }, - { - "prompt": "Jaký význam má Brixen / Tyrolsko v kontextu sbírky?", - "options": [ - "Místo Havlíčkova vyhnanství, odkud píše s nadhledem na domov", - "Fiktivní planeta", - "Sídlo Gatsbyho", - "Lokalita bez souvislosti s autorem" - ], - "correct": 0, - "expl": "Autobiografický rámec vysvětluje název i tón elegií." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Revolution 1848 je potlačena", - "Havlíček v exile / Tyrolsku", - "Píše ironické elegie", - "Satirizuje Habsburky a reakci", - "Oslovuje český národ", - "Elegie jako zbraň publicisty" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: porážka revoluce → exil → satirické elegie → kritika moci → národní apel → literární odkaz." - ] -} diff --git a/data/cetba/valka-s-mloky.json b/data/cetba/valka-s-mloky.json deleted file mode 100644 index 88e0588..0000000 --- a/data/cetba/valka-s-mloky.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Karel Čapek (1890–1938)", - "Žánr: antiutopická satira / novela", - "Poprvé vydáno: 1936", - "Děj: svět a obchod s mloky (salamany)", - "Forma: koláž – články, vědecké zprávy, dialogy" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Inteligentní mloci na Tahiti – obchodní zázrak.", - "Civilizace mloky roste – hrozba pro lidstvo.", - "Satira fašismu, kapitalismu, militarismu.", - "Přímá paralela s hitlerovským Německem.", - "Čapek varuje před lidskou chamtivostí.", - "Konec – válka s mloky, jaderná hrozba." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Pan Bondy – podnikatel s mloky.", - "Captain van Toch – objevitel.", - "Mloci – inteligentní, organizovaní.", - "Vědci, politici – krátkozrací.", - "Narrator / kolážní hlasy.", - "Lidstvo jako sebevrah." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Salamandři / mloci – alegorie totalitního národa.", - "Koláž – montáž různých stylů.", - "Satira – groteskní eskalace.", - "Fašismus – uniformy, mluví, armáda mloků.", - "Ekonomie – mloci jako zboží a vojáci.", - "Varování před zneužitím vědy." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Válku s mloky?", - "options": [ - "Hašek", - "Karel Čapek", - "Orwell", - "Vančura" - ], - "correct": 1, - "expl": "Čapek 1936." - }, - { - "prompt": "Co jsou mloci v knize?", - "options": [ - "Inteligentní obojživelníci", - "Lidé", - "Roboti", - "Ptáci" - ], - "correct": 0, - "expl": "Salamandři s vědomím." - }, - { - "prompt": "Kdo objeví mloky?", - "options": [ - "Captain van Toch", - "Gatsby", - "Svejk", - "Winston" - ], - "correct": 0, - "expl": "Tichomořský objev." - }, - { - "prompt": "Bondy?", - "options": [ - "Podnikatel znezužívající mloky", - "Kněz", - "Němec", - "Dítě" - ], - "correct": 0, - "expl": "Kapitalista." - }, - { - "prompt": "Žánr?", - "options": [ - "Antiutopická satira", - "Realistická vesnická novela", - "Lyrika", - "Historický román" - ], - "correct": 0, - "expl": "Čapkova satira." - }, - { - "prompt": "Forma?", - "options": [ - "Koláž – různé texty a styly", - "Jeden deník", - "Drama", - "Epos" - ], - "correct": 0, - "expl": "Montáž." - }, - { - "prompt": "Satira míří na?", - "options": [ - "Fašismus, militarismus, chamtivost", - "Jen rybaření", - "Lásku", - "Bez" - ], - "correct": 0, - "expl": "Politický subtext." - }, - { - "prompt": "Mloci se organizují?", - "options": [ - "Ano – stát, armáda", - "Ne", - "Jen jako domácí mazlíčci", - "Umírají hned" - ], - "correct": 0, - "expl": "Eskalace." - }, - { - "prompt": "Paralela s historií?", - "options": [ - "Nacistické Německo 30. let", - "Antika", - "2000", - "Bez" - ], - "correct": 0, - "expl": "Čapek varoval." - }, - { - "prompt": "Rok vydání?", - "options": [ - "1936", - "1949", - "1890", - "2005" - ], - "correct": 0, - "expl": "Před 2. sv. válkou." - }, - { - "prompt": "Jak končí?", - "options": [ - "Válka lidstva s mloky, hrozba zničení", - "Svatba", - "Mloci jako pets", - "Emigrace" - ], - "correct": 0, - "expl": "Apokalypsa." - }, - { - "prompt": "Čapek jiné?", - "options": [ - "R.U.R., Krakatit", - "Gatsby", - "Kytice", - "Saturnin" - ], - "correct": 0, - "expl": "Sci-fi a satira." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Satira", - "Varování", - "Koláž", - "Bezmyšlenkovitá pohádka bez politiky" - ], - "correct": 3, - "expl": "Politická alegorie." - }, - { - "prompt": "Mloci mluví?", - "options": [ - "Ano – jazyk, ideologie", - "Ne", - "Jen pes", - "Latině" - ], - "correct": 0, - "expl": "Inteligence." - }, - { - "prompt": "Ekonomika?", - "options": [ - "Obchod s mloky jako zbožím", - "Bez", - "Socialismus hotový", - "Bez peněz" - ], - "correct": 0, - "expl": "Kapitalismus." - }, - { - "prompt": "Maturita?", - "options": [ - "Satira, forma, kontext 30. let", - "Bez", - "Jen biologie mloků", - "Mapa" - ], - "correct": 0, - "expl": "Česká literatura." - }, - { - "prompt": "Tón?", - "options": [ - "Groteskní, varovný", - "Idyla", - "Bez humoru", - "Pure romance" - ], - "correct": 0, - "expl": "Černý humor." - }, - { - "prompt": "Věda?", - "options": [ - "Zneužita pro zisk", - "Chválena bez rizika", - "Ne", - "Zakázána" - ], - "correct": 0, - "expl": "Kritika." - }, - { - "prompt": "Lidstvo?", - "options": [ - "Krátkozraké, sebedestruktivní", - "Moudré", - "Neexistuje", - "Vždy vítězí" - ], - "correct": 0, - "expl": "Pesimismus." - }, - { - "prompt": "Tichomoří?", - "options": [ - "Počátek děje", - "Praha", - "Siberie", - "Měsíc" - ], - "correct": 0, - "expl": "Tahiti." - }, - { - "prompt": "Uniformy mloků?", - "options": [ - "Parodie fašismu", - "Ne", - "Bez", - "Sport" - ], - "correct": 0, - "expl": "Vizuální satira." - }, - { - "prompt": "Čapek smrt?", - "options": [ - "1938 před okupací", - "2000", - "1950", - "1890" - ], - "correct": 0, - "expl": "Autor nezažil válku." - }, - { - "prompt": "Kolážní efekt?", - "options": [ - "Ironie z různých perspektiv", - "Chaos bez smyslu", - "Bez", - "Jen báseň" - ], - "correct": 0, - "expl": "Forma = obsah." - }, - { - "prompt": "Brother Čapek?", - "options": [ - "Josef – umělec", - "Neexistuje", - "Shakespeare", - "Hitler" - ], - "correct": 0, - "expl": "Rodina Čapků." - }, - { - "prompt": "Varování?", - "options": [ - "Před totalitou a obchodem se zbraněmi", - "Před mloky v akváriu", - "Bez", - "Před školou" - ], - "correct": 0, - "expl": "Politické." - }, - { - "prompt": "Překlad?", - "options": [ - "Originál česky", - "Anglicky jen", - "Bez", - "Němec" - ], - "correct": 0, - "expl": "Český autor." - }, - { - "prompt": "Mloci vs R.U.R.?", - "options": [ - "Obě alegorie – jiný motiv", - "Totéž", - "Bez", - "R.U.R. o mlocích" - ], - "correct": 0, - "expl": "Čapkovo sci-fi." - }, - { - "prompt": "Čtenář 1936?", - "options": [ - "Chápal narážky na Evropu", - "Bez kontextu vždy", - "Děti", - "Bez" - ], - "correct": 0, - "expl": "Aktuální satira." - }, - { - "prompt": "Závěrečná válka?", - "options": [ - "Lidstvo v ohrožení", - "Mloci prohrají bez boje", - "Mír", - "Svatba" - ], - "correct": 0, - "expl": "Katastrofa." - }, - { - "prompt": "Hlavní myšlenka?", - "options": [ - "Lidská chamtivost zbrojí protivníka", - "Miluj mloky", - "Bez", - "Sport" - ], - "correct": 0, - "expl": "Etické varování." - }, - { - "prompt": "Kdo je Chief Salamander?", - "options": [ - "Vůdce mloků, který mluví jménem rostoucí moci", - "Kapitán van Toch", - "Pan Povondra", - "Gatsby" - ], - "correct": 0, - "expl": "Salamander reprezentuje organizovanou sílu zneužitých mloků." - }, - { - "prompt": "Proč je montážní forma pro Válku s mloky typická?", - "options": [ - "Napodobuje tisk a dokumenty – satira působí jako zpráva z reality", - "Je to náhodný experiment bez smyslu", - "Nahrazuje děj úplně", - "Patří k romantismu 18. st." - ], - "correct": 0, - "expl": "Koláž zpráv, reklam a projevů zesiluje alegorii i humor." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Objev inteligentních mloků", - "Obchod a chov mloků", - "Mloci budují civilizaci a armádu", - "Satira fašistoidní organizace", - "Konflikt lidstva s mloky", - "Hrozba zničení světa" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: objev → obchod → organizace mloků → militarizace → válka → apokalyptická hrozba." - ] -} diff --git a/data/cetba/velky-cirkus.json b/data/cetba/velky-cirkus.json deleted file mode 100644 index 2dd41a1..0000000 --- a/data/cetba/velky-cirkus.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Pierre Clostermann (1921–2006)", - "Žánr: válečné memoáry / autobiografická próza", - "Poprvé vydáno: 1948 (Le Grand Cirque)", - "Děj: 2. sv. válka, RAF, letecké souboje", - "Forma: ich-forma – zápisky francouzského stíhače" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Clostermann – Francouz v britském RAF.", - "Stíhací letouny Spitfire, Typhoon.", - "Intenzita vzdušných bitev nad Evropou.", - "Strach, únava, kamarádství pilotů.", - "Velký cirkus = metafora bojiště nebe.", - "Válečná autenticita bez glorifikace." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Pierre Clostermann – pilot, vypravěč.", - "Spolubojovníci RAF – mezinárodní posádka.", - "Nepřátelské letectvo – Luftwaffe.", - "Velitelé a ground crew.", - "Civilní oběti bombardování.", - "Clostermann po válce – politik, pilot." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "RAF – britské letectvo, spojenci.", - "Stíhačka – osobní zbraň i past.", - "Velký cirkus – metafora chaosu nebe.", - "Letecká válka – technika a odvaha.", - "Memoáry – subjektivní pravda.", - "Francouz v exilové armádě." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Velký cirkus?", - "options": [ - "Ryan", - "Pierre Clostermann", - "Hemingway", - "Remarque" - ], - "correct": 1, - "expl": "Francouzský pilot." - }, - { - "prompt": "O čem kniha?", - "options": [ - "Vzdušné boje 2. sv. války v RAF", - "Cirkus artistů", - "Gatsby", - "Mloci" - ], - "correct": 0, - "expl": "Letectvo." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Clostermann jako pilot", - "Němec", - "Dítě", - "Rybář" - ], - "correct": 0, - "expl": "Ich-forma." - }, - { - "prompt": "Velký cirkus znamená?", - "options": [ - "Metafora leteckého bojiště", - "Skutečný cirkus", - "Škola", - "Moře" - ], - "correct": 0, - "expl": "Chaos nebe." - }, - { - "prompt": "Kde slouží?", - "options": [ - "RAF – britské letectvo", - "Luftwaffe", - "Československé", - "Nikde" - ], - "correct": 0, - "expl": "Francouz u Spojenců." - }, - { - "prompt": "Letadla?", - "options": [ - "Spitfire, Typhoon aj.", - "Bez letadel", - "Jen balóny", - "Rakety" - ], - "correct": 0, - "expl": "Stíhačky." - }, - { - "prompt": "Žánr?", - "options": [ - "Válečné memoáry", - "Pohádka", - "Lyrika", - "Detektivka" - ], - "correct": 0, - "expl": "Autobiografická próza." - }, - { - "prompt": "Rok vydání?", - "options": [ - "1948", - "1936", - "2000", - "1890" - ], - "correct": 0, - "expl": "Po válce." - }, - { - "prompt": "Tón?", - "options": [ - "Autentický, napínavý, bez patosu", - "Pure komedie", - "Sci-fi", - "Bez" - ], - "correct": 0, - "expl": "Realismus." - }, - { - "prompt": "Clostermann národnost?", - "options": [ - "Francouz", - "Čech", - "Němec", - "Rus" - ], - "correct": 0, - "expl": "Free French." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Letectvo", - "Válka", - "Memoáry", - "Milostný román Gatsby" - ], - "correct": 3, - "expl": "Jiné dílo." - }, - { - "prompt": "Strach pilotů?", - "options": [ - "Ano, součást textu", - "Ne", - "Jen radost", - "Bez" - ], - "correct": 0, - "expl": "Psychologie." - }, - { - "prompt": "Kamarádství?", - "options": [ - "Mezi piloty RAF", - "Ne", - "Jen nepřátelé", - "Bez" - ], - "correct": 0, - "expl": "Spoluboj." - }, - { - "prompt": "Překlad Jedlička?", - "options": [ - "České vydání", - "Ne", - "Anglicky jen", - "Bez" - ], - "correct": 0, - "expl": "Maturitní seznam." - }, - { - "prompt": "Luftwaffe?", - "options": [ - "Nepřítel", - "Spojenec", - "Ne", - "Cirkus" - ], - "correct": 0, - "expl": "Německé letectvo." - }, - { - "prompt": "Glorifikace?", - "options": [ - "Spíše realistický popis", - "Bez boje", - "Pouze propaganda", - "Bez" - ], - "correct": 0, - "expl": "Memoáry." - }, - { - "prompt": "Maturita proč?", - "options": [ - "Válka z perspektivy pilota", - "Bez", - "Jen mapa", - "Komiks" - ], - "correct": 0, - "expl": "Historická próza." - }, - { - "prompt": "Technické detaily?", - "options": [ - "Letadla, mise", - "Bez", - "Jen láska", - "Kuchařka" - ], - "correct": 0, - "expl": "Autenticita." - }, - { - "prompt": "Po válce autor?", - "options": [ - "Politik, publicista", - "Zmizel", - "Dítě", - "Kněz" - ], - "correct": 0, - "expl": "Clostermann žil dlouho." - }, - { - "prompt": "Bitvy?", - "options": [ - "Nad Francií, Evropou", - "Antarktida", - "Měsíc", - "Bez" - ], - "correct": 0, - "expl": "Evropské nebe." - }, - { - "prompt": "Únava?", - "options": [ - "Fyzická i psychická", - "Ne", - "Bez", - "Jen sport" - ], - "correct": 0, - "expl": "Válka vydrží." - }, - { - "prompt": "Originální název?", - "options": [ - "Le Grand Cirque", - "1984", - "Saturnin", - "Gatsby" - ], - "correct": 0, - "expl": "Francouzsky." - }, - { - "prompt": "Spojenci?", - "options": [ - "Britové, Čechoslováci v RAF aj.", - "Nikdo", - "Jen Němci", - "Bez" - ], - "correct": 0, - "expl": "Koalice." - }, - { - "prompt": "Civilní?", - "options": [ - "Bombardování – oběti", - "Ne", - "Bez", - "Jen piloti" - ], - "correct": 0, - "expl": "Válka zasahuje vše." - }, - { - "prompt": "Forma?", - "options": [ - "Chronologické zápisky", - "Báseň", - "Drama", - "Koláž Čapek" - ], - "correct": 0, - "expl": "Memoáry." - }, - { - "prompt": "Clostermann věk války?", - "options": [ - "Mladý pilot", - "Generál 80 let", - "Dítě", - "Bez" - ], - "correct": 0, - "expl": "Mladý muž." - }, - { - "prompt": "Hlavní téma?", - "options": [ - "Odvaha a hrůza letecké války", - "Láska k moři", - "Mloci", - "Škola" - ], - "correct": 0, - "expl": "Letectvo." - }, - { - "prompt": "Čtenář?", - "options": [ - "Chápe 2. sv. válku z nebe", - "Bez", - "Jen děti", - "Bez historie" - ], - "correct": 0, - "expl": "Perspektiva." - }, - { - "prompt": "Konec války?", - "options": [ - "Vítězství Spojenců – v knize", - "Prohra RAF", - "Bez", - "2000" - ], - "correct": 0, - "expl": "Historický výsledek." - }, - { - "prompt": "Proč „cirkus“?", - "options": [ - "Akrobatické manévry, chaos soubojů", - "Klauni", - "Bez", - "Cirkus na zemi" - ], - "correct": 0, - "expl": "Metafora." - }, - { - "prompt": "Proč se kniha jmenuje Velký cirkus?", - "options": [ - "Metaforicky popisuje chaotické nebe a letecké bojiště 2. světové války", - "Je groteskní školní hra o třídní knize", - "Popisuje cirkus na Kubě", - "Jde o sbírku tyrolských elegií" - ], - "correct": 0, - "expl": "Titul vystihuje víření soubojů, nebezpečí a napětí ve vzduchu." - }, - { - "prompt": "Jak Clostermann líčí válečné zážitky?", - "options": [ - "Autenticky, bez patosu – strach, únava i odvaha pilotů", - "Jako pohádku bez nebezpečí", - "Jen statisticky bez emocí", - "Jako satiru na mloky" - ], - "correct": 0, - "expl": "Memoáry zachycují subjektivní pravdu stíhače v RAF." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Clostermann vstupuje do RAF", - "Výcvik a první mise", - "Intenzivní vzdušné souboje", - "Ztráty kamarádů a únava", - "Gradace Velkého cirkusu", - "Válka končí – bilance pilotova života" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: nástup RAF → výcvik → souboje → ztráty → vrchol nebe → konec války." - ] -} diff --git a/data/cetba/velky-gatsby.json b/data/cetba/velky-gatsby.json deleted file mode 100644 index 9e2f08a..0000000 --- a/data/cetba/velky-gatsby.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: F. Scott Fitzgerald (1896–1940)", - "Žánr: modernistický román", - "Poprvé vydáno: 1925", - "Děj: Long Island, New York, „roaring twenties“", - "Vyprávění: ich-forma Nicka Carrawaye" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Americký sen – bohatství, láska, iluze.", - "Jay Gatsby – tajemný milionář, párty.", - "Daisy Buchanan – dávná láska, vdaná za Toma.", - "Zelené světlo – symbol touhy.", - "Tragédie – Myrtle, Wilson, Gatsbyho smrt.", - "Kritika prázdného luxusu jazz age." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Jay Gatsby (James Gatz) – hlavní hrdina.", - "Nick Carraway – vypravěč, soused.", - "Daisy Buchanan – milovaná žena.", - "Tom Buchanan – bohatý, arogantní manžel.", - "Jordan Baker – golfistka, Nickova přítelkyně.", - "Myrtle a George Wilson – tragické vedlejší postavy." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Americký sen – slib úspěchu.", - "Zelené světlo na konci Daisyina doku.", - "Nové vs. staré peníze – East/West Egg.", - "Párty – maska osamělosti.", - "Iluze – Gatsby miluje idealizovanou Daisy.", - "Oko doktora T. J. Eckleburga – symbol." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Velkého Gatsbyho?", - "options": [ - "Hemingway", - "F. Scott Fitzgerald", - "Styron", - "Keyes" - ], - "correct": 1, - "expl": "Fitzgerald 1925." - }, - { - "prompt": "Vypravěč?", - "options": [ - "Gatsby", - "Nick Carraway", - "Tom", - "Daisy" - ], - "correct": 1, - "expl": "Nick je svědek." - }, - { - "prompt": "Gatsby miluje?", - "options": [ - "Jordan", - "Daisy Buchanan", - "Myrtle", - "Nick" - ], - "correct": 1, - "expl": "Dávná láska." - }, - { - "prompt": "Daisy je?", - "options": [ - "Vdaná za Toma Buchanan", - "Gatsbyho manželka", - "Sestra Nick", - "Učitelka" - ], - "correct": 0, - "expl": "Manželka Toma." - }, - { - "prompt": "Zelené světlo?", - "options": [ - "Symbol touhy po Daisy / budoucnosti", - "Reklama", - "Vlak", - "Bez" - ], - "correct": 0, - "expl": "Na konci doku." - }, - { - "prompt": "East Egg vs West Egg?", - "options": [ - "Staré vs. nové bohatství", - "Stejné", - "Evropa", - "Bez" - ], - "correct": 0, - "expl": "Třídní rozdíl." - }, - { - "prompt": "Gatsby bohatství?", - "options": [ - "Pašování / nejasný původ", - "Dědictví Toma", - "Státní plat", - "Bez" - ], - "correct": 0, - "expl": "Tajemství." - }, - { - "prompt": "Párty u Gatsbyho?", - "options": [ - "Velkolepé, ale osamělé", - "Ne", - "Malé", - "Bez" - ], - "correct": 0, - "expl": "Maska." - }, - { - "prompt": "Myrtle?", - "options": [ - "Milenka Toma, umírá under car", - "Manželka Gatsby", - "Nick", - "Bez" - ], - "correct": 0, - "expl": "Tragédie." - }, - { - "prompt": "Kdo zabije Gatsbyho?", - "options": [ - "George Wilson", - "Tom", - "Nick", - "Daisy" - ], - "correct": 0, - "expl": "Myrtlein manžel." - }, - { - "prompt": "Jak Gatsby zemře?", - "options": [ - "V bazénu – střela", - "Stářím", - "Moře", - "Válka" - ], - "correct": 0, - "expl": "Tragický konec." - }, - { - "prompt": "Nick na konci?", - "options": [ - "Odejde zpět na Midwest", - "S Daisy", - "Král", - "Bez" - ], - "correct": 0, - "expl": "Disiluze." - }, - { - "prompt": "Americký sen?", - "options": [ - "Kritika – iluze úspěchu", - "Bez tématu", - "Sci-fi", - "Bez" - ], - "correct": 0, - "expl": "Jádro románu." - }, - { - "prompt": "Tom Buchanan?", - "options": [ - "Arogantní boháč", - "Chudý", - "Kněz", - "Pilot" - ], - "correct": 0, - "expl": "Antagonista morálky." - }, - { - "prompt": "Jordan?", - "options": [ - "Golfistka, vztah s Nickem", - "Gatsbyho sestra", - "Wilson", - "Bez" - ], - "correct": 0, - "expl": "Vedlejší linie." - }, - { - "prompt": "Valley of Ashes?", - "options": [ - "Průmyslová chudoba mezi Eggs", - "Raj", - "Moře", - "Bez" - ], - "correct": 0, - "expl": "Kontrast." - }, - { - "prompt": "Eckleburg oči?", - "options": [ - "Billboard – symbol", - "Bez", - "Gatsby", - "Daisy" - ], - "correct": 0, - "expl": "Moderní symbol." - }, - { - "prompt": "Gatsby původní jméno?", - "options": [ - "James Gatz", - "Nick", - "Tom", - "Jay only" - ], - "correct": 0, - "expl": "Přetvoření identity." - }, - { - "prompt": "Daisy a Gatsby minulost?", - "options": [ - "Milovali se před válkou", - "Ne", - "Sourozenci", - "Bez" - ], - "correct": 0, - "expl": "Louisville." - }, - { - "prompt": "Auto accident?", - "options": [ - "Myrtle killed – zvrat", - "Bez", - "Gatsby wins", - "Bez" - ], - "correct": 0, - "expl": "Klíčová scéna." - }, - { - "prompt": "Kdo řídí auto?", - "options": [ - "Daisy (debata) – Gatsby chrání", - "Wilson", - "Nick", - "Bez" - ], - "correct": 0, - "expl": "Gatsby přebírá vinu." - }, - { - "prompt": "Žánr?", - "options": [ - "Modernistický román", - "Epos", - "Báseň", - "Drama" - ], - "correct": 0, - "expl": "Literature 20. st." - }, - { - "prompt": "Rok?", - "options": [ - "1925", - "1949", - "2000", - "1890" - ], - "correct": 0, - "expl": "Jazz age." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Kritika snu", - "Láska", - "Tragedie", - "Kosmické mloky" - ], - "correct": 3, - "expl": "Realistický USA." - }, - { - "prompt": "Nick a Gatsby?", - "options": [ - "Přátelství, obdiv", - "Nepřátelé", - "Bratři", - "Bez" - ], - "correct": 0, - "expl": "Nick vypráví." - }, - { - "prompt": "Gatsbyho pohřeb?", - "options": [ - "Skoro nikdo nepřijde", - "Národní slavnost", - "Bez", - "Tom only" - ], - "correct": 0, - "expl": "Osamělost." - }, - { - "prompt": "Překlad Dorůžka?", - "options": [ - "České vydání", - "Bez", - "Anglicky jen", - "Bez" - ], - "correct": 0, - "expl": "Maturita." - }, - { - "prompt": "Tón?", - "options": [ - "Elegický, kritický", - "Pure comedy", - "Horor", - "Bez" - ], - "correct": 0, - "expl": "Tragédie snu." - }, - { - "prompt": "Daisy hlas?", - "options": [ - "Symbol půvabu a prázdnoty", - "Bez", - "Sci-fi", - "Bez" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Poselství?", - "options": [ - "Sen může být iluze ničící", - "Vždy vyhraj", - "Bez", - "Sport" - ], - "correct": 0, - "expl": "Fitzgeraldova kritika." - }, - { - "prompt": "Co symbolizují oči doktora T. J. Eckleburga?", - "options": [ - "Prázdný moralismus reklamní civilizace / „Bůh“ údolí popela", - "Gatsbyho majetek", - "Nickovu rodinu", - "Daisyin hlas" - ], - "correct": 0, - "expl": "Billboard je jedním z nejsilnějších obrazů románu." - }, - { - "prompt": "Proč Gatsby na konci zůstává osamělý i při velkých párty?", - "options": [ - "Hosté využívají lesk, ne jeho – touží jen po Daisy", - "Protože je neznámý", - "Protože je z chudiny", - "Protože je v exilu" - ], - "correct": 0, - "expl": "Párty maskují osamělost muže žijícího v iluzi minulosti." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Nick přijede na Long Island", - "Pozná Gatsbyho a párty", - "Gatsby chce Daisy zpět", - "Aféra, napětí s Tomem", - "Myrtleina smrt autem", - "Wilson zabije Gatsbyho – Nick odchází" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: Nick → Gatsby → Daisy → konflikt → nehoda → smrt Gatsbyho." - ] -} diff --git a/data/cetba/zabijak.json b/data/cetba/zabijak.json deleted file mode 100644 index 6744796..0000000 --- a/data/cetba/zabijak.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Émile Zola (1840–1902)", - "Žánr: naturalistický román", - "Poprvé vydáno: 1870", - "Děj: Les Halles, pařížská tržnice, maso", - "Vyprávění: er-forma, determinismus, sociální prostředí" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Florent – bývalý učitel, údajný vrah.", - "Tržnice Halles – pach, maso, dělníci.", - "Florent vs. Lisa – tchyně, konflikt.", - "Politické sny – revoluce, represe.", - "Naturalismus – prostředí formuje charakter.", - "Titul Zabiják – Florentova minulost." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Florent – hlavní hrdina, „zabiják“.", - "Lisa Quenu – tchyně, majitelka.", - "Quenu – řezník, manžel.", - "La Normande, Les Halles dělníci.", - "Police, revolucionáři.", - "Paříž – městský organismus." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Naturalismus – dědictvost a prostředí.", - "Halles – symbol kapitalismu a těla.", - "Maso – metafora brutality.", - "Florent – sny o spravedlnosti.", - "Determinismus – osud z ložnice vraždy.", - "Zola – dokumentární detail trhu." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Zabijáka?", - "options": [ - "Hugo", - "Émile Zola", - "Flaubert", - "Styron" - ], - "correct": 1, - "expl": "Zola 1870." - }, - { - "prompt": "Kde děj?", - "options": [ - "Paříž – tržnice Les Halles", - "Praha", - "Moře", - "RAF" - ], - "correct": 0, - "expl": "Masná tržnice." - }, - { - "prompt": "Florent?", - "options": [ - "Údajný vrah, bývalý učitel", - "Pilot", - "Sluha", - "Gatsby" - ], - "correct": 0, - "expl": "Titulní role." - }, - { - "prompt": "Proč zabiják?", - "options": [ - "Zabil muže v sebeobraně – odsouzen", - "Bez důvodu", - "Detektiv", - "Král" - ], - "correct": 0, - "expl": "Minulost." - }, - { - "prompt": "Lisa?", - "options": [ - "Tchyně, antagonistka", - "Manželka Florent", - "Daisy", - "Ester" - ], - "correct": 0, - "expl": "Konflikt." - }, - { - "prompt": "Quenu?", - "options": [ - "Řezník, manžel", - "Pilot", - "Učitel", - "Bez" - ], - "correct": 0, - "expl": "Rodina." - }, - { - "prompt": "Naturalismus?", - "options": [ - "Prostředí určuje osud", - "Bez", - "Sci-fi", - "Bez" - ], - "correct": 0, - "expl": "Zolův program." - }, - { - "prompt": "Halles?", - "options": [ - "Obrovská tržnice, maso, pach", - "Moře", - "Škola", - "Bez" - ], - "correct": 0, - "expl": "Prostředí." - }, - { - "prompt": "Florent sny?", - "options": [ - "Revoluce, spravedlnost", - "Bez", - "Jen láska", - "Sport" - ], - "correct": 0, - "expl": "Politika." - }, - { - "prompt": "Konflikt Florent–Lisa?", - "options": [ - "Moc v domě a na trhu", - "Bez", - "Přátelé", - "Bez" - ], - "correct": 0, - "expl": "Tlak." - }, - { - "prompt": "Jak končí Florent?", - "options": [ - "Znovu zatčen / zničen", - "Král", - "Šťastný", - "Emigrace" - ], - "correct": 0, - "expl": "Tragicky." - }, - { - "prompt": "Maso symbol?", - "options": [ - "Brutalita, kapitalismus", - "Bez", - "Láska", - "Bez" - ], - "correct": 0, - "expl": "Naturalistická metafora." - }, - { - "prompt": "Rok?", - "options": [ - "1870", - "1925", - "2000", - "1867 Tereza" - ], - "correct": 0, - "expl": "Zola." - }, - { - "prompt": "Tereza Raquin?", - "options": [ - "Jiné Zolino dílo", - "Totéž", - "Bez", - "Gatsby" - ], - "correct": 0, - "expl": "Stejný autor." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Naturalismus", - "Paříž", - "Tržnice", - "Kosmické mloky" - ], - "correct": 3, - "expl": "Jiné dílo." - }, - { - "prompt": "Dělníci Halles?", - "options": [ - "Sociální vrstva", - "Ne", - "Jen králové", - "Bez" - ], - "correct": 0, - "expl": "Realismus." - }, - { - "prompt": "Florent návrat?", - "options": [ - "Z trestu na trh", - "Z moře", - "Bez", - "RAF" - ], - "correct": 0, - "expl": "Děj." - }, - { - "prompt": "Atmosféra?", - "options": [ - "Těžká, pach, hlučnost", - "Idyla", - "Bez", - "Komedy" - ], - "correct": 0, - "expl": "Naturalismus." - }, - { - "prompt": "Maturita?", - "options": [ - "Zola, naturalismus, prostředí", - "Bez", - "Jen mapa", - "Bez" - ], - "correct": 0, - "expl": "Francouzská próza." - }, - { - "prompt": "Vyprávění?", - "options": [ - "Er-forma", - "Deník", - "Drama", - "Báseň" - ], - "correct": 0, - "expl": "Román." - }, - { - "prompt": "Lisa moc?", - "options": [ - "Manipuluje domácnost", - "Bez", - "Slabá", - "Bez" - ], - "correct": 0, - "expl": "Antagonista." - }, - { - "prompt": "Revoluce?", - "options": [ - "Florent idealista", - "Bez", - "Vždy vítězí", - "Bez" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Zola cyklus?", - "options": [ - "Rougon-Macquart", - "Bez", - "1984", - "Bez" - ], - "correct": 0, - "expl": "Součást." - }, - { - "prompt": "Překlad Kárl?", - "options": [ - "České vydání", - "Bez", - "Anglicky", - "Bez" - ], - "correct": 0, - "expl": "Maturita." - }, - { - "prompt": "Tělo / maso?", - "options": [ - "Fyziologie města", - "Bez", - "Bez tématu", - "Bez" - ], - "correct": 0, - "expl": "Detail." - }, - { - "prompt": "Florent charakter?", - "options": [ - "Snílek i outsider", - "Král", - "Bez", - "Dítě" - ], - "correct": 0, - "expl": "Psychologie." - }, - { - "prompt": "Tón?", - "options": [ - "Temný naturalismus", - "Pure comedy", - "Bez", - "Pohádka" - ], - "correct": 0, - "expl": "Zola." - }, - { - "prompt": "Trh Halles?", - "options": [ - "Srdce děje", - "Okraj", - "Bez", - "Moře" - ], - "correct": 0, - "expl": "Prostředí." - }, - { - "prompt": "Determinismus?", - "options": [ - "Vina minulosti + prostředí", - "Svoboda bez limitů", - "Bez", - "Magie" - ], - "correct": 0, - "expl": "Teorie." - }, - { - "prompt": "Titul?", - "options": [ - "Odkaz na Florentovu minulost", - "Lovec srn", - "Bez", - "Pilot" - ], - "correct": 0, - "expl": "Zabiják." - }, - { - "prompt": "Proč se Florent nazývá „zabiják“?", - "options": [ - "V minulosti zabil muže a pyká trestem odnětí svobody", - "Pracuje jako řezník na Halles", - "Je detektiv z Paříže", - "Je fiktivní hrdina Hemingwaye" - ], - "correct": 0, - "expl": "Titul vychází z Florentovy vražedné minulosti, která ho pronásleduje." - }, - { - "prompt": "Co symbolizují pařížské Halles v románu?", - "options": [ - "Kapitalistický svět masa, těla a brutality města", - "Idylickou venkovskou přírodu", - "Klášterní ticho", - "Vzdušné souboje RAF" - ], - "correct": 0, - "expl": "Tržnice je naturalistickým prostředím, které formuje postavy i atmosféru." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Florent se vrací z trestu", - "Bydlí u řezníka Quenua", - "Konflikt s Lisou na Halles", - "Politické sny a napětí", - "Florent se propadá", - "Znovu ztrácí svobodu / zničení" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: návrat → rodina → konflikt → sny → eskalace → pád Florenta." - ] -} diff --git a/data/cetba/zbabelci.json b/data/cetba/zbabelci.json deleted file mode 100644 index 6bd093d..0000000 --- a/data/cetba/zbabelci.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Josef Škvorecký (1924–2012)", - "Žánr: autobiograficky laděný román", - "Poprvé vydáno: 1958 (v exilu)", - "Děj: květen 1945, Náchodsko, konec války", - "Vyprávění: er-forma – Danny Smiřický" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Danny – gymnazista, jazz, holky, strach z války.", - "Nacisté ustupují, partyzáni, chaos osvobození.", - "Motiv zbabělosti vs. odvahy – ironie titulu.", - "Láska k jazzu a americké kultuře.", - "Škvorecký – censorship, později exil.", - "Jazyk hovorový, generační perspektiva." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Danny Smiřický – vypravěč, student.", - "Lída, Irena – dívky.", - "Němečtí vojáci, partyzáni.", - "Dannyho rodiče, učitelé.", - "Konopný – postava okolí.", - "Město Náchod – prostředí." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Květen 1945 – konec okupace.", - "Jazz – symbol svobody a identity.", - "Zbabělci – sebeironie, strach mládí.", - "Erotika a válka – kontrast.", - "Cenzura – kniha u nás později.", - "Exilový autor – svoboda slova." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Zbabělce?", - "options": [ - "Kundera", - "Josef Škvorecký", - "Hrabal", - "Otčenášek" - ], - "correct": 1, - "expl": "Škvorecký 1958." - }, - { - "prompt": "Kdo vypráví?", - "options": [ - "Danny Smiřický", - "Gatsby", - "Winston", - "Svejk" - ], - "correct": 0, - "expl": "Gymnazista." - }, - { - "prompt": "Kdy děj?", - "options": [ - "Květen 1945", - "1920", - "1989", - "1848" - ], - "correct": 0, - "expl": "Konec války." - }, - { - "prompt": "Kde?", - "options": [ - "Náchodsko", - "Long Island", - "Paříž Halles", - "Moře" - ], - "correct": 0, - "expl": "České pohraničí." - }, - { - "prompt": "Proč zbabělci?", - "options": [ - "Ironie – strach mládí v chaosu", - "Všichni hrdinové", - "Bez", - "Detektivka" - ], - "correct": 0, - "expl": "Titul." - }, - { - "prompt": "Jazz?", - "options": [ - "Dannyho vášeň, symbol svobody", - "Ne", - "Zakázáno bez významu", - "Bez" - ], - "correct": 0, - "expl": "Motiv." - }, - { - "prompt": "Škvorecký?", - "options": [ - "Později v exilu v Kanadě", - "Nikdy neodešel", - "Němec", - "Bez" - ], - "correct": 0, - "expl": "Osud autora." - }, - { - "prompt": "Cenzura?", - "options": [ - "Kniha u nás dlouho problematická", - "Bez", - "Vždy volná", - "Bez" - ], - "correct": 0, - "expl": "Normalizace." - }, - { - "prompt": "Žánr?", - "options": [ - "Autobiografický román", - "Báseň", - "Drama", - "Epos" - ], - "correct": 0, - "expl": "Próza." - }, - { - "prompt": "Danny věk?", - "options": [ - "Gymnazista – mládí", - "Starý", - "Dítě", - "Generál" - ], - "correct": 0, - "expl": "Perspektiva." - }, - { - "prompt": "Válka končí?", - "options": [ - "Chaos osvobození", - "Bez", - "1940", - "2000" - ], - "correct": 0, - "expl": "Květen." - }, - { - "prompt": "Lásky?", - "options": [ - "Lída, Irena aj.", - "Bez", - "Jen Gatsby", - "Bez" - ], - "correct": 0, - "expl": "Erotika." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Konec války", - "Jazz", - "Mládí", - "Kosmické mloky" - ], - "correct": 3, - "expl": "Jiné dílo." - }, - { - "prompt": "Tón?", - "options": [ - "Hovorový, ironický", - "Epický bez humoru", - "Bez", - "Opera" - ], - "correct": 0, - "expl": "Styl." - }, - { - "prompt": "Partyzáni?", - "options": [ - "Součást osvobození", - "Ne", - "Jen Němci", - "Bez" - ], - "correct": 0, - "expl": "Děj." - }, - { - "prompt": "Němci ustupují?", - "options": [ - "Ano", - "Ne", - "Bez", - "2000" - ], - "correct": 0, - "expl": "Květen 45." - }, - { - "prompt": "Maturita?", - "options": [ - "Generace 45, jazz, Škvorecký", - "Bez", - "Mapa", - "Bez" - ], - "correct": 0, - "expl": "Česká próza." - }, - { - "prompt": "Emigrace autora?", - "options": [ - "Po 68", - "Nikdy", - "1890", - "Bez" - ], - "correct": 0, - "expl": "Historie." - }, - { - "prompt": "Danny strach?", - "options": [ - "Válka, sex, budoucnost", - "Bez", - "Jen jazz", - "Bez" - ], - "correct": 0, - "expl": "Psychologie." - }, - { - "prompt": "Americká kultura?", - "options": [ - "Idealizace", - "Ne", - "Zakázáno bez motivu", - "Bez" - ], - "correct": 0, - "expl": "Jazz." - }, - { - "prompt": "Škvorecký jiné?", - "options": [ - "Mirákl, Tankový prapor", - "Gatsby", - "Bez", - "Wolker" - ], - "correct": 0, - "expl": "Tvorba." - }, - { - "prompt": "Vyprávění?", - "options": [ - "Er-forma", - "Deník", - "Drama", - "Báseň" - ], - "correct": 0, - "expl": "Román." - }, - { - "prompt": "Ironie?", - "options": [ - "Zbabělci – self-deprecation", - "Bez", - "Bez humoru", - "Bez" - ], - "correct": 0, - "expl": "Titul." - }, - { - "prompt": "Publikum?", - "options": [ - "Mladí i dospělí", - "Bez", - "Jen děti", - "Bez" - ], - "correct": 0, - "expl": "Generační." - }, - { - "prompt": "Okupace?", - "options": [ - "Končí – radost i chaos", - "Začíná", - "Bez", - "2000" - ], - "correct": 0, - "expl": "Květen." - }, - { - "prompt": "Jazyk?", - "options": [ - "Hovorová čeština", - "Angličtina", - "Bez", - "Latině" - ], - "correct": 0, - "expl": "Styl." - }, - { - "prompt": "Hrdinství?", - "options": [ - "Problematizováno", - "Jasné", - "Bez", - "Bez" - ], - "correct": 0, - "expl": "Antihero." - }, - { - "prompt": "Rok vydání?", - "options": [ - "1958", - "1945", - "2000", - "1869" - ], - "correct": 0, - "expl": "Exil." - }, - { - "prompt": "Náchod?", - "options": [ - "Reálné město", - "Fikce", - "USA", - "Bez" - ], - "correct": 0, - "expl": "Prostředí." - }, - { - "prompt": "Poselství?", - "options": [ - "Mladí v historickém zlomu", - "Bez", - "Válka je hra", - "Bez" - ], - "correct": 0, - "expl": "Generační novela." - }, - { - "prompt": "Jak Danny reaguje na konec války a příchod Sovětů?", - "options": [ - "S mísením naděje, strachu a ironie – generace na rozhraní", - "Bez emocí", - "Okamžitě emigruje", - "Stává se rybářem" - ], - "correct": 0, - "expl": "Román zachycuje psychiku mládí v květnu 1945." - }, - { - "prompt": "Proč je jazz ve Zbabělcích důležitý?", - "options": [ - "Symbol svobody, identity a jiného světa než ideologie", - "Jen kulisa bez významu", - "Zakázaný bez zmínky", - "Nahrazuje děj" - ], - "correct": 0, - "expl": "Dannyho vášeň pro jazz kontrastuje s politickým tlakem." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Danny žije okupaci a jazz", - "Květen 1945 – chaos", - "Osvobození a strach", - "Lásky a party", - "Setkání s realitou války", - "Závěr – mládí v nové době" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: okupace → květen 45 → osvobození → vztahy → zrání → nová éra." - ] -} diff --git a/data/cetba/zert.json b/data/cetba/zert.json deleted file mode 100644 index d13a35b..0000000 --- a/data/cetba/zert.json +++ /dev/null @@ -1,421 +0,0 @@ -{ - "notes": [ - { - "title": "O knize", - "icon": "book", - "lines": [ - "Autor: Milan Kundera (1929–2023)", - "Žánr: philosophický román", - "Poprvé vydáno: 1967", - "Děj: Československo 50.–60. let, pomsta za žert", - "Vyprávění: er-forma, retrospektivy, komentáře autora" - ] - }, - { - "title": "Doba a svět", - "icon": "globe", - "lines": [ - "Ludvík Jahn – student, pošle žertovný dopis.", - "Poslanec Pavel Zeman – trest, vyhoštění z KSČ.", - "Pomsta na Zemanově milence Markétě.", - "Téma historie, osudu, ironie.", - "Kundera – formy románu, existenciální otázky.", - "Normalizace – kniha rezonovala i později." - ] - }, - { - "title": "Postavy", - "icon": "people", - "lines": [ - "Ludvík Jahn – hlavní hrdina.", - "Markéta – Zemanova milenka, pomsta.", - "Pavel Zeman – poslanec, oběť žertu.", - "Kostra, Helena – další postavy.", - "Autorův komentář – rovina vypravěče.", - "Studenti, politická komise." - ] - }, - { - "title": "Klíčové pojmy", - "icon": "bulb", - "lines": [ - "Žert – drobnost s fatálními následky.", - "Komunistický režim 50. let.", - "Pomsta – kruhové dějiny.", - "Láska a moc.", - "Ironie osudu – Ludvík nevyhrává.", - "Kundera – román jako dialog s čtenářem." - ] - } - ], - "quiz": [ - { - "prompt": "Kdo napsal Žert?", - "options": [ - "Škvorecký", - "Milan Kundera", - "Havel", - "Čapek" - ], - "correct": 1, - "expl": "Kundera 1967." - }, - { - "prompt": "Co Ludvík udělá?", - "options": [ - "Pošle žertovný postcard poslanci", - "Zavraždí", - "Uteče", - "Bez" - ], - "correct": 0, - "expl": "Trigger děje." - }, - { - "prompt": "Důsledek žertu?", - "options": [ - "Vyhoštění z KSČ, gulag práce", - "Nobelovka", - "Svatba", - "Bez" - ], - "correct": 0, - "expl": "Režim." - }, - { - "prompt": "Pomsta?", - "options": [ - "Na Zemanově milence Markétě", - "Na Tomovi", - "Bez", - "Na mlokovi" - ], - "correct": 0, - "expl": "Plán Ludvíka." - }, - { - "prompt": "Kdy děj?", - "options": [ - "50.–60. léta ČSSR", - "1945", - "1984", - "1890" - ], - "correct": 0, - "expl": "Socialismus." - }, - { - "prompt": "Zeman?", - "options": [ - "Poslanec, oběť", - "Pilot", - "Sluha", - "Gatsby" - ], - "correct": 0, - "expl": "Politik." - }, - { - "prompt": "Markéta?", - "options": [ - "Milenka, nástroj pomsty", - "Sestra", - "Bez", - "Němka" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Jak pomsta dopadne?", - "options": [ - "Ludvík neuspěje – ironie", - "Dokonalá", - "Bez", - "Smrt všech" - ], - "correct": 0, - "expl": "Kunderova ironie." - }, - { - "prompt": "Kundera styl?", - "options": [ - "Filosofické odbočky, struktura", - "Bez", - "Jen báseň", - "Bez" - ], - "correct": 0, - "expl": "Moderní román." - }, - { - "prompt": "Téma historie?", - "options": [ - "Osobní osud vs. ideologie", - "Bez", - "Sci-fi", - "Bez" - ], - "correct": 0, - "expl": "Jádro." - }, - { - "prompt": "Rok vydání?", - "options": [ - "1967", - "1958", - "2000", - "1949" - ], - "correct": 0, - "expl": "Před 68." - }, - { - "prompt": "Co NENÍ?", - "options": [ - "Politika", - "Pomsta", - "Ironie", - "Kosmické mloky" - ], - "correct": 3, - "expl": "Jiné dílo." - }, - { - "prompt": "Ludvík po trestu?", - "options": [ - "Manuální práce, outsider", - "Ministr", - "Bez", - "Král" - ], - "correct": 0, - "expl": "Stigma." - }, - { - "prompt": "Film?", - "options": [ - "1969 Jaromil Jireš", - "Bez", - "Gatsby", - "Bez" - ], - "correct": 0, - "expl": "Nová vlna." - }, - { - "prompt": "Kostra?", - "options": [ - "Přítel Ludvíka", - "Bez", - "Němec", - "Bez" - ], - "correct": 0, - "expl": "Postava." - }, - { - "prompt": "Helena?", - "options": [ - "Manželka Ludvíka", - "Bez", - "Daisy", - "Bez" - ], - "correct": 0, - "expl": "Rodina." - }, - { - "prompt": "Maturita?", - "options": [ - "Struktura, témata, kontext 50. let", - "Bez", - "Mapa", - "Bez" - ], - "correct": 0, - "expl": "Česká próza." - }, - { - "prompt": "Ironie?", - "options": [ - "Pomsta se obrátí proti pomstiteli", - "Bez", - "Bez humoru", - "Bez" - ], - "correct": 0, - "expl": "Závěr." - }, - { - "prompt": "Autor komentář?", - "options": [ - "Kundera přerušuje děj", - "Ne", - "Bez", - "Shakespeare" - ], - "correct": 0, - "expl": "Forma." - }, - { - "prompt": "KSČ?", - "options": [ - "Politická moc", - "Bez", - "Jazz klub", - "Bez" - ], - "correct": 0, - "expl": "Režim." - }, - { - "prompt": "Existenciální?", - "options": [ - "Smysl, náhoda, osud", - "Bez", - "Jen sport", - "Bez" - ], - "correct": 0, - "expl": "Filosofie." - }, - { - "prompt": "Kundera později?", - "options": [ - "Emigrace do Francie", - "Nikdy", - "1890", - "Bez" - ], - "correct": 0, - "expl": "Autor." - }, - { - "prompt": "Žert definice?", - "options": [ - "Drobnost s velkými důsledky", - "Válka", - "Bez", - "Láska only" - ], - "correct": 0, - "expl": "Titul." - }, - { - "prompt": "Markéta a Ludvík?", - "options": [ - "Aféra jako pomsta", - "Sourozenci", - "Bez", - "Bez" - ], - "correct": 0, - "expl": "Děj." - }, - { - "prompt": "Tón?", - "options": [ - "Ironický, vážný", - "Pure comedy", - "Bez", - "Pohádka" - ], - "correct": 0, - "expl": "Kundera." - }, - { - "prompt": "Struktura?", - "options": [ - "Retrospektivy, kapitoly", - "Jeden den", - "Bez", - "Báseň" - ], - "correct": 0, - "expl": "Román." - }, - { - "prompt": "Normalizace?", - "options": [ - "Kniha rezonovala", - "Bez", - "2000", - "Bez" - ], - "correct": 0, - "expl": "Kontext." - }, - { - "prompt": "Láska a moc?", - "options": [ - "Propleteno", - "Bez", - "Bez tématu", - "Bez" - ], - "correct": 0, - "expl": "Téma." - }, - { - "prompt": "Vypravěč?", - "options": [ - "Ludvík + autor", - "Nick", - "Bez", - "Bez" - ], - "correct": 0, - "expl": "Perspektivy." - }, - { - "prompt": "Poselství?", - "options": [ - "Historie ničí i drobné činy", - "Bez", - "Vždy vyhraj", - "Bez" - ], - "correct": 0, - "expl": "Kunderova myšlenka." - }, - { - "prompt": "Kdo je Kostka v Žertu?", - "options": [ - "Křesťanský intelektuál, s nímž Ludvík debatuje o smyslu", - "Velitel SNB", - "Rybář Santiago", - "Gatsby" - ], - "correct": 0, - "expl": "Kostka reprezentuje jinou etickou perspektivu než režim." - }, - { - "prompt": "Jak dopadne Ludvíkova pomsta skrze Helenu?", - "options": [ - "Neplní očekávání – ironie a selhání plánu", - "Dokonalý triumf", - "Helena zatčena hned", - "Ludvík emigruje bez důsledků" - ], - "correct": 0, - "expl": "Kundera ukazuje, že minulost nelze jednoduše „opravit“ pomstou." - } - ], - "plot": [ - { - "prompt": "Přetáhněte části příběhu do správného pořadí:", - "words": [ - "Ludvík pošle žertovný dopis", - "Trest – vyhoštění z strany, práce", - "Léta plynou – hořkost", - "Plán pomsty přes Markétu", - "Aféra a zklamání", - "Pomsta se nezdaří – ironický konec" - ] - } - ], - "plotMeaning": [ - "Správné pořadí: žert → trest → léta → plán pomsty → Markéta → neúspěch pomsty." - ] -} diff --git a/data/changelog.txt b/data/changelog.txt deleted file mode 100644 index 3cd6823..0000000 --- a/data/changelog.txt +++ /dev/null @@ -1,161 +0,0 @@ -# User-facing notes, newest first. Copied next to style.css in every -# package and folded into content.json for Android and iOS. -# After an update the home screen shows the latest blocks until dismissed. -# -# --- YYYY-MM-DD -# cs: bullet -# en: bullet - ---- 2026-10-07 -cs: Sítě a technické vybavení: doplněné 2. až 4. ročníky, v každém 8 lekcí -cs: Výklad a kvíz od VLAN a sestavení počítače po maturitu -en: Networks and hardware: years 2 to 4 are filled in, eight lessons each -en: Slides and a quiz, from VLANs and PC assembly through to the exam - ---- 2026-10-07 -cs: Němčina: čtyři ročníky, 24 lekcí s poslechem, čtením a psaním -cs: Učebnice Neue Freunde zůstává, k ní přibyl kurz od A1 k B1 -en: German: four years, 24 lessons with listening, reading and writing -en: The Neue Freunde textbook stays, and a course from A1 to B1 sits beside it - ---- 2026-10-07 -cs: Angličtina: čtyři ročníky, 32 lekcí podle osnov gymnázia -cs: Poslech, čtení, psaní, doplňování, kvízy a testy od A2 k maturitě -en: English: four years, 32 lessons from the gymnasium syllabus -en: Listening, reading, writing, gap-fill, quizzes and tests from A2 to the exam - ---- 2026-10-06 -cs: Matematika: opakování základní školy a čtyři ročníky, 40 lekcí -cs: Příklady se píšou a kontrolují, u geometrie se rýsuje na mřížku -en: Mathematics: elementary review and four years, 40 lessons -en: Examples are typed and checked, and some geometry is drawn on a grid - ---- 2026-10-06 -cs: Fyzika: čtyři ročníky, 32 lekcí podle osnov středních škol -cs: Od mechaniky přes teplo a elektřinu až po optiku, jádro a astrofyziku -en: Physics: four years, 32 lessons from the secondary-school syllabus -en: From mechanics through heat and electricity to optics, the nucleus and astrophysics - ---- 2026-10-06 -cs: Základy přírodopisných věd: chemie a biologie, v každé 8 lekcí podle osnov -cs: Každá lekce má výklad a kvíz se čtyřmi otázkami -en: Natural sciences: chemistry and biology, eight lessons each, from the syllabus -en: Every lesson has an overview and a four-question quiz -cs: Český jazyk: literatura ve čtyřech ročnících podle osnov středních škol -cs: 32 lekcí od starověku po současnost, každá s výkladem a kvízem -en: Czech: literature across four years, following the secondary-school syllabus -en: 32 lessons from antiquity to the present, each with an overview and a quiz - ---- 2026-10-03 -cs: Občanská nauka: 4. ročník, 16 lekcí (hospodářství, svět a filozofie) -en: Civics: year 4, 16 lessons (the economy, the world and philosophy) - ---- 2026-10-02 -cs: Občanská nauka: 1. ročník, 17 lekcí (člověk v lidském společenství) -cs: Občanská nauka: 2. ročník, 16 lekcí (člověk jako občan) -cs: Občanská nauka: 3. ročník, 16 lekcí (člověk a právo) -en: Civics: year 1, 17 lessons (the individual and society) -en: Civics: year 2, 16 lessons (the citizen in a democratic state) -en: Civics: year 3, 16 lessons (the individual and the law) - ---- 2026-09-25 -cs: Technické vybavení: pět lekcí o digitalizaci zvuku (vzorkování, kvantování, PCM) -cs: Technické vybavení: skříň, zdroj, deska, CPU, karty, disky a vstupní zařízení -cs: Technické vybavení: dosavadní lekce jsou 1. ročník, další ročníky jsou zatím zamčené -en: Hardware: five lessons on digitizing sound (sampling, quantization, PCM) -en: Hardware: case, PSU, board, CPU, cards, drives and input devices -en: Hardware: current lessons are year 1; later years are still locked - ---- 2026-09-23 -cs: Repozitář se jmenuje Graduately; instalátory a updater míří tam -cs: Balíčky a instalátory se jmenují graduately-* (už ne maturita-*) -cs: Aplikace se jmenuje Graduately; úvod stále říká „Maturita? To dáme.“ -cs: Kompletní maturitní četba (82 knih) se zápisky, kvízem a sestavením děje -cs: Studium knih: nejdřív procvičení (kvíz / sestavte děj), pak zápisky -cs: Kvíz a sestavení děje u všech knih i na GTK (Linux / Windows) -cs: Větší a čitelnější rozhraní na Macu -cs: Opravy výběru slov v dialogu a otevření knihy z vyhledávání -en: Repository renamed to Graduately; installers and updater follow -en: Packages and installers are now graduately-* (no more maturita-*) -en: The app is now Graduately; the welcome line still says “Maturita? We've got this.” -en: Full maturita reading list (82 books) with notes, quiz, and plot ordering -en: Book study flow: practice first (quiz / order the plot), then notes -en: Quiz and plot assembly for every book on GTK too (Linux / Windows) -en: Larger, more readable Mac interface -en: Fixes for dialogue word picking and opening a book from search - ---- 2026-09-18 -cs: Po aktualizaci se na hlavní stránce ukáže, co je nového -cs: Android aplikace se stejnými cvičeními a funkčním updaterem -cs: iOS aplikace nativně na iOS 26 (Liquid Glass) z Maturita.xcworkspace -en: After an update the home screen shows what is new -en: Android app with the same exercises and a working updater -en: Native iOS 26 app (Liquid Glass) from Maturita.xcworkspace - ---- 2026-09-17 -cs: Vestavěný updater a instalátory, které stáhnou nejnovější build -cs: Vyhledávání předmětů, lekcí a cvičení -cs: Nový vzhled rozhraní a publikování do větve builds -en: Built-in updater and installers that fetch the newest build -en: Search for subjects, lessons and exercises -en: A new interface look and publishing to the builds branch - ---- 2026-09-16 -cs: Samostatné balíčky pro Linux, macOS a Windows -en: Self-contained packages for Linux, macOS and Windows - ---- 2026-09-15 -cs: Cvičení z české mluvnice -cs: Ikona aplikace na macOS, Windows i Linuxu -en: Czech grammar exercises -en: App icon on macOS, Windows and Linux - ---- 2026-09-14 -cs: Česká literatura: 1984 a Spalovač mrtvol -cs: Sítě: ročníky 1–4 a jednotky až po Wi-Fi -cs: Slovní zásoba pro Deutsch jednotky 2 a 3 -en: Czech literature: 1984 and The Cremator -en: Networks: years 1–4 and units through Wi-Fi -en: Vocabulary for Deutsch units 2 and 3 - ---- 2026-09-11 -cs: Technické vybavení: von Neumann, historie počítačů, bity a bajty -cs: Deset jednotek sítí s kvízy -cs: Slovní zásoba v Deutsch jednotce 1 -en: Hardware: von Neumann, computer history, bits and bytes -en: Ten network units with quizzes -en: Vocabulary in Deutsch unit 1 - ---- 2026-09-10 -cs: Sestavení na Windows -en: Windows build support - ---- 2026-09-09 -cs: Otevřený předmět sítí -cs: Statistiky postupu po jednotkách -en: Networks subject unlocked -en: Progress statistics by unit - ---- 2026-09-08 -cs: Deutsch jednotka 3 a vylepšený hangman -en: Deutsch unit 3 and a better hangman - ---- 2026-09-07 -cs: Z němčiny na více předmětů -cs: Deutsch jednotka 2 -cs: Témata, světlý režim a čeština / angličtina -en: From German-only to multiple subjects -en: Deutsch unit 2 -en: Themes, light mode and Czech / English - ---- 2026-09-06 -cs: Cesta cvičení a překlady po kontrole -en: Exercise path and translations after checking - ---- 2026-09-05 -cs: Cvičení v Deutsch jednotce 1 -en: Exercises in Deutsch unit 1 - ---- 2026-09-03 -cs: První verze Graduately -en: First version of Graduately diff --git a/data/macos/Graduately.entitlements b/data/macos/Graduately.entitlements deleted file mode 100644 index a917201..0000000 --- a/data/macos/Graduately.entitlements +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - com.apple.security.cs.allow-dyld-environment-variables - - - com.apple.security.cs.disable-library-validation - - - diff --git a/data/style.css b/data/style.css deleted file mode 100644 index 1d3d1c5..0000000 --- a/data/style.css +++ /dev/null @@ -1,1155 +0,0 @@ -/* Interface stylesheet. - * - * theme.c prepends the @define-color bindings of the active palette before - * this file is parsed, so nothing here names a literal colour: the rules - * describe shape, spacing and type only, and every palette stays swappable. - * - * Keep to the scales below when adding rules. - * - * type 12 caption | 14 small | 16 body | 18 lead | 28 44 headings - * weight 400 body | 500 emphasis | 600 controls | 700 headings - * radius 999 pills | 20 cards | 16 popovers - * motion 120ms colour | 150ms elevation - * - * Fills are flat and elevation is neutral; accent colour marks state, never - * decoration. Rules below the no-scale marker at the end of the file keep a - * fixed font size while the rest grows with the window. - */ - -/* ------------------------------------------------------------------ */ -/* Window chrome */ -/* ------------------------------------------------------------------ */ - -window { - background-color: @bg_base; -} -headerbar, -headerbar.titlebar, -.titlebar { - background-color: @bg_base; - background-image: none; - color: @fg_text; - border: none; - box-shadow: inset 0 -1px 0 alpha(@fg_text, 0.07); -} -.app-title { - color: @fg_text; - font-size: 15px; - font-weight: 700; - letter-spacing: -0.3px; -} -windowcontrols button:not(:hover), -windowcontrols button:not(:hover) image { - color: @fg_subtext; -} -button { - background-image: none; - transition: background-color 120ms ease, color 120ms ease; -} -tooltip { - background-color: @bg_crust; - border: 1px solid alpha(@fg_text, 0.10); - border-radius: 8px; - color: @fg_text; -} - -/* Keyboard focus stays visible on every real control; the map nodes below - * are canvas items and opt out explicitly. */ -.btn-primary:focus-visible, -.back-btn:focus-visible, -.settings-btn:focus-visible, -.search-hit:focus-visible, -.pill:focus-visible, -.chip:focus-visible, -.group-btn:focus-visible, -.mode-chip:focus-visible, -.theme-card:focus-visible, -.kahoot-opt:focus-visible { - outline-style: solid; - outline-width: 2px; - outline-color: alpha(@accent, 0.65); - outline-offset: 2px; -} - -/* ------------------------------------------------------------------ */ -/* Type */ -/* ------------------------------------------------------------------ */ - -.heading { - color: @fg_text; - font-size: 44px; - font-weight: 700; - letter-spacing: -1.4px; - line-height: 1.08; -} -.roadmap-title { - color: @fg_text; - font-size: 28px; - font-weight: 700; - letter-spacing: -0.6px; -} -.roadmap-sub { - color: @fg_subtext; - font-size: 15px; -} -.welcome-kicker { - color: @fg_text; - font-size: 15px; - font-weight: 700; - letter-spacing: -0.2px; -} -.welcome-body { - color: @fg_subtext; - font-size: 16px; -} -.welcome-meta { - color: @fg_overlay; - font-size: 12px; -} -.welcome-page { - padding: 48px 48px 56px 48px; - min-width: 640px; -} -.welcome-feature { - background-color: @bg_mantle; - border: 1px solid alpha(@fg_text, 0.07); - border-radius: 20px; - padding: 22px 24px 18px 24px; -} -.welcome-feature-title { - color: @fg_text; - font-size: 18px; - font-weight: 700; - letter-spacing: -0.3px; -} -.welcome-feature-body { - color: @fg_subtext; - font-size: 15px; -} -.welcome-link { - background-image: none; - background-color: alpha(@fg_text, 0.05); - color: @fg_text; - border: none; - border-radius: 999px; - padding: 8px 16px; - font-size: 13px; - font-weight: 600; - box-shadow: none; - margin-top: 6px; -} -.welcome-link:hover { - background-color: alpha(@fg_text, 0.09); -} -.welcome-badge { - min-width: 116px; - min-height: 116px; - padding: 18px 16px; - border-radius: 999px; - background-color: @bg_mantle; - border: 1px solid alpha(@fg_text, 0.08); -} -.welcome-badge-value { - color: @fg_text; - font-size: 32px; - font-weight: 700; - letter-spacing: -1px; -} -.welcome-badge-label { - color: @fg_subtext; - font-size: 12px; - font-weight: 600; -} -.changelog-card { - background-color: alpha(@accent, 0.10); - border: 1px solid alpha(@accent, 0.28); - border-radius: 20px; - padding: 20px 24px 16px 24px; -} -.changelog-title { - color: @fg_text; - font-size: 18px; - font-weight: 700; - letter-spacing: -0.3px; -} -.changelog-date { - color: @fg_subtext; - font-size: 12px; - font-weight: 600; -} -.changelog-item { - color: @fg_text; - font-size: 15px; -} -.changelog-dismiss { - background-image: none; - background-color: @accent; - color: @on_accent; - border: none; - border-radius: 999px; - padding: 8px 16px; - font-size: 13px; - font-weight: 600; - box-shadow: none; - margin-top: 6px; -} -.changelog-dismiss:hover { - background-color: shade(@accent, 1.1); -} -.subject-grid { - padding: 8px 4px 24px 4px; -} -.subject-tile { - background-image: none; - background-color: @bg_mantle; - color: @fg_text; - border: 1px solid alpha(@fg_text, 0.08); - border-radius: 20px; - padding: 22px 16px 18px 16px; - min-width: 196px; - box-shadow: none; - transition: background-color 120ms ease, border-color 120ms ease; -} -.subject-tile:hover { - background-image: none; - border-color: alpha(@fg_text, 0.22); -} -.subject-tile.open:hover { - border-color: @accent; -} -.subject-tile.locked { - opacity: 0.48; -} -.subject-name { - color: @fg_text; - font-size: 13px; - font-weight: 600; -} - -/* Small all-caps-ish section markers. */ -.settings-label, -.stats-section, -.stats-metric-label, -.notes-kicker, -.group-panel-label { - color: @fg_subtext; - font-size: 12px; - font-weight: 600; -} -.notes-kicker { - color: @accent; - letter-spacing: 0.6px; -} - -.hint, -.meaning { - color: @fg_subtext; - font-size: 13px; -} -.ex-prompt { - color: @fg_text; - font-size: 15px; - font-weight: 400; -} -.ex-sub { - color: @fg_subtext; - font-size: 13px; - font-weight: 500; -} -.trans-word { - color: @fg_text; - font-size: 24px; - font-weight: 600; -} -.dlg-speaker { - color: @accent; - font-size: 15px; - font-weight: 600; -} -.number-big { - color: @fg_text; - font-size: 24px; - font-weight: 600; -} -.hm-word { - color: @fg_text; - font-family: monospace; - font-size: 26px; - font-weight: 600; - letter-spacing: 2px; -} -.chain { - color: @fg_text; - font-size: 17px; - font-weight: 500; - letter-spacing: 0.5px; -} -.u3-answer { - color: @success; - font-size: 13px; - font-weight: 600; -} -.feedback-ok { - color: @success; - font-size: 14px; - font-weight: 600; -} -.feedback-err { - color: @error; - font-size: 14px; - font-weight: 600; -} -.feedback-warn { - color: @warning; - font-size: 14px; - font-weight: 600; -} - -/* ------------------------------------------------------------------ */ -/* Surfaces */ -/* ------------------------------------------------------------------ */ - -.quiz-card, -.notes-card, -.stats-metric, -.stats-unit-row, -.book-card, -.lit-link { - background-color: mix(@bg_base, @bg_surface0, 0.55); - background-image: none; - border: 1px solid alpha(@fg_text, 0.09); - border-radius: 20px; - color: @fg_text; - box-shadow: none; -} -.quiz-card { - padding: 16px 18px; -} -.notes-card { - padding: 22px 26px; -} -.notes-title { - color: @fg_text; - font-size: 20px; - font-weight: 700; -} -.notes-body { - color: @fg_text; - font-size: 15px; -} -.notes-tip { - color: @success; - font-size: 14px; - font-weight: 500; -} -.group-panel, -.sent-group { - background-color: alpha(@fg_text, 0.04); - border: 1px solid alpha(@fg_text, 0.09); - border-radius: 20px; - padding: 12px; -} -.sent-group.ok { - border-color: @success; -} -.sent-group.wrong { - border-color: @error; -} - -popover, -popover.background, -.settings-popover { - background-color: @bg_mantle; - color: @fg_text; - border: 1px solid alpha(@fg_text, 0.12); - border-radius: 16px; - box-shadow: 0 12px 32px alpha(@bg_crust, 0.45); -} -popover > contents, -.settings-popover > contents { - background-color: transparent; - border: none; - border-radius: 16px; - box-shadow: none; - padding: 0; -} - -/* ------------------------------------------------------------------ */ -/* Buttons */ -/* ------------------------------------------------------------------ */ - -.btn-primary { - background-image: none; - background-color: @accent; - color: @on_accent; - font-size: 15px; - font-weight: 600; - padding: 12px 28px; - border: none; - border-radius: 999px; - box-shadow: none; - transition: background-color 120ms ease; -} -.btn-primary:hover { - background-color: shade(@accent, 1.1); -} -.btn-primary:active { - background-color: shade(@accent, 0.92); -} -.btn-primary:disabled { - background-color: alpha(@fg_text, 0.10); - color: @fg_overlay; -} - -/* Flat icon buttons in the header bar and above each page. */ -.back-btn, -.settings-btn, -.settings-btn:hover, -.settings-btn:active, -.settings-btn:checked, -.settings-btn:focus { - min-width: 32px; - min-height: 32px; - padding: 0; - border-radius: 8px; - background-color: transparent; - background-image: none; - border: none; - box-shadow: none; - color: @fg_subtext; - transition: background-color 120ms ease, color 120ms ease; -} -.back-btn:hover, -.settings-btn:hover { - background-color: alpha(@fg_text, 0.09); - color: @fg_text; -} -.back-btn:active, -.settings-btn:active { - background-color: alpha(@fg_text, 0.15); - color: @fg_text; -} - -/* Word / answer chips. */ -.pill, -.chip, -.group-btn { - background-image: none; - background-color: mix(@bg_base, @bg_surface0, 0.7); - color: @fg_text; - border: 1px solid alpha(@fg_text, 0.12); - border-radius: 999px; - padding: 7px 14px; - font-size: 14px; - font-weight: 500; - box-shadow: none; - transition: background-color 120ms ease, border-color 120ms ease; -} -.pill:hover, -.chip:hover, -.group-btn:hover { - background-image: none; - background-color: mix(@bg_base, @bg_surface0, 1.0); - border-color: alpha(@accent, 0.7); -} -.pill:active, -.chip:active, -.group-btn:active { - background-image: none; - background-color: @bg_surface1; -} -.pill:checked, -.group-btn:checked { - background-image: none; - background-color: @accent; - border-color: @accent; - color: @on_accent; - font-weight: 600; -} -.pill.ok, -.pill.ok:checked, -.pill.ok:hover { - background-image: none; - background-color: @success; - border-color: @success; - color: @on_accent; -} -.pill.wrong, -.pill.wrong:checked, -.pill.wrong:hover { - background-image: none; - background-color: @error; - border-color: @error; - color: @on_accent; -} -.pill.hm-key { - min-width: 32px; - padding: 5px 6px; - font-size: 13px; -} -.chip { - border-radius: 999px; -} -.chip.ghost-host { - opacity: 0; -} -.group-panel-label { - margin-bottom: 4px; -} - -/* Multiple-choice rows read as list items rather than as chips. They are - * outlined instead of filled, so they do not have to be lighter than the card - * in dark mode and darker in light mode. */ -.quiz-pill { - background-color: transparent; - border-color: alpha(@fg_text, 0.13); - border-radius: 10px; - padding: 11px 14px; - min-height: 40px; -} -.quiz-pill label { - font-weight: 400; -} -.quiz-pill:checked label { - font-weight: 600; -} -.quiz-heading { - color: @fg_text; - font-size: 17px; - font-weight: 600; -} -.quiz-intro { - color: @fg_subtext; - font-size: 14px; -} -.listen-script { - color: @fg_text; - font-size: 15px; -} -.listen-caption { - color: @fg_subtext; - font-size: 12px; - font-weight: 600; -} -.listen-scale trough { - min-height: 4px; - border-radius: 999px; - background-color: alpha(@fg_text, 0.16); -} -.listen-scale highlight { - border-radius: 999px; - background-color: @accent; -} -.listen-scale value { - color: @fg_subtext; - font-size: 12px; - font-weight: 600; -} -.quiz-q { - color: @fg_text; - font-size: 15px; - font-weight: 600; -} -.quiz-options { - margin-top: 4px; -} - -/* Four-colour quiz board: the colours are the mechanic, so they stay, but - * they are flat and the answer state is shown by the border alone. */ -.kahoot-opt { - background-image: none; - color: @on_accent; - font-size: 15px; - font-weight: 600; - padding: 14px 16px; - border: 2px solid transparent; - border-radius: 20px; - box-shadow: none; - transition: border-color 120ms ease, opacity 120ms ease; -} -.kahoot-0 { - background-color: @accent; -} -.kahoot-1 { - background-color: @error; -} -.kahoot-2 { - background-color: @warning; -} -.kahoot-3 { - background-color: @success; -} -.kahoot-opt:hover { - border-color: alpha(@fg_text, 0.35); -} -.kahoot-opt.ok { - border-color: @fg_text; -} -.kahoot-opt.wrong { - opacity: 0.4; -} - -/* ------------------------------------------------------------------ */ -/* Text entry */ -/* ------------------------------------------------------------------ */ - -entry { - background-color: @bg_mantle; - color: @fg_text; - border: 1px solid alpha(@fg_text, 0.14); - border-radius: 8px; - padding: 7px 11px; - font-size: 15px; - caret-color: @accent; - box-shadow: none; -} -entry:focus { - border-color: @accent; - box-shadow: 0 0 0 2px alpha(@accent, 0.22); -} -entry.answer-ok { - border-color: @success; - background-color: alpha(@success, 0.10); -} -entry.answer-wrong { - border-color: @error; - background-color: alpha(@error, 0.10); -} -combobox { - background-color: transparent; - color: @fg_text; -} -combobox button { - background-image: none; - background-color: @bg_mantle; - color: @fg_text; - border: 1px solid alpha(@fg_text, 0.14); - border-radius: 8px; - padding: 4px 10px; - box-shadow: none; -} -combobox button:hover { - background-image: none; - border-color: alpha(@accent, 0.7); -} -combobox.answer-ok button { - border-color: @success; - background-color: alpha(@success, 0.10); -} -combobox.answer-wrong button { - border-color: @error; - background-color: alpha(@error, 0.10); -} - -/* ------------------------------------------------------------------ */ -/* Progress maps */ -/* ------------------------------------------------------------------ */ - -.unit-node, -.ex-bubble { - background-image: none; - background-color: @node_bg; - color: @fg_text; - border: 2px solid @locked_border; - border-radius: 999px; - padding: 0; - box-shadow: none; - transition: background-color 120ms ease, border-color 120ms ease, - box-shadow 150ms ease; -} -.ex-bubble { - min-width: 64px; - min-height: 64px; -} -.unit-node.done, -.ex-bubble.done { - background-color: @success; - border-color: @success; - color: @on_accent; -} -.unit-node.current { - background-color: @accent; - border-color: @accent; - color: @on_accent; - box-shadow: none; -} -.unit-node.locked { - background-color: @locked_bg; - border-color: @locked_border; - color: @fg_overlay; -} -.unit-node.finish { - background-color: transparent; - border: none; - color: @fg_overlay; -} -.unit-node:hover, -.ex-bubble:hover { - border-color: @accent; -} -.unit-node.locked:hover { - border-color: @locked_border; -} -.unit-node.done:hover, -.ex-bubble.done:hover { - border-color: shade(@success, 1.15); -} -.unit-node.current:hover { - box-shadow: none; -} -.unit-node:focus, -.unit-node:focus-visible, -.ex-bubble:focus, -.ex-bubble:focus-visible { - outline-style: none; -} -.ex-branch { - border-style: dashed; - border-color: @accent; -} -.ex-branch:hover { - border-style: solid; -} - -.unit-number { - font-size: 22px; - font-weight: 700; -} -.bubble-number { - font-size: 20px; - font-weight: 700; -} -.unit-node.done .unit-number, -.unit-node.current .unit-number, -.ex-bubble.done .bubble-number, -.state-icon, -.bubble-icon { - color: @on_accent; -} -.unit-node.locked .unit-number { - color: @fg_overlay; -} -.unit-node.locked .lock-icon { - color: @fg_overlay; -} - -/* Node captions sit on top of the rail, so they carry the page background. */ -.unit-name, -.ex-label { - color: @fg_text; - font-size: 13px; - font-weight: 500; -} -.unit-name-locked { - color: @fg_overlay; -} -.cz-label { - background-color: @bg_base; - border-radius: 6px; - padding: 2px 6px; -} - -/* ------------------------------------------------------------------ */ -/* Reading list and literature */ -/* ------------------------------------------------------------------ */ - -.book-card, -.lit-link { - padding: 16px 20px; - transition: background-color 120ms ease, border-color 120ms ease; -} -.book-card:hover, -.lit-link:hover { - background-color: mix(@bg_base, @bg_surface0, 0.9); - border-color: alpha(@accent, 0.6); -} -.book-card:active, -.lit-link:active { - background-color: alpha(@accent, 0.14); -} -.reading-hero { - opacity: 0.18; -} -.book-title { - color: @fg_text; - font-size: 20px; - font-weight: 700; -} -.book-author { - color: @fg_subtext; - font-size: 15px; - font-weight: 500; -} -.book-sub, -.lit-link-sub { - color: @fg_subtext; - font-size: 13px; -} -.lit-link-title { - color: @fg_text; - font-size: 17px; - font-weight: 600; -} -.lit-progress { - color: @accent; - font-size: 13px; - font-weight: 600; -} -.lit-score { - color: @fg_subtext; - font-size: 13px; - font-weight: 500; -} -.lit-prompt { - color: @fg_text; - font-size: 17px; - font-weight: 600; -} -.lit-expl { - color: @fg_text; - font-size: 14px; - background-color: alpha(@success, 0.10); - border-left: 3px solid @success; - border-radius: 6px; - padding: 10px 14px; -} - -/* ------------------------------------------------------------------ */ -/* Settings popover */ -/* ------------------------------------------------------------------ */ - -.settings-box { - background-color: transparent; - color: @fg_text; - min-width: 292px; - padding: 16px; -} -.settings-title { - color: @fg_text; - font-size: 17px; - font-weight: 700; -} -.settings-seg { - background-color: alpha(@fg_text, 0.06); - border: none; - border-radius: 8px; - padding: 3px; -} -.mode-chip { - background-image: none; - background-color: transparent; - color: @fg_subtext; - border: none; - border-radius: 6px; - padding: 7px 12px; - font-size: 13px; - font-weight: 500; - min-width: 0; - box-shadow: none; - transition: background-color 120ms ease, color 120ms ease; -} -.mode-chip:hover { - background-color: alpha(@fg_text, 0.07); - color: @fg_text; -} -.mode-chip:checked, -.mode-chip:checked:hover { - background-image: none; - background-color: @accent; - color: @on_accent; - font-weight: 600; -} -.theme-grid, -flowboxchild { - background-color: transparent; - border: none; - box-shadow: none; - padding: 0; - margin: 0; -} -.theme-card { - background-image: none; - background-color: transparent; - color: @fg_text; - border: none; - border-radius: 8px; - padding: 6px 4px; - min-width: 0; - box-shadow: none; - transition: background-color 120ms ease; -} -.theme-card:hover, -.theme-card:checked:hover { - background-color: alpha(@fg_text, 0.07); -} -.theme-card:checked { - background-color: alpha(@fg_text, 0.04); -} -.theme-card-name { - color: @fg_subtext; - font-size: 12px; - font-weight: 500; -} -.theme-card:checked .theme-card-name { - color: @fg_text; - font-weight: 600; -} - -/* ------------------------------------------------------------------ */ -/* Updates */ -/* ------------------------------------------------------------------ */ - -.update-banner { - background-color: alpha(@accent, 0.12); - border-bottom: 1px solid alpha(@accent, 0.3); - padding: 8px 16px; -} -.update-banner-text { - color: @fg_text; - font-size: 13px; - font-weight: 500; -} -.update-banner-btn { - background-image: none; - background-color: @accent; - color: @on_accent; - border: none; - border-radius: 999px; - padding: 5px 14px; - font-size: 13px; - font-weight: 600; - box-shadow: none; - transition: background-color 120ms ease; -} -.update-banner-btn:hover { - background-color: shade(@accent, 1.1); -} -.update-banner-later { - background-image: none; - background-color: transparent; - color: @fg_subtext; - border: none; - border-radius: 8px; - padding: 5px 10px; - font-size: 13px; - font-weight: 500; - box-shadow: none; -} -.update-banner-later:hover { - background-color: alpha(@fg_text, 0.09); - color: @fg_text; -} -.update-status { - color: @fg_subtext; - font-size: 12px; -} -.update-btn { - background-image: none; - background-color: mix(@bg_base, @bg_surface0, 0.7); - color: @fg_text; - border: 1px solid alpha(@fg_text, 0.12); - border-radius: 8px; - padding: 5px 12px; - font-size: 12px; - font-weight: 600; - box-shadow: none; - transition: background-color 120ms ease, border-color 120ms ease; -} -.update-btn:hover { - background-image: none; - background-color: mix(@bg_base, @bg_surface0, 1.0); - border-color: alpha(@accent, 0.7); -} -.update-btn:disabled { - color: @fg_overlay; -} -.update-progress, -.update-progress trough { - min-height: 6px; - min-width: 6px; - border: none; - border-radius: 3px; - padding: 0; - background-color: alpha(@fg_text, 0.11); -} -.update-progress progress { - min-height: 6px; - min-width: 6px; - border: none; - border-radius: 3px; - background-image: none; - background-color: @accent; -} - -/* ------------------------------------------------------------------ */ -/* Statistics */ -/* ------------------------------------------------------------------ */ - -.stats-page { - padding: 24px 32px 24px 32px; -} -.stats-summary { - margin-top: 10px; - margin-bottom: 16px; -} -.stats-metric { - padding: 14px 16px; - min-width: 120px; -} -.stats-metric-value { - color: @fg_text; - font-size: 32px; - font-weight: 700; - letter-spacing: -1px; -} -.stats-metric-label { - margin-top: 2px; -} -.stats-section { - margin-bottom: 8px; -} -.stats-subject { - margin-bottom: 20px; -} -.stats-subject-name { - color: @fg_text; - font-size: 15px; - font-weight: 600; -} -.stats-subject-count { - color: @fg_subtext; - font-size: 13px; - font-weight: 500; -} -.stats-subject-count.locked { - color: @fg_overlay; -} -.stats-units { - margin-top: 8px; - padding-left: 14px; -} -.stats-unit-row { - padding: 13px 14px; - margin-bottom: 6px; -} -.stats-unit-row.locked { - opacity: 0.5; -} -.stats-unit-row.done { - border-color: alpha(@success, 0.5); -} -.stats-unit-index { - color: @fg_overlay; - font-size: 13px; - font-weight: 500; - min-width: 20px; -} -.stats-unit-name { - color: @fg_text; - font-size: 15px; - font-weight: 500; -} -.stats-unit-count { - color: @fg_subtext; - font-size: 13px; - font-weight: 500; -} -.stats-unit-badge { - color: @success; - font-size: 12px; - font-weight: 600; -} - -/* One shared bar geometry; only the fill colour differs. */ -.stats-overall-bar, -.stats-overall-bar trough, -.stats-subject-bar, -.stats-subject-bar trough, -.stats-unit-bar, -.stats-unit-bar trough { - min-height: 6px; - min-width: 6px; - border: none; - border-radius: 3px; - padding: 0; - background-color: alpha(@fg_text, 0.11); -} -.stats-overall-bar progress, -.stats-subject-bar progress, -.stats-unit-bar progress { - min-height: 6px; - min-width: 6px; - border: none; - border-radius: 3px; - background-image: none; - background-color: @accent; -} -.stats-unit-bar.done progress { - background-color: @success; -} -/* stats_set_fraction() marks bars at zero, whose fill GTK would otherwise - * still paint at its minimum width. */ -.stats-overall-bar.empty progress, -.stats-subject-bar.empty progress, -.stats-unit-bar.empty progress { - background-color: transparent; -} -.stats-overall-bar { - margin-bottom: 20px; -} -.stats-subject-bar { - margin-top: 6px; -} - -.search-scrim { - background-color: alpha(@bg_crust, 0.46); -} -.search-card { - background-color: @bg_surface0; - border: 1px solid alpha(@fg_text, 0.10); - border-radius: 20px; - padding: 16px; - min-width: 520px; -} -.search-entry { - min-height: 40px; - font-size: 16px; -} -.search-empty { - color: @fg_subtext; - font-size: 14px; - padding: 18px 8px 8px; -} -.search-results { - background-color: transparent; - background-image: none; - border: none; -} -.search-results row { - border-radius: 12px; - margin-bottom: 4px; - background-color: transparent; -} -.search-results row:hover, -.search-results row:selected { - background-color: alpha(@fg_text, 0.07); -} -.search-hit-title { - color: @fg_text; - font-size: 16px; - font-weight: 600; -} -.search-hit-sub { - color: @fg_subtext; - font-size: 13px; -} -.search-hit-locked .search-hit-title, -.search-hit-locked .search-hit-sub { - opacity: 0.62; -} - -/* no-scale */ -/* Rules below keep a fixed size (symbols/icons) even when the window grows. */ -.bubble-number.branch-star { - font-size: 20px; -} diff --git a/data/windows/maturita.rc b/data/windows/maturita.rc deleted file mode 100644 index 1cb2d50..0000000 --- a/data/windows/maturita.rc +++ /dev/null @@ -1,3 +0,0 @@ -/* Windows application icon embedded into graduately.exe. - * The first ICON resource becomes the Explorer / taskbar icon. */ -1 ICON "../../assets/app-icon.ico" diff --git a/run-windows.bat b/run-windows.bat deleted file mode 100644 index f535511..0000000 --- a/run-windows.bat +++ /dev/null @@ -1,17 +0,0 @@ -@echo off -setlocal - -REM Launch a locally built graduately.exe with the GTK4 runtime on PATH, so the -REM app can be started by double-clicking even when GTK is not installed -REM system-wide. - -if not defined GTK_ROOT set "GTK_ROOT=C:\gtk" -set "PATH=%GTK_ROOT%\bin;%PATH%" - -if not exist "%~dp0graduately.exe" ( - echo [error] graduately.exe not found next to this script. - echo Build it first with build-windows.bat. - exit /b 1 -) - -start "" /D "%~dp0" "%~dp0graduately.exe" diff --git a/scripts/bundle-macos.sh b/scripts/bundle-macos.sh deleted file mode 100755 index 36dc22d..0000000 --- a/scripts/bundle-macos.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -# Official macOS package is the native Swift app. -# The GTK bundler used to live here; Linux/Windows still use GTK. -set -euo pipefail -exec "$(cd "$(dirname "$0")" && pwd)/bundle-macos-swift.sh" "$@" diff --git a/scripts/extract-android-content.py b/scripts/extract-android-content.py deleted file mode 100644 index 7972c7d..0000000 --- a/scripts/extract-android-content.py +++ /dev/null @@ -1,1869 +0,0 @@ -#!/usr/bin/env python3 -"""Pull educational content out of the GTK C sources into content.json.""" - -from __future__ import annotations - -import json -import re -import sys -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -SRC = ROOT / "src" -# Default target is the Android asset; Xcode (iOS / native macOS) passes -# `--out` and copies the file into the app bundle itself, so nothing -# generated lives under ios/ or macos/. -OUTS = [ - ROOT / "android" / "app" / "src" / "main" / "assets" / "content.json", -] -if "--out" in sys.argv: - OUTS = [Path(a) for a in sys.argv[sys.argv.index("--out") + 1:] if a] - if not OUTS: - sys.exit("usage: extract-android-content.py [--out PATH ...]") -OUT = OUTS[0] - -IDENT = re.compile(r"[A-Za-z_][A-Za-z0-9_]*") - - -def strip_comments(src: str) -> str: - out = [] - i, n = 0, len(src) - while i < n: - c = src[i] - if c == '"' or c == "'": - q = c - out.append(c) - i += 1 - while i < n: - ch = src[i] - out.append(ch) - if ch == "\\" and i + 1 < n: - out.append(src[i + 1]) - i += 2 - continue - i += 1 - if ch == q: - break - continue - if c == "/" and i + 1 < n and src[i + 1] == "/": - i += 2 - while i < n and src[i] != "\n": - i += 1 - continue - if c == "/" and i + 1 < n and src[i + 1] == "*": - i += 2 - while i + 1 < n and not (src[i] == "*" and src[i + 1] == "/"): - i += 1 - i = min(n, i + 2) - out.append(" ") - continue - out.append(c) - i += 1 - return "".join(out) - - -def unescape(s: str) -> str: - out = [] - i = 0 - while i < len(s): - if s[i] == "\\" and i + 1 < len(s): - n = s[i + 1] - mapping = { - "n": "\n", - "t": "\t", - "r": "\r", - "\\": "\\", - '"': '"', - "'": "'", - } - if n in mapping: - out.append(mapping[n]) - i += 2 - continue - if n == "x": - j = i + 2 - hexdigits = "" - while j < len(s) and s[j] in "0123456789abcdefABCDEF" and len(hexdigits) < 2: - hexdigits += s[j] - j += 1 - out.append(chr(int(hexdigits, 16)) if hexdigits else "x") - i = j - continue - out.append(s[i]) - i += 1 - return "".join(out) - - -class Tok: - def __init__(self, kind: str, value, pos: int): - self.kind = kind - self.value = value - self.pos = pos - - -def tokenize(src: str) -> list[Tok]: - toks: list[Tok] = [] - i, n = 0, len(src) - while i < n: - c = src[i] - if c.isspace(): - i += 1 - continue - if c == '"': - i += 1 - raw = [] - while i < n: - ch = src[i] - if ch == "\\" and i + 1 < n: - raw.append(ch) - raw.append(src[i + 1]) - i += 2 - continue - if ch == '"': - i += 1 - break - raw.append(ch) - i += 1 - while i < n and src[i].isspace(): - i += 1 - while i < n and src[i] == '"': - i += 1 - while i < n: - ch = src[i] - if ch == "\\" and i + 1 < n: - raw.append(ch) - raw.append(src[i + 1]) - i += 2 - continue - if ch == '"': - i += 1 - break - raw.append(ch) - i += 1 - while i < n and src[i].isspace(): - i += 1 - toks.append(Tok("str", unescape("".join(raw)), i)) - continue - if c in "{}[],;=": - toks.append(Tok(c, c, i)) - i += 1 - continue - if c == "-" and i + 1 < n and src[i + 1].isdigit(): - j = i + 1 - while j < n and (src[j].isdigit() or src[j] == "."): - j += 1 - toks.append(Tok("num", int(float(src[i:j])), i)) - i = j - continue - if c.isdigit(): - j = i - while j < n and (src[j].isdigit() or src[j] == "."): - j += 1 - text = src[i:j] - toks.append(Tok("num", int(float(text)) if "." not in text else int(float(text)), i)) - i = j - continue - if c == "'" and i + 2 < n: - j = i + 1 - raw = [] - while j < n and src[j] != "'": - if src[j] == "\\" and j + 1 < n: - raw.append(src[j + 1]) - j += 2 - continue - raw.append(src[j]) - j += 1 - j += 1 - toks.append(Tok("num", ord(raw[0]) if raw else 0, i)) - i = j - continue - m = IDENT.match(src, i) - if m: - name = m.group(0) - i = m.end() - if name == "NULL": - toks.append(Tok("null", None, i)) - elif name in ("TRUE", "FALSE"): - toks.append(Tok("num", 1 if name == "TRUE" else 0, i)) - else: - toks.append(Tok("id", name, i)) - continue - i += 1 - return toks - - -def parse_value(toks: list[Tok], i: int): - if i >= len(toks): - return None, i - t = toks[i] - if t.kind == "str": - return t.value, i + 1 - if t.kind == "num": - return t.value, i + 1 - if t.kind == "null": - return None, i + 1 - if t.kind == "id": - name = t.value - i += 1 - if i < len(toks) and toks[i].kind == "(": - depth = 1 - i += 1 - while i < len(toks) and depth: - if toks[i].kind == "(": - depth += 1 - elif toks[i].kind == ")": - depth -= 1 - i += 1 - return None, i - return {"$ref": name}, i - if t.kind == "{": - return parse_list(toks, i) - return None, i + 1 - - -def parse_list(toks: list[Tok], i: int): - assert toks[i].kind == "{" - i += 1 - items = [] - while i < len(toks) and toks[i].kind != "}": - if toks[i].kind == ",": - i += 1 - continue - val, i = parse_value(toks, i) - items.append(val) - if i < len(toks) and toks[i].kind == ",": - i += 1 - if i < len(toks) and toks[i].kind == "}": - i += 1 - return items, i - - -ARRAY_RE = re.compile( - r"(?:static\s+)?const\s+" - r"(?:struct\s+)?(?P[A-Za-z_][A-Za-z0-9_]*)" - r"(?:\s+\*|\s+const\s+\*|\s*)\s*" - r"(?P[A-Za-z_][A-Za-z0-9_]*)" - r"(?:\s*\[[^\]]*\])+\s*=\s*\{", - re.M, -) - -CHARPTR_RE = re.compile( - r"(?:static\s+)?const\s+char\s*\*\s*(?:const\s+)?" - r"(?P[A-Za-z_][A-Za-z0-9_]*)" - r"(?:\s*\[[^\]]*\])+\s*=\s*\{", - re.M, -) - -STRING_ASSIGN_RE = re.compile( - r"(?:static\s+)?const\s+char\s*\*\s*" - r"(?P[A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?P\"(?:\\.|[^\"\\])*\"(?:\s*\"(?:\\.|[^\"\\])*\")*)\s*;", - re.S, -) - -FUNC_RE = re.compile( - r"^(?:static\s+)?(?:GtkWidget\s*\*|void|gboolean|int|char\s*\*)\s*" - r"([A-Za-z_][A-Za-z0-9_]*)\s*\(", - re.M, -) - - -def find_arrays(src: str) -> dict[str, tuple[str, list]]: - found: dict[str, tuple[str, list]] = {} - funcs = [(m.start(), m.group(1)) for m in FUNC_RE.finditer(src)] - - def func_at(pos: int) -> str | None: - current = None - for start, name in funcs: - if start < pos: - current = name - else: - break - if current is None: - return None - # Only treat as local if the array sits after the function's opening brace - # and before the next top-level function. Good enough for this codebase. - return current - - def add(typ: str, name: str, pos_brace: int): - toks = tokenize(src[pos_brace:]) - if not toks or toks[0].kind != "{": - return - val, _ = parse_list(toks, 0) - fn = func_at(pos_brace) - key = f"{fn}.{name}" if fn and name in { - "slides", "qs", "hints", "about", "world", "people", "terms", - "persons", "nouns", "ans", - } else name - # Prefer the first global, overwrite locals with prefixed names. - if key in found and not key.startswith(fn or "\0"): - return - found[key] = (typ, val) - - for m in ARRAY_RE.finditer(src): - add(m.group("type"), m.group("name"), m.end() - 1) - for m in CHARPTR_RE.finditer(src): - add("char*", m.group("name"), m.end() - 1) - for m in STRING_ASSIGN_RE.finditer(src): - toks = tokenize(m.group("body")) - text = "".join(t.value for t in toks if t.kind == "str") - found[m.group("name")] = ("char", [text]) - return found - - -def as_list(v): - return v if isinstance(v, list) else [] - - -def as_str(v) -> str | None: - if v is None: - return None - if isinstance(v, str): - return v - return None - - -def resolve(arrays: dict, val, depth=0): - if depth > 8: - return val - if isinstance(val, dict) and "$ref" in val: - name = val["$ref"] - if name in arrays: - return resolve(arrays, arrays[name][1], depth + 1) - return None - if isinstance(val, list): - return [resolve(arrays, x, depth + 1) for x in val] - return val - - -def choice_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 4: - continue - opts = [o for o in as_list(row[1]) if isinstance(o, str)] - correct = row[3] if isinstance(row[3], int) else 0 - out.append({ - "prompt": as_str(row[0]) or "", - "options": opts, - "correct": correct, - }) - return out - - -def typed_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 2: - continue - out.append({ - "prompt": as_str(row[0]) or "", - "answers": as_str(row[1]) or "", - "meaning": as_str(row[2]) if len(row) > 2 else None, - }) - return out - - -def assembly_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 2: - continue - words = [w for w in as_list(row[1]) if isinstance(w, str)] - n = row[2] if len(row) > 2 and isinstance(row[2], int) else len(words) - out.append({ - "prompt": as_str(row[0]), - "words": words[:n], - }) - return out - - -def str_list(rows) -> list[str]: - return [x for x in as_list(rows) if isinstance(x, str)] - - -def verb_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 3: - continue - out.append({ - "before": as_str(row[0]) or "", - "after": as_str(row[1]) or "", - "answer": as_str(row[2]) or "", - }) - return out - - -def verb_clue_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 4: - continue - out.append({ - "emoji": as_str(row[0]) or "", - "before": as_str(row[1]) or "", - "after": as_str(row[2]) or "", - "answer": as_str(row[3]) or "", - }) - return out - - -def assign_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 3: - continue - out.append({ - "emoji": as_str(row[0]), - "label": as_str(row[1]) or "", - "group": row[2] if isinstance(row[2], int) else 0, - }) - return out - - -def free_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 4: - continue - out.append({ - "question": as_str(row[0]) or "", - "qCs": as_str(row[1]) or "", - "sample": as_str(row[2]) or "", - "aCs": as_str(row[3]) or "", - }) - return out - - -def profile_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 2: - continue - out.append({ - "stem": as_str(row[0]) or "", - "sample": as_str(row[1]) or "", - }) - return out - - -def math_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 3: - continue - out.append({ - "prompt": as_str(row[0]) or "", - "answer": as_str(row[1]) or "", - "hint": as_str(row[2]) or "", - }) - return out - - -def slides_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 4: - continue - lines = [x for x in as_list(row[3]) if isinstance(x, str)] - out.append({ - "kicker": as_str(row[0]) or "", - "title": as_str(row[1]) or "", - "tip": as_str(row[2]), - "lines": lines, - }) - return out - - -def fill_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 9: - continue - segs = [as_str(row[1]), as_str(row[3]), as_str(row[5]), as_str(row[7])] - ans = [as_str(row[2]), as_str(row[4]), as_str(row[6])] - out.append({ - "num": as_str(row[0]), - "segs": [s or "" for s in segs], - "answers": [a for a in ans if a], - "mean": as_str(row[8]), - }) - return out - - -def let_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 11: - continue - segs = [as_str(row[i]) or "" for i in (1, 3, 5, 7, 9)] - ans = [as_str(row[i]) for i in (2, 4, 6, 8)] - out.append({ - "num": as_str(row[0]), - "segs": segs, - "answers": [a for a in ans if a], - "mean": as_str(row[10]), - }) - return out - - -def ex4row_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 6: - continue - segs = [s for s in as_list(row[0]) if s is None or isinstance(s, str)] - ans = [a for a in as_list(row[1]) if isinstance(a, str)] - words = [w for w in as_list(row[3]) if isinstance(w, str)] if len(row) > 3 else [] - gmean = [g for g in as_list(row[4]) if isinstance(g, str)] if len(row) > 4 else [] - gaps = row[5] if len(row) > 5 and isinstance(row[5], int) else len(ans) - out.append({ - "segs": [s or "" for s in segs], - "answers": ans[:gaps], - "czech": as_str(row[2]) if len(row) > 2 else None, - "words": words[:gaps], - "gmean": gmean[:gaps], - }) - return out - - -def kw_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 2: - continue - out.append({ - "prompt": as_str(row[0]) or "", - "answers": as_str(row[1]) or "", - "mean": as_str(row[2]) if len(row) > 2 else None, - "german": as_str(row[3]) if len(row) > 3 else None, - }) - return out - - -def mluv_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 5: - continue - nblank = row[2] if isinstance(row[2], int) else 1 - out.append({ - "prompt": as_str(row[0]) or "", - "shown": as_str(row[1]) or "", - "hints": [h for h in as_list(row[3]) if isinstance(h, str)][:nblank], - "answers": [a for a in as_list(row[4]) if isinstance(a, str)][:nblank], - }) - return out - - -def reveal_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 2: - continue - out.append({ - "prompt": as_str(row[0]) or "", - "solution": as_str(row[1]) or "", - }) - return out - - -def lit_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 4: - continue - opts = [o for o in as_list(row[1]) if isinstance(o, str)] - out.append({ - "prompt": as_str(row[0]) or "", - "options": opts, - "correct": row[2] if isinstance(row[2], int) else 0, - "expl": as_str(row[3]), - }) - return out - - -def trans_sections(rows, arrays) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 2: - continue - data = resolve(arrays, row[1]) - out.append({ - "header": as_str(row[0]) or "", - "rows": typed_items(data), - }) - return out - - -def dialogs(arrays) -> list[dict]: - out = [] - for key in ("ex1_d1", "ex1_d2", "ex1_d3"): - if key not in arrays: - continue - rows = [] - for row in as_list(arrays[key][1]): - row = as_list(row) - if len(row) < 4: - continue - rows.append({ - "speaker": as_str(row[0]) or "", - "before": as_str(row[1]) or "", - "answer": as_str(row[2]) or "", - "after": as_str(row[3]) or "", - }) - titles = {"ex1_d1": "Sich vorstellen", "ex1_d2": "Begrüßung", "ex1_d3": "Verabschiedung"} - out.append({"name": titles[key], "rows": rows}) - return out - - -def ordne_items(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 3: - continue - out.append({ - "mid": as_str(row[0]) or "", - "fw": as_str(row[1]) or "", - "ans": as_str(row[2]) or "", - }) - return out - - -def ex2_items(arrays) -> list[dict]: - out = [] - if "ex2_u3_items" not in arrays: - return out - for row in as_list(arrays["ex2_u3_items"][1]): - row = as_list(row) - if len(row) < 2: - continue - raw_rows = resolve(arrays, row[1]) - parsed = [] - for r in as_list(raw_rows): - r = as_list(r) - if len(r) < 4: - continue - segs = [s or "" for s in as_list(r[1]) if s is None or isinstance(s, str)] - ans = [a for a in as_list(r[2]) if isinstance(a, str)] - gaps = r[3] if isinstance(r[3], int) else len(ans) - parsed.append({ - "num": as_str(r[0]), - "segs": segs, - "answers": ans[:gaps], - }) - out.append({"czech": as_str(row[0]) or "", "rows": parsed}) - return out - - -def net_ans(rows) -> list[list[dict]]: - out = [] - for block in as_list(rows): - block = as_list(block) - inner = [] - for row in block: - row = as_list(row) - if len(row) < 5: - continue - inner.append({ - "pfx": row[0] if isinstance(row[0], int) else -1, - "net": as_str(row[1]), - "bcast": as_str(row[2]), - "lo": as_str(row[3]), - "hi": as_str(row[4]), - }) - out.append(inner) - return out - - -def net_tasks(rows) -> list[dict]: - out = [] - for row in as_list(rows): - row = as_list(row) - if len(row) < 2: - continue - out.append({"prompt": as_str(row[0]) or "", "solution": as_str(row[1]) or ""}) - return out - - -def parse_changelog(path: Path) -> list[dict]: - if not path.is_file(): - return [] - entries: list[dict] = [] - current = None - for raw in path.read_text(encoding="utf-8").splitlines(): - line = raw.strip() - if not line or line.startswith("#"): - continue - if line.startswith("---"): - current = {"date": line[3:].strip(), "cs": [], "en": []} - entries.append(current) - continue - if current is None: - continue - if line.startswith("cs:"): - current["cs"].append(line[3:].strip()) - elif line.startswith("en:"): - current["en"].append(line[3:].strip()) - return [e for e in entries if e["cs"] or e["en"]] - - -def expand_local_includes(src: str, directory: Path, seen: set[Path] | None = None) -> str: - """Inline #include "file" so keys that live in a fragment are extracted.""" - seen = set() if seen is None else seen - - def repl(match: re.Match) -> str: - path = (directory / match.group(1)).resolve() - if not path.is_file() or path in seen: - return match.group(0) - seen.add(path) - return expand_local_includes(path.read_text(encoding="utf-8"), path.parent, seen) - - return re.sub(r'^\s*#include\s+"([^"]+)"', repl, src, flags=re.M) - - -def parse_i18n(src: str) -> dict: - arrays = find_arrays(src) - out = {} - for name in ("tr_ui", "tr_content"): - if name not in arrays: - continue - for row in as_list(arrays[name][1]): - row = as_list(row) - if not row or not as_str(row[0]): - continue - key = as_str(row[0]) - cs = as_str(row[1]) if len(row) > 1 else None - en = as_str(row[2]) if len(row) > 2 else None - if key: - out[key] = {"cs": cs, "en": en} - return out - - -def combo(title, sub, pool, rows, meanings=None, kind="combo", **extra): - spec = { - "type": kind, - "title": title, - "sub": sub, - "pool": pool or [], - "rows": rows, - "meanings": meanings or [], - } - spec.update(extra) - return spec - - -def main() -> int: - arrays: dict[str, tuple[str, list]] = {} - i18n = {} - for path in sorted(SRC.glob("*.c")): - raw = path.read_text(encoding="utf-8") - if path.name in ("english.c", "german_course.c"): - raw = expand_local_includes(raw, path.parent) - text = strip_comments(raw) - arrays.update(find_arrays(text)) - if path.name == "i18n.c": - i18n = parse_i18n(strip_comments(expand_local_includes(text, path.parent))) - - def A(name): - if name not in arrays: - return [] - return resolve(arrays, arrays[name][1]) - - german_units = [ - { - "id": 0, - "title": "Neue Freunde", - "page": "unit1", - "tag": "u1", - "sub": "unit1_sub", - "unlocked": True, - "names": [ - "Dialog", "Sätze bilden", "Was ist richtig?", "Freie Antwort", - "Zahlen", "Wie viel?", "Zahlenreihe", "Verb einsetzen", - "Wer? Wie? Wo?", "Wörter trennen", "Grußformen", - "Was macht er/sie?", "Länder", - ], - "branch": "u1vocab", - "exercises": { - "1": combo("Dialog", "sub_dialog", str_list(A("ex1_pool")), - [], str_list(A("ex1_meaning")), "dialog", - dialogues=dialogs(arrays)), - "2": { - "type": "assembly", "title": "Sätze bilden", "sub": "sub_assembly", - "items": assembly_items(A("ex2_items")), - "meanings": str_list(A("ex2_meaning")), - }, - "3": { - "type": "choice", "title": "Was ist richtig?", "sub": "sub_choice_num", - "questions": choice_items(A("ex3_questions")), - "meanings": str_list(A("ex3_meaning")), - }, - "4": { - "type": "free", "title": "Freie Antwort", "sub": "sub_free", - "tip": "tip_ss", "questions": free_items(A("ex4_questions")), - }, - "5": combo("Zahlen", "sub_zahlen", str_list(A("ex5_pool")), - [{"digits": as_list(r)[0], "answer": as_list(r)[1]} - for r in as_list(A("ex5_data")) if len(as_list(r)) >= 2], - str_list(A("ex5_meaning")), "number"), - "6": combo("Wie viel?", "sub_wieviel", str_list(A("ex6_pool")), - [{"emoji": as_list(r)[0], "count": as_list(r)[1], - "noun": as_list(r)[2], "answer": as_list(r)[3]} - for r in as_list(A("ex6_data")) if len(as_list(r)) >= 4], - str_list(A("ex6_meaning")), "count"), - "7": combo("Zahlenreihe", "sub_reihe", str_list(A("ex7_pool")), - [{"before": as_list(r)[0], "after": as_list(r)[1], - "answer": as_list(r)[2]} - for r in as_list(A("ex7_data")) if len(as_list(r)) >= 3], - str_list(A("ex7_meaning")), "seq"), - "8": combo("Verb einsetzen", "sub_verb", str_list(A("ex8_pool")), - verb_items(A("ex8_data")), str_list(A("ex8_meaning")), - "verb"), - "9": { - "type": "choice", "title": "Wer? Wie? Wo?", "sub": "sub_wer", - "questions": choice_items(A("ex9_questions")), - "meanings": str_list(A("ex9_meaning")), - }, - "10": { - "type": "assembly", "title": "Wörter trennen", "sub": "sub_assembly", - "items": assembly_items(A("ex10_items")), - "meanings": str_list(A("ex10_meaning")), - }, - "11": { - "type": "assign", "title": "Grußformen", "sub": "sub_gruss", - "items": assign_items(A("ex11_items")), - "groups": str_list(A("ex11_groups")), - "meanings": str_list(A("ex11_meaning")), - }, - "12": combo("Was macht er/sie?", "sub_bild", str_list(A("ex12_pool")), - verb_clue_items(A("ex12_data")), - str_list(A("ex12_meaning")), "verbclue"), - "13": { - "type": "assign", "title": "Länder", "sub": "sub_land", - "items": assign_items(A("ex13_items")), - "groups": str_list(A("ex13_groups")), - "meanings": str_list(A("ex13_meaning")), - }, - }, - "vocab": { - "type": "vocab", "title": "Vokabeltraining", "sub": "sub_translate", - "sections": trans_sections(A("u1_trans_sections"), arrays), - }, - }, - { - "id": 1, - "title": "Aus aller Welt", - "page": "unit2", - "tag": "u2", - "sub": "unit2_sub", - "unlocked": True, - "names": [ - "Verben konjugieren", "aus oder in", "Fragewörter", "sprechen", - "Nationalitäten", "Woher?", "Länder schreiben", "Verben einsetzen", - "Freie Antwort", "Euro", "Wörter suchen", "Was ist richtig?", - "Ordne zu", "Lückentext", "Verbinde", "Zahlen", - "Steckbrief", "Berufe", "Nationalität", - ], - "branch": "u2vocab", - "exercises": { - "1": combo("Verben konjugieren", "sub_verben", str_list(A("g01_pool")), - [], [], "verb_sections", - sections=[ - {"title": "Peter Fritsch:", - "rows": verb_items(A("g01_peter")), - "meanings": str_list(A("g01_peter_mean"))}, - {"title": "Jana Nová und Pavol Korčák:", - "rows": verb_items(A("g01_jana")), - "meanings": str_list(A("g01_jana_mean"))}, - ], - transUpfront=True, revealGerman=True), - "2": { - "type": "choice", "title": "aus oder in", "sub": "sub_ausin", - "questions": choice_items(A("g02_rows")), - "meanings": str_list(A("g02_mean")), - }, - "3": { - "type": "choice", "title": "Fragewörter", "sub": "sub_wer", - "questions": choice_items(A("g03_rows")), - "meanings": str_list(A("g03_mean")), - }, - "4": combo("sprechen", "sub_sprich", str_list(A("g04_pool")), - verb_items(A("g04_rows")), str_list(A("g04_mean")), "verb"), - "5": { - "type": "typed", "title": "Nationalitäten", "sub": "sub_nation", - "rows": typed_items(A("g05_rows")), - "bank": as_str(A("g05_bank")[0]) if A("g05_bank") else - (as_str(arrays["g05_bank"][1][0]) if "g05_bank" in arrays - and arrays["g05_bank"][1] and isinstance(arrays["g05_bank"][1][0], str) - else None), - "answersNote": False, - }, - "6": { - "type": "typed", "title": "Woher?", "sub": "sub_woher", - "rows": typed_items(A("g06_rows")), - }, - "7": { - "type": "typed", "title": "Länder schreiben", "sub": "sub_laender", - "rows": typed_items(A("g07_rows")), - }, - "8": combo("Verben einsetzen", "sub_verb2", str_list(A("g08_pool")), - verb_items(A("g08_rows")), str_list(A("g08_mean")), "verb"), - "9": { - "type": "free", "title": "Freie Antwort", "sub": "sub_free", - "tip": "tip_ss", "questions": free_items(A("ex9_free_qs")), - }, - "10": combo("Euro", "sub_euro", str_list(A("g10_pool")), - verb_items(A("g10_rows")), str_list(A("g10_mean")), - "verb", preMeaning=True), - "11": { - "type": "typed", "title": "Wörter suchen", "sub": "sub_wortsuchen", - "rows": typed_items(A("g11_rows")), - }, - "12": { - "type": "choice", "title": "Was ist richtig?", "sub": "sub_verb2", - "questions": choice_items(A("g12_rows")), - "meanings": str_list(A("g12_mean")), - }, - "13": combo("Ordne zu", "sub_ordne", [], - ordne_items(A("g13_rows")), str_list(A("g13_mean")), - "ordne", - fwPool=str_list(A("g13_fw_pool")), - ansPool=str_list(A("g13_ans_pool"))), - "14": combo("Lückentext", "sub_luecke", str_list(A("g14_pool")), - verb_items(A("g14_rows")), str_list(A("g14_mean")), - "verb", preMeaning=True, gloss=str_list(A("g14_gloss"))), - "15": combo("Verbinde", "sub_verbinde", str_list(A("g15_pool")), - verb_items(A("g15_rows")), str_list(A("g15_mean")), - "verb", preMeaning=True, gloss=str_list(A("g15_gloss"))), - "16": combo("Zahlen", "sub_zahlpaar", str_list(A("g16_pool")), - verb_items(A("g16_rows")), str_list(A("g16_mean")), - "verb"), - "17": { - "type": "profile", "title": "Steckbrief", "sub": "sub_steckbrief", - "questions": profile_items(A("s01_rows")), - }, - "18": { - "type": "hangman", "title": "Berufe", "sub": "sub_berufe", - "words": str_list(A("hm_words")), - "tips": str_list(A("hm_tips")), - "letters": str_list(A("hm_letters")), - }, - "19": { - "type": "typed", "title": "Nationalität", "sub": "sub_bistdu", - "rows": typed_items(A("s03_rows")), - "answersNote": True, - }, - }, - "vocab": { - "type": "vocab", "title": "Vokabeltraining", "sub": "sub_translate", - "sections": trans_sections(A("u2_trans_sections"), arrays), - }, - }, - { - "id": 2, - "title": "Bei uns zu Hause", - "page": "unit3", - "tag": "u3", - "sub": "unit3_sub", - "unlocked": True, - "names": [ - "Familienpaare", "mein oder dein", "ein / kein", "Lückentext", - "Marcos Familie", "Sortieren", "Possessivtabelle", "Akkusativ", - "kein / nicht", "Sätze bauen", "Was siehst du?", "Wem gehört das?", - "Es gibt …", "Beschreiben", "Wochenende", - ], - "branch": "u3vocab", - "exercises": { - "1": combo("Familienpaare", "sub3_pair", str_list(A("ex1_u3_pool")), - fill_items(A("ex1_u3_rows")), [], "fill", - sample="Beispiel: der Vater ↔ die Mutter", - showGerman=False), - "2": { - "type": "ex2", "title": "mein oder dein", "sub": "sub3_poss", - "pool": str_list(A("ex2_u3_pool")), - "items": ex2_items(arrays), - }, - "3": combo("ein / kein", "sub3_haustier", str_list(A("ex3_u3_pool")), - fill_items(A("ex3_u3_rows")), [], "fill", - sample="Beispiel: Hast du eine Katze? – Nein, ich habe keine Katze. Ich habe einen Hund.", - showGerman=True), - "4": { - "type": "letters_gap", "title": "Lückentext", "sub": "sub3_buchst", - "rows": ex4row_items(A("ex4_u3_rows")), - }, - "5": { - "type": "typed", "title": "Marcos Familie", "sub": "sub3_marco", - "rows": typed_items(A("ex5_u3_rows")), - "bank": None, - }, - "6": { - "type": "assign", "title": "Sortieren", "sub": "sub3_sort", - "items": assign_items(A("ex6_u3_items")), - "groups": str_list(A("ex6_u3_groups")), - "meanings": str_list(A("ex6_u3_meaning")), - }, - "7": { - "type": "table", "title": "Possessivtabelle", "sub": "sub3_tabelle", - "persons": [ - "ich", "du", "er", "sie", "es", "wir", "ihr", "sie / Sie", - ], - "nouns": ["der Garten", "die Idee", "das Fest", "die Geschwister"], - "answers": [ - ["mein", "dein", "sein", "ihr", "sein", "unser", "euer", "ihr"], - ["meine", "deine", "seine", "ihre", "seine", "unsere", "eure", "ihre"], - ["mein", "dein", "sein", "ihr", "sein", "unser", "euer", "ihr"], - ["meine", "deine", "seine", "ihre", "seine", "unsere", "eure", "ihre"], - ], - }, - "8": combo("Akkusativ", "sub3_akk", str_list(A("ex8_u3_pool")), - fill_items(A("ex8_u3_rows")), str_list(A("ex8_u3_gloss")), - "fill", showGerman=True), - "9": combo("kein / nicht", "sub3_nicht", str_list(A("ex9_u3_pool")), - fill_items(A("ex9_u3_rows")), [], "fill", showGerman=True), - "10": { - "type": "assembly", "title": "Sätze bauen", "sub": "sub3_satz", - "items": assembly_items(A("ex10_u3_items")), - "meanings": str_list(A("ex10_u3_meaning")), - }, - "11": { - "type": "kw", "title": "Was siehst du?", "sub": "sub3_sehen", - "sample": "Beispiel: Ich sehe eine Burg. / Ich sehe ein Schloss.", - "rows": kw_items(A("ex11_u3_qs")), - }, - "12": combo("Wem gehört das?", "sub3_wem", str_list(A("ex12_u3_pool")), - fill_items(A("ex12_u3_rows")), [], "fill", showGerman=True), - "13": combo("Es gibt …", "sub3_gibt", str_list(A("ex13_u3_pool")), - fill_items(A("ex13_u3_rows")), [], "fill", showGerman=True), - "14": { - "type": "kw", "title": "Beschreiben", "sub": "sub3_saetze", - "sample": "Beispiel: Ich sehe einen Jungen. Er liest ein Buch.", - "rows": kw_items(A("ex14_u3_qs")), - }, - "15": { - "type": "letters", "title": "Wochenende", "sub": "sub3_wochen", - "rows": let_items(A("ex15_u3_rows")), - }, - }, - "vocab": { - "type": "vocab", "title": "Vokabeltraining", "sub": "sub_translate", - "sections": trans_sections(A("u3_trans_sections"), arrays), - }, - }, - ] - - locked_german = [ - "Schule und Freizeit", "Guten Appetit!", "Mein Tagesablauf", - "Meine Freunde", "Wir treffen uns in Salzburg", - "Mein Haus ist meine Burg", "Urlaub in Österreich", - ] - for i, title in enumerate(locked_german, start=3): - german_units.append({ - "id": i, "title": title, "page": None, "tag": None, - "sub": None, "unlocked": False, "names": [], - "exercises": {}, - }) - - # g05_bank is a single string, not an array of strings - if "g05_bank" in arrays: - raw = arrays["g05_bank"][1] - bank = None - if isinstance(raw, list) and raw and isinstance(raw[0], str) and len(raw) == 1: - bank = raw[0] - elif isinstance(raw, str): - bank = raw - if bank: - german_units[1]["exercises"]["5"]["bank"] = bank - - if "ex5_u3_bank" in arrays: - raw = arrays["ex5_u3_bank"][1] - if isinstance(raw, list) and raw and isinstance(raw[0], str): - german_units[2]["exercises"]["5"]["bank"] = raw[0] if len(raw) == 1 else " ".join( - x for x in raw if isinstance(x, str) - ) - - net_lessons = [] - for i in range(1, 28): - slides = slides_items(A(f"build_net_unit{i}_page.slides")) - qs = choice_items(A(f"net{i}_qs")) if i > 1 else [] - net_lessons.append({ - "id": i, - "titleKey": f"net_unit{i}", - "subKey": f"net_unit{i}_sub", - "exTitleKey": f"net_ex{i}_title" if i > 1 else "net_ex_title", - "quizHeadKey": f"net_quiz{i}_head" if i > 1 else None, - "slides": slides, - "quiz": qs, - }) - - def lit_pack(prefix): - lessons = [] - for i in range(1, 9): - fn_u = f"build_{prefix}_unit{i}_page" - fn_e = f"build_{prefix}_unit{i}_exercise_page" - quiz = choice_items(A(f"{fn_e}.qs")) - hints = str_list(A(f"{fn_e}.hints")) if f"{fn_e}.hints" in arrays else [] - for qi, q in enumerate(quiz): - if qi < len(hints) and hints[qi]: - q["expl"] = hints[qi] - lessons.append({ - "id": i, - "titleKey": f"{prefix}_unit{i}", - "subKey": f"{prefix}_unit{i}_sub", - "exTitleKey": f"{prefix}_ex{i}_title", - "quizHeadKey": f"{prefix}_quiz{i}_head", - "slides": slides_items(A(f"{fn_u}.slides")), - "quiz": quiz, - }) - return lessons - - lit_lessons = lit_pack("lit") - lit2_lessons = lit_pack("lit2") - lit3_lessons = lit_pack("lit3") - lit4_lessons = lit_pack("lit4") - chem_lessons = lit_pack("chem") - bio_lessons = lit_pack("bio") - net2_lessons = lit_pack("net2") - net3_lessons = lit_pack("net3") - net4_lessons = lit_pack("net4") - hw2_lessons = lit_pack("hw2") - hw3_lessons = lit_pack("hw3") - hw4_lessons = lit_pack("hw4") - fyz_lessons = lit_pack("fyz") - fyz2_lessons = lit_pack("fyz2") - fyz3_lessons = lit_pack("fyz3") - fyz4_lessons = lit_pack("fyz4") - - def math_pack(prefix): - lessons = [] - for i in range(1, 9): - fn_u = f"build_{prefix}_unit{i}_page" - fn_e = f"build_{prefix}_unit{i}_exercise_page" - lessons.append({ - "id": i, - "titleKey": f"{prefix}_unit{i}", - "subKey": f"{prefix}_unit{i}_sub", - "exTitleKey": f"{prefix}_ex{i}_title", - "quizHeadKey": f"{prefix}_quiz{i}_head", - "slides": slides_items(A(f"{fn_u}.slides")), - "problems": math_items(A(f"{fn_e}.qs")), - }) - return lessons - - mat0_lessons = math_pack("mat0") - mat_lessons = math_pack("mat") - mat2_lessons = math_pack("mat2") - mat3_lessons = math_pack("mat3") - mat4_lessons = math_pack("mat4") - - on_lessons = [] - for i in range(1, 18): - on_lessons.append({ - "id": i, - "titleKey": f"on_unit{i}", - "subKey": f"on_unit{i}_sub", - "exTitleKey": f"on_ex{i}_title", - "quizHeadKey": f"on_quiz{i}_head", - "slides": slides_items(A(f"build_on_unit{i}_page.slides")), - "quiz": choice_items(A(f"build_on_unit{i}_exercise_page.qs")), - }) - - on2_lessons = [] - for i in range(1, 17): - on2_lessons.append({ - "id": i, - "titleKey": f"on2_unit{i}", - "subKey": f"on2_unit{i}_sub", - "exTitleKey": f"on2_ex{i}_title", - "quizHeadKey": f"on2_quiz{i}_head", - "slides": slides_items(A(f"build_on2_unit{i}_page.slides")), - "quiz": choice_items(A(f"build_on2_unit{i}_exercise_page.qs")), - }) - - on3_lessons = [] - for i in range(1, 17): - on3_lessons.append({ - "id": i, - "titleKey": f"on3_unit{i}", - "subKey": f"on3_unit{i}_sub", - "exTitleKey": f"on3_ex{i}_title", - "quizHeadKey": f"on3_quiz{i}_head", - "slides": slides_items(A(f"build_on3_unit{i}_page.slides")), - "quiz": choice_items(A(f"build_on3_unit{i}_exercise_page.qs")), - }) - - on4_lessons = [] - for i in range(1, 17): - on4_lessons.append({ - "id": i, - "titleKey": f"on4_unit{i}", - "subKey": f"on4_unit{i}_sub", - "exTitleKey": f"on4_ex{i}_title", - "quizHeadKey": f"on4_quiz{i}_head", - "slides": slides_items(A(f"build_on4_unit{i}_page.slides")), - "quiz": choice_items(A(f"build_on4_unit{i}_exercise_page.qs")), - }) - - hw_lessons = [] - for i in range(1, 30): - hw_lessons.append({ - "id": i, - "titleKey": f"hw_unit{i}", - "subKey": f"hw_unit{i}_sub", - "exTitleKey": f"hw_ex{i}_title", - "quizHeadKey": f"hw_quiz{i}_head", - "slides": slides_items(A(f"build_hw_unit{i}_page.slides")), - "quiz": choice_items(A(f"build_hw_unit{i}_exercise_page.qs")), - }) - - mluv_meta = [ - (1, "typed", "Pravopis – i/y po obojetných souhláskách", - "Doplňte i/í nebo y/ý.", None, "e1_items"), - (2, "choice", "Pravopis – velká/malá písmena", - "Vyberte správnou variantu.", None, "e2_qs"), - (3, "typed", "Slovní druhy", - "Určete slovní druh podtržených slov.", - "Do pole napište název slovního druhu.", "e3_items"), - (4, "typed", "Mluvnické kategorie – podstatná jména", - "Určete rod, číslo a pád podtržených slov.", - "Vyplňte tři pole: rod, číslo a pád.", "e4_items"), - (5, "typed", "Mluvnické kategorie – slovesa", - "Určete osobu, číslo, čas a způsob u těchto sloves.", - "U rozkazovacího a podmiňovacího způsobu napište do pole čas „neurčitý“.", - "e5_items"), - (6, "reveal", "Slovotvorba", "Rozeberte slova na morfémy.", - "Určete předponu, kořen, příponu a koncovku.", "e6_items"), - (7, "typed", "Větné členy", - "Určete větný člen podtržených výrazů.", None, "e7_items"), - (8, "typed", "Druhy vedlejších vět", - "Určete druh vedlejší věty.", None, "e8_items"), - (9, "typed", "Synonyma", "Ke každému slovu napište synonymum.", None, "e9_items"), - (10, "typed", "Antonyma", "Napište opak.", None, "e10_items"), - (11, "typed", "Pravopis – s/z na začátku slova", - "Vyberte správnou předponu s-/z-.", None, "e11_items"), - (12, "reveal", "Skladba – najděte chybu", - "Každá věta obsahuje jednu chybu. Najděte ji a opravte.", None, "e12_items"), - (13, "typed", "Tvarosloví – správný tvar", - "Dejte slovo do správného tvaru.", None, "e13_items"), - (14, "choice", "Výběr ze čtyř možností", - "Vyberte správnou odpověď.", None, "e14_qs"), - (15, "reveal", "Přímá a nepřímá řeč", - "Přepište přímou řeč na nepřímou.", None, "e15_items"), - (16, "reveal", "Slovní zásoba – rozdíly", - "Vysvětlete rozdíl mezi těmito dvojicemi slov.", None, "e16_items"), - (17, "reveal", "Interpunkce", - "Doplňte čárky tam, kde patří.", None, "e17_items"), - (18, "typed", "Obrazná pojmenování", - "Určete, o jaký druh obrazného pojmenování jde.", None, "e18_items"), - (19, "typed", "Stylistika – slohové útvary", - "Přiřaďte ukázku ke správnému slohovému útvaru.", None, "e19_items"), - (20, "choice", "Souhrnné opakování", - "Vyberte správnou odpověď.", None, "e20_qs"), - ] - mluv_names = [ - "i/y", "Velká písmena", "Slovní druhy", "Podst. jména", "Slovesa", - "Slovotvorba", "Větné členy", "Vedlejší věty", "Synonyma", "Antonyma", - "s/z", "Najdi chybu", "Tvary", "Test A–D", "Přímá řeč", - "Rozdíly", "Interpunkce", "Obrazná pojmen.", "Slohové útvary", - "Opakování", - ] - mluvnice = [] - for n, kind, title, sub, note, key in mluv_meta: - item = {"id": n, "name": mluv_names[n - 1], "type": kind, - "title": title, "sub": sub, "note": note} - if kind == "typed": - item["items"] = mluv_items(A(key)) - elif kind == "reveal": - item["items"] = reveal_items(A(key)) - else: - item["questions"] = choice_items(A(key)) - expl_key = key.replace("_qs", "_expl") - if expl_key in arrays: - item["expls"] = str_list(A(expl_key)) - mluvnice.append(item) - - def note_lines(fn, name): - return str_list(A(f"{fn}.{name}")) - - catalog_path = ROOT / "data" / "cetba-catalog.json" - catalog = json.loads(catalog_path.read_text(encoding="utf-8")) - - full_books = { - "1984": { - "subKey": "cetba1984_sub", - "page": "cetba1984", - "quizTitle": "lit_quiz_title", - "quizSub": "lit_quiz_sub", - "plotTitle": "lit_plot_title", - "plotSub": "lit_plot_sub", - "notes": [ - {"title": "O knize", "icon": "book", - "lines": note_lines("build_cetba1984_page", "about")}, - {"title": "Svět a strana", "icon": "globe", - "lines": note_lines("build_cetba1984_page", "world")}, - {"title": "Postavy", "icon": "people", - "lines": note_lines("build_cetba1984_page", "people")}, - {"title": "Klíčové pojmy", "icon": "bulb", - "lines": note_lines("build_cetba1984_page", "terms")}, - ], - "quiz": lit_items(A("lit_qs")), - "plot": assembly_items(A("lit_plot_items")), - "plotMeaning": str_list(A("lit_plot_meaning")), - }, - "fuks": { - "subKey": "cetbaFuks_sub", - "page": "cetbaFuks", - "quizTitle": "lit_fuks_quiz_title", - "quizSub": "lit_fuks_quiz_sub", - "plotTitle": "lit_fuks_plot_title", - "plotSub": "lit_fuks_plot_sub", - "notes": [ - {"title": "O knize", "icon": "book", - "lines": note_lines("build_cetba_fuks_page", "about")}, - {"title": "Doba a svět", "icon": "globe", - "lines": note_lines("build_cetba_fuks_page", "world")}, - {"title": "Postavy", "icon": "people", - "lines": note_lines("build_cetba_fuks_page", "people")}, - {"title": "Klíčové motivy", "icon": "bulb", - "lines": note_lines("build_cetba_fuks_page", "terms")}, - ], - "quiz": lit_items(A("fuks_qs")), - "plot": assembly_items(A("fuks_plot_items")), - "plotMeaning": str_list(A("fuks_plot_meaning")), - }, - } - - books = [] - cetba_dir = ROOT / "data" / "cetba" - for entry in catalog: - bid = entry["id"] - display = f"{entry['author']} – {entry['title']}" - page = entry.get("page") or f"cetba_{bid.replace('-', '_')}" - content_path = cetba_dir / f"{bid}.json" - disk = None - if content_path.exists(): - disk = json.loads(content_path.read_text(encoding="utf-8")) - - if bid in full_books and not disk: - book = {"id": bid, "title": display, **full_books[bid]} - book["genre"] = entry.get("genre", "") - books.append(book) - continue - - if disk: - notes = disk.get("notes") or [] - quiz = disk.get("quiz") or [] - plot = disk.get("plot") or [] - plot_meaning = disk.get("plotMeaning") or [] - book = { - "id": bid, - "title": display, - "subKey": "cetba1984_sub" if quiz else "cetba_entry_sub", - "page": page if not entry.get("full") else (entry.get("page") or page), - "genre": entry.get("genre", ""), - "quizTitle": "book_quiz_heading" if quiz else "", - "quizSub": "lit_quiz_sub" if quiz else "", - "plotTitle": "lit_plot_title" if plot else "", - "plotSub": "lit_plot_sub" if plot else "", - "notes": notes, - "quiz": quiz, - "plot": plot, - "plotMeaning": plot_meaning, - } - if bid in full_books: - # Keep stable page ids for the two classic GTK screens - book["page"] = full_books[bid]["page"] - book["subKey"] = full_books[bid]["subKey"] - book["quizTitle"] = full_books[bid]["quizTitle"] - book["quizSub"] = full_books[bid]["quizSub"] - book["plotTitle"] = full_books[bid]["plotTitle"] - book["plotSub"] = full_books[bid]["plotSub"] - books.append(book) - continue - - about = [f"Autor: {entry['author']}", f"Žánr: {entry['genre']}"] - if entry.get("translator"): - about.append(f"Překlad: {entry['translator']}") - about.append("Ze školního seznamu maturitní četby.") - books.append({ - "id": bid, - "title": display, - "subKey": "cetba_entry_sub", - "page": page, - "genre": entry["genre"], - "quizTitle": "", - "quizSub": "", - "plotTitle": "", - "plotSub": "", - "notes": [ - {"title": "O knize", "icon": "book", "lines": about}, - ], - "quiz": [], - "plot": [], - "plotMeaning": [], - }) - - # Prefer disk content for 1984/fuks when present (already handled above). - # GTK catalog: mark full when we have quiz content on disk or classic pages. - has_full = {b["id"] for b in books if b.get("quiz")} - - # GTK catalog include for the reading-list path map - inc_lines = [ - "/* Generated from data/cetba-catalog.json – do not edit by hand. */", - f"#define BOOK_NODES {len(catalog)}", - "", - "typedef struct {", - " const char *title;", - " const char *target;", - " const char *author;", - " const char *work;", - " const char *genre;", - " const char *translator;", - " int full;", - "} BookDef;", - "", - "static const BookDef book_defs[BOOK_NODES] = {", - ] - for entry in catalog: - bid = entry["id"] - display = f"{entry['author']} – {entry['title']}" - page = entry.get("page") or f"cetba_{bid.replace('-', '_')}" - if bid in ("1984", "fuks") or entry.get("full"): - target = entry.get("page") or page - full = 1 - elif bid in has_full: - # Data-driven books still open the shared stub page for now; - # Swift/Android use content.json fully. - target = "cetbastub" - full = 0 - else: - target = "cetbastub" - full = 0 - transl = entry.get("translator") or "" - def c_str(s: str) -> str: - return '"' + s.replace("\\", "\\\\").replace('"', '\\"') + '"' - transl_c = "NULL" if not transl else c_str(transl) - inc_lines.append( - f" {{{c_str(display)}, {c_str(target)}, {c_str(entry['author'])}, " - f"{c_str(entry['title'])}, {c_str(entry['genre'])}, {transl_c}, {full}}}," - ) - inc_lines.append("};") - inc_lines.append("") - (SRC / "cetba_catalog.inc").write_text("\n".join(inc_lines) + "\n", encoding="utf-8") - - # Full note packs for the GTK stub/detail page (Swift/Android use content.json). - def c_escape(s: str) -> str: - return s.replace("\\", "\\\\").replace('"', '\\"') - - notes_lines = [ - "/* Generated from data/cetba JSON packs – do not edit by hand. */", - "", - "typedef struct {", - " const char *title;", - " const char *const *lines;", - "} BookNoteSec;", - "", - "typedef struct {", - " const BookNoteSec *secs;", - " int nsec;", - "} BookNotePack;", - "", - ] - pack_entries = [] - for i, entry in enumerate(catalog): - bid = entry["id"] - safe = re.sub(r"[^a-zA-Z0-9_]", "_", bid) - content_path = cetba_dir / f"{bid}.json" - notes = [] - if content_path.exists(): - disk = json.loads(content_path.read_text(encoding="utf-8")) - notes = disk.get("notes") or [] - if not notes: - about = [f"Autor: {entry['author']}", f"Žánr: {entry['genre']}"] - if entry.get("translator"): - about.append(f"Překlad: {entry['translator']}") - notes = [{"title": "O knize", "lines": about}] - sec_names = [] - for si, note in enumerate(notes): - arr = f"book_{safe}_n{si}" - notes_lines.append(f"static const char *const {arr}[] = {{") - for line in note.get("lines") or []: - notes_lines.append(f' "{c_escape(line)}",') - notes_lines.append(" NULL") - notes_lines.append("};") - notes_lines.append("") - sec_names.append((note.get("title") or "Poznámky", arr)) - secs_arr = f"book_{safe}_secs" - notes_lines.append(f"static const BookNoteSec {secs_arr}[] = {{") - for title, arr in sec_names: - notes_lines.append(f' {{"{c_escape(title)}", {arr}}},') - notes_lines.append("};") - notes_lines.append("") - pack_entries.append(f" {{{secs_arr}, {len(sec_names)}}}") - notes_lines.append(f"static const BookNotePack book_note_packs[BOOK_NODES] = {{") - notes_lines.append(",\n".join(pack_entries)) - notes_lines.append("};") - notes_lines.append("") - (SRC / "cetba_book_notes.inc").write_text("\n".join(notes_lines) + "\n", encoding="utf-8") - - # Quiz + plot packs for the GTK stub pages (shared by every catalog book). - ex_lines = [ - "/* Generated from data/cetba JSON packs – do not edit by hand. */", - "/* Requires LitQ (cetba.c) and AssemblyItem (graduately.h). */", - "", - "typedef struct {", - " const LitQ *qs;", - " int nq;", - " const AssemblyItem *plot;", - " const char **plot_meaning;", - " int nplot;", - "} BookExPack;", - "", - ] - ex_pack_entries = [] - for entry in catalog: - bid = entry["id"] - safe = re.sub(r"[^a-zA-Z0-9_]", "_", bid) - content_path = cetba_dir / f"{bid}.json" - disk = {} - if content_path.exists(): - disk = json.loads(content_path.read_text(encoding="utf-8")) - quiz = disk.get("quiz") or [] - plot = disk.get("plot") or [] - plot_meaning = disk.get("plotMeaning") or [] - - qs_name = f"book_{safe}_qs" - if quiz: - ex_lines.append(f"static const LitQ {qs_name}[] = {{") - for q in quiz[:32]: - opts = (q.get("options") or []) + ["", "", "", ""] - ex_lines.append(" {") - ex_lines.append(f' "{c_escape(q.get("prompt") or "")}",') - ex_lines.append(" {") - for o in opts[:4]: - ex_lines.append(f' "{c_escape(o)}",') - ex_lines.append(" },") - ex_lines.append(f' {int(q.get("correct") or 0)},') - ex_lines.append(f' "{c_escape(q.get("expl") or "")}",') - ex_lines.append(" },") - ex_lines.append("};") - ex_lines.append("") - nq = min(len(quiz), 32) - qs_ref = qs_name - else: - nq = 0 - qs_ref = "NULL" - - plot_name = f"book_{safe}_plot" - mean_name = f"book_{safe}_plot_meaning" - if plot and isinstance(plot[0], dict): - words = (plot[0].get("words") or [])[:6] - while len(words) < 6: - words.append("") - prompt = plot[0].get("prompt") or "Přetáhněte části příběhu do správného pořadí:" - nwords = sum(1 for w in words if w) - ex_lines.append(f"static const AssemblyItem {plot_name}[] = {{") - ex_lines.append(" {") - ex_lines.append(f' "{c_escape(prompt)}",') - ex_lines.append(" {") - for w in words: - ex_lines.append(f' "{c_escape(w)}",') - ex_lines.append(" },") - ex_lines.append(f" {nwords},") - ex_lines.append(" },") - ex_lines.append("};") - ex_lines.append("") - meaning = plot_meaning[0] if plot_meaning else "" - ex_lines.append(f"static const char *{mean_name}[] = {{") - ex_lines.append(f' "{c_escape(meaning)}",') - ex_lines.append("};") - ex_lines.append("") - plot_ref = plot_name - mean_ref = mean_name - nplot = 1 - else: - plot_ref = "NULL" - mean_ref = "NULL" - nplot = 0 - - ex_pack_entries.append( - f" {{{qs_ref}, {nq}, {plot_ref}, {mean_ref}, {nplot}}}" - ) - - ex_lines.append("static const BookExPack book_ex_packs[BOOK_NODES] = {") - ex_lines.append(",\n".join(ex_pack_entries)) - ex_lines.append("};") - ex_lines.append("") - (SRC / "cetba_book_exercises.inc").write_text("\n".join(ex_lines) + "\n", encoding="utf-8") - - def en_text(name): - if name not in arrays: - return None - raw = A(name) - if isinstance(raw, list): - parts = [x for x in raw if isinstance(x, str)] - return parts[0] if len(parts) == 1 else ("\n".join(parts) if parts else None) - return raw if isinstance(raw, str) else None - - def en_choice(name): - if name not in arrays: - return [] - quiz = choice_items(A(name)) - hint_name = name + "_hints" - hints = str_list(A(hint_name)) if hint_name in arrays else [] - for qi, q in enumerate(quiz): - if qi < len(hints) and hints[qi]: - q["expl"] = hints[qi] - return quiz - - def skill_year(tag, year, count): - lessons = [] - for i in range(1, count + 1): - prefix = f"{tag}_y{year}_l{i}" - write = str_list(A(f"{prefix}_write")) if f"{prefix}_write" in arrays else [] - writing = None - if len(write) >= 3: - writing = { - "prompt": write[0], - "model": write[1], - "keys": write[2], - "minWords": int(write[3]) if len(write) > 3 and str(write[3]).isdigit() else 20, - } - lessons.append({ - "id": i, - "titleKey": f"{tag}_y{year}_u{i}", - "subKey": f"{tag}_y{year}_u{i}_sub", - "slides": slides_items(A(f"{prefix}_slides")), - "reading": en_text(f"{prefix}_read"), - "readQuiz": en_choice(f"{prefix}_readq"), - "listening": en_text(f"{prefix}_listen"), - "listenQuiz": en_choice(f"{prefix}_listenq"), - "gaps": typed_items(A(f"{prefix}_gaps")) if f"{prefix}_gaps" in arrays else [], - "writing": writing, - "quiz": en_choice(f"{prefix}_quiz"), - }) - return lessons - - en_lessons = skill_year("en", 1, 8) - en2_lessons = skill_year("en", 2, 8) - en3_lessons = skill_year("en", 3, 8) - en4_lessons = skill_year("en", 4, 8) - de_lessons = skill_year("de", 1, 6) - de2_lessons = skill_year("de", 2, 6) - de3_lessons = skill_year("de", 3, 6) - de4_lessons = skill_year("de", 4, 6) - - subjects = [ - {"key": "Deutsch", "open": True, "target": "dehome", "icon": "de"}, - {"key": "Správa počítačových sítí", "open": True, "target": "netyears", "icon": "wifi"}, - {"key": "Technické vybavení", "open": True, "target": "hwyears", "icon": "chip"}, - {"key": "Český jazyk a literatura", "open": True, "target": "czechmap", "icon": "cz"}, - {"key": "Občanská nauka", "open": True, "target": "onyears", "icon": "people"}, - {"key": "English", "open": True, "target": "enyears", "icon": "uk"}, - {"key": "Matematika", "open": True, "target": "matyears", "icon": "function"}, - {"key": "Fyzika", "open": True, "target": "fyzyears", "icon": "bolt"}, - {"key": "Základy Přírodopisných věd", "open": True, "target": "scimap", "icon": "flask"}, - {"key": "Technická grafika", "open": False, "target": None, "icon": "lock"}, - {"key": "Prezentační grafika", "open": False, "target": None, "icon": "lock"}, - {"key": "Programování", "open": False, "target": None, "icon": "lock"}, - {"key": "Programové vybavení", "open": False, "target": None, "icon": "lock"}, - ] - - payload = { - "i18n": i18n, - "subjects": subjects, - "german": german_units, - "net": { - "lessons": net_lessons, - "tasks": net_tasks(A("net_tasks")), - "answers": net_ans(A("net_ans")), - }, - "hw": hw_lessons, - "net2": net2_lessons, - "net3": net3_lessons, - "net4": net4_lessons, - "hw2": hw2_lessons, - "hw3": hw3_lessons, - "hw4": hw4_lessons, - "on": on_lessons, - "lit": lit_lessons, - "lit2": lit2_lessons, - "lit3": lit3_lessons, - "lit4": lit4_lessons, - "chem": chem_lessons, - "bio": bio_lessons, - "fyz": fyz_lessons, - "fyz2": fyz2_lessons, - "fyz3": fyz3_lessons, - "fyz4": fyz4_lessons, - "mat0": mat0_lessons, - "mat": mat_lessons, - "mat2": mat2_lessons, - "mat3": mat3_lessons, - "mat4": mat4_lessons, - "on2": on2_lessons, - "on3": on3_lessons, - "on4": on4_lessons, - "en": en_lessons, - "en2": en2_lessons, - "en3": en3_lessons, - "en4": en4_lessons, - "de": de_lessons, - "de2": de2_lessons, - "de3": de3_lessons, - "de4": de4_lessons, - "mluvnice": mluvnice, - "books": books, - "changelog": parse_changelog(ROOT / "data" / "changelog.txt"), - } - - # Fix single-string banks stored as char* "arrays" - for key in ("g05_bank", "ex5_u3_bank"): - if key not in arrays: - continue - raw = arrays[key][1] - if isinstance(raw, list) and len(raw) == 1 and isinstance(raw[0], str) and " " in raw[0]: - if key == "g05_bank": - german_units[1]["exercises"]["5"]["bank"] = raw[0] - else: - german_units[2]["exercises"]["5"]["bank"] = raw[0] - - text = json.dumps(payload, ensure_ascii=False, indent=2) - for dest in OUTS: - dest.parent.mkdir(parents=True, exist_ok=True) - dest.write_text(text, encoding="utf-8") - - def count(path, pred): - node = payload - for p in path: - node = node[p] - return sum(1 for x in node if pred(x)) - - print("wrote " + ", ".join(str(dest) for dest in OUTS)) - print(f" i18n keys: {len(i18n)}") - print(f" german unlocked exercises: " - f"{sum(len(u.get('exercises', {})) for u in german_units if u['unlocked'])}") - print(f" net lessons with slides: {sum(1 for L in net_lessons if L['slides'])}") - print(f" net quizzes: {sum(1 for L in net_lessons if L['quiz'])}") - print(f" hw lessons: {sum(1 for L in hw_lessons if L['slides'])}") - print(f" on lessons: {sum(1 for L in on_lessons if L['slides'])}") - print(f" lit lessons: {sum(1 for L in lit_lessons + lit2_lessons + lit3_lessons + lit4_lessons if L['slides'])}") - print(f" chem lessons: {sum(1 for L in chem_lessons if L['slides'])}") - print(f" bio lessons: {sum(1 for L in bio_lessons if L['slides'])}") - print(f" fyz lessons: {sum(1 for L in fyz_lessons + fyz2_lessons + fyz3_lessons + fyz4_lessons if L['slides'])}") - print(f" math lessons: {sum(1 for L in mat0_lessons + mat_lessons + mat2_lessons + mat3_lessons + mat4_lessons if L['slides'])}") - print(f" on2 lessons: {sum(1 for L in on2_lessons if L['slides'])}") - print(f" on3 lessons: {sum(1 for L in on3_lessons if L['slides'])}") - print(f" on4 lessons: {sum(1 for L in on4_lessons if L['slides'])}") - print(f" mluvnice: {len(mluvnice)}") - print(f" books quiz items: {[len(b['quiz']) for b in books]}") - print(f" changelog entries: {len(payload.get('changelog', []))}") - missing = [] - for u in german_units: - if not u["unlocked"]: - continue - for k, ex in u["exercises"].items(): - t = ex["type"] - if t == "choice" and not ex.get("questions"): - missing.append(f"{u['tag']}e{k} choice") - if t == "typed" and not ex.get("rows"): - missing.append(f"{u['tag']}e{k} typed") - if t == "assembly" and not ex.get("items"): - missing.append(f"{u['tag']}e{k} assembly") - if t == "vocab" and not ex.get("sections"): - missing.append(f"{u['tag']} vocab") - if t == "fill" and not ex.get("rows"): - missing.append(f"{u['tag']}e{k} fill") - if t == "hangman" and not ex.get("words"): - missing.append(f"{u['tag']}e{k} hangman") - if u.get("vocab") and not u["vocab"].get("sections"): - missing.append(f"{u['tag']} vocab sections") - for L in net_lessons: - if not L["slides"]: - missing.append(f"net{L['id']} slides") - if L["id"] > 1 and not L["quiz"]: - missing.append(f"net{L['id']} quiz") - for L in hw_lessons: - if not L["slides"]: - missing.append(f"hw{L['id']} slides") - if not L["quiz"]: - missing.append(f"hw{L['id']} quiz") - for L in on_lessons: - if not L["slides"]: - missing.append(f"on{L['id']} slides") - if not L["quiz"]: - missing.append(f"on{L['id']} quiz") - for L in on2_lessons: - if not L["slides"]: - missing.append(f"on2{L['id']} slides") - if not L["quiz"]: - missing.append(f"on2{L['id']} quiz") - for L in on3_lessons: - if not L["slides"]: - missing.append(f"on3{L['id']} slides") - if not L["quiz"]: - missing.append(f"on3{L['id']} quiz") - for L in on4_lessons: - if not L["slides"]: - missing.append(f"on4{L['id']} slides") - if not L["quiz"]: - missing.append(f"on4{L['id']} quiz") - for label, block in ( - ("lit", lit_lessons), ("lit2", lit2_lessons), - ("lit3", lit3_lessons), ("lit4", lit4_lessons), - ("chem", chem_lessons), ("bio", bio_lessons), - ("fyz", fyz_lessons), ("fyz2", fyz2_lessons), - ("fyz3", fyz3_lessons), ("fyz4", fyz4_lessons), - ): - for L in block: - if not L["slides"]: - missing.append(f"{label}{L['id']} slides") - if len(L["quiz"]) < 4: - missing.append(f"{label}{L['id']} quiz") - if not all(q.get("expl") for q in L["quiz"]): - missing.append(f"{label}{L['id']} expl") - for label, block in ( - ("mat0", mat0_lessons), ("mat", mat_lessons), - ("mat2", mat2_lessons), ("mat3", mat3_lessons), ("mat4", mat4_lessons), - ): - for L in block: - if len(L["slides"]) != 3: - missing.append(f"{label}{L['id']} slides") - if not L["problems"]: - missing.append(f"{label}{L['id']} problems") - if not all(p.get("prompt") and p.get("answer") and p.get("hint") for p in L["problems"]): - missing.append(f"{label}{L['id']} answer") - for m in mluvnice: - if m["type"] in ("typed", "reveal") and not m.get("items"): - missing.append(f"mluv{m['id']}") - if m["type"] == "choice" and not m.get("questions"): - missing.append(f"mluv{m['id']}") - if missing: - print("MISSING:") - for m in missing: - print(" ", m) - return 1 - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/scripts/gen-english.py b/scripts/gen-english.py deleted file mode 100644 index 402f3b6..0000000 --- a/scripts/gen-english.py +++ /dev/null @@ -1,2541 +0,0 @@ -#!/usr/bin/env python3 -"""Generate src/english_lessons.inc and src/english_i18n.inc. - -Curriculum: four-year gymnasium English (RVP G, cizí jazyk, aiming at -maturita B1 and the CERMAT catalogue). Year 1 is A2, year 2 B1, -year 3 B1+, year 4 B2 exam skills. Texts are original. -""" - -from __future__ import annotations - -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] - - -def norm(s: str) -> str: - out = [] - space = False - for ch in s.lower(): - if ch.isalnum(): - out.append(ch) - space = False - elif ch.isspace(): - if out and not space: - out.append(" ") - space = True - return "".join(out).strip() - - -def has_word(text: str, word: str) -> bool: - n = f" {norm(text)} " - w = norm(word) - return f" {w} " in n - - -def words(text: str) -> int: - n = norm(text) - return len(n.split()) if n else 0 - - -def c_str(s: str) -> str: - esc = ( - s.replace("\\", "\\\\") - .replace('"', '\\"') - .replace("\n", "\\n") - .replace("\t", "\\t") - ) - return f'"{esc}"' - - -def Q(prompt, options, correct, hint): - if len(options) != 4: - raise SystemExit(f"need 4 options: {prompt}") - if not 0 <= correct < 4: - raise SystemExit(f"bad correct: {prompt}") - return (prompt, options, correct, hint) - - -def G(prompt, answers, meaning): - return (prompt, answers, meaning) - - -def W(prompt, model, keys, min_words): - for key in keys.split("|"): - if not has_word(model, key): - raise SystemExit(f"model misses keyword {key!r}: {prompt[:40]}") - if words(model) < min_words: - raise SystemExit(f"model shorter than {min_words}: {prompt[:40]}") - return (prompt, model, keys, min_words) - - -def S(kicker, title, tip, lines): - return (kicker, title, tip, lines) - - -def L(title_cs, title_en, sub_cs, sub_en, slides, **parts): - return { - "title_cs": title_cs, - "title_en": title_en, - "sub_cs": sub_cs, - "sub_en": sub_en, - "slides": slides, - **parts, - } - - -YEARS = [ - { - "sub_cs": "Osobní život, škola, domov a minulost. Úroveň A2.", - "sub_en": "Personal life, school, home and the past. Level A2.", - "lessons": [ - L( - "Já a moje rodina", - "Me and my family", - "Sloveso be, have got a přivlastňovací zájmena. Doplňování a kvíz.", - "The verb be, have got and possessives. Gaps and a quiz.", - [ - S( - "1 / 2 • Be", - "Kdo jsem", - "Tip: věk se říká slovesem be. „She has 16 years“ je čechismus.", - [ - "I am, you are, he/she/it is, we/you/they are.", - "Zápor a otázka: She isn't tall. Are you from Prague?", - "Věk, povolání i nálada: I am 16. My mum is a nurse. I am fine.", - "Přivlastňovací zájmena: my, your, his, her, its, our, their.", - ], - ), - S( - "2 / 2 • Have got", - "Co mám", - "Tip: have got je britská hovorová vazba pro vlastnictví, ne pro věk.", - [ - "I've got a younger brother. She hasn't got a pet.", - "Have you got any cousins? — Yes, I have. / No, I haven't.", - "V americké angličtině stačí have: I have a brother.", - "Rodina: parents, siblings, only child, get on well, look like.", - ], - ), - ], - gaps=[ - G("My sister ___ sixteen.", "is", "Věk: be, ne have."), - G("___ you got a bike?", "Have", "Otázka s have got."), - G("This is ___ grandmother. She lives with us.", "our", "Přivlastňovací zájmeno."), - G("They ___ not from Brno. They are from Olomouc.", "are", "They + are."), - G("He ___ got a dog, but he has got two cats.", "hasn't|has not", "Zápor have got."), - ], - quiz=[ - Q( - "Which sentence is correct?", - ["She has 16 years.", "She is 16 years old.", "She is 16 years.", "She has 16 years old."], - 1, - "Věk: be + years old.", - ), - Q( - "I ___ two cousins and one aunt.", - ["am", "have got", "has got", "is"], - 1, - "Vlastnictví v 1. osobě: have got.", - ), - Q( - "Eva is my sister. ___ room is next to mine.", - ["She", "Her", "His", "Hers"], - 1, - "Před podstatným jménem je her, ne she.", - ), - Q( - "___ your parents at home?", - ["Is", "Are", "Have", "Do"], - 1, - "Parents je množné číslo: Are.", - ), - ], - ), - L( - "Školní den", - "A school day", - "Přítomný čas prostý. Čtení a doplňování.", - "The present simple. Reading and gaps.", - [ - S( - "1 / 2 • Present simple", - "Co dělám pravidelně", - "Tip: ve 3. osobě jednotného čísla přibývá -s/-es: she watches.", - [ - "I get up at seven. He gets up at six.", - "Zápor: I don't like maths. She doesn't eat meat.", - "Otázka: Do you walk to school? Does she play the piano?", - "Příslovce četnosti stojí před slovesem: I usually walk. She is always late.", - ], - ), - S( - "2 / 2 • Škola", - "Rozvrh a přestávky", - "Tip: předmět ve škole je bez členu, když mluvíme obecně: I like biology.", - [ - "lessons, break, canteen, homework, timetable, subject.", - "Čas: at eight, at half past twelve, in the morning, on Monday.", - "because vysvětluje důvod: I like biology because we do experiments.", - "never / sometimes / often / usually / always.", - ], - ), - ], - reading=( - "My school day starts early. I get up at half past six, have breakfast " - "and catch the tram. Lessons begin at eight. On Monday we have maths, " - "English and biology. I like biology because we do experiments, but I " - "don't like maths. We have lunch at half past twelve in the canteen. " - "After school I do my homework or meet friends. I never go to bed after " - "ten on a school night." - ), - readq=[ - Q( - "What time do lessons begin?", - ["At half past six", "At eight", "At half past twelve", "At ten"], - 1, - "Lessons begin at eight.", - ), - Q( - "Why does the writer like biology?", - [ - "Because it is easy", - "Because they do experiments", - "Because the teacher is funny", - "Because there is no homework", - ], - 1, - "because we do experiments.", - ), - Q( - "Where do they have lunch?", - ["At home", "On the tram", "In the canteen", "In the park"], - 2, - "in the canteen.", - ), - Q( - "On a school night the writer goes to bed…", - ["after eleven", "at midnight", "never after ten", "before six"], - 2, - "never go to bed after ten.", - ), - ], - gaps=[ - G("She ___ (watch) a series every evening.", "watches", "3. osoba: watches."), - G("We ___ (not go) to school on Sunday.", "don't go|do not go", "Zápor v 1. osobě množného čísla."), - G("___ he play football on Fridays?", "Does", "Otázka ve 3. osobě."), - G("I usually ___ (get) up at seven.", "get", "Usually nemění tvar slovesa."), - ], - ), - L( - "Víkend ve městě", - "A weekend in town", - "Přítomný čas průběhový pro domluvené plány. Poslech.", - "The present continuous for arrangements. Listening.", - [ - S( - "1 / 2 • Continuous", - "Co právě probíhá a co je domluvené", - "Tip: I'm meeting Eva at ten je plán, ne jen „potkávám“.", - [ - "Tvar: am/is/are + -ing. I'm waiting. She isn't coming.", - "Teď: Look, it is raining. Please be quiet, the baby is sleeping.", - "Blízký plán: We're having lunch on Saturday. I'm playing volleyball.", - "Stavová slovesa obvykle průběhový čas nemají: I know, I like, I want.", - ], - ), - S( - "2 / 2 • Poslech", - "Jak poslouchat vzkaz", - "Tip: nejdřív si přečtěte otázky, pak teprve pusťte nahrávku.", - [ - "Chyťte jména, časy a místa. Ta se v otázkách opakují.", - "Nenechte se zastavit jedním slovem. Poslouchejte dál.", - "I'm meeting, we're going, I'm playing jsou v tomhle vzkazu klíčové.", - "Na konci bývá prosba: Call me back.", - ], - ), - ], - listening=( - "Hi Tom, it's Anna. Are you free on Saturday? I'm meeting Eva at the " - "station at ten. We're going to the market first, and then we're having " - "lunch in that new café by the river. In the afternoon I'm playing " - "volleyball with my class in the park. Do you want to come to the café? " - "Call me back tonight." - ), - listenq=[ - Q("Who is Anna meeting?", ["Tom", "Eva", "Her class", "Her mum"], 1, "I'm meeting Eva."), - Q( - "Where are they meeting?", - ["At school", "At the station", "In the park", "By the river only"], - 1, - "at the station at ten.", - ), - Q( - "What is Anna doing in the afternoon?", - ["Going to the market", "Having lunch", "Playing volleyball", "Sleeping"], - 2, - "I'm playing volleyball.", - ), - Q( - "What should Tom do?", - ["Buy tickets", "Call her back", "Come to school", "Bring a map"], - 1, - "Call me back tonight.", - ), - ], - gaps=[ - G("Listen, the phone ___.", "is ringing", "Děje se to teď."), - G("We ___ lunch with Eva on Saturday.", "are having|'re having", "Domluvený plán."), - G("I ___ not coming to the match.", "am|'m", "Zápor: am not."), - G("She ___ volleyball this afternoon.", "is playing|'s playing", "Domluvená aktivita."), - ], - ), - L( - "Můj pokoj", - "My room", - "There is / there are a předložky místa. Krátký popis a kvíz.", - "There is / there are and prepositions. A short description and a quiz.", - [ - S( - "1 / 2 • There is", - "Co v pokoji je", - "Tip: there is pro jedno, there are pro více. There je formální podmět.", - [ - "There is a desk under the window. There are two chairs.", - "Zápor: There isn't a TV. There aren't any posters.", - "Otázka: Is there a lamp? Are there any books?", - "Předložky: in, on, under, next to, between, behind, in front of.", - ], - ), - S( - "2 / 2 • Psaní", - "Popis místa", - "Tip: jděte od velkého k malému, od dveří k oknu.", - [ - "Začněte velikostí a světlem: small but bright.", - "Každá věta ať má věc a místo: The bag is under the chair.", - "Střídejte there is a there are, ať text není seznam.", - "Na konci jedna osobní věta: I like it because it is quiet.", - ], - ), - ], - writing=W( - "Describe your room in at least 30 words. Say what is in it and where things are. Use on and a piece of furniture such as a bed, and mention a window.", - "My room is small but bright. There is a bed next to the window and a wooden desk under a shelf. My books are on the desk and my school bag is under the chair. There are two posters on the wall. I like the room because it is quiet in the evening.", - "bed|window|on", - 30, - ), - quiz=[ - Q( - "The lamp is ___ the desk.", - ["under", "on", "between", "at"], - 1, - "Lampa stojí na desce: on.", - ), - Q( - "There ___ a big window.", - ["are", "is", "be", "have"], - 1, - "Jedno okno: there is.", - ), - Q( - "There ___ two posters on the wall.", - ["is", "are", "has", "been"], - 1, - "Dva plakáty: there are.", - ), - Q( - "The cat is sleeping ___ the bed.", - ["under", "next", "between to", "at to"], - 0, - "Pod postelí: under the bed.", - ), - ], - ), - L( - "Na trhu", - "At the market", - "Počitatelnost, some a any, how much a how many. Čtení a doplňování.", - "Countability, some and any, how much and how many. Reading and gaps.", - [ - S( - "1 / 2 • Množství", - "Počitatelné a nepočitatelné", - "Tip: some v kladné větě, any v otázce a záporu. Nabídka je výjimka: Would you like some tea?", - [ - "Počitatelné: an apple, some apples. Nepočitatelné: some bread, some milk.", - "How many apples? How much milk?", - "a little milk, a few rolls, a lot of cheese.", - "V obchodě: How much is it? It's four euros a kilo.", - ], - ), - S( - "2 / 2 • Dialog", - "Zdvořilá žádost", - "Tip: Can I have… a I'd like… zní v obchodě přirozeně.", - [ - "Have you got any bread? — Sorry, we haven't got any today.", - "We've got some rolls instead.", - "How many would you like? — Six, please.", - "Anything else? — No, that's all. Thank you.", - ], - ), - ], - reading=( - "On Saturday morning the market by the river is busy. A woman asks, " - "\"How much is this cheese?\" The seller says, \"It's four euros a kilo.\" " - "Then she asks, \"Have you got any bread?\" He answers, \"Sorry, we " - "haven't got any bread today, but we've got some fresh rolls.\" " - "\"How many rolls do you want?\" \"Six, please, and a little milk.\" " - "She also buys a few apples. \"Anything else?\" \"No, that's all.\"" - ), - readq=[ - Q( - "How much is the cheese?", - ["Four euros a piece", "Four euros a kilo", "Six euros", "A little"], - 1, - "four euros a kilo.", - ), - Q( - "What hasn't the seller got?", - ["Rolls", "Milk", "Bread", "Apples"], - 2, - "haven't got any bread today.", - ), - Q( - "How many rolls does the woman want?", - ["Four", "A few", "Six", "A kilo"], - 2, - "Six, please.", - ), - Q( - "Which phrase is an offer of more shopping?", - ["That's all.", "Anything else?", "How much is it?", "A little milk."], - 1, - "Anything else? nabízí další nákup.", - ), - ], - gaps=[ - G("We haven't got ___ bread today.", "any", "Zápor: any."), - G("There are ___ rolls in the bag.", "some", "Kladná věta: some."), - G("How ___ apples do you want?", "many", "Apples se dají počítat."), - G("How ___ milk is in the bottle?", "much", "Milk je nepočitatelné."), - ], - ), - L( - "Minulé léto", - "Last summer", - "Minulý čas prostý, pravidelná i nepravidelná slovesa. Poslech a kvíz.", - "The past simple, regular and irregular verbs. Listening and a quiz.", - [ - S( - "1 / 2 • Past simple", - "Co se stalo a je dokončené", - "Tip: zápor a otázka používají did, sloveso zůstává v základním tvaru.", - [ - "Pravidelná: play → played, visit → visited, try → tried, stop → stopped.", - "Nepravidelná: go → went, take → took, swim → swam, buy → bought.", - "I didn't stay in a hotel. Did you visit the island?", - "Signály: yesterday, last July, ago, in 2019, when I was ten.", - ], - ), - S( - "2 / 2 • Vyprávění", - "Jedna událost za druhou", - "Tip: then, after that a one day drží příběh pohromadě.", - [ - "Začněte kdy a kam: Last July we went to Croatia.", - "Pak doprava, počasí a jedna konkrétní příhoda.", - "Nepravidelná slovesa se neučí po jednom u testu, ale ve větě.", - "Na konci dojem: It was the best week of the year.", - ], - ), - ], - listening=( - "Last July we went to Croatia. We travelled by train and then by bus " - "because the flight was too expensive. The weather was hot every day. " - "I swam in the morning and my brother tried surfing. He fell off the " - "board a lot, but he loved it. One day we visited a small island. We " - "didn't stay in a hotel. We stayed with our uncle near the beach. I " - "took hundreds of photos." - ), - listenq=[ - Q("Where did they go?", ["Italy", "Croatia", "Greece", "Spain"], 1, "went to Croatia."), - Q( - "How did they travel?", - ["By plane", "By train and bus", "By car", "By ferry only"], - 1, - "by train and then by bus.", - ), - Q( - "What did the brother try?", - ["Swimming", "Surfing", "Cooking", "Driving"], - 1, - "tried surfing.", - ), - Q( - "Where did they stay?", - ["In a hotel", "On the island", "With their uncle", "On the train"], - 2, - "stayed with our uncle.", - ), - ], - quiz=[ - Q("go → ___", ["goed", "went", "gone", "going"], 1, "go, went, gone."), - Q("I ___ a lot of photos.", ["taked", "took", "taken", "token"], 1, "take, took, taken."), - Q("She ___ in the sea every morning.", ["swimmed", "swam", "swum", "swims"], 1, "Minulý tvar swim je swam."), - Q("We ___ stay in a hotel.", ["don't", "didn't", "wasn't", "haven't"], 1, "Zápor minulého času: didn't + sloveso."), - ], - ), - L( - "Zpráva kamarádovi", - "A message to a friend", - "Will a going to. Krátká neformální zpráva a doplňování.", - "Will and going to. A short informal message and gaps.", - [ - S( - "1 / 2 • Budoucnost", - "Plán, nebo rozhodnutí teď", - "Tip: going to má důkaz nebo plán. Will je rozhodnutí v tu chvíli nebo odhad.", - [ - "We've got tickets. We're going to leave at six. To je plán.", - "Look at those clouds. It's going to rain. To je důkaz.", - "The phone is ringing. I'll answer it. Rozhodnutí teď.", - "I think I'll stay at home. Will jako názor, ne jistý plán.", - ], - ), - S( - "2 / 2 • Zpráva", - "Neformální styl", - "Tip: Hi, kontraktované tvary a na konci otázka kamarádovi.", - [ - "Začněte Hi a jménem, ne Dear Sir.", - "Napište kdy, co a proč. Jedna věta s because stačí.", - "I'm going to… je v takové zprávě přirozené.", - "Konec: Want to come? Write back.", - ], - ), - ], - writing=W( - "Write a short message to a friend about next weekend. Use at least 25 words. Say what you are going to do, mention the weekend, and give a reason with because.", - "Hi Lena, next weekend I am going to visit my cousins in Pilsen. We are going to the cinema on Saturday because a new film is on. On Sunday we are going to cook lunch together. Do you want to come with me? Write back soon.", - "going|weekend|because", - 25, - ), - gaps=[ - G("Look at those clouds. It ___ rain.", "is going to|'s going to", "Je vidět důkaz: going to."), - G("I think I ___ stay at home tonight.", "will|'ll", "Názor v tu chvíli: will."), - G("The tickets are in my bag. We ___ leave at six.", "are going to|'re going to", "Už je to domluvené."), - G("Don't worry. I ___ help you with the bags.", "will|'ll", "Rozhodnutí teď: will."), - ], - ), - L( - "Test 1. ročníku", - "Year 1 test", - "Čtení, poslech, gramatika a krátké psaní. Úroveň A2.", - "Reading, listening, grammar and a short piece of writing. Level A2.", - [ - S( - "1 / 2 • Co test bere", - "A2 v jedné sadě", - "Tip: nejdřív otázky, pak text nebo nahrávku. U psaní počítejte slova.", - [ - "Čtení: najděte v textu čas, místo a důvod, nehádejte z jednoho slova.", - "Poslech: jména a čísla si poznamenejte hned.", - "Gramatika: be, přítomné časy, some/any, minulý čas, will a going to.", - "Psaní: krátký souvislý text, ne jen odrážky.", - ], - ), - S( - "2 / 2 • Jak opravovat", - "Nejčastější čechismy", - "Tip: po kontrole si přečtěte nápovědy, i když je věta správně.", - [ - "I am 16, ne I have 16 years.", - "She likes, ne she like.", - "Did you went je špatně. Did you go.", - "There is a book, ne It is a book on the table, když věc uvádíte.", - ], - ), - ], - reading=( - "Klara lives in a flat with her parents and a small dog. On weekdays " - "she walks to school because it is only ten minutes away. She loves " - "art. Last Friday her class visited a gallery and she bought a poster. " - "This Saturday she is meeting her cousin at the station. They are going " - "to a concert in the evening." - ), - readq=[ - Q( - "How does Klara get to school?", - ["By tram", "She walks", "Her dad drives", "By train"], - 1, - "she walks to school.", - ), - Q( - "What did she buy at the gallery?", - ["A dog", "A ticket", "A poster", "A flat"], - 2, - "she bought a poster.", - ), - Q( - "Who is she meeting on Saturday?", - ["Her parents", "Her art teacher", "Her cousin", "The singer"], - 2, - "meeting her cousin.", - ), - ], - listening=( - "Hi, it's Marek. I missed you after school. I'm at the sports centre. " - "The match starts at four, not at three, so don't hurry. Can you bring " - "my blue jacket? It's on the chair in the kitchen. See you there." - ), - listenq=[ - Q("Where is Marek?", ["At school", "At the sports centre", "In the kitchen", "On the tram"], 1, "at the sports centre."), - Q("What time does the match start?", ["At three", "At four", "At five", "At ten"], 1, "starts at four, not at three."), - Q("What should his friend bring?", ["A ticket", "A blue jacket", "Lunch", "A poster"], 1, "bring my blue jacket."), - ], - quiz=[ - Q("She ___ coffee.", ["don't like", "doesn't like", "not like", "isn't like"], 1, "3. osoba: doesn't like."), - Q("There ___ any milk.", ["isn't", "aren't", "hasn't", "don't"], 0, "Milk je jednotné: there isn't."), - Q("Yesterday we ___ to the lake.", ["go", "went", "gone", "going"], 1, "Minulý tvar go je went."), - Q("I've got the tickets. We ___ leave at noon.", ["will", "are going to", "did", "are"], 1, "Plán s důkazem: going to."), - ], - writing=W( - "Write at least 30 words about your family. Use is or are, and the words family and because.", - "My family is not very big. I live with my parents and my younger sister. She is twelve and she is funny. We get on well because we both like films. My dad is a driver and my mum is a nurse. I am happy at home.", - "family|because", - 30, - ), - ), - ], - }, - { - "sub_cs": "Cestování, zdraví, práce, média a příroda. Úroveň B1.", - "sub_en": "Travel, health, work, the media and nature. Level B1.", - "lessons": [ - L( - "Na cestách", - "On the road", - "Stupňování a minulý čas průběhový. Doplňování a kvíz.", - "Comparison and the past continuous. Gaps and a quiz.", - [ - S( - "1 / 2 • Stupňování", - "Porovnat dvě věci i celou skupinu", - "Tip: kratší přídavná jména berou -er/-est, delší more/most.", - [ - "cheap → cheaper → the cheapest. Expensive → more expensive → the most expensive.", - "Nepravidelné: good → better → the best, bad → worse → the worst, far → further → the furthest.", - "as … as: The bus is as fast as the train today.", - "than stojí po komparativu: This hostel is cheaper than the hotel.", - ], - ), - S( - "2 / 2 • Past continuous", - "Děje, který probíhal, když se stalo něco jiného", - "Tip: průběhový čas je pozadí, prostý je krátká událost.", - [ - "I was reading when the train stopped.", - "While we were waiting, it started to rain.", - "Zápor: We weren't sleeping. Otázka: Were you driving?", - "Nepleťte si ho s minulým prostým: I walked home popisuje celou cestu.", - ], - ), - ], - gaps=[ - G("This ticket is ___ (cheap) than the night train.", "cheaper", "Krátké přídavné jméno: -er."), - G("It was the ___ (bad) hotel in the town.", "worst", "bad, worse, the worst."), - G("Prague is not as ___ as London.", "big", "as + základní tvar + as."), - G("I ___ (read) when the bus suddenly stopped.", "was reading", "Pozadí: past continuous."), - G("While we ___ (wait), a street musician started to play.", "were waiting", "While + průběhový děj."), - ], - quiz=[ - Q("far → ___ → the furthest", ["farer", "further", "more far", "farthest only"], 1, "far, further, the furthest. Farthest je taky možné, ale further je v učebnici první."), - Q( - "Which sentence is correct?", - [ - "This café is more cheap than that one.", - "This café is cheaper than that one.", - "This café is the cheaper than that one.", - "This café is cheap than that one.", - ], - 1, - "cheap → cheaper than.", - ), - Q( - "She ___ a map when she missed the stop.", - ["looked", "was looking", "looks", "is looking"], - 1, - "Dělo se to v okamžiku, kdy zmeškala zastávku.", - ), - Q( - "good → better → ___", - ["the goodest", "the better", "the best", "the most good"], - 2, - "the best.", - ), - ], - ), - L( - "U lékaře", - "At the clinic", - "Should, must a have to. Čtení letáku a kvíz.", - "Should, must and have to. A leaflet and a quiz.", - [ - S( - "1 / 2 • Modální slovesa", - "Rada, povinnost, zákaz", - "Tip: must je silný pocit mluvčího, have to je pravidlo zvenku.", - [ - "You should rest. You shouldn't go to school tomorrow. To je rada.", - "I must call the doctor. Mluvčí cítí, že to je nutné.", - "You have to show your insurance card. To chce ordinace.", - "Mustn't je zákaz. Don't have to znamená, že to není nutné.", - ], - ), - S( - "2 / 2 • Tělo a příznaky", - "Jak to říct u přepážky", - "Tip: I've got a sore throat zní přirozeněji než I have pain in throat.", - [ - "a headache, a sore throat, a cough, a temperature, a rash.", - "It hurts when I swallow. I feel dizzy.", - "How long have you had it? — Since Monday. / For three days.", - "Take these tablets twice a day. Drink plenty of water.", - ], - ), - ], - reading=( - "The school clinic is open from seven to three. If you feel ill, you " - "should tell your teacher first. You have to bring your insurance card. " - "You must not come to school with a high temperature. Students with a " - "cough should wear a mask in the waiting room. You don't have to make " - "an appointment for a small cut, but you should come before noon. The " - "nurse can give you a painkiller. She can't give you antibiotics." - ), - readq=[ - Q( - "What do you have to bring?", - ["A mask", "An insurance card", "Antibiotics", "An appointment"], - 1, - "have to bring your insurance card.", - ), - Q( - "What is forbidden?", - [ - "Coming with a high temperature", - "Telling the teacher", - "Wearing a mask", - "Coming before noon", - ], - 0, - "must not come with a high temperature.", - ), - Q( - "You don't have to make an appointment if…", - [ - "you need antibiotics", - "you have a small cut", - "you have a temperature", - "you arrive at four", - ], - 1, - "for a small cut.", - ), - Q( - "What can't the nurse give you?", - ["Water", "A painkiller", "Antibiotics", "A mask"], - 2, - "She can't give you antibiotics.", - ), - ], - quiz=[ - Q( - "You ___ shout in the waiting room. It's a rule.", - ["don't have to", "mustn't", "shouldn't to", "haven't"], - 1, - "Zákaz: mustn't.", - ), - Q( - "You ___ wear a tie. Nobody minds.", - ["mustn't", "don't have to", "must", "should to"], - 1, - "Není to nutné: don't have to.", - ), - Q( - "I've got a headache. You ___ drink some water and rest.", - ["should", "must to", "have", "are"], - 0, - "Rada: should.", - ), - Q( - "Visitors ___ show a card. The clinic asks for it.", - ["have to", "should to", "don't must", "are have"], - 0, - "Pravidlo zvenku: have to.", - ), - ], - ), - L( - "První brigáda", - "A first job", - "Předpřítomný čas, for a since. Poslech pohovoru a doplňování.", - "The present perfect, for and since. A job interview and gaps.", - [ - S( - "1 / 2 • Present perfect", - "Zkušenost a děj až do teď", - "Tip: have/has + příčestí. Otázka na zkušenost začíná Have you ever…?", - [ - "I have worked in a café. She has never had a paid job.", - "Ever v otázce, never v záporném významu: Have you ever used a till?", - "For three months = jak dlouho. Since May = od kdy.", - "Just, already, yet: I've just finished. I haven't finished yet.", - ], - ), - S( - "2 / 2 • Pohovor", - "Krátké odpovědi", - "Tip: odpovězte a přidejte jednu konkrétní větu, ať to není jen yes.", - [ - "I'm reliable and I get on well with people.", - "I have looked after my neighbours' children.", - "I can work on Saturdays, but I can't work on Sunday mornings.", - "Could you tell me what the shift is?", - ], - ), - ], - listening=( - "Manager: Have you ever worked in a shop? Tereza: Not in a shop, but " - "I have helped in my uncle's bakery since May. Manager: What do you do " - "there? Tereza: I have served customers and I have learned to use the " - "till. I haven't baked bread yet. Manager: Can you start next Saturday? " - "Tereza: Yes. I have already asked my uncle, and he says it's fine. " - "I can't work on Sunday mornings because I have a match." - ), - listenq=[ - Q( - "Where has Tereza helped?", - ["In a supermarket", "In her uncle's bakery", "In a hotel", "At school"], - 1, - "in my uncle's bakery.", - ), - Q( - "Since when?", - ["Since March", "Since May", "Since Saturday", "For a year"], - 1, - "since May.", - ), - Q( - "What hasn't she done yet?", - ["Served customers", "Used the till", "Baked bread", "Asked her uncle"], - 2, - "I haven't baked bread yet.", - ), - Q( - "Why can't she work on Sunday mornings?", - ["The bakery is closed", "She has a match", "She is ill", "She has no till"], - 1, - "because I have a match.", - ), - ], - gaps=[ - G("She ___ (live) here since 2019.", "has lived|'s lived", "Since + předpřítomný čas."), - G("I have known him ___ three years.", "for", "For + délka."), - G("Have you ___ (be) to London?", "been", "Been to = mít zkušenost."), - G("We haven't finished ___.", "yet", "Yet v záporu na konci."), - G("He has ___ eaten, so he isn't hungry.", "already|just", "Already nebo just."), - ], - ), - L( - "Recenze filmu", - "A film review", - "Vztažné věty who, which a that. Krátká recenze a kvíz.", - "Relative clauses with who, which and that. A short review and a quiz.", - [ - S( - "1 / 2 • Vztažné věty", - "Která osoba, která věc", - "Tip: who pro lidi, which pro věci. That jde často pro obojí v definující větě.", - [ - "The actor who plays the captain is brilliant.", - "A lighthouse which stands on a black rock.", - "V definující větě se čárka nepíše: The boy who lives next door.", - "Nedefinující věta čárku má a that se v ní nepoužívá: Prague, which I love, …", - ], - ), - S( - "2 / 2 • Recenze", - "Názor, ne jen děj", - "Tip: neprozrazujte konec. Napište, pro koho film je.", - [ - "Jedna věta o ději, jedna o postavě, jedna o tom, co se povedlo.", - "I would recommend it to anyone who likes quiet films.", - "The ending, which I will not describe, stays with you.", - "Hodnocení ať je konkrétní: the music is too loud, the script is sharp.", - ], - ), - ], - writing=W( - "Write a short review of a film or a book in at least 40 words. Use who once and which once, and say who you would recommend it to.", - "The Lighthouse Keeper is a quiet film which follows a woman on a small island. The actor who plays her hardly speaks, but her face tells the story. The sea, which is almost a character, is beautiful and dangerous. I would recommend it to anyone who likes slow films. The ending is sad but honest.", - "who|which|recommend", - 40, - ), - quiz=[ - Q( - "The nurse ___ helped me was very calm.", - ["which", "who", "where", "whose it"], - 1, - "Člověk: who.", - ), - Q( - "The app ___ crashed is useless.", - ["who", "which", "where", "whom"], - 1, - "Věc: which.", - ), - Q( - "Prague, ___ is my home city, is full of tourists in July.", - ["that", "which", "who", "what"], - 1, - "S čárkou that nepatří. Which.", - ), - Q( - "That's the boy ___ dog ran into the road.", - ["who", "which", "whose", "that his"], - 2, - "Čí: whose.", - ), - ], - ), - L( - "Počasí a výlet", - "Weather and a trip", - "Too a enough, will a going to v předpovědi. Čtení a doplňování.", - "Too and enough, will and going to in a forecast. Reading and gaps.", - [ - S( - "1 / 2 • Too / enough", - "Příliš a dost", - "Tip: too stojí před přídavným jménem, enough za ním.", - [ - "It's too cold to swim. The water isn't warm enough.", - "Too many people, too much rain.", - "Enough + podstatné jméno: enough water. Nebo za přídavným jménem: old enough.", - "Not enough time je častější než too little time.", - ], - ), - S( - "2 / 2 • Předpověď", - "Co říct, když se díváte z okna", - "Tip: mraky, které vidíte, vedou k going to. Odhad bez důkazu k will.", - [ - "Those clouds are black. It's going to storm.", - "I think it will be sunny on Sunday. To je jen odhad.", - "If it rains, we'll stay in the cabin.", - "Slovník: foggy, chilly, pouring, a heatwave, a breeze.", - ], - ), - ], - reading=( - "We wanted to cycle to the lake, but the morning was too foggy to " - "start. By ten the sun was out and the path was dry enough. There " - "were too many cyclists near the dam, so we took a quieter road. " - "We didn't have enough water, which was a mistake. At the lake a " - "guard said, \"Look at that cloud. It's going to pour. I think the " - "storm will last an hour.\" We were not fast enough. We got soaked." - ), - readq=[ - Q( - "Why didn't they start early?", - ["The bikes were broken", "It was too foggy", "The lake was closed", "They had no map"], - 1, - "too foggy to start.", - ), - Q( - "Why did they change the road?", - [ - "There were too many cyclists", - "They were lost", - "It was pouring", - "The guard sent them back", - ], - 0, - "too many cyclists near the dam.", - ), - Q( - "What mistake did they make?", - ["They forgot the bikes", "They didn't have enough water", "They started at night", "They swam"], - 1, - "didn't have enough water.", - ), - Q( - "What did the guard predict from the cloud?", - ["Fog", "A heatwave", "Rain", "Snow"], - 2, - "It's going to pour.", - ), - ], - gaps=[ - G("The rucksack is ___ heavy to carry.", "too", "Too + přídavné jméno."), - G("She isn't tall ___ to reach the shelf.", "enough", "Enough za přídavným jménem."), - G("There is too ___ sugar in this tea.", "much", "Nepočitatelné: too much."), - G("Look at the sky. It ___ snow.", "is going to|'s going to", "Viditelný důkaz."), - ], - ), - L( - "Festival", - "A festival", - "Předpřítomný čas proti minulému. Poslech a kvíz.", - "Present perfect versus past simple. Listening and a quiz.", - [ - S( - "1 / 2 • Dva časy", - "Kdy je děj uzavřený", - "Tip: jakmile zazní yesterday, last year nebo in 2019, patří minulý čas.", - [ - "I have been to the festival three times. Neříkám kdy.", - "I went in 2023. Tehdy pršelo. To už je uzavřené.", - "Have you ever slept in a tent? — Yes. I slept in one last June.", - "Been to znamená, že už je člověk zpátky. Gone to znamená, že je pořád pryč.", - ], - ), - S( - "2 / 2 • Reportáž", - "Co se děje na místě", - "Tip: reportér míchá „už se stalo“ a „bylo to včera večer“.", - [ - "The gates have just opened.", - "Last night the main band played for two hours.", - "Have you seen the lanterns yet?", - "A local baker has made a cake in the shape of a violin.", - ], - ), - ], - listening=( - "This is Nora at the river festival. The gates have just opened and " - "hundreds of people have already come in. I have never seen so many " - "lanterns. Last night the main band played for two hours, but tonight's " - "singer hasn't arrived yet. A local baker has made a cake in the shape " - "of a violin. I tried a piece yesterday. It was delicious. Have you " - "ever been here? I came for the first time in 2022, and I have come " - "back every summer since then." - ), - listenq=[ - Q( - "What has just happened?", - ["The band has left", "The gates have opened", "It has started to snow", "The baker has closed"], - 1, - "The gates have just opened.", - ), - Q( - "When did the main band play?", - ["Just now", "Last night", "In 2022", "Every summer"], - 1, - "Last night the main band played.", - ), - Q( - "What hasn't happened yet?", - ["People have come in", "Tonight's singer has arrived", "Nora tried the cake", "The gates opened"], - 1, - "hasn't arrived yet.", - ), - Q( - "When did Nora come for the first time?", - ["Yesterday", "Last night", "In 2022", "This morning"], - 2, - "for the first time in 2022.", - ), - ], - quiz=[ - Q( - "I ___ this play in 2019.", - ["have seen", "saw", "seen", "have saw"], - 1, - "Rok uzavírá děj: saw.", - ), - Q( - "She has ___ to Paris. She is still there.", - ["been", "gone", "went", "going"], - 1, - "Pořád je pryč: gone.", - ), - Q( - "___ you ever slept in a tent?", - ["Did", "Have", "Do", "Were"], - 1, - "Ever + present perfect: Have you ever…?", - ), - Q( - "We ___ the lanterns yesterday.", - ["have seen", "saw", "seen", "have watch"], - 1, - "Yesterday → past simple.", - ), - ], - ), - L( - "Kdyby", - "If I could", - "První a druhá podmínková věta. Psaní a doplňování.", - "First and second conditionals. Writing and gaps.", - [ - S( - "1 / 2 • Podmínky", - "Reálná a hypotetická", - "Tip: v if větě není will. If it rains, we will stay in.", - [ - "1. kondicionál: If I finish early, I will call you. Je to možné.", - "2. kondicionál: If I had a car, I would drive. Teď auto nemám.", - "V formální druhé podmínce je were: If I were you, I would apologise.", - "Unless = if not: We'll miss the bus unless we leave now.", - ], - ), - S( - "2 / 2 • Vlastní věta", - "Jedna reálná, jedna vysněná", - "Tip: would se v if větě druhé podmínky neopakuje na obou stranách špatně. If I would have je chyba.", - [ - "Napište situaci, která se může stát tento týden.", - "Pak situaci, která teď pravda není.", - "Would like není druhá podmínka. To je jen přání: I'd like a tea.", - "Krátký text ať má oba typy, ať je rozdíl vidět.", - ], - ), - ], - writing=W( - "Write at least 35 words. Include one real plan with if and will, and one unreal dream with would. Use the word if twice.", - "If I finish my project tonight, I will go climbing with Eva on Saturday. We will take the early bus if the weather is fine. If I had more free time, I would learn the guitar. I would also travel by night train if tickets were cheaper. If is a small word with two very different lives.", - "if|will|would", - 35, - ), - gaps=[ - G("If it ___ (rain), we will stay in the tent.", "rains", "1. podmínka: přítomný čas v if."), - G("If I ___ (be) you, I would tell the truth.", "were|was", "Were je přesnější, was se taky slyší."), - G("She would travel more if she ___ (have) time.", "had", "2. podmínka: minulý tvar."), - G("We'll be late ___ we hurry.", "unless", "Unless = if not."), - ], - ), - L( - "Test 2. ročníku", - "Year 2 test", - "Čtení, poslech, gramatika B1 a krátké psaní.", - "Reading, listening, B1 grammar and a short piece of writing.", - [ - S( - "1 / 2 • B1", - "Co už má držet pohromadě", - "Tip: u předpřítomného času hledejte ever, yet, since. U minulého yesterday a rok.", - [ - "Stupňování, past continuous, modální slovesa rady a povinnosti.", - "Present perfect proti past simple.", - "Who a which, too a enough, první a druhá podmínka.", - "Psaní: krátký souvislý názor, ne odrážkový seznam.", - ], - ), - S( - "2 / 2 • Strategie", - "Jedna věta navíc", - "Tip: v psaní ať je důvod. Because nebo so text zvedne.", - [ - "U čtení škrtněte odpověď, která v textu vůbec není.", - "U poslechu si čísla zapište číslicí.", - "Mustn't není don't have to.", - "If I would have time je chyba. If I had time, I would…", - ], - ), - ], - reading=( - "The night bus to Brno is cheaper than the train, but it is also " - "slower. Last Friday I was sleeping when the driver stopped at a " - "dark petrol station. A woman who had missed her connection asked " - "if she could sit next to me. She has travelled this route since " - "March because her new job starts at six. If the bus is late, she " - "has to run. She says she would move closer if flats were cheaper." - ), - readq=[ - Q( - "The bus is ___ than the train.", - ["faster and cheaper", "cheaper and slower", "the best", "as fast"], - 1, - "cheaper, but slower.", - ), - Q( - "What was the writer doing when the bus stopped?", - ["Reading", "Sleeping", "Running", "Driving"], - 1, - "I was sleeping when the driver stopped.", - ), - Q( - "Why has the woman travelled this route since March?", - ["She likes petrol stations", "Her job starts early", "Flats are cheap", "She missed a concert"], - 1, - "her new job starts at six.", - ), - ], - listening=( - "Doctor: How long have you had this cough? Adam: Since Sunday. I have " - "also had a sore throat for two days. Doctor: You should rest and drink " - "water. You don't have to stay in bed all day, but you mustn't play " - "football this week. If you still feel ill on Friday, come back." - ), - listenq=[ - Q("Since when has Adam had the cough?", ["Since Friday", "Since Sunday", "For a month", "Since March"], 1, "Since Sunday."), - Q("What mustn't he do?", ["Drink water", "Rest", "Play football", "Come back"], 2, "mustn't play football."), - Q("When should he come back?", ["If he is still ill on Friday", "Every day", "Never", "On Sunday morning"], 0, "If you still feel ill on Friday."), - ], - quiz=[ - Q("This hostel is ___ than the hotel.", "cheaper / more cheap / the cheapest / cheap".split(" / "), 0, "cheap → cheaper."), - Q("I have lived here ___ 2020.", ["for", "since", "ago", "during"], 1, "Since + bod v čase."), - Q("You ___ wear a helmet. It's the law.", ["must to", "have to", "don't have", "should to"], 1, "Pravidlo: have to."), - Q("If I ___ richer, I would take the train.", ["am", "will be", "were", "would be"], 2, "2. podmínka: were."), - ], - writing=W( - "Write at least 35 words about a trip or a job you would like. Use would and because.", - "I would like to work in a small bookshop by the station because I love quiet mornings. I would talk to customers and I would also read in the breaks. If I had the job, I would cycle there. I have never worked in a shop, but I have helped at school events.", - "would|because", - 35, - ), - ), - ], - }, -] - - -def y3(): - forest = ( - "Last month our class recorded a podcast called The Last Beech. " - "A ranger said that the trees were thirsty because the summers had " - "become hotter. She told us that volunteers had planted two thousand " - "young trees, but she added that many would die unless it rained. " - "If the town banned cars from the forest road, the air would be cleaner. " - "If people keep using it as a shortcut, the soil will wash away." - ) - return { - "sub_cs": "Společnost, prostředí, média a složitější gramatika. Úroveň B1 až B2.", - "sub_en": "Society, the environment, the media and harder grammar. Level B1 to B2.", - "lessons": [ - L( - "Jak se to vyrábí", - "How things are made", - "Trpný rod v přítomnosti a minulosti. Doplňování a kvíz.", - "The present and past passive. Gaps and a quiz.", - [ - S( - "1 / 2 • Passive", - "Když je důležitější děj než původce", - "Tip: be + příčestí. Čas nese sloveso be, ne příčestí.", - [ - "English is spoken here. The window was broken last night.", - "Původce s by, jen když na něm záleží: The book was written by a nurse.", - "Modální trpný rod: The form must be signed. It can be recycled.", - "Nelze trpně vyjádřit každé sloveso. Happen trpný rod nemá.", - ], - ), - S( - "2 / 2 • Popis procesu", - "Od suroviny k věci", - "Tip: first, then, after that, finally. Původce často chybí, protože je obecný.", - [ - "The beans are picked by hand. They are dried in the sun.", - "The jars were labelled yesterday.", - "Waste paper is collected every Thursday.", - "A new bridge is being built. To už je průběhový trpný rod, zatím stačí ho poznat.", - ], - ), - ], - gaps=[ - G("This bread ___ (bake) every morning.", "is baked", "Přítomný trpný rod."), - G("The letters ___ (send) yesterday.", "were sent", "Minulý trpný rod, množné číslo."), - G("The poem ___ (write) by a student.", "was written", "Write → written."), - G("These bottles can ___ (recycle).", "be recycled", "Modální sloveso + be + příčestí."), - G("The window ___ (not break) by the wind. Someone hit it.", "wasn't broken|was not broken", "Zápor minulého trpného rodu."), - ], - quiz=[ - Q( - "Which sentence is passive?", - [ - "Someone stole my bike.", - "My bike was stolen.", - "My bike stole.", - "Someone was steal my bike.", - ], - 1, - "was + stolen.", - ), - Q( - "The news ___ at ten.", - ["is reading", "are read", "is read", "read"], - 2, - "News je jednotné: is read.", - ), - Q( - "You ___ wear a badge. The factory requires it, in the passive of must.", - ["must be worn a badge", "A badge must be worn", "A badge must worn", "A badge is must wear"], - 1, - "A badge must be worn.", - ), - Q( - "They built the school in 1998. → The school ___ in 1998.", - ["built", "was built", "was build", "has built"], - 1, - "was built.", - ), - ], - ), - L( - "Škola, o které se mluví", - "A school people talk about", - "Nepřímá řeč oznamovací. Čtení a kvíz.", - "Reported statements. Reading and a quiz.", - [ - S( - "1 / 2 • Reported speech", - "Posun času", - "Tip: said that, told me that. Tell potřebuje osobu, say ne.", - [ - "„I am tired.“ → She said she was tired.", - "„I will help.“ → He said he would help.", - "„I have finished.“ → She told me she had finished.", - "„I can't come.“ → He said he couldn't come.", - ], - ), - S( - "2 / 2 • Kdy čas neposouvat", - "Pořád to platí", - "Tip: obecné pravdy a situace, které trvají, často zůstávají v přítomném čase.", - [ - "The teacher said that water boils at 100 degrees.", - "She said she lives in Kolín, a pořád tam bydlí.", - "Zájmena se mění podle smyslu: „my book“ → he said his book.", - "Today → that day, tomorrow → the next day, yesterday → the day before. V testu to bude jen u jasných vět.", - ], - ), - ], - reading=( - "Our head teacher told the local paper that the school was changing. " - "She said that students would start an hour later next term. One pupil " - "told the reporter that he was pleased because he hated early buses. " - "A parent said that she was worried. She said her daughter had joined " - "three clubs and had very little time. The cook said that lunch would " - "still be at noon. He added that the menu was going to include more vegetables." - ), - readq=[ - Q( - "What did the head teacher say about the start of school?", - [ - "It would start an hour later", - "It would start at night", - "It had already closed", - "Clubs would end", - ], - 0, - "students would start an hour later.", - ), - Q( - "Why was the pupil pleased?", - ["He liked buses", "He hated early buses", "He wanted less lunch", "He had three clubs"], - 1, - "because he hated early buses.", - ), - Q( - "What had the daughter done?", - ["She had left school", "She had joined three clubs", "She had become a cook", "She had bought a bus"], - 1, - "had joined three clubs.", - ), - Q( - "Lunch, according to the cook, …", - ["would move to the evening", "would still be at noon", "had been cancelled", "was only vegetables"], - 1, - "would still be at noon.", - ), - ], - quiz=[ - Q( - "„I am hungry.“ → She said she ___ hungry.", - ["is", "was", "has", "were be"], - 1, - "am → was.", - ), - Q( - "„I will call.“ → He said he ___ call.", - ["will", "would", "called", "has"], - 1, - "will → would.", - ), - Q( - "Which verb needs a person?", - ["say", "tell", "speak that", "talk that"], - 1, - "tell somebody.", - ), - Q( - "She said, „I can't swim.“ → She said she ___.", - ["can't swim", "couldn't swim", "doesn't swim", "hasn't swum"], - 1, - "can → could. V nepřímé řeči o minulém rozhovoru.", - ), - ], - ), - L( - "Poslední buk", - "The last beech", - "Podmínky a slovník prostředí. Poslech podcastu a doplňování.", - "Conditionals and environment vocabulary. A podcast and gaps.", - [ - S( - "1 / 2 • Prostředí", - "Konkrétní slova, ne jen nature", - "Tip: drought, soil, volunteer, ban, shortcut. U maturitního tématu zabírají víc než slovo pollution samo.", - [ - "A drought is a long time without rain. Soil is the earth plants grow in.", - "Unless it rains, the young trees will die.", - "If the town banned cars, the air would be cleaner. Teď je nezakázalo, proto would.", - "If people keep using the road, the soil will wash away. To se může stát.", - ], - ), - S( - "2 / 2 • Podcast", - "Kdo co řekl", - "Tip: u nepřímé řeči v poslechu si pamatujte sloveso řekl/řekla a pak obsah.", - [ - "Ranger = strážce lesa.", - "Young trees were planted, but many may still die.", - "A shortcut šetří čas a někdy ničí místo.", - "Čísla si zapište: two thousand.", - ], - ), - ], - listening=forest, - listenq=[ - Q( - "What did the ranger say about the trees?", - ["They were thirsty", "They had been cut down", "They were a shortcut", "They banned cars"], - 0, - "the trees were thirsty.", - ), - Q( - "How many young trees had volunteers planted?", - ["Two hundred", "Two thousand", "Twenty", "None"], - 1, - "two thousand.", - ), - Q( - "The young trees will die unless…", - ["people drive there", "it rains", "the podcast ends", "the soil is sold"], - 1, - "unless it rained / unless it rains. V textu: unless it rained v nepřímé řeči.", - ), - Q( - "What would make the air cleaner?", - [ - "Banning cars from the forest road", - "Using the road as a shortcut", - "Cutting the beeches", - "Washing the soil", - ], - 0, - "If the town banned cars.", - ), - ], - gaps=[ - G("If we ___ (ban) cars here, the air would be cleaner.", "banned", "2. podmínka."), - G("The soil will wash away ___ people stop using the shortcut.", "unless", "Unless = if not. Pozor: věta chce if not ve významu dokud nepřestanou. Unless people stop = if they don't stop."), - G("Many young trees ___ (plant) last month.", "were planted", "Minulý trpný rod."), - G("She said the summers ___ (become) hotter.", "had become", "Posun předpřítomného času."), - ], - ), - L( - "Pro a proti", - "For and against", - "Stavba úvahy a spojovací výrazy. Esej a kvíz.", - "Essay structure and linking words. An essay and a quiz.", - [ - S( - "1 / 2 • Čtyři kroky", - "Úvod, dvě strany, závěr", - "Tip: v úvodu otázku neopakujte doslova. Převeďte ji vlastními slovy.", - [ - "Úvod: o čem text je a že existují dva pohledy.", - "Jeden odstavec pro výhody, jeden pro nevýhody.", - "On the one hand … On the other hand …", - "Závěr: váš názor. In my opinion, I believe. Nepřidávejte úplně nový argument.", - ], - ), - S( - "2 / 2 • Spojky", - "However není because", - "Tip: however stojí mezi větami a odděluje se čárkou. Although spojuje věty v jednu.", - [ - "School uniforms are cheaper. However, they limit personality.", - "Although uniforms save time, many students hate them.", - "Because dává důvod. So dává výsledek.", - "In conclusion shrnuje. Nepíše se In the conclusion.", - ], - ), - ], - writing=W( - "Write a for-and-against paragraph of at least 50 words about school uniforms. Use however and because, and finish with your opinion using believe.", - "School uniforms are a common argument. They are practical because students do not have to decide what to wear, and families spend less money. However, a uniform hides personality and can feel childish at eighteen. Although it makes mornings faster, it does not make lessons better. I believe schools should keep a simple dress code, but they should not force one jacket on everyone.", - "however|because|believe", - 50, - ), - quiz=[ - Q( - "Which linker shows contrast?", - ["because", "however", "so", "for example"], - 1, - "However staví protiklad.", - ), - Q( - "___ uniforms save time, students still complain.", - ["However", "Although", "So", "Believe"], - 1, - "Although spojuje dvě části jedné věty.", - ), - Q( - "Choose the best ending of an essay.", - [ - "In conclusion, I have no idea.", - "In conclusion, I believe a simple rule is enough.", - "Because however so.", - "To begin with, the essay starts now.", - ], - 1, - "Závěr má názor, ne nový zmatek.", - ), - Q( - "Because introduces…", - ["a result only", "a reason", "a list of names", "a question"], - 1, - "Because = důvod.", - ), - ], - ), - L( - "Kdo to musel být", - "It must have been", - "Modální slovesa dedukce. Čtení záhady a kvíz.", - "Modals of deduction. A short mystery and a quiz.", - [ - S( - "1 / 2 • Dedukce", - "Jisté, možné, vyloučené", - "Tip: must je skoro jistota, might je možnost, can't je „to přece nejde“.", - [ - "The lights are on. She must be at home.", - "He might be in the lab. I'm not sure.", - "That can't be Eva. Eva is in Vienna this week.", - "O minulosti: must have left, might have forgotten, can't have seen it.", - ], - ), - S( - "2 / 2 • Vynález", - "Čtěte důkazy, ne nadpis", - "Tip: u must have hledejte důkaz, který už nejde rozumně popřít.", - [ - "A notebook with today's date is stronger than a guess.", - "Can't have znamená, že to odporuje faktu.", - "Might have nechává dvě možnosti otevřené.", - "Nepoužívejte can pro dedukci v kladné větě. Can umí, must musí být.", - ], - ), - ], - reading=( - "Someone left a strange machine in the physics lab. It was warm, so " - "it must have been switched on recently. The only key can't have been " - "used by the caretaker, because he is in hospital. Two students, Nora " - "and Adam, know the code. Nora might have come back after the club, " - "but her train ticket shows she was in Pardubice. Adam's notebook is " - "on the bench and the handwriting matches the label. He must have built it." - ), - readq=[ - Q( - "Why must the machine have been on recently?", - ["It was noisy", "It was warm", "It was new", "It was labelled"], - 1, - "It was warm.", - ), - Q( - "Why can't the caretaker have used the key?", - ["He lost it", "He is in hospital", "He hates physics", "He was in Pardubice"], - 1, - "he is in hospital.", - ), - Q( - "Where was Nora?", - ["In the lab", "In Pardubice", "In hospital", "On the bench"], - 1, - "her ticket shows Pardubice.", - ), - Q( - "Who must have built the machine?", - ["The caretaker", "Nora", "Adam", "Nobody"], - 2, - "The notebook and the handwriting point to Adam.", - ), - ], - quiz=[ - Q("The window is broken and his bag is gone. He ___ left in a hurry.", ["must have", "must", "can have", "should"], 0, "Minulá skoro jistota: must have left."), - Q("That ___ be Lea. Lea is abroad.", ["must", "can't", "should", "is"], 1, "Odporuje faktu: can't."), - Q("I'm not sure. They ___ have missed the bus.", ["must", "can't", "might", "are"], 2, "Možnost: might have."), - Q("Which sentence is a deduction, not a duty?", ["You must wear gloves.", "She must be tired.", "You must sign this.", "Visitors must wait."], 1, "She must be tired je úsudek."), - ], - ), - L( - "Zprávy dne", - "The news desk", - "Nepřímé otázky. Poslech rozhovoru a kvíz.", - "Reported questions. An interview and a quiz.", - [ - S( - "1 / 2 • Reported questions", - "Otázka se v nepřímé řeči narovná", - "Tip: žádný otazník a pořadí podmětu a slovesa jako v oznamovací větě.", - [ - "„Where do you live?“ → She asked me where I lived.", - "„Did you see it?“ → He asked if I had seen it.", - "Whether a if jsou u zjišťovacích otázek obě možné.", - "Tázací výraz zůstává: what, where, why, how long.", - ], - ), - S( - "2 / 2 • Redakce", - "Novinář se ptá starosty", - "Tip: v poslechu odlište otázku reportéra od odpovědi starosty.", - [ - "Asked if the bridge was safe.", - "Wondered how long the repairs would take.", - "The mayor said he didn't know yet.", - "Slovesa ask, wonder, want to know.", - ], - ), - ], - listening=( - "Reporter: Mayor, is the old bridge safe? Mayor: I can't promise that. " - "An engineer told me that two cables were weak. Reporter: How long will " - "the repairs take? Mayor: She asked the firm the same question yesterday. " - "They said they didn't know yet. Reporter: Did anyone complain? Mayor: " - "A shopkeeper asked me why the bus stop had moved. I asked her if she " - "could wait until Friday. Reporter: Will you close the bridge? Mayor: " - "We might. I have asked the police whether they can send officers tonight." - ), - listenq=[ - Q( - "What did the engineer tell the mayor?", - ["The bridge was new", "Two cables were weak", "The shop was closed", "Friday was impossible"], - 1, - "two cables were weak.", - ), - Q( - "What didn't the firm know?", - ["The mayor's name", "How long the repairs would take", "Where the bus stop was", "Who the police were"], - 1, - "They said they didn't know yet. Šlo o délku oprav.", - ), - Q( - "What did the shopkeeper ask?", - [ - "Why the bus stop had moved", - "If the mayor could swim", - "Where the cables were made", - "Whether Friday was a holiday", - ], - 0, - "why the bus stop had moved.", - ), - Q( - "Who might come tonight?", - ["The firm", "The shopkeeper", "Police officers", "The engineer only"], - 2, - "whether they can send officers tonight.", - ), - ], - quiz=[ - Q( - "„Where do you live?“ → He asked me where I ___.", - ["did live", "lived", "do live", "living"], - 1, - "Pořadí oznamovací věty: where I lived.", - ), - Q( - "„Are you ready?“ → She asked if I ___.", - ["was ready", "am I ready", "ready was", "did ready"], - 0, - "if I was ready.", - ), - Q( - "Which sentence is wrong?", - [ - "He asked where she was.", - "He asked where was she.", - "He asked if she was tired.", - "He wanted to know why she had left.", - ], - 1, - "V nepřímé otázce není inverze.", - ), - Q( - "Whether means about the same as…", - ["because", "if", "however", "whose"], - 1, - "Whether ≈ if v nepřímé zjišťovací otázce.", - ), - ], - ), - L( - "Frázová slovesa v příběhu", - "Phrasal verbs in a story", - "Běžná frázová slovesa. Doplňování a kvíz.", - "Common phrasal verbs. Gaps and a quiz.", - [ - S( - "1 / 2 • Částice mění význam", - "Look není look after", - "Tip: frázové sloveso se učte jako jednu jednotku, s českým protějškem ve větě.", - [ - "look after = starat se, look for = hledat, look forward to = těšit se.", - "give up = vzdát se, find out = zjistit, run out of = dojít zásoba.", - "turn off = vypnout, take off = sundat nebo vzlétnout, get on = nastoupit i vycházet.", - "Look forward to je následované -ing: I look forward to seeing you.", - ], - ), - S( - "2 / 2 • Příběh", - "Jedno sloveso, jedna situace", - "Tip: když částici neznáte, představte si gesto. Off je pryč, up je do konce.", - [ - "The bus took off není o oblečení. U letadla ano, u autobusu spíš pulled away.", - "Take off a coat = sundat. Take off = vzlétnout. Kontext rozhoduje.", - "Get on with somebody = vycházet s někým.", - "Run out of time je u testu častější než run out time.", - ], - ), - ], - gaps=[ - G("Can you look ___ my dog this weekend?", "after", "Look after = postarat se."), - G("We are looking ___ to the trip.", "forward", "Look forward to."), - G("Don't give ___. The last chapter is the best.", "up", "Give up = vzdát to."), - G("I need to find ___ who left the note.", "out", "Find out = zjistit."), - G("We've run ___ of milk.", "out", "Run out of."), - ], - quiz=[ - Q("Please turn ___ the lights.", ["off", "after", "forward", "out of"], 0, "Turn off = vypnout."), - Q("She gets ___ well with her neighbours.", ["on", "off", "up", "after"], 0, "Get on with = vycházet."), - Q("He took ___ his wet coat.", ["off", "up to", "after", "forward"], 0, "Sundat: take off."), - Q("I look forward to ___ you.", ["see", "seeing", "saw", "seen"], 1, "To je předložka, následuje -ing."), - ], - ), - L( - "Test 3. ročníku", - "Year 3 test", - "Čtení, poslech, gramatika B1+ a krátká úvaha.", - "Reading, listening, B1+ grammar and a short argument.", - [ - S( - "1 / 2 • B1+", - "Trpný rod, řeč, podmínky, dedukce", - "Tip: u trpného rodu hledejte be. U nepřímé otázky žádnou inverzi.", - [ - "was written, must be signed, is spoken.", - "said she would, asked where I lived.", - "If they banned cars, the air would be cleaner.", - "must have, might have, can't have.", - ], - ), - S( - "2 / 2 • Úvaha ve zkratce", - "However a because v jednom textu", - "Tip: jedna výhoda, jeden háček, jedna věta s názorem.", - [ - "Neopakujte zadání první větou.", - "Phrasal verbs nechte ve správné částici. Look after není look for.", - "Told me, ne said me.", - "In conclusion je až na konci, ne v úvodu.", - ], - ), - ], - reading=( - "A repair café opened in a former bakery. Broken radios are mended " - "there on Saturdays. The founder said that people would rather repair " - "than buy if they were shown how. She told a reporter that twenty " - "kettles had been saved in March. Visitors have to bring the broken " - "object, but they don't have to pay. If the café closed, a lot of " - "working parts would be thrown away." - ), - readq=[ - Q("What happens to radios there?", ["They are sold", "They are mended", "They are banned", "They are thrown away at once"], 1, "are mended."), - Q("How many kettles had been saved in March?", ["Twelve", "Twenty", "Two thousand", "None"], 1, "twenty kettles."), - Q("What would happen if the café closed?", ["Parts would be thrown away", "Radios would be cheaper", "People would pay more", "The bakery would reopen as a shop"], 0, "working parts would be thrown away."), - ], - listening=( - "Editor: Did the mayor answer you? Journalist: I asked him whether the " - "bridge was safe. He said he didn't know. I also asked how long the " - "repairs would take. He told me that the firm hadn't decided. A resident " - "asked me why the paper hadn't printed a map. I said we would print one " - "tomorrow." - ), - listenq=[ - Q("What did the journalist ask about safety?", ["Whether the bridge was safe", "If the paper was closed", "Where the mayor lived", "Why kettles break"], 0, "whether the bridge was safe."), - Q("What hadn't the firm done?", ["Decided", "Printed a map", "Closed the paper", "Asked the resident"], 0, "hadn't decided."), - Q("What did the journalist promise?", ["To close the bridge", "To print a map tomorrow", "To repair the cables", "To interview a baker"], 1, "we would print one tomorrow."), - ], - quiz=[ - Q("The cake ___ by a student.", ["baked", "was baked", "was bake", "has bake"], 1, "was baked."), - Q("She asked me where I ___.", ["did live", "lived", "do live", "living"], 1, "where I lived."), - Q("He ___ be at school. I just saw him there.", ["can't", "must", "mustn't", "should to"], 1, "Skoro jistota: must."), - Q("Please look ___ the tickets. I can't find them.", ["for", "forward", "after", "up of"], 0, "Look for = hledat. Look after by bylo hlídat."), - ], - writing=W( - "In at least 40 words, give one reason for repairing things and one objection. Use because and however.", - "Repairing things matters because a kettle can work for years after a small fix. However, some people do not have the tools or the time, so a café where volunteers help is a fair idea. I believe every town should have one quiet room for broken objects. It is slower than shopping, but it is kinder.", - "because|however", - 40, - ), - ), - ], - } - - -def y4(): - article = ( - "When the night train from Prague to Berlin returned last spring, " - "stations filled with people who prefer a bed to a boarding gate. " - "A single ticket is often more expensive than a flight, which surprises " - "anyone who thinks trains are always the cheap choice. Still, passengers " - "say they arrive calmer. They can read, talk and avoid the bright shops " - "of an airport. Critics point out that a delay of two hours is common " - "and that the cabins are small. The railway has promised that new carriages " - "will be added if demand stays high. A student I spoke to had taken the " - "train three times. She said she would fly only if she missed the evening " - "departure. For her, the journey is part of the trip, not a problem to be " - "deleted." - ) - interview = ( - "Interviewer: Why did you apply to the summer camp in Wales? " - "Hana: I have worked with children for two years, and I wanted a job " - "where English is the only language. Interviewer: What would you do if " - "a child refused to join an activity? Hana: I wouldn't force them. I " - "would ask why, and I might offer a quieter task. Interviewer: Have you " - "ever dealt with an emergency? Hana: Yes. Last August a boy cut his foot. " - "I cleaned the cut and called the nurse. I didn't give him any medicine. " - "Interviewer: The camp is rainy. Is that a problem? Hana: Not really. " - "I have already bought boots. I look forward to the hills, although I " - "know the work will be tiring." - ) - return { - "sub_cs": "Maturitní dovednosti: mluvení, formální psaní, čtení, poslech a gramatika. Úroveň B2.", - "sub_en": "Exam skills: speaking, formal writing, reading, listening and grammar. Level B2.", - "lessons": [ - L( - "Maturitní kartička", - "The speaking card", - "Strategie ústní zkoušky a kolokace osobních témat. Kvíz a doplňování.", - "Speaking-exam strategy and personal-topic collocations. A quiz and gaps.", - [ - S( - "1 / 2 • Ústní zkouška", - "Čtyři minuty nejsou román", - "Tip: katalog CERMAT chce souvislý projev, popis obrázku, porovnání a reakci na otázky. Ne seznam slov.", - [ - "Úvod jednou větou: I'd like to talk about my town, which is smaller than it looks.", - "Obecné plus osobní: Many people commute. I cycle, because the centre is close.", - "Když slovo chybí, opis: the thing you use to open a tin.", - "Na obrázku: In the foreground, in the background, it looks as if.", - ], - ), - S( - "2 / 2 • Kolokace", - "Make, do, have, take", - "Tip: české „dělat“ se rozpadá. Do homework, make a mistake, take a photo, have a rest.", - [ - "Make a decision, make friends, make the bed.", - "Do the washing-up, do a course, do someone a favour.", - "Take part in, take care of, take an exam.", - "Have a look, have a word with, have trouble with.", - ], - ), - ], - gaps=[ - G("I need to ___ a decision before Friday.", "make", "Make a decision."), - G("She ___ her homework on the train.", "does|did", "Do homework."), - G("Can I ___ a photo of the bridge?", "take", "Take a photo."), - G("Let's ___ a rest. We've walked for hours.", "have", "Have a rest."), - G("He ___ part in the school play every year.", "takes|took", "Take part in."), - ], - quiz=[ - Q( - "You don't know the word kettle. What helps?", - [ - "Stop the exam", - "Paraphrase it", - "Switch to Czech for the rest", - "Invent a Latin word and insist", - ], - 1, - "Opis je lepší než ticho.", - ), - Q( - "In the foreground means…", - ["at the back", "at the front of the picture", "outside the frame", "in the past"], - 1, - "Foreground = popředí.", - ), - Q( - "Which collocation is right?", - ["do a mistake", "make a mistake", "take a mistake", "have a mistake"], - 1, - "Make a mistake.", - ), - Q( - "A strong speaking answer…", - [ - "is a list of single words", - "adds a personal example", - "translates the question", - "avoids all verbs", - ], - 1, - "Obecné plus vlastní příklad.", - ), - ], - ), - L( - "Formální e-mail", - "A formal email", - "Žádost a stížnost. Psaní a kvíz rejstříku.", - "A request and a complaint. Writing and a register quiz.", - [ - S( - "1 / 2 • Kostra", - "Komu, proč, co chcete, jak se loučíte", - "Tip: neznámé jméno → Dear Sir or Madam a Yours faithfully. Známé jméno → Dear Ms Novák a Yours sincerely.", - [ - "I am writing to apply for… / to complain about…", - "I would be grateful if you could…", - "Kontrakce v čistě formálním textu omezte: I am, not I'm.", - "Na konci celé jméno. Žádné Cheers ani xoxo.", - ], - ), - S( - "2 / 2 • Stížnost", - "Fakta, dopad, žádost", - "Tip: zlost text oslabuje. Datum, číslo spoje a klidná žádost ho posílí.", - [ - "The train on 3 May, which I had booked, arrived 90 minutes late.", - "As a result I missed the interview.", - "I would like a refund or an explanation.", - "I look forward to your reply.", - ], - ), - ], - writing=W( - "Write a formal email of at least 55 words to a railway company. Complain about a delay. Start with Dear, use would, and end with sincerely or faithfully.", - "Dear Sir or Madam, I am writing to complain about the night train to Berlin on 3 May. It arrived ninety minutes late, so I missed a morning interview. I would be grateful if you could explain the delay and offer a refund. I have attached my ticket. Please reply to this address. Yours faithfully, Tereza Malá.", - "dear|would|faithfully", - 55, - ), - quiz=[ - Q( - "You do not know the person's name. You end with…", - ["Yours faithfully", "Yours sincerely", "Cheers", "Love"], - 0, - "Neznámé jméno: faithfully. Po Dear Sir or Madam.", - ), - Q( - "Dear Ms Novák, … ___", - ["Yours faithfully", "Yours sincerely", "Hi again", "Bye"], - 1, - "Jméno znáte: sincerely.", - ), - Q( - "Which opening is formal?", - ["Hey!!!", "I am writing to apply for the post.", "I wanna the job.", "What's up"], - 1, - "I am writing to…", - ), - Q( - "A formal request sounds like…", - [ - "Give me a refund now.", - "I would be grateful if you could look into this.", - "You guys messed up.", - "Send money pls.", - ], - 1, - "I would be grateful if you could…", - ), - ], - ), - L( - "Noční vlak", - "The night train", - "Delší čtení ve stylu didaktického testu. Čtyři otázky k článku.", - "A longer reading in the style of the written paper. Four questions.", - [ - S( - "1 / 2 • Čtení u maturity", - "Nečtěte každé slovo stejně pomalu", - "Tip: u výběru ze čtyř možností nejdřív zjistěte, na co se otázka ptá, a teprve pak hledejte odstavec.", - [ - "Hlavní myšlenka bývá v úvodu nebo v závěru, ne v jednom příkladu.", - "Distraktor často opakuje slovo z textu, ale v jiném vztahu.", - "Which surprises… uvádí postoj, ne jen fakt o ceně.", - "Not given v tomhle cvičení není. Jedna možnost je opřená o text.", - ], - ), - S( - "2 / 2 • Slovník z kontextu", - "Boarding gate a carriage", - "Tip: neznámé slovo ohraničte větou před ním a za ním.", - [ - "A boarding gate je letištní východ k letadlu. Text ho staví proti posteli ve vlaku.", - "A carriage je vůz vlaku.", - "Demand = poptávka. If demand stays high, přidají vozy.", - "Deleted journey by byl let, který člověk chce mít co nejkratší.", - ], - ), - ], - reading=article, - readq=[ - Q( - "What is the main point?", - [ - "Flights have been cancelled", - "Some people choose the night train even when it costs more", - "Berlin has closed its station", - "Students may not travel", - ], - 1, - "Lístek bývá dražší než let, a přesto lidé vlak volí.", - ), - Q( - "What surprises some readers?", - [ - "That a train ticket can cost more than a flight", - "That stations are empty", - "That nobody reads", - "That the train is free", - ], - 0, - "more expensive than a flight, which surprises…", - ), - Q( - "What do critics mention?", - ["Free meals", "Delays and small cabins", "Too many books", "A lack of stations"], - 1, - "a delay of two hours, cabins are small.", - ), - Q( - "The student would fly only if…", - [ - "the ticket was cheap", - "she missed the evening departure", - "the cabins were small", - "she hated reading", - ], - 1, - "only if she missed the evening departure.", - ), - Q( - "New carriages will be added if…", - ["critics agree", "demand stays high", "flights are banned", "students complain"], - 1, - "if demand stays high.", - ), - ], - ), - L( - "Tábor ve Walesu", - "A camp in Wales", - "Delší poslech: pohovor. Pět otázek.", - "A longer listening: an interview. Five questions.", - [ - S( - "1 / 2 • Poslech u maturity", - "Dvě přehrání stačí, když víte co", - "Tip: při prvním poslechu chyťte kostru, při druhém doplňte past, podmínku a zápor.", - [ - "Otázky si přečtěte dřív. Podtrhněte tázací slovo.", - "Čísla a never/already mění význam celé věty.", - "Wouldn't force není couldn't.", - "I didn't give him any medicine je důležité právě proto, že je zápor.", - ], - ), - S( - "2 / 2 • Práce s dětmi", - "Slovník pohovoru", - "Tip: deal with an emergency, refuse, offer, look forward to.", - [ - "For two years je délka, ne bod v čase.", - "A quieter task je alternativa, ne trest.", - "Although přiznává nevýhodu a názor nemění.", - "Boots jsou důkaz, že s deštěm počítá. Proto going to / already.", - ], - ), - ], - listening=interview, - listenq=[ - Q( - "Why does Hana want the job?", - [ - "She has never met children", - "She wants a job where only English is spoken", - "She hates hills", - "She wants to sell boots", - ], - 1, - "where English is the only language.", - ), - Q( - "How long has she worked with children?", - ["For two weeks", "For two years", "Since last August only", "She hasn't"], - 1, - "for two years.", - ), - Q( - "What would she do if a child refused an activity?", - [ - "Force them", - "Send them home", - "Ask why and maybe offer a quieter task", - "Give them medicine", - ], - 2, - "I wouldn't force them. I might offer a quieter task.", - ), - Q( - "What didn't she do in the emergency?", - ["Clean the cut", "Call the nurse", "Give medicine", "Help the boy"], - 2, - "I didn't give him any medicine.", - ), - Q( - "How does she feel about the rain?", - [ - "She has already bought boots and still looks forward to the hills", - "She will refuse the job", - "She has never seen rain", - "She hates children", - ], - 0, - "already bought boots, look forward to the hills.", - ), - ], - ), - L( - "Názorová esej", - "An opinion essay", - "Struktura názoru. Esej a kvíz o odstavcích.", - "Opinion-essay structure. An essay and a quiz about paragraphs.", - [ - S( - "1 / 2 • Názor", - "Nejdřív stanovisko, pak důvody", - "Tip: u názorové eseje čtenář nemá hádat, na čí straně jste. Řekněte to v úvodu.", - [ - "I believe that… / In my opinion…", - "First reason, second reason, a short answer to the other side.", - "Although some people argue that…, I still think…", - "Závěr ať zní jako závěr, ne jako třetí nový důvod.", - ], - ), - S( - "2 / 2 • Rozsah", - "Radši čtyři hutné věty než deset prázdných", - "Tip: u písemné práce se počítají slova. Opakování zadání se nepočítá jako myšlenka.", - [ - "Každý důvod ať má příklad z běžného života.", - "Nepoužívejte etc. Místo toho jedno konkrétní slovo.", - "Spojky: firstly, in addition, on the other hand, in conclusion.", - "Kontraktované tvary jsou v názorové eseji v pořádku, když text není stížnost úřadu.", - ], - ), - ], - writing=W( - "Write an opinion of at least 60 words: should students have a gap year before university? Use believe, although and in conclusion.", - "I believe a gap year can help, but only when it has a plan. Although some students waste the time, others work, travel or look after a relative and return calmer. A year in a job also shows whether a degree is really necessary. On the other hand, a long break can make it harder to study again. In conclusion, a gap year is useful if the person can explain what they will do with it.", - "believe|although|conclusion", - 60, - ), - quiz=[ - Q( - "Where should your opinion appear in this kind of essay?", - ["Only in a footnote", "In the introduction and again at the end", "Never", "Only in the title"], - 1, - "Úvod i závěr.", - ), - Q( - "Although introduces…", - ["a concession", "a list of books", "a greeting", "a date"], - 0, - "Ústupka: something true that does not win.", - ), - Q( - "In conclusion should…", - ["start a brand-new topic", "sum up", "replace the introduction", "ask the examiner a question"], - 1, - "Shrnutí.", - ), - Q( - "Which is the best topic sentence?", - [ - "Gap year gap year gap year.", - "A gap year is worth it when it has a clear plan.", - "Hello my name is and I will write.", - "Etc. etc. etc.", - ], - 1, - "Věta, která už nese názor.", - ), - ], - ), - L( - "Slovní zásoba okruhů", - "Topic vocabulary", - "Kolokace k maturitním tématům. Doplňování a kvíz.", - "Collocations for the exam topics. Gaps and a quiz.", - [ - S( - "1 / 2 • Okruhy", - "Ne izolovaná slovíčka", - "Tip: ústní zkouška sahá na osobu, rodinu, domov, školu, volný čas, kulturu, sport, cestování, zdraví, jídlo, služby, práci, společnost a přírodu.", - [ - "Heavy rain, strong coffee, fast food, junk food. Ne strong rain.", - "A balanced diet, processed food, a food allergy.", - "Public transport, rush hour, a traffic jam, a return ticket.", - "Renewable energy, a carbon footprint, a heatwave, a drought.", - ], - ), - S( - "2 / 2 • Společnost a práce", - "Fráze, které unesou odstavec", - "Tip: apply for a job, hand in a notice, earn a living, from home.", - [ - "A gap year, an apprenticeship, a degree, tuition fees.", - "Freedom of speech, a stereotype, volunteer work.", - "Break the law, pay a fine, a witness.", - "Mental health, a check-up, be in pain. Ne have pain in the leg jako jediná možnost: My leg hurts.", - ], - ), - ], - gaps=[ - G("There was heavy ___ all night.", "rain", "Heavy rain, ne strong rain."), - G("I'd like a ___ ticket to Brno.", "return", "Return ticket = zpáteční."), - G("She applied ___ the post of guide.", "for", "Apply for."), - G("Solar power is ___ energy.", "renewable", "Renewable energy."), - G("He has a nut ___, so he can't eat the cake.", "allergy", "A food allergy."), - ], - quiz=[ - Q("Which pair is right?", ["strong rain / heavy coffee", "heavy rain / strong coffee", "fast coffee / junk rain", "a traffic diet"], 1, "Heavy rain, strong coffee."), - Q("Rush hour is…", ["a quiet morning", "the busiest time to travel", "a kind of ticket", "a school subject"], 1, "Špička."), - Q("An apprenticeship is…", ["a fine", "training for a job", "a heatwave", "a stereotype"], 1, "Praktická příprava na řemeslo nebo práci."), - Q("My leg ___.", ["hurts", "is pain", "has hurted", "does hurtness"], 0, "My leg hurts."), - ], - ), - L( - "Gramatická ambulance", - "Grammar clinic", - "Smíšené jevy k didaktickému testu. Kvíz a doplňování.", - "Mixed points for the language paper. A quiz and gaps.", - [ - S( - "1 / 2 • Články a časy", - "To, co se v testu sype", - "Tip: the night train, a night train, night trains. Člen podle toho, jestli čtenář ví který.", - [ - "I have lived here since May. I lived there in 2018.", - "If I were you, I would wait. If it rains, we will wait.", - "The book was written in 1962. People speak English here → English is spoken here.", - "Used to: I used to walk. Zvyk, který už neplatí. Didn't use to.", - ], - ), - S( - "2 / 2 • Věta", - "Slovosled a shoda", - "Tip: never dávejte před sloveso, ale za am/is/are: She is never late. She never arrives late.", - [ - "A little time, a few minutes. Much v záporu a otázce, a lot of v kladné větě je bezpečné.", - "Suggest + -ing nebo suggest that. Suggest me to go je chyba.", - "Enjoy, avoid, mind, can't help + -ing.", - "Want, decide, promise, hope + to.", - ], - ), - ], - gaps=[ - G("I ___ (live) in this flat since May.", "have lived|'ve lived", "Since → present perfect."), - G("She suggested ___ (take) the night train.", "taking", "Suggest + -ing."), - G("If I ___ you, I would book earlier.", "were|was", "If I were you."), - G("These letters must ___ (sign) today.", "be signed", "Must be + příčestí."), - G("I ___ to get up at five. I don't anymore.", "used", "Used to."), - ], - quiz=[ - Q("She enjoys ___.", ["to swim", "swimming", "swim", "swam"], 1, "Enjoy + -ing."), - Q("I have ___ finished.", ["yet", "just", "since", "ago"], 1, "Just before the participle. Yet belongs at the end in negatives."), - Q("English ___ all over the building.", ["speaks", "is spoken", "is spoke", "speak"], 1, "Trpný rod."), - Q("There isn't ___ time.", ["many", "much", "a few", "several"], 1, "Time je nepočitatelné: much."), - Q("He asked me where ___.", ["did I live", "I lived", "do I lived", "lived I"], 1, "Bez inverze."), - Q("You ___ shout. The baby is asleep. It is forbidden.", ["don't have to", "mustn't", "might", "used to"], 1, "Zákaz: mustn't."), - ], - ), - L( - "Cvičná maturita", - "A practice paper", - "Čtení, poslech, jazyková kompetence a krátká písemná práce.", - "Reading, listening, language in use and a short piece of writing.", - [ - S( - "1 / 2 • Celá zkouška", - "Tři části, jeden mozek", - "Tip: didaktický test míchá poslech, čtení a jazykovou kompetenci. Písemná práce je zvlášť. Tady je zmenšený model.", - [ - "Nejdřív přečtěte zadání psaní, ať víte, kolik času si necháte.", - "U čtení nehledejte stejná slova. Hledejte stejný význam.", - "U poslechu zápor bývá ta správná odpověď.", - "Když váháte mezi dvěma, vyhoďte tu, která přidává informaci v textu neslyšenou.", - ], - ), - S( - "2 / 2 • Písemná práce", - "Účel, čtenář, rozsah", - "Tip: e-mail kamarádovi a stížnost úřadu se nepíšou stejným jazykem. Tady jde o kamaráda.", - [ - "Řekněte proč píšete hned v první větě.", - "Dejte tam čas a místo, ať text není mlha.", - "Jedna věta s because a jedna s if textu pomůžou.", - "Na konci otázka, která zní jako opravdový zájem.", - ], - ), - ], - reading=( - "The town library now lends tools as well as books. Hammers, " - "sewing machines and a cake tin can be borrowed for a week. " - "The idea came from a librarian who was tired of people buying " - "things they would use once. She said the workshop had been " - "visited by more teenagers than the reading room. Critics argue " - "that a library should stay quiet. She replies that a library " - "should be useful. If the experiment works, other branches will " - "copy it. Users have to return each object clean, and they must " - "not lend it to anyone else." - ), - readq=[ - Q( - "What can people borrow besides books?", - ["Cars", "Tools", "Flats", "Tickets to Berlin"], - 1, - "Hammers, sewing machines, a cake tin.", - ), - Q( - "Why did the idea start?", - [ - "People were buying things they would use once", - "The reading room was too popular", - "Teenagers hated books", - "The tools were illegal", - ], - 0, - "buying things they would use once.", - ), - Q( - "Who has visited the workshop more, according to her?", - ["Critics", "Teenagers, more than the reading room", "Other branches", "Nobody"], - 1, - "more teenagers than the reading room.", - ), - Q( - "What must users not do?", - ["Return the object", "Clean it", "Lend it to someone else", "Visit the library"], - 2, - "must not lend it to anyone else.", - ), - ], - listening=( - "Welcome to the night-train podcast. The 22:40 to Berlin has been " - "delayed by forty minutes because a tree is on the line near Ústí. " - "Passengers who already have a seat can wait in carriage four, where " - "tea is being served. If you have not checked in, please do it on " - "your phone. We would be grateful if you kept the corridor clear. " - "The delay might be shorter. We will know more at ten." - ), - listenq=[ - Q("How long is the delay?", ["14 minutes", "40 minutes", "4 hours", "22 minutes"], 1, "forty minutes."), - Q("Why?", ["Snow", "A tree on the line", "A missing driver", "A festival"], 1, "a tree is on the line."), - Q("Where can passengers with a seat wait?", ["Carriage four", "The airport", "Ústí station only", "The corridor"], 0, "carriage four."), - Q("What should people without a check-in do?", ["Buy tea", "Check in on their phone", "Leave the train", "Call the mayor"], 1, "do it on your phone."), - ], - quiz=[ - Q("Tea ___ in carriage four.", ["serves", "is being served", "is serving", "has serve"], 1, "Průběhový trpný rod."), - Q("We would be grateful if you ___ the corridor clear.", ["keep", "kept", "keeping", "to keep"], 1, "Would be grateful if + minulý tvar."), - Q("She said the workshop ___ by more teenagers.", ["visited", "had been visited", "has visit", "is visiting"], 1, "Had been visited."), - Q("Users ___ return the tools clean.", ["have to", "must to", "don't must", "are have"], 0, "Have to."), - ], - writing=W( - "Write at least 45 words to a friend. Invite them to borrow something from a library of things. Use because and if.", - "Hi Adam, the library now lends tools, and I think you would like it because you always need a drill for one afternoon. If you come on Saturday, I will show you how it works. You have to bring your card and return everything clean. We could borrow a cake tin and bake something after. Let me know if you are free.", - "because|if", - 45, - ), - ), - ], - } - - -YEARS.append(y3()) -YEARS.append(y4()) - - -def emit_questions(name, items, lines): - lines.append(f"static const ChoiceQ {name}[] = {{") - for prompt, options, correct, _hint in items: - opts = ", ".join(c_str(o) for o in options) - lines.append(f" {{{c_str(prompt)}, {{{opts}}}, 4, {correct}}},") - lines.append("};") - lines.append(f"static const char *{name}_hints[] = {{") - for _p, _o, _c, hint in items: - lines.append(f" {c_str(hint)},") - lines.append("};") - lines.append("") - - -def emit_lesson(year, index, lesson, lines, inits, prefix="en"): - p = f"{prefix}_y{year}_l{index}" - lines.append(f"static const NetSlide {p}_slides[] = {{") - for kicker, title, tip, bullets in lesson["slides"]: - lines.append(" {") - lines.append(f" {c_str(kicker)}, {c_str(title)}, {c_str(tip)},") - lines.append(" {") - for bullet in bullets: - lines.append(f" {c_str(bullet)},") - lines.append(" NULL,") - lines.append(" },") - lines.append(" },") - lines.append("};") - lines.append("") - - init = [ - f" .slides = {p}_slides,", - f" .n_slides = (int)(sizeof {p}_slides / sizeof {p}_slides[0]),", - ] - - if lesson.get("reading"): - lines.append(f"static const char *{p}_read = {c_str(lesson['reading'])};") - lines.append("") - init.append(f" .reading = {c_str(lesson['reading'])},") - if lesson.get("readq"): - emit_questions(f"{p}_readq", lesson["readq"], lines) - init.append(f" .readq = {p}_readq,") - init.append(f" .read_hints = {p}_readq_hints,") - init.append(f" .n_read = (int)(sizeof {p}_readq / sizeof {p}_readq[0]),") - if lesson.get("listening"): - lines.append(f"static const char *{p}_listen = {c_str(lesson['listening'])};") - lines.append("") - init.append(f" .listening = {c_str(lesson['listening'])},") - if lesson.get("listenq"): - emit_questions(f"{p}_listenq", lesson["listenq"], lines) - init.append(f" .listenq = {p}_listenq,") - init.append(f" .listen_hints = {p}_listenq_hints,") - init.append(f" .n_listen = (int)(sizeof {p}_listenq / sizeof {p}_listenq[0]),") - if lesson.get("gaps"): - lines.append(f"static const TypedQ {p}_gaps[] = {{") - for prompt, answers, meaning in lesson["gaps"]: - lines.append(f" {{{c_str(prompt)}, {c_str(answers)}, {c_str(meaning)}}},") - lines.append("};") - lines.append("") - init.append(f" .gaps = {p}_gaps,") - init.append(f" .n_gaps = (int)(sizeof {p}_gaps / sizeof {p}_gaps[0]),") - if lesson.get("writing"): - prompt, model, keys, min_words = lesson["writing"] - lines.append(f"static const char *{p}_write[] = {{") - lines.append(f" {c_str(prompt)},") - lines.append(f" {c_str(model)},") - lines.append(f" {c_str(keys)},") - lines.append(f" {c_str(str(min_words))},") - lines.append("};") - lines.append("") - init.append(f" .write_prompt = {c_str(prompt)},") - init.append(f" .write_model = {c_str(model)},") - init.append(f" .write_keys = {c_str(keys)},") - init.append(f" .write_min = {min_words},") - if lesson.get("quiz"): - emit_questions(f"{p}_quiz", lesson["quiz"], lines) - init.append(f" .quiz = {p}_quiz,") - init.append(f" .quiz_hints = {p}_quiz_hints,") - init.append(f" .n_quiz = (int)(sizeof {p}_quiz / sizeof {p}_quiz[0]),") - - kinds = [k for k in ("reading", "listening", "writing", "gaps", "quiz", "readq", "listenq") if lesson.get(k)] - if len(kinds) < 2 and "reading" not in kinds and "listening" not in kinds: - raise SystemExit(f"thin lesson y{year} l{index}: {kinds}") - inits.append(" {\n" + "\n".join(init) + "\n }") - - -def main() -> None: - if len(YEARS) != 4 or any(len(y["lessons"]) != 8 for y in YEARS): - raise SystemExit("expected 4 years × 8 lessons") - - body = [ - "/* Generated by scripts/gen-english.py. Do not edit by hand. */", - "", - ] - table = ["static const EnLesson en_lessons[EN_YEARS][EN_N] = {"] - i18n = [ - ' {"en_years_sub", "Čtyři ročníky podle osnov gymnázia, od A2 k maturitě.", "Four years of the gymnasium syllabus, from A2 to the exam."},', - ' {"en_year1", "1. ročník", "Year 1"},', - ' {"en_year2", "2. ročník", "Year 2"},', - ' {"en_year3", "3. ročník", "Year 3"},', - ' {"en_year4", "4. ročník", "Year 4"},', - ' {"en_sec_read", "Čtení", "Reading"},', - ' {"en_sec_listen", "Poslech", "Listening"},', - ' {"en_sec_write", "Psaní", "Writing"},', - ' {"en_sec_gap", "Doplňte", "Complete"},', - ' {"en_sec_quiz", "Kvíz", "Quiz"},', - ' {"en_sec_test", "Jazyková část", "Language"},', - ' {"en_play", "Přehrát", "Play"},', - ' {"en_pause", "Pauza", "Pause"},', - ' {"en_resume", "Pokračovat", "Resume"},', - ' {"en_speed", "Rychlost", "Speed"},', - ' {"en_volume", "Hlasitost", "Volume"},', - ' {"en_listen_note", "Text nahrávky zůstává vidět. Přehrání obstará hlas zařízení.", "The recording text stays visible. The device voice plays it."},', - ' {"en_listen_first", "Nejdřív poslech přehrajte.", "Play the recording first."},', - ' {"en_listen_fallback", "Hlas není dostupný. Text si můžete přečíst.", "No voice is available. You can read the text."},', - ' {"en_write_short", "Text je krátký nebo v něm chybí požadovaná slova.", "The text is short or it misses the required words."},', - ' {"en_model", "Vzor", "Model"},', - ' {"en_write_ph", "Pište anglicky…", "Write in English…"},', - ] - for yi, year in enumerate(YEARS, start=1): - i18n.append( - f' {{"en_y{yi}_sub", {c_str(year["sub_cs"])}, {c_str(year["sub_en"])}}},' - ) - row = [] - for li, lesson in enumerate(year["lessons"], start=1): - i18n.append( - f' {{"en_y{yi}_u{li}", {c_str(lesson["title_cs"])}, {c_str(lesson["title_en"])}}},' - ) - i18n.append( - f' {{"en_y{yi}_u{li}_sub", {c_str(lesson["sub_cs"])}, {c_str(lesson["sub_en"])}}},' - ) - inits = [] - emit_lesson(yi, li, lesson, body, inits) - row.append(inits[0]) - table.append(" {\n" + ",\n".join(row) + "\n },") - table.append("};") - table.append("") - body.extend(table) - - (ROOT / "src" / "english_lessons.inc").write_text("\n".join(body) + "\n", encoding="utf-8") - (ROOT / "src" / "english_i18n.inc").write_text("\n".join(i18n) + "\n", encoding="utf-8") - skills = [] - for yi, year in enumerate(YEARS, start=1): - bag = set() - for lesson in year["lessons"]: - bag.update(k for k in ("reading", "listening", "writing", "gaps", "quiz") if lesson.get(k)) - skills.append(f"year {yi}: {', '.join(sorted(bag))}") - print("wrote", len(YEARS) * 8, "lessons") - print("\n".join(skills)) - - -if __name__ == "__main__": - main() diff --git a/scripts/gen-german.py b/scripts/gen-german.py deleted file mode 100644 index 39629b6..0000000 --- a/scripts/gen-german.py +++ /dev/null @@ -1,1387 +0,0 @@ -#!/usr/bin/env python3 -"""German skill course: four years, same activity mix as English. - -Textbook units (Neue Freunde and the next two) stay as they are. -This course follows a typical Czech secondary-school ŠVP for German -as a second foreign language: A1, A2, then B1 exam skills. -""" - -from importlib.machinery import SourceFileLoader -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -eng = SourceFileLoader( - "gen_english", str(Path(__file__).with_name("gen-english.py")) -).load_module() - -L, S, Q, G, W = eng.L, eng.S, eng.Q, eng.G, eng.W -c_str = eng.c_str -emit_lesson = eng.emit_lesson - -YEARS = [ - { - "sub_cs": "Pozdravy, rodina, škola, jídlo a den. Úroveň A1.", - "sub_en": "Greetings, family, school, food and the day. Level A1.", - "lessons": [ - L( - "Pozdravy a představení", - "Greetings and introductions", - "Sein, heißen a woher. Doplňování a kvíz.", - "Sein, heißen and woher. Gaps and a quiz.", - [ - S("1 / 2 • Sein", "Kdo jsem", - "Tip: věk je Ich bin 16, ne Ich habe 16 Jahre.", - [ - "ich bin, du bist, er/sie/es ist, wir/ihr/sie sind.", - "Ich heiße Anna. Wie heißt du?", - "Woher kommst du? — Ich komme aus Prag.", - "Guten Tag, Hallo, Tschüss, Danke, Bitte.", - ]), - S("2 / 2 • Otázka", "Sloveso na druhém místě", - "Tip: v otázce je sloveso hned za tázacím slovem.", - [ - "Wie heißt du? Wo wohnst du? Was machst du?", - "Zápor: Ich heiße nicht Peter. Er ist nicht hier.", - "Sie s velkým S je vykání. sie s malým je ona nebo oni.", - "Zdvořilost: Guten Morgen, Frau Novak.", - ]), - ], - gaps=[ - G("Ich ___ Anna.", "heiße|heisse", "heißen ve 1. osobě."), - G("___ kommst du?", "Woher", "Odkud."), - G("Wir ___ Schüler.", "sind", "wir + sein."), - G("Er ___ mein Bruder.", "ist", "er + sein."), - G("Wie ___ du?", "heißt|heisst", "du + heißen."), - ], - quiz=[ - Q("Jak se německy řekne věk?", - ["Ich habe 16 Jahre.", "Ich bin 16 Jahre alt.", "Ich ist 16.", "Ich bin 16 Jahre."], - 1, "bin + Jahre alt."), - Q("Woher kommst du?", - ["Ich bin gut.", "Ich komme aus Brno.", "Ich heiße aus Brno.", "Ich wohne kommst."], - 1, "kommen aus + město."), - Q("du + sein", - ["du ist", "du bist", "du sind", "du bin"], - 1, "du bist."), - Q("Který pozdrav je odpoledne neutrální?", - ["Gute Nacht", "Guten Tag", "Tschüss gleich", "Bitte sehr Tag"], - 1, "Guten Tag."), - ], - ), - L( - "Rodina", - "Family", - "Haben a přivlastňovací zájmena. Čtení a doplňování.", - "Haben and possessives. Reading and gaps.", - [ - S("1 / 2 • Haben", "Co mám", - "Tip: haben není věk. Ich habe einen Bruder.", - [ - "ich habe, du hast, er hat, wir haben.", - "Přivlastňovací: mein, dein, sein, ihr, unser, euer.", - "Člen der/die/das se v 1. pádu u jmen učí s podstatným jménem.", - "die Mutter, der Vater, die Schwester, der Bruder, die Eltern.", - ]), - S("2 / 2 • Text", "Krátký medailon", - "Tip: v textu hledejte čísla a kdo s kým bydlí.", - [ - "und spojuje, aber staví proti.", - "nicht stojí před tím, co popíráme.", - "auch = taky.", - "zu Hause = doma.", - ]), - ], - reading=( - "Ich heiße Lukas und ich bin fünfzehn. Ich wohne mit meinen Eltern " - "in Pilsen. Ich habe eine Schwester. Sie heißt Eva und sie ist zwölf. " - "Mein Vater ist Lehrer und meine Mutter arbeitet im Krankenhaus. " - "Wir haben auch einen Hund. Er heißt Max. Am Wochenende besuchen " - "wir meine Oma. Sie wohnt nicht bei uns, aber sie wohnt in derselben Stadt." - ), - readq=[ - Q("Wie alt ist Lukas?", - ["Zwölf", "Fünfzehn", "Sechzehn", "Der Text sagt es nicht"], - 1, "ich bin fünfzehn."), - Q("Was ist der Vater von Beruf?", - ["Arzt", "Lehrer", "Koch", "Schüler"], - 1, "Mein Vater ist Lehrer."), - Q("Wo wohnt die Oma?", - ["Bei der Familie", "In einer anderen Stadt", "In derselben Stadt", "Im Krankenhaus"], - 2, "in derselben Stadt."), - Q("Wie heißt der Hund?", - ["Lukas", "Eva", "Max", "Der Text nennt keinen Namen"], - 2, "Er heißt Max."), - ], - gaps=[ - G("Ich ___ eine Schwester.", "habe", "haben, 1. osoba."), - G("___ Vater ist Lehrer.", "Mein", "Přivlastňovací u maskulina."), - G("Sie ___ zwölf.", "ist", "Věk: sein."), - G("Wir ___ einen Hund.", "haben", "wir haben."), - ], - ), - L( - "Ve škole", - "At school", - "Přítomný čas. Poslech a doplňování.", - "The present tense. Listening and gaps.", - [ - S("1 / 2 • Präsens", "Pravidelné sloveso", - "Tip: kmen + koncovka. spielen: ich spiele, du spielst, er spielt.", - [ - "ich -e, du -st, er/sie/es -t, wir -en, ihr -t, sie -en.", - "Otázka bez tázacího slova: Spielst du Fußball?", - "Zápor: Ich spiele nicht Klavier.", - "Sloveso je ve větě na druhém místě: Heute spiele ich Tennis.", - ]), - S("2 / 2 • Poslech", "Rozvrh", - "Tip: nejdřív otázky, pak nahrávka. Chyťte předměty a dny.", - [ - "am Montag, am Dienstag, in der Pause.", - "das Fach, die Stunde, die Hausaufgabe.", - "gern = rád. Ich lerne gern Deutsch.", - "lieber = radši.", - ]), - ], - listening=( - "Hallo, ich bin Mia. Am Montag haben wir Deutsch, Mathe und Biologie. " - "Deutsch mag ich gern, weil die Lehrerin nett ist. Mathe mag ich nicht. " - "In der Pause esse ich ein Brötchen und spreche mit Eva. Nach der Schule " - "mache ich Hausaufgaben oder ich spiele Volleyball. Am Abend lese ich " - "oder ich höre Musik. Um zehn gehe ich ins Bett." - ), - listenq=[ - Q("Welches Fach mag Mia gern?", - ["Mathe", "Deutsch", "Volleyball", "Musik nur"], - 1, "Deutsch mag ich gern."), - Q("Warum?", - ["Weil es leicht ist", "Weil die Lehrerin nett ist", "Weil sie keine Hausaufgaben hat", "Weil es am Abend ist"], - 1, "weil die Lehrerin nett ist."), - Q("Was macht sie in der Pause?", - ["Sie schläft", "Sie isst ein Brötchen und spricht mit Eva", "Sie spielt Volleyball", "Sie lernt Mathe"], - 1, "esse ich ein Brötchen und spreche mit Eva."), - Q("Wann geht sie ins Bett?", - ["Um acht", "Um neun", "Um zehn", "Um elf"], - 2, "Um zehn."), - ], - gaps=[ - G("Ich ___ (spielen) gern Tennis.", "spiele", "ich + -e."), - G("___ du heute Deutsch?", "Lernst", "Otázka: Lernst du heute Deutsch?"), - G("Er ___ (wohnen) in Prag.", "wohnt", "er + -t."), - G("Wir ___ (machen) Hausaufgaben.", "machen", "wir + -en."), - ], - ), - L( - "Jídlo", - "Food", - "Möchten a 4. pád. Krátký dialog a kvíz.", - "Möchten and the accusative. A short dialogue and a quiz.", - [ - S("1 / 2 • Möchten", "Chtěl bych", - "Tip: ich möchte, du möchtest, er möchte. Je to zdvořilé chtít.", - [ - "Ich möchte einen Apfel. die → eine, der → einen v akuzativu.", - "Maskulinum: der Salat → einen Salat. Neutrum: das Brot → ein Brot.", - "Femininum se v akuzativu nemění: die Suppe → eine Suppe.", - "Was möchten Sie? je vykání v restauraci.", - ]), - S("2 / 2 • Psaní", "Objednávka", - "Tip: začněte Guten Tag a skončete Danke.", - [ - "Ich möchte … und …", - "Für mich bitte einen Tee.", - "Die Rechnung, bitte.", - "Es schmeckt gut.", - ]), - ], - writing=W( - "Schreib mindestens 25 Wörter. Bestell im Café etwas zu essen und zu trinken. Benutze möchte und bitte.", - "Guten Tag, ich möchte eine Suppe und ein Brot, bitte. Für mich bitte auch einen Tee. Meine Schwester möchte einen Apfelsaft. Die Suppe schmeckt gut. Die Rechnung, bitte. Danke, das ist alles.", - "möchte|bitte", - 25, - ), - quiz=[ - Q("der Salat im Akkusativ", - ["eine Salat", "einen Salat", "einem Salat", "der Salat bleibt immer"], - 1, "Maskulinum: einen."), - Q("Was ist höflich?", - ["Ich will sofort Pizza.", "Ich möchte eine Suppe, bitte.", "Gib mir Essen.", "Du bist Hunger."], - 1, "möchte + bitte."), - Q("die Suppe im Akkusativ", - ["einen Suppe", "einem Suppe", "eine Suppe", "ein Suppe"], - 2, "Femininum se nemění: eine Suppe."), - Q("Ich ___ einen Tee.", - ["möchte", "möchtest", "möchten du", "bist möchte"], - 0, "ich möchte."), - ], - ), - L( - "Můj den", - "My day", - "Čas a odlučitelné předpony. Čtení a doplňování.", - "Time and separable verbs. Reading and gaps.", - [ - S("1 / 2 • Čas", "Um, am, im", - "Tip: um + hodina, am + den, im + měsíc nebo roční období.", - [ - "Um sieben stehe ich auf. Am Montag habe ich Deutsch.", - "Im Sommer fahre ich ans Meer.", - "Odlučitelné: aufstehen → Ich stehe um sieben auf.", - "Předpona jde na konec věty.", - ]), - S("2 / 2 • Pořadí", "Nejdřív, potom, nakonec", - "Tip: zuerst, dann, danach, zum Schluss.", - [ - "Zuerst stehe ich auf. Dann frühstücke ich.", - "Danach gehe ich zur Schule.", - "Am Abend sehe ich fern.", - "fernsehen → Ich sehe abends fern.", - ]), - ], - reading=( - "An einem Schultag stehe ich um halb sieben auf. Zuerst dusche ich, " - "dann frühstücke ich Brot und Tee. Um sieben fahre ich mit der " - "Straßenbahn zur Schule. Der Unterricht beginnt um acht. Nach der " - "Schule mache ich Hausaufgaben. Am Abend sehe ich manchmal fern " - "oder ich rufe eine Freundin an. Um zehn gehe ich ins Bett." - ), - readq=[ - Q("Wann steht sie auf?", - ["Um zehn", "Um halb sieben", "Um acht", "Am Abend"], - 1, "um halb sieben."), - Q("Womit fährt sie zur Schule?", - ["Mit dem Auto", "Mit der Straßenbahn", "Zu Fuß nur", "Mit dem Zug"], - 1, "mit der Straßenbahn."), - Q("Was macht sie nach der Schule?", - ["Sie schläft sofort", "Sie macht Hausaufgaben", "Sie fährt ans Meer", "Sie hat frei"], - 1, "mache ich Hausaufgaben."), - Q("anrufen v větě Ich ___ eine Freundin ___.", - ["rufe … an", "anrufe …", "rufe … auf", "stehe … an"], - 0, "Předpona an jde na konec."), - ], - gaps=[ - G("Ich stehe um sieben ___.", "auf", "aufstehen."), - G("___ Montag habe ich Deutsch.", "Am", "am + den."), - G("Der Unterricht beginnt ___ acht.", "um", "um + hodina."), - G("Ich sehe abends ___.", "fern", "fernsehen."), - ], - ), - L( - "Test 1. ročníku", - "Year 1 test", - "Čtení, poslech, gramatika A1 a krátké psaní.", - "Reading, listening, A1 grammar and a short text.", - [ - S("1 / 2 • A1", "Co už má sedět", - "Tip: bin pro věk, habe pro vlastnictví, sloveso na druhém místě.", - [ - "sein, haben, heißen, wohnen, möchten.", - "mein/dein, ein/einen.", - "um, am, odlučitelná předpona na konci.", - "Psaní: Guten Tag a bitte.", - ]), - S("2 / 2 • Kontrola", "Nejčastější chyby", - "Tip: po kontrole si přečtěte nápovědy.", - [ - "Ich bin 15, ne Ich habe 15 Jahre.", - "Ich komme aus Prag, ne Ich bin aus Prag kommen.", - "einen Apfel, ne ein Apfel jako předmět.", - "Ich stehe auf, ne Ich aufstehe.", - ]), - ], - reading=( - "Nina ist sechzehn und wohnt in Olomouc. Sie hat einen Bruder. " - "Er heißt Tom und er ist zehn. Am Morgen isst Nina Brot. In der " - "Schule lernt sie gern Deutsch, aber sie mag Mathe nicht. Nach " - "der Schule ruft sie ihre Freundin an." - ), - readq=[ - Q("Wo wohnt Nina?", - ["In Prag", "In Olomouc", "In Brno", "Der Text sagt es nicht"], - 1, "wohnt in Olomouc."), - Q("Wie alt ist Tom?", - ["Sechzehn", "Zehn", "Zwölf", "Fünfzehn"], - 1, "er ist zehn."), - Q("Was macht Nina nach der Schule?", - ["Sie schläft", "Sie ruft ihre Freundin an", "Sie kocht für Tom", "Sie fährt nach Wien"], - 1, "ruft sie ihre Freundin an."), - ], - listening=( - "Guten Tag, ich möchte einen Salat und ein Wasser, bitte. " - "Haben Sie auch Brot? Ja, natürlich. Dann bitte noch ein Brot. " - "Möchten Sie Kaffee? Nein, danke, nur Wasser. Die Rechnung " - "mache ich später." - ), - listenq=[ - Q("Was bestellt die Person zuerst?", - ["Kaffee und Kuchen", "Einen Salat und ein Wasser", "Nur Brot", "Eine Suppe"], - 1, "einen Salat und ein Wasser."), - Q("Möchte sie Kaffee?", - ["Ja", "Nein", "Nur am Abend", "Der Text sagt es nicht"], - 1, "Nein, danke."), - Q("Was kommt noch dazu?", - ["Ein Brot", "Ein Tee", "Ein Hund", "Die Oma"], - 0, "noch ein Brot."), - ], - quiz=[ - Q("Ich ___ fünfzehn Jahre alt.", - ["habe", "bin", "ist", "hat"], - 1, "Alter mit sein."), - Q("Sie hat ___ Bruder.", - ["eine", "einen", "einem", "der"], - 1, "der Bruder → einen Bruder."), - Q("Ich stehe um sieben ___.", - ["auf", "an", "ein", "um"], - 0, "aufstehen."), - Q("___ du aus Prag?", - ["Kommst", "Wohnst", "Bist", "Hast"], - 0, "kommen aus: Kommst du aus Prag?"), - ], - writing=W( - "Schreib mindestens 30 Wörter über deine Familie. Benutze bin und habe.", - "Ich bin sechzehn und ich wohne in Prag. Ich habe eine Schwester und meine Eltern. Mein Vater ist nett und meine Mutter arbeitet viel. Wir haben keine Katze, aber ich habe einen Freund in der Schule. Am Sonntag besuchen wir oft meine Oma.", - "bin|habe", - 30, - ), - ), - ], - }, - { - "sub_cs": "Město, nákupy, volný čas, bydlení a perfektum. Úroveň A2.", - "sub_en": "Town, shopping, free time, home and the perfect. Level A2.", - "lessons": [ - L( - "Ve městě", - "In town", - "Wo a wohin, předložky. Doplňování a kvíz.", - "Wo and wohin, prepositions. Gaps and a quiz.", - [ - S("1 / 2 • Místo", "Kde a kam", - "Tip: wo ptá kde to je, wohin ptá kam někdo jde.", - [ - "Wo ist der Bahnhof? — Er ist neben der Post.", - "Wohin gehst du? — Ich gehe zum Bahnhof.", - "in, an, auf, neben, zwischen, gegenüber.", - "zu + der = zur, zu + dem = zum.", - ]), - S("2 / 2 • Popis cesty", "Krátké věty", - "Tip: zuerst, dann, dann links, dann rechts.", - [ - "Gehen Sie geradeaus.", - "Nehmen Sie die erste Straße links.", - "Die Apotheke ist gegenüber vom Park.", - "Es ist nicht weit.", - ]), - ], - gaps=[ - G("Wo ___ der Bahnhof?", "ist", "Wo + sein."), - G("Ich gehe ___ Bahnhof.", "zum", "zu + dem = zum."), - G("Die Post ist ___ der Schule.", "neben", "vedle."), - G("___ gehst du?", "Wohin", "Kam."), - G("Gehen Sie ___.", "geradeaus", "rovně."), - ], - quiz=[ - Q("Wohin bedeutet…", - ["wo", "woher", "kam", "wann"], - 2, "wohine = kam."), - Q("zu + dem", - ["zur", "zum", "zu dem bleibt immer zwei Wörter", "beim"], - 1, "zum."), - Q("zu + der", - ["zum", "zur", "zu die", "am"], - 1, "zur."), - Q("Die Apotheke ist ___ vom Park.", - ["gegenüber", "weil", "um", "aufstehe"], - 0, "gegenüber."), - ], - ), - L( - "Nákupy", - "Shopping", - "Ceny a 4. pád v obchodě. Čtení a kvíz.", - "Prices and the accusative in a shop. Reading and a quiz.", - [ - S("1 / 2 • Obchod", "Kolik to stojí", - "Tip: Wie viel kostet das? Es kostet fünf Euro.", - [ - "Ich suche einen Pullover.", - "Haben Sie das auch in Blau?", - "Das ist mir zu teuer. Haben Sie etwas Billigeres?", - "Ich nehme den Pullover.", - ]), - S("2 / 2 • Barvy a velikost", - "Velikost", - "Tip: die Größe M, zu klein, zu groß.", - [ - "groß, klein, billig, teuer, bequem.", - "die Jacke, der Schuh, das Hemd.", - "Zahlen: zweiundzwanzig Euro.", - "Bar oder mit Karte?", - ]), - ], - reading=( - "Anna sucht eine Jacke. Die rote Jacke kostet neunzig Euro. " - "Das ist ihr zu teuer. Eine blaue Jacke kostet fünfundvierzig Euro " - "und sie ist bequem. Anna nimmt die blaue Jacke. Dazu kauft sie " - "noch ein Hemd für ihren Bruder. Das Hemd kostet zwanzig Euro. " - "Sie zahlt mit Karte." - ), - readq=[ - Q("Warum nimmt Anna die rote Jacke nicht?", - ["Sie ist zu klein", "Sie ist zu teuer", "Es gibt sie nicht", "Sie ist nicht rot"], - 1, "zu teuer."), - Q("Was kostet die blaue Jacke?", - ["90 Euro", "45 Euro", "20 Euro", "22 Euro"], - 1, "fünfundvierzig Euro."), - Q("Für wen ist das Hemd?", - ["Für Anna", "Für den Bruder", "Für die Lehrerin", "Für niemanden"], - 1, "für ihren Bruder."), - Q("Wie zahlt sie?", - ["Bar", "Mit Karte", "Sie zahlt nicht", "Mit dem Hemd"], - 1, "mit Karte."), - ], - quiz=[ - Q("Ich suche ___ Pullover.", - ["eine", "einen", "einem", "der"], - 1, "der Pullover → einen."), - Q("Das ist mir zu ___. Ich habe nur zwanzig Euro.", - ["billig", "teuer", "bequem", "blau"], - 1, "zu teuer."), - Q("Wie viel ___ das?", - ["kostet", "kosten du", "bist", "heißt"], - 0, "kostet."), - Q("Sie zahlt ___ Karte.", - ["mit", "zu", "am", "auf"], - 0, "mit Karte."), - ], - ), - L( - "Volný čas", - "Free time", - "Modální slovesa. Poslech a doplňování.", - "Modal verbs. Listening and gaps.", - [ - S("1 / 2 • Modály", "können, müssen, wollen", - "Tip: modální sloveso je na druhém místě, významové na konci.", - [ - "Ich kann schwimmen. Du musst lernen. Wir wollen ins Kino.", - "können: ich kann, du kannst, er kann, wir können.", - "müssen: ich muss, du musst, er muss.", - "Zápor: Ich kann heute nicht kommen.", - ]), - S("2 / 2 • Koníčky", "gern a lieber", - "Tip: Ich schwimme gern. Ich spiele lieber Fußball als Tennis.", - [ - "das Hobby, die Mannschaft, das Training.", - "am Wochenende, in der Freizeit.", - "zu laut, zu spät.", - "Darf ich mitkommen?", - ]), - ], - listening=( - "Am Samstag muss ich vormittags lernen, weil wir am Montag einen " - "Test haben. Nachmittags kann ich aber Fußball spielen. Mein Freund " - "Paul will auch kommen. Er kann nicht so gut spielen, aber er ist " - "nett. Abends wollen wir einen Film sehen. Ich darf nicht zu spät " - "nach Hause kommen. Um elf muss ich zu Hause sein." - ), - listenq=[ - Q("Warum muss er vormittags lernen?", - ["Weil er krank ist", "Weil am Montag ein Test ist", "Weil Paul nicht kann", "Weil der Film lang ist"], - 1, "am Montag einen Test."), - Q("Was kann er nachmittags machen?", - ["Schlafen", "Fußball spielen", "Nach Wien fahren", "Kochen"], - 1, "Fußball spielen."), - Q("Wann muss er zu Hause sein?", - ["Um neun", "Um zehn", "Um elf", "Um zwölf"], - 2, "Um elf."), - Q("Was wollen sie abends machen?", - ["Einen Film sehen", "Lernen", "Fußball spielen", "Einkaufen"], - 0, "einen Film sehen."), - ], - gaps=[ - G("Ich ___ heute nicht kommen.", "kann", "können, ich kann."), - G("Du ___ lernen.", "musst", "müssen, du musst."), - G("Wir ___ ins Kino.", "wollen", "wollen, wir wollen."), - G("Das Modalverb steht, das andere Verb steht am ___.", "Ende|Satzende", "Významové sloveso na konci."), - ], - ), - L( - "Bydlení", - "Home", - "Místnosti a předložky. Popis bytu.", - "Rooms and prepositions. A description of a flat.", - [ - S("1 / 2 • Byt", "Wo steht was", - "Tip: Es gibt + akuzativ. Es gibt einen Balkon.", - [ - "die Küche, das Wohnzimmer, das Bad, das Schlafzimmer.", - "Das Sofa steht vor dem Fenster.", - "an der Wand, auf dem Tisch, unter dem Bett.", - "hell, dunkel, ruhig, laut, gemütlich.", - ]), - S("2 / 2 • Psaní", "Můj pokoj", - "Tip: nejdřív velikost, pak nábytek a místo.", - [ - "Mein Zimmer ist klein, aber hell.", - "Es gibt ein Bett und einen Schreibtisch.", - "Das Buch liegt auf dem Tisch.", - "Ich mag mein Zimmer, weil es ruhig ist.", - ]), - ], - writing=W( - "Beschreib dein Zimmer in mindestens 35 Wörtern. Benutze es gibt und weil.", - "Mein Zimmer ist klein, aber hell. Es gibt ein Bett, einen Schreibtisch und ein Fenster. Das Bett steht an der Wand und der Schreibtisch steht vor dem Fenster. Meine Bücher liegen auf dem Tisch. Ich mag das Zimmer, weil es ruhig ist und ich dort gut lernen kann.", - "weil|gibt", - 35, - ), - quiz=[ - Q("Es gibt ___ Balkon.", - ["ein", "einen", "einem", "der"], - 1, "der Balkon → einen."), - Q("Das Buch liegt ___ dem Tisch.", - ["auf", "weil", "um", "zum"], - 0, "auf dem Tisch."), - Q("gemütlich bedeutet…", - ["teuer", "příjemný, útulný", "hlasitý", "prázdný"], - 1, "útulný."), - Q("Das Bad ist…", - ["die Küche", "koupelna", "ložnice", "balkon"], - 1, "das Bad = koupelna."), - ], - ), - L( - "Perfektum", - "The perfect tense", - "Haben nebo sein a příčestí. Doplňování a kvíz.", - "Haben or sein plus the participle. Gaps and a quiz.", - [ - S("1 / 2 • Perfekt", "Minulost v hovoru", - "Tip: haben/sein je na druhém místě, příčestí na konci.", - [ - "Ich habe gestern Fußball gespielt.", - "Ich bin nach Wien gefahren. Pohyb a změna stavu berou sein.", - "ge- + kmen + t u pravidelných: gemacht, gespielt.", - "Nepravidelné: gesehen, gegessen, getrunken, genommen.", - ]), - S("2 / 2 • Signály", "Kdy", - "Tip: gestern, letzte Woche, vor zwei Tagen, im Urlaub.", - [ - "gehen → ist gegangen. kommen → ist gekommen.", - "bleiben → ist geblieben.", - "kaufen → hat gekauft. Lernen bere sein, protože to není pohyb.", - "Otázka: Hast du das gesehen? Bist du gekommen?", - ]), - ], - gaps=[ - G("Ich ___ gestern Tennis gespielt.", "habe", "spielen bere haben."), - G("Wir ___ nach Berlin gefahren.", "sind", "fahren bere sein."), - G("Er hat einen Film ___.", "gesehen", "sehen → gesehen."), - G("___ du gut geschlafen?", "Hast", "schlafen s haben v této učebnicové řadě často haben; otázka Hast du."), - G("Sie ist um acht ___ Hause gekommen.", "nach", "nach Hause."), - ], - quiz=[ - Q("gehen im Perfekt", - ["hat gegangen", "ist gegangen", "ist gehen", "hat gegehen"], - 1, "ist gegangen."), - Q("kaufen im Perfekt", - ["ist gekauft", "hat gekauft", "hat kaufen", "ist gekaufen"], - 1, "hat gekauft."), - Q("Wo steht das Partizip?", - ["Am Anfang", "Am Ende", "Vor dem Subjekt", "Es verschwindet"], - 1, "Na konci."), - Q("gestern bedeutet…", - ["zítra", "včera", "vždycky", "nikdy"], - 1, "včera."), - ], - ), - L( - "Test 2. ročníku", - "Year 2 test", - "Čtení, poslech, A2 a krátké psaní.", - "Reading, listening, A2 and a short text.", - [ - S("1 / 2 • A2", "Nové jevy", - "Tip: wohin, modální sloveso, perfektum, es gibt.", - [ - "zum a zur.", - "Ich kann / muss / will + infinitiv na konci.", - "habe gemacht, bin gegangen.", - "weil přijde ve 3. ročníku pořádně, tady stačí protože v jednoduché větě.", - ]), - S("2 / 2 • Strategie", - "Jedna věta", - "Tip: v psaní ať je sloveso na druhém místě.", - [ - "Nejdřív podmět, pak sloveso.", - "Čísla si zapište.", - "einen u maskulina ve 4. pádu.", - "Partizip na konec.", - ]), - ], - reading=( - "Letztes Wochenende bin ich mit Paul in die Stadt gefahren. " - "Zuerst haben wir einen Pullover gesucht. Er war zu teuer. " - "Dann sind wir ins Café gegangen. Ich habe einen Kuchen gegessen " - "und Paul hat einen Tee getrunken. Danach sind wir nach Hause " - "gefahren, weil Paul lernen musste." - ), - readq=[ - Q("Wohin sind sie zuerst gefahren?", - ["Nach Hause", "In die Stadt", "Ins Krankenhaus", "Nach Wien"], - 1, "in die Stadt."), - Q("Warum haben sie den Pullover nicht genommen?", - ["Er war zu teuer", "Er war blau", "Paul war krank", "Das Café war zu"], - 0, "zu teuer."), - Q("Warum sind sie nach Hause gefahren?", - ["Weil der Tee kalt war", "Weil Paul lernen musste", "Weil es geregnet hat", "Weil der Zug weg war"], - 1, "weil Paul lernen musste."), - ], - listening=( - "Entschuldigung, wo ist die Apotheke? Gehen Sie geradeaus und " - "dann links. Sie ist neben der Post. Ist es weit? Nein, nur " - "fünf Minuten. Danke! Kann ich dort auch Tee kaufen? Nein, " - "Tee gibt es im Supermarkt gegenüber." - ), - listenq=[ - Q("Wo ist die Apotheke?", - ["Im Bahnhof", "Neben der Post", "Im Café", "Weit vom Zentrum"], - 1, "neben der Post."), - Q("Wie weit ist es?", - ["Fünf Minuten", "Eine Stunde", "Zu weit", "Neben dem Tee"], - 0, "fünf Minuten."), - Q("Wo gibt es Tee?", - ["In der Apotheke", "Im Supermarkt gegenüber", "Im Zug", "Nirgends"], - 1, "im Supermarkt gegenüber."), - ], - quiz=[ - Q("Ich ___ schwimmen.", - ["kann", "kannst", "bin kann", "können"], - 0, "ich kann."), - Q("Wir sind nach Prag ___.", - ["gefahren", "gefahrt", "fahren", "gegeht"], - 0, "gefahren."), - Q("Es gibt ___ Balkon.", - ["ein", "einen", "einem", "eine"], - 1, "einen Balkon."), - Q("Wohin ___ du?", - ["gehst", "kommst aus", "bist wo", "hast wohin"], - 0, "Wohin gehst du?"), - ], - writing=W( - "Schreib mindestens 30 Wörter. Was hast du gestern gemacht? Benutze habe und bin.", - "Gestern bin ich in die Schule gegangen und ich habe einen Test geschrieben. Danach habe ich mit Eva gesprochen. Am Abend bin ich nach Hause gekommen und ich habe Musik gehört. Ich bin um elf ins Bett gegangen.", - "habe|bin", - 30, - ), - ), - ], - }, - { - "sub_cs": "Zdraví, cestování, věty s weil, práce a srovnání. Úroveň A2+.", - "sub_en": "Health, travel, weil-clauses, work and comparison. Level A2+.", - "lessons": [ - L( - "U lékaře", - "At the doctor's", - "Tělo, tut a rozkaz. Čtení a kvíz.", - "The body, tut and the imperative. Reading and a quiz.", - [ - S("1 / 2 • Körper", "Co mě bolí", - "Tip: Mir tut der Kopf weh. Ich habe Fieber.", - [ - "der Kopf, der Hals, der Bauch, der Rücken.", - "Ich fühle mich nicht gut.", - "Du sollst viel trinken. Sie müssen im Bett bleiben.", - "Rozkaz: Trink Wasser! Bleiben Sie zu Hause!", - ]), - S("2 / 2 • Rada", "sollen", - "Tip: sollen je rada. müssen je nutné.", - [ - "Du sollst heute nicht trainieren.", - "Sie müssen die Tabletten zweimal am Tag nehmen.", - "Gute Besserung!", - "die Apotheke, das Rezept, die Tablette.", - ]), - ], - reading=( - "Tom hat Halsschmerzen und ein bisschen Fieber. Die Ärztin sagt: " - "Sie sollen viel trinken und heute zu Hause bleiben. Sie müssen " - "nicht im Bett liegen, aber Sie sollen nicht Fußball spielen. " - "Hier ist ein Rezept. Die Tabletten nehmen Sie zweimal am Tag. " - "Wenn es am Freitag nicht besser ist, kommen Sie wieder." - ), - readq=[ - Q("Was hat Tom?", - ["Nur Kopfschmerzen", "Halsschmerzen und Fieber", "Ein gebrochenes Bein", "Keine Symptome"], - 1, "Halsschmerzen und Fieber."), - Q("Was soll er heute nicht machen?", - ["Trinken", "Fußball spielen", "Zum Arzt gehen", "Schlafen"], - 1, "nicht Fußball spielen."), - Q("Wie oft nimmt er die Tabletten?", - ["Einmal", "Zweimal am Tag", "Nur am Freitag", "Gar nicht"], - 1, "zweimal am Tag."), - Q("Wann kommt er wieder?", - ["Wenn es am Freitag nicht besser ist", "Jeden Morgen", "Nie", "Nur mit dem Rezept"], - 0, "am Freitag."), - ], - quiz=[ - Q("Mir tut der Kopf ___.", - ["weh", "gut", "auf", "zum"], - 0, "weh tun."), - Q("Du ___ viel trinken. Das ist ein Rat.", - ["sollst", "bist", "heißt", "wohinst"], - 0, "sollen."), - Q("Gute Besserung znamená…", - ["dobrou chuť", "brzké uzdravení", "na shledanou navždy", "účet prosím"], - 1, "uzdravení."), - Q("Rozkaz pro du od trinken", - ["Trinkst!", "Trink!", "Trinken du!", "Du trink bitte nicht Form"], - 1, "Trink!"), - ], - ), - L( - "Cesta", - "A trip", - "Perfektum v vyprávění. Poslech a doplňování.", - "The perfect in a story. Listening and gaps.", - [ - S("1 / 2 • Vyprávění", "Jedna věc po druhé", - "Tip: dann, danach, später, am Ende.", - [ - "Zuerst sind wir zum Bahnhof gegangen.", - "Der Zug hatte Verspätung, ale v A2 stačí: Der Zug war zu spät.", - "Wir haben Tickets gekauft.", - "angekommen, eingestiegen, ausgestiegen.", - ]), - S("2 / 2 • Vlak", "Slovník", - "Tip: der Bahnsteig, die Fahrkarte, umsteigen.", - [ - "eine einfache Fahrt, hin und zurück.", - "der Sitzplatz, das Abteil.", - "Entschuldigung, ist dieser Platz frei?", - "in Wien umsteigen.", - ]), - ], - listening=( - "Letzten Samstag sind wir nach Wien gefahren. Zuerst haben wir " - "am Automaten zwei Fahrkarten gekauft, hin und zurück. Der Zug " - "war zwanzig Minuten zu spät. Im Zug habe ich ein Buch gelesen " - "und meine Schwester hat geschlafen. In Wien sind wir am " - "Hauptbahnhof ausgestiegen. Danach haben wir die Innenstadt " - "gesehen. Am Abend sind wir wieder nach Hause gefahren." - ), - listenq=[ - Q("Wohin sind sie gefahren?", - ["Nach Berlin", "Nach Wien", "Nach Prag", "Ans Meer"], - 1, "nach Wien."), - Q("Wie viel Verspätung hatte der Zug?", - ["Keine", "Zehn Minuten", "Zwanzig Minuten", "Zwei Stunden"], - 2, "zwanzig Minuten."), - Q("Was hat die Schwester gemacht?", - ["Sie hat gelesen", "Sie hat geschlafen", "Sie hat gekocht", "Sie ist zu Hause geblieben"], - 1, "hat geschlafen."), - Q("Wo sind sie ausgestiegen?", - ["Am Hauptbahnhof", "Am Flughafen", "In der Schule", "Im Café"], - 0, "am Hauptbahnhof."), - ], - gaps=[ - G("Wir haben zwei Fahrkarten ___.", "gekauft", "kaufen → gekauft."), - G("Der Zug war zwanzig Minuten zu ___.", "spät", "zu spät."), - G("Wir sind in Wien ___.", "ausgestiegen", "aussteigen."), - G("Am Abend sind wir nach Hause ___.", "gefahren", "fahren → gefahren."), - ], - ), - L( - "Weil, dass, wenn", - "Weil, dass, wenn", - "Vedlejší věta a sloveso na konci. Doplňování a kvíz.", - "Subordinate clauses and the verb at the end. Gaps and a quiz.", - [ - S("1 / 2 • Sloveso na konci", "weil", - "Tip: po weil, dass a wenn jde sloveso na konec.", - [ - "Ich bleibe zu Hause, weil ich krank bin.", - "Sie sagt, dass sie morgen kommt.", - "Wenn es regnet, bleiben wir hier. V wenn-větě je sloveso na konci, v hlavní na druhém místě.", - "Čárka mezi větami.", - ]), - S("2 / 2 • denn a weil", - "Dvě možnosti", - "Tip: denn nemění pořádek. weil ano.", - [ - "Ich lerne, denn ich habe einen Test. Sloveso habe je druhé.", - "Ich lerne, weil ich einen Test habe.", - "dass není das. das je člen nebo vztažné.", - "ob = jestli v otázce: Ich weiß nicht, ob er kommt.", - ]), - ], - gaps=[ - G("Ich bleibe hier, weil ich krank ___.", "bin", "Sloveso na konci."), - G("Sie sagt, dass sie morgen ___.", "kommt", "dass + sloveso na konci."), - G("___ es regnet, bleiben wir zu Hause.", "Wenn", "když."), - G("Ich lerne, ___ ich einen Test habe.", "weil", "důvod se slovesem na konci."), - G("Ich weiß nicht, ___ er kommt.", "ob", "jestli."), - ], - quiz=[ - Q("Welche Variante ist richtig?", - ["weil ich bin krank", "weil ich krank bin", "weil bin ich krank", "weil ich krank ist"], - 1, "bin na konci."), - Q("denn…", - ["schickt das Verb ans Ende", "ändert die Wortstellung nicht", "bedeutet wenn", "ist ein Artikel"], - 1, "Po denn zůstává běžný pořádek."), - Q("dass oder das? Sie sagt, ___ sie kommt.", - ["das", "dass", "weil", "den"], - 1, "spojka dass."), - Q("Wenn es regnet, ___ wir zu Hause.", - ["bleiben", "bleiben wir", "wir bleiben am Ende nur", "bleibt du"], - 1, "V hlavní větě po wenn je sloveso první: bleiben wir."), - ], - ), - L( - "Práce a vykání", - "Work and Sie", - "Formální věta. E-mail a kvíz.", - "A formal sentence. An email and a quiz.", - [ - S("1 / 2 • Sie", "Vykání", - "Tip: Sie, Ihr, Ihnen se píšou velké.", - [ - "Wie heißen Sie? Was machen Sie beruflich?", - "Ich möchte mich bewerben.", - "der Lebenslauf, die Stelle, das Vorstellungsgespräch.", - "Mit freundlichen Grüßen.", - ]), - S("2 / 2 • E-mail", "Krátká žádost", - "Tip: Sehr geehrte Frau …, na konci jméno.", - [ - "Ich schreibe Ihnen, weil ich die Stelle interessant finde.", - "Im Anhang ist mein Lebenslauf.", - "Ich freue mich auf Ihre Antwort.", - "Ne Piš Hi a Tschüss ve formálním mailu.", - ]), - ], - writing=W( - "Schreib eine kurze formale E-Mail, mindestens 40 Wörter. Benutze Sie a Grüßen.", - "Sehr geehrte Frau Berger, ich schreibe Ihnen, weil ich die Stelle im Café interessant finde. Ich bin siebzehn und ich habe schon im Sommer in einem Geschäft gearbeitet. Ich kann am Samstag arbeiten. Können Sie mich anrufen? Im Anhang ist mein Lebenslauf. Mit freundlichen Grüßen, Eva Malá.", - "Sie|Grüßen", - 40, - ), - quiz=[ - Q("Vykání od heißen", - ["Wie heißt du?", "Wie heißen Sie?", "Wie heißt Sie?", "Wie heißen du?"], - 1, "Wie heißen Sie?"), - Q("Formální konec", - ["Tschüss, dein Freund", "Mit freundlichen Grüßen", "Hi und Kuss", "Bye weil"], - 1, "Mit freundlichen Grüßen."), - Q("der Lebenslauf je…", - ["účtenka", "životopis", "nádraží", "recept"], - 1, "životopis."), - Q("Ihr v Ich freue mich auf ___ Antwort.", - ["deine", "Ihre", "sein", "mein Sie"], - 1, "Ihre s velkým I."), - ], - ), - L( - "Srovnání a příroda", - "Comparison and nature", - "Komparativ a superlativ. Čtení a doplňování.", - "Comparative and superlative. Reading and gaps.", - [ - S("1 / 2 • Stupňování", "-er a am -sten", - "Tip: billig → billiger → am billigsten. gern → lieber → am liebsten.", - [ - "klein, kleiner, am kleinsten.", - "gut, besser, am besten. viel, mehr, am meisten.", - "als po komparativu: Prag ist größer als Pilsen.", - "so … wie: nicht so teuer wie.", - ]), - S("2 / 2 • Prostředí", "Jednoduchá slova", - "Tip: der Müll, trennen, sparen, die Natur, das Klima.", - [ - "zu Fuß gehen statt mit dem Auto fahren.", - "weniger Plastik, mehr Gemüse.", - "Ich finde die Bahn besser als das Flugzeug.", - "weil es die Umwelt schont.", - ]), - ], - reading=( - "Die Bahn ist oft besser für die Umwelt als das Flugzeug, aber " - "nicht immer billiger. Ein Ticket nach Berlin kann teurer sein " - "als ein Flug. Trotzdem fahren viele Jugendliche lieber mit dem " - "Zug, weil sie unterwegs lesen können. Am liebsten fahre ich " - "nachts, weil der Sitz dann so ruhig ist wie zu Hause." - ), - readq=[ - Q("Was ist oft besser für die Umwelt?", - ["Das Flugzeug", "Die Bahn", "Das Auto immer", "Nichts"], - 1, "Die Bahn."), - Q("Ist die Bahn immer billiger?", - ["Ja", "Nein", "Nur nachts", "Nur für Jugendliche"], - 1, "nicht immer billiger."), - Q("Warum fahren viele lieber mit dem Zug?", - ["Weil sie unterwegs lesen können", "Weil es immer gratis ist", "Weil es kein Flugzeug gibt", "Weil Berlin klein ist"], - 0, "lesen können."), - Q("am liebsten bedeutet…", - ["nejradši", "málo", "včera", "naproti"], - 0, "nejradši."), - ], - gaps=[ - G("Prag ist ___ (groß) als Pilsen.", "größer", "Komparativ + als."), - G("Das ist am ___.", "besten", "gut → am besten."), - G("Ich fahre ___ mit dem Zug als mit dem Flugzeug.", "lieber", "gern → lieber."), - G("Nicht so teuer ___ ein Flug.", "wie", "so … wie."), - ], - ), - L( - "Test 3. ročníku", - "Year 3 test", - "Čtení, poslech, weil a krátký názor.", - "Reading, listening, weil and a short opinion.", - [ - S("1 / 2 • A2+", "Věta", - "Tip: po weil je sloveso na konci. V perfektu je příčestí taky na konci.", - [ - "sollen a müssen.", - "weil, dass, wenn, ob.", - "Sie s velkým S.", - "größer als, am liebsten.", - ]), - S("2 / 2 • Psaní", "Jeden důvod", - "Tip: jedna věta s weil stačí, když je sloveso správně.", - [ - "Ich finde …, weil …", - "Neweil ich bin.", - "Konkrétní příklad.", - "Na konec Mit freundlichen Grüßen jen ve formálním textu.", - ]), - ], - reading=( - "Mia bleibt heute zu Hause, weil sie Fieber hat. Die Ärztin hat " - "gesagt, dass sie viel trinken soll. Wenn es morgen besser ist, " - "geht Mia wieder in die Schule. Sie findet die Bahn besser als " - "das Auto, aber heute kann sie nicht fahren." - ), - readq=[ - Q("Warum bleibt Mia zu Hause?", - ["Weil sie Fieber hat", "Weil die Bahn teuer ist", "Weil morgen Samstag ist", "Weil sie Fußball spielt"], - 0, "weil sie Fieber hat."), - Q("Was soll sie machen?", - ["Viel trinken", "Fußball spielen", "Nach Wien fahren", "Nichts sagen"], - 0, "viel trinken."), - Q("Was findet sie besser als das Auto?", - ["Das Flugzeug", "Die Bahn", "Das Fieber", "Die Schule"], - 1, "die Bahn."), - ], - listening=( - "Ich habe mich für die Stelle beworben, weil ich gern mit Menschen " - "arbeite. Die Chefin hat gesagt, dass ich am Samstag kommen soll. " - "Wenn das Gespräch gut ist, kann ich im Juli anfangen. Ich bin " - "nervös, aber ich freue mich." - ), - listenq=[ - Q("Warum hat sie sich beworben?", - ["Weil sie gern mit Menschen arbeitet", "Weil sie Fieber hat", "Weil der Zug zu spät war", "Weil sie nicht arbeiten will"], - 0, "gern mit Menschen."), - Q("Wann soll sie kommen?", - ["Am Montag", "Am Samstag", "Im Zug", "Nie"], - 1, "am Samstag."), - Q("Wann kann sie anfangen?", - ["Im Juli, wenn das Gespräch gut ist", "Gestern", "Nur im Winter", "Sie weiß es nicht"], - 0, "im Juli."), - ], - quiz=[ - Q("weil ich krank ___", - ["bin", "bin ich", "ist", "habe bin"], - 0, "bin na konci."), - Q("Mir tut der Hals ___.", - ["weh", "weil", "auf", "gern"], - 0, "weh."), - Q("größer ___ Berlin? Nein, Prag ist kleiner.", - ["wie", "als", "dass", "ob"], - 1, "Komparativ + als. Otázka je schválně o vztahu als."), - Q("Wie heißen ___?", - ["Sie", "du Sie", "dein", "dir"], - 0, "Sie."), - ], - writing=W( - "Schreib mindestens 35 Wörter. Was findest du besser, Bahn oder Auto, und warum? Benutze weil.", - "Ich finde die Bahn besser als das Auto, weil ich unterwegs lesen kann und nicht selbst fahren muss. Das Auto ist manchmal schneller, aber die Bahn ist ruhiger. Am liebsten fahre ich mit dem Zug, weil ich dabei Musik hören kann.", - "weil|besser", - 35, - ), - ), - ], - }, - { - "sub_cs": "Média, formální dopis, čtení, konjunktiv a maturitní témata. Úroveň B1.", - "sub_en": "Media, a formal letter, reading, the subjunctive and exam topics. Level B1.", - "lessons": [ - L( - "Média", - "The media", - "Poslech rozhovoru a kvíz k slovům.", - "An interview and a vocabulary quiz.", - [ - S("1 / 2 • Medien", "Co sleduju", - "Tip: die Nachrichten, die Serie, das Handy, der Account.", - [ - "Ich schaue selten fern, aber ich bin oft online.", - "eine Nachricht teilen, einen Kommentar schreiben.", - "Das stimmt nicht. Das ist ein Gerücht.", - "die Quelle, seriös, falsch.", - ]), - S("2 / 2 • Poslech", "Dvě otázky předem", - "Tip: čísla a zápor si zapište hned.", - [ - "seit zwei Jahren, jeden Abend, fast nie.", - "nicht mehr = už ne.", - "zu viel Zeit.", - "Ich habe gemerkt, dass …", - ]), - ], - listening=( - "Früher habe ich jeden Abend ferngesehen. Seit zwei Jahren mache " - "ich das nicht mehr. Ich höre einen Podcast auf dem Weg zur Schule " - "und ich lese die Nachrichten auf dem Handy. Manche Videos sind " - "lustig, aber nicht jede Quelle ist seriös. Letzte Woche habe ich " - "ein Gerücht geteilt und später gemerkt, dass es falsch war. " - "Seitdem prüfe ich den Text, bevor ich ihn schicke." - ), - listenq=[ - Q("Seit wann sieht er nicht mehr jeden Abend fern?", - ["Seit zwei Wochen", "Seit zwei Jahren", "Seit gestern", "Er sieht immer noch fern"], - 1, "Seit zwei Jahren."), - Q("Was hört er auf dem Weg zur Schule?", - ["Einen Podcast", "Nur Musik aus dem Fernseher", "Nichts", "Die Lehrerin"], - 0, "einen Podcast."), - Q("Was ist letzte Woche passiert?", - ["Er hat ein Gerücht geteilt", "Er hat den Fernseher gekauft", "Er hat die Prüfung bestanden", "Er ist nach Wien gefahren"], - 0, "ein Gerücht geteilt."), - Q("Was macht er seitdem?", - ["Er teilt alles sofort", "Er prüft den Text, bevor er ihn schickt", "Er sieht wieder jeden Abend fern", "Er schreibt keine Nachrichten"], - 1, "prüft den Text."), - Q("seriös bedeutet…", - ["vtipný", "důvěryhodný", "zdarma", "hlasitý"], - 1, "seriózní, důvěryhodný."), - ], - ), - L( - "Formální e-mail", - "A formal email", - "Stížnost nebo žádost. Psaní a kvíz.", - "A complaint or a request. Writing and a quiz.", - [ - S("1 / 2 • Kostra", "Čtyři části", - "Tip: oslovení, důvod, prosba, rozloučení.", - [ - "Sehr geehrte Damen und Herren,", - "Ich schreibe Ihnen, weil …", - "Ich bitte Sie um eine Antwort.", - "Mit freundlichen Grüßen und jméno.", - ]), - S("2 / 2 • Tón", "Klidně a konkrétně", - "Tip: datum, spoj, co chcete. Bez nadávek.", - [ - "Der Zug am 3. Mai hatte Verspätung.", - "Deshalb habe ich den Termin verpasst.", - "Ich bitte um eine Erklärung oder um Geld zurück.", - "Im Anhang finden Sie das Ticket.", - ]), - ], - writing=W( - "Schreib eine formelle E-Mail, mindestens 45 Wörter. Der Zug hatte Verspätung. Benutze Ihnen a Grüßen.", - "Sehr geehrte Damen und Herren, ich schreibe Ihnen, weil der Zug am 3. Mai nach Berlin zwanzig Minuten zu spät war. Deshalb habe ich meinen Termin verpasst. Ich bitte Sie um eine Erklärung oder um das Geld zurück. Im Anhang ist mein Ticket. Mit freundlichen Grüßen, Tereza Malá.", - "Ihnen|Grüßen", - 45, - ), - quiz=[ - Q("Neznámé jméno", - ["Hi Leute", "Sehr geehrte Damen und Herren", "Tschüss Chef", "Liebe du"], - 1, "Damen und Herren."), - Q("Ich schreibe ___, weil …", - ["dir du", "Ihnen", "dein", "euch Sie"], - 1, "Ihnen."), - Q("im Anhang znamená…", - ["v příloze", "na nástupišti", "včera", "zdarma"], - 0, "v příloze."), - Q("Který konec sedí?", - ["Bye!", "Mit freundlichen Grüßen", "Dein Kumpel", "Kuss"], - 1, "Mit freundlichen Grüßen."), - ], - ), - L( - "Čtení: noční vlak", - "Reading: the night train", - "Delší text a otázky jako u maturity.", - "A longer text and exam-style questions.", - [ - S("1 / 2 • Čtení", "Nejdřív otázka", - "Tip: nehledejte stejné slovo, hledejte stejný význam.", - [ - "Hlavní myšlenka bývá na začátku nebo na konci.", - "obwohl = ačkoli. Sloveso po obwohl je na konci.", - "trotzdem = přesto. Po trotzdem je běžný pořádek.", - "die Verspätung, das Abteil, der Schaffner.", - ]), - S("2 / 2 • Slovo z kontextu", - "Neznámé slovo", - "Tip: věta před ním a za ním ho ohraničí.", - [ - "umsteigen = přestupovat.", - "pünktlich = včas.", - "sich lohnen = vyplatit se.", - "lieber = radši.", - ]), - ], - reading=( - "Der Nachtzug von Prag nach Berlin ist für viele Jugendliche " - "interessanter als ein billiger Flug, obwohl das Ticket oft mehr " - "kostet. Man kann lesen, schlafen und muss nicht um fünf Uhr am " - "Flughafen sein. Kritiker sagen, dass die Verspätung ein Problem " - "ist und dass die Abteile klein sind. Trotzdem lohnt sich die Fahrt " - "für Lea. Sie ist schon dreimal gefahren. Sie sagt, dass sie nur " - "fliegt, wenn sie den Abendzug verpasst. Für sie ist die Reise ein " - "Teil des Urlaubs und nicht nur eine Strecke." - ), - readq=[ - Q("Was ist die Hauptidee?", - ["Flüge sind verboten", "Manche Leute nehmen den Nachtzug, obwohl er mehr kosten kann", "Berlin hat keinen Bahnhof", "Lea fliegt jeden Tag"], - 1, "obwohl das Ticket oft mehr kostet, přesto vlak volí."), - Q("Was kann man im Zug machen?", - ["Nur stehen", "Lesen und schlafen", "Das Flugzeug steuern", "Nichts"], - 1, "lesen, schlafen."), - Q("Was sagen die Kritiker?", - ["Der Zug ist immer gratis", "Verspätung und kleine Abteile sind ein Problem", "Es gibt keine Tickets", "Lea ist der Schaffner"], - 1, "Verspätung, Abteile klein."), - Q("Wann fliegt Lea?", - ["Immer", "Nur wenn sie den Abendzug verpasst", "Nie, das steht nicht so", "Jeden Morgen um fünf"], - 1, "wenn sie den Abendzug verpasst."), - Q("obwohl bedeutet…", - ["protože", "ačkoli", "potom", "bez"], - 1, "ačkoli."), - ], - ), - L( - "Kdyby", - "If I were", - "Konjunktiv II. Doplňování a kvíz.", - "Konjunktiv II. Gaps and a quiz.", - [ - S("1 / 2 • wäre a hätte", "Neskutečná podmínka", - "Tip: Wenn ich Zeit hätte, würde ich mehr lesen.", - [ - "haben → hätte, sein → wäre.", - "würde + infinitiv pro ostatní slovesa.", - "Wenn ich reich wäre, würde ich reisen.", - "Sloveso po wenn je na konci: Wenn ich Zeit hätte.", - ]), - S("2 / 2 • Zdvořilost", "würde a könnte", - "Tip: Könnten Sie mir helfen? je měkčí než Können Sie.", - [ - "Ich hätte gern einen Kaffee.", - "Würden Sie das bitte wiederholen?", - "An deiner Stelle würde ich warten.", - "Není to minulost, i když tvar vypadá jako minulý.", - ]), - ], - gaps=[ - G("Wenn ich Zeit ___, würde ich mehr lesen.", "hätte", "haben → hätte."), - G("Wenn ich reich ___, würde ich reisen.", "wäre", "sein → wäre."), - G("Ich ___ gern einen Kaffee.", "hätte", "Ich hätte gern."), - G("An deiner Stelle ___ ich warten.", "würde", "würde + infinitiv."), - G("___ Sie das bitte wiederholen?", "Würden|Könnten", "Zdvořilá prosba."), - ], - quiz=[ - Q("Wenn ich du wäre, ___ ich das nicht machen.", - ["werde", "würde", "bin", "hast"], - 1, "würde."), - Q("hätte je od slovesa…", - ["sein", "haben", "werden", "gehen"], - 1, "haben."), - Q("Könnten Sie… je…", - ["rozkaz", "zdvořilejší otázka", "minulý čas perfekta", "člen"], - 1, "zdvořilost."), - Q("Welche Satz ist richtig?", - ["Wenn ich hätte Zeit", "Wenn ich Zeit hätte", "Wenn hätte ich Zeit", "Wenn ich Zeit habe würde nur so"], - 1, "hätte na konci."), - ], - ), - L( - "Témata k maturitě", - "Exam topics", - "Kolokace k běžným okruhům. Doplňování a kvíz.", - "Collocations for common topics. Gaps and a quiz.", - [ - S("1 / 2 • Okruhy", "Ne izolovaná slovíčka", - "Tip: ústní zkouška z němčiny bere osobu, rodinu, školu, volný čas, město, zdraví, práci a média.", - [ - "eine Meinung haben, ein Beispiel nennen.", - "zu Fuß gehen, mit der Bahn fahren, im Stau stehen.", - "sich gesund ernähren, Sport treiben.", - "einen Nebenjob haben, Geld verdienen.", - ]), - S("2 / 2 • Věta navíc", - "Obecné a osobní", - "Tip: Viele Jugendliche … Ich persönlich …", - [ - "Einerseits … andererseits …", - "Das finde ich gut, weil …", - "Zum Beispiel …", - "Zusammenfassend …", - ]), - ], - gaps=[ - G("Ich treibe dreimal pro Woche ___.", "Sport", "Sport treiben."), - G("Viele Leute stehen morgens im ___.", "Stau", "im Stau stehen."), - G("Sie hat einen ___ im Café.", "Nebenjob|Job", "brigáda, práce."), - G("Ich persönlich ___ die Bahn besser.", "finde", "finden."), - G("___ Beispiel lese ich im Zug.", "Zum", "Zum Beispiel."), - ], - quiz=[ - Q("einerseits … andererseits", - ["nejdřív a nakonec bez kontrastu", "na jedné straně … na druhé straně", "protože … když", "včera … zítra"], - 1, "kontrast."), - Q("sich gesund ernähren", - ["zdravě jíst", "být v zácpě", "psát e-mail", "zmeškat vlak"], - 0, "stravovat se."), - Q("Was passt zu einer mündlichen Prüfung?", - ["Nur einzelne Wörter", "Eine allgemeine Aussage und ein persönliches Beispiel", "Ein Formular ohne Verben", "Nur Ja"], - 1, "obecné plus příklad."), - Q("im Stau stehen", - ["stát ve frontě v bance jen", "být v dopravní zácpě", "stát na balkóně", "stát v čele třídy"], - 1, "zácpa."), - ], - ), - L( - "Cvičná zkouška", - "A practice paper", - "Čtení, poslech, gramatika a krátký text.", - "Reading, listening, grammar and a short text.", - [ - S("1 / 2 • Celek", "Tři dovednosti", - "Tip: nejdřív si přečtěte otázky. U weil a wenn kontrolujte konec věty.", - [ - "Čtení: význam, ne stejné slovo.", - "Poslech: čísla a nein.", - "Konjunktiv: hätte, wäre, würde.", - "Psaní: sloveso na druhém místě v hlavní větě.", - ]), - S("2 / 2 • Text", - "Kamarádovi", - "Tip: tady není formální mail. Hallo stačí, ale věty ať jsou celé.", - [ - "Napište proč píšete.", - "Jedna věta s weil.", - "Jedna věta s wenn nebo würde.", - "Otázka na konci.", - ]), - ], - reading=( - "In unserer Bibliothek kann man jetzt nicht nur Bücher, sondern " - "auch Werkzeug ausleihen. Die Idee kommt von einer Bibliothekarin, " - "die sagte, dass viele Leute Dinge kaufen, die sie nur einmal " - "brauchen. Im März haben Jugendliche zwanzig Wasserkocher repariert. " - "Wenn das Projekt weitergeht, machen andere Bibliotheken mit. " - "Man muss die Sachen sauber zurückgeben." - ), - readq=[ - Q("Was kann man außer Büchern ausleihen?", - ["Autos", "Werkzeug", "Wohnungen", "Flugtickets"], - 1, "Werkzeug."), - Q("Warum entstand die Idee?", - ["Weil Leute Dinge nur einmal brauchen und trotzdem kaufen", "Weil es keine Bücher gibt", "Weil der Zug zu spät war", "Weil niemand liest"], - 0, "nur einmal brauchen."), - Q("Wie viele Wasserkocher haben sie im März repariert?", - ["Zwei", "Zwölf", "Zwanzig", "Zweihundert"], - 2, "zwanzig."), - Q("Was muss man machen?", - ["Die Sachen sauber zurückgeben", "Einen neuen Kocher kaufen", "Nach Berlin fahren", "Nichts"], - 0, "sauber zurückgeben."), - ], - listening=( - "Der Nachtzug nach Berlin hat vierzig Minuten Verspätung, weil " - "ein Baum auf den Gleisen liegt. Fahrgäste mit einem Platz können " - "in Wagen vier warten. Wenn Sie noch nicht eingecheckt haben, " - "machen Sie das bitte am Handy. Wir wären froh, wenn der Gang frei " - "bliebe. Um zehn wissen wir mehr." - ), - listenq=[ - Q("Wie lang ist die Verspätung?", - ["Vier Minuten", "Vierzig Minuten", "Vier Stunden", "Der Zug ist pünktlich"], - 1, "vierzig Minuten."), - Q("Warum?", - ["Schnee", "Ein Baum auf den Gleisen", "Kein Personal", "Ein Fest"], - 1, "ein Baum."), - Q("Wo können Fahrgäste mit Platz warten?", - ["In Wagen vier", "Am Flughafen", "Zu Hause", "Im Gang"], - 0, "Wagen vier."), - Q("Was sollen Leute ohne Check-in machen?", - ["Den Baum wegtragen", "Am Handy einchecken", "Nach Prag laufen", "Nichts sagen"], - 1, "am Handy."), - ], - quiz=[ - Q("Wenn ich Zeit ___, würde ich kommen.", - ["hätte", "habe würde", "bin", "hatte nur Perfekt"], - 0, "hätte."), - Q("Sie sagt, dass der Zug Verspätung ___.", - ["hat", "hat er", "ist hat", "haben"], - 0, "hat na konci."), - Q("Man muss die Sachen sauber ___.", - ["zurückgeben", "zurückgibt", "geben zurück sofort als einziges", "zu zurück"], - 0, "zurückgeben na konci po muss."), - Q("Ich wäre froh, wenn du ___.", - ["kommst sofort nur so", "kommen würdest", "bist kommen", "kommst du"], - 1, "würdest na konci je v pořádku. Alternativa wenn du kämst je těžší."), - ], - writing=W( - "Schreib mindestens 40 Wörter an einen Freund. Lad ihn ein, Werkzeug in der Bibliothek auszuleihen. Benutze weil.", - "Hallo Adam, in der Bibliothek kann man jetzt Werkzeug ausleihen, und ich glaube, das ist etwas für dich, weil du oft nur eine Bohrmaschine für einen Nachmittag brauchst. Wenn du am Samstag Zeit hast, komme ich mit. Wir müssen die Sachen danach sauber zurückgeben. Hast du Lust?", - "weil|wenn", - 40, - ), - ), - ], - }, -] - - -def main() -> None: - if len(YEARS) != 4 or any(len(y["lessons"]) != 6 for y in YEARS): - raise SystemExit("expected 4×6 lessons") - body = ["/* Generated by scripts/gen-german.py. Do not edit by hand. */", ""] - table = ["static const EnLesson de_lessons[DE_YEARS][DE_N] = {"] - i18n = [ - ' {"de_home_sub", "Učebnice a čtyři ročníky s poslechem, čtením a psaním.", "The textbook plus four years of listening, reading and writing."},', - ' {"de_book_title", "Učebnice", "Textbook"},', - ' {"de_book_sub", "Neue Freunde, Aus aller Welt a Bei uns zu Hause.", "Neue Freunde, Aus aller Welt and Bei uns zu Hause."},', - ' {"de_years_title", "Ročníky", "School years"},', - ] - for yi, year in enumerate(YEARS, start=1): - i18n.append( - f' {{"de_y{yi}_sub", {c_str(year["sub_cs"])}, {c_str(year["sub_en"])}}},' - ) - i18n.append( - f' {{"de_year{yi}", "{yi}. ročník", "Year {yi}"}},' - ) - row = [] - for li, lesson in enumerate(year["lessons"], start=1): - i18n.append( - f' {{"de_y{yi}_u{li}", {c_str(lesson["title_cs"])}, {c_str(lesson["title_en"])}}},' - ) - i18n.append( - f' {{"de_y{yi}_u{li}_sub", {c_str(lesson["sub_cs"])}, {c_str(lesson["sub_en"])}}},' - ) - inits = [] - emit_lesson(yi, li, lesson, body, inits, prefix="de") - row.append(inits[0]) - table.append(" {\n" + ",\n".join(row) + "\n },") - table.append("};") - table.append("") - body.extend(table) - (ROOT / "src" / "german_lessons.inc").write_text("\n".join(body) + "\n", encoding="utf-8") - (ROOT / "src" / "german_i18n.inc").write_text("\n".join(i18n) + "\n", encoding="utf-8") - print("wrote", 24, "german lessons") - - -if __name__ == "__main__": - main() diff --git a/scripts/gen-it-years.py b/scripts/gen-it-years.py deleted file mode 100644 index eb9e061..0000000 --- a/scripts/gen-it-years.py +++ /dev/null @@ -1,2472 +0,0 @@ -#!/usr/bin/env python3 -"""Years 2–4 of networks and hardware. Slides plus a four-question quiz.""" - -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] - - -def c(text): - return '"' + text.replace("\\", "\\\\").replace('"', '\\"') + '"' - - -def S(kicker, title, tip, *lines): - return (kicker, title, tip, lines) - - -def Q(prompt, options, correct, hint): - if len(options) != 4: - raise SystemExit(f"need 4 options: {prompt}") - if not 0 <= correct < 4: - raise SystemExit(prompt) - return (prompt, options, correct, hint) - - -def L(title, title_en, sub, sub_en, slides, quiz): - if len(slides) != 3 or len(quiz) != 4: - raise SystemExit(title) - return { - "title": title, "title_en": title_en, - "sub": sub, "sub_en": sub_en, - "slides": slides, "quiz": quiz, - } - - -def course(prefix, sub, sub_en, lessons): - if len(lessons) != 8: - raise SystemExit(f"{prefix} has {len(lessons)}") - return {"prefix": prefix, "sub": sub, "sub_en": sub_en, "lessons": lessons} - - -NET2 = course( - "net2", - "VLAN, STP, DHCP, DNS, NAT, IPv6, statické směrování a ACL.", - "VLANs, STP, DHCP, DNS, NAT, IPv6, static routing and ACLs.", - [ - L("VLAN a trunk", "VLANs and trunks", - "Logické sítě na jednom přepínači a značkovaný spoj.", - "Logical networks on one switch and a tagged link.", - [ - S("1 / 3 • VLAN", "Oddělení provozu", - "Tip: VLAN není samostatný kabel, je to značka v rámci.", - "VLAN sdružuje porty do jedné vysílací domény.", - "Počítače v různých VLAN spolu přímo na druhé vrstvě nemluví.", - "Číslo VLAN se na trunku vozí ve značce 802.1Q.", - "Nativní VLAN na trunku jede neznačkovaná. Na obou koncích musí sedět."), - S("2 / 3 • Porty", "Access a trunk", - "Tip: access port patří do jedné VLAN, trunk jich nese víc.", - "Access port se připojuje ke koncovému zařízení.", - "Trunk spojuje přepínače nebo přepínač s routerem.", - "Povolené VLAN na trunku omezí, co smí přejít.", - "Špatně nastavený trunk pustí cizí VLAN do špatné sítě."), - S("3 / 3 • Provoz", "K čemu se VLAN hodí", - "Tip: oddělení hostů od školy nesmí stát jen na hesle Wi-Fi.", - "Hosté, škola a správa mohou sdílet jeden přepínač.", - "Hlasová VLAN oddělí telefony od dat.", - "Mezi VLAN se dostane jen směrovač nebo přepínač třetí vrstvy.", - "VLAN zmenšuje broadcast, nenahrazuje firewall."), - ], - [ - Q("Co VLAN na přepínači dělá?", - ["Sdruží porty do jedné vysílací domény", "Zrychlí procesor serveru", - "Nahradí šifrování WPA3", "Přidělí veřejnou IPv4 adresu"], - 0, "VLAN odděluje provoz na druhé vrstvě."), - Q("Jak se VLAN pozná na trunku?", - ["Značkou 802.1Q v rámci", "Jinou MAC adresou zdroje", - "Jiným konektorem RJ11", "Bitem v ICMP"], - 0, "802.1Q vloží do ethernetového rámce číslo VLAN."), - Q("Kam patří access port?", - ["Ke koncovému počítači v jedné VLAN", "Jen mezi dvěma routery", - "Na optický spoj s vlnovým multiplexem", "Do napájecího zdroje"], - 0, "Access port má jednu VLAN a značku obvykle sundá."), - Q("Jak spolu mluví dvě různé VLAN?", - ["Přes směrování, ne přímo na druhé vrstvě", - "Samy od sebe, VLAN je jen barva kabelu", - "Jedině přes ARP broadcast do všech VLAN", - "Jen když mají stejnou MAC adresu"], - 0, "Mezi VLAN je potřeba router nebo L3 switch."), - ]), - L("STP a smyčky", "STP and loops", - "Proč smyčka na druhé vrstvě shodí síť a jak ji STP přeruší.", - "Why a layer-2 loop takes the network down, and how STP breaks it.", - [ - S("1 / 3 • Smyčka", "Broadcastová bouře", - "Tip: na druhé vrstvě není TTL, rámec může kroužit donekonečna.", - "Dva kabely mezi stejnými přepínači vytvoří smyčku.", - "Broadcast se kopíruje na všechny porty a vrátí se zpět.", - "Přepínač se zahltí a přestane přenášet užitečný provoz.", - "Na třetí vrstvě paket TTL snižuje, ethernetový rámec ne."), - S("2 / 3 • STP", "Jedna aktivní cesta", - "Tip: STP nevybírá nejrychlejší cestu pro data, brání smyčce.", - "Přepínače si volí root bridge, obvykle nejnižší bridge ID.", - "Některé porty zůstanou ve stavu blocking a rámce nepřeposílají.", - "Když aktivní linka spadne, blocking port se může otevřít.", - "RSTP reaguje rychleji než původní STP."), - S("3 / 3 • Ochrana", "Porty, které nemají přepínat", - "Tip: port k tiskárně nemá poslouchat cizí BPDU.", - "PortFast na access portu zrychlí připojení počítače.", - "BPDU Guard port shodí, když na něm přijde BPDU.", - "Root Guard brání tomu, aby se cizí switch stal rootem.", - "Záložní kabel má smysl, ale jen se zapnutým STP."), - ], - [ - Q("Proč je smyčka na přepínačích nebezpečná?", - ["Broadcast může kroužit bez omezení TTL", - "IPv4 přestane mít masku", - "DNS přejmenuje domény", - "Procesor v počítači se vypne"], - 0, "Ethernetový rámec nemá TTL."), - Q("Co STP s nadbytečným portem udělá?", - ["Nechá ho blokovat, aby nevznikla smyčka", - "Zdvojnásobí rychlost obou kabelů", - "Smaže MAC tabulku navždy", - "Přesměruje port na VLAN 1 a vypne ostatní"], - 0, "Blocking port rámce nepřeposílá, dokud není potřeba."), - Q("K čemu je BPDU Guard?", - ["Shodí access port, na kterém se objeví cizí přepínač", - "Šifruje heslo k Wi-Fi", - "Přiděluje IPv6 adresy", - "Měří útlum optiky"], - 0, "Na portu pro počítač nemá co dělat protokol přepínačů."), - Q("Které tvrzení o RSTP sedí?", - ["Na výpadek reaguje rychleji než původní STP", - "Ruší potřebu VLAN", - "Funguje jen na IPv6", - "Nahrazuje směrovací tabulku"], - 0, "RSTP zkracuje čekání při změně topologie."), - ]), - L("DHCP a DNS", "DHCP and DNS", - "Kdo přiděluje adresu a kdo překládá jméno.", - "Who hands out an address, and who translates a name.", - [ - S("1 / 3 • DHCP", "Adresa bez opisování", - "Tip: DHCP dává adresu na čas, ne navždy.", - "Klient pošle broadcast a hledá server.", - "Nabídka obsahuje adresu, masku, bránu a DNS.", - "Zapůjčení má dobu platnosti a klient ji obnovuje.", - "Rezervace přiváže adresu ke konkrétní MAC adrese."), - S("2 / 3 • Rozsah", "Co se nesmí překrývat", - "Tip: dva servery se stejnou adresou v jedné síti si škodí.", - "Rozsah musí ležet v síti, kterou má brána.", - "Statické adresy serverů do rozsahu nepatří, nebo se vyloučí.", - "Špatná brána v nabídce odřízne celou VLAN od internetu.", - "DHCP relay přenese požadavek z VLAN, kde server není."), - S("3 / 3 • DNS", "Jméno na adresu", - "Tip: DNS není totéž co DHCP. Jedno dává adresu, druhé jméno.", - "A záznam ukazuje na IPv4, AAAA na IPv6.", - "Reverzní PTR překládá adresu zpět na jméno.", - "Rekurzivní resolver se ptá dál, autoritativní server zónu vlastní.", - "TTL u záznamu říká, jak dlouho se smí odpověď cacheovat."), - ], - [ - Q("Co klient od DHCP obvykle dostane?", - ["Adresu, masku, bránu a DNS", "Jen heslo k Wi-Fi", - "Novou MAC adresu", "Kořenový certifikát webu"], - 0, "To jsou čtyři údaje, bez kterých stanice v síti nepracuje."), - Q("Proč se rezervace v DHCP hodí?", - ["Zařízení s danou MAC dostane pořád stejnou adresu", - "Vypne potřebu masky", - "Nahradí směrování", - "Zašifruje disk"], - 0, "Rezervace je vhodná pro tiskárny a kamery."), - Q("Čím se liší A a AAAA?", - ["A je IPv4, AAAA je IPv6", "A je pošta, AAAA je web", - "A je jméno VLAN, AAAA je číslo portu", - "Oba ukazují jen na IPv4"], - 0, "Čtyři A v názvu připomínají delší IPv6 adresu."), - Q("K čemu je DHCP relay?", - ["Pošle požadavek z jiné VLAN k serveru", - "Překládá jména bez DNS", - "Blokuje STP", - "Mění rychlost portu na 10 Gb/s"], - 0, "Broadcast DHCP jinak VLAN neopustí."), - ]), - L("NAT a PAT", "NAT and PAT", - "Jedna veřejná adresa pro mnoho počítačů.", - "One public address for many computers.", - [ - S("1 / 3 • NAT", "Soukromé adresy ven", - "Tip: 192.168.0.0/16 a 10.0.0.0/8 na internetu směrovat nejdou.", - "NAT přepíše zdrojovou adresu při odchodu z lokální sítě.", - "Zpět router podle tabulky překladů provoz vrátí.", - "Zvenku nikdo sám od sebe spojení dovnitř nenaváže.", - "To je vedlejší efekt, ne náhrada firewallu."), - S("2 / 3 • PAT", "Mnoho počítačů, jedna adresa", - "Tip: PAT si pamatuje i číslo portu, ne jen adresu.", - "Více vnitřních adres sdílí jednu veřejnou.", - "Rozliší je zdrojový port.", - "Domácí router dělá téměř vždy PAT, ne čistý NAT jedna ku jedné.", - "Dojdou-li porty, nová spojení se neotevřou."), - S("3 / 3 • Dovnitř", "Když má server být vidět", - "Tip: přesměrování portu otevře jen tu službu, kterou opravdu chcete.", - "Port forward pošle příchozí port na vnitřní adresu.", - "Na serveru pak musí poslouchat daná služba a firewall ji pustit.", - "DMZ na domácím routeru vystaví jeden počítač hodně otevřeně.", - "Lepší je konkrétní port než celá DMZ."), - ], - [ - Q("Proč stanice s adresou 192.168.1.20 není z internetu vidět přímo?", - ["Je to soukromá adresa a ven jde až přes NAT", - "IPv4 takové adresy nezná", - "MAC adresa se na internetu nesmí použít jako jméno", - "DNS soukromé adresy maže"], - 0, "Soukromé rozsahy se mezi poskytovateli nesměrují."), - Q("Čím se PAT liší od NAT jedna ku jedné?", - ["Více vnitřních adres sdílí jednu veřejnou a liší se portem", - "PAT šifruje provoz", - "PAT funguje jen pro IPv6", - "PAT ruší potřebu brány"], - 0, "Překlad zahrnuje adresu i port."), - Q("K čemu je přesměrování portu?", - ["Příchozí spojení na daný port pošle na vnitřní server", - "Přidělí VLAN", - "Zapne STP", - "Změní masku celé školy na /8"], - 0, "Bez něj zvenku na vnitřní web sami nedosáhnete."), - Q("Proč NAT není firewall?", - ["Jen překládá adresy, pravidla provozu řeší firewall", - "NAT umí totéž co antivir", - "NAT kontroluje hesla uživatelů", - "NAT šifruje Wi-Fi"], - 0, "Nechtěný publikovaný port NAT klidně pustí."), - ]), - L("IPv6 základy", "IPv6 basics", - "Delší adresa, jiný zápis a co se nemění.", - "A longer address, a different notation, and what stays the same.", - [ - S("1 / 3 • Adresa", "128 bitů", - "Tip: nuly v jedné skupině za sebou smí zkrátit :: jen jednou.", - "Adresa má osm skupin po čtyřech hexadecimálních číslicích.", - "Prefix se píše jako /64, ne jako stará maska 255.255.255.0.", - "Link-local adresa fe80:: platí jen na tom spoji.", - "Globální adresa je vidět i mimo místní spoj."), - S("2 / 3 • Přidělení", "SLAAC a DHCPv6", - "Tip: výchozí bránu v IPv6 často ohlašuje router, ne DHCP.", - "Router advertisement řekne prefix a jestli se stanice smí nastavit sama.", - "SLAAC složí adresu z prefixu a identifikátoru rozhraní.", - "DHCPv6 přidá adresu nebo jen DNS, podle příznaků.", - "Obě varianty mohou běžet vedle sebe."), - S("3 / 3 • Vedle IPv4", "Dual stack", - "Tip: IPv6 nevypínejte jen proto, že mu nerozumíte. Rozbitý IPv6 zpomalí i weby.", - "Počítač může mít IPv4 i IPv6 naráz.", - "DNS AAAA záznam rozhoduje, jestli se klient zkusí spojit po IPv6.", - "NAT u IPv6 není nutný tak jako u IPv4, ale firewall ano.", - "Ping na IPv6 je jiný příkaz než ping na IPv4, podle systému."), - ], - [ - Q("Jak je IPv6 adresa dlouhá?", - ["128 bitů", "32 bitů", "48 bitů", "256 bitů"], - 0, "IPv4 má 32 bitů, IPv6 čtyřikrát tolik."), - Q("Která adresa je link-local?", - ["fe80::1", "192.168.1.1", "8.8.8.8", "255.255.255.255"], - 0, "fe80:: platí jen na místním spoji."), - Q("Kdo v IPv6 často oznámí prefix?", - ["Router advertisement", "ARP request", - "STP hello", "Jen ruční zápis do hosts"], - 0, "Router říká stanicím, jaký prefix na spoji platí."), - Q("Co znamená dual stack?", - ["Zařízení používá IPv4 i IPv6", - "Dva switche v jedné VLAN", - "Dvě masky u jedné IPv4 adresy", - "Záloha jen na pásku"], - 0, "Oba protokoly běží současně."), - ]), - L("Statické směrování", "Static routing", - "Ruční cesta, metrika a kdy přestane stačit.", - "A hand-written route, the metric, and when it is no longer enough.", - [ - S("1 / 3 • Trasa", "Kam s paketem", - "Tip: směrovací tabulka se dívá na síť, ne na jednu adresu stanice.", - "Záznam říká síť, masku nebo prefix a další skok.", - "Další skok musí být dosažitelný na přímo připojeném rozhraní.", - "Výchozí trasa 0.0.0.0/0 chytí vše, co nemá přesnější záznam.", - "Přesnější prefix vyhraje nad kratším."), - S("2 / 3 • Metrika", "Když je cest víc", - "Tip: nižší administrativní vzdálenost znamená důvěryhodnější zdroj trasy.", - "Statická trasa má lepší vzdálenost než OSPF nebo RIP.", - "Metrika porovnává trasy ze stejného zdroje.", - "Plovoucí statická trasa má horší vzdálenost a čeká jako záloha.", - "Špatný další skok vytvoří černou díru: paket odejde a ztratí se."), - S("3 / 3 • Meze", "Kdy ruční tabulka nestačí", - "Tip: deset poboček se statickými trasami neudržíte po každé změně.", - "Statika je přehledná v malé síti a na okraji k poskytovateli.", - "Neumí sama obejít spadlou cestu, pokud záloha není připravená.", - "Na směrovači musí sedět trasa tam i zpět, jinak odpověď nepřijde.", - "Změna adresace znamená obejít všechny ruční záznamy."), - ], - [ - Q("Na co se směrovač dívá při výběru trasy?", - ["Na síť a prefix, ne na jméno počítače", - "Na barvu kabelu", - "Na VLAN jméno v DNS", - "Jen na MAC adresu cíle"], - 0, "Třetí vrstva směruje podle prefixu."), - Q("Která trasa je výchozí?", - ["0.0.0.0/0", "255.255.255.255/32", "192.168.1.1/32", "::1/128"], - 0, "Nulová síť s nulovým prefixem chytí zbytek."), - Q("Co je plovoucí statická trasa?", - ["Záložní ruční trasa s horší vzdáleností", - "Trasa, která plave mezi VLAN bez routeru", - "Automatický OSPF", - "Záznam jen v ARP"], - 0, "Nastoupí, až když zmizí lepší cesta."), - Q("Proč odpověď ze serveru nedorazí, i když tam paket došel?", - ["Chybí zpáteční trasa", - "TCP nemá porty", - "IPv4 neumí odpovědi", - "Switch maže cílové MAC adresy"], - 0, "Cesta musí existovat oběma směry."), - ]), - L("ACL a filtrování", "ACLs and filtering", - "Seznam, který provoz pustí a který zahodí.", - "A list that permits traffic or drops it.", - [ - S("1 / 3 • Pravidla", "Pořadí rozhoduje", - "Tip: první shoda vyhrává. Obecné povolení na začátku pozdější zákaz schová.", - "ACL zkouší řádky shora dolů.", - "Na konci bývá tiché zamítnutí všeho ostatního.", - "Pravidlo umí adresu, protokol a port.", - "Jedno špatné pořadí otevře službu, kterou jste chtěli zavřít."), - S("2 / 3 • Směr", "Dovnitř a ven", - "Tip: blíž zdroji filtrujte to, co nemá vůbec vstoupit.", - "Příchozí ACL sedí na paketech, které do rozhraní vcházejí.", - "Odchozí ACL sedí na paketech, které rozhraní opouštějí.", - "Filtr na VLAN rozhraní hlídá provoz mezi sítěmi.", - "ACL na směrovači nevidí provoz, který zůstane uvnitř jednoho switche."), - S("3 / 3 • Praxe", "Co obvykle pustit", - "Tip: nejdřív povolte, co potřebujete, a zbytek nechte spadnout.", - "Správa směrovače nemá poslouchat z hostovské VLAN.", - "Do serverové sítě pusťte jen porty služeb, které tam jsou.", - "ICMP můžete omezit, ale úplný zákaz ztíží hledání chyb.", - "Po změně ACL ověřte, že legitimní provoz pořád prochází."), - ], - [ - Q("Jak ACL vybírá pravidlo?", - ["Použije první řádek, který sedí", - "Sečte všechny řádky a udělá průměr", - "Vždy použije poslední řádek", - "Ptá se DNS"], - 0, "Pořadí je součást významu seznamu."), - Q("Co udělá tiché zamítnutí na konci?", - ["Zahodí provoz, který žádný řádek nepovolil", - "Povolí všechno, co zbylo", - "Přepne port do trunku", - "Pošle paket do IPv6"], - 0, "Co není povoleno, neprojde."), - Q("Proč ACL na routeru nehlídá dva počítače v jedné VLAN?", - ["Jejich rámce jdou jen přes switch a k routeru nemusí", - "ACL umí jen Wi-Fi", - "VLAN nemá MAC adresy", - "TCP takový provoz šifruje před switchem"], - 0, "Provoz uvnitř VLAN zůstane na druhé vrstvě."), - Q("Kam nepatří správa routeru?", - ["Do hostovské sítě", "Na konzolový port technika", - "Do správní VLAN", "Na šifrované SSH z dohledu"], - 0, "Host nemá mít cestu na správu infrastruktury."), - ]), - L("Podniková Wi-Fi", "Enterprise Wi-Fi", - "SSID, WPA3 a proč jedno heslo na nástěnce nestačí.", - "SSIDs, WPA3, and why one password on the wall is not enough.", - [ - S("1 / 3 • SSID", "Více sítí, jedna infrastruktura", - "Tip: hostovské SSID má skončit v jiné VLAN než učitelé.", - "Jedno rádio může ohlašovat víc SSID.", - "Každé SSID se mapuje na VLAN.", - "Schované SSID není zabezpečení, jméno jde pořád zachytit.", - "Stejné SSID na více přístupových bodech umožní přechod."), - S("2 / 3 • Klíče", "WPA2 a WPA3", - "Tip: společné heslo PSK se nedá vzít jednomu člověku, aniž by ho dostali všichni.", - "WPA2-Personal sdílí jedno heslo.", - "WPA2-Enterprise ověřuje uživatele přes RADIUS.", - "WPA3 lépe chrání i slabší hesla a má lepší dopředné utajení.", - "Starý WEP se nepoužívá."), - S("3 / 3 • Pokrytí", "Kanály a přechod", - "Tip: dva sousední body na stejném kanále si překážejí.", - "Pásmo 2,4 GHz má málo nepřekrývajících se kanálů.", - "5 GHz má víc kanálů a hůř prochází zdí.", - "Výkon nesmí být zbytečně vysoký, jinak buňky slyší i cizí provoz.", - "Roaming funguje, když se SSID a zabezpečení shodují."), - ], - [ - Q("Kam má vést hostovské SSID?", - ["Do vlastní VLAN, oddělené od školní sítě", - "Do stejné sítě jako ředitelna", - "Přímo do správy routeru", - "Do sítě bez DHCP i bez izolace"], - 0, "Host nemá vidět školní servery."), - Q("Čím se liší WPA2-Enterprise od společného hesla?", - ["Každý uživatel se ověřuje zvlášť, často přes RADIUS", - "Nemá šifrování", - "Funguje jen na 2,4 GHz", - "Sdílí jeden klíč napsaný na tabuli"], - 0, "Účet jde odebrat jednomu člověku."), - Q("Proč schované SSID není ochrana?", - ["Jméno sítě jde při připojení stejně zachytit", - "Skryté SSID nejde vůbec použít", - "WPA3 ho zakazuje", - "Switch ho vyhlásí v STP"], - 0, "Utajené jméno není šifra."), - Q("Co vadí dvěma sousedním AP na stejném kanále?", - ["Slyší se a kazí si přenos", - "Smažou si VLAN", - "Přestanou dělat DHCP", - "Změní IPv6 na IPv4"], - 0, "Kanály se mají plánovat, ne nechat náhodě."), - ]), - ], -) - -NET3 = course( - "net3", - "OSPF, směrování mezi VLAN, WAN, VPN, firewall, QoS a dohled.", - "OSPF, inter-VLAN routing, WAN, VPN, firewalls, QoS and monitoring.", - [ - L("OSPF", "OSPF", - "Směrovače si samy řeknou, jaké sítě znají.", - "Routers tell each other which networks they know.", - [ - S("1 / 3 • Sousedé", "Stejná oblast", - "Tip: OSPF soused nevznikne, když se neshoduje oblast nebo hello.", - "Směrovače v jednom spoji si vymění hello.", - "Hello interval a dead interval musí sedět.", - "Oblast 0 je páteř. Ostatní oblasti se k ní připojují.", - "Pasivní rozhraní hello neposílá, třeba k počítačům."), - S("2 / 3 • Cena", "Kratší neznamená míň skoků", - "Tip: OSPF sčítá cenu linek, ne počet routerů jako RIP.", - "Rychlejší linka má obvykle nižší cenu.", - "Součet cen rozhodne, kudy paket půjde.", - "Ruční cena umí odtáhnout provoz ze špatné linky.", - "Změna topologie se přepočítá bez přepisování statických tras."), - S("3 / 3 • Tabulka", "Co se z OSPF stane", - "Tip: v tabulce uvidíte zdroj trasy, ne jen další skok.", - "Naučená síť se vloží do směrovací tabulky.", - "Když lepší cesta spadne, použije se náhradní.", - "Redistribuce natáhne do OSPF i statiku nebo jiný protokol.", - "Špatná redistribuce umí do sítě pustit cizí trasy."), - ], - [ - Q("Co musí u OSPF sousedů sedět?", - ["Oblast a časy hello", "Stejná MAC adresa", - "Stejné SSID", "Stejný počet VLAN na switchi"], - 0, "Nesoulad hello nebo oblasti sousedství nesestaví."), - Q("Podle čeho OSPF vybírá cestu?", - ["Podle součtu cen linek", "Podle počtu písmen v názvu routeru", - "Podle VLAN ID", "Podle stáří DNS záznamu"], - 0, "Cena vyjadřuje náklad cesty, často odvozený z rychlosti."), - Q("K čemu je pasivní rozhraní?", - ["Neposílá hello tam, kde žádný soused být nemá", - "Vypne směrování celé sítě", - "Zapne NAT", - "Skryje SSID"], - 0, "K uživatelům se hello zbytečně neposílá."), - Q("Co je oblast 0?", - ["Páteř, ke které se ostatní oblasti připojují", - "VLAN pro hosty", - "Výchozí heslo WPA", - "Číslo konzolového portu"], - 0, "Bez páteře se víc oblastí OSPF nespojí správně."), - ]), - L("Směrování mezi VLAN", "Inter-VLAN routing", - "Jedna brána pro každou VLAN.", - "One gateway for each VLAN.", - [ - S("1 / 3 • Router na tyči", "Jeden spoj, víc VLAN", - "Tip: trunk k routeru nese značky a každá VLAN má své podrozhraní.", - "Switch pošle trunk do routeru.", - "Každá VLAN má vlastní IP bránu.", - "Stanice má jako bránu adresu své VLAN, ne cizí.", - "Bez trasy mezi VLAN k sobě sítě nedosáhnou."), - S("2 / 3 • L3 switch", "Směrování v přepínači", - "Tip: přepínač třetí vrstvy má pro VLAN rozhraní SVI.", - "SVI je virtuální rozhraní s adresou brány.", - "Provoz mezi VLAN nemusí odejít na samostatný router.", - "ACL na SVI hlídá, která VLAN kam smí.", - "Zapomenuté SVI znamená, že VLAN nemá bránu."), - S("3 / 3 • Chyby", "Když to nejde", - "Tip: nejdřív ověřte, že stanice je ve správné VLAN a má správnou bránu.", - "Špatná maska na bráně rozhodí celou VLAN.", - "Trunk, který VLAN nepropouští, bránu odstřihne.", - "Stanice v access portu špatné VLAN dostane cizí DHCP.", - "Kontrola: adresa, maska, brána, VLAN, trunk, ACL."), - ], - [ - Q("Co je brána pro stanici ve VLAN?", - ["Adresa routeru nebo SVI v té samé VLAN", - "Libovolná veřejná DNS adresa", - "MAC adresa switche", - "Číslo VLAN zapsané do masky"], - 0, "Brána musí být dosažitelná na druhé vrstvě, tedy ve stejné VLAN."), - Q("Co je SVI?", - ["Virtuální rozhraní VLAN na L3 přepínači", - "Typ optického vlákna", - "Protokol pošty", - "Záloha konfigurace"], - 0, "SVI nese IP adresu brány dané VLAN."), - Q("Jak router na tyči pozná VLAN?", - ["Podle značky 802.1Q na trunku", - "Podle barvy LED na počítači", - "Podle jména v DNS", - "Podle rychlosti ventilátoru"], - 0, "Každé podrozhraní patří jedné značce."), - Q("Co udělá trunk, který VLAN 20 nepropouští?", - ["Střihne bránu VLAN 20 od zbytku sítě", - "Smaže OSPF v celé škole", - "Přepne Wi-Fi na WEP", - "Zdvojí adresy DHCP"], - 0, "Povolené VLAN na trunku jsou součást návrhu."), - ]), - L("WAN", "WAN", - "Spoj mezi pobočkami a k poskytovateli.", - "A link between sites and towards the provider.", - [ - S("1 / 3 • Okraj", "Kde končí vaše síť", - "Tip: za routerem k poskytovateli už neřídíte fyzickou cestu.", - "WAN spojuje vzdálené sítě přes síť, kterou nevlastníte.", - "Poskytovatel vám dá adresu, bránu a často i VLAN.", - "Výchozí trasa obvykle míří právě sem.", - "Výpadek poslední míle odřízne pobočku, i když jádro žije."), - S("2 / 3 • Technologie", "Čím se to vozí", - "Tip: dnešní WAN často vypadá jako ethernet, i když pod ním je jiná síť.", - "Starší spoje používaly pronajaté linky a PPP.", - "MPLS u poskytovatele spojí pobočky jako jednu službu.", - "Metro Ethernet přivede do budovy běžný ethernetový port.", - "Rychlost, odezva a ztráty jsou parametry, které se sledují."), - S("3 / 3 • Návrh", "Co domluvit", - "Tip: záložní spoj má smysl jen s cestou, která se na něj umí přepnout.", - "Jedna přípojka je jednoduchá a křehká.", - "Druhý poskytovatel sníží riziko, když nejde stejnou trasou.", - "Adresy od poskytovatele musí sedět s vaším NAT a firewallem.", - "Na okraji filtrujte, co do školy z internetu lézt nemá."), - ], - [ - Q("Co je WAN z pohledu školy?", - ["Spoj mimo budovu, často přes poskytovatele", - "Kabel mezi dvěma porty jednoho switche", - "VLAN pro tiskárny", - "Diskové pole"], - 0, "WAN překračuje místní síť."), - Q("Kam obvykle míří výchozí trasa?", - ["K poskytovateli", "Na tiskárnu", - "Do STP rootu", "Na adresu 127.0.0.1"], - 0, "Co směrovač nezná, pošle ven."), - Q("Proč dva spoje stejnou ulicí nemusí být záloha?", - ["Jedna porucha překope oba naráz", - "OSPF dva spoje zakazuje", - "IPv4 umí jen jednu bránu na světě", - "Ethernet nesmí mít zálohu"], - 0, "Fyzicky oddělená trasa je součást redundance."), - Q("Co je metro Ethernet?", - ["WAN služba, která u vás končí ethernetovým portem", - "Wi-Fi ve vlaku", - "Protokol místo DNS", - "Typ procesoru"], - 0, "Pod portem může být síť poskytovatele, vy vidíte ethernet."), - ]), - L("VPN", "VPN", - "Šifrovaný tunel přes síť, které nevěříte.", - "An encrypted tunnel across a network you do not trust.", - [ - S("1 / 3 • Tunel", "Cizí síť jako kabel", - "Tip: VPN neschová provoz před sítí, ve které tunel končí.", - "Mezi dvěma body se postaví šifrovaný tunel.", - "Uvnitř mohou téct soukromé adresy.", - "Venku je vidět jen obal mezi konci tunelu.", - "Bez shodných klíčů nebo certifikátů tunel nevstane."), - S("2 / 3 • Dva tvary", "Pobočka a člověk", - "Tip: site-to-site spojuje sítě, remote access jednoho uživatele.", - "Site-to-site propojí dvě pobočky trvale.", - "Remote access pustí notebook do školní sítě.", - "Uživatel se ověřuje účtem, ne jen společným heslem na zdi.", - "Split tunnel posílá tunelem jen školní sítě, zbytek jde přímo."), - S("3 / 3 • Chyby", "Když tunel stojí a data ne", - "Tip: tunel může svítit zeleně a přesto chybí trasa dovnitř.", - "Musí sedět návrh šifry na obou koncích.", - "Firewall po cestě musí pustit port VPN.", - "Uvnitř musí existovat trasa do cílových sítí.", - "Příliš široký tunel stáhne na školu i provoz, který tam být neměl."), - ], - [ - Q("Co VPN před cizí sítí skrývá?", - ["Obsah a vnitřní adresy, venku je vidět obal tunelu", - "I to, že nějaký provoz existuje", - "MAC adresu switche ve třídě", - "Úplně všechno včetně konců tunelu"], - 0, "Koncové adresy tunelu vidět jsou, náklad ne."), - Q("Čím se liší site-to-site od remote access?", - ["První spojuje sítě, druhá připojuje uživatele", - "První je Wi-Fi, druhá je VLAN", - "Obě jen mění DNS", - "Remote access nejde šifrovat"], - 0, "Notebook není druhá pobočka, i když tunel vypadá podobně."), - Q("Proč tunel svítí, ale server nehraje?", - ["Chybí trasa nebo firewall uvnitř", - "IPv4 zakazuje VPN", - "STP tunely maže", - "DNS přejmenuje šifru"], - 0, "Šifra a dosažitelnost jsou dvě vrstvy."), - Q("Co je split tunnel?", - ["Tunelem jde jen provoz do vnitřních sítí", - "Každý paket se rozpůlí", - "VPN bez šifry", - "Dva SSID na jednom kanále"], - 0, "Internet z notebooku pak nemusí téct přes školu."), - ]), - L("Firewall a zóny", "Firewalls and zones", - "Kdo s kým smí mluvit, ne jen jestli kabel svítí.", - "Who may talk to whom, not only whether the cable is lit.", - [ - S("1 / 3 • Zóny", "Důvěra není stejná", - "Tip: LAN, WAN a DMZ nemají stejná pravidla.", - "Rozhraní se sdruží do zón podle důvěry.", - "Z důvěryhodnější zóny ven se často povoluje snáz.", - "Z internetu dovnitř se povoluje jen to, co je schválené.", - "Pravidlo se píše od zóny ke zóně, ne jen na jednu adresu."), - S("2 / 3 • Stav", "Pamatuje si spojení", - "Tip: stavový firewall pustí odpověď, aniž byste psali pravidlo nazpátek.", - "Nové spojení se kontroluje proti politice.", - "Odpověď patřící ke spojení se pustí.", - "Bezestavový filtr zkoumá každý paket zvlášť.", - "Ukončené spojení se z tabulky smaže."), - S("3 / 3 • DMZ", "Server, který má být vidět", - "Tip: web v DMZ nemá mít cestu ke všem diskům ve škole.", - "Veřejná služba sedí v oddělené zóně.", - "Z internetu se otevře jen její port.", - "Z DMZ do LAN se pustí jen to, co služba opravdu potřebuje.", - "Kompromitovaný web pak neotevře celou školu."), - ], - [ - Q("Proč se zóny liší?", - ["Mají jinou důvěru a tedy jiná pravidla", - "Každá zóna musí mít vlastní DNS jméno switche", - "Zóny nahrazují IP adresy", - "Bez zón nejde STP"], - 0, "Internet a učebna nejsou stejně důvěryhodné."), - Q("Co umí stavový firewall?", - ["Pustí odpověď k už otevřenému spojení", - "Smaže VLAN", - "Přidělí MAC adresu", - "Nahradí směrovací protokol"], - 0, "Pamatuje si, kdo spojení začal."), - Q("Kam patří veřejný web, který nemá vidět celou LAN?", - ["Do DMZ", "Do stejné sítě jako účtárna", - "Na access port ředitele", "Do nativní VLAN trunku bez pravidel"], - 0, "DMZ omezí, kam se útočník dostane dál."), - Q("Co samotná zóna ještě není?", - ["Náhrada za konkrétní pravidla služeb", - "Způsob, jak sdružit rozhraní", - "Hranice důvěry", - "Místo, kam se píše politika"], - 0, "Zóna bez pravidel nic nechrání."), - ]), - L("QoS", "QoS", - "Když je linka plná, někdo musí dostat přednost.", - "When the link is full, someone has to go first.", - [ - S("1 / 3 • Fronty", "Ne všechno snese čekání", - "Tip: QoS nevytvoří rychlost, jen rozhodne, kdo počká.", - "Hlas a videohovor kazí zpoždění a kolísání.", - "Záloha disku snese čekání líp než telefonát.", - "Fronta na úzké lince řadí pakety.", - "Bez označení provozu switch neví, co je hlas."), - S("2 / 3 • Značky", "Kdo si řekne o přednost", - "Tip: značce z koncového portu nevěřte, uživatel si ji může nastavit sám.", - "IP hlavička umí nést DSCP.", - "Ethernet umí prioritu na VLAN značce.", - "Na vstupu se značka přepíše podle politiky.", - "Hlasová VLAN se často značí automaticky."), - S("3 / 3 • Praxe", "Kde to má smysl", - "Tip: na prázdné gigabitové lince QoS nic viditelného neudělá.", - "Úzké hrdlo bývá WAN, ne páteřní switch.", - "Rezervace pro hlas nesmí sežrat celou linku.", - "Testujte hovor ve chvíli, kdy běží velká kopie.", - "Špatná politika umí zpomalit i správu sítě."), - ], - [ - Q("Co QoS neumí?", - ["Vyrobit větší rychlost linky", - "Dát přednost hlasu před zálohou", - "Omezit kolísání hovoru", - "Označit provoz"], - 0, "Dělí existující kapacitu, nepřidá ji."), - Q("Proč se značka z počítače přepisuje?", - ["Uživatel by si jinak dal nejvyšší prioritu", - "DSCP nejde číst", - "IPv4 značky zakazuje", - "STP značky maže"], - 0, "Důvěryhodná značka vznikne na vstupu podle pravidel."), - Q("Kde QoS obvykle pomůže nejdřív?", - ["Na pomalé WAN lince", "Na prázdném 10Gb portu mezi switchi", - "Uvnitř jednoho počítače na smyčce", "Na vypnutém Wi-Fi"], - 0, "Přednost se projeví, až když se linka plní."), - Q("Který provoz čekání snese hůř?", - ["Telefonní hovor", "Noční kopie disku", - "Stahování aktualizace", "Archiv pošty"], - 0, "Hlas potřebuje malé a stálé zpoždění."), - ]), - L("Dohled sítě", "Watching the network", - "SNMP, syslog a co z grafu opravdu plyne.", - "SNMP, syslog, and what a graph really tells you.", - [ - S("1 / 3 • SNMP", "Čísla z zařízení", - "Tip: SNMPv2c posílá jméno komunity skoro jako heslo v čistém textu.", - "Dohled se ptá na vytížení, chyby a stav portů.", - "Komunita není ozdoba, je to přístup.", - "SNMPv3 umí uživatele a šifrování.", - "Zařízení má poslouchat SNMP jen ze sítě dohledu."), - S("2 / 3 • Syslog", "Věty o tom, co se stalo", - "Tip: log na zařízení se při restartu může ztratit. Posílejte ho pryč.", - "Syslog odnáší hlášky na server.", - "Úrovně od ladění po nouzi se nemají všechny sypat do jedné hromady.", - "Čas na zařízeních musí sedět, jinak nejde srovnat události.", - "NTP je proto součást dohledu, ne jen hodiny na zdi."), - S("3 / 3 • Čtení", "Graf není diagnóza", - "Tip: špička jednou za den může být záloha, ne útok.", - "Chyby na portu často znamenají kabel nebo duplex.", - "Vytrvalé vytížení WAN řekne, jestli je čas na silnější spoj.", - "Výpadek, který nikdo nevidí, se bude opakovat.", - "Upozornění má chodit člověku, který může reagovat."), - ], - [ - Q("Proč SNMPv2c nestačí na nezabezpečené síti?", - ["Jméno komunity jde odposlechnout", - "Neumí číst vytížení", - "Funguje jen na IPv6", - "Maže syslog"], - 0, "Komunita cestuje bez pořádné ochrany. Lepší je SNMPv3."), - Q("Proč posílat syslog pryč ze zařízení?", - ["Lokální log se při restartu může ztratit", - "Syslog nahrazuje heslo", - "Switch jinak vypne porty", - "DNS bez logu nefunguje"], - 0, "Po restartu už příčinu pádu na zařízení nemusíte najít."), - Q("K čemu je při dohledu NTP?", - ["Aby časy událostí šly srovnat", - "Aby přidělil VLAN", - "Aby šifroval Wi-Fi", - "Aby nahradil SNMP"], - 0, "Bez společného času nejde říct, co bylo dřív."), - Q("Co často znamenají rostoucí chyby na portu?", - ["Špatný kabel nebo duplex", - "Že je VLAN správně", - "Že OSPF konverguje", - "Že DNS TTL vypršelo"], - 0, "Fyzická vrstva se v počítadlech chyb projeví dřív než v teorii."), - ]), - L("Záloha konfigurace", "Configuration backups", - "Co uložit, než se přepínač vymění.", - "What to save before a switch is replaced.", - [ - S("1 / 3 • Běžící a uložená", "Restart není uložení", - "Tip: změna v běžící konfiguraci po restartu zmizí, dokud ji neuložíte.", - "Běžící konfigurace je to, co zařízení právě dělá.", - "Startovní se načte po zapnutí.", - "Uložení zkopíruje běžící do startovní.", - "Bez uložení druhý den síť vypadá jako včera."), - S("2 / 3 • Kopie ven", "Nejen na zařízení", - "Tip: záloha na tom samém přepínači shoří spolu s ním.", - "Konfigurace patří na server mimo to zařízení.", - "Ukládejte i verzi, ať víte, co se změnilo.", - "Hesla v exportu mohou být čitelná. Soubor chraňte.", - "Automatická záloha po změně porazí dobrý úmysl."), - S("3 / 3 • Popis", "Aby to přečetl i kolega", - "Tip: port bez popisu je za půl roku hádanka.", - "Popis portu říká, co je na druhém konci.", - "Schéma VLAN a adres má sedět s konfigurací.", - "Změna bez poznámky se špatně vrací.", - "Nový switch postavíte z zálohy jen tehdy, když záloha existuje."), - ], - [ - Q("Co se stane se změnou, kterou neuložíte?", - ["Po restartu zmizí", "Zapíše se do VLAN navždy", - "Přepíše firmware", "Pošle se sama do DNS"], - 0, "Běžící konfigurace není totéž co startovní."), - Q("Proč záloha jen na tom samém switchi nestačí?", - ["S poškozeným switchem zmizí i ona", - "Switch zálohy šifruje tak, že je nečitelné i pro vás", - "STP zálohy maže", - "IPv6 zálohy zakazuje"], - 0, "Kopie musí žít jinde."), - Q("Co má být u portu napsané?", - ["Co je na druhém konci", "Heslo administrátora", - "Celá směrovací tabulka", "Soukromý klíč VPN"], - 0, "Popis portu šetří hodiny při poruše."), - Q("Proč chránit soubor se zálohou?", - ["Může obsahovat čitelná hesla", - "Soubor sám otevírá porty", - "DNS ho publikuje", - "Je větší než disk"], - 0, "Export není vždy v zašifrované podobě."), - ]), - ], -) - -NET4 = course( - "net4", - "Návrh adres, redundance, 802.1X, hledání chyb, cloud a maturita.", - "Address plans, redundancy, 802.1X, troubleshooting, cloud and the exam.", - [ - L("Adresní plán", "An address plan", - "Sítě se navrhují dřív, než se zapojí první kabel.", - "Networks are designed before the first cable is patched.", - [ - S("1 / 3 • Rozsahy", "Každá VLAN má svůj prefix", - "Tip: nenechávejte v každé síti jen čtyři volné adresy.", - "Nejdřív spočítejte stanice, tiskárny, AP a rezervu.", - "Brána, síťová a broadcast adresa se do stanic nepočítají.", - "Sousední VLAN nemají mít překryv.", - "Dokument říká, která čísla jsou volná."), - S("2 / 3 • Členění", "Škola není jedna velká síť", - "Tip: /16 na celou budovu se snadno spravuje a špatně izoluje.", - "Učebny, správa, servery, hosté a telefony patří odděleně.", - "Stejný řád čísel ve všech budovách se líp pamatuje.", - "Souhrn tras na páteři zmenší tabulku.", - "Výjimka pro jednu tiskárnu se má zapsat, ne jen zapamatovat."), - S("3 / 3 • Změna", "Plán, který jde rozšířit", - "Tip: když přidáte budovu, neměli byste přečíslovat celou školu.", - "Nechte v páteřním rozsahu díry pro další sítě.", - "Přechod na nový prefix znamená DHCP, DNS, brány i firewall.", - "IPv6 prefix se plánuje stejně vědomě, ne jako dodatek.", - "Tabulka adres je součást maturity i běžného provozu."), - ], - [ - Q("Co se v síti /24 nedá přiřadit stanici?", - ["Adresa sítě a broadcast", "První použitelná adresa", - "Adresa brány, pokud ji stanice nemá mít", - "Adresa s lichým posledním oktetem"], - 0, "Krajní adresy mají zvláštní význam. Brána se stanicím také nedává dvakrát."), - Q("Proč nerozdat celé škole jednu velkou síť?", - ["Špatně se izoluje porucha i provoz", - "IPv4 to zakazuje", - "Switch umí jen 8 adres", - "DNS pak nejde spustit"], - 0, "Menší sítě se líp hlídají a míň se ruší broadcastem."), - Q("K čemu je souhrn tras?", - ["Jedna trasa pokryje víc menších sítí", - "Smaže VLAN", - "Nahradí NAT", - "Zapne WPA3"], - 0, "Páteř nemusí znát každou učebnu zvlášť."), - Q("Co patří do adresního plánu?", - ["Prefix, VLAN, brána a k čemu síť je", - "Jen heslo Wi-Fi", - "Typ procesoru serveru", - "Seznam učitelů"], - 0, "Bez účelu sítě je tabulka jen sloupec čísel."), - ]), - L("Redundance", "Redundancy", - "Druhá cesta, která se opravdu použije.", - "A second path that is actually used.", - [ - S("1 / 3 • Dvojice", "Dva boxy nestačí", - "Tip: dva switche se stejnou konfigurací nejsou záloha, dokud provoz neumí přejít.", - "Redundance chce druhou cestu i protokol, který ji hlídá.", - "STP řeší smyčku na druhé vrstvě.", - "Na třetí vrstvě zálohu hlídá směrování nebo HSRP a příbuzné protokoly.", - "Jedna brána v DHCP znamená, že pád routeru odstřihne všechny."), - S("2 / 3 • Brána", "Virtuální adresa", - "Tip: stanice mají jako bránu virtuální adresu, ne jednu fyzickou krabici.", - "Dva směrovače sdílejí jednu adresu brány.", - "Aktivní drží provoz, druhý čeká.", - "Když aktivní ztichne, druhý adresu převezme.", - "Stanice nemusí dostat nové DHCP."), - S("3 / 3 • Zkouška", "Nevyzkoušená záloha je teorie", - "Tip: vytáhněte kabel v okně, kdy smíte, ne až při maturitní písemce.", - "Ověřte, že záložní cesta opravdu přenáší data.", - "Sledujte, za jak dlouho se provoz vrátí.", - "Záložní zdroj má jinou pojistku a jinou fázi, když to jde.", - "Zápis z zkoušky říká, co se má stát příště."), - ], - [ - Q("Proč dva stejné routery samy o sobě nestačí?", - ["Stanice musí mít kam přejít, když jeden ztichne", - "IPv4 povoluje jen jeden router v budově", - "Druhý router maže VLAN", - "STP dva routery zakazuje"], - 0, "Bez společné nebo přepínané brány počítače zůstanou na mrtvé adrese."), - Q("Co stanice používá při protokolu virtuální brány?", - ["Virtuální adresu, ne konkrétní krabici", - "Svou vlastní MAC jako bránu", - "Adresu DNS", - "Broadcast 255.255.255.255 jako další skok"], - 0, "Převzetí adresy stanice nepozná jako výměnu DHCP."), - Q("Kdy se záloha ověřuje?", - ["Nanečisto, dřív než o ni opřete provoz", - "Až když síť leží", - "Jen na papíře", - "Záloha se ověřovat nemá, ať se nepokazí"], - 0, "Nevyzkoušený přepínač překvapí v nejhorší chvíli."), - Q("Co na druhé vrstvě řeší náhradní kabel?", - ["STP, jinak vznikne smyčka", - "Jen NAT", - "Jen WPA3", - "Nic, ethernet smyčky umí sám"], - 0, "Druhý kabel bez STP je recept na bouři."), - ]), - L("802.1X", "802.1X", - "Port pustí data, až když se zařízení představí.", - "A port forwards data only after the device identifies itself.", - [ - S("1 / 3 • Port", "Nejdřív průkaz", - "Tip: dokud ověření neskončí, na portu nemá téct běžný provoz.", - "Počítač se prokáže certifikátem nebo jménem a heslem.", - "Switch se ptá serveru RADIUS.", - "Až pak pustí port do dané VLAN.", - "Neznámé zařízení zůstane venku nebo v omezené síti."), - S("2 / 3 • Lidé a věci", "Ne všechno umí 802.1X", - "Tip: tiskárna bez klienta potřebuje výjimku, ne vypnutí celé ochrany.", - "Počítač v doméně zvládne ověření sám.", - "Tiskárna, kamera a telefon často ne.", - "MAB pustí zařízení podle MAC adresy. Tu jde zfalšovat.", - "Výjimka má být na konkrétní port, ne na celý switch."), - S("3 / 3 • VLAN", "Kam koho pustit", - "Tip: učitel a host nemají po ověření skončit ve stejné VLAN.", - "Úspěch může přiřadit VLAN podle skupiny.", - "Neúspěch skončí v síti bez přístupu k serverům.", - "Účet jde odebrat, aniž by se měnilo heslo Wi-Fi.", - "Stejný princip sedí na kabel i na podnikovou Wi-Fi."), - ], - [ - Q("Kdo rozhodne, že zařízení smí do sítě?", - ["RADIUS na základě údajů od switche", - "Sám kabel podle barvy", - "DNS záznam A", - "STP root"], - 0, "Switch se ptá, server odpovídá."), - Q("Proč MAB není silné ověření?", - ["MAC adresu lze zfalšovat", - "MAC adresa je jednorázové heslo", - "MAB šifruje silněji než certifikát", - "Funguje jen na IPv6"], - 0, "Adresa na štítku není průkaz."), - Q("Kam patří zařízení, které ověřením neprojde?", - ["Do omezené sítě nebo nikam", - "Do VLAN serverů", - "Na trunk všech VLAN", - "Do správy routeru"], - 0, "Neúspěch nemá otevírat vnitřní síť."), - Q("Jaká je výhoda účtů proti jednomu heslu Wi-Fi?", - ["Jednomu člověku jde přístup odebrat", - "Heslo se nemusí nikdy měnit, protože účty ho ruší", - "Netřeba RADIUS ani switch", - "WEP pak stačí"], - 0, "Sdílené heslo po odchodu člověka zná pořád."), - ]), - L("Hledání chyby", "Troubleshooting", - "Postup zdola nahoru, ne náhodné restarty.", - "Bottom-up steps, not random reboots.", - [ - S("1 / 3 • Vrstvy", "Nejdřív světlo na portu", - "Tip: nehledejte chybu v DNS, když port nesvítí.", - "Fyzická vrstva: kabel, port, napájení, duplex, chyby.", - "Druhá vrstva: VLAN, MAC tabulka, trunk, STP.", - "Třetí vrstva: adresa, maska, brána, trasa, ACL.", - "Výš: DNS, port služby, firewall na konci."), - S("2 / 3 • Jedna změna", "Ať víte, co pomohlo", - "Tip: pět změn naráz nic nenaučí.", - "Zapište, co vidíte, než něco přepnete.", - "Ověřte jednu hypotézu.", - "Ping na bránu, pak za ni, pak jméno.", - "Když oprava sedí, uložte konfiguraci a dopište důvod."), - S("3 / 3 • Rozsah", "Koho to postihlo", - "Tip: jeden počítač je jiná chyba než celá učebna.", - "Jeden stroj: jeho kabel, port, adresa, účet.", - "Celá VLAN: brána, DHCP, trunk, SVI.", - "Celá škola: jádro, firewall, poskytovatel.", - "Čas začátku často sedí se změnou, kterou někdo neoznámil."), - ], - [ - Q("Co ověříte jako první, když port nesvítí?", - ["Kabel, port a napájení", "Záznam AAAA", - "Cenu OSPF", "Pravidlo QoS pro hlas"], - 0, "Vyšší vrstvy nemají na čem jet."), - Q("Proč měnit jen jednu věc?", - ["Ať je vidět, která změna pomohla", - "Switch víc změn zakazuje", - "IPv4 umí jen jednu opravu denně", - "DNS jinak smaže zónu"], - 0, "Více zásahů naráz zamaskuje příčinu."), - Q("Celá učebna nedostane adresu. Kde začnete?", - ["DHCP, VLAN a brána té sítě", - "Heslem jednoho studenta k webu", - "Jasem monitoru", - "Verzí prohlížeče"], - 0, "Společný příznak ukazuje na společnou službu."), - Q("Co uděláte, když oprava sedí?", - ["Uložíte konfiguraci a zapíšete důvod", - "Restartujete všechno ještě jednou", - "Smažete popis portů", - "Vypnete dohled, ať neruší"], - 0, "Neuložená oprava do rána zmizí."), - ]), - L("Cloud a hybrid", "Cloud and hybrid networks", - "Část služeb není ve skříni na chodbě.", - "Some services are no longer in the cupboard in the corridor.", - [ - S("1 / 3 • Kam s tím", "Vlastní sál, nebo cizí", - "Tip: cloud neruší síť ve škole, mění jen to, kam vede spoj.", - "Veřejný cloud provozuje poskytovatel a vy si berete službu.", - "Soukromý cloud je pořád vaše zařízení, jen obalené portálem.", - "Hybrid nechá část dat ve škole a část venku.", - "Účet a síťová cesta jsou pořád vaše odpovědnost."), - S("2 / 3 • Cesta", "Jak se tam školní síť dostane", - "Tip: služba v cloudu bez cesty a bez jmen je jen faktura.", - "VPN do cloudu vypadá jako další pobočka.", - "Veřejná služba jede přes internet a firewall.", - "DNS musí ukazovat na nové adresy.", - "Výpadek WAN teď shodí i to, co dřív jelo z místního serveru."), - S("3 / 3 • Hranice", "Kdo zálohuje a kdo pustí dovnitř", - "Tip: poskytovatel nezálohuje vaše data, dokud to není ve smlouvě.", - "Pravidla firewallu se stěhují s službou.", - "Účty v cloudu mají mít stejný řád jako účty ve škole.", - "Test obnovy platí i pro data, která nejsou ve vašem racku.", - "Škola pořád řeší osobní údaje, i když disk je jinde."), - ], - [ - Q("Co hybridní síť znamená?", - ["Část služeb je ve škole a část u poskytovatele", - "Dva switche v jedné VLAN", - "IPv4 i papírový sešit", - "Wi-Fi bez hesla"], - 0, "Hranice školy už není hranicí všech služeb."), - Q("Co se pokazí, když WAN spadne a pošta je jen v cloudu?", - ["Škola se k poště nedostane", - "Místní switch přestane dělat VLAN", - "STP zvolí cloud jako root", - "Nic, cloud WAN nepotřebuje"], - 0, "Cesta ven je součást dostupnosti služby."), - Q("Kdo zálohuje data v cloudu?", - ["Ten, koho to smlouva a nastavení opravdu určují", - "Vždy automaticky stát", - "STP", - "Nikdo, cloud zálohy zakazuje"], - 0, "Předpoklad, že poskytovatel zálohuje vše, často neplatí."), - Q("Co škola řeší i u cizího disku?", - ["Kdo má přístup a jak se chrání osobní údaje", - "Jen barvu loga", - "Jen typ ventilátoru v sále poskytovatele", - "Nic, odpovědnost přechází celá"], - 0, "Umístění dat nemaže pravidla přístupu."), - ]), - L("Automatizace", "Automation", - "Opakovanou práci ať dělá skript, ne deset kliknutí.", - "Let a script do the repeated work, not ten clicks.", - [ - S("1 / 3 • SSH", "Správa bez společného hesla na lístečku", - "Tip: Telnet posílá heslo čitelně. Na správu patří SSH.", - "Klíč jde odebrat konkrétnímu člověku.", - "Heslo v příkazu historie nemá ležet.", - "Přístup omezte na správní síť.", - "Záznam, kdo se přihlásil, patří do logu."), - S("2 / 3 • Opakování", "Stejná VLAN ve dvaceti switchích", - "Tip: ruční opis se v desátém switchi liší v jednom čísle.", - "Šablona drží názvy VLAN a popis portů.", - "Skript změnu pošle na seznam zařízení.", - "Nejdřív ho pusťte na jednom switchi.", - "Záloha před hromadnou změnou je povinnost, ne ozdoba."), - S("3 / 3 • Mez", "Skript není výmluva", - "Tip: automat neopraví špatný záměr, jen ho provede rychleji.", - "Kontrola po běhu srovná, co opravdu sedí.", - "Tajné heslo nepatří do veřejného souboru.", - "Člověk pořád schvaluje změnu, která shodí výuku.", - "Verzovaný soubor konfigurace ukáže, kdo řádek změnil."), - ], - [ - Q("Proč na správu nepoužívat Telnet?", - ["Heslo jde po síti čitelně", - "Telnet neumí IPv4", - "Switch Telnet zakazuje standardem STP", - "Telnet maže VLAN"], - 0, "SSH spojení chrání."), - Q("Jak pustíte stejnou změnu do dvaceti switchů?", - ["Šablonou a skriptem, neopisovat ji dvacetkrát", - "Jen restartem všech naráz", - "Přes DHCP", - "Jedním broadcastem bez kontroly"], - 0, "Nejdřív jeden switch, pak ostatní."), - Q("Co před hromadnou změnou uděláte?", - ["Zálohu konfigurací", - "Vypnete dohled", - "Smažete popisy portů", - "Zakážete SSH"], - 0, "Ať se máte kam vrátit."), - Q("Co skript neumí?", - ["Poznat, že záměr byl špatně", - "Poslat stejný příkaz víckrát", - "Uložit konfiguraci", - "Připojit se přes SSH"], - 0, "Rychlost neopraví chybný příkaz."), - ]), - L("Provoz a maturita", "Operations and the exam", - "Síť ve škole má pravidla, ne jen blikající porty.", - "A school network has rules, not only blinking ports.", - [ - S("1 / 3 • Řád", "Kdo smí co změnit", - "Tip: heslo admin na lístečku u switche není provozní řád.", - "Účty jsou jmenné, ne jedno společné admin.", - "Změna ve výuce se hlásí dopředu.", - "Hostovská síť je oddělená a časově omezená.", - "Osobní údaje v logu se nenechávají ležet bez důvodu."), - S("2 / 3 • Výpadek", "Co říct a co udělat", - "Tip: nejdřív rozsah a dopad, pak ladění detailu.", - "Řekněte, co nejede a koho se to týká.", - "Oddělte výpadek poskytovatele od chyby ve škole.", - "Po obnově ověřte poštu, přihlášení i tisk, ne jen ping.", - "Krátký zápis příště zkrátí stejnou poruchu."), - S("3 / 3 • U zkoušky", "Co umět ukázat", - "Tip: maturita chce důvod, ne jen zkratku.", - "Umíte přečíst adresu, masku, bránu a VLAN.", - "Umíte říct, k čemu je trunk, NAT, firewall a záloha.", - "Schéma malé sítě nakreslíte i bez nápovědy.", - "Postup hledání chyby od kabelu po službu odvykládáte po vrstvách."), - ], - [ - Q("Jak nemají vypadat účty ke switchi?", - ["Jedno heslo admin pro celou sborovnu", - "Jmenný účet s možností odebrání", - "Přístup jen ze správní sítě", - "Záznam přihlášení"], - 0, "Společné heslo nejde vzít jednomu člověku."), - Q("Co řeknete jako první při výpadku?", - ["Co nejede a koho se to týká", - "Celou směrovací tabulku zpaměti", - "Typ ventilátoru v racku", - "Že se to vyřeší samo"], - 0, "Rozsah je důležitější než první domněnka."), - Q("Co po obnově nestačí?", - ["Jen ping na bránu", - "Ověřit poštu a přihlášení", - "Podívat se na tisk", - "Zkontrolovat, že VLAN sedí"], - 0, "Brána může žít a služba pořád ne."), - Q("Co u maturity k VLAN umíte říct?", - ["Odděluje provoz a mezi VLAN se směruje", - "Je to typ pevného disku", - "Nahrazuje zálohu konfigurace", - "Je totéž co WPA3"], - 0, "Definice a důvod, ne jen zkratka."), - ]), - L("Dokumentace sítě", "Network documentation", - "Schéma, které sedí s tím, co je ve zdi.", - "A diagram that matches what is actually in the wall.", - [ - S("1 / 3 • Schéma", "Co na něm má být", - "Tip: schéma z doby instalace bez datumu je pohádka.", - "Jsou na něm jádro, učebny, VLAN a přípojka ven.", - "Adresní plán sedí se schématem, ne s pamětí.", - "Porty páteře mají popisky na obou koncích.", - "Datum a jméno autora říkají, jak je obrázek starý."), - S("2 / 3 • Změna", "Nejdřív papír, pak kabel", - "Tip: přepojit a zapsat až za měsíc znamená, že zápis už nesedí.", - "Změna VLAN se zapíše ve stejný den.", - "Fotka rozvaděče doplní schéma tam, kde čáry lžou.", - "Hesla do schématu nepatří. Patří do trezoru účtů.", - "Kopie schématu není jen na počítači, který ta síť živí."), - S("3 / 3 • Předání", "Až tu nebudete", - "Tip: kolega má síť převzít bez vašeho telefonu.", - "Seznam zařízení, adres správy a kde leží zálohy.", - "Kontakt na poskytovatele a číslo spoje.", - "Co se nesmí restartovat ve výuce.", - "Jedna stránka je lepší než nikde neuložená hlava."), - ], - [ - Q("Co do schématu sítě nepatří?", - ["Heslo správce", "VLAN a jejich účel", - "Přípojka k poskytovateli", "Datum, kdy naposledy sedělo"], - 0, "Heslo patří jinam než na obrázek, který visí ve sborovně."), - Q("Kdy se změna zapíše?", - ["V den, kdy se provede", "Až se na ni někdo zeptá u maturity", - "Jen když spadne celá škola", "Zápis není potřeba, stačí paměť"], - 0, "Nezapsaná změna je příští závada."), - Q("Proč mít kopii schématu i mimo školní server?", - ["Když síť neběží, schéma na ní neotevřete", - "Server schémata maže", - "IPv6 schémata zakazuje", - "STP obrázky nepouští"], - 0, "Dokumentace má přežít výpadek toho, co popisuje."), - Q("Co má kolega najít bez vašeho telefonu?", - ["Adresy správy, zálohy a kontakt na poskytovatele", - "Jen barvu racku", - "Vaše soukromé heslo", - "Nic, síť se nepředává"], - 0, "Provoz nesmí stát na jednom člověku."), - ]), - ], -) - -HW2 = course( - "hw2", - "Monitory, tisk, sběrnice, chlazení, sestavení, UEFI a diagnostika.", - "Displays, printing, buses, cooling, assembly, UEFI and diagnostics.", - [ - L("Monitory", "Displays", - "Panel, rozlišení a proč 60 Hz není jediné číslo.", - "The panel, the resolution, and why 60 Hz is not the only number.", - [ - S("1 / 3 • Panel", "LCD a OLED", - "Tip: rozbité podsvícení LCD zhasne obraz, i když panel pořád kreslí.", - "LCD svítí podsvícením a panel světlo cloní.", - "OLED svítí samotnými body a umí opravdovou černou.", - "Lesklý panel má vyšší kontrast a víc odlesků.", - "Uhlopříčka v palcích není totéž co pracovní plocha v bodech."), - S("2 / 3 • Obraz", "Rozlišení a frekvence", - "Tip: nativní rozlišení panelu je to, na které je mřížka bodů.", - "Nižší rozlišení interpoluje a obraz měkne.", - "Obnovovací frekvence říká, kolikrát za sekundu se obraz překreslí.", - "Odezva panelu není totéž co frekvence.", - "HDR chce vyšší jas, ne jen zaškrtnutou volbu."), - S("3 / 3 • Kabel", "Obraz musí stihnout pásmo", - "Tip: starý kabel nebo slabá verze HDMI oseká frekvenci i rozlišení.", - "DisplayPort a HDMI mají verze s různým datovým tokem.", - "VGA je analogové a na dlouhém kabelu měkne.", - "USB-C obraz poveze jen tehdy, když port umí alternativní režim.", - "Dokovací stanice má vlastní limit, ne limit notebooku."), - ], - [ - Q("Čím se OLED liší od běžného LCD?", - ["Body samy svítí a černá je opravdu zhasnutá", - "Nemá rozlišení", - "Jede jen po VGA", - "Nepotřebuje grafickou kartu"], - 0, "LCD obraz skládá cloněním podsvícení."), - Q("Co je nativní rozlišení?", - ["Počet bodů, na který je panel vyroben", - "Nejvyšší číslo v herním menu bez ohledu na panel", - "Rychlost procesoru", - "Počet USB portů"], - 0, "Jiné rozlišení se musí přepočítat."), - Q("Proč 4K při 144 Hz někdy nejde?", - ["Kabel nebo verze portu nestihne datový tok", - "OLED zakazuje frekvenci nad 60 Hz", - "IPv4 omezuje monitory", - "BIOS maže rozlišení"], - 0, "Pásmo portu je strop, ne přání v menu."), - Q("Kdy USB-C nepřenese obraz?", - ["Když port umí jen data a nabíjení", - "Když je kabel černý", - "Když má notebook SSD", - "Když je v síti VLAN"], - 0, "Konektor stejného tvaru ještě neznamená DisplayPort v něm."), - ]), - L("Tisk a sken", "Print and scan", - "Laser, inkoust a síťová fronta.", - "Laser, inkjet, and a network queue.", - [ - S("1 / 3 • Princip", "Toner a kapky", - "Tip: laser netaví toner na papír sám, dělá to zapékací válec.", - "Laser nabije válec a toner se chytí podle obrazu.", - "Inkoust stříká kapky a hodí se na fotky i občasný tisk.", - "Zaschnutá hlava je častější než porucha desky.", - "Termotransfer na štítky není totéž co kancelářský laser."), - S("2 / 3 • Síť", "Jedna tiskárna pro učebnu", - "Tip: tiskárna s vlastní adresou má rezervaci v DHCP.", - "Sdílená tiskárna na počítači žije, jen když je ten počítač zapnutý.", - "Síťová tiskárna poslouchá sama.", - "Fronta na serveru drží ovladač na jednom místě.", - "Špatný ovladač tiskne znaky místo stránky."), - S("3 / 3 • Sken", "Obraz zpět do počítače", - "Tip: rozlišení 600 dpi na text stačí, plakát chce víc.", - "Plochý skener i podavač mají jiný limit gramáže.", - "ADF nezvládne sešité listy.", - "Síťový sken může poslat soubor do složky nebo na poštu.", - "Sklo a podavač se mažou, jinak jsou na stránce pruhy."), - ], - [ - Q("Co v laserové tiskárně připevní toner k papíru?", - ["Zapékací válec", "Inkoustová hlava", - "Ventilátor zdroje", "VGA kabel"], - 0, "Teplo a tlak toner zataví."), - Q("Kdy sdílená tiskárna na učitelském počítači netiskne?", - ["Když je ten počítač vypnutý", - "Když má tiskárna vlastní IP a server", - "Když je v síti DHCP", - "Když je papír v zásobníku"], - 0, "Sdílení přes počítač z toho počítače dělá server."), - Q("Proč dát tiskárně rezervaci v DHCP?", - ["Aby ovladače mířily pořád na stejnou adresu", - "Aby se zvýšilo rozlišení", - "Aby toner vydržel dýl", - "Aby nešla skenovat"], - 0, "Nová adresa po restartu rozbije frontu."), - Q("Co podavač skeneru nezvládne?", - ["Sešitou sadu listů", "Jednotlivé běžné listy", - "Černobílý text", "Odeslání do složky, pokud to umí firmware"], - 0, "Sešit patří na sklo, ne do ADF."), - ]), - L("Sběrnice a disky", "Buses and drives", - "USB, SATA a NVMe nejsou zaměnitelné jen konektorem.", - "USB, SATA and NVMe are not interchangeable just because of the plug.", - [ - S("1 / 3 • USB", "Versie a napájení", - "Tip: port USB-A 2.0 fyzicky vezme i rychlý flash disk a stáhne ho na svou rychlost.", - "USB 2.0, 3.x a 4 se liší tokem dat.", - "USB-C je tvar, ne záruka rychlosti.", - "Thunderbolt po stejném tvaru umí obraz, síť i disk.", - "Hub bez napájení nestačí pro víc disků."), - S("2 / 3 • SATA", "Klasické disky", - "Tip: napájení SATA a datový kabel jsou dva různé vodiče.", - "HDD i starší SSD sedí na SATA.", - "Rychlost rozhraní je strop, disk může být pomalejší.", - "Kabel bez západky vypadne a disk zmizí z BIOSu.", - "Externí box schová SATA za USB."), - S("3 / 3 • NVMe", "SSD přímo na PCIe", - "Tip: M.2 je rozměr destičky. NVMe a SATA na M.2 nejsou totéž.", - "NVMe jede po PCIe a obchází starý řadič SATA.", - "Slot M.2 na desce může umět jen jednu z variant.", - "Dlouhá destička do krátkého slotu nepatří.", - "Bez chlazení rychlé SSD ve špičce zpomalí."), - ], - [ - Q("Co říká samotný tvar USB-C?", - ["Jen tvar konektoru, ne rychlost ani obraz", - "Vždy Thunderbolt", - "Vždy 40 Gb/s", - "Vždy nabíjení 100 W a DisplayPort"], - 0, "Schopnosti určuje řadič a kabel, ne obrys."), - Q("Čím se NVMe liší od SATA SSD?", - ["Jede po PCIe, ne po starém SATA", - "Nemá paměťové buňky", - "Jde zapojit jen do VGA", - "Nepotřebuje desku"], - 0, "Protokol a sběrnice jsou rychlejší cesta."), - Q("Co může umět slot M.2?", - ["Jen SATA, jen NVMe, nebo obojí, podle desky", - "Vždy obojí", - "Jen grafickou kartu", - "Jen operační paměť"], - 0, "Manuál desky je závaznější než tvar zářezu."), - Q("Proč rychlé SSD ve špičce zpomalí?", - ["Přehřeje se a stáhne výkon", - "SATA mu sebere VLAN", - "BIOS maže buňky", - "USB-C ho přepne na 2.0 vždy"], - 0, "Řadič hlídá teplotu."), - ]), - L("Chlazení", "Cooling", - "Vzduch musí mít kudy dovnitř a ven.", - "Air needs a way in and a way out.", - [ - S("1 / 3 • Tok", "Podtlak a přetlak", - "Tip: všechny ventilátory foukající dovnitř bez odtahu jen víří prach.", - "Vpředu a dole se vzduch nasává, vzadu a nahoře odchází.", - "Filtr patří na vstup, ne na výfuk.", - "Zavřená přední stěna designové skříně škrtí přívod.", - "Kabel přes ventilátor je ucpaný filtr."), - S("2 / 3 • CPU", "Chladič musí sednout", - "Tip: pasta není vrstva másla. Má vyplnit nerovnosti.", - "Vzduchový chladič potřebuje místo k bočnici.", - "Voda odvede teplo do radiátoru, který pořád potřebuje vzduch.", - "Špatně dotažený chladič pustí teplotu hned po startu.", - "Limit teploty v BIOSu je pojistka, ne pracovní režim."), - S("3 / 3 • Prach", "Tichý vrah zdroje", - "Tip: vrstva prachu na žebru je izolace.", - "Zdroj s filtrem se čistí, nezalepuje.", - "Notebookový výfuk do měkké deky se udusí.", - "Po roce bez čištění rostou otáčky a teplota.", - "Čištění stlačeným vzduchem nedrží ventilátor v roztočeném stavu naslepo."), - ], - [ - Q("Kam patří prachový filtr?", - ["Na vstup vzduchu", "Jen na výfuk vzadu", - "Dovnitř zdroje bez mřížky", "Na displej"], - 0, "Filtruje se to, co teprve vstupuje."), - Q("Co dělá příliš silná vrstva pasty?", - ["Zhorší přestup tepla", "Zvýší takt samo", - "Nahradí chladič", "Opraví špatný socket"], - 0, "Pasta vede hůř než kov chladiče."), - Q("Proč vodní chlazení pořád potřebuje vzduch?", - ["Radiátor musí teplo předat do místnosti", - "Voda chladí jen při otevřeném okně skříně", - "Čerpadlo jede na VGA", - "Bez ventilátoru se voda vaří vždy do minuty"], - 0, "Okruh teplo přesune, radiátor ho odvede."), - Q("Co udělá notebook na dece?", - ["Zakryje sání a přehřeje se", - "Zvýší jas panelu", - "Přepne disk na NVMe", - "Opraví ventilátor"], - 0, "Sání bývá zespodu."), - ]), - L("Sestavení", "Building a PC", - "Pořadí, které nerozbije desku.", - "An order that does not break the board.", - [ - S("1 / 3 • Příprava", "Nejdřív mimo skříň", - "Tip: sestavu nejdřív oživte na stole. Ve skříni se špatně hledá nedosedlá paměť.", - "Deska, procesor, chladič a jeden modul paměti.", - "Zdroj mimo skříň a obraz na základní grafiku.", - "Až potom disk, karty a zbytek paměti.", - "Antistatická podložka a klidné ruce porazí koberec."), - S("2 / 3 • Socket", "Procesor nemá kam spadnout", - "Tip: ohnutý pin na desce LGA nevrátíte pinzetou naslepo.", - "Trojúhelník na procesoru sedí se značkou na socketu.", - "Páka se zavírá až když procesor leží rovně.", - "Pasta až po usazení, ne do socketu.", - "Chladič se dotahuje křížem, ne jednou stranou nadoraz."), - S("3 / 3 • Skříň", "Kabely jsou součást airflow", - "Tip: distanční sloupky pod deskou musí sedět s otvory, jinak deska zkratuje.", - "Nejdřív zdroj a distanční sloupky, potom deska.", - "Napájení desky, procesoru a karty jsou tři různé konektory.", - "Přední USB a tlačítko mají malé konektory podle manuálu.", - "První start se sleduje: ventilátory, obraz, pípnutí nebo LED."), - ], - [ - Q("Proč oživit sestavu nejdřív mimo skříň?", - ["Nedosedlá paměť se ve skříni hledá hůř", - "Ve skříni nejde zapnout zdroj", - "BIOS ve skříni neběží", - "Pasta venku schne"], - 0, "Minimum dílů na stole ukáže, jestli jádro žije."), - Q("Co se nesmí stát pinům na socketu LGA?", - ["Ohnout je", "Nechat je v socketu", - "Srovnat procesor podle značky", - "Zavřít páku až po usazení"], - 0, "Pin na desce je křehký."), - Q("K čemu jsou distanční sloupky?", - ["Drží desku dál od plechu skříně", - "Napájí ventilátor", - "Jsou to šrouby do disku", - "Uzemňují jen přední LED"], - 0, "Bez nich nebo se špatnými sloupky deska zkratuje."), - Q("Který konektor nepatří do napájení procesoru?", - ["PCIe konektor grafické karty místo EPS", - "Hlavní 24pin na desku", - "EPS konektor k socketu", - "SATA napájení disku"], - 0, "Konektory si jsou podobné a sedí špatně záměrně."), - ]), - L("UEFI a boot", "UEFI and boot", - "Co se děje, než naběhne systém.", - "What happens before the operating system starts.", - [ - S("1 / 3 • Firmware", "BIOS a UEFI", - "Tip: UEFI není jen barevné menu. Umí jiné dělení disku a Secure Boot.", - "Firmware otestuje železo a najde disk se systémem.", - "UEFI používá tabulku GPT, starý BIOS často MBR.", - "Secure Boot pustí jen podepsaný zavaděč.", - "Vypnutí Secure Bootu je výjimka, ne výchozí rada."), - S("2 / 3 • Pořadí", "Z čeho se startuje", - "Tip: flash disk v pořadí před systémem nabootuje omylem instalaci.", - "Nabídka bootu umí jednorázově vybrat zařízení.", - "Disk bez zavaděče se v seznamu nechytí.", - "Více systémů potřebuje bootovací nabídku, ne přepisování pořád dokola.", - "Síťový boot PXE hledá obraz na serveru."), - S("3 / 3 • Heslo", "Menu není pro celou třídu", - "Tip: heslo BIOSu bez záznamu je past, až se bude měnit disk.", - "Heslo na setup brání přehazování bootu.", - "Heslo na disk je silnější a bez něj jsou data nedostupná.", - "Clear CMOS heslo setupu často smaže a vezme i nastavení.", - "Po změně profilu paměti ověřte, že systém naběhne dvakrát."), - ], - [ - Q("Co Secure Boot hlídá?", - ["Aby se spustil jen důvěryhodný zavaděč", - "Aby měl disk aspoň 1 TB", - "Aby ventilátor točil na maximum", - "Aby nešel USB flash disk vůbec zapojit"], - 0, "Nepodepsaný zavaděč se nespustí."), - Q("Čím se liší GPT od MBR?", - ["GPT je tabulka oddílů pro UEFI a větší disky", - "GPT je typ pasty", - "MBR je jen pro NVMe", - "Jsou to totéž"], - 0, "Starý MBR má omezení, na která velký disk naráží."), - Q("Proč nenechat flash disk trvale první v bootu?", - ["Omylem z něj naběhne cizí systém", - "Flash disk vypne Secure Boot navždy", - "UEFI flash disky zakazuje", - "Smaže TPM"], - 0, "Jednorázová nabídka bootu je bezpečnější."), - Q("Co často udělá vymazání CMOS?", - ["Smaže heslo setupu i ostatní volby", - "Smaže jen soubory na ploše", - "Přepne Windows na jiný jazyk", - "Opraví ohnutý pin"], - 0, "Je to návrat firmware k výchozímu stavu."), - ]), - L("Diagnostika", "Diagnostics", - "POST, pípání a minimum, které ještě naběhne.", - "POST, beep codes, and the smallest build that still starts.", - [ - S("1 / 3 • POST", "Test hned po zapnutí", - "Tip: žádný obraz a žádné pípnutí neznamená automaticky mrtvý procesor.", - "Firmware zkouší procesor, paměť a grafiku.", - "Kódy na displeji desky jsou přesnější než staré pípání.", - "Reproduktor skříně musí být zapojený, jinak ticho nic neřekne.", - "Manuál desky překládá kódy. Nejsou u všech stejné."), - S("2 / 3 • Minimum", "Uberte, co může lhát", - "Tip: jeden modul paměti v doporučeném slotu porazí čtyři najednou.", - "Ven grafika, pokud má procesor vlastní obraz.", - "Ven disky a karty.", - "Zkuste jiný kabel obrazu a jiný port.", - "Až jádro naběhne, vracejte díly po jednom."), - S("3 / 3 • Paměť a disk", "Náhodné pády", - "Tip: pád až ve Windows může být paměť, ne jen ovladač.", - "Test paměti běží déle než jedno pípnutí.", - "Chyby čtení disku se projeví v jeho vlastních statistikách.", - "Přehřátí shodí stroj až při zátěži, ne v menu BIOSu.", - "Vyměněný díl ověřte stejnou zkouškou, která předtím selhala."), - ], - [ - Q("Co POST dělá?", - ["Po zapnutí zkouší základní díly", - "Instaluje systém", - "Formátuje SSD", - "Stahuje ovladače z internetu"], - 0, "Je to první test firmware, ne operační systém."), - Q("Proč začít s jedním modulem paměti?", - ["Špatný modul nebo slot se snáz odhalí", - "Deska víc modulů zakazuje", - "BIOS umí jen 4 GB", - "Druhý modul maže UEFI"], - 0, "Minimum dílů zužuje chybu."), - Q("Kdy se přehřátí často neprojeví?", - ["V menu BIOSu bez zátěže", - "Při dlouhém testu procesoru", - "Ve hře", - "Při kódování videa"], - 0, "Teplota roste až s odběrem."), - Q("Co ověří výměnu dílu?", - ["Stejná zkouška, která předtím selhala", - "Jen to, že ventilátor se točí", - "Nová tapeta", - "Jiná barva skříně"], - 0, "Bez opakování testu nevíte, jestli to byla příčina."), - ]), - L("Porty a dokování", "Ports and docks", - "Co z notebooku opravdu vyleze.", - "What a laptop can actually drive.", - [ - S("1 / 3 • Dok", "Jeden kabel, mnoho omezení", - "Tip: levný USB hub není dok. Nepřenese obraz, který port neumí.", - "Dok může nést obraz, síť i napájení.", - "Limit je nejslabší článek: port, kabel nebo dok.", - "Dva externí monitory chtějí port, který to umí, ne přání uživatele.", - "Napájení přes dok nemusí stačit hernímu notebooku."), - S("2 / 3 • Síť", "Kabel z notebooku", - "Tip: mnoho tenkých notebooků už ethernet nemá a potřebuje adaptér.", - "USB adaptér je síťová karta mimo šasi.", - "Rychlost adaptéru bývá 1 Gb/s, ne rychlost školní páteře.", - "Dok s vlastní síťovkou má vlastní MAC adresu.", - "Rezervace DHCP na MAC notebooku pak neplatí pro dok."), - S("3 / 3 • Výběr", "Na co se ptát", - "Tip: stejný USB-C na dvou noteboocích nemá stejné schopnosti.", - "Kolik obrazů, jaké rozlišení a jestli se notebook nabíjí.", - "Jestli síť jede z doku, nebo se čeká Wi-Fi.", - "Jestli čtečka karet a USB sedí verzi, kterou škola používá.", - "Manuál portu je důležitější než fotka konektoru."), - ], - [ - Q("Kdy USB-C dok nepřenese dva monitory?", - ["Když port notebooku umí jen data", - "Když je dok černý", - "Když je v učebně VLAN", - "Když má disk NVMe"], - 0, "Dok neumí vyrobit schopnost, kterou port nemá."), - Q("Proč DHCP rezervace na notebook neplatí přes dok?", - ["Dok má vlastní MAC adresu", - "DHCP doky zakazuje", - "VLAN maže rezervace", - "Ethernet nemá MAC"], - 0, "Rezervace sedí na adresu, kterou server vidí."), - Q("Co je nejslabší článek řetězu obrazu?", - ["Port, kabel nebo dok, podle toho, co umí nejmíň", - "Vždy monitor", - "Vždy procesor", - "Vždy tapeta"], - 0, "Datový tok musí projít všemi."), - Q("Čím se liší USB hub od doku s obrazem?", - ["Hub sám o sobě obraz z datového portu nevyrobí", - "Hub je vždy rychlejší", - "Dok neumí napájení", - "Jsou to totéž"], - 0, "Obraz chce alternativní režim nebo DisplayPort v kabelu."), - ]), - ], -) - -HW3 = course( - "hw3", - "RAID, NAS, servery, virtualizace, zálohy, UPS a firmware.", - "RAID, NAS, servers, virtualisation, backups, UPS and firmware.", - [ - L("RAID", "RAID", - "Více disků jako jeden svazek, ne jako záloha.", - "Several drives as one volume, not as a backup.", - [ - S("1 / 3 • Zrcadlo", "RAID 1", - "Tip: zrcadlo přežije pád jednoho disku, ne smazání souboru.", - "Stejná data jsou na dvou discích.", - "Kapacita je jako jeden disk.", - "Čtení může být rychlejší, zápis ne dvojnásobný.", - "Po výměně disku se pole musí obnovit."), - S("2 / 3 • Prokládání", "RAID 0 a 5", - "Tip: RAID 0 při pádu jednoho disku ztratí všechno.", - "RAID 0 skládá rychlost a kapacitu a nemá ochranu.", - "RAID 5 snese pád jednoho disku z aspoň tří.", - "Parita zabere kapacitu jednoho disku.", - "Obnova velkého pole trvá dlouho a druhý pád v té době je zkáza."), - S("3 / 3 • Řadič", "Hardware a software", - "Tip: pole z jiného řadiče v novém serveru nemusí naběhnout.", - "Hardwarový řadič má vlastní cache a baterii.", - "Softwarové pole řeší systém a je přenosnější.", - "Cache bez ochrany při výpadku proudu rozbije zápis.", - "RAID nenahrazuje zálohu na jiné místo."), - ], - [ - Q("Co RAID 1 přežije?", - ["Pád jednoho z dvojice disků", - "Smazání souboru uživatelem", - "Požár místnosti", - "Ransomware na obou discích naráz"], - 0, "Oba disky mají stejná data, včetně chyby, kterou tam zapíšete."), - Q("Co je RAID 0?", - ["Prokládání bez ochrany při pádu disku", - "Zrcadlo", - "Záloha na pásku", - "Šifrování disku"], - 0, "Rychlost a kapacita, nulová odolnost."), - Q("Proč RAID není záloha?", - ["Neochrání před smazáním, malwarem ani požárem skříně", - "Protože neumí víc než dva disky", - "Protože Windows RAID zakazuje", - "Protože parita maže soubory"], - 0, "Záloha je další kopie jinde a v jiném čase."), - Q("Co hrozí velkému poli při obnově?", - ["Druhý disk spadne dřív, než se obnova dopočítá", - "Pole se samo přepne na RAID 0", - "BIOS smaže paritu", - "NIC se při obnově nesmí točit"], - 0, "Obnova je dlouhá a disky jsou stejně staré."), - ]), - L("NAS a sítě disků", "NAS and storage networks", - "Disky, které nejsou uvnitř jednoho počítače.", - "Drives that are not inside one computer.", - [ - S("1 / 3 • NAS", "Souborový server v krabici", - "Tip: NAS v učebně bez zálohy je jen jeden košík na všechna data.", - "Nabízí složky po síti.", - "Má vlastní účty nebo se ptá školního adresáře.", - "Dva porty se dají spojit, ale jen když to umí i switch.", - "Hlučný diskový provoz nepatří do tiché učebny."), - S("2 / 3 • SAN", "Disk jako místní", - "Tip: SAN nedává složku, dává blokové zařízení.", - "Server vidí disk, i když leží jinde.", - "Síť pro SAN se nemíchá s provozem žáků.", - "Špatné zónování vystaví disk cizímu serveru.", - "Výpadek této sítě shodí systémy, které na disku jedou."), - S("3 / 3 • Soubor", "Práva a snímky", - "Tip: snímek disku není záloha, dokud leží na stejném poli.", - "Práva na složce mají sedět se skupinami, ne s jedním účtem učitele.", - "Snímek umí vrátit soubor smazaný dopoledne.", - "Plný svazek zastaví i zdánlivě nesouvisející službu.", - "Kapacita se hlídá dřív, než svítí červeně."), - ], - [ - Q("Co NAS obvykle nabízí?", - ["Složky po síti", "Blokový disk celé škole bez oprávnění", - "Náhradu procesoru v noteboocích", "Obraz monitoru"], - 0, "Je to souborová služba."), - Q("Čím se SAN liší?", - ["Server dostane disk jako bloky, ne jako složku", - "Je to jen jiné jméno pro USB flash disk", - "Jede jen po Wi-Fi", - "Nemá disky"], - 0, "Souborový systém si na těch blocích dělá až server."), - Q("Proč snímek na stejném poli není záloha?", - ["Pád pole vezme i snímek", - "Snímek nejde vytvořit", - "Snímek maže RAID", - "SMB snímky zakazuje"], - 0, "Záloha musí přežít ztrátu původního úložiště."), - Q("Kam nepatří hlučné diskové pole?", - ["Do tiché učebny vedle žáků", - "Do racku s odtahem", - "Do místnosti se zámek", - "Do sítě oddělené od hostů"], - 0, "Hluk a přístup jsou součást návrhu."), - ]), - L("Servery a rack", "Servers and racks", - "Skříň, do které se nedává herní počítač naležato.", - "A cabinet that is not a gaming PC on its side.", - [ - S("1 / 3 • Tvar", "Racková jednotka", - "Tip: 1U je výška, ne výkon.", - "Server v racku se měří v jednotkách U.", - "Kolejnice musí unést hloubku skříně.", - "Napájecí lišta není prodlužovačka z kuchyně.", - "Proud a teplo se počítají dopředu, ne až když jistič spadne."), - S("2 / 3 • Vzduch", "Studená ulička", - "Tip: servery v racku sají vepředu a foukají dozadu. Otočený kus kazí ostatním.", - "Studený vzduch jde před servery, teplý za ně.", - "Zaslepení prázdných pozic nutí vzduch přes stroje.", - "Kabelová armáda před sáním je ucpávka.", - "Teplota v místnosti není teplota uvnitř 1U serveru."), - S("3 / 3 • Vzdáleně", "Když nejste ve škole", - "Tip: vzdálená správa má vlastní port a vlastní heslo.", - "IPMI nebo iDRAC žije i když systém ne.", - "Patří do správní sítě, ne do učebny.", - "Konzole v racku je záloha, když síť správy spadne.", - "Štítek na serveru říká, co na něm jede."), - ], - [ - Q("Co znamená 1U?", - ["Výšku zařízení v racku", "Výkon jednoho jádra", - "Rychlost disku", "Počet zdrojů"], - 0, "Je to rozměr, ne třída výkonu."), - Q("Kudy má server v racku sát vzduch?", - ["Vepředu a foukat dozadu", "Zezadu dopředu", - "Jen shora bez mřížky", "Z podlahy dírami v desce"], - 0, "Otočený server ohřívá sousedům sání."), - Q("K čemu je vzdálená správa serveru?", - ["Ovládáte ho, i když systém neběží", - "Nahrazuje zálohu dat", - "Je to Wi-Fi pro žáky", - "Maže RAID"], - 0, "Vidíte obraz a umíte stroj zapnout po síti."), - Q("Kam nepatří port vzdálené správy?", - ["Do žákovské VLAN", "Do správní sítě", - "Za firewall", "Na heslo jiné než admin na lístečku"], - 0, "Je to klíče od serveru."), - ]), - L("Virtualizace", "Virtualisation", - "Více systémů na jednom železe.", - "Several systems on one piece of hardware.", - [ - S("1 / 3 • Hypervizor", "Kdo rozděluje železo", - "Tip: virtuální počítač nemá vlastní zdroj. Dělí se o ten fyzický.", - "Hypervizor pouští více systémů nad jedním hardwarem.", - "Každý systém má vlastní diskový soubor a virtuální síťovku.", - "Paměť, kterou slíbíte navíc, se ve špičce potká.", - "Pád fyzického serveru shodí všechny hosty naráz."), - S("2 / 3 • Síť", "Virtuální switch", - "Tip: VLAN ve virtuálu musí sedět s trunkem na fyzické kartě.", - "Virtuální switch propojí hosty mezi sebou.", - "Most je pustí ven fyzickým portem.", - "Izolovaná síť jen mezi virtuály ven nevede.", - "Špatný trunk vystaví správní virtuál do učebny."), - S("3 / 3 • Disk", "Soubor není kouzlo", - "Tip: tenký disk roste a může zaplnit svazek, na kterém leží.", - "Tenké provizionování slíbí víc, než je na začátku obsazeno.", - "Snímek před změnou umí vrátit systém.", - "Zapomenuté snímky zpomalí disk a zaplní úložiště.", - "Záloha virtuálu patří mimo ten samý disk."), - ], - [ - Q("Co se stane, když spadne fyzický server s pěti virtuály?", - ["Spadnou všechny, pokud nemají kam utéct", - "Přežije aspoň správní virtuál", - "Hypervizor je přenese na notebook", - "Nic, virtuál zdroj nepotřebuje"], - 0, "Sdílejí jedno železo."), - Q("K čemu je most virtuálního switche?", - ["Pustí virtuál do fyzické sítě", - "Smaže VLAN", - "Nahradí RAID", - "Zapne Secure Boot hostitele"], - 0, "Bez mostu virtuál ven neodejde."), - Q("Čím je tenký disk nebezpečný?", - ["Doroste a zaplní úložiště pod sebou", - "Nejde zálohovat", - "Nemá souborový systém", - "Vypne hypervizor"], - 0, "Slíbená kapacita není volné místo."), - Q("Co udělá zapomenutý snímek?", - ["Roste a zpomaluje disk", - "Smaže heslo BIOSu", - "Opraví RAID 0", - "Přidá paměť"], - 0, "Snímek je dočasná pojistka, ne trvalý režim."), - ]), - L("Zálohování", "Backups", - "Kopie, kterou umíte vrátit.", - "A copy you can actually restore.", - [ - S("1 / 3 • Pravidlo", "Tři místa", - "Tip: kopie na tom samém disku přežije jen omyl v koši, ne pád disku.", - "Jedna kopie je málo, když leží u originálu.", - "Druhá má být mimo stroj a třetí mimo budovu, když na tom záleží.", - "Verze v čase vrátí soubor z pátku, ne jen ze včerejška.", - "Šifrovaná záloha bez klíče je hromada nic."), - S("2 / 3 • Co zálohovat", "Ne jen plochu", - "Tip: obraz systému bez dat školy je pěkná, ale prázdná záchrana.", - "Data, účty a konfigurace sítě jsou různé věci.", - "Poštovní schránka v cloudu má vlastní nastavení retence.", - "Databáze se nezálohuje kopírováním otevřeného souboru naslepo.", - "Seznam, co se nezálohuje, má být vědomý."), - S("3 / 3 • Zkouška", "Obnova je součást zálohy", - "Tip: záloha, kterou jste nikdy neobnovili, je hypotéza.", - "Jednou za čas obnovte soubor i celý systém nanečisto.", - "Měřte, jak dlouho obnova trvá.", - "Zápis říká, kdo má klíče a kde leží média.", - "Po ransomware rozhoduje stáří poslední čisté kopie."), - ], - [ - Q("Proč nestačí kopie na stejném disku?", - ["Pád disku vezme originál i kopii", - "Systém druhou složku zakazuje", - "RAID ji sám smaže", - "NTFS umí jen jeden soubor"], - 0, "Chyba média je společná."), - Q("Co není pořádná zkouška zálohy?", - ["Jen to, že noční úloha svítí zeleně", - "Obnova jednoho souboru", - "Změřený čas obnovy systému", - "Ověření, že klíč k šifře existuje"], - 0, "Zelená fajfka neznamená, že data jdou otevřít."), - Q("Co rozhoduje po ransomware?", - ["Jestli existuje čistá kopie starší než nákaza", - "Barva skříně", - "Počet ventilátorů", - "Verze spořiče obrazovky"], - 0, "Šifrovaná záloha z doby, kdy už malware běžel, je taky šifrovaná."), - Q("Proč nekopírovat otevřenou databázi jako obyčejný soubor?", - ["Rozpracovaný zápis bude nekonzistentní", - "Databáze nemá soubor", - "SMB databáze zakazuje", - "Kopie by smazala RAID"], - 0, "Běžící databáze se zálohuje nástrojem, který umí konzistentní snímek."), - ]), - L("UPS", "UPS", - "Minuty na uložení, ne náhradní elektrárna.", - "Minutes to shut down cleanly, not a spare power station.", - [ - S("1 / 3 • Úkol", "Překlenout výpadek", - "Tip: malá UPS neutáhne učebnu. Utáhne server, než se uloží.", - "Při výpadku přejde na baterii.", - "Čas běhu závisí na odběru, ne na nálepce bez zátěže.", - "Server dostane signál a vypne se po pořádku.", - "Tiskárna a monitor na UPS servery okrádají o minuty."), - S("2 / 3 • Tvar", "Ne každá UPS je pro zdroj serveru", - "Tip: levná UPS s obdélníkovým průběhem modernímu zdroji vadí.", - "Sinusový výstup je jistější pro aktivní PFC zdroje.", - "Výkon ve voltampérech není totéž co watty na štítku zdroje.", - "Přetížená UPS spadne právě ve výpadku.", - "Zkouška pod zátěží ukáže skutečné minuty."), - S("3 / 3 • Baterie", "Spotřební díl", - "Tip: baterie po třech letech v teple už slíbené minuty nedá.", - "Test baterie nečeká na první bouřku.", - "Výměna se dělá dřív, než článek nabobtná.", - "Teplá místnost baterii ničí rychleji.", - "UPS není náhrada za zálohu dat."), - ], - [ - Q("K čemu malá UPS u serveru je?", - ["Aby se systém stihl uložit a vypnout", - "Aby učebna jela celé odpoledne", - "Aby nahradila zálohu disků", - "Aby chladila rack"], - 0, "Jsou to minuty, ne směna."), - Q("Proč na UPS nepatří laserová tiskárna?", - ["Má velký odběr a sebere čas serverům", - "Tiskárna UPS zničí vždy okamžitě", - "USB tiskárny UPS zakazuje", - "Toner potřebuje jinou frekvenci"], - 0, "Špička zapékání baterii vybíjí zbytečně."), - Q("Co ukáže jen nálepka bez zátěže?", - ["Optimistický čas, který v provozu neplatí", - "Přesné minuty při plném serveru", - "Stav RAID", - "Teplotu procesoru"], - 0, "Měří se s tím, co na UPS opravdu visí."), - Q("Jak často baterie přestane držet slib?", - ["Po letech, dřív v teple", - "Nikdy, je součástí zdroje navždy", - "Až po deseti minutách prvního provozu", - "Jen když je UPS černá"], - 0, "Je to spotřební díl a má se zkoušet."), - ]), - L("Firmware", "Firmware", - "Aktualizace, která nejde udělat uprostřed hodiny.", - "An update that is not applied in the middle of a lesson.", - [ - S("1 / 3 • Co to je", "Program v železe", - "Tip: firmware není ovladač ve Windows. Žije v zařízení i bez systému.", - "Deska, disk, switch i BIOS mají vlastní verzi.", - "Chyba ve firmware shodí zařízení bez ohledu na systém.", - "Výrobce vydává opravy i roky po prodeji.", - "Neznámá verze se nejdřív zjistí, potom se teprve stahuje."), - S("2 / 3 • Postup", "Jedno zařízení, zdroj, záloha", - "Tip: aktualizace při bouřce bez UPS je způsob, jak dostat cihlu.", - "Přečtěte, co verze opravuje a co rozbije.", - "Záloha konfigurace switche jde bokem.", - "Napájení nesmí vypadnout v půlce zápisu.", - "Po dokončení ověřte, že naběhla i služba, ne jen dioda."), - S("3 / 3 • Řada", "Ne všechno v pátek odpoledne", - "Tip: neaktualizujte jádro sítě a jediný server ve stejné hodině.", - "Nejdřív méně důležité zařízení.", - "Okno, kdy smí síť ležet, je domluvené.", - "Když nová verze zlobí, musíte umět předchozí.", - "Zápis verze patří k zařízení, ne do hlavy jednoho člověka."), - ], - [ - Q("Čím se firmware liší od ovladače?", - ["Je v zařízení a běží i bez operačního systému", - "Je to jen soubor na ploše", - "Maže se s přeinstalací vždy", - "Umí ho jen tiskárna"], - 0, "BIOS a firmware disku přežijí nový systém."), - Q("Co před aktualizací switche uložíte?", - ["Konfiguraci a zajistíte napájení", - "Jen tapetu na ploše", - "Heslo Wi-Fi na tabuli", - "Nic, aktualizace si pamatuje sama"], - 0, "Přerušený zápis a chybějící záloha jsou dvě pasti."), - Q("Proč neaktualizovat jádro a jediný server naráz?", - ["Když obojí selže, nemáte z čeho učit ani spravovat", - "Výrobce to technicky zakazuje vždy", - "Firmware umí jen jedno zařízení na budovu", - "UPS to nesežere"], - 0, "Nechte si cestu zpět."), - Q("Co po aktualizaci ověříte?", - ["Že služba opravdu naběhla, ne jen že svítí dioda", - "Že je krabice teplejší", - "Že se změnila barva menu", - "Nic, firmware se neověřuje"], - 0, "Start zařízení není totéž co fungující síť."), - ]), - L("Měření výkonu", "Measuring performance", - "Číslo bez podmínek nic neznamená.", - "A number without the conditions means nothing.", - [ - S("1 / 3 • Co měřit", "Úzké hrdlo", - "Tip: rychlý procesor nezachrání pomalý disk, na kterém systém čeká.", - "Sledujte procesor, paměť, disk a síť zvlášť.", - "Vytížení 100 % chvíli není chyba, trvale ano.", - "Fronta na disku řekne víc než otáčky ventilátoru.", - "Jedno číslo z herního testu není návrh školního serveru."), - S("2 / 3 • Podmínky", "Stejná zkouška", - "Tip: srovnávejte stejný test, stejná data a stejný čas běhu.", - "Studený start a druhý běh z cache nejsou totéž.", - "Notebook na baterii schválně zpomalí.", - "Antivirus v testu umí sežrat výsledek.", - "Zapište verzi systému i to, co na pozadí jelo."), - S("3 / 3 • Rozhodnutí", "Kdy dokoupit", - "Tip: nejdřív paměť nebo disk, ne automaticky nejnovější procesor.", - "Málo paměti žene systém na disk a všechno zpomalí.", - "Plný a pomalý disk kazí i silný procesor.", - "Slabé Wi-Fi nezrychlíte výměnou grafické karty.", - "Nákup bez měření je odhad."), - ], - [ - Q("Co neznamená krátká špička procesoru na 100 %?", - ["Že je procesor nutně slabý", - "Že je všechno v pořádku navždy", - "Že disk neexistuje", - "Že se má hned vyměnit deska"], - 0, "Záleží, jestli špička trvá a jestli na ní někdo čeká."), - Q("Proč druhý běh testu bývá rychlejší?", - ["Data už jsou v cache", - "Procesor se sám přetaktuje natrvalo", - "Disk se zmenší", - "BIOS test podruhé vynechá"], - 0, "Cache není výkon železa v prvním čtení."), - Q("Co často zpomalí celý systém dřív než procesor?", - ["Málo paměti a pomalý disk", - "Příliš mnoho USB myš", - "Barva skříně", - "Počet ikon na ploše"], - 0, "Systém pak pořád čeká na stránkování."), - Q("Co k výsledku testu patří zapsat?", - ["Verze, napájení a co jelo na pozadí", - "Jen nejvyšší číslo", - "Jméno učitele", - "Heslo k BIOSu"], - 0, "Bez podmínek číslo nejde zopakovat."), - ]), - ], -) - -HW4 = course( - "hw4", - "Údržba, TPM, nákup, mobily, periferie, ekologie a maturita.", - "Maintenance, TPM, buying, mobiles, peripherals, disposal and the exam.", - [ - L("Údržba", "Maintenance", - "Čištění a revize dřív, než něco shoří.", - "Cleaning and checks before something burns.", - [ - S("1 / 3 • Prašnost", "Řád, ne až když hučí", - "Tip: otevřená skříň vysátá naslepo umí nasát prach dovnitř zdroje.", - "Filtry se perou dřív, než zčernají.", - "Zdroj se neotevírá. Čistí se zvenku.", - "Klávesnice a myš učebny jsou spotřební a špinavé.", - "Zápis, kdy se učebna dělala, příště určí interval."), - S("2 / 3 • Kontakty", "Uvolněný kabel vypadá jako mrtvá deska", - "Tip: než objednáte desku, domáčkněte napájení a vyzkoušejte jiný kabel obrazu.", - "Oxidy na stolních konektorech kazí obraz i USB.", - "Ohnutý konektor HDMI se do portu necpe silou.", - "Napájecí kabel s poškozenou izolací se vyřadí, nelepí páskou.", - "Prodlužovačka pod kobercem je požár, ne úspora místa."), - S("3 / 3 • Evidence", "Co ve třídě vůbec je", - "Tip: bez inventárního čísla nepoznáte, který zdroj se vrací do záruky.", - "Štítek, umístění a rok pořízení.", - "Záruka a doklad nejsou v šuplíku jednoho člověka.", - "Odepsaný stroj se nevrací do sítě s původním účtem.", - "Pravidelná prohlídka je levnější než hodina bez učebny."), - ], - [ - Q("Co se při údržbě se zdrojem nedělá?", - ["Neotevírá se", "Omývá se mu mřížka zvenku", - "Kontroluje se kabel", "Píše se, kdy byl čištěný"], - 0, "Uvnitř je napětí i po odpojení."), - Q("Co uděláte s kabelem s porušenou izolací?", - ["Vyřadíte ho", "Zalepíte izolepou a vrátíte pod koberec", - "Schováte ho za skříň", "Dáte ho k žákovskému počítači"], - 0, "Poškozená izolace je požár a úraz."), - Q("K čemu je inventární číslo?", - ["Aby šlo dohledat záruku a umístění", - "Aby zrychlilo procesor", - "Nahrazuje heslo BIOSu", - "Je to sériové číslo Windows"], - 0, "Bez něj je reklamace hádanka."), - Q("Kam nepatří odepsaný počítač?", - ["Zpět do sítě s původními účty", - "Do evidence odpadu", - "K smazání disků", - "Mimo žákovskou VLAN"], - 0, "Starý účet na mrtvém stroji je pořád díra, když ho někdo zapne."), - ]), - L("TPM a Secure Boot", "TPM and Secure Boot", - "Železo, které hlídá start systému.", - "Hardware that watches the system start.", - [ - S("1 / 3 • TPM", "Klíče mimo disk", - "Tip: TPM není heslo, které uživatel píše při každém startu.", - "Čip drží klíče použité při startu a šifrování disku.", - "Bez něj některé systémy šifrování disku odmítnou.", - "Vymazání TPM bez zálohy klíčů znamená ztrátu přístupu k disku.", - "Na virtuálu bývá TPM také virtuální a patří k tomu stroji."), - S("2 / 3 • Start", "Řetěz důvěry", - "Tip: Secure Boot a TPM řeší start, ne to, co uživatel spustí odpoledne.", - "Firmware ověří zavaděč.", - "Zavaděč ověří jádro.", - "Cizí systém z flash disku bez podpisu nenaběhne.", - "V laboratoři se výjimka zapíše, nenechá vypnutá navždy."), - S("3 / 3 • Zámek", "Kensington není šifra", - "Tip: lankový zámek zdrží odnesení, data chrání šifrování disku.", - "Zámek skříně zpomalí toho, kdo chce odnést RAM.", - "Heslo BIOSu zpomalí toho, kdo chce přeházet boot.", - "Šifra disku zastaví toho, kdo disk odnese.", - "Všechny tři vrstvy řeší jiného zloděje."), - ], - [ - Q("Co TPM drží?", - ["Klíče pro start a šifrování", - "Zálohu všech dokumentů školy", - "Obraz monitoru", - "Seznam VLAN"], - 0, "Není to úložiště souborů."), - Q("Co se stane po vymazání TPM bez zálohy klíčů?", - ["Šifrovaný disk nemusí jít otevřít", - "Zrychlí se start", - "Smaže se jen spořič", - "Nic, TPM klíče nepoužívá"], - 0, "Klíč v čipu bez kopie je pryč."), - Q("Co Secure Boot nezastaví?", - ["Program, který uživatel spustí v už naběhlém systému", - "Nepodepsaný zavaděč", - "Cizí systém z flashe, pokud podpis chybí", - "Změnu řetězu startu"], - 0, "Hlídá start, ne každé pozdější kliknutí."), - Q("Co ochrání data na odcizeném disku?", - ["Šifrování disku", "Jen lankový zámek skříně", - "Heslo spořiče", "Inventární štítek"], - 0, "Zámek zdrží odnesení celé skříně, ne čtení disku na jiném stroji."), - ]), - L("Nákup sestavy", "Buying a computer", - "Nejdřív práce, potom krabice.", - "The work comes first, then the box.", - [ - S("1 / 3 • Účel", "Učebna není střih videa", - "Tip: stejná sestava pro psaní a pro CAD je buď drahá, nebo pomalá.", - "Kancelář chce spolehlivost, ticho a dost paměti na prohlížeč.", - "Střih a CAD chtějí procesor, paměť a často grafiku.", - "Server chce ECC nebo aspoň diskové pole a správu, ne podsvícení.", - "Počet portů a dokování je součást ceny, ne doplněk potom."), - S("2 / 3 • Čísla", "Co srovnávat", - "Tip: více jader nepomůže programu, který umí jen jedno.", - "Paměť berte s rezervou na čtyři roky, ne na dnešní minimum.", - "SSD jako systémový disk je základ. Velký sklad může být pomalejší.", - "Zdroj má rezervu nad součtem štítků, ne jen přesný součet.", - "Záruka na místě je u učebny levnější než odvoz dvaceti strojů."), - S("3 / 3 • Stejnost", "Jedna image", - "Tip: dvacet různých desek znamená dvacet ovladačů.", - "Stejný model v učebně zjednoduší image i náhradní díl.", - "Dokoupit za dva roky stejnou desku často nejde. Pište, co je uvnitř.", - "Nejlevnější kus bez portů, které učebna používá, levný není.", - "Příkon a hluk patří do zadání, ne až do reklamace."), - ], - [ - Q("Podle čeho se volí sestava?", - ["Podle práce, kterou na ní škola dělá", - "Podle barvy krabice", - "Podle nejvyššího čísla v reklamě", - "Podle počtu RGB ventilátorů"], - 0, "CAD a psaní dopisu nechtějí stejné železo."), - Q("Proč v učebně stejný model?", - ["Jedna image a jeden náhradní díl", - "Aby se lišily ovladače", - "Aby každý stroj bootoval jinak", - "Zákon to vyžaduje kvůli VLAN"], - 0, "Různé desky znamenají různou údržbu."), - Q("Co u zdroje nestačí?", - ["Součet štítků bez rezervy", - "Rezerva nad typický odběr", - "Správný formát do skříně", - "Pojistka, která sedí k rozvodu"], - 0, "Špička a stárnutí se do přesného součtu nevejdou."), - Q("Co zdraží zdánlivě levný notebook?", - ["Chybějící porty a dok, který musíte dokoupit", - "To, že má SSD", - "To, že má záruku", - "To, že je tichý"], - 0, "Učebna bez obrazových výstupů potřebuje doky."), - ]), - L("Mobilní zařízení", "Mobile devices", - "Tablet a telefon ve školní síti.", - "Tablets and phones on the school network.", - [ - S("1 / 3 • Správa", "Cizí kapsy", - "Tip: telefon žáka není školní majetek a nepatří mu školní certifikát natrvalo.", - "Školní tablet se dá zapsat do správy a na dálku smazat.", - "Soukromý telefon do správy školy nepatří.", - "Účet školy na soukromém zařízení má jít odebrat.", - "Ztracený školní tablet bez správy je cizí počítač s vašimi daty."), - S("2 / 3 • Síť", "Kam ho pustit", - "Tip: telefon učitelů ve stejné VLAN jako servery je zbytečné riziko.", - "Hostovská nebo mobilní síť je oddělená.", - "Školní tablet může dostat jinou síť než návštěva.", - "Sdílené tablety se mezi žáky mažou nebo přepínají profil.", - "Nabíjení ve třídě je otázka pojistek, ne jen kabelů na stole."), - S("3 / 3 • Život", "Baterie a pád", - "Tip: cyklování baterie v nabíjecím kufru ji po dvou letech unaví.", - "Obal a popruh jsou součást nákupu, ne charita.", - "Aktualizace systému se dělají hromadně, ne podle nálady.", - "Rozbitý displej se nevrací do oběhu s trčícím sklem.", - "Evidence IMEI nebo sériového čísla patří k inventuře."), - ], - [ - Q("Čím se liší školní tablet od soukromého telefonu?", - ["Školní jde zapsat do správy a na dálku vymazat", - "Soukromý musí mít školní certifikát navždy", - "Jsou to stejné režimy", - "Tablet nepatří do inventury"], - 0, "Majetek školy se dá spravovat, kapsa žáka ne."), - Q("Kam nepatří učitelský telefon?", - ["Do VLAN se servery", - "Do oddělené mobilní sítě", - "Na účet, který jde odebrat", - "Mimo žákovská data, pokud to jde"], - 0, "Ztracený telefon nemá být klíč k serverům."), - Q("Co sdílený tablet mezi žáky potřebuje?", - ["Mazání profilu nebo oddělené účty", - "Jedno heslo napsané na obalu", - "Trvalou složku předchozího žáka", - "Vypnuté aktualizace"], - 0, "Cizí účet na dalším žákovi je únik."), - Q("Co patří do evidence tabletu?", - ["Sériové číslo a umístění", - "Jen barva obalu", - "Heslo žáka", - "Soukromé fotky"], - 0, "Bez čísla ho nepoznáte v kupě stejných."), - ]), - L("Periferie v provozu", "Peripherals in daily use", - "Tiskárny, projektory a co se na nich láme.", - "Printers, projectors, and what actually breaks.", - [ - S("1 / 3 • Projektor", "Lampa a síť", - "Tip: lampa má hodiny. Nečekejte, až praskne uprostřed hodiny.", - "Zdroj obrazu a kabel jsou častější chyba než deska.", - "Filtr projektoru se ucpe prachem a přístroj se vypne.", - "Stropní držák se dotahuje, nevěší se na něj.", - "Náhradní kabel ve třídě je levnější než přestávka."), - S("2 / 3 • Tisk", "Fronta a toner", - "Tip: prázdný toner a zaseknutý papír jsou dvě různé hlášky.", - "Sklad toneru má být suchý, ne na topení.", - "Účet tisku omezí náhodné desítky stran.", - "Síťová tiskárna se po výměně adresy musí najít znovu.", - "Servisní interval bubnu není totéž co výměna toneru."), - S("3 / 3 • Drobnosti", "Myš, sluchátka, kamera", - "Tip: bezdrátová myš bez náhradní baterie je v hodině mrtvá.", - "Sluchátka ve třídě mají být omyvatelná.", - "Kamera na dálkovou výuku chce světlo před obličejem, ne za zády.", - "USB přijímač myši ztracený v portu projektoru se špatně hledá.", - "Spotřební věci se objednávají dřív, než dojde poslední kus."), - ], - [ - Q("Co u projektoru kontrolovat dřív než desku?", - ["Zdroj obrazu, kabel a filtr", - "Jen typ žárovky ve stropě učebny", - "Heslo Wi-Fi", - "Verzi BIOSu učitelského telefonu"], - 0, "Obraz často končí na kabelu."), - Q("Čím se liší toner a buben?", - ["Toner je prach s barvou, buben je díl, který obraz přenáší", - "Jsou to totéž", - "Buben se mění každý den", - "Toner je jen u inkoustové tiskárny"], - 0, "Prázdný toner a unavený buben vypadají na stránce jinak."), - Q("Proč účty tisku?", - ["Omezí náhodné velké tisky", - "Zvýší rozlišení", - "Nahradí papír", - "Vypnou skener"], - 0, "Fronta bez limitu tiskne omylem celé knihy."), - Q("Co ve třídě dochází bez náhrady jako první?", - ["Baterie, kabely a spotřební díly", - "Procesory", - "Rackové lišty", - "TPM čipy"], - 0, "Drobnost zastaví hodinu stejně jako velká porucha."), - ]), - L("Ekologie a data", "Disposal and data", - "Vyhozený disk pořád obsahuje školu.", - "A discarded drive still contains the school.", - [ - S("1 / 3 • Disk", "Smazat neznamená vyhodit", - "Tip: rychlé formátování nechá data čitelná.", - "Před vyřazením se disk smaže tak, aby nešel běžně obnovit.", - "Nefunkční disk se fyzicky zničí, ne jen odloží.", - "SSD se maže příkazem, který buňky opravdu uvolní.", - "Potvrzení o likvidaci patří k inventuře."), - S("2 / 3 • Železo", "Není to směsný odpad", - "Tip: monitor a deska nepatří do popelnice za školou.", - "Elektroodpad se odevzdává na určené místo.", - "Baterie zvlášť, a nabobtnané ještě opatrněji.", - "Toner je taky odpad s režimem, ne koš ve sborovně.", - "Štítek s jménem žáka se před odvozem sundá."), - S("3 / 3 • Darování", "Starý stroj ven ze školy", - "Tip: darovaný počítač bez smazání účtů je dar i s přístupy.", - "Nejdřív data, potom majetek.", - "Licence vázaná na školu se nesmí odstěhovat s počítačem.", - "Zápis, komu stroj připadl, chrání školu.", - "Nefunkční dar je jen přesun odpadu."), - ], - [ - Q("Proč nestačí rychlé formátování?", - ["Data jdou často obnovit", - "Formát disk fyzicky rozbije", - "SSD formát zakazuje", - "Smaže i TPM v jiném počítači"], - 0, "Zmizí odkaz, ne obsah buněk."), - Q("Kam nepatří stará deska?", - ["Do směsného koše", - "Do elektroodpadu", - "K evidované likvidaci", - "Po smazání dat, pokud se vyřazuje"], - 0, "Elektroodpad má vlastní režim."), - Q("Co před darem počítače uděláte?", - ["Smažete data a ověříte licence", - "Necháte účty, ať se nový majitel přihlásí", - "Jen umyjete skříň", - "Přilepíte heslo na víko"], - 0, "Dar není předání školní sítě."), - Q("Čím se maže SSD líp než jedním přepisem naslepo?", - ["Příkazem, který buňky opravdu uvolní", - "Smazáním koše", - "Změnou tapety", - "Vypnutím Secure Boot"], - 0, "Řadič SSD přepis naslepo nemusí uložit tam, kde čekáte."), - ]), - L("Metodika závady", "A fault method", - "Jedna věta, která drží celý postup.", - "One sentence that holds the whole procedure.", - [ - S("1 / 3 • Příznak", "Co přesně nejde", - "Tip: ‚nejde počítač‘ může být černý obraz, špatné heslo i spadlá síť.", - "Zeptejte se, co uživatel čekal a co vidí.", - "Od kdy a jestli to jde jinde.", - "Jedna učebna, nebo jen jeden stůl.", - "Bez příznaku se mění díly naslepo."), - S("2 / 3 • Izolace", "Nejužší místo", - "Tip: fungující kabel a fungující port rozdělí chybu na dvě hromady.", - "Vyměňte kabel, port, účet nebo zařízení, vždy jen jedno.", - "Když náhradní kus funguje, původní je vinný nebo špatně nastavený.", - "Když nefunguje ani náhradní, chyba je ve společné věci.", - "Pište si mezivýsledky. Paměť po obědě lže."), - S("3 / 3 • Závěr", "Oprava a prevence", - "Tip: vyměněný kabel bez zápisu se příští měsíc tváří jako záhada.", - "Opravte příčinu, ne jen příznak na jednom stole.", - "Řekněte uživateli, co se změnilo.", - "Díly do opravy nepatří zpátky do skříně potichu.", - "Opakovaná závada chce úpravu nákupu nebo zapojení."), - ], - [ - Q("Co je první otázka?", - ["Co přesně nejde a od kdy", - "Jakou má deska barvu", - "Jestli je ve škole VLAN 20", - "Kolik stojí nový notebook"], - 0, "Příznak zužuje vrstvu, kterou budete zkoušet."), - Q("Proč měnit jen jeden díl?", - ["Ať víte, který rozdíl pomohl", - "Sklad má jen jeden kabel", - "BIOS víc výměn zakazuje", - "Uživatel jinak zapomene heslo"], - 0, "Dvě výměny naráz nic nedokážou."), - Q("Náhradní kabel taky nejde. Co z toho plyne?", - ["Chyba je spíš ve portu, účtu nebo zařízení", - "Oba kabely jsou vždy špatné", - "Síť nemá smysl", - "Je rozbitý TPM"], - 0, "Společné selhání ukazuje na společnou část."), - Q("Co patří do zápisu opravy?", - ["Příznak, příčina a co se vyměnilo", - "Jen ‚hotovo‘", - "Heslo uživatele", - "Soukromý názor na učitele"], - 0, "Příště podle zápisu nezačínáte od nuly."), - ]), - L("Opakování k maturitě", "Exam review", - "Železo, které umíte pojmenovat a zdůvodnit.", - "Hardware you can name and justify.", - [ - S("1 / 3 • Tok dat", "Od kliknutí k disku", - "Tip: maturita chce cestu, ne seznam zkratek.", - "Vstup, paměť, procesor, sběrnice, disk a výstup.", - "RAM je pracovní, disk je trvalý. Není to totéž.", - "Grafika může mít vlastní paměť a pořád jede po sběrnici.", - "Úzké hrdlo je nejpomalejší článek této cesty."), - S("2 / 3 • Spolehlivost", "Co drží učebnu", - "Tip: záloha, RAID a UPS řeší tři různé nehody.", - "RAID drží provoz při pádu disku.", - "Záloha vrátí data z jiného místa a času.", - "UPS dá čas na vypnutí.", - "Firmware a čištění jsou prevence, ne oprava po požáru."), - S("3 / 3 • Rozhodnutí", "Proč právě tahle krabice", - "Tip: umíte obhájit paměť, disk a porty pro konkrétní učebnu.", - "Kancelář, střih a server mají jiné priority.", - "Stejný model ve třídě šetří image.", - "Vyřazení začíná smazáním dat.", - "Závadu vedete od příznaku po jedné změně."), - ], - [ - Q("Čím se liší RAM a disk?", - ["RAM je pracovní paměť, disk drží data i bez napájení", - "Jsou to totéž", - "Disk je vždy rychlejší", - "RAM se zálohuje na pásku"], - 0, "Vypnutí smaže obsah RAM, ne uložený soubor na disku."), - Q("Co vrátí soubor smazaný před týdnem?", - ["Záloha z dřívějšího dne, ne RAID", - "RAID 1 sám", - "UPS", - "Secure Boot"], - 0, "RAID má pořád aktuální, tedy i smazaný stav."), - Q("Co dá UPS?", - ["Čas na pořádné vypnutí", - "Kopii dat v jiné budově", - "Rychlejší procesor", - "Nový disk"], - 0, "Baterie není archiv."), - Q("Čím začíná vyřazení počítače?", - ["Smazáním dat", - "Sundáním obalu", - "Darem bez kontroly", - "Zápisem do VLAN"], - 0, "Nejdřív obsah, potom plech."), - ]), - ], -) - -COURSES = [NET2, NET3, NET4, HW2, HW3, HW4] -BACK = { - "net2": "netyears", "net3": "netyears", "net4": "netyears", - "hw2": "hwyears", "hw3": "hwyears", "hw4": "hwyears", -} -TITLE = { - "net2": "net_year2", "net3": "net_year3", "net4": "net_year4", - "hw2": "hw_year2", "hw3": "hw_year3", "hw4": "hw_year4", -} -PTR = { - "net2": "qy_net2", "net3": "qy_net3", "net4": "qy_net4", - "hw2": "qy_hw2", "hw3": "qy_hw3", "hw4": "qy_hw4", -} - - -def emit(): - lines = [ - '#include "graduately.h"', - "", - "/* Generated by scripts/gen-it-years.py. Do not edit by hand. */", - "", - ] - i18n = [] - pages = [] - for course in COURSES: - p = course["prefix"] - i18n.append( - f' {{"{p}_sub", {c(course["sub"])}, {c(course["sub_en"])}}},' - ) - for n, lesson in enumerate(course["lessons"], start=1): - i18n.append( - f' {{"{p}_unit{n}", {c(lesson["title"])}, {c(lesson["title_en"])}}},' - ) - i18n.append( - f' {{"{p}_unit{n}_sub", {c(lesson["sub"])}, {c(lesson["sub_en"])}}},' - ) - i18n.append( - f' {{"{p}_ex{n}_title", {c("Kvíz: " + lesson["title"])}, ' - f'{c("Quiz: " + lesson["title_en"])}}},' - ) - i18n.append( - f' {{"{p}_quiz{n}_head", {c("Kvíz k tématu " + lesson["title"])}, ' - f'{c("Quiz on " + lesson["title_en"])}}},' - ) - lines.append(f"static GtkWidget *build_{p}_unit{n}_page(void) {{") - lines.append(" static const NetSlide slides[] = {") - for kicker, title, tip, bullets in lesson["slides"]: - lines.append(" {") - lines.append(f" {c(kicker)}, {c(title)}, {c(tip)},") - lines.append(" {") - for bullet in bullets: - lines.append(f" {c(bullet)},") - lines.append(" NULL,") - lines.append(" },") - lines.append(" },") - lines.append(" };") - lines.append( - f' return quizyear_unit({PTR[p]}, {n - 1}, "{p}_unit{n}", ' - f'"{p}_unit{n}_sub", slides, (int)(sizeof slides / sizeof slides[0]));' - ) - lines.append("}") - lines.append("") - lines.append(f"static GtkWidget *build_{p}_unit{n}_exercise_page(void) {{") - lines.append(" static const ChoiceQ qs[] = {") - for prompt, options, correct, _hint in lesson["quiz"]: - opts = ", ".join(c(o) for o in options) - lines.append(f" {{{c(prompt)}, {{{opts}}}, 4, {correct}}},") - lines.append(" };") - lines.append(" static const char *hints[] = {") - for _prompt, _options, _correct, hint in lesson["quiz"]: - lines.append(f" {c(hint)},") - lines.append(" };") - lines.append( - f' return quizyear_quiz({PTR[p]}, {n - 1}, "{p}_ex{n}_title", ' - f'"{p}_quiz{n}_head", qs, hints, (int)(sizeof qs / sizeof qs[0]));' - ) - lines.append("}") - lines.append("") - pages.append((f"{p}unit{n}", f"build_{p}_unit{n}_page")) - pages.append((f"{p}ex{n}", f"build_{p}_unit{n}_exercise_page")) - - lines.append("void add_it_year_pages(GtkStack *stack) {") - lines.append(" quizyear_boot();") - for course in COURSES: - p = course["prefix"] - lines.append( - f' gtk_stack_add_named(stack, quizyear_map({PTR[p]}), "{p}map");' - ) - for name, fn in pages: - lines.append(f' gtk_stack_add_named(stack, {fn}(), "{name}");') - lines.append("}") - lines.append("") - - (ROOT / "src" / "it_year_pages.c").write_text("\n".join(lines) + "\n", encoding="utf-8") - (ROOT / "src" / "it_years_i18n.inc").write_text("\n".join(i18n) + "\n", encoding="utf-8") - print(f"wrote {len(COURSES) * 8} lessons") - - -if __name__ == "__main__": - emit() diff --git a/scripts/gen-math.py b/scripts/gen-math.py deleted file mode 100644 index c5d2e9a..0000000 --- a/scripts/gen-math.py +++ /dev/null @@ -1,2040 +0,0 @@ -#!/usr/bin/env python3 -"""Generate the mathematics lessons. - -Numeric answers are built from fractions.Fraction, then checked by -src/math_check.c. Slide text is Czech, like the other subjects. -""" -from __future__ import annotations - -import subprocess -import sys -from fractions import Fraction -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -SRC = ROOT / "src" - - -def show(value) -> str: - fr = Fraction(value) - if fr.denominator == 1: - return str(fr.numerator) - return f"{fr.numerator}/{fr.denominator}" - - -class Prob: - def __init__(self, prompt: str, spec: str, hint: str, draw: str | None = None): - self.prompt = prompt - self.spec = spec - self.hint = hint - self.draw = draw - - -def N(prompt: str, value, how: str) -> Prob: - fr = Fraction(value) - return Prob(prompt, "num:" + show(fr), f"{how} Výsledek je {show(fr)}.") - - -def PI(prompt: str, coeff, how: str) -> Prob: - fr = Fraction(coeff) - if fr == 1: - spec = "num:pi" - shown = "π" - elif fr == -1: - spec = "num:-pi" - shown = "-π" - elif fr.denominator == 1: - spec = f"num:{fr.numerator}*pi" - shown = f"{fr.numerator}π" - else: - spec = f"num:{show(fr)}*pi" - shown = f"({show(fr)})π" - return Prob(prompt, spec, f"{how} Výsledek je {shown}.") - - -def SQRT(prompt: str, spec: str, how: str) -> Prob: - if not spec.startswith("num:"): - raise ValueError(spec) - return Prob(prompt, spec, how) - - -def PAIR(prompt: str, a, b, how: str) -> Prob: - return Prob(prompt, f"pair:{show(a)};{show(b)}", - f"{how} Napište {show(a)};{show(b)}.") - - -def SET(prompt: str, values, how: str) -> Prob: - body = ";".join(show(v) for v in values) - return Prob(prompt, "set:" + body, f"{how} Napište {body}.") - - -def DRAW(prompt: str, spec: str, how: str, sample: str) -> Prob: - return Prob(prompt, spec, how, draw=sample) - - -def c_escape(text: str) -> str: - return text.replace("\\", "\\\\").replace('"', '\\"') - - -def c_string(text: str) -> str: - if "\n" in text: - raise ValueError(text) - return '"' + c_escape(text) + '"' - - -def lesson(title_cs, title_en, sub_cs, sub_en, slides, problems): - return { - "title_cs": title_cs, - "title_en": title_en, - "sub_cs": sub_cs, - "sub_en": sub_en, - "slides": slides, - "problems": problems, - } - - -def S(kicker, title, tip, lines): - if len(lines) < 3 or len(lines) > 7: - raise ValueError(title) - return (kicker, title, tip, lines) - - -def year0(): - return [ - lesson( - "Pořadí operací", "Order of operations", - "Závorky, násobení a dělení, sčítání a odčítání.", - "Brackets, then multiplication and division, then addition and subtraction.", - [ - S("1 / 3 • Pravidlo", "Co se počítá dřív", - "Tip: násobení a dělení jsou stejně silné a jdou zleva doprava.", - [ - "Nejprve se vyřeší závorky, zevnitř ven.", - "Pak jsou mocniny a odmocniny.", - "Násobení a dělení mají přednost před sčítáním a odčítáním.", - "Sčítání a odčítání se také provádějí zleva doprava.", - ]), - S("2 / 3 • Bez závorek", "Násobení má přednost", - "Tip: 2 + 3 · 4 není 20.", - [ - "Ve výrazu 2 + 3 · 4 se nejdřív násobí: 3 · 4 = 12.", - "Teprve potom se přičtou dvě: 2 + 12 = 14.", - "Ve výrazu 20 − 6 / 2 se nejdřív dělí: 6 / 2 = 3.", - "Pak 20 − 3 = 17.", - ]), - S("3 / 3 • Závorky", "Závorka změní pořadí", - "Tip: závorka se chová jako jeden počet.", - [ - "(8 − 3) · 2 začíná v závorce: 5 · 2 = 10.", - "3 · (4 + 1) je 3 · 5 = 15.", - "Bez závorky by 3 · 4 + 1 vyšlo 13.", - "Závorku proto pište vždy, když má sčítání předběhnout násobení.", - ]), - ], - [ - N("Spočítejte 2 + 3 · 4.", 2 + 3 * 4, - "Násobení má přednost: 3 · 4 = 12 a 2 + 12 = 14."), - N("Spočítejte (8 − 3) · 2.", (8 - 3) * 2, - "Nejdřív závorka: 8 − 3 = 5, potom 5 · 2 = 10."), - N("Spočítejte 20 − 6 / 2.", 20 - Fraction(6, 2), - "Nejdřív dělení: 6 / 2 = 3, potom 20 − 3 = 17."), - N("Spočítejte 3 · (4 + 1).", 3 * (4 + 1), - "Nejdřív závorka: 4 + 1 = 5, potom 3 · 5 = 15."), - ], - ), - lesson( - "Zlomky", "Fractions", - "Sčítání, odčítání, násobení a dělení zlomků.", - "Adding, subtracting, multiplying and dividing fractions.", - [ - S("1 / 3 • Součet", "Společný jmenovatel", - "Tip: zlomek v základním tvaru má nesoudělný čitatel a jmenovatel.", - [ - "Sčítat a odčítat lze zlomky se stejným jmenovatelem.", - "Jinak se jmenovatelé rozšíří na nejmenší společný násobek.", - "1/2 + 1/3 má společný jmenovatel 6: 3/6 + 2/6 = 5/6.", - "3/4 − 1/4 = 2/4 = 1/2.", - ]), - S("2 / 3 • Součin", "Čitatel s čitatelem", - "Tip: před násobením jde často krátit křížem.", - [ - "Zlomky se násobí čitatel čitatelem a jmenovatel jmenovatelem.", - "2/3 · 3/5 = 6/15 = 2/5.", - "Krátit se smí jen čitatel se jmenovatelem, ne dvě horní čísla mezi sebou.", - "Smíšené číslo se před počtem převede na zlomek.", - ]), - S("3 / 3 • Podíl", "Dělit znamená násobit převráceným", - "Tip: převrácený zlomek k a/b je b/a.", - [ - "Dělení zlomkem je násobení jeho převrácenou hodnotou.", - "(3/4) : (1/2) = 3/4 · 2/1 = 6/4 = 3/2.", - "Výsledek se uvede v základním tvaru.", - "Nulou se dělit nesmí, proto jmenovatel nesmí vyjít 0.", - ]), - ], - [ - N("Spočítejte 1/2 + 1/3. Zlomek v základním tvaru.", - Fraction(1, 2) + Fraction(1, 3), - "Společný jmenovatel je 6: 3/6 + 2/6 = 5/6."), - N("Spočítejte 3/4 − 1/4.", - Fraction(3, 4) - Fraction(1, 4), - "Jmenovatel už je stejný: 2/4 = 1/2."), - N("Spočítejte 2/3 · 3/5.", - Fraction(2, 3) * Fraction(3, 5), - "6/15 se zkrátí třemi na 2/5."), - N("Spočítejte (3/4) : (1/2).", - Fraction(3, 4) / Fraction(1, 2), - "Násobí se převráceným zlomkem: 3/4 · 2/1 = 3/2."), - ], - ), - lesson( - "Desetinná čísla", "Decimals", - "Sčítání, násobení a dělení desetinných čísel.", - "Adding, multiplying and dividing decimals.", - [ - S("1 / 3 • Zápis", "Čárka i tečka", - "Tip: 0,5 je totéž co 1/2.", - [ - "Desetinná čárka odděluje celou část od desetin, setin a tisícin.", - "0,1 je jedna desetina, 0,01 je jedna setina.", - "Při sčítání se čárky píšou pod sebe.", - "2,5 + 1,5 = 4.", - ]), - S("2 / 3 • Násobení", "Čárka se posouvá", - "Tip: násobení deseti posune čárku o jedno místo doprava.", - [ - "Počet desetinných míst součinu je součet počtů míst činitelů.", - "0,2 · 5 = 1, protože dvě desetiny pětkrát jsou jedna celá.", - "1,25 − 0,5 = 0,75, což je 3/4.", - "Výsledek lze psát desetinně i zlomkem.", - ]), - S("3 / 3 • Dělení", "Dělit desetinným číslem", - "Tip: dělitel se nejdřív upraví na celé číslo.", - [ - "3,6 : 0,3 se rozšíří deseti na 36 : 3 = 12.", - "Čárka se v děliteli i děleném posune o stejný počet míst.", - "Dělení deseti posune čárku o jedno místo doleva.", - "Nulou se ani u desetinných čísel dělit nesmí.", - ]), - ], - [ - N("Spočítejte 2,5 + 1,5.", Fraction("2.5") + Fraction("1.5"), - "Pět desetin a pět desetin je jedna celá, celkem 4."), - N("Spočítejte 0,2 · 5.", Fraction("0.2") * 5, - "Dvě desetiny pětkrát jsou 10 desetin, tedy 1."), - N("Spočítejte 3,6 : 0,3.", Fraction("3.6") / Fraction("0.3"), - "Posun čárky dá 36 : 3 = 12."), - N("Spočítejte 1,25 − 0,5.", Fraction("1.25") - Fraction("0.5"), - "1,25 − 0,50 = 0,75, tedy 3/4."), - ], - ), - lesson( - "Procenta", "Percentages", - "Procento ze základu, počet procent a cena po slevě.", - "A percentage of a base, the rate, and a price after a discount.", - [ - S("1 / 3 • Základ", "Jedno procento je setina", - "Tip: pište jen číslo, znak procenta ne.", - [ - "1 % ze základu je jedna setina základu.", - "p % ze základu z je (p/100) · z.", - "20 % ze 150 je 0,2 · 150 = 30.", - "Základ, procentová část a počet procent jsou tři veličiny.", - ]), - S("2 / 3 • Kolik procent", "Část dělená základem", - "Tip: výsledek 0,25 znamená 25 %.", - [ - "Počet procent je (část / základ) · 100.", - "15 ze 60 je 15/60 = 1/4, tedy 25 %.", - "Do odpovědi se píše 25, ne 0,25 a ne 25 %.", - "Zlomek se na procenta násobí stem.", - ]), - S("3 / 3 • Sleva a základ", "Dopočítání celku", - "Tip: sleva 10 % nechá z ceny 90 %.", - [ - "Po slevě 10 % zbývá 90 % původní ceny.", - "400 − 10 % je 0,9 · 400 = 360.", - "Když 20 % základu je 18, je 1 % rovno 18/20.", - "Celý základ je pak 100 takových dílů: 90.", - ]), - ], - [ - N("Kolik je 20 % ze 150? Napište jen číslo.", - Fraction(20, 100) * 150, - "20 % je 0,2 a 0,2 · 150 = 30."), - N("15 je kolik procent z 60? Napište jen číslo, bez znaku %.", - Fraction(15, 60) * 100, - "15/60 = 1/4 = 25 %."), - N("Cena 400 se sníží o 10 %. Jaká bude nová cena?", - 400 * Fraction(90, 100), - "Zůstane 90 %: 0,9 · 400 = 360."), - N("20 % základu je 18. Jak velký je základ?", - 18 / Fraction(20, 100), - "1 % je 18/20 = 0,9 a 100 % je 90."), - ], - ), - lesson( - "Poměr a měřítko", "Ratio and scale", - "Dělení v poměru, úměra a měřítko mapy.", - "Sharing in a ratio, proportion and the scale of a map.", - [ - S("1 / 3 • Poměr", "Díly celku", - "Tip: poměr 2 : 3 má dohromady 5 dílů.", - [ - "Poměr a : b říká, na kolik stejných dílů se celek rozdělí.", - "Počet dílů je a + b.", - "První část je a/(a + b) z celku.", - "Z 20 v poměru 2 : 3 připadá na první část 8.", - ]), - S("2 / 3 • Úměra", "Součin vnějších a vnitřních členů", - "Tip: 3 : 5 = x : 20 znamená 3/5 = x/20.", - [ - "V úměře a : b = c : d platí a · d = b · c.", - "Z 3/5 = x/20 vyjde x = 3/5 · 20 = 12.", - "Stejný poměr lze rozšiřovat i krátit.", - "Neznámý člen se dopočítá jedním násobením a jedním dělením.", - ]), - S("3 / 3 • Měřítko", "Mapa a skutečnost", - "Tip: 1 : 1000 znamená, že 1 cm na mapě je 10 m ve skutečnosti.", - [ - "Měřítko 1 : k zmenšuje: skutečnost je k-krát větší než plán.", - "5 cm na mapě 1 : 1000 je 5000 cm, tedy 50 m.", - "Měřítko 5 : 1 je zvětšení, obraz je pětkrát větší.", - "4 cm v měřítku 5 : 1 odpovídá obrazu 20 cm.", - ]), - ], - [ - N("Číslo 20 rozdělte v poměru 2 : 3. Jak velká je první část?", - 20 * Fraction(2, 5), - "Dílů je 5 a první část jsou 2 z nich: 2/5 · 20 = 8."), - N("Na mapě 1 : 1000 jsou 5 cm. Kolik metrů je to ve skutečnosti?", - Fraction(5 * 1000, 100), - "5 cm · 1000 = 5000 cm = 50 m."), - N("Platí 3 : 5 = x : 20. Kolik je x?", - Fraction(3, 5) * 20, - "x = 3/5 · 20 = 12."), - N("Úsečka 4 cm se zobrazí v měřítku 5 : 1. Jak dlouhý je obraz v centimetrech?", - 4 * 5, - "Měřítko 5 : 1 zvětšuje pětkrát: 4 · 5 = 20."), - ], - ), - lesson( - "Záporná čísla", "Negative numbers", - "Sčítání, násobení a absolutní hodnota.", - "Addition, multiplication and absolute value.", - [ - S("1 / 3 • Číselná osa", "Vpravo roste, vlevo klesá", - "Tip: přičíst kladné číslo znamená posun doprava.", - [ - "Kladná čísla leží vpravo od nuly, záporná vlevo.", - "−3 + 8 je posun z −3 o 8 kroků doprava, tedy na 5.", - "Odčítání záporného čísla je totéž co přičítání kladného.", - "6 − (−2) = 6 + 2 = 8.", - ]), - S("2 / 3 • Násobení", "Znaménka", - "Tip: dvě záporná znaménka dají kladný součin.", - [ - "Součin kladného a záporného čísla je záporný.", - "Součin dvou záporných čísel je kladný.", - "(−4) · (−5) = 20.", - "Stejné pravidlo platí pro dělení.", - ]), - S("3 / 3 • Absolutní hodnota", "Vzdálenost od nuly", - "Tip: absolutní hodnota nikdy není záporná.", - [ - "|a| je vzdálenost čísla a od nuly na ose.", - "|−7| = 7 a |7| = 7.", - "|0| = 0.", - "Absolutní hodnota smaže znaménko, ale číslo jinak nezmění.", - ]), - ], - [ - N("Spočítejte −3 + 8.", -3 + 8, - "Z −3 se jde o 8 doprava, na 5."), - N("Spočítejte (−4) · (−5).", (-4) * (-5), - "Součin dvou záporných čísel je kladný: 20."), - N("Spočítejte |−7|.", 7, - "Vzdálenost −7 od nuly je 7."), - N("Spočítejte 6 − (−2).", 6 - (-2), - "Odčítat −2 znamená přičíst 2: 6 + 2 = 8."), - ], - ), - lesson( - "Lineární rovnice", "Linear equations", - "Ekvivalentní úpravy a jednoduché rovnice.", - "Equivalent steps and simple equations.", - [ - S("1 / 3 • Rovnováha", "Stejně na obě strany", - "Tip: co uděláte vlevo, udělejte i vpravo.", - [ - "Rovnice říká, že levá strana se rovná pravé.", - "K oběma stranám lze přičíst stejné číslo.", - "Obě strany lze vynásobit stejným nenulovým číslem.", - "Cílem je osamostatnit neznámou.", - ]), - S("2 / 3 • Kroky", "Nejdřív číslo, pak koeficient", - "Tip: 2x − 4 = 10 se nejdřív zbaví čtyřky.", - [ - "x + 5 = 12 se odečtením pěti změní na x = 7.", - "3x = 15 se vydělí třemi: x = 5.", - "2x − 4 = 10 dá po přičtení čtyř 2x = 14, tedy x = 7.", - "Zkouška dosadí výsledek do původní rovnice.", - ]), - S("3 / 3 • Dělení neznámé", "Zlomek s x", - "Tip: x/2 = 6 se násobí dvěma.", - [ - "x/2 je totéž co (1/2) · x.", - "Násobení obou stran dvěma dá x = 12.", - "Násobit nulou se nesmí, rovnice by ztratila význam.", - "U lineární rovnice s nenulovým koeficientem je řešení jedno.", - ]), - ], - [ - N("Vyřešte x + 5 = 12. Napište x.", 12 - 5, - "Od obou stran se odečte 5."), - N("Vyřešte 3x = 15. Napište x.", Fraction(15, 3), - "Obě strany se vydělí 3."), - N("Vyřešte 2x − 4 = 10. Napište x.", Fraction(10 + 4, 2), - "2x = 14, takže x = 7."), - N("Vyřešte x/2 = 6. Napište x.", 6 * 2, - "Obě strany se násobí 2."), - ], - ), - lesson( - "Obvod, obsah a čtverec", "Perimeter, area and a square", - "Obdélník, trojúhelník a doplnění čtverce na mřížce.", - "A rectangle, a triangle, and completing a square on the grid.", - [ - S("1 / 3 • Obdélník", "Obvod a obsah", - "Tip: obvod je součet všech stran, obsah je součin dvou sousedních.", - [ - "Obdélník a × b má obvod 2 · (a + b).", - "Obdélník 5 × 3 má obvod 2 · 8 = 16.", - "Obsah je a · b. Obdélník 6 × 4 má obsah 24.", - "Jednotky obvodu jsou délkové, jednotky obsahu čtvereční.", - ]), - S("2 / 3 • Trojúhelník", "Základna a výška", - "Tip: výška je kolmá na základnu, ne délka šikmé strany.", - [ - "Součet vnitřních úhlů trojúhelníku je 180°.", - "Třetí úhel je 180° minus součet dvou známých.", - "Úhly 60° a 50° doplňuje 70°.", - "Obsah je (základna · výška) / 2. Pro 8 a 5 je to 20.", - ]), - S("3 / 3 • Čtverec", "Doplnění na mřížce", - "Tip: osa y míří nahoru. Klepnutím na bod ho odeberete.", - [ - "Čtverec má čtyři shodné strany a čtyři pravé úhly.", - "Druhé dva vrcholy vzniknou posunutím strany o stejnou délku kolmo.", - "U vodorovné strany leží zbývající vrcholy přímo nad ní, nebo pod ní.", - "Na mřížce jsou platné jen oba vrcholy téže strany.", - ]), - ], - [ - N("Obdélník má strany 5 a 3. Jaký je jeho obvod?", - 2 * (5 + 3), - "2 · (5 + 3) = 16."), - N("Obdélník má strany 6 a 4. Jaký je jeho obsah?", - 6 * 4, - "Obsah je 6 · 4 = 24."), - N("Trojúhelník má základnu 8 a výšku 5. Jaký je jeho obsah?", - Fraction(8 * 5, 2), - "Obsah je (8 · 5) / 2 = 20."), - N("Dva úhly trojúhelníku jsou 60° a 50°. Jak velký je třetí úhel ve stupních?", - 180 - 60 - 50, - "Součet je 180°, takže třetí úhel je 70°."), - DRAW("Na mřížce je strana čtverce od A = [2; 3] k B = [5; 3]. Doplňte zbývající dva vrcholy.", - "square:2,3;5,3", - "Strana má délku 3. Druhé dva vrcholy jsou [2; 6] a [5; 6], nebo [2; 0] a [5; 0].", - "5,6;2,6"), - ], - ), - ] - - -def year1(): - return [ - lesson( - "Dělitelnost a prvočísla", "Divisibility and primes", - "Největší společný dělitel, násobek a rozklad.", - "Highest common factor, lowest common multiple and factorisation.", - [ - S("1 / 3 • Dělitel", "Čísla, která dělí beze zbytku", - "Tip: prvočíslo má právě dva dělitele, jedničku a sebe.", - [ - "Dělitel čísla a je celé číslo, kterým a dělí beze zbytku.", - "Číslo 12 má dělitele 1, 2, 3, 4, 6 a 12, tedy šest dělitelů.", - "Prvočíslo nelze rozložit na součin dvou menších celých čísel větších než 1.", - "Jednička prvočíslo není.", - ]), - S("2 / 3 • NSD a NSN", "Společný dělitel a násobek", - "Tip: NSD · NSN dvou čísel je jejich součin.", - [ - "Největší společný dělitel je největší číslo, které dělí obě čísla.", - "NSD(24, 36) = 12.", - "Nejmenší společný násobek je nejmenší kladné číslo, které je násobkem obou.", - "NSN(6, 8) = 24.", - ]), - S("3 / 3 • Rozklad", "Součin mocnin prvočísel", - "Tip: společné prvočinitele berte v nejmenší mocnině pro NSD.", - [ - "Každé celé číslo větší než 1 má jediný rozklad na prvočísla.", - "72 = 2³ · 3².", - "V NSD se bere nižší exponent, v NSN vyšší.", - "Rozklad usnadní krácení zlomků i hledání společného jmenovatele.", - ]), - ], - [ - N("Jaký je největší společný dělitel čísel 24 a 36?", 12, - "Společní dělitelé jsou 1, 2, 3, 4, 6 a 12."), - N("Jaký je nejmenší společný násobek čísel 6 a 8?", 24, - "Násobky 6 jsou 6, 12, 18, 24, … a 24 je první z nich dělitelné osmi."), - N("Spočítejte 2³ · 3².", (2 ** 3) * (3 ** 2), - "8 · 9 = 72."), - N("Kolik kladných dělitelů má číslo 12?", 6, - "Jsou to 1, 2, 3, 4, 6 a 12."), - ], - ), - lesson( - "Mocniny a odmocniny", "Powers and roots", - "Mocniny se stejným základem a druhá odmocnina.", - "Powers with the same base and the square root.", - [ - S("1 / 3 • Mocnina", "Opakované násobení", - "Tip: aⁿ je a násobené sebou n-krát.", - [ - "2⁵ = 2 · 2 · 2 · 2 · 2 = 32.", - "10³ = 1000, tři nuly za jedničkou.", - "Každé číslo na první je ono samo a a⁰ = 1 pro a ≠ 0.", - "Záporný exponent znamená převrácenou hodnotu mocniny.", - ]), - S("2 / 3 • Pravidla", "Stejný základ", - "Tip: (aᵐ)ⁿ = aᵐ·ⁿ.", - [ - "aᵐ · aⁿ = aᵐ⁺ⁿ.", - "aᵐ : aⁿ = aᵐ⁻ⁿ pro a ≠ 0.", - "(a · b)ⁿ = aⁿ · bⁿ.", - "(2³)² = 2⁶ = 64.", - ]), - S("3 / 3 • Odmocnina", "Druhá odmocnina", - "Tip: √a je nezáporné číslo, jehož druhá mocnina je a.", - [ - "√81 = 9, protože 9² = 81.", - "√0 = 0 a √1 = 1.", - "Ze záporného čísla se v reálných číslech druhá odmocnina nedělá.", - "√(a²) = |a|, ne vždy a.", - ]), - ], - [ - N("Spočítejte 2⁵.", 2 ** 5, "Pět dvojkových činitelů je 32."), - N("Spočítejte 10³.", 10 ** 3, "10 · 10 · 10 = 1000."), - N("Spočítejte √81.", 9, "9 · 9 = 81."), - N("Spočítejte (2³)².", (2 ** 3) ** 2, "(8)² = 64, nebo 2⁶ = 64."), - ], - ), - lesson( - "Algebraické výrazy", "Algebraic expressions", - "Dosazení, druhá mocnina součtu a rozklad rozdílu čtverců.", - "Substitution, the square of a sum and a difference of squares.", - [ - S("1 / 3 • Dosazení", "Písmeno je číslo", - "Tip: nejdřív závorky, potom mocniny a násobení.", - [ - "Do výrazu se za proměnnou dosadí dané číslo.", - "2(x + 3) při x = 4 je 2 · 7 = 14.", - "3x − 2x + 5 se nejdřív sloučí na x + 5.", - "Při x = 2 je x + 5 = 7.", - ]), - S("2 / 3 • Vzorce", "Druhá mocnina dvojčlenu", - "Tip: (a + b)² není a² + b².", - [ - "(a + b)² = a² + 2ab + b².", - "(a − b)² = a² − 2ab + b².", - "a² − b² = (a − b)(a + b).", - "Pro a = 3 a b = 1 je (a + b)² = 16.", - ]), - S("3 / 3 • Zkrácení", "Rozdíl čtverců", - "Tip: krátit lze jen pro x, která nejsou kořenem jmenovatele.", - [ - "x² − 9 = (x − 3)(x + 3).", - "(x² − 9)/(x − 3) = x + 3 pro x ≠ 3.", - "Při x = 5 je hodnota 8.", - "Dosazení x = 3 by dělilo nulou, výraz tam není definován.", - ]), - ], - [ - N("Do výrazu 2(x + 3) dosažte x = 4.", 2 * (4 + 3), - "2 · (4 + 3) = 14."), - N("Do výrazu (a + b)² dosažte a = 3 a b = 1.", (3 + 1) ** 2, - "4² = 16. Rozepsáno 9 + 6 + 1 = 16."), - N("Do výrazu 3x − 2x + 5 dosažte x = 2.", 3 * 2 - 2 * 2 + 5, - "Výraz je x + 5, při x = 2 je 7."), - N("Do výrazu (x² − 9)/(x − 3) dosažte x = 5.", - Fraction(5 ** 2 - 9, 5 - 3), - "Pro x ≠ 3 je výraz roven x + 3, tedy 8."), - ], - ), - lesson( - "Lineární rovnice s úpravami", "Linear equations", - "Rovnice s koeficientem, závorkou a zlomkem.", - "Equations with a coefficient, a bracket and a fraction.", - [ - S("1 / 3 • Převod", "Neznámé na jednu stranu", - "Tip: člen s x se převádí s opačným znaménkem.", - [ - "2x + 1 = 9 se odečtením jedné změní na 2x = 8.", - "x = 4.", - "Členy s x patří obvykle vlevo, čísla vpravo.", - "Po každé úpravě zůstává rovnost zachovaná.", - ]), - S("2 / 3 • Obě strany", "Stejný člen vlevo i vpravo", - "Tip: 5x − 3 = 2x + 9 se zbaví 2x odečtením.", - [ - "5x − 2x = 9 + 3.", - "3x = 12 a x = 4.", - "Zkouška: levá strana 5 · 4 − 3 = 17, pravá 8 + 9 = 17.", - "Když koeficient u x vyjde 0, rovnice buď nemá řešení, nebo jich má nekonečně mnoho.", - ]), - S("3 / 3 • Závorka a zlomek", "Nejdřív roznásobit", - "Tip: x/2 + 1 = 5 se nejdřív zbaví jedničky.", - [ - "x/2 + 1 = 5 dá x/2 = 4, tedy x = 8.", - "3(x − 2) = 12 se vydělí třemi: x − 2 = 4.", - "Nebo se závorka roznásobí: 3x − 6 = 12.", - "Obě cesty dají x = 6.", - ]), - ], - [ - N("Vyřešte 2x + 1 = 9. Napište x.", Fraction(9 - 1, 2), - "2x = 8, takže x = 4."), - N("Vyřešte 5x − 3 = 2x + 9. Napište x.", Fraction(9 + 3, 5 - 2), - "3x = 12, takže x = 4."), - N("Vyřešte x/2 + 1 = 5. Napište x.", (5 - 1) * 2, - "x/2 = 4, takže x = 8."), - N("Vyřešte 3(x − 2) = 12. Napište x.", 12 / 3 + 2, - "x − 2 = 4, takže x = 6."), - ], - ), - lesson( - "Slovní úlohy", "Word problems", - "Dráha, společná práce, směs a sleva.", - "Distance, joint work, a mixture and a discount.", - [ - S("1 / 3 • Dráha", "Rychlost krát čas", - "Tip: jednotky času a rychlosti musí patřit k sobě.", - [ - "Při stálé rychlosti je dráha s = v · t.", - "60 km/h po dobu 2,5 h urazí 150 km.", - "2,5 h je dvě a půl hodiny, ne dvě hodiny a padesát minut.", - "Z dráhy a času se rychlost dopočítá jako s/t.", - ]), - S("2 / 3 • Práce a směs", "Sčítají se výkony, ne časy", - "Tip: kdo práci udělá za 3 hodiny, udělá za hodinu třetinu.", - [ - "První pracovník udělá za hodinu 1/6 práce, druhý 1/3.", - "Společně udělají 1/6 + 2/6 = 1/2 práce za hodinu, tedy celou za 2 hodiny.", - "U směsi se sčítá množství čisté látky.", - "2 kg dvacetiprocentní a 3 kg desetiprocentní směsi obsahují 0,4 + 0,3 = 0,7 kg, tedy 14 %.", - ]), - S("3 / 3 • Sleva", "Nová cena je část základu", - "Tip: po slevě 20 % zbývá 80 % původní ceny.", - [ - "Když je nová cena 160 a sleva byla 20 %, je 160 rovno 80 % původní ceny.", - "Původní cena je 160 / 0,8 = 200.", - "Sleva v korunách je pak 40.", - "Nepleťte si slevu 20 % s tím, že se k nové ceně přičte 20 %.", - ]), - ], - [ - N("Auto jede 2,5 hodiny rychlostí 60 km/h. Kolik kilometrů ujede?", - Fraction("2.5") * 60, - "s = v · t = 60 · 2,5 = 150."), - N("První pracovník práci udělá za 6 hodin, druhý za 3 hodiny. Za kolik hodin ji udělají společně?", - 1 / (Fraction(1, 6) + Fraction(1, 3)), - "Za hodinu spolu udělají 1/2 práce, celou tedy za 2 hodiny."), - N("Smíchají se 2 kg směsi s 20 % látky a 3 kg směsi s 10 % látky. Kolik procent látky má směs? Napište jen číslo.", - (2 * 20 + 3 * 10) / 5, - "Čisté látky je 0,7 kg z 5 kg, tedy 14 %."), - N("Po slevě 20 % stojí zboží 160. Jaká byla původní cena?", - 160 / Fraction(80, 100), - "160 je 80 % původní ceny, základ je 200."), - ], - ), - lesson( - "Planimetrie", "Plane figures", - "Úhly trojúhelníku, vnější úhel a pravidelný mnohoúhelník.", - "Angles of a triangle, the exterior angle and a regular polygon.", - [ - S("1 / 3 • Trojúhelník", "Součet 180°", - "Tip: rovnoramenný trojúhelník má dvě ramena a dva úhly u základny shodné.", - [ - "Součet vnitřních úhlů každého trojúhelníku je 180°.", - "V rovnoramenném trojúhelníku jsou úhly při základně shodné.", - "Když jsou úhly při základně 70°, je úhel proti základně 40°.", - "Rovnostranný trojúhelník má všechny strany shodné a každý úhel 60°.", - ]), - S("2 / 3 • Vnější úhel", "Součet dvou vzdálených vnitřních", - "Tip: vnější úhel a sousední vnitřní úhel dávají 180°.", - [ - "Vnější úhel vznikne prodloužením jedné strany.", - "Je roven součtu dvou vnitřních úhlů, které s ním nesousedí.", - "Vnitřní úhly 40° a 60° dávají vnější úhel 100° u zbývajícího vrcholu.", - "Součet vnějšího úhlu a přilehlého vnitřního je 180°.", - ]), - S("3 / 3 • Mnohoúhelník", "Pravidelný šestiúhelník", - "Tip: součet vnitřních úhlů n-úhelníku je (n − 2) · 180°.", - [ - "Trojúhelník má součet 180°, čtyřúhelník 360°.", - "Obecný vzorec je (n − 2) · 180°.", - "Pravidelný mnohoúhelník má všechny strany i úhly shodné.", - "Pravidelný šestiúhelník má vnitřní úhel 720° / 6 = 120°.", - ]), - ], - [ - N("Vnější úhel trojúhelníku je součet vnitřních úhlů 40° a 60°. Jak je velký ve stupních?", - 40 + 60, - "Vnější úhel se rovná součtu dvou nesousedních vnitřních úhlů: 100°."), - N("Rovnoramenný trojúhelník má úhly při základně 70°. Jak velký je úhel proti základně?", - 180 - 70 - 70, - "180° − 140° = 40°."), - N("Rovnostranný trojúhelník má stranu 6. Jaký je jeho obvod?", - 3 * 6, - "Tři shodné strany: 3 · 6 = 18."), - N("Jak velký je jeden vnitřní úhel pravidelného šestiúhelníku ve stupních?", - (6 - 2) * 180 / 6, - "Součet je (6 − 2) · 180° = 720° a jeden úhel je 120°."), - ], - ), - lesson( - "Obvody a obsahy", "Perimeter and area", - "Kružnice, lichoběžník a Pythagorova věta.", - "The circle, the trapezium and Pythagoras.", - [ - S("1 / 3 • Kružnice", "Obvod a obsah", - "Tip: u výsledku s π nechte π ve výrazu a pište ho jako pi.", - [ - "Kružnice s poloměrem r má obvod 2πr.", - "Obsah kruhu je πr².", - "Pro r = 7 je obvod 14π.", - "Pro r = 3 je obsah 9π.", - ]), - S("2 / 3 • Lichoběžník", "Dvě základny a výška", - "Tip: obsah je průměr základen krát výška.", - [ - "Lichoběžník má právě jednu dvojici rovnoběžných stran, základny a a c.", - "Obsah je (a + c) · v / 2.", - "Základny 4 a 6 a výška 3 dávají obsah 15.", - "Výška je kolmá vzdálenost základen.", - ]), - S("3 / 3 • Pythagoras", "Pravoúhlý trojúhelník", - "Tip: přepona je nejdelší strana a leží proti pravému úhlu.", - [ - "V pravoúhlém trojúhelníku je a² + b² = c².", - "c je přepona, a a b jsou odvěsny.", - "Trojúhelník 5, 12, 13 je pravoúhlý, protože 25 + 144 = 169.", - "Přepona je 13.", - ]), - ], - [ - PI("Jaký je obvod kružnice s poloměrem 7? Nechte výsledek v násobcích π.", - 2 * 7, "Obvod je 2πr = 14π."), - PI("Jaký je obsah kruhu s poloměrem 3? Nechte výsledek v násobcích π.", - 3 ** 2, "Obsah je πr² = 9π."), - N("Lichoběžník má základny 4 a 6 a výšku 3. Jaký je jeho obsah?", - Fraction(4 + 6, 2) * 3, - "(4 + 6) · 3 / 2 = 15."), - N("Pravoúhlý trojúhelník má odvěsny 5 a 12. Jak dlouhá je přepona?", - 13, "5² + 12² = 25 + 144 = 169 = 13²."), - ], - ), - lesson( - "Konstrukce trojúhelníku", "Constructing a triangle", - "Vzdálenost bodů a trojúhelník daný třemi stranami.", - "The distance between points and a triangle given by three sides.", - [ - S("1 / 3 • Body", "Vzdálenost na mřížce", - "Tip: u svislé nebo vodorovné úsečky stačí rozdíl souřadnic.", - [ - "Bod v rovině má souřadnice [x; y].", - "Vzdálenost [x₁; y₁] a [x₂; y₂] je √((x₂ − x₁)² + (y₂ − y₁)²).", - "A = [1; 1] a B = [5; 1] mají vzdálenost 4.", - "Osa y na naší mřížce míří nahoru.", - ]), - S("2 / 3 • SSS", "Trojúhelník ze tří stran", - "Tip: třetí vrchol je průsečík dvou kružnic.", - [ - "Konstrukce SSS použije tři strany.", - "Z bodu A se rýsuje kružnice o poloměru |AC|, z bodu B o poloměru |BC|.", - "Kružnice se protnou ve dvou bodech, pokud trojúhelník existuje.", - "Trojúhelníková nerovnost: součet dvou stran je větší než třetí.", - ]), - S("3 / 3 • Příklad", "Strany 4, 3 a 5", - "Tip: 3² + 4² = 5², pravý úhel je u bodu A.", - [ - "A = [1; 1], B = [5; 1], takže |AB| = 4.", - "Hledáme C tak, aby |AC| = 3 a |BC| = 5.", - "Na mřížce od 0 do 10 a od 0 do 8 leží jen C = [1; 4].", - "Druhý průsečík [1; −2] je pod mřížkou.", - ]), - ], - [ - N("Jaká je vzdálenost bodů A = [1; 1] a B = [5; 1]?", - 4, "Body mají stejné y, vzdálenost je 5 − 1 = 4."), - N("Jaký je obsah pravoúhlého trojúhelníku s odvěsnami 3 a 4?", - Fraction(3 * 4, 2), - "Obsah je (3 · 4) / 2 = 6."), - N("Jaký je obvod trojúhelníku se stranami 3, 4 a 5?", - 3 + 4 + 5, "3 + 4 + 5 = 12."), - DRAW("A = [1; 1] a B = [5; 1] jsou dané. Zakreslete C, pro které je |AC| = 3 a |BC| = 5.", - "points:1,4;fix:1,1;fix:5,1", - "Kružnice se na mřížce protnou v [1; 4]. Bod [1; −2] už na ní není.", - "1,4"), - ], - ), - ] - - -def year2(): - return [ - lesson( - "Lineární funkce", "Linear functions", - "Předpis, průsečík s osou y, směrnice a nulový bod.", - "The formula, the y-intercept, the slope and a root.", - [ - S("1 / 3 • Předpis", "y = ax + b", - "Tip: a je směrnice, b je úsek na ose y.", - [ - "Lineární funkce má předpis f(x) = ax + b.", - "Grafem je přímka.", - "b je hodnota f(0), tedy průsečík s osou y.", - "Pro f(x) = 2x − 3 je průsečík s osou y číslo −3.", - ]), - S("2 / 3 • Směrnice", "O kolik y vzroste", - "Tip: směrnice je podíl změny y a změny x.", - [ - "Mezi body [x₁; y₁] a [x₂; y₂] je a = (y₂ − y₁)/(x₂ − x₁).", - "Body [1; 2] a [3; 8] dávají směrnici (8 − 2)/(3 − 1) = 3.", - "Kladná směrnice znamená růst, záporná pokles.", - "Nulová směrnice je vodorovná přímka.", - ]), - S("3 / 3 • Hodnota a kořen", "Dosazení a rovnice", - "Tip: nulový bod je x, pro které je f(x) = 0.", - [ - "f(4) u funkce 2x − 3 je 8 − 3 = 5.", - "Rovnice 2x − 6 = 0 má řešení x = 3.", - "To je průsečík přímky y = 2x − 6 s osou x.", - "Lineární funkce s a ≠ 0 má právě jeden nulový bod.", - ]), - ], - [ - N("Funkce f(x) = 2x − 3. Kolik je f(4)?", 2 * 4 - 3, - "2 · 4 − 3 = 5."), - N("Jaký je průsečík funkce f(x) = 2x − 3 s osou y?", -3, - "f(0) = −3."), - N("Jaká je směrnice přímky body [1; 2] a [3; 8]?", - Fraction(8 - 2, 3 - 1), - "(8 − 2)/(3 − 1) = 3."), - N("Vyřešte 2x − 6 = 0. Napište x.", Fraction(6, 2), - "2x = 6, takže x = 3."), - ], - ), - lesson( - "Soustavy rovnic", "Systems of equations", - "Dvě lineární rovnice o dvou neznámých.", - "Two linear equations in two unknowns.", - [ - S("1 / 3 • Dvojice", "Jedno x a jedno y", - "Tip: výsledek pište x;y, nejdřív x.", - [ - "Soustava dvou lineárních rovnic hledá dvojici [x; y], která vyhovuje oběma.", - "Řešením je průsečík dvou přímek.", - "Sčítací metoda sečte rovnice tak, aby jedna neznámá zmizela.", - "Dosazovací metoda vyjádří jednu neznámou a dosadí ji do druhé rovnice.", - ]), - S("2 / 3 • Sčítání", "Opačné koeficienty", - "Tip: x + y = 10 a x − y = 2 se sčítají na 2x = 12.", - [ - "Součet dá 2x = 12, tedy x = 6.", - "Z x + y = 10 je y = 4.", - "Zkouška ve druhé rovnici: 6 − 4 = 2.", - "Odečtení rovnic se použije, když má neznámá v obou stejný koeficient.", - ]), - S("3 / 3 • Odečtení", "Stejný koeficient", - "Tip: rovnice lze před odečtením násobit.", - [ - "2x + y = 8 a x + y = 5 se odečtou na x = 3.", - "Pak y = 2.", - "3x + y = 10 a x + y = 6 dají 2x = 4, tedy x = 2 a y = 4.", - "x + y = 7 a x − y = 1 dají x = 4 a y = 3.", - ]), - ], - [ - PAIR("Vyřešte soustavu x + y = 10 a x − y = 2. Napište x a y oddělené středníkem.", - 6, 4, "Sečtení dá 2x = 12, x = 6 a y = 4."), - PAIR("Vyřešte soustavu 2x + y = 8 a x + y = 5. Napište x a y oddělené středníkem.", - 3, 2, "Odečtení dá x = 3 a y = 2."), - PAIR("Vyřešte soustavu x + y = 7 a x − y = 1. Napište x a y oddělené středníkem.", - 4, 3, "Sečtení dá 2x = 8, x = 4 a y = 3."), - PAIR("Vyřešte soustavu 3x + y = 10 a x + y = 6. Napište x a y oddělené středníkem.", - 2, 4, "Odečtení dá 2x = 4, x = 2 a y = 4."), - ], - ), - lesson( - "Kvadratické rovnice", "Quadratic equations", - "Rozklad, diskriminant a dvojnásobný kořen.", - "Factoring, the discriminant and a double root.", - [ - S("1 / 3 • Tvar", "ax² + bx + c = 0", - "Tip: kořeny pište oddělené středníkem, pořadí nehraje roli.", - [ - "Kvadratická rovnice má a ≠ 0.", - "Kořeny rovnice x² − 5x + 6 = 0 jsou 2 a 3, protože (x − 2)(x − 3) = 0.", - "x² − 4 = 0 má kořeny −2 a 2.", - "Součin je nula, právě když je nula aspoň jeden činitel.", - ]), - S("2 / 3 • Diskriminant", "D = b² − 4ac", - "Tip: D > 0 znamená dva různé reálné kořeny.", - [ - "Pro ax² + bx + c = 0 je D = b² − 4ac.", - "U x² − 2x − 3 je a = 1, b = −2, c = −3 a D = 4 + 12 = 16.", - "D = 0 znamená jeden dvojnásobný kořen.", - "D < 0 znamená, že v reálných číslech řešení není.", - ]), - S("3 / 3 • Vzorec", "Kořen je (−b ± √D) / (2a)", - "Tip: dvojnásobný kořen x² + 6x + 9 = 0 je −3.", - [ - "x = (−b ± √D) / (2a).", - "x² + 6x + 9 = (x + 3)², takže kořen −3 je dvojnásobný.", - "U dvojnásobného kořene stačí napsat číslo jednou.", - "Zkouška dosadí kořen zpět do rovnice.", - ]), - ], - [ - SET("Najděte kořeny rovnice x² − 5x + 6 = 0. Oddělte je středníkem.", - [2, 3], "(x − 2)(x − 3) = 0."), - SET("Najděte kořeny rovnice x² − 4 = 0. Oddělte je středníkem.", - [-2, 2], "x² = 4, takže x = −2 nebo x = 2."), - N("Jaký je diskriminant rovnice x² − 2x − 3 = 0?", - (-2) ** 2 - 4 * 1 * (-3), - "D = (−2)² − 4 · 1 · (−3) = 4 + 12 = 16."), - N("Jaký je dvojnásobný kořen rovnice x² + 6x + 9 = 0?", - -3, "(x + 3)² = 0, kořen je −3."), - ], - ), - lesson( - "Lomené výrazy", "Rational expressions", - "Krácení, definiční obor a násobení zlomků s proměnnou.", - "Cancelling, the domain and multiplying algebraic fractions.", - [ - S("1 / 3 • Obor", "Jmenovatel nesmí být nula", - "Tip: podmínku pište dřív, než krátíte.", - [ - "Lomený výraz je podíl dvou mnohočlenů.", - "Není definován tam, kde je jmenovatel nula.", - "(x + 2)/(x − 2) nemá smysl pro x = 2.", - "Po krácení se vyloučené hodnoty do oboru nevracejí.", - ]), - S("2 / 3 • Krácení", "Rozdíl čtverců", - "Tip: x² − 1 = (x − 1)(x + 1).", - [ - "(x² − 1)/(x − 1) = x + 1 pro x ≠ 1.", - "Při x = 4 je hodnota 5.", - "(x² − 4)/(x + 2) = x − 2 pro x ≠ −2.", - "Při x = 5 je hodnota 3.", - ]), - S("3 / 3 • Násobení", "Čitatel s čitatelem", - "Tip: x ve jmenovateli se zkrátí jen pro x ≠ 0.", - [ - "Zlomky se násobí stejně jako číselné.", - "(2x/4) · (6/x) = 12x/(4x) = 3 pro x ≠ 0.", - "6x/(3x) = 2 pro x ≠ 0.", - "Než se zkrátí písmeno, ověří se, že není nula.", - ]), - ], - [ - N("Do výrazu (x² − 1)/(x − 1) dosažte x = 4.", - Fraction(4 ** 2 - 1, 4 - 1), - "Pro x ≠ 1 je výraz x + 1, tedy 5."), - N("Pro které x nemá výraz (x + 2)/(x − 2) smysl?", - 2, "Jmenovatel x − 2 je nula právě při x = 2."), - N("Upravte (2x/4) · (6/x) pro x ≠ 0.", - 3, "12x/(4x) = 3."), - N("Do výrazu (x² − 4)/(x + 2) dosažte x = 5.", - Fraction(25 - 4, 5 + 2), - "Pro x ≠ −2 je výraz x − 2, tedy 3."), - ], - ), - lesson( - "Mocniny s racionálním exponentem", "Rational exponents", - "Odmocniny, součin mocnin a záporný exponent.", - "Roots, a product of powers and a negative exponent.", - [ - S("1 / 3 • Odmocnina jako exponent", "a^(1/n)", - "Tip: a^(1/2) je druhá odmocnina z a.", - [ - "Pro a > 0 je a^(1/n) n-tá odmocnina z a.", - "16^(1/2) = 4.", - "a^(m/n) je n-tá odmocnina z aᵐ, nebo m-tá mocnina odmocniny.", - "8^(2/3) = (8^(1/3))² = 2² = 4.", - ]), - S("2 / 3 • Stejný základ", "Exponenty se sčítají", - "Tip: 3² · 3³ = 3⁵.", - [ - "aᵐ · aⁿ = aᵐ⁺ⁿ.", - "3² · 3³ = 3⁵ = 243.", - "(aᵐ)ⁿ = aᵐ·ⁿ.", - "Základ musí být při sčítání exponentů stejný.", - ]), - S("3 / 3 • Záporný exponent", "Převrácená hodnota", - "Tip: a⁻ⁿ = 1/aⁿ pro a ≠ 0.", - [ - "10⁻² = 1/100.", - "10⁻¹ = 0,1 a 10⁰ = 1.", - "Záporný exponent nepřevrací znaménko základu, ale celou mocninu.", - "(−2)⁻² = 1/4, protože (−2)² = 4.", - ]), - ], - [ - N("Spočítejte 16^(1/2).", 4, "Druhá odmocnina z 16 je 4."), - N("Spočítejte 8^(2/3).", 4, "Třetí odmocnina z 8 je 2 a 2² = 4."), - N("Spočítejte 3² · 3³.", 3 ** 5, "3⁵ = 243."), - N("Spočítejte 10⁻².", Fraction(1, 100), "10⁻² = 1/10² = 1/100."), - ], - ), - lesson( - "Goniometrie pravoúhlého trojúhelníku", "Right-triangle trigonometry", - "Sinus, kosinus a tangens ostrého úhlu.", - "Sine, cosine and tangent of an acute angle.", - [ - S("1 / 3 • Poměry", "Odvěsny a přepona", - "Tip: sinus je protilehlá odvěsna ku přeponě.", - [ - "V pravoúhlém trojúhelníku je sin α = protilehlá / přepona.", - "cos α = přilehlá / přepona.", - "tan α = protilehlá / přilehlá.", - "Přepona je strana proti pravému úhlu.", - ]), - S("2 / 3 • Tabulkové úhly", "30°, 45° a 60°", - "Tip: sinus 30° je 1/2.", - [ - "sin 30° = 1/2 a cos 60° = 1/2.", - "sin 60° = cos 30° = √3/2.", - "sin 45° = cos 45° = √2/2.", - "tan 45° = 1.", - ]), - S("3 / 3 • Dopočet strany", "Přepona a úhel", - "Tip: proti úhlu 30° je polovina přepony.", - [ - "Známe-li přeponu a úhel, protilehlá odvěsna je přepona · sin α.", - "Proti 30° při přeponě 10 je odvěsna 5.", - "Přilehlá odvěsna by byla 10 · cos 30°.", - "Tangens se hodí, když jsou známé dvě odvěsny a ne přepona.", - ]), - ], - [ - N("Kolik je sin 30°?", Fraction(1, 2), - "Sinus 30° je 1/2."), - N("Kolik je cos 60°?", Fraction(1, 2), - "Kosinus 60° je 1/2."), - N("Kolik je tan 45°?", 1, - "Protilehlá a přilehlá odvěsna jsou u 45° stejně dlouhé."), - N("Přepona pravoúhlého trojúhelníku je 10 a jeden úhel je 30°. Jak dlouhá je odvěsna proti tomuto úhlu?", - 10 * Fraction(1, 2), - "10 · sin 30° = 10 · 1/2 = 5."), - ], - ), - lesson( - "Pythagorova a Eukleidovy věty", "Pythagoras and Euclid", - "Přepona, obsah čtverce nad ní a úseky přepony.", - "The hypotenuse, the square on it, and the projections on it.", - [ - S("1 / 3 • Pythagoras", "a² + b² = c²", - "Tip: 8² + 15² = 64 + 225 = 289 = 17².", - [ - "V pravoúhlém trojúhelníku se součet čtverců nad odvěsnami rovná čtverci nad přeponou.", - "Trojúhelník 8, 15, 17 je pravoúhlý a přepona je 17.", - "Čtverec nad přeponou trojúhelníku 3, 4, 5 má obsah 25.", - "Věta platí jen v pravoúhlém trojúhelníku.", - ]), - S("2 / 3 • Eukleides", "Úsek přepony", - "Tip: a² = c · a_c, kde a_c je úsek přepony přilehlý k odvěsně a.", - [ - "Odvěsna je geometrický průměr přepony a svého úseku.", - "a² = c · a_c a b² = c · b_c.", - "Úseky a_c a b_c dají dohromady přeponu c.", - "U odvěsen 6 a 8 je přepona 10 a úsek u odvěsny 6 je 36/10 = 18/5.", - ]), - S("3 / 3 • Výška", "v² = a_c · b_c", - "Tip: také platí a · b = c · v.", - [ - "Výška k přeponě je geometrický průměr obou úseků.", - "Z a · b = c · v plyne v = ab/c.", - "Pro odvěsny 6 a 8 a přeponu 10 je v = 48/10 = 24/5.", - "Obsah trojúhelníku je pak (c · v) / 2, stejně jako (a · b) / 2.", - ]), - ], - [ - N("Pravoúhlý trojúhelník má odvěsny 8 a 15. Jak dlouhá je přepona?", - 17, "64 + 225 = 289 = 17²."), - N("Jaký obsah má čtverec sestrojený nad přeponou pravoúhlého trojúhelníku se stranami 3, 4 a 5?", - 25, "Přepona je 5 a 5² = 25."), - N("Odvěsny jsou 6 a 8, přepona je 10. Jak dlouhý je úsek přepony přilehlý k odvěsně 6?", - Fraction(36, 10), - "a² = c · a_c, takže a_c = 36/10 = 18/5."), - N("Odvěsny jsou 6 a 8, přepona je 10. Jak dlouhá je výška k přeponě?", - Fraction(6 * 8, 10), - "v = ab/c = 48/10 = 24/5."), - ], - ), - lesson( - "Kružnice a Thaletova věta", "Circles and Thales", - "Obvodový a středový úhel, délka oblouku a pravý úhel nad průměrem.", - "An inscribed and a central angle, arc length, and the right angle in a semicircle.", - [ - S("1 / 3 • Úhly", "Obvodový je polovina středového", - "Tip: oba úhly musí být nad stejným obloukem.", - [ - "Středový úhel má vrchol ve středu kružnice.", - "Obvodový úhel má vrchol na kružnici.", - "Nad stejným obloukem je obvodový úhel polovinou středového.", - "Středový úhel 80° patří k obvodovému úhlu 40°.", - ]), - S("2 / 3 • Oblouk", "Část obvodu", - "Tip: délka oblouku je (α/360°) · 2πr.", - [ - "Celý obvod je 2πr.", - "Oblouk 60° je šestina obvodu.", - "Při r = 6 je jeho délka 2π.", - "Výsledek nechte v násobcích π.", - ]), - S("3 / 3 • Thales", "Pravý úhel nad průměrem", - "Tip: vrchol pravého úhlu leží na kružnici s průměrem AB.", - [ - "Thaletova věta: úhel nad průměrem je pravý.", - "Je-li AB průměr, je úhel ACB pravý pro každé C na kružnici různé od A a B.", - "Na mřížce má průměr od [2; 4] do [8; 4] střed [5; 4] a poloměr 3.", - "Vyhovují body [5; 7] a [5; 1].", - ]), - ], - [ - N("Středový úhel je 80°. Jak velký je obvodový úhel nad stejným obloukem ve stupních?", - 40, "Obvodový úhel je polovina středového."), - PI("Kružnice má poloměr 6. Jak dlouhý je oblouk 60°? Nechte π ve výsledku.", - 2, "(60/360) · 2π · 6 = 2π."), - N("Obvodový úhel je 35°. Jak velký je středový úhel nad stejným obloukem ve stupních?", - 70, "Středový úhel je dvojnásobek obvodového."), - DRAW("AB je průměr od [2; 4] do [8; 4]. Zakreslete bod C na kružnici, ve kterém je úhel ACB pravý.", - "right:2,4;8,4", - "Thaletova kružnice má střed [5; 4] a poloměr 3. Na mřížce vyhovuje [5; 7] nebo [5; 1].", - "5,7"), - ], - ), - ] - - -def year3(): - return [ - lesson( - "Kvadratická funkce", "The quadratic function", - "Vrchol, kořeny a hodnota paraboly.", - "The vertex, the roots and a value of a parabola.", - [ - S("1 / 3 • Parabola", "f(x) = ax² + bx + c", - "Tip: pro a > 0 má parabola minimum, pro a < 0 maximum.", - [ - "Grafem kvadratické funkce je parabola.", - "Průsečík s osou y je bod [0; c].", - "U f(x) = x² − 4x + 3 je f(0) = 3.", - "Osa paraboly je svislá.", - ]), - S("2 / 3 • Vrchol", "x = −b/(2a)", - "Tip: souřadnice vrcholu pište x;y.", - [ - "x-ová souřadnice vrcholu je −b/(2a).", - "U x² − 4x + 3 je to −(−4)/2 = 2.", - "f(2) = 4 − 8 + 3 = −1.", - "Vrchol je tedy [2; −1].", - ]), - S("3 / 3 • Kořeny", "Průsečíky s osou x", - "Tip: kořeny jsou řešení f(x) = 0.", - [ - "x² − 4x + 3 = (x − 1)(x − 3).", - "Kořeny jsou 1 a 3.", - "Leží symetricky kolem osy paraboly.", - "f(4) = 16 − 16 + 3 = 3, stejně jako f(0).", - ]), - ], - [ - PAIR("Najděte vrchol funkce f(x) = x² − 4x + 3. Napište x a y oddělené středníkem.", - 2, -1, "x = 4/2 = 2 a f(2) = −1."), - SET("Najděte kořeny funkce f(x) = x² − 4x + 3. Oddělte je středníkem.", - [1, 3], "(x − 1)(x − 3) = 0."), - N("Kolik je f(0) u funkce f(x) = x² − 4x + 3?", 3, - "f(0) = 3, to je absolutní člen."), - N("Kolik je f(4) u funkce f(x) = x² − 4x + 3?", 16 - 16 + 3, - "16 − 16 + 3 = 3."), - ], - ), - lesson( - "Exponenciální funkce a logaritmus", "Exponentials and logarithms", - "Mocnina se základem a logaritmus jako její opak.", - "A power and the logarithm as its inverse.", - [ - S("1 / 3 • Definice", "Logaritmus je exponent", - "Tip: log_b(x) = y právě tehdy, když bʸ = x.", - [ - "Základ logaritmu je kladný a různý od 1.", - "Argument logaritmu je kladný.", - "log₁₀(1000) = 3, protože 10³ = 1000.", - "log₂(32) = 5, protože 2⁵ = 32.", - ]), - S("2 / 3 • Rovnice", "Stejný základ", - "Tip: 2ˣ = 16 se přepíše jako 2ˣ = 2⁴.", - [ - "Exponentialní rovnice se stejným základem porovná exponenty.", - "2ˣ = 16 má řešení x = 4.", - "log₃(81) = 4, protože 3⁴ = 81.", - "log_b(b) = 1 a log_b(1) = 0.", - ]), - S("3 / 3 • Pravidla", "Součin a podíl", - "Tip: logaritmus součinu je součet logaritmů.", - [ - "log_b(xy) = log_b(x) + log_b(y).", - "log_b(x/y) = log_b(x) − log_b(y).", - "log_b(xⁿ) = n · log_b(x).", - "Těmito pravidly se argument zjednodušuje, ne základ.", - ]), - ], - [ - N("Spočítejte logaritmus o základu 10 z 1000.", 3, - "10³ = 1000, takže logaritmus je 3."), - N("Spočítejte logaritmus o základu 2 z 32.", 5, - "2⁵ = 32."), - N("Vyřešte 2ˣ = 16. Napište x.", 4, - "16 = 2⁴, takže x = 4."), - N("Spočítejte logaritmus o základu 3 z 81.", 4, - "3⁴ = 81."), - ], - ), - lesson( - "Goniometrické funkce", "Trigonometric functions", - "Sinus a kosinus na jednotkové kružnici.", - "Sine and cosine on the unit circle.", - [ - S("1 / 3 • Jednotková kružnice", "Úhel od kladné poloosy x", - "Tip: sinus je y-ová souřadnice, kosinus x-ová.", - [ - "Bod na jednotkové kružnici pod úhlem α má souřadnice [cos α; sin α].", - "cos 0° = 1 a sin 0° = 0.", - "sin 90° = 1 a cos 90° = 0.", - "cos 180° = −1 a sin 180° = 0.", - ]), - S("2 / 3 • 45°", "Polovina pravého úhlu", - "Tip: sin 45° = cos 45° = √2/2.", - [ - "Úhel 45° půlí čtvrtkružnici.", - "Souřadnice bodu splňují x = y a x² + y² = 1.", - "Kladné řešení je √2/2.", - "Odpověď lze psát jako sqrt(2)/2 nebo 1/sqrt(2).", - ]), - S("3 / 3 • Znaménka", "Čtyři kvadranty", - "Tip: v prvním kvadrantu jsou sinus i kosinus kladné.", - [ - "Ve druhém kvadrantu je sinus kladný a kosinus záporný.", - "Ve třetím jsou oba záporné.", - "Ve čtvrtém je kosinus kladný a sinus záporný.", - "Tangens je sinus dělený kosinem a není definován při cos α = 0.", - ]), - ], - [ - N("Kolik je sin 90°?", 1, "Bod [0; 1] má y-ovou souřadnici 1."), - N("Kolik je cos 180°?", -1, "Bod [−1; 0] má x-ovou souřadnici −1."), - SQRT("Kolik je sin 45°? Můžete psát sqrt(2)/2.", - "num:sqrt(2)/2", - "sin 45° = √2/2. Stejnou hodnotu má 1/√2."), - N("Kolik je cos 0°?", 1, "Úhel 0° je bod [1; 0]."), - ], - ), - lesson( - "Sinová a kosinová věta", "The sine and cosine rules", - "Obecný trojúhelník, poloměr kružnice a obsah.", - "A general triangle, the circumradius and the area.", - [ - S("1 / 3 • Sinová věta", "a/sin α = 2R", - "Tip: poměr strany a sinu protilehlého úhlu je pro všechny strany stejný.", - [ - "a/sin α = b/sin β = c/sin γ = 2R.", - "R je poloměr kružnice opsané.", - "Když a = 10 a α = 30°, je 10 / (1/2) = 20 = 2R.", - "Poloměr R je 10.", - ]), - S("2 / 3 • Kosinová věta", "c² = a² + b² − 2ab cos γ", - "Tip: pro pravý úhel je cos 90° = 0 a věta přejde v Pythagora.", - [ - "Kosinová věta dopočítá stranu proti známému úhlu.", - "Jsou-li dvě strany 2 a sevřený úhel 60°, je třetí strana také 2.", - "a² = 4 + 4 − 2 · 2 · 2 · cos 60° = 8 − 8 · 1/2 = 4.", - "Rovnostranný trojúhelník má všechny úhly 60°.", - ]), - S("3 / 3 • Obsah", "Dvě strany a sevřený úhel", - "Tip: S = (1/2) · b · c · sin α.", - [ - "Obsah je polovina součinu dvou stran a sinu sevřeného úhlu.", - "(1/2) · 4 · 6 · sin 30° = 12 · 1/2 = 6.", - "Sinová věta také dopočítá další stranu: b = a · sin β / sin α.", - "Pro a = 8, α = 30° a β = 45° je b = 8√2.", - ]), - ], - [ - N("Strana a = 10 leží proti úhlu 30°. Jaký je poloměr kružnice opsané?", - 10, "a/sin 30° = 20 = 2R, takže R = 10."), - N("Dvě strany trojúhelníku mají délku 2 a svírají úhel 60°. Jak dlouhá je třetí strana?", - 2, "a² = 4 + 4 − 8 · 1/2 = 4, takže a = 2."), - N("Dvě strany mají délky 4 a 6 a svírají úhel 30°. Jaký je obsah trojúhelníku?", - Fraction(1, 2) * 4 * 6 * Fraction(1, 2), - "(1/2) · 4 · 6 · 1/2 = 6."), - SQRT("Strana a = 8 je proti 30° a úhel β je 45°. Jak dlouhá je strana b? Sin 45° je √2/2.", - "num:8*sqrt(2)", - "b = 8 · sin 45° / sin 30° = 8 · (√2/2) / (1/2) = 8√2."), - ], - ), - lesson( - "Posloupnosti a řady", "Sequences and series", - "Aritmetická a geometrická posloupnost a nekonečná řada.", - "An arithmetic and a geometric sequence, and an infinite series.", - [ - S("1 / 3 • Aritmetická", "Stálý rozdíl", - "Tip: aₙ = a₁ + (n − 1)d.", - [ - "Aritmetická posloupnost přičítá stále stejný rozdíl d.", - "Pro a₁ = 3 a d = 2 je a₅ = 3 + 4 · 2 = 11.", - "Součet prvních n členů je sₙ = n/2 · (2a₁ + (n − 1)d).", - "s₅ = 5/2 · (6 + 8) = 35.", - ]), - S("2 / 3 • Geometrická", "Stálý kvocient", - "Tip: aₙ = a₁ · qⁿ⁻¹.", - [ - "Geometrická posloupnost násobí stále stejným kvocientem q.", - "Pro a₁ = 2 a q = 3 je a₄ = 2 · 3³ = 54.", - "q = 1 znamená, že se členy nemění.", - "q = 0 je po prvním členu samá nula, pokud je první člen definován.", - ]), - S("3 / 3 • Nekonečná řada", "Součet pro |q| < 1", - "Tip: s = a₁ / (1 − q).", - [ - "Nekonečná geometrická řada má součet jen pro |q| < 1.", - "Pro a₁ = 6 a q = 1/2 je s = 6 / (1/2) = 12.", - "Pro |q| ≥ 1 se součet členů neblíží ke konečnému číslu, kromě případu q = 1 a a₁ = 0.", - "Řada 6 + 3 + 3/2 + … se tedy blíží ke 12.", - ]), - ], - [ - N("Aritmetická posloupnost má a₁ = 3 a d = 2. Kolik je a₅?", - 3 + 4 * 2, "a₅ = 3 + 4 · 2 = 11."), - N("Aritmetická posloupnost má a₁ = 3 a d = 2. Kolik je součet prvních pěti členů?", - Fraction(5, 2) * (2 * 3 + 4 * 2), - "s₅ = 5/2 · (6 + 8) = 35."), - N("Geometrická posloupnost má a₁ = 2 a q = 3. Kolik je a₄?", - 2 * (3 ** 3), "a₄ = 2 · 27 = 54."), - N("Nekonečná geometrická řada má a₁ = 6 a q = 1/2. Jaký je její součet?", - 6 / Fraction(1, 2), "s = 6 / (1/2) = 12."), - ], - ), - lesson( - "Kombinatorika", "Combinatorics", - "Permutace, variace a kombinace.", - "Permutations, variations and combinations.", - [ - S("1 / 3 • Permutace", "Pořadí všech prvků", - "Tip: n! = 1 · 2 · … · n a 0! = 1.", - [ - "Permutace je uspořádání všech n různých prvků.", - "Počet je n!.", - "4! = 24 a 3! = 6.", - "Na prvním místě je n možností, na dalším n − 1, a tak dál.", - ]), - S("2 / 3 • Variace", "Pořadí vybraných prvků", - "Tip: variace bez opakování V(n, k) = n! / (n − k)!.", - [ - "Variace vybírá k prvků z n a záleží na pořadí.", - "V(5, 2) = 5 · 4 = 20.", - "Opakování by dovolilo vybrat stejný prvek víckrát.", - "Permutace je variace, která vybírá všech n prvků.", - ]), - S("3 / 3 • Kombinace", "Pořadí nehraje roli", - "Tip: C(n, k) = n! / (k! · (n − k)!).", - [ - "Kombinace vybírá k prvků a dvě vybrané skupiny se stejným obsahem jsou jedna.", - "C(5, 2) = 10.", - "C(n, k) = C(n, n − k).", - "Počet variací je k! krát větší než počet kombinací.", - ]), - ], - [ - N("Kolik je permutací čtyř různých prvků?", 24, - "4! = 24."), - N("Kolik je kombinací 2 prvků z 5?", 10, - "C(5, 2) = (5 · 4) / 2 = 10."), - N("Kolik je variací 2 prvků z 5 bez opakování?", 20, - "V(5, 2) = 5 · 4 = 20."), - N("Kolik je 3!?", 6, "3 · 2 · 1 = 6."), - ], - ), - lesson( - "Pravděpodobnost", "Probability", - "Klasická pravděpodobnost, kostka, mince a karty.", - "Classical probability with a die, a coin and cards.", - [ - S("1 / 3 • Definice", "Příznivé ku všem", - "Tip: všechny výsledky musí být stejně možné.", - [ - "Klasická pravděpodobnost je počet příznivých výsledků dělený počtem všech.", - "Hodnota leží od 0 do 1.", - "Jev jistý má pravděpodobnost 1, jev nemožný 0.", - "Na kostce je sudé číslo ve třech případech ze šesti, tedy 1/2.", - ]), - S("2 / 3 • Nezávislost", "Součin pravděpodobností", - "Tip: dvě mince mají čtyři stejně možné dvojice výsledků.", - [ - "U dvou nezávislých mincí jsou možnosti PP, PO, OP a OO.", - "Dva panny jsou jedna možnost ze čtyř, tedy 1/4.", - "U dvou kostek je 36 stejně možných dvojic.", - "Součet 7 nastane u šesti dvojic: 1+6, 2+5, 3+4, 4+3, 5+2 a 6+1.", - ]), - S("3 / 3 • Karty", "Čtyři esa v balíčku 32 karet", - "Tip: mariášový balíček má 32 karet.", - [ - "Pravděpodobnost esa je 4/32 = 1/8.", - "Tažení jedné karty považuje každou kartu za stejně možnou.", - "Doplňkový jev má pravděpodobnost 1 − p.", - "Výsledek se krátí do základního tvaru.", - ]), - ], - [ - N("Jaká je pravděpodobnost sudého čísla při hodu hrací kostkou?", - Fraction(3, 6), - "Sudá jsou 2, 4 a 6, tedy 3 ze 6, čili 1/2."), - N("Jaká je pravděpodobnost, že na dvou mincích padnou dvě panny?", - Fraction(1, 4), - "Ze čtyř dvojic je příznivá jedna."), - N("V balíčku 32 karet jsou 4 esa. Jaká je pravděpodobnost, že tažená karta je eso?", - Fraction(4, 32), - "4/32 = 1/8."), - N("Jaká je pravděpodobnost, že součet na dvou hracích kostkách je 7?", - Fraction(6, 36), - "Příznivých dvojic je 6 z 36, tedy 1/6."), - ], - ), - lesson( - "Stereometrie", "Solid geometry", - "Krychle, válec, koule a jehlan.", - "The cube, the cylinder, the sphere and a pyramid.", - [ - S("1 / 3 • Krychle", "Objem a povrch", - "Tip: krychle o hraně a má objem a³ a povrch 6a².", - [ - "Objem je počet jednotkových krychlí, které se do tělesa vejdou.", - "Krychle o hraně 3 má objem 27.", - "Povrch je součet obsahů všech stěn: 6 · 9 = 54.", - "Jednotky objemu jsou krychlové, jednotky povrchu čtvereční.", - ]), - S("2 / 3 • Válec a koule", "Vzorce s π", - "Tip: výsledek nechte v násobcích π.", - [ - "Objem válce je πr²v.", - "Pro r = 2 a v = 5 je objem 20π.", - "Objem koule je (4/3)πr³.", - "Pro r = 3 je objem (4/3)π · 27 = 36π.", - ]), - S("3 / 3 • Jehlan", "Třetina hranolu", - "Tip: objem jehlanu je (1/3) · obsah podstavy · výška.", - [ - "Jehlan má stejný objem jako třetina hranolu se stejnou podstavou a výškou.", - "Podstava o obsahu 12 a výška 4 dávají objem 16.", - "Výška je kolmá vzdálenost vrcholu od roviny podstavy.", - "Stejný vztah třetiny platí i pro kužel vůči válci.", - ]), - ], - [ - N("Krychle má hranu 3. Jaký je její objem?", 3 ** 3, - "3³ = 27."), - N("Krychle má hranu 3. Jaký je její povrch?", 6 * (3 ** 2), - "Šest stěn o obsahu 9 dává 54."), - PI("Válec má poloměr 2 a výšku 5. Jaký je jeho objem? Nechte π ve výsledku.", - (2 ** 2) * 5, "πr²v = π · 4 · 5 = 20π."), - PI("Koule má poloměr 3. Jaký je její objem? Nechte π ve výsledku.", - Fraction(4, 3) * (3 ** 3), - "(4/3)π · 27 = 36π."), - ], - ), - ] - - -def year4(): - return [ - lesson( - "Vektory", "Vectors", - "Velikost, součet, skalární součin a koncový bod.", - "Magnitude, a sum, the dot product and an endpoint.", - [ - S("1 / 3 • Souřadnice", "Velikost a součet", - "Tip: velikost vektoru (a; b) je √(a² + b²).", - [ - "Vektor má velikost a směr.", - "|(3; 4)| = 5, protože 9 + 16 = 25.", - "Vektory se sčítají po souřadnicích.", - "(1; 2) + (3; −1) = (4; 1).", - ]), - S("2 / 3 • Skalární součin", "Číslo, ne vektor", - "Tip: (a; b) · (c; d) = ac + bd.", - [ - "Skalární součin dvou vektorů je číslo.", - "(1; 2) · (3; 4) = 3 + 8 = 11.", - "Nulový skalární součin znamená kolmé vektory.", - "Velikost lze psát jako odmocninu ze skalárního součinu vektoru se sebou.", - ]), - S("3 / 3 • Vzdálenost", "Velikost rozdílu", - "Tip: na mřížce osa y míří nahoru.", - [ - "Vzdálenost bodů je velikost vektoru mezi nimi.", - "Od [1; 1] do [4; 5] je vektor (3; 4) a vzdálenost 5.", - "Koncový bod vektoru (3; 2) umístěného do [1; 1] je [4; 3].", - "Pořadí souřadnic je x a potom y.", - ]), - ], - [ - N("Jaká je velikost vektoru (3; 4)?", 5, - "√(9 + 16) = √25 = 5."), - PAIR("Sečtěte vektory (1; 2) a (3; −1). Napište souřadnice oddělené středníkem.", - 4, 1, "(1 + 3; 2 + (−1)) = (4; 1)."), - N("Spočítejte skalární součin vektorů (1; 2) a (3; 4).", - 1 * 3 + 2 * 4, "1 · 3 + 2 · 4 = 11."), - N("Jaká je vzdálenost bodů [1; 1] a [4; 5]?", 5, - "Rozdíl je (3; 4) a jeho velikost je 5."), - DRAW("Z bodu A = [1; 1] naneste vektor (3; 2). Zakreslete koncový bod.", - "points:4,3;fix:1,1", - "Ke každé souřadnici se přičte složka vektoru: [1 + 3; 1 + 2] = [4; 3].", - "4,3"), - ], - ), - lesson( - "Analytická přímka", "The line in the plane", - "Směrnice, úsek, parametrické vyjádření a vzdálenost od přímky.", - "Slope, intercept, a parametric equation and the distance from a line.", - [ - S("1 / 3 • Směrnice", "y = ax + b", - "Tip: a = (y₂ − y₁)/(x₂ − x₁).", - [ - "Body [1; 2] a [4; 8] určují směrnici (8 − 2)/(4 − 1) = 2.", - "Přímka procházející bodem [0; 1] se směrnicí 2 má rovnici y = 2x + 1.", - "Úsek na ose y je 1.", - "Svislá přímka směrnici tohoto tvaru nemá.", - ]), - S("2 / 3 • Parametr", "Bod a směrový vektor", - "Tip: X = A + t · u.", - [ - "Parametrické vyjádření je x = x₀ + t · u₁, y = y₀ + t · u₂.", - "Přímka (1; 3) + t(2; 0) má při t = 2 bod [5; 3].", - "Každé t dá právě jeden bod přímky.", - "Směrový vektor (2; 0) je vodorovný.", - ]), - S("3 / 3 • Vzdálenost", "Bod od přímky", - "Tip: pro ax + by + c = 0 je vzdálenost |ax₀ + by₀ + c| / √(a² + b²).", - [ - "Přímka 3x + 4y − 10 = 0 má a = 3, b = 4 a c = −10.", - "Vzdálenost počátku je |−10| / √(9 + 16) = 10/5 = 2.", - "Čitatel je absolutní hodnota, vzdálenost není záporná.", - "Čtvrtý vrchol rovnoběžníku k bodům A, B a C je B + C − A.", - ]), - ], - [ - N("Jaká je směrnice přímky body [1; 2] a [4; 8]?", - Fraction(8 - 2, 4 - 1), - "(8 − 2)/(4 − 1) = 2."), - N("Přímka má rovnici y = 2x + 1. Jaký je její úsek na ose y?", - 1, "Úsek je absolutní člen, tedy 1."), - PAIR("Bod přímky je (1; 3) + t(2; 0). Kam přímka dojde pro t = 2? Napište x a y středníkem.", - 5, 3, "(1; 3) + 2 · (2; 0) = (5; 3)."), - N("Jaká je vzdálenost bodu [0; 0] od přímky 3x + 4y − 10 = 0?", - 2, "|−10| / √(9 + 16) = 10/5 = 2."), - DRAW("A = [1; 1], B = [4; 1] a C = [2; 3]. Zakreslete čtvrtý vrchol rovnoběžníku, ve kterém jsou AB a AC sousední strany.", - "para:1,1;4,1;2,3", - "D = B + C − A = [4 + 2 − 1; 1 + 3 − 1] = [5; 3].", - "5,3"), - ], - ), - lesson( - "Kuželosečky", "Conic sections", - "Kružnice a elipsa v osové poloze.", - "A circle and an ellipse aligned with the axes.", - [ - S("1 / 3 • Kružnice", "Střed a poloměr", - "Tip: (x − m)² + (y − n)² = r² má střed [m; n].", - [ - "Kružnice je množina bodů stejně vzdálených od středu.", - "(x − 1)² + (y + 2)² = 9 má střed [1; −2].", - "y + 2 je totéž co y − (−2).", - "Poloměr je √9 = 3, ne 9.", - ]), - S("2 / 3 • Elipsa", "Dvě poloosy", - "Tip: ve tvaru x²/a² + y²/b² = 1 je a poloosa na ose x.", - [ - "Elipsa v osové poloze se středem v počátku má rovnici x²/a² + y²/b² = 1.", - "U x²/25 + y²/9 = 1 je a = 5 a b = 3.", - "Delší poloosa je hlavní, kratší vedlejší.", - "Vrcholy na ose x jsou [±a; 0], na ose y [0; ±b].", - ]), - S("3 / 3 • Excentricita", "Vzdálenost ohniska od středu", - "Tip: pro a > b je e = √(a² − b²).", - [ - "Lineární výstřednost e splňuje e² = a² − b², když je a hlavní poloosa.", - "√(25 − 9) = √16 = 4.", - "Ohniska elipsy jsou [±e; 0].", - "Součet vzdáleností bodu elipsy od obou ohnisek je 2a.", - ]), - ], - [ - PAIR("Kružnice má rovnici (x − 1)² + (y + 2)² = 9. Napište souřadnice středu jako x;y.", - 1, -2, "Střed je [1; −2]."), - N("Jaký je poloměr kružnice (x − 1)² + (y + 2)² = 9?", - 3, "Pravá strana je r², takže r = 3."), - N("Elipsa má rovnici x²/25 + y²/9 = 1. Jak dlouhá je poloosa a na ose x?", - 5, "a² = 25, takže a = 5."), - N("Elipsa má rovnici x²/25 + y²/9 = 1. Jak dlouhá je poloosa b na ose y?", - 3, "b² = 9, takže b = 3."), - N("Elipsa má a = 5 a b = 3. Jaká je její lineární výstřednost e?", - 4, "e = √(25 − 9) = √16 = 4."), - ], - ), - lesson( - "Komplexní čísla", "Complex numbers", - "Součet, součin, absolutní hodnota a mocnina i.", - "A sum, a product, the modulus and a power of i.", - [ - S("1 / 3 • Tvar", "a + bi", - "Tip: i² = −1. Reálnou a imaginární část pište oddělené středníkem.", - [ - "Komplexní číslo a + bi má reálnou část a a imaginární část b.", - "i je imaginární jednotka a i² = −1.", - "Čísla se sčítají po složkách.", - "(2 + 3i) + (1 − i) = 3 + 2i.", - ]), - S("2 / 3 • Násobení", "Jako dvojčlen", - "Tip: (1 + i)(1 − i) je rozdíl čtverců.", - [ - "(a + bi)(c + di) = ac + adi + bci + bdi².", - "bdi² = −bd, proto se imaginární jednotka ve výsledku nemusí objevit.", - "(1 + i)(1 − i) = 1 − (i)² = 1 − (−1) = 2.", - "Komplexní čísla lze násobit i v goniometrickém tvaru sčítáním argumentů.", - ]), - S("3 / 3 • Absolutní hodnota", "Vzdálenost od nuly", - "Tip: |a + bi| = √(a² + b²).", - [ - "Absolutní hodnota je vzdálenost obrazu čísla od počátku Gaussovy roviny.", - "|3 + 4i| = 5.", - "|z| je vždy reálné nezáporné číslo.", - "i² = −1, i³ = −i a i⁴ = 1.", - ]), - ], - [ - PAIR("Sečtěte 2 + 3i a 1 − i. Napište reálnou a imaginární část středníkem.", - 3, 2, "(2 + 1) + (3 − 1)i = 3 + 2i."), - N("Spočítejte (1 + i)(1 − i).", 2, - "1 − i² = 1 − (−1) = 2."), - N("Jaká je absolutní hodnota čísla 3 + 4i?", 5, - "√(9 + 16) = 5."), - N("Kolik je i²?", -1, "Imaginární jednotka splňuje i² = −1."), - ], - ), - lesson( - "Derivace", "The derivative", - "Derivace mocniny, tečna a derivace sinu.", - "The derivative of a power, a tangent and the derivative of sine.", - [ - S("1 / 3 • Mocnina", "(xⁿ)' = n xⁿ⁻¹", - "Tip: derivace je směrnice tečny.", - [ - "Derivace funkce v bodě je směrnice tečny grafu v tom bodě.", - "(x³)' = 3x². V bodě x = 2 je 3 · 4 = 12.", - "(5x²)' = 10x. V bodě x = 1 je 10.", - "Derivace konstanty je 0 a konstanta se vytýká.", - ]), - S("2 / 3 • Tečna", "Směrnice v bodě", - "Tip: u f(x) = x² je f'(x) = 2x.", - [ - "Tečna ke grafu y = x² v bodě x = 1 má směrnici 2.", - "Rovnice tečny používá bod [1; 1] a tuto směrnici.", - "Kladná derivace znamená, že funkce v bodě roste.", - "Záporná derivace znamená, že funkce klesá.", - ]), - S("3 / 3 • Sinus", "Derivace sinu je kosinus", - "Tip: (sin x)' = cos x a cos 0 = 1.", - [ - "Derivace funkce sin x je cos x.", - "Derivace funkce cos x je −sin x.", - "V bodě x = 0 je derivace sinu rovna cos 0 = 1.", - "Úhel v tomto vzorci je v radiánech, ale nula je nula v obou jednotkách.", - ]), - ], - [ - N("Jaká je derivace funkce x³ v bodě x = 2?", 3 * (2 ** 2), - "(x³)' = 3x² a 3 · 4 = 12."), - N("Jaká je derivace funkce 5x² v bodě x = 1?", 10 * 1, - "(5x²)' = 10x a v jedničce je 10."), - N("Jakou směrnici má tečna ke grafu y = x² v bodě x = 1?", 2, - "Derivace 2x je v bodě 1 rovna 2."), - N("Jaká je derivace funkce sin x v bodě x = 0? Derivace sinu je kosinus.", - 1, "(sin x)' = cos x a cos 0 = 1."), - ], - ), - lesson( - "Průběh funkce", "The shape of a function", - "Stacionární body, lokální extrémy a nulová derivace.", - "Stationary points, local extrema and a zero derivative.", - [ - S("1 / 3 • Stacionární bod", "Derivace je nula", - "Tip: f'(x) = 0 je vodorovná tečna.", - [ - "V lokálním extrému diferencovatelné funkce je derivace nulová.", - "U f(x) = x³ − 3x je f'(x) = 3x² − 3.", - "3(x² − 1) = 0 dává x = −1 a x = 1.", - "To jsou jediní kandidáti na lokální extrém.", - ]), - S("2 / 3 • Maximum a minimum", "Znaménko druhé derivace", - "Tip: f''(x) = 6x. Záporná druhá derivace znamená lokální maximum.", - [ - "V x = −1 je f''(−1) = −6 < 0, takže jde o lokální maximum.", - "f(−1) = −1 + 3 = 2.", - "V x = 1 je f''(1) = 6 > 0, takže jde o lokální minimum.", - "f(1) = 1 − 3 = −2.", - ]), - S("3 / 3 • Jiný příklad", "Lineární derivace", - "Tip: g'(x) = 2x − 4 je nula při x = 2.", - [ - "Kde je derivace nula, má graf vodorovnou tečnu.", - "Rovnice 2x − 4 = 0 má řešení x = 2.", - "Pro x < 2 je derivace 2x − 4 záporná, funkce klesá.", - "Pro x > 2 je derivace kladná, funkce roste.", - ]), - ], - [ - N("Funkce f(x) = x³ − 3x. Ve kterém x má lokální maximum?", - -1, "f'(x) = 3x² − 3 = 0 pro x = ±1 a v −1 je maximum."), - N("Funkce f(x) = x³ − 3x. Jaká je hodnota lokálního maxima?", - (-1) ** 3 - 3 * (-1), - "f(−1) = −1 + 3 = 2."), - N("Funkce f(x) = x³ − 3x. Ve kterém x má lokální minimum?", - 1, "Druhá derivace 6x je v x = 1 kladná."), - N("Derivace funkce je g'(x) = 2x − 4. Pro které x je derivace nulová?", - 2, "2x − 4 = 0 dává x = 2."), - ], - ), - lesson( - "Integrál", "The integral", - "Určitý integrál mocniny jako obsah pod grafem.", - "The definite integral of a power as the area under the graph.", - [ - S("1 / 3 • Primitivní funkce", "Opačný postup k derivaci", - "Tip: primitivní funkce k xⁿ je xⁿ⁺¹/(n + 1) pro n ≠ −1.", - [ - "Neurčitý integrál je množina primitivních funkcí.", - "Liší se o konstantu, protože derivace konstanty je nula.", - "Primitivní funkce k 2x je x².", - "Primitivní funkce k x² je x³/3.", - ]), - S("2 / 3 • Určitý integrál", "Newtonův vzorec", - "Tip: ∫ od a do b z f je F(b) − F(a).", - [ - "Určitý integrál nezáporné funkce je obsah plochy pod grafem.", - "∫ od 0 do 3 z 2x dx = [x²] od 0 do 3 = 9.", - "∫ od 0 do 2 z x² dx = [x³/3] od 0 do 2 = 8/3.", - "Dolní mez 0 u těchto mocnin často vynuluje první člen.", - ]), - S("3 / 3 • Konstanta", "Násobek lze vytknout", - "Tip: integrál z c · f je c krát integrál z f.", - [ - "∫ od 0 do 1 z 3x² dx = [x³] od 0 do 1 = 1.", - "∫ od 0 do 2 z 6x dx = [3x²] od 0 do 2 = 12.", - "Záporná funkce dává záporný integrál, nejde vždy o obsah beze znaménka.", - "Součet funkcí se integruje člen po členu.", - ]), - ], - [ - N("Spočítejte integrál od 0 do 3 z funkce 2x.", - 3 ** 2 - 0, "Primitivní funkce je x² a 9 − 0 = 9."), - N("Spočítejte integrál od 0 do 2 z funkce x².", - Fraction(2 ** 3, 3), - "Primitivní funkce je x³/3 a 8/3 − 0 = 8/3."), - N("Spočítejte integrál od 0 do 1 z funkce 3x².", - 1, "Primitivní funkce je x³ a 1 − 0 = 1."), - N("Spočítejte integrál od 0 do 2 z funkce 6x.", - 3 * (2 ** 2), - "Primitivní funkce je 3x² a 12 − 0 = 12."), - ], - ), - lesson( - "Maturitní mix", "Maturita mix", - "Logaritmus, kombinace, vektor, zlomek a kvadratická rovnice.", - "A logarithm, a combination, a vector, a fraction and a quadratic equation.", - [ - S("1 / 3 • Číslo", "Logaritmus a zlomek", - "Tip: log₂(8) = 3, protože 2³ = 8.", - [ - "Logaritmus vrací exponent.", - "1/2 + 1/3 = 5/6.", - "Společný jmenovatel se hledá i v maturitním příkladu stejně jako na základní škole.", - "Výsledek se krátí.", - ]), - S("2 / 3 • Počet a vektor", "Kombinace a velikost", - "Tip: C(6, 2) = 15 a |(3; 4)| = 5.", - [ - "C(6, 2) = (6 · 5) / 2 = 15.", - "Pořadí vybrané dvojice se nepočítá dvakrát.", - "Velikost vektoru (3; 4) je přepona trojúhelníku 3-4-5.", - "Skalární součin by u kolmých vektorů vyšel nula.", - ]), - S("3 / 3 • Rovnice", "x² − 1 = 0", - "Tip: rozdíl čtverců (x − 1)(x + 1).", - [ - "x² − 1 = 0 má kořeny −1 a 1.", - "Oba se napíšou, oddělené středníkem.", - "Diskriminant je 0 − 4 · 1 · (−1) = 4.", - "Zkouška: 1 − 1 = 0 a 1 − 1 = 0.", - ]), - ], - [ - N("Spočítejte logaritmus o základu 2 z 8.", 3, - "2³ = 8."), - N("Kolik je kombinací 2 prvků ze 6?", 15, - "C(6, 2) = 15."), - N("Jaká je velikost vektoru (3; 4)?", 5, - "√(9 + 16) = 5."), - N("Spočítejte 1/2 + 1/3.", Fraction(1, 2) + Fraction(1, 3), - "3/6 + 2/6 = 5/6."), - SET("Najděte kořeny rovnice x² − 1 = 0. Oddělte je středníkem.", - [-1, 1], "(x − 1)(x + 1) = 0."), - ], - ), - ] - - -YEARS = [ - { - "prefix": "mat0", - "year": 0, - "array": "mat0_lessons", - "add": "add_mat0_pages", - "title_key": "mat0_year", - "title_cs": "Opakování základní školy", - "title_en": "Elementary-school review", - "sub_key": "mat0_sub", - "sub_cs": "Pořadí operací, zlomky, procenta, rovnice a rýsování.", - "sub_en": "Order of operations, fractions, percentages, equations and a construction.", - "lessons": year0(), - }, - { - "prefix": "mat", - "year": 1, - "array": "mat_lessons", - "add": "add_mat_pages", - "title_key": "mat_year1", - "title_cs": "1. ročník", - "title_en": "Year 1", - "sub_key": "mat_sub", - "sub_cs": "Dělitelnost, výrazy, rovnice, planimetrie a konstrukce.", - "sub_en": "Divisibility, expressions, equations, plane figures and a construction.", - "lessons": year1(), - }, - { - "prefix": "mat2", - "year": 2, - "array": "mat2_lessons", - "add": "add_mat2_pages", - "title_key": "mat_year2", - "title_cs": "2. ročník", - "title_en": "Year 2", - "sub_key": "mat2_sub", - "sub_cs": "Funkce, soustavy, kvadratické rovnice, goniometrie a kružnice.", - "sub_en": "Functions, systems, quadratic equations, trigonometry and circles.", - "lessons": year2(), - }, - { - "prefix": "mat3", - "year": 3, - "array": "mat3_lessons", - "add": "add_mat3_pages", - "title_key": "mat_year3", - "title_cs": "3. ročník", - "title_en": "Year 3", - "sub_key": "mat3_sub", - "sub_cs": "Logaritmus, posloupnosti, pravděpodobnost a stereometrie.", - "sub_en": "Logarithms, sequences, probability and solid geometry.", - "lessons": year3(), - }, - { - "prefix": "mat4", - "year": 4, - "array": "mat4_lessons", - "add": "add_mat4_pages", - "title_key": "mat_year4", - "title_cs": "4. ročník", - "title_en": "Year 4", - "sub_key": "mat4_sub", - "sub_cs": "Analytická geometrie, derivace, integrál a maturitní opakování.", - "sub_en": "Coordinate geometry, derivatives, integrals and a maturita review.", - "lessons": year4(), - }, -] - - -def emit_year(info) -> str: - prefix = info["prefix"] - lines = [ - '#include "graduately.h"', - "", - f"NetLesson {info['array']}[MATH_N] = {{", - ] - for i in range(1, 9): - lines.append( - f' {{ .n_slides = 3, .unit_page = "{prefix}unit{i}", .ex_page = "{prefix}ex{i}" }},' - ) - lines.append("};") - lines.append("") - for i, lesson in enumerate(info["lessons"], start=1): - lines.append(f"static GtkWidget *build_{prefix}_unit{i}_page(void) {{") - lines.append(" static const NetSlide slides[] = {") - for kicker, title, tip, body in lesson["slides"]: - lines.append(" {") - lines.append(f" {c_string(kicker)}, {c_string(title)},") - lines.append(f" {c_string(tip)},") - lines.append(" {") - for row in body: - lines.append(f" {c_string(row)},") - lines.append(" NULL,") - lines.append(" },") - lines.append(" },") - lines.append(" };") - lines.append("") - lines.append( - f' return math_unit_page({info["year"]}, &{info["array"]}[{i - 1}], ' - f'"{prefix}_unit{i}", "{prefix}_unit{i}_sub",' - ) - lines.append(" slides, G_N_ELEMENTS(slides));") - lines.append("}") - lines.append("") - lines.append(f"static GtkWidget *build_{prefix}_unit{i}_exercise_page(void) {{") - lines.append(" static const MathItem qs[] = {") - for prob in lesson["problems"]: - lines.append( - f" {{{c_string(prob.prompt)}, {c_string(prob.spec)}, {c_string(prob.hint)}}}," - ) - lines.append(" };") - lines.append("") - lines.append( - f' return math_practice_page({info["year"]}, {i - 1}, "{prefix}unit{i}",' - ) - lines.append( - f' "{prefix}_ex{i}_title", "{prefix}_quiz{i}_head",' - ) - lines.append(" qs, G_N_ELEMENTS(qs));") - lines.append("}") - lines.append("") - lines.append(f"void {info['add']}(GtkStack *stack) {{") - lines.append(" typedef GtkWidget *(*MathBuilder)(void);") - lines.append(" static const struct {") - lines.append(" const char *unit_name;") - lines.append(" const char *ex_name;") - lines.append(" MathBuilder build_unit;") - lines.append(" MathBuilder build_ex;") - lines.append(" } pages[] = {") - for i in range(1, 9): - lines.append( - f' {{"{prefix}unit{i}", "{prefix}ex{i}", ' - f"build_{prefix}_unit{i}_page, build_{prefix}_unit{i}_exercise_page}}," - ) - lines.append(" };") - lines.append("") - lines.append(" for (guint i = 0; i < G_N_ELEMENTS(pages); i++) {") - lines.append(" gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name);") - lines.append(" gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name);") - lines.append(" }") - lines.append("}") - lines.append("") - return "\n".join(lines) - - -def emit_i18n() -> str: - rows = [ - ("mat_years_sub", - "Opakování základní školy a čtyři ročníky gymnázia.", - "Elementary review and four years of gymnasium mathematics."), - ("math_quiz_intro", - "Napište výsledek. Zlomky jako 3/4, desetinnou čárku i tečku, π jako pi, odmocninu jako sqrt(2) nebo √2. Více čísel oddělte středníkem.", - "Write the result. Fractions as 3/4, a decimal comma or point, π as pi, a root as sqrt(2) or √2. Separate several numbers with a semicolon."), - ("math_answer_ph", "výsledek", "result"), - ("math_undo", "Zpět", "Undo"), - ("math_clear", "Smazat body", "Clear points"), - ("math_draw_hint", "Klepněte na mřížku. Osa y směřuje nahoru.", - "Tap the grid. The y-axis points up."), - ] - for info in YEARS: - rows.append((info["title_key"], info["title_cs"], info["title_en"])) - rows.append((info["sub_key"], info["sub_cs"], info["sub_en"])) - for i, lesson in enumerate(info["lessons"], start=1): - p = info["prefix"] - rows.append((f"{p}_unit{i}", lesson["title_cs"], lesson["title_en"])) - rows.append((f"{p}_unit{i}_sub", lesson["sub_cs"], lesson["sub_en"])) - rows.append((f"{p}_ex{i}_title", "Příklady", "Practice")) - rows.append((f"{p}_quiz{i}_head", lesson["title_cs"], lesson["title_en"])) - lines = [] - for key, cs, en in rows: - lines.append(f" {{{c_string(key)}, {c_string(cs)}, {c_string(en)}}},") - return "\n".join(lines) + "\n" - - -def cases() -> list[str]: - out = [] - for info in YEARS: - for lesson in info["lessons"]: - for prob in lesson["problems"]: - if prob.draw: - out.append(f"draw {prob.spec}\t{prob.draw}\t1") - else: - kind, _, body = prob.spec.partition(":") - user = body.split("|", 1)[0] if kind == "word" else body - out.append(f"{prob.spec}\t{user}\t1") - out.append("draw square:2,3;5,3\t5,0;2,0\t1") - out.append("draw right:2,4;8,4\t5,1\t1") - return out - - -def main() -> int: - for info in YEARS: - if len(info["lessons"]) != 8: - raise SystemExit(f"{info['prefix']} has {len(info['lessons'])} lessons") - text = emit_year(info) - name = { - "mat0": "mat_year0.c", - "mat": "mat_year1.c", - "mat2": "mat_year2.c", - "mat3": "mat_year3.c", - "mat4": "mat_year4.c", - }[info["prefix"]] - (SRC / name).write_text(text, encoding="utf-8") - print(f"wrote {name}") - (SRC / "math_i18n.inc").write_text(emit_i18n(), encoding="utf-8") - case_path = Path("/tmp/math_cases.txt") - case_path.write_text("\n".join(cases()) + "\n", encoding="utf-8") - binary = Path("/tmp/mathcheck") - if binary.exists(): - result = subprocess.run([str(binary), str(case_path)], check=False) - if result.returncode != 0: - return result.returncode - print("generated answers accepted") - else: - print("checker binary missing, cases written only") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/src/biologie.c b/src/biologie.c deleted file mode 100644 index 8612458..0000000 --- a/src/biologie.c +++ /dev/null @@ -1,617 +0,0 @@ -#include "graduately.h" - -/* Biology for Základy přírodopisných věd. - * Follows the secondary-school outline: general biology, a survey of - * organisms, human biology, genetics and ecology. */ - -NetLesson bio_lessons[SCI_N] = { - { .n_slides = 3, .unit_page = "biounit1", .ex_page = "bioex1" }, - { .n_slides = 3, .unit_page = "biounit2", .ex_page = "bioex2" }, - { .n_slides = 3, .unit_page = "biounit3", .ex_page = "bioex3" }, - { .n_slides = 3, .unit_page = "biounit4", .ex_page = "bioex4" }, - { .n_slides = 3, .unit_page = "biounit5", .ex_page = "bioex5" }, - { .n_slides = 3, .unit_page = "biounit6", .ex_page = "bioex6" }, - { .n_slides = 3, .unit_page = "biounit7", .ex_page = "bioex7" }, - { .n_slides = 3, .unit_page = "biounit8", .ex_page = "bioex8" }, -}; - -static GtkWidget *build_bio_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Život", "Čím se živé liší", - "Tip: metabolismus je přeměna látek a energie, ne jen dýchání.", - { - "Živé soustavy mají metabolismus, dráždivost, růst a vývin.", - "Rozmnožují se a předávají dědičnou informaci.", - "Udržují stálé vnitřní prostředí, homeostázu.", - "Bez příjmu energie a látek z okolí život nepokračuje.", - NULL, - }, - }, - { - "2 / 3 • Řada", "Od buňky k ekosystému", - "Tip: populace je jeden druh, společenstvo je víc druhů pohromadě.", - { - "Buňka je základní stavební a funkční jednotka živého.", - "Tkáně tvoří orgány, orgány soustavy a soustavy organismus.", - "Populace jsou jedinci téhož druhu na jednom místě.", - "Společenstvo s neživým prostředím tvoří ekosystém.", - NULL, - }, - }, - { - "3 / 3 • Výživa", "Autotrof a heterotrof", - "Tip: zelená rostlina je autotrof, živočich heterotrof.", - { - "Autotrof tvoří organické látky z anorganických, hlavně fotosyntézou.", - "Heterotrof přijímá hotové organické látky.", - "Život na Zemi je vázaný na vodu a na zdroj energie.", - "Buňka vznikla dřív než mnohobuněčné organismy.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[0], "bio_unit1", "bio_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je základní jednotka živých organismů?", - {"Atom", "Buňka", "Ekosystém", "Orgán"}, - 4, 1}, - {"Co je metabolismus?", - {"Jen pohyb živočicha", - "Přeměna látek a energie v organismu", - "Počet chromozomů", - "Rozmnožování viru mimo buňku"}, - 4, 1}, - {"Co je populace?", - {"Jedinci jednoho druhu na určitém místě", - "Všechny druhy v ekosystému", - "Jedna buňka", - "Neživé složky prostředí"}, - 4, 0}, - {"Čím se autotrof liší od heterotrofa?", - {"Nemá buňky", - "Sám tvoří organické látky z anorganických", - "Nepotřebuje energii", - "Žije jen bez vody"}, - 4, 1}, - }; - static const char *hints[] = { - "Buněčná teorie: nová buňka vzniká z buňky.", - "Metabolismus zahrnuje výstavbu i rozklad látek.", - "Společenstvo už sdružuje populace různých druhů.", - "Rostliny fotosyntetizují. Živočichové a houby jsou heterotrofní.", - }; - - return sci_mcq_page(1, 0, "biounit1", "bio_ex1_title", "bio_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_bio_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Dva typy", "Prokaryota a eukaryota", - "Tip: bakterie nemají jádro, živočišná a rostlinná buňka ano.", - { - "Prokaryotní buňka nemá pravé jádro. Patří sem bakterie.", - "Eukaryotní buňka má jádro oddělené membránou a má organely.", - "Plazmatická membrána ohraničuje každou buňku.", - "Ribozomy vyrábějí bílkoviny v obou typech buněk.", - NULL, - }, - }, - { - "2 / 3 • Organely", "Co je v eukaryotní buňce", - "Tip: chloroplast mají rostliny, mitochondrii mají i živočichové.", - { - "Jádro obsahuje DNA a řídí buňku.", - "Mitochondrie uvolňují energii buněčným dýcháním.", - "Chloroplasty provádějí fotosyntézu a jsou v rostlinách.", - "Rostlinná buňka má navíc buněčnou stěnu a vakuolu.", - NULL, - }, - }, - { - "3 / 3 • Dělení", "Mitóza a meióza", - "Tip: člověk má 46 chromozomů, pohlavní buňka 23.", - { - "Mitóza dává dvě tělní buňky se stejnou genetickou informací.", - "Slouží k růstu, obnově a nepohlavnímu rozmnožování.", - "Meióza tvoří pohlavní buňky s polovičním počtem chromozomů.", - "Oplozením se počet chromozomů vrací na původní.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[1], "bio_unit2", "bio_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Která buňka je prokaryotní?", - {"Bakterie", "Rostlinná buňka", "Živočišná buňka", "Buňka houby s jádrem"}, - 4, 0}, - {"Kde probíhá fotosyntéza v rostlinné buňce?", - {"V mitochondrii", "V chloroplastu", "V ribozomu", "Jen v jádře"}, - 4, 1}, - {"K čemu slouží mitóza?", - {"Ke vzniku pohlavních buněk s poloviční sadou", - "Ke vzniku dvou geneticky stejných tělních buněk", - "K tvorbě viru", - "K odstranění jádra"}, - 4, 1}, - {"Kolik chromozomů má lidská pohlavní buňka?", - {"46", "23", "92", "2"}, - 4, 1}, - }; - static const char *hints[] = { - "Prokaryota nemají pravé jádro. Eukaryota ano.", - "Chloroplast je zelený a je v rostlinách a některých protistech.", - "Meióza, ne mitóza, snižuje počet chromozomů na polovinu.", - "Tělní buňka má 46, spermie a vajíčko po 23.", - }; - - return sci_mcq_page(1, 1, "biounit2", "bio_ex2_title", "bio_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_bio_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Virus", "Na hranici živého", - "Tip: virus není buňka a sám se mimo hostitele nemnoží.", - { - "Virus má nukleovou kyselinu v bílkovinném obalu.", - "Nemá vlastní metabolismus a množí se jen v hostitelské buňce.", - "Způsobuje třeba chřipku. Antibiotika na virus nepůsobí.", - "Očkování učí imunitu poznat virus dřív, než nemoc propukne.", - NULL, - }, - }, - { - "2 / 3 • Bakterie a houby", "Rozkladači a původci", - "Tip: houba není rostlina, živí se hotovými organickými látkami.", - { - "Bakterie jsou prokaryota. Některé jsou symbionti, jiné patogeny.", - "V průmyslu kvasí jogurt, v přírodě rozkládají organické zbytky.", - "Houby mají buněčnou stěnu z chitinu a nemají chlorofyl.", - "Kvasinky, plísně i kloboukaté houby patří mezi houby.", - NULL, - }, - }, - { - "3 / 3 • Rostliny", "Kořen, stonek, list", - "Tip: fotosyntéza běží hlavně v listech, v chloroplastech.", - { - "Rostliny jsou autotrofní a mají buněčnou stěnu z celulózy.", - "Kořen přijímá vodu a minerály a upevňuje rostlinu.", - "Stonek nese listy a vede látky, list je hlavní místo fotosyntézy.", - "Květ slouží rozmnožování, semeno obsahuje zárodek.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[2], "bio_unit3", "bio_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč se virus množí jen v hostiteli?", - {"Má vlastní chloroplast, ale bez světla", - "Nemá buněčný metabolismus", - "Je to prokaryotní buňka", - "Má jádro a mitochondrie"}, - 4, 1}, - {"Čím se houby liší od rostlin?", - {"Nemají buňky", - "Jsou heterotrofní a nemají chlorofyl", - "Mají chloroplasty navíc", - "Jsou vždy jednobuněčné prokaryota"}, - 4, 1}, - {"Kde v rostlině probíhá většina fotosyntézy?", - {"V kořeni", "V listu", "Jen v květu", "Ve dřevu bez chloroplastů"}, - 4, 1}, - {"Z čeho je buněčná stěna rostlin?", - {"Z chitinu", "Z celulózy", "Z cholesterolu", "Z peptidoglykanu jako u všech hub"}, - 4, 1}, - }; - static const char *hints[] = { - "Virus je nukleová kyselina v obalu. Buňku si půjčuje.", - "Chitin je stěna hub. Rostliny mají celulózu a chlorofyl.", - "List má nejvíc chloroplastů. Kořen je většinou pod zemí.", - "Rostliny: celulóza. Houby: chitin. Bakterie: peptidoglykan.", - }; - - return sci_mcq_page(1, 2, "biounit3", "bio_ex3_title", "bio_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_bio_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Bezobratlí", "Hmyz a další", - "Tip: hmyz má tři páry nohou a tělo ze tří částí.", - { - "Bezobratlí nemají vnitřní kostru z obratlů.", - "Kroužkovci, třeba žížala, mají článkované tělo.", - "Měkkýši mají měkké tělo, často schránku. Patří sem hlemýžď.", - "Hmyz má hlavu, hruď a zadeček a šest nohou.", - NULL, - }, - }, - { - "2 / 3 • Obratlovci", "Pět tříd, které škola probírá", - "Tip: ptáci i savci mají stálou tělesnou teplotu.", - { - "Ryby dýchají žábrami a žijí ve vodě.", - "Obojživelníci mají larvu ve vodě a vlhkou kůži, třeba žába.", - "Plazi mají suchou kůži se šupinami a vejce s obalem.", - "Ptáci mají peří, savci srst a mláďata krmí mlékem.", - NULL, - }, - }, - { - "3 / 3 • Vývoj", "Jak číst příbuznost", - "Tip: vývoj není žebřík od horšího k dokonalému člověku.", - { - "Druhy se mění v čase. Společný předek vysvětluje podobnost.", - "Obratlovci jsou jedna větev, ne vrchol všech živočichů.", - "Hmyz je druhově nejbohatší skupina živočichů.", - "Přizpůsobení prostředí se týká stavby těla i chování.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[3], "bio_unit4", "bio_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kolik nohou má hmyz?", - {"Čtyři", "Šest", "Osm", "Deset"}, - 4, 1}, - {"Čím dýchají ryby?", - {"Plicemi jako savci", "Žábrami", "Jen kůží bez cév", "Vzdušnicemi jako hmyz"}, - 4, 1}, - {"Který znak patří ptákům?", - {"Mléčné žlázy", "Peří", "Žábry u dospělce", "Tělo bez kostry"}, - 4, 1}, - {"Čím savci živí mláďata?", - {"Vždy jen žloutkem mimo tělo", "Mlékem", - "Fotosyntézou mláděte", "Filtrací vody žábrami"}, - 4, 1}, - }; - static const char *hints[] = { - "Tři páry nohou jsou šest. Pavouci mají osm a nejsou hmyz.", - "Žábry berou kyslík z vody. Dospělá žába už dýchá plícemi a kůží.", - "Peří je ptačí znak. Srst a mléko patří savcům.", - "Mléčné žlázy jsou znak savců. Ptáci vejce zahřívají.", - }; - - return sci_mcq_page(1, 3, "biounit4", "bio_ex4_title", "bio_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_bio_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Pohyb", "Kostra a svaly", - "Tip: kost je živá tkáň, ne jen minerál.", - { - "Kostra dává oporu, chrání orgány a je zásobárna vápníku.", - "Sval se upíná na kost šlachou a pohyb vzniká jeho stahem.", - "Kloub spojuje kosti pohyblivě.", - "Páteř chrání míchu.", - NULL, - }, - }, - { - "2 / 3 • Oběh", "Srdce a krev", - "Tip: malý oběh vede krev do plic, velký do těla.", - { - "Srdce člověka má dvě síně a dvě komory.", - "Pravá komora žene krev do plic, levá do těla.", - "Tepny vedou krev ze srdce, žíly do srdce.", - "V plicních sklípcích se do krve dostává kyslík a odchází oxid uhličitý.", - NULL, - }, - }, - { - "3 / 3 • Trávení", "Od úst k ledvinám", - "Tip: živiny se vstřebávají hlavně v tenkém střevě.", - { - "V ústech začíná mechanické a chemické zpracování potravy.", - "Žaludek kyselinou a enzymy pokračuje v trávení bílkovin.", - "Tenké střevo živiny vstřebá, tlusté hlavně vodu.", - "Ledviny filtrují krev a tvoří moč, játra zpracovávají živiny.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[4], "bio_unit5", "bio_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kolik dutin má srdce člověka?", - {"Dvě", "Tři", "Čtyři", "Jednu"}, - 4, 2}, - {"Kam vede malý krevní oběh?", - {"Z levé komory do celého těla", "Z pravé komory do plic", - "Z jater do žaludku", "Z ledvin do střeva"}, - 4, 1}, - {"Kde se vstřebává většina živin?", - {"V jícnu", "V tenkém střevě", "V tlustém střevě jako cukry", "Ve slezině"}, - 4, 1}, - {"Co tvoří ledviny?", - {"Žluč", "Moč", "Insulin", "Slinu"}, - 4, 1}, - }; - static const char *hints[] = { - "Dvě síně a dvě komory. Mezi pravou a levou polovinou je přepážka.", - "Malý oběh okysličuje krev. Velký ji rozvádí tělem.", - "Klky tenkého střeva zvětšují plochu. Tlusté střevo hlavně zahušťuje.", - "Játra tvoří žluč. Slinivka insulin. Ledviny moč.", - }; - - return sci_mcq_page(1, 4, "biounit5", "bio_ex5_title", "bio_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_bio_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Nervy", "Řízení organismu", - "Tip: mozek a mícha jsou ústřední nervová soustava.", - { - "Nervová soustava vede vzruchy rychle a cíleně.", - "Mozek a mícha tvoří ústřední část, nervy obvodovou.", - "Reflex je odpověď na podnět, třeba ucuknutí od horka.", - "Smysly převádějí podněty z okolí na vzruch.", - NULL, - }, - }, - { - "2 / 3 • Hormony", "Pomalejší řízení", - "Tip: insulin ze slinivky snižuje hladinu glukózy v krvi.", - { - "Hormony jsou signální látky přenášené krví.", - "Štítná žláza ovlivňuje metabolismus, nadledviny stresovou odpověď.", - "Insulin snižuje glykemii, glukagon ji zvyšuje.", - "Pohlavní hormony řídí dospívání a rozmnožování.", - NULL, - }, - }, - { - "3 / 3 • Obrana", "Rozmnožování a imunita", - "Tip: očkování připraví imunitu, aniž by člověk nemoc prodělal.", - { - "Spermie a vajíčko mají po 23 chromozomech, zygota 46.", - "Oplození spojí genetickou informaci obou rodičů.", - "Bílé krvinky a protilátky patří k imunitě.", - "Imunita rozliší vlastní buňky od cizích a od patogenů.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[5], "bio_unit6", "bio_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co tvoří ústřední nervovou soustavu?", - {"Jen obvodové nervy", "Mozek a mícha", - "Jen štítná žláza", "Srdce a plíce"}, - 4, 1}, - {"Co dělá insulin?", - {"Zvyšuje množství glukózy v krvi", - "Snižuje hladinu glukózy v krvi", - "Tvoří moč", - "Nahrazuje červené krvinky"}, - 4, 1}, - {"Kolik chromozomů má lidská zygota?", - {"23", "46", "92 v každé běžné tělní buňce navíc", "2"}, - 4, 1}, - {"K čemu je očkování?", - {"Aby virus získal buňku", - "Aby se imunita naučila poznat patogen předem", - "Aby nahradilo všechny bílé krvinky natrvalo", - "Aby zastavilo mitózu"}, - 4, 1}, - }; - static const char *hints[] = { - "Obvodové nervy spojují ústředí se smysly a svaly.", - "Insulin vyrábí slinivka. Jeho nedostatek je podstatou cukrovky 1. typu.", - "23 + 23 = 46. Pohlavní buňky jsou haploidní, zygota diploidní.", - "Vakcína je antigen, který imunitní paměť připraví.", - }; - - return sci_mcq_page(1, 5, "biounit6", "bio_ex6_title", "bio_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_bio_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • DNA", "Gen a alela", - "Tip: gen je úsek DNA, alela je jeho konkrétní forma.", - { - "DNA nese dědičnou informaci a je v chromozomech.", - "Gen je úsek DNA, který ovlivňuje určitý znak.", - "Alely jsou varianty téhož genu.", - "Dominantní alela se projeví i v jedné kopii, recesivní až ve dvou.", - NULL, - }, - }, - { - "2 / 3 • Mendel", "Genotyp a fenotyp", - "Tip: fenotyp je to, co vidíme, genotyp je zápis alel.", - { - "Johann Gregor Mendel sledoval dědičnost na hrachu.", - "Při křížení se alely rozcházejí do pohlavních buněk.", - "Genotyp je sestava alel, fenotyp je jejich projev.", - "Ne každý znak řídí jediný gen a prostředí projev také mění.", - NULL, - }, - }, - { - "3 / 3 • Změna", "Mutace a pohlaví", - "Tip: u člověka je typická žena XX a typický muž XY.", - { - "Mutace je změna DNA. Může být neutrální, škodlivá, nebo vzácně užitečná.", - "Mutace v pohlavní buňce se může přenést na potomka.", - "Pohlavní chromozomy člověka jsou X a Y.", - "Kombinace XX odpovídá ženě, XY muži.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[6], "bio_unit7", "bio_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je gen?", - {"Celá buňka", "Úsek DNA ovlivňující znak", - "Druh bílkoviny v potravě", "Hormon štítné žlázy"}, - 4, 1}, - {"Co je fenotyp?", - {"Sestava alel v buňce", "Pozorovatelný projev znaku", - "Počet ribozomů", "Vzorec glukózy"}, - 4, 1}, - {"Kdy se projeví recesivní alela?", - {"Vždycky, i když je v páru s dominantní", - "Až když jsou recesivní obě alely", - "Jen u bakterií", - "Jen jako mutace viru"}, - 4, 1}, - {"Která sestava chromozomů odpovídá muži?", - {"XX", "XY", "YY jako jediná možnost u savců", "Jen autozomy bez X a Y"}, - 4, 1}, - }; - static const char *hints[] = { - "Alela je varianta genu. Chromozom nese mnoho genů.", - "Genotyp je zápis, fenotyp je výsledek genů a prostředí.", - "Heterozygot s dominantní alelou má dominantní fenotyp.", - "XX je žena, XY muž. Y nese gen pro vývoj varlat.", - }; - - return sci_mcq_page(1, 6, "biounit7", "bio_ex7_title", "bio_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_bio_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Úrovně", "Od jedince k biosféře", - "Tip: ekosystém zahrnuje živé i neživé.", - { - "Ekologie zkoumá vztahy organismů mezi sebou a k prostředí.", - "Populace, společenstvo a ekosystém jsou tři navazující úrovně.", - "Biosféra je všechny ekosystémy Země.", - "Abiotické faktory jsou světlo, voda, teplota, vzduch a půda.", - NULL, - }, - }, - { - "2 / 3 • Potravní vztahy", "Kdo koho živí", - "Tip: na každý další článek řetězce zbývá méně energie.", - { - "Producenti, hlavně rostliny, vážou energii fotosyntézou.", - "Konzumenti se živí jinými organismy.", - "Rozkladači, bakterie a houby, vracejí látky do koloběhu.", - "V potravním řetězci se většina energie ztrácí jako teplo.", - NULL, - }, - }, - { - "3 / 3 • Člověk", "Prostředí a ochrana", - "Tip: fotosyntéza váže CO2, dýchání a spalování ho vracejí.", - { - "Člověk mění krajinu, klima i biodiverzitu.", - "Znečištění, kácení a nadměrný lov snižují rozmanitost druhů.", - "Koloběh uhlíku spojuje fotosyntézu, dýchání a spalování.", - "Ochrana přírody drží životní podmínky i pro člověka.", - NULL, - }, - }, - }; - - return sci_unit_page(1, &bio_lessons[7], "bio_unit8", "bio_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_bio_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je ekosystém?", - {"Jen jedinci jednoho druhu", - "Společenstvo spolu s neživým prostředím", - "Jedna buňka", - "Jen atmosféra bez organismů"}, - 4, 1}, - {"Kdo je v ekosystému producent?", - {"Dravec", "Zelená rostlina", "Houba rozkladač", "Virus"}, - 4, 1}, - {"Co dělají rozkladači?", - {"Vyrábějí kyslík fotosyntézou jako hlavní producenti", - "Rozkládají organické zbytky a vracejí látky do koloběhu", - "Jsou vždy obratlovci", - "Nahrazují producenty v moři i na souši jako rostliny"}, - 4, 1}, - {"Proč je na vrcholu potravního řetězce málo energie?", - {"Protože se na každém článku část energie ztratí", - "Protože producenti energii nevytvářejí", - "Protože rozkladači energii zdvojnásobí", - "Protože slunce ekosystém neovlivňuje"}, - 4, 0}, - }; - static const char *hints[] = { - "Společenstvo jsou živé složky. Ekosystém k nim přidává neživé.", - "Producent je autotrof. Konzument je heterotrof, který někoho žere.", - "Bakterie a houby mineralizují zbytky. Rostliny je znovu využijí.", - "Škola často uvádí, že na další hladinu přejde jen malá část energie.", - }; - - return sci_mcq_page(1, 7, "biounit8", "bio_ex8_title", "bio_quiz8_head", - qs, hints, 4); -} - -void add_bio_pages(GtkStack *stack) { - typedef GtkWidget *(*SciBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - SciBuilder build_unit; - SciBuilder build_ex; - } pages[] = { - {"biounit1", "bioex1", build_bio_unit1_page, build_bio_unit1_exercise_page}, - {"biounit2", "bioex2", build_bio_unit2_page, build_bio_unit2_exercise_page}, - {"biounit3", "bioex3", build_bio_unit3_page, build_bio_unit3_exercise_page}, - {"biounit4", "bioex4", build_bio_unit4_page, build_bio_unit4_exercise_page}, - {"biounit5", "bioex5", build_bio_unit5_page, build_bio_unit5_exercise_page}, - {"biounit6", "bioex6", build_bio_unit6_page, build_bio_unit6_exercise_page}, - {"biounit7", "bioex7", build_bio_unit7_page, build_bio_unit7_exercise_page}, - {"biounit8", "bioex8", build_bio_unit8_page, build_bio_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/cetba.c b/src/cetba.c deleted file mode 100644 index bb0cc07..0000000 --- a/src/cetba.c +++ /dev/null @@ -1,1836 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Maturitní četba: George Orwell – 1984 */ -/* ------------------------------------------------------------------ */ - -typedef struct { - const char *q; - const char *opts[4]; - int correct; - const char *expl; -} LitQ; - -static const LitQ lit_qs[] = { - { - "Kdo je hlavní hrdina románu a co dělá?", - { - "Winston Smith – přepisuje historii na Ministerstvu pravdy", - "O'Brien – řídí Ministerstvo lásky", - "Emmanuel Goldstein – vede Bratrstvo", - "Winston Smith – velí Policii myšlení", - }, - 0, - "Winston Smith je vnější člen strany, který na Ministerstvu pravdy " - "upravuje staré záznamy a novinové články.", - }, - { - "Ve kterém fiktivním státě se děj odehrává?", - {"V Eurasii", "V Oceánii", "Ve Východasii", "V Angsocu"}, - 1, - "Příběh se odehrává v Oceánii, v provincii Letopočet 1 (bývalá " - "Anglie), jejímž hlavním městem je Londýn.", - }, - { - "Co znamená slogan „VÁLKA JE MÍR, SVOBODA JE OTROCTVÍ, " - "NEVĚDOMOST JE SÍLA“?", - { - "Jsou to tři zásady Bratrstva", - "Jsou to názvy ministerstev", - "Jde o hesla prolety", - "Jsou to paradoxní hesla, kterými strana ospravedlňuje útlak", - }, - 3, - "Strana používá dvojité myšlení: hesla znějí vznešeně, ale ve " - "skutečnosti obhajují válku, otroctví a nevědomost.", - }, - { - "Kdo je Velký bratr a je reálnou osobou?", - { - "Skutečný vůdce Bratrstva", - "Winstonův nadřízený na ministerstvu", - "Symbol všemocné moci a kultu osobnosti; možná vůbec neexistuje", - "O'Brienův pseudonym", - }, - 2, - "Velký bratr je tvář režimu. Není jasné, zda jde o živou osobu, " - "nebo jen o symbol, který drží strach a poslušnost.", - }, - { - "Co je Newspeak (novořeč) a proč ho strana zavádí?", - { - "Tajná řeč Bratrstva", - "Zjednodušená angličtina omezující slovní zásobu, aby nešlo " - "vyslovit zakázané myšlenky", - "Úřední jazyk prolety", - "Šifra Policie myšlení", - }, - 1, - "Newspeak neustále ubírá slova. Když pro svobodu nebo odpor " - "neexistuje slovo, nelze o nich ani myslet.", - }, - { - "Co je teleobrazovka (telescreen) a jak funguje?", - { - "Televize určená jen pro zábavu", - "Zařízení, které vysílá i sleduje; nelze ji úplně vypnout", - "Rozhlasová stanice", - "Počítač Ministerstva pravdy", - }, - 1, - "Telescreen funguje obousměrně – neustále sleduje občany. Vypnout " - "lze jen zvuk, obraz běží dál.", - }, - { - "Jak se jmenují tři supervelmoci světa 1984?", - { - "Oceánie, Eurasie a Východasie", - "Oceánie, Evropa a Asie", - "Anglie, Eurasie a Ostasie", - "Oceánie, Východasie a Afrika", - }, - 0, - "Svět je rozdělen na tři státy ve věčném, ale nerozhodném " - "konfliktu: Oceánii, Eurasii a Východasii.", - }, - { - "Čím se zabývá Ministerstvo pravdy?", - { - "Vede válku", - "Dohlíží na morálku a sňatky", - "Upravuje a přepisuje historii, noviny a archivy", - "Rozděluje potraviny", - }, - 2, - "Ministerstvo pravdy vyrábí „pravdu“ – Winston v něm přepisuje " - "staré záznamy tak, aby vždy odpovídaly současné linii strany.", - }, - { - "K čemu slouží Ministerstvo lásky?", - { - "Zajišťuje sňatky a lásku", - "Je to budova bez oken, kde se mučí a likvidují nepřátelé strany", - "Vyrábí zbraně", - "Školí děti", - }, - 1, - "Ministerstvo lásky je opakem svého názvu – sídlí tam mučírny a " - "nachází se v něm i obávaná místnost 101.", - }, - { - "V čem je paradox Ministerstva hojnosti?", - { - "Má na starosti hospodářství, ale ve skutečnosti drží lidi " - "v nedostatku", - "Rozdává jídlo a zboží zdarma", - "Zajišťuje dostatek pro všechny", - "Starají se o něj prolety", - }, - 0, - "Ministerstvo hojnosti plánuje výrobu, ale ekonomika je záměrně " - "nastavena tak, aby lidé žili v trvalém nedostatku.", - }, - { - "Co je Ministerstvo míru a čím se zabývá?", - { - "Uzavírá mírové smlouvy", - "Dojednává příměří", - "Ve skutečnosti vede válku", - "Velí Policii myšlení", - }, - 2, - "Název je přesně opačný: Ministerstvo míru řídí válku, protože " - "trvalý válečný stav pomáhá udržet moc strany.", - }, - { - "Kdo je Julie a jaký vztah s ní Winston naváže?", - { - "Winstonova žena", - "Mladá členka strany, s níž Winston prožije tajnou milostnou " - "aféru", - "O'Brienova asistentka", - "Proletka a obchodnice", - }, - 1, - "Julie pracuje v oddělení beletrie a naoko je vzornou členkou " - "strany. S Winstonem vytvoří tajný milostný vztah.", - }, - { - "Proč je vztah Winstona a Julie zakázaný?", - { - "Strana zakazuje lásku a sexualitu jako zločin; vztah je navíc " - "tajný", - "Julie je vdaná za člena vnitřní strany", - "Winston je jejím nadřízeným", - "Julie patří k proletům", - }, - 0, - "Strana potlačuje citové a sexuální vazby, protože oddanost má " - "patřit jen straně. Tajný vztah je proto dvojnásob nebezpečný.", - }, - { - "Kdo je O'Brien a jakou roli hraje v příběhu?", - { - "Skutečný vůdce Bratrstva", - "Vysoce postavený člen vnitřní strany, který Winstona nakonec " - "mučí a „vyléčí“", - "Winstonův přítel z dětství", - "Proletářský básník", - }, - 1, - "Winston věří, že O'Brien je odbojář. Ve skutečnosti je to věrný " - "člen vnitřní strany, který ho dostane do místnosti 101.", - }, - { - "Co je Bratrstvo a existuje vůbec?", - { - "Skutečná armáda Oceánie", - "Náboženská organizace", - "Údajná tajná organizace odporu; není jisté, zda existuje", - "Odbory prolety", - }, - 2, - "Bratrstvo zmiňuje Goldstein i O'Brien, ale kniha nikdy nepotvrdí, " - "že doopravdy existuje – může jít o past strany.", - }, - { - "Kdo je Emmanuel Goldstein?", - { - "Ministr pravdy", - "Oficiální nepřítel státu a údajný vůdce Bratrstva", - "Winstonův kolega", - "Velký bratrův dvojník", - }, - 1, - "Goldstein je terčem dvouminutovky nenávisti. Má ztělesňovat " - "nepřítele, proti kterému strana sjednocuje občany.", - }, - { - "Co je dvojité myšlení (doublethink)?", - { - "Schopnost myslet ve dvou jazycích", - "Zdvojení osobnosti", - "Schopnost věřit dvěma protikladným tvrzením zároveň", - "Tajné zapisování myšlenek", - }, - 2, - "Dvojité myšlení je jádro stranické ideologie – člověk přijme i " - "zjevné rozpory, jako „válka je mír“.", - }, - { - "Proč strana neustále přepisuje minulost?", - { - "Aby opravila chyby v archivech", - "Aby měla vždy pravdu a nepřítel jí nemohl dokázat opak", - "Aby ušetřila papír", - "Aby potěšila prolety", - }, - 1, - "Kdo ovládá minulost, ovládá i budoucnost. Přepisováním historie " - "strana udržuje absolutní kontrolu nad pravdou.", - }, - { - "Co je zločin myšlení (thoughtcrime)?", - { - "Pouhá myšlenka nebo názor, který se nelíbí straně", - "Krádež státního majetku", - "Nelegální obchod", - "Opomenutí dvouminutovky", - }, - 0, - "Strana trestá už samotné myšlenky. Winston se proviní tím, že si " - "do deníku napíše „Dolů s Velkým bratrem“.", - }, - { - "Kdo je pan Charrington a jaké je jeho skutečné postavení?", - { - "Winstonův přítel a majitel hospody", - "Proletářský básník", - "Zdánlivě starý majitel obchodu, ve skutečnosti agent Policie " - "myšlení", - "Člen Bratrstva", - }, - 2, - "Charrington Winstonovi pronajme pokoj bez teleobrazovky, ale " - "právě on nakonec oba milence udá.", - }, - { - "Co je místnost 101?", - { - "Winstonova cela na policii", - "Skladiště knih", - "Místnost, ve které každého čeká jeho největší strach", - "Zasedací místnost vnitřní strany", - }, - 2, - "Místnost 101 je vrcholný mučicí nástroj. Winstonovi v ní hrozí " - "krysy – jeho největší fobie.", - }, - { - "Jak skončí vztah Winstona a Julie?", - { - "Utečou spolu do Eurasie", - "Vezmou se a žijí svobodně", - "Winston se stane členem Bratrstva", - "Zradí se a nakonec se přestanou milovat", - }, - 3, - "Oba jsou po mučení zlomení a vzájemně se zradí. Na konci už " - "k sobě nic necítí.", - }, - { - "Co znamená závěrečná věta „Miloval Velkého bratra“?", - { - "Winstonův vzdor se změnil v pokornou lásku k režimu", - "Winston se stal novým vůdcem", - "Byl to jen Winstonův sen", - "Julie mu to řekla", - }, - 0, - "Winston byl vnitřně zlomen. Přestal být sám sebou a nakonec " - "režim opravdu přijal za svůj.", - }, - { - "Které tvrzení NENÍ jedním z hlavních témat románu?", - { - "Moc a absolutní kontrola", - "Pravda a přepisování historie", - "Svoboda a identita", - "Idylický venkovský život", - }, - 3, - "1984 je temná antiutopie. Hlavními tématy jsou moc, kontrola, " - "manipulace s pravdou a ztráta svobody, ne venkovská idyla.", - }, - { - "V jakém roce byl román 1984 poprvé vydán?", - {"1936", "1949", "1954", "1984"}, - 1, - "Román vyšel v roce 1949; letopočet 1984 označuje blízkou " - "budoucnost, do níž Orwell příběh zasadil.", - }, - { - "Které další Orwellovo dílo se dá s 1984 srovnat?", - {"Farma zvířat", "Velký Gatsby", "Zločin a trest", "Babička"}, - 0, - "Obě Orwellova díla varují před totalitou. Farma zvířat ji líčí " - "alegoricky pomocí zvířat, 1984 očima jedince.", - }, - { - "Co je „dvouminutovka nenávisti“?", - { - "Krátká každodenní akce, při níž občané společně nenávidí " - "Goldsteina a nepřítele", - "Pravidelná modlitba ke Velkému bratrovi", - "Sportovní přestávka ve škole", - "Porada vedení ministerstva", - }, - 0, - "Slouží k uvolnění a přesměrování agrese občanů na nepřítele " - "státu, čímž strana posiluje svou moc.", - }, - { - "Proč je podle knihy válka pro systém nezbytná?", - { - "Přináší mír a blahobyt", - "Udržuje strach, spotřebovává výrobu a zachovává chudobu " - "i hierarchii", - "Rozvíjí vědu a techniku", - "Sjednocuje vládu s prolety", - }, - 1, - "Trvalá válka pohlcuje nadbytečnou produkci a udržuje lidi ve " - "strachu i chudobě, takže se nemohou vzbouřit.", - }, - { - "Jaký je rozdíl mezi vnějšími členy strany a prolety?", - { - "Proleti mají více práv než členové strany", - "Vnější členové jsou dozíráni, kdežto proleti žijí v chudobě " - "a strana o ně nestojí", - "Není mezi nimi žádný rozdíl", - "Proleti tvoří vedení strany", - }, - 1, - "Proleti tvoří asi 85 % obyvatel. Žijí v bídě a jsou považováni " - "za neškodné, dokud si neuvědomí svou sílu.", - }, - { - "Jak strana kontroluje sexualitu a osobní vztahy?", - { - "Podporuje volnou lásku a nezávislost", - "Potlačuje lásku a sexualitu, děti vede k oddanosti straně", - "Zakazuje veškerá manželství", - "Povoluje vztahy jen s prolety", - }, - 1, - "Strana chce, aby veškerá oddanost a energie patřily jí. Proto " - "podporuje zdrženlivost a vede děti v Antisexuální lize mládeže.", - }, - { - "Co symbolizuje papírové těžítko, které si Winston koupí?", - { - "Jeho nenávist ke Goldsteinovi", - "Kousek krásy a minulosti, kterou už nelze vrátit", - "Moc Velkého bratra", - "Lásku k Julii", - }, - 1, - "Těžítko je drobný, krásný předmět z minulosti. Pro Winstona " - "ztělesňuje svět, který strana zničila.", - }, - { - "Jaké poselství chtěl Orwell románem nejspíš předat?", - { - "Varování před totalitou a ztrátou svobody i pravdy", - "Oslavu technického pokroku", - "Návod, jak založit stát", - "Kritiku sportu a zábavy", - }, - 0, - "1984 je varování: když lidé přestanou bránit pravdu a svobodu, " - "mohou o ně nenávratně přijít.", - }, -}; - -#define LIT_NQ ((int)G_N_ELEMENTS(lit_qs)) - -static const LitQ fuks_qs[] = { - { - "Kdo je hlavní postava románu a jaké je jeho povolání?", - { - "Pan Kopfrkingl – zaměstnanec krematoria", - "Willi Reinke – nacistický důstojník", - "Dr. Bettelheim – psychiatr", - "Pan Kopfrkingl – ředitel školy", - }, - 0, - "Hlavní postavou je pan Kopfrkingl, spořádaný zaměstnanec krematoria, " - "který svou práci vnímá jako poslání.", - }, - { - "V jakém prostředí pan Kopfrkingl pracuje?", - {"V nemocnici", "V krematoriu", "V divadle", "Ve škole"}, - 1, - "Kopfrkingl pracuje v krematoriu, kde má na starosti zpopelňování " - "zemřelých.", - }, - { - "V jaké historické době se děj románu odehrává?", - { - "Za první republiky", - "Za protektorátu Čechy a Morava (před a během 2. světové války)", - "Po roce 1989", - "V 19. století", - }, - 1, - "Román se odehrává v době nastupujícího nacismu a protektorátu, " - "který umožňuje Kopfrkinglovu proměnu.", - }, - { - "Jak se proměňuje hlavní hrdina v průběhu příběhu?", - { - "Z laskavého spořádaného muže v chladnokrevného vraha a fanatika", - "Z vraha v kajícníka", - "Z chudáka v boháče", - "Vůbec se nemění", - }, - 0, - "Kopfrkingl se postupně mění v člověka, který vraždí své blízké a " - "ospravedlňuje to vyšším dobrem.", - }, - { - "Jaký je vztah pana Kopfrkingla k jeho rodině na začátku knihy?", - { - "Nenávidí je", - "Je starostlivý, zdvořilý a především spořádaný", - "S rodinou se nezná", - "Týrá je", - }, - 1, - "Na začátku působí jako vzorný manžel a otec, posedlý řádem a " - "zdvořilostí.", - }, - { - "Jak se jmenuje manželka pana Kopfrkingla a jaký je jejich vztah?", - { - "Marie – milují se", - "Lakmé – formálně zdvořilý, chladný vztah", - "Zina – nenávidí se", - "Julie – jsou rozvedení", - }, - 1, - "Manželka se jmenuje Lakmé. Jejich vztah je spíš zdvořilá forma než " - "opravdová láska.", - }, - { - "Jaký je vztah pana Kopfrkingla k dětem, Zině a Mílovi?", - { - "Miluje je víc než sebe", - "Chová se k nim odtažitě, jako k součásti řádu", - "Nevidí je", - "Jsou adoptované", - }, - 1, - "K dětem je odměřený; vnímá je spíš jako součást svého spořádaného " - "světa než jako milované bytosti.", - }, - { - "Kdo je Willi Reinke a jakou roli hraje v proměně hlavního hrdiny?", - { - "Soused z krematoria", - "Německý úředník a bývalý voják, který Kopfrkingla ovlivní", - "Kopfrkinglův bratr", - "Lékař v nemocnici", - }, - 1, - "Reinke je Němec, který v Kopfrkinglovi probudí touhu po árijském " - "původu a kariéře.", - }, - { - "Jak Willi Reinke ovlivňuje Kopfrkinglovo smýšlení?", - { - "Přesvědčí ho, aby se přidal k nacistům a byl „lepší“", - "Nabádá ho k odchodu do zahraničí", - "Učí ho tibetštinu", - "Nijak ho neovlivní", - }, - 0, - "Reinke v něm posiluje antisemitismus a touhu po moci a uznání " - "v novém režimu.", - }, - { - "Jaký je Kopfrkinglův vztah ke krematoriu a smrti obecně?", - { - "Bojí se jich", - "Má je rád, kremaci vnímá jako krásný obřad osvobození", - "Nechce tam pracovat", - "Je mu to lhostejné", - }, - 1, - "Smrt a kremace jsou pro něj estetickým a filozofickým rituálem, ne " - "něčím hrůzným.", - }, - { - "Jak pan Kopfrkingl vnímá a popisuje proces kremace?", - { - "Jako nutné zlo", - "Jako vznešený, očistný obřad, o kterém rád mluví", - "Jako hroznou povinnost", - "Nikdy o něm nemluví", - }, - 1, - "Kopfrkingl o kremaci hovoří básnivě a s nadšením, což ostře " - "kontrastuje s hrůzou jeho činů.", - }, - { - "Jaká je symbolika krematoria v celém románu?", - { - "Symbol naděje", - "Smrt, odlidštění a zvrácená ideologie, která z lidí dělá jen těla", - "Symbol lásky", - "Symbol mládí", - }, - 1, - "Krematorium je ústředním symbolem – odhaluje chladnou mašinerii " - "smrti, do níž se ideologie snaží proměnit člověka.", - }, - { - "Co symbolizuje Kopfrkinglova záliba v tibetské Knize mrtvých?", - { - "Jeho touhu po vědění a zvrácenou víru ve vlastní výjimečnost", - "Historický zájem o Asii", - "Strach ze smrti", - "Lásku k manželce", - }, - 0, - "Kopfrkingl si z ní vybírá jen to, co se hodí k ospravedlnění jeho " - "činů a jeho pocitu vyvolenosti.", - }, - { - "Jak se v knize projevuje motiv buddhismu a reinkarnace?", - { - "Kopfrkingl jimi ospravedlňuje smrt jako „osvobození duše“", - "Postavy se modlí k Bohu", - "Nikde se neobjevuje", - "Je to hlavní téma manželky", - }, - 0, - "Reinkarnace a „osvobození od utrpení“ se v jeho mysli zvrhávají " - "v právo zabíjet.", - }, - { - "Jak Kopfrkingl zneužívá filozofické a náboženské myšlenky?", - { - "Ospravedlňuje jimi vlastní vraždy jako službu vyššímu dobru", - "Pomáhá jimi druhým", - "Odmítá je", - "Používá je jen v práci", - }, - 0, - "Z vznešených idejí si staví masku, za kterou skrývá krutost a touhu " - "po moci.", - }, - { - "Jak se postupně mění Kopfrkinglova mluva a způsob vyjadřování?", - { - "Začíná mluvit vulgárně", - "Mění se v patetickou, ráznou řeč plnou frází o řádu a osvobození", - "Přestane mluvit", - "Od začátku mluví jen německy", - }, - 1, - "Jeho zdvořilá mluvnost se postupně mění v ideologické fráze a " - "bezcitný patos.", - }, - { - "Jaké opakující se fráze nebo návyky pana Kopfrkingla si všímáš?", - { - "Neustále se ptá na počasí", - "Opakuje „to je takové“, „vidíte“ a lpí na zdvořilosti", - "Zpívá si", - "Mluví jen o jídle", - }, - 1, - "Opakující se fráze a zdvořilostní obraty vytvářejí rytmus, který je " - "čím dál tím děsivější.", - }, - { - "Jaký je vypravěčský styl románu (ich-forma, er-forma)?", - { - "Er-forma bez vnitřního světa", - "Ich-forma – vypráví sám Kopfrkingl", - "Deníková forma", - "Forma dopisů", - }, - 1, - "Ich-forma je klíčová: čtenář sleduje svět zkreslený Kopfrkinglovou " - "myslí a sám postupně propadá jeho logice.", - }, - { - "Jak se v knize projevuje černý humor a groteska?", - { - "Vážné scény jsou líčeny s odstupem a absurditou", - "Kniha je čistě vážná", - "Humor je jediný žánr", - "V knize se neprojevuje", - }, - 0, - "Groteskní kontrast mezi slavnostním vyprávěním a hrůzou vytváří " - "mrazivý černý humor.", - }, - { - "Jak kontrastuje banalita každodenního života s hrůzností činů?", - { - "Vůbec nesouvisí", - "Všední detaily a zdvořilost činí hrůzu ještě děsivější", - "Hrůza je potlačena", - "Den je popsán jen jednou", - }, - 1, - "Fuks zesiluje otřes tím, že vraždění je popisováno stejně klidně " - "jako ranní káva nebo kremace.", - }, - { - "Jak se v knize projevuje antisemitismus?", - { - "Od začátku otevřeně", - "Postupně, nejdřív v náznacích a vlivem Reinkeho", - "Nikdy", - "Jen mimochodem v závěru", - }, - 1, - "Kopfrkinglův antisemitismus se rodí pozvolna a je živen dobovou " - "atmosférou i Reinkem.", - }, - { - "Jak nacistická ideologie postupně prostupuje Kopfrkinglovo myšlení?", - { - "Odmítá ji", - "Přijímá ji jako vyšší řád a ospravedlnění vlastní výjimečnosti", - "Nerozumí jí", - "Zajímá ho jen hudba", - }, - 1, - "Ideologie se mu stává nástrojem kariéry i vnitřním ospravedlněním " - "vražd.", - }, - { - "Jak se mění Kopfrkinglův vztah k manželce kvůli jejímu původu?", - { - "Začne ji milovat víc", - "Odcizí se jí, protože je židovského původu", - "Nijak se nemění", - "Odstěhují se od sebe", - }, - 1, - "Kvůli jejímu původu ji přestane vnímat jako rovnocennou a nakonec " - "ji zabije.", - }, - { - "Co se stane s Kopfrkinglovou rodinou ve druhé polovině románu?", - { - "Odstěhují se", - "Kopfrkingl svou ženu i děti zabije", - "Všichni přežijí", - "Zachrání je Reinke", - }, - 1, - "Pod vlivem ideologie Kopfrkingl vyvraždí vlastní rodinu a považuje " - "to za „osvobození“.", - }, - { - "Jak Kopfrkingl zdůvodňuje vraždu vlastní ženy?", - { - "Zlobila se na něj", - "Že je židovského původu a překáží jeho kariéře", - "Že ho podváděla", - "Nijak ji nezdůvodňuje", - }, - 1, - "Svou ženu zabije mimo jiné proto, že je židovského původu, tedy " - "„méněcenná“ pro nový režim.", - }, - { - "Jakým způsobem Kopfrkingl vraždí své blízké?", - { - "Ve zlosti a afektu", - "Chladně a s pocitem, že je „osvobozuje od utrpení“", - "Omylem", - "Na příkaz úřadů", - }, - 1, - "Vraždí klidně, jako by vykonával bohulibý úkon, a svou krutost si " - "vykládá jako soucit.", - }, - { - "Jak souvisí přesvědčení o „osvobození“ s jeho vražednými činy?", - { - "Dává mu zdání vyššího smyslu, kterým si vraždy ospravedlňuje", - "Nemá s nimi nic společného", - "Brání mu v zabíjení", - "Je to jen náhodná fráze", - }, - 0, - "Zvrácená víra v osvobození od utrpení mu slouží jako mravní alibi " - "pro vraždy.", - }, - { - "Jaký je vztah pana Kopfrkingla k postavě Dr. Bettelheima?", - { - "Obdivuje ho a rád s ním mluví", - "Nenávidí ho", - "Nikdy se nepotkají", - "Je to jeho nadřízený", - }, - 0, - "S doktorem Bettelheimem vede Kopfrkingl své „filozofické“ rozhovory " - "o smrti a lidskosti.", - }, - { - "Jak se mění společenské postavení pana Kopfrkingla v době okupace?", - { - "Upadá", - "Stoupá – díky režimu a touze po árijském původu", - "Nemění se", - "Odchází do penze", - }, - 1, - "Spolu s nacistickou mocí roste i Kopfrkinglova kariéra a " - "sebevědomí.", - }, - { - "Jaký je symbolický význam jména Kopfrkingl?", - { - "Zdánlivě úřednické, ale zní hrozivě – naznačuje zvrácenost", - "Je to běžné české jméno", - "Znamená „laskavý“", - "Je to pseudonym", - }, - 0, - "Zvukomalebné jméno působí úředně a zároveň hrozivě, což podtrhuje " - "dvojí tvář postavy.", - }, - { - "Jak funguje motiv masek, divadla a přetvářky?", - { - "Postavy nosí masky dobroty, pod nimiž se skrývá krutost", - "V knize jsou jen skutečné divadelní masky", - "Motiv se neobjevuje", - "Masky symbolizují lásku", - }, - 0, - "Přetvářka a předstíraná spořádanost jsou ústřední – zlo se tváří " - "jako slušnost.", - }, - { - "Jaký je vztah mezi soukromým a kolektivním šílenstvím doby?", - { - "Kopfrkinglovo osobní šílenství roste spolu s ideologií doby", - "Nijak nesouvisí", - "Doba je klidná a šťastná", - "Lidé režim jednomyslně odmítají", - }, - 0, - "Fuks ukazuje, jak se individuální porucha napojí na kolektivní " - "ideologii a čerpá z ní sílu.", - }, - { - "Jak končí román a co se stane s panem Kopfrkinglem na konci?", - { - "Uteče do zahraničí", - "Je zatčen a zničen", - "Stane se hrdinou", - "Věří, že je vtělením Dalajlámy, a zůstává zaslepený", - }, - 3, - "Kopfrkinglova zaslepenost vrcholí přesvědčením o vlastní božskosti; " - "jeho zvrácená víra ho neopouští.", - }, - { - "Jak je Spalovač mrtvol adaptován filmově?", - { - "Film Juraje Herze je vizuálně expresivní a patří k vrcholům " - "české kinematografie", - "Byl zfilmován jen v zahraničí", - "Film neexistuje", - "Vznikl jako animovaný seriál", - }, - 0, - "Známá filmová verze je od režiséra Juraje Herze z roku 1968.", - }, - { - "Které další dílo Ladislava Fukse se dá srovnat s touto knihou?", - { - "Pan Theodor Mundstock nebo Myši Natálie Mooshabrové", - "Farma zvířat", - "R.U.R.", - "Babička", - }, - 0, - "Fuks se opakovaně zabýval osudem židovských postav a atmosférou " - "strachu; srovnat lze např. Pana Theodora Mundstocka.", - }, - { - "Jaká jsou hlavní témata románu?", - { - "Moc, manipulace, ideologie, násilí a přetvářka", - "Láska a dobrodružství", - "Sport a přátelství", - "Příroda a vesmír", - }, - 0, - "Kniha zkoumá, jak se obyčejný člověk přizpůsobí zlu a stane se jeho " - "nástrojem.", - }, - { - "Jaké poselství podle tebe chtěl Ladislav Fuks knihou předat?", - { - "Varování před manipulací a tím, jak se zlo rodí z banality a " - "lhostejnosti", - "Oslavu války", - "Návod k podnikání", - "Kritiku školství", - }, - 0, - "Fuks ukazuje, že hrůza může vzniknout z poslušnosti a touhy být " - "„lepší“ než ostatní.", - }, -}; - -#define FUKS_NQ ((int)G_N_ELEMENTS(fuks_qs)) - -typedef struct { - const LitQ *qs; - int n; - int idx; - int score; - int answered; - int finished; - GtkWidget *progress; - GtkWidget *score_lbl; - GtkWidget *prompt; - GtkWidget *grid; - GtkWidget *opts[4]; - GtkWidget *opt_lbl[4]; - GtkWidget *expl; - GtkWidget *next; -} LitQuiz; - -static void lit_quiz_show(LitQuiz *z) { - const LitQ *q = &z->qs[z->idx]; - char buf[128]; - - g_snprintf(buf, sizeof(buf), tr("lit_question_fmt"), z->idx + 1, z->n); - gtk_label_set_text(GTK_LABEL(z->progress), buf); - g_snprintf(buf, sizeof(buf), tr("lit_score_fmt"), z->score, z->n); - gtk_label_set_text(GTK_LABEL(z->score_lbl), buf); - - gtk_label_set_text(GTK_LABEL(z->prompt), q->q); - for (int i = 0; i < 4; i++) { - gtk_label_set_text(GTK_LABEL(z->opt_lbl[i]), q->opts[i]); - gtk_widget_remove_css_class(z->opts[i], "ok"); - gtk_widget_remove_css_class(z->opts[i], "wrong"); - gtk_widget_set_sensitive(z->opts[i], TRUE); - } - gtk_widget_set_visible(z->grid, TRUE); - gtk_widget_set_visible(z->expl, FALSE); - gtk_widget_set_visible(z->next, FALSE); - gtk_button_set_label(GTK_BUTTON(z->next), tr("lit_next")); - z->answered = 0; - z->finished = 0; -} - -static void lit_quiz_finish(LitQuiz *z) { - char buf[128]; - - z->finished = 1; - gtk_label_set_text(GTK_LABEL(z->progress), tr("lit_finished")); - gtk_label_set_text(GTK_LABEL(z->prompt), tr("lit_finished_text")); - g_snprintf(buf, sizeof(buf), tr("lit_score_fmt"), z->score, z->n); - gtk_label_set_text(GTK_LABEL(z->score_lbl), buf); - gtk_widget_set_visible(z->grid, FALSE); - gtk_widget_set_visible(z->expl, FALSE); - gtk_widget_set_visible(z->next, TRUE); - gtk_button_set_label(GTK_BUTTON(z->next), tr("lit_again")); -} - -static void lit_opt_clicked(GtkButton *button, gpointer data) { - LitQuiz *z = data; - int chosen = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "idx")); - const LitQ *q; - char buf[128]; - - if (z->answered) - return; - z->answered = 1; - q = &z->qs[z->idx]; - - for (int i = 0; i < 4; i++) - gtk_widget_set_sensitive(z->opts[i], FALSE); - - gtk_widget_add_css_class(z->opts[q->correct], "ok"); - if (chosen == q->correct) - z->score++; - else - gtk_widget_add_css_class(z->opts[chosen], "wrong"); - - g_snprintf(buf, sizeof(buf), tr("lit_score_fmt"), z->score, z->n); - gtk_label_set_text(GTK_LABEL(z->score_lbl), buf); - - gtk_label_set_text(GTK_LABEL(z->expl), q->expl); - gtk_widget_set_visible(z->expl, TRUE); - - gtk_button_set_label(GTK_BUTTON(z->next), - z->idx + 1 >= z->n ? tr("lit_show_result") - : tr("lit_next")); - gtk_widget_set_visible(z->next, TRUE); -} - -static void lit_next_clicked(GtkButton *button, gpointer data) { - LitQuiz *z = data; - - (void)button; - - if (z->finished) { - z->finished = 0; - z->idx = 0; - z->score = 0; - lit_quiz_show(z); - return; - } - if (z->idx + 1 >= z->n) { - lit_quiz_finish(z); - return; - } - z->idx++; - lit_quiz_show(z); -} - -static GtkWidget *lit_quiz_page(const LitQ *qs, int n, const char *back, - const char *title, const char *sub) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *box; - GtkWidget *head; - LitQuiz *z = g_new0(LitQuiz, 1); - - z->qs = qs; - z->n = n; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back, title, sub)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_margin_start(box, 6); - gtk_widget_set_margin_end(box, 6); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), box); - - head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_append(GTK_BOX(box), head); - - z->progress = gtk_label_new(""); - gtk_widget_set_halign(z->progress, GTK_ALIGN_START); - gtk_widget_set_hexpand(z->progress, TRUE); - gtk_label_set_xalign(GTK_LABEL(z->progress), 0.0); - gtk_widget_add_css_class(z->progress, "lit-progress"); - gtk_box_append(GTK_BOX(head), z->progress); - - z->score_lbl = gtk_label_new(""); - gtk_widget_set_halign(z->score_lbl, GTK_ALIGN_END); - gtk_widget_add_css_class(z->score_lbl, "lit-score"); - gtk_box_append(GTK_BOX(head), z->score_lbl); - - z->prompt = gtk_label_new(""); - gtk_widget_set_halign(z->prompt, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(z->prompt), TRUE); - gtk_widget_set_margin_top(z->prompt, 4); - gtk_widget_add_css_class(z->prompt, "lit-prompt"); - gtk_box_append(GTK_BOX(box), z->prompt); - - z->grid = gtk_grid_new(); - gtk_grid_set_row_spacing(GTK_GRID(z->grid), 12); - gtk_grid_set_column_spacing(GTK_GRID(z->grid), 12); - gtk_grid_set_row_homogeneous(GTK_GRID(z->grid), TRUE); - gtk_grid_set_column_homogeneous(GTK_GRID(z->grid), TRUE); - gtk_widget_set_vexpand(z->grid, TRUE); - gtk_box_append(GTK_BOX(box), z->grid); - - for (int i = 0; i < 4; i++) { - GtkWidget *btn = gtk_button_new(); - GtkWidget *lbl; - char cls[16]; - - lbl = gtk_label_new(""); - gtk_label_set_wrap(GTK_LABEL(lbl), TRUE); - gtk_label_set_justify(GTK_LABEL(lbl), GTK_JUSTIFY_CENTER); - gtk_label_set_max_width_chars(GTK_LABEL(lbl), 26); - - g_snprintf(cls, sizeof(cls), "kahoot-%d", i); - gtk_widget_add_css_class(btn, "kahoot-opt"); - gtk_widget_add_css_class(btn, cls); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_vexpand(btn, TRUE); - gtk_button_set_child(GTK_BUTTON(btn), lbl); - g_object_set_data(G_OBJECT(btn), "idx", GINT_TO_POINTER(i)); - g_signal_connect(btn, "clicked", G_CALLBACK(lit_opt_clicked), z); - - z->opts[i] = btn; - z->opt_lbl[i] = lbl; - gtk_grid_attach(GTK_GRID(z->grid), btn, i % 2, i / 2, 1, 1); - } - - z->expl = gtk_label_new(""); - gtk_widget_set_halign(z->expl, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(z->expl), TRUE); - gtk_label_set_xalign(GTK_LABEL(z->expl), 0.0); - gtk_widget_add_css_class(z->expl, "lit-expl"); - gtk_widget_set_visible(z->expl, FALSE); - gtk_box_append(GTK_BOX(box), z->expl); - - z->next = gtk_button_new(); - i18n_bind(z->next, "lit_next", 1); - gtk_widget_add_css_class(z->next, "btn-primary"); - gtk_widget_set_halign(z->next, GTK_ALIGN_END); - gtk_widget_set_margin_top(z->next, 6); - gtk_widget_set_visible(z->next, FALSE); - gtk_box_append(GTK_BOX(box), z->next); - g_signal_connect(z->next, "clicked", G_CALLBACK(lit_next_clicked), z); - - lit_quiz_show(z); - - g_object_set_data(G_OBJECT(page), "lit-quiz", z); - return page; -} - -GtkWidget *build_cetba1984_quiz_page(void) { - return lit_quiz_page(lit_qs, LIT_NQ, "cetba1984", - "lit_quiz_title", "lit_quiz_sub"); -} - -GtkWidget *build_cetba_fuks_quiz_page(void) { - return lit_quiz_page(fuks_qs, FUKS_NQ, "cetbaFuks", - "lit_fuks_quiz_title", "lit_fuks_quiz_sub"); -} - -/* ------------------------------------------------------------------ */ -/* Sestavte děj (drag & drop) */ -/* ------------------------------------------------------------------ */ - -static const AssemblyItem lit_plot_items[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Winston upravuje historii na Ministerstvu pravdy", - "Seznámí se s Julií a začnou se tajně scházet", - "Pronajme si pokoj nad obchodem pana Charringtona", - "Přečte Goldsteinovu knihu u O'Briena", - "Jsou zatčeni Policií myšlení", - "Winston se zlomí v místnosti 101", - }, - 6, - }, -}; - -static const char *lit_plot_meaning[] = { - "Správné pořadí: přepisování historie → seznámení s Julií → " - "pronájem pokoje → četba Goldsteinovy knihy → zatčení → místnost 101.", -}; - -static UnitCtx lit_plot_unit; - -GtkWidget *build_cetba1984_plot_page(void) { - lit_plot_unit.page = "cetba1984"; - lit_plot_unit.progress_file = app_progress_cetba; - return build_assembly(&lit_plot_unit, tr("lit_plot_title"), - "lit_plot_sub", 1, lit_plot_items, - lit_plot_meaning, 1); -} - -static const AssemblyItem fuks_plot_items[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Kopfrkingl je spořádaným zaměstnancem krematoria", - "Seznámí se s Willim Reinkem", - "Začne věřit v árijskou nadřazenost", - "Postupně se odcizí své rodině", - "Zabije ženu a děti jako „osvobození“", - "Na konci se považuje za vtělení Dalajlámy", - }, - 6, - }, -}; - -static const char *fuks_plot_meaning[] = { - "Správné pořadí: spořádaný úředník → setkání s Reinkem → árijská " - "ideologie → odcizení rodině → vraždy → přesvědčení o vlastní " - "božskosti.", -}; - -GtkWidget *build_cetba_fuks_plot_page(void) { - lit_plot_unit.page = "cetbaFuks"; - lit_plot_unit.progress_file = app_progress_cetba; - return build_assembly(&lit_plot_unit, tr("lit_fuks_plot_title"), - "lit_fuks_plot_sub", 1, fuks_plot_items, - fuks_plot_meaning, 1); -} - -/* ------------------------------------------------------------------ */ -/* Reading list and 1984 overview */ -/* ------------------------------------------------------------------ */ - -static GtkWidget *lit_link_card_ex(const char *target, const char *title, - const char *sub, - GtkDrawingAreaDrawFunc icon, - GCallback clicked) { - GtkWidget *btn = gtk_button_new(); - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - GtkWidget *ic; - GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3); - GtkWidget *t = gtk_label_new(NULL); - GtkWidget *s = gtk_label_new(NULL); - - gtk_widget_add_css_class(btn, "lit-link"); - gtk_widget_set_hexpand(btn, TRUE); - - ic = icon_area_new(icon, 0, 0, 0, 34); - gtk_widget_set_valign(ic, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), ic); - - gtk_widget_set_valign(box, GTK_ALIGN_CENTER); - gtk_widget_set_hexpand(box, TRUE); - gtk_widget_set_halign(t, GTK_ALIGN_START); - gtk_label_set_xalign(GTK_LABEL(t), 0.0); - gtk_label_set_wrap(GTK_LABEL(t), TRUE); - gtk_label_set_max_width_chars(GTK_LABEL(t), 40); - gtk_widget_add_css_class(t, "lit-link-title"); - i18n_bind(t, title, 0); - gtk_box_append(GTK_BOX(box), t); - - gtk_widget_set_halign(s, GTK_ALIGN_START); - gtk_label_set_xalign(GTK_LABEL(s), 0.0); - gtk_label_set_wrap(GTK_LABEL(s), TRUE); - gtk_label_set_max_width_chars(GTK_LABEL(s), 46); - gtk_widget_add_css_class(s, "lit-link-sub"); - i18n_bind(s, sub, 0); - gtk_box_append(GTK_BOX(box), s); - - gtk_box_append(GTK_BOX(row), box); - gtk_button_set_child(GTK_BUTTON(btn), row); - if (target) - g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free); - g_signal_connect(btn, "clicked", - clicked ? clicked : G_CALLBACK(on_nav_clicked), NULL); - return btn; -} - -static GtkWidget *lit_link_card(const char *target, const char *title, - const char *sub, GtkDrawingAreaDrawFunc icon) { - return lit_link_card_ex(target, title, sub, icon, NULL); -} - -static void lit_note_card(GtkWidget *parent, const char *title, - GtkDrawingAreaDrawFunc icon, - const char *const *lines) { - GtkWidget *card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - GtkWidget *head; - GtkWidget *ic; - GtkWidget *t; - - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_margin_bottom(card, 14); - gtk_box_append(GTK_BOX(parent), card); - - head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_append(GTK_BOX(card), head); - - ic = icon_area_new(icon, 0, 0, 0, 26); - gtk_widget_set_valign(ic, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(head), ic); - - t = gtk_label_new(title); - gtk_widget_set_halign(t, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(t), TRUE); - gtk_widget_set_valign(t, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(t, "notes-title"); - gtk_box_append(GTK_BOX(head), t); - - for (int i = 0; lines[i]; i++) { - GtkWidget *l = gtk_label_new(lines[i]); - - gtk_widget_set_halign(l, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(l), TRUE); - gtk_label_set_xalign(GTK_LABEL(l), 0.0); - gtk_widget_add_css_class(l, "notes-body"); - gtk_box_append(GTK_BOX(card), l); - } -} - -/* ------------------------------------------------------------------ */ -/* Reading roadmap (Maturitní četba) */ -/* ------------------------------------------------------------------ */ - -#include "cetba_catalog.inc" -#include "cetba_book_notes.inc" -#include "cetba_book_exercises.inc" - -static int stub_book_idx = -1; -static GtkWidget *stub_title_lbl; -static GtkWidget *stub_links_box; -static GtkWidget *stub_notes_box; -static LitQuiz *stub_quiz; -static GtkWidget *stub_plot_host; -static UnitCtx stub_plot_unit; - -static void cetba_prepare_stub_quiz(void) { - const BookExPack *p; - - if (!stub_quiz || stub_book_idx < 0 || stub_book_idx >= BOOK_NODES) - return; - p = &book_ex_packs[stub_book_idx]; - if (!p->qs || p->nq <= 0) - return; - stub_quiz->qs = p->qs; - stub_quiz->n = p->nq; - stub_quiz->idx = 0; - stub_quiz->score = 0; - stub_quiz->answered = 0; - stub_quiz->finished = 0; - lit_quiz_show(stub_quiz); -} - -static void cetba_prepare_stub_plot(void) { - GtkWidget *child; - const BookExPack *p; - GtkWidget *inner; - - if (!stub_plot_host || stub_book_idx < 0 || stub_book_idx >= BOOK_NODES) - return; - - while ((child = gtk_widget_get_first_child(stub_plot_host))) - gtk_box_remove(GTK_BOX(stub_plot_host), child); - - p = &book_ex_packs[stub_book_idx]; - if (!p->plot || p->nplot <= 0) - return; - - stub_plot_unit.page = "cetbastub"; - stub_plot_unit.progress_file = app_progress_cetba; - inner = build_assembly(&stub_plot_unit, tr("lit_plot_title"), - "lit_plot_sub", 1, p->plot, p->plot_meaning, - p->nplot); - gtk_widget_set_hexpand(inner, TRUE); - gtk_widget_set_vexpand(inner, TRUE); - gtk_box_append(GTK_BOX(stub_plot_host), inner); -} - -static void on_stub_quiz_clicked(GtkButton *button, gpointer user_data) { - (void)button; - (void)user_data; - cetba_prepare_stub_quiz(); - if (main_stack) - show_page("cetbastubquiz", 1); -} - -static void on_stub_plot_clicked(GtkButton *button, gpointer user_data) { - (void)button; - (void)user_data; - cetba_prepare_stub_plot(); - if (main_stack) - show_page("cetbastubdej", 1); -} - -static GtkWidget *book_rail; -static GtkWidget *book_nodes[BOOK_NODES]; -static GtkWidget *book_labels[BOOK_NODES]; -static double book_cx[BOOK_NODES]; -static double book_cy[BOOK_NODES]; -static int book_cw = 540; -static int book_ch = 300; - -static void book_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= BOOK_NODES - 1) { k = BOOK_NODES - 2; u = 1.0; } - - p1x = book_cx[k]; p1y = book_cy[k]; - p2x = book_cx[k + 1]; p2y = book_cy[k + 1]; - if (k - 1 >= 0) { p0x = book_cx[k - 1]; p0y = book_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < BOOK_NODES) { p3x = book_cx[k + 2]; p3y = book_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -static void book_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 48.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - - if (n < 1) - n = 1; - book_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (int s = 1; s <= n; s++) { - book_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -static void book_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(BOOK_NODES - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= BOOK_NODES; rows++) { - int cols = (BOOK_NODES + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > BOOK_NODES) - rows = BOOK_NODES; - int cols = (BOOK_NODES + rows - 1) / rows; - if (cols < 1) - cols = 1; - book_cw = (int)(2.0 * ROAD_MX + (cols - 1) * PATH_SPAC); - book_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * cols; - int len = MIN(cols, BOOK_NODES - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (cols - 1 - c); - book_cx[i] = ROAD_MX + cc * PATH_SPAC; - book_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -static void draw_book_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double t_end = (double)(BOOK_NODES - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - (void)area; - (void)width; - (void)height; - (void)data; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - book_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - book_path(cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -void book_rail_theme_reset(void) { - if (book_rail) - gtk_widget_queue_draw(book_rail); -} - -static void rebuild_stub_about(int idx) { - GtkWidget *child; - const BookNotePack *pack; - const BookExPack *ex; - GtkDrawingAreaDrawFunc icons[4] = { - draw_book_icon, draw_globe_icon, draw_people_icon, draw_bulb_icon - }; - - if (idx < 0 || idx >= BOOK_NODES) - return; - - if (stub_links_box) { - while ((child = gtk_widget_get_first_child(stub_links_box))) - gtk_box_remove(GTK_BOX(stub_links_box), child); - ex = &book_ex_packs[idx]; - if (ex->qs && ex->nq > 0) - gtk_box_append(GTK_BOX(stub_links_box), - lit_link_card_ex(NULL, "book_quiz_heading", - "lit_quiz_sub", draw_quiz_icon, - G_CALLBACK(on_stub_quiz_clicked))); - if (ex->plot && ex->nplot > 0) - gtk_box_append(GTK_BOX(stub_links_box), - lit_link_card_ex(NULL, "lit_plot_title", - "lit_plot_sub", draw_order_icon, - G_CALLBACK(on_stub_plot_clicked))); - gtk_widget_set_visible(stub_links_box, - gtk_widget_get_first_child(stub_links_box) != NULL); - } - - if (!stub_notes_box) - return; - - while ((child = gtk_widget_get_first_child(stub_notes_box))) - gtk_box_remove(GTK_BOX(stub_notes_box), child); - - pack = &book_note_packs[idx]; - if (!pack->secs || pack->nsec <= 0) - return; - for (int i = 0; i < pack->nsec; i++) { - GtkDrawingAreaDrawFunc icon = icons[i < 4 ? i : 0]; - lit_note_card(stub_notes_box, pack->secs[i].title, icon, - pack->secs[i].lines); - } -} - -static void on_book_node_clicked(GtkButton *button, gpointer user_data) { - int idx = GPOINTER_TO_INT(user_data); - const char *target = book_defs[idx].target; - - (void)button; - if (!book_defs[idx].full) { - stub_book_idx = idx; - if (stub_title_lbl) - gtk_label_set_text(GTK_LABEL(stub_title_lbl), book_defs[idx].title); - rebuild_stub_about(idx); - } - if (main_stack && target) - show_page(target, 1); -} - -static GtkWidget *book_make_node(int i) { - GtkWidget *btn = gtk_button_new(); - GtkWidget *icon = icon_area_new(draw_book_badge_icon, 0, 0, 0, 48); - - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_size_request(btn, (int)NODE_SIZE, (int)NODE_SIZE); - - gtk_button_set_child(GTK_BUTTON(btn), icon); - - g_signal_connect(btn, "clicked", G_CALLBACK(on_book_node_clicked), - GINT_TO_POINTER(i)); - return btn; -} - -GtkWidget *build_readinglist_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - int i; - - book_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("czechmap", "Maturitní četba", "reading_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, book_cw, book_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - gtk_widget_set_margin_start(fixed, 24); - gtk_widget_set_margin_end(fixed, 24); - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, book_cw, book_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), draw_book_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - book_rail = rail; - - for (i = 0; i < BOOK_NODES; i++) { - GtkWidget *btn = book_make_node(i); - GtkWidget *name = gtk_label_new(book_defs[i].title); - - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - gtk_widget_add_css_class(name, "cz-label"); - - gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0); - gtk_fixed_put(GTK_FIXED(fixed), name, 0, 0); - - gtk_fixed_move(GTK_FIXED(fixed), btn, - (int)(book_cx[i] - NODE_SIZE / 2.0), - (int)(book_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(fixed), name, - (int)(book_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(book_cy[i] + NODE_SIZE / 2.0 + 10.0)); - - book_nodes[i] = btn; - book_labels[i] = name; - } - - return page; -} - -GtkWidget *build_cetba1984_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *box; - GtkWidget *links; - static const char *about[] = { - "Autor: George Orwell (vl. jm. Eric Arthur Blair)", - "Žánr: antiutopický (dystopický) román", - "Poprvé vydáno: 1949", - "Děj: Londýn, provincie Letopočet 1, stát Oceánie", - "Vyprávění: v er-formě, po deníkových zápiscích Winstona Smithe", - NULL, - }; - static const char *world[] = { - "Svět je rozdělen na tři supervelmoci: Oceánii, Eurasii a Východasii, " - "které spolu vedou trvalou válku.", - "Vládne jediná strana (Angsoc) v čele s kultem Velkého bratra.", - "Ministerstvo pravdy – přepisuje historii a vyrábí „pravdu“.", - "Ministerstvo lásky – mučírny a likvidace nepohodlných.", - "Ministerstvo hojnosti – plánuje hospodářství a drží lidi v " - "nedostatku.", - "Ministerstvo míru – vede válku.", - NULL, - }; - static const char *people[] = { - "Winston Smith – hlavní hrdina, přepisuje historii, touží po svobodě.", - "Julie – mladá členka strany, Winstonova tajná láska.", - "O'Brien – člen vnitřní strany, předstírá odboj a Winstona zničí.", - "Emmanuel Goldstein – nepřítel státu, údajný vůdce Bratrstva.", - "Velký bratr – symbol všemocné moci strany.", - "Pan Charrington – zdánlivý obchodník, ve skutečnosti agent.", - NULL, - }; - static const char *terms[] = { - "Newspeak – uměle zjednodušovaný jazyk, který omezuje myšlení.", - "Dvojité myšlení – ochota věřit dvěma protikladným pravdám.", - "Zločin myšlení – už samotná zakázaná myšlenka.", - "Policie myšlení – tajná policie, která zatýká a mučí.", - "Bratrstvo – možná neexistující odbojová organizace.", - "Místnost 101 – nejhlubší mučírna, pro každého jeho největší strach.", - NULL, - }; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("readinglist", "George Orwell – 1984", - "cetba1984_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_widget_set_margin_bottom(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), box); - - links = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_margin_bottom(links, 14); - gtk_box_append(GTK_BOX(box), links); - gtk_box_append(GTK_BOX(links), - lit_link_card("cetba1984quiz", "lit_quiz_title", - "lit_quiz_sub", draw_quiz_icon)); - gtk_box_append(GTK_BOX(links), - lit_link_card("cetba1984dej", "lit_plot_title", - "lit_plot_sub", draw_order_icon)); - - lit_note_card(box, "O knize", draw_book_icon, about); - lit_note_card(box, "Svět a strana", draw_globe_icon, world); - lit_note_card(box, "Postavy", draw_people_icon, people); - lit_note_card(box, "Klíčové pojmy", draw_bulb_icon, terms); - - return page; -} - -GtkWidget *build_cetba_fuks_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *box; - GtkWidget *links; - static const char *about[] = { - "Autor: Ladislav Fuks (1923–1994)", - "Žánr: psychologický román s prvky grotesky a hororu", - "Poprvé vydáno: 1967", - "Děj: Praha v době protektorátu (konec 30. let)", - "Vyprávění: ich-forma – vypráví sám pan Kopfrkingl", - NULL, - }; - static const char *world[] = { - "Děj se odehrává v protektorátu Čechy a Morava za nastupujícího " - "nacismu.", - "Atmosféru tvoří strach, přizpůsobování a touha zalíbit se moci.", - "Krematorium je symbolem smrti a odlidštění.", - "Antisemitismus a árijská ideologie postupně prostupují společnost.", - "Obyčejný úředník se mění v nástroj zla.", - NULL, - }; - static const char *people[] = { - "Pan Kopfrkingl – zaměstnanec krematoria, vypravěč a vrah své rodiny.", - "Lakmé – jeho žena, židovského původu.", - "Zina a Mil – jeho děti.", - "Willi Reinke – Němec, který Kopfrkingla přivede k nacismu.", - "Dr. Bettelheim – lékař, s nímž Kopfrkingl rozmlouvá o smrti.", - NULL, - }; - static const char *terms[] = { - "Krematorium – symbol smrti a zvrácené „očisty“.", - "Kniha mrtvých – tibetský text, který si Kopfrkingl překrucuje.", - "Reinkarnace a „osvobození“ – záminka pro vraždy.", - "Masky a přetvářka – zlo se tváří jako zdvořilost a řád.", - "Groteska a černý humor – hrůza podaná klidným, slavnostním tónem.", - "Voda a Vltava – motiv smrti a plynutí.", - NULL, - }; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("readinglist", "Ladislav Fuks – Spalovač mrtvol", - "cetbaFuks_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_widget_set_margin_bottom(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), box); - - links = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_margin_bottom(links, 14); - gtk_box_append(GTK_BOX(box), links); - gtk_box_append(GTK_BOX(links), - lit_link_card("cetbaFuksQuiz", "lit_fuks_quiz_title", - "lit_fuks_quiz_sub", draw_quiz_icon)); - gtk_box_append(GTK_BOX(links), - lit_link_card("cetbaFuksDej", "lit_fuks_plot_title", - "lit_fuks_plot_sub", draw_order_icon)); - - lit_note_card(box, "O knize", draw_book_icon, about); - lit_note_card(box, "Doba a svět", draw_globe_icon, world); - lit_note_card(box, "Postavy", draw_people_icon, people); - lit_note_card(box, "Klíčové motivy", draw_bulb_icon, terms); - - return page; -} - -GtkWidget *build_cetba_stub_page(void) { - GtkWidget *page; - GtkWidget *top; - GtkWidget *center; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *sub; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - top = gtk_center_box_new(); - gtk_widget_add_css_class(top, "page-top"); - gtk_widget_set_margin_top(top, 8); - gtk_widget_set_margin_bottom(top, 18); - gtk_center_box_set_start_widget(GTK_CENTER_BOX(top), - make_back_button("readinglist")); - - center = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_widget_set_valign(center, GTK_ALIGN_CENTER); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(top), center); - - stub_title_lbl = gtk_label_new("…"); - gtk_widget_set_halign(stub_title_lbl, GTK_ALIGN_CENTER); - gtk_label_set_wrap(GTK_LABEL(stub_title_lbl), TRUE); - gtk_widget_add_css_class(stub_title_lbl, "roadmap-title"); - gtk_box_append(GTK_BOX(center), stub_title_lbl); - - sub = gtk_label_new(NULL); - i18n_bind(sub, "cetba1984_sub", 0); - gtk_widget_set_halign(sub, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(sub, "roadmap-sub"); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_box_append(GTK_BOX(center), sub); - - gtk_box_append(GTK_BOX(page), top); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_widget_set_margin_bottom(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - stub_links_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_margin_bottom(stub_links_box, 14); - gtk_box_append(GTK_BOX(body), stub_links_box); - - stub_notes_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_append(GTK_BOX(body), stub_notes_box); - - return page; -} - -GtkWidget *build_cetba_stub_quiz_page(void) { - const LitQ *qs = book_ex_packs[0].qs; - int n = book_ex_packs[0].nq > 0 ? book_ex_packs[0].nq : 1; - GtkWidget *page; - - page = lit_quiz_page(qs, n, "cetbastub", - "book_quiz_heading", "lit_quiz_sub"); - stub_quiz = g_object_get_data(G_OBJECT(page), "lit-quiz"); - return page; -} - -GtkWidget *build_cetba_stub_plot_page(void) { - stub_plot_host = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(stub_plot_host, TRUE); - gtk_widget_set_vexpand(stub_plot_host, TRUE); - return stub_plot_host; -} - -void cetba_open_stub(int idx) { - if (idx < 0 || idx >= BOOK_NODES || book_defs[idx].full) - return; - stub_book_idx = idx; - if (stub_title_lbl) - gtk_label_set_text(GTK_LABEL(stub_title_lbl), book_defs[idx].title); - rebuild_stub_about(idx); - if (main_stack) - show_page("cetbastub", 1); -} - -void cetba_register_search(void) { - char target[32]; - - for (int i = 0; i < BOOK_NODES; i++) { - if (book_defs[i].full) { - search_catalog_add(book_defs[i].title, tr("search_book"), - book_defs[i].target, FALSE, 2, book_defs[i].author); - if (g_strcmp0(book_defs[i].target, "cetba1984") == 0) - search_catalog_add(tr("lit_quiz_title"), tr("search_exercise"), - "cetba1984quiz", FALSE, 3, "orwell kviz"); - else if (g_strcmp0(book_defs[i].target, "cetbaFuks") == 0) - search_catalog_add(tr("lit_fuks_quiz_title"), - tr("search_exercise"), "cetbaFuksQuiz", - FALSE, 3, "fuks kviz"); - } else { - g_snprintf(target, sizeof target, "cetbastub:%d", i); - search_catalog_add(book_defs[i].title, tr("search_book"), - target, FALSE, 2, book_defs[i].author); - } - } -} diff --git a/src/cetba_book_exercises.inc b/src/cetba_book_exercises.inc deleted file mode 100644 index c258b41..0000000 --- a/src/cetba_book_exercises.inc +++ /dev/null @@ -1,29642 +0,0 @@ -/* Generated from data/cetba JSON packs – do not edit by hand. */ -/* Requires LitQ (cetba.c) and AssemblyItem (maturita.h). */ - -typedef struct { - const LitQ *qs; - int nq; - const AssemblyItem *plot; - const char **plot_meaning; - int nplot; -} BookExPack; - -static const LitQ book_1984_qs[] = { - { - "Kdo je hlavní hrdina románu a co dělá?", - { - "Winston Smith – přepisuje historii na Ministerstvu pravdy", - "O'Brien – řídí Ministerstvo lásky", - "Emmanuel Goldstein – vede Bratrstvo", - "Winston Smith – velí Policii myšlení", - }, - 0, - "Winston Smith je vnější člen strany, který na Ministerstvu pravdy upravuje staré záznamy a novinové články.", - }, - { - "Ve kterém fiktivním státě se děj odehrává?", - { - "V Eurasii", - "V Oceánii", - "Ve Východasii", - "V Angsocu", - }, - 1, - "Příběh se odehrává v Oceánii, v provincii Letopočet 1 (bývalá Anglie), jejímž hlavním městem je Londýn.", - }, - { - "Co znamená slogan „VÁLKA JE MÍR, SVOBODA JE OTROCTVÍ, NEVĚDOMOST JE SÍLA“?", - { - "Jsou to tři zásady Bratrstva", - "Jsou to názvy ministerstev", - "Jde o hesla prolety", - "Jsou to paradoxní hesla, kterými strana ospravedlňuje útlak", - }, - 3, - "Strana používá dvojité myšlení: hesla znějí vznešeně, ale ve skutečnosti obhajují válku, otroctví a nevědomost.", - }, - { - "Kdo je Velký bratr a je reálnou osobou?", - { - "Skutečný vůdce Bratrstva", - "Winstonův nadřízený na ministerstvu", - "Symbol všemocné moci a kultu osobnosti; možná vůbec neexistuje", - "O'Brienův pseudonym", - }, - 2, - "Velký bratr je tvář režimu. Není jasné, zda jde o živou osobu, nebo jen o symbol, který drží strach a poslušnost.", - }, - { - "Co je Newspeak (novořeč) a proč ho strana zavádí?", - { - "Tajná řeč Bratrstva", - "Zjednodušená angličtina omezující slovní zásobu, aby nešlo vyslovit zakázané myšlenky", - "Úřední jazyk prolety", - "Šifra Policie myšlení", - }, - 1, - "Newspeak neustále ubírá slova. Když pro svobodu nebo odpor neexistuje slovo, nelze o nich ani myslet.", - }, - { - "Co je teleobrazovka (telescreen) a jak funguje?", - { - "Televize určená jen pro zábavu", - "Zařízení, které vysílá i sleduje; nelze ji úplně vypnout", - "Rozhlasová stanice", - "Počítač Ministerstva pravdy", - }, - 1, - "Telescreen funguje obousměrně – neustále sleduje občany. Vypnout lze jen zvuk, obraz běží dál.", - }, - { - "Jak se jmenují tři supervelmoci světa 1984?", - { - "Oceánie, Eurasie a Východasie", - "Oceánie, Evropa a Asie", - "Anglie, Eurasie a Ostasie", - "Oceánie, Východasie a Afrika", - }, - 0, - "Svět je rozdělen na tři státy ve věčném, ale nerozhodném konfliktu: Oceánii, Eurasii a Východasii.", - }, - { - "Čím se zabývá Ministerstvo pravdy?", - { - "Vede válku", - "Dohlíží na morálku a sňatky", - "Upravuje a přepisuje historii, noviny a archivy", - "Rozděluje potraviny", - }, - 2, - "Ministerstvo pravdy vyrábí „pravdu“ – Winston v něm přepisuje staré záznamy tak, aby vždy odpovídaly současné linii strany.", - }, - { - "K čemu slouží Ministerstvo lásky?", - { - "Zajišťuje sňatky a lásku", - "Je to budova bez oken, kde se mučí a likvidují nepřátelé strany", - "Vyrábí zbraně", - "Školí děti", - }, - 1, - "Ministerstvo lásky je opakem svého názvu – sídlí tam mučírny a nachází se v něm i obávaná místnost 101.", - }, - { - "V čem je paradox Ministerstva hojnosti?", - { - "Má na starosti hospodářství, ale ve skutečnosti drží lidi v nedostatku", - "Rozdává jídlo a zboží zdarma", - "Zajišťuje dostatek pro všechny", - "Starají se o něj prolety", - }, - 0, - "Ministerstvo hojnosti plánuje výrobu, ale ekonomika je záměrně nastavena tak, aby lidé žili v trvalém nedostatku.", - }, - { - "Co je Ministerstvo míru a čím se zabývá?", - { - "Uzavírá mírové smlouvy", - "Dojednává příměří", - "Ve skutečnosti vede válku", - "Velí Policii myšlení", - }, - 2, - "Název je přesně opačný: Ministerstvo míru řídí válku, protože trvalý válečný stav pomáhá udržet moc strany.", - }, - { - "Kdo je Julie a jaký vztah s ní Winston naváže?", - { - "Winstonova žena", - "Mladá členka strany, s níž Winston prožije tajnou milostnou aféru", - "O'Brienova asistentka", - "Proletka a obchodnice", - }, - 1, - "Julie pracuje v oddělení beletrie a naoko je vzornou členkou strany. S Winstonem vytvoří tajný milostný vztah.", - }, - { - "Proč je vztah Winstona a Julie zakázaný?", - { - "Strana zakazuje lásku a sexualitu jako zločin; vztah je navíc tajný", - "Julie je vdaná za člena vnitřní strany", - "Winston je jejím nadřízeným", - "Julie patří k proletům", - }, - 0, - "Strana potlačuje citové a sexuální vazby, protože oddanost má patřit jen straně. Tajný vztah je proto dvojnásob nebezpečný.", - }, - { - "Kdo je O'Brien a jakou roli hraje v příběhu?", - { - "Skutečný vůdce Bratrstva", - "Vysoce postavený člen vnitřní strany, který Winstona nakonec mučí a „vyléčí“", - "Winstonův přítel z dětství", - "Proletářský básník", - }, - 1, - "Winston věří, že O'Brien je odbojář. Ve skutečnosti je to věrný člen vnitřní strany, který ho dostane do místnosti 101.", - }, - { - "Co je Bratrstvo a existuje vůbec?", - { - "Skutečná armáda Oceánie", - "Náboženská organizace", - "Údajná tajná organizace odporu; není jisté, zda existuje", - "Odbory prolety", - }, - 2, - "Bratrstvo zmiňuje Goldstein i O'Brien, ale kniha nikdy nepotvrdí, že doopravdy existuje – může jít o past strany.", - }, - { - "Kdo je Emmanuel Goldstein?", - { - "Ministr pravdy", - "Oficiální nepřítel státu a údajný vůdce Bratrstva", - "Winstonův kolega", - "Velký bratrův dvojník", - }, - 1, - "Goldstein je terčem dvouminutovky nenávisti. Má ztělesňovat nepřítele, proti kterému strana sjednocuje občany.", - }, - { - "Co je dvojité myšlení (doublethink)?", - { - "Schopnost myslet ve dvou jazycích", - "Zdvojení osobnosti", - "Schopnost věřit dvěma protikladným tvrzením zároveň", - "Tajné zapisování myšlenek", - }, - 2, - "Dvojité myšlení je jádro stranické ideologie – člověk přijme i zjevné rozpory, jako „válka je mír“.", - }, - { - "Proč strana neustále přepisuje minulost?", - { - "Aby opravila chyby v archivech", - "Aby měla vždy pravdu a nepřítel jí nemohl dokázat opak", - "Aby ušetřila papír", - "Aby potěšila prolety", - }, - 1, - "Kdo ovládá minulost, ovládá i budoucnost. Přepisováním historie strana udržuje absolutní kontrolu nad pravdou.", - }, - { - "Co je zločin myšlení (thoughtcrime)?", - { - "Pouhá myšlenka nebo názor, který se nelíbí straně", - "Krádež státního majetku", - "Nelegální obchod", - "Opomenutí dvouminutovky", - }, - 0, - "Strana trestá už samotné myšlenky. Winston se proviní tím, že si do deníku napíše „Dolů s Velkým bratrem“.", - }, - { - "Kdo je pan Charrington a jaké je jeho skutečné postavení?", - { - "Winstonův přítel a majitel hospody", - "Proletářský básník", - "Zdánlivě starý majitel obchodu, ve skutečnosti agent Policie myšlení", - "Člen Bratrstva", - }, - 2, - "Charrington Winstonovi pronajme pokoj bez teleobrazovky, ale právě on nakonec oba milence udá.", - }, - { - "Co je místnost 101?", - { - "Winstonova cela na policii", - "Skladiště knih", - "Místnost, ve které každého čeká jeho největší strach", - "Zasedací místnost vnitřní strany", - }, - 2, - "Místnost 101 je vrcholný mučicí nástroj. Winstonovi v ní hrozí krysy – jeho největší fobie.", - }, - { - "Jak skončí vztah Winstona a Julie?", - { - "Utečou spolu do Eurasie", - "Vezmou se a žijí svobodně", - "Winston se stane členem Bratrstva", - "Zradí se a nakonec se přestanou milovat", - }, - 3, - "Oba jsou po mučení zlomení a vzájemně se zradí. Na konci už k sobě nic necítí.", - }, - { - "Co znamená závěrečná věta „Miloval Velkého bratra“?", - { - "Winstonův vzdor se změnil v pokornou lásku k režimu", - "Winston se stal novým vůdcem", - "Byl to jen Winstonův sen", - "Julie mu to řekla", - }, - 0, - "Winston byl vnitřně zlomen. Přestal být sám sebou a nakonec režim opravdu přijal za svůj.", - }, - { - "Které tvrzení NENÍ jedním z hlavních témat románu?", - { - "Moc a absolutní kontrola", - "Pravda a přepisování historie", - "Svoboda a identita", - "Idylický venkovský život", - }, - 3, - "1984 je temná antiutopie. Hlavními tématy jsou moc, kontrola, manipulace s pravdou a ztráta svobody, ne venkovská idyla.", - }, - { - "V jakém roce byl román 1984 poprvé vydán?", - { - "1936", - "1949", - "1954", - "1984", - }, - 1, - "Román vyšel v roce 1949; letopočet 1984 označuje blízkou budoucnost, do níž Orwell příběh zasadil.", - }, - { - "Které další Orwellovo dílo se dá s 1984 srovnat?", - { - "Farma zvířat", - "Velký Gatsby", - "Zločin a trest", - "Babička", - }, - 0, - "Obě Orwellova díla varují před totalitou. Farma zvířat ji líčí alegoricky pomocí zvířat, 1984 očima jedince.", - }, - { - "Co je „dvouminutovka nenávisti“?", - { - "Krátká každodenní akce, při níž občané společně nenávidí Goldsteina a nepřítele", - "Pravidelná modlitba ke Velkému bratrovi", - "Sportovní přestávka ve škole", - "Porada vedení ministerstva", - }, - 0, - "Slouží k uvolnění a přesměrování agrese občanů na nepřítele státu, čímž strana posiluje svou moc.", - }, - { - "Proč je podle knihy válka pro systém nezbytná?", - { - "Přináší mír a blahobyt", - "Udržuje strach, spotřebovává výrobu a zachovává chudobu i hierarchii", - "Rozvíjí vědu a techniku", - "Sjednocuje vládu s prolety", - }, - 1, - "Trvalá válka pohlcuje nadbytečnou produkci a udržuje lidi ve strachu i chudobě, takže se nemohou vzbouřit.", - }, - { - "Jaký je rozdíl mezi vnějšími členy strany a prolety?", - { - "Proleti mají více práv než členové strany", - "Vnější členové jsou dozíráni, kdežto proleti žijí v chudobě a strana o ně nestojí", - "Není mezi nimi žádný rozdíl", - "Proleti tvoří vedení strany", - }, - 1, - "Proleti tvoří asi 85 % obyvatel. Žijí v bídě a jsou považováni za neškodné, dokud si neuvědomí svou sílu.", - }, - { - "Jak strana kontroluje sexualitu a osobní vztahy?", - { - "Podporuje volnou lásku a nezávislost", - "Potlačuje lásku a sexualitu, děti vede k oddanosti straně", - "Zakazuje veškerá manželství", - "Povoluje vztahy jen s prolety", - }, - 1, - "Strana chce, aby veškerá oddanost a energie patřily jí. Proto podporuje zdrženlivost a vede děti v Antisexuální lize mládeže.", - }, - { - "Co symbolizuje papírové těžítko, které si Winston koupí?", - { - "Jeho nenávist ke Goldsteinovi", - "Kousek krásy a minulosti, kterou už nelze vrátit", - "Moc Velkého bratra", - "Lásku k Julii", - }, - 1, - "Těžítko je drobný, krásný předmět z minulosti. Pro Winstona ztělesňuje svět, který strana zničila.", - }, - { - "Jaké poselství chtěl Orwell románem nejspíš předat?", - { - "Varování před totalitou a ztrátou svobody i pravdy", - "Oslavu technického pokroku", - "Návod, jak založit stát", - "Kritiku sportu a zábavy", - }, - 0, - "1984 je varování: když lidé přestanou bránit pravdu a svobodu, mohou o ně nenávratně přijít.", - }, -}; - -static const AssemblyItem book_1984_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Winston upravuje historii na Ministerstvu pravdy", - "Seznámí se s Julií a začnou se tajně scházet", - "Pronajme si pokoj nad obchodem pana Charringtona", - "Přečte Goldsteinovu knihu u O'Briena", - "Jsou zatčeni Policií myšlení", - "Winston se zlomí v místnosti 101", - }, - 6, - }, -}; - -static const char *book_1984_plot_meaning[] = { - "Správné pořadí: přepisování historie → seznámení s Julií → pronájem pokoje → četba Goldsteinovy knihy → zatčení → místnost 101.", -}; - -static const LitQ book_fahrenheit451_qs[] = { - { - "Kdo je hlavní hrdina a jaké má povolání?", - { - "Guy Montag – hasič pálící knihy", - "Beatty – spisovatel", - "Faber – politik", - "Granger – televizní režisér", - }, - 0, - "Montag pracuje v hasičské jednotce, která místo hašení požárů ničí knihy.", - }, - { - "Co znamená titulní „451 stupňů Fahrenheita“ v kontextu románu?", - { - "Teplota varu vody", - "Údajná teplota hoření knižního papíru", - "Rychlost hasičského vozu", - "Kód tajné policie", - }, - 1, - "Bradbury používá číslo jako symbol ničení literatury ohněm.", - }, - { - "Kdo poprvé naruší Montagovu spokojenost s režimem?", - { - "Mildred", - "Clarisse McClellan", - "Beatty", - "Granger", - }, - 1, - "Clarisse klade otázky o štěstí, přírodě a smyslu života.", - }, - { - "Jak žije Mildred Montagová?", - { - "Jako odbojářka se skrytými knihami", - "Pasivně u televizních stěn a prášků", - "Jako učitelka literatury", - "Jako velitelka hasičů", - }, - 1, - "Mildred je otupělá masovou zábavou a nevnímá hlubší vztah k Guyovi.", - }, - { - "Proč podle Beattyho společnost knihy zakázala?", - { - "Kvůli nedostatku papíru", - "Aby lidé nemysleli samostatně a byli spokojení", - "Protože knihy jsou drahé", - "Kvůli náboženským důvodům", - }, - 1, - "Beatty tvrdí, že knihy kazí „klid“ tím, že nutí přemýšlet a polemizovat.", - }, - { - "Kdo je profesor Faber?", - { - "Velitel hasičů", - "Bývalý učitel, který Montagovi pomáhá", - "Montagův švagr", - "Autor zakázaných románů v tisku", - }, - 1, - "Faber Montaga vede k čtení a přes sluchátko ho podporuje v krizi.", - }, - { - "Co je mechanický pes v románu?", - { - "Mildredin domácí mazlíček", - "Robotický lovec stíhající režimem označené osoby", - "Hasičské auto", - "Postava dětského pořadu", - }, - 1, - "Mechanický pes je nástroj strachu; později stíhá i Montaga.", - }, - { - "Co Montag udělá s kapitánem Beattym při zatýkání?", - { - "Přesvědčí ho ke čtení", - "Spálí ho proudem plamenometu", - "Uteče s ním z města", - "Udá ho policii", - }, - 1, - "Po Beattyho provokacích Montag obrátí oheň proti svému nadřízenému.", - }, - { - "Kdo jsou „pamatovači“ na konci románu?", - { - "Hasiči v důchodu", - "Lidé, kteří si pamatují knihy nazpaměť", - "Televizní herci", - "Vojáci v zákopu", - }, - 1, - "Skupina kolem Grangera uchovává literární texty v paměti jako most k budoucnosti.", - }, - { - "Jaký symbol nese oheň v průběhu příběhu?", - { - "Pouze ničení", - "Nejdřív ničení, později i možnost obnovy (metafora fénixe)", - "Jen romantická láska", - "Výhradně válka", - }, - 1, - "Montag přechází od pálení knih k vnímání ohně jako zdroje tepla i nového začátku.", - }, - { - "Jak Mildred reaguje na Montagovo skryté čtení?", - { - "Podporuje ho", - "Je vyděšená a raději knihy nechce vidět", - "Okamžitě utíká k hasičům", - "Začne psát vlastní deník", - }, - 1, - "Mildred se bojí následků a zůstává věrná konzumnímu životnímu stylu.", - }, - { - "Co se stane s Montagovou domácností?", - { - "Stane se útočištěm odboje", - "Beatty nechá Montaga sám spálit jeho dům s knihami", - "Mildred ji prodá", - "Faber v ní otevře knihovnu", - }, - 1, - "Beatty nutí Montaga zničit vlastní domov jako veřejnou lekci poslušnosti.", - }, - { - "Proč Montag utíká k řece?", - { - "Chce najít Clarisse", - "Uteče před mechanickým psem a pronásledováním", - "Jde k Beattymu na večeři", - "Hledá televizní studio", - }, - 1, - "Po zabití Beattyho musí opustit město a skrýt se před technologií i lidmi.", - }, - { - "Jakou roli hraje televize ve společnosti románu?", - { - "Vzdělává občany", - "Nahrazuje knihy, dialog a kritické myšlení", - "Slouží jen hasičům", - "Vysílá výhradně zprávy o válce", - }, - 1, - "Interaktivní stěny a rychlé pořady udržují lidi pasivní a spokojené.", - }, - { - "Které téma román NEZdůrazňuje?", - { - "Cenzura", - "Nebezpečí konzumní zábavy", - "Idylický venkovský realism 19. století", - "Odpor jednotlivce", - }, - 2, - "Jde o dystopii o knihách a médiích, ne o historický venkovský román.", - }, - { - "V jakém roce román poprvé vyšel?", - { - "1949", - "1953", - "1968", - "1984", - }, - 1, - "451 stupňů Fahrenheita vyšlo v roce 1953 a patří k klasice antiutopie.", - }, - { - "Jaký vztah měl Bradbury k televizi podle kontextu díla?", - { - "Bezvýhradně ji oslavoval", - "Varoval před jejím návykovým vlivem na kulturu", - "Ignoroval ji", - "Považoval ji za náhradu školy", - }, - 1, - "Román kritizuje pasivní sledování obrazovek místo čtení a rozhovoru.", - }, - { - "Co Montag ukradne u staré ženy s knihami?", - { - "Televizní ovladač", - "Kniha (biblický text)", - "Plamenomet", - "Mechanický pes", - }, - 1, - "Montag si nechá knihu, i když vidí, jak žena raději zemře v plamenech než knihy vydá.", - }, - { - "Proč je scéna se starou ženou důležitá?", - { - "Ukazuje lehkost smrti", - "Montag chápe, že knihy mají pro lidi hodnotu života", - "Beatty se stane hrdinou", - "Mildred se obrátí", - }, - 1, - "Obětí ženy v plamenech Montag poprvé silně pocítí absurditu pálení knih.", - }, - { - "Jak Faber pomáhá Montagovi během pronásledování?", - { - "Letí s ním vrtulníkem", - "Komunikuje přes miniaturní sluchátko v uchu", - "Zastřelí mechanického psa", - "Spálí Beattyho knihovnu", - }, - 1, - "Faber ho radí na dálku, dokud Montag neunikne z města.", - }, - { - "Co se stane s městem na konci?", - { - "Slaví mír", - "Je zničeno leteckým útokem", - "Stane se knihovnou", - "Zmizí televize", - }, - 1, - "Válka na pozadí exploduje; město letecky zničí, zatímco Montag je mimo.", - }, - { - "Jak Granger vnímá budoucnost po zkáze?", - { - "Bez naděje", - "Jako šanci znovu budovat kulturu z paměti", - "Jako konec světa bez smyslu", - "Jako vítězství hasičů", - }, - 1, - "Pamatovači přirovnávají obnovu k fénixovi – z popela může vyrůst nové.", - }, - { - "Která postava představuje konformitu nejvíc?", - { - "Clarisse", - "Mildred", - "Granger", - "Faber", - }, - 1, - "Mildred je vzor občana spokojeného s prázdnou zábavou.", - }, - { - "Která postava ztělesňuje vzdělaný cynismus moci?", - { - "Faber", - "Beatty", - "Clarisse", - "Granger", - }, - 1, - "Beatty cituje literaturu, ale obhajuje její ničení.", - }, - { - "Jaký žánr nejlépe vystihuje román?", - { - "Antiutopický sci-fi román", - "Historický epos", - "Detektivka", - "Pastorální idyla", - }, - 0, - "Děj v budoucnosti kritizuje společnost a technologie – typická antiutopie.", - }, - { - "Co Montag dělá na začátku knihy profesně?", - { - "Učí na gymnáziu", - "Pálí knihy jako hasič", - "Píše pro televizi", - "Vyrábí mechanické psy", - }, - 1, - "Úvodní scény ukazují rutinní pálení knih.", - }, - { - "Proč je Clarisse „nebezpečná“ pro systém?", - { - "Je bohatá", - "Ptá se na zakázané otázky a myslí jinak", - "Je hasička", - "Píše knihy", - }, - 1, - "Její zvědavost a pomalost odporují konzumnímu tempu společnosti.", - }, - { - "Jaký význam má řeka v závěru?", - { - "Hranice státu", - "Cesta úniku a symbol očištění", - "Místo pálení knih", - "Beattyho hrob", - }, - 1, - "Montag se v řece skrývá před psem a přechází k novému životu.", - }, - { - "Kdo v románu představuje most mezi starou kulturou a odbojem?", - { - "Beatty", - "Faber", - "Mildred", - "Mechanický pes", - }, - 1, - "Faber zná knihy, ale dlouho se bál jednat – Montaga k akci povzbudí.", - }, - { - "Jaké poselství je pro maturitu nejdůležitější?", - { - "Knihy lze nahradit televizí", - "Svoboda myšlení a kultura se brání i za cenu rizika", - "Hasiči by měli pálit domy", - "Válka je lepší než čtení", - }, - 1, - "Román obhajuje literaturu a kritické myšlení proti cenzuře a pasivitě.", - }, - { - "Jaký český překladatel je u díla tradičně uváděn v maturitních seznamech?", - { - "Gössell", - "Nezval", - "Skoumal", - "Nevrla", - }, - 1, - "V katalogu maturitní četby je u díla uveden překlad Vítězslava Nezvala.", - }, - { - "Co následuje po Montagově připojení k pamatovačům?", - { - "Návrat k Mildred", - "Pohled na zkázu města a naděje v obnovu", - "Beattyho rehabilitace", - "Zákaz paměti", - }, - 1, - "Závěr spojuje zkázu s možností nového začátku skrze paměť a knihy.", - }, -}; - -static const AssemblyItem book_fahrenheit451_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Montag rutinně pálí knihy jako hasič", - "Clarisse ho přiměje pochybovat o systému", - "Montag schovává knihy a hledá radu u Fabera", - "Beatty nechá Montaga spálit vlastní dům", - "Montag zabije Beattyho a utíká z města", - "Připojí se k pamatovačům a vidí zkázu města", - }, - 6, - }, -}; - -static const char *book_fahrenheit451_plot_meaning[] = { - "Správné pořadí: rutinní pálení → Clarisse a pochybnosti → knihy a Faber → spálení domu → útěk a Beatty → pamatovači a zkáza města.", -}; - -static const LitQ book_audience_qs[] = { - { - "Kdo je autorem hry Audience?", - { - "Jaroslav Hašek", - "Václav Havel", - "Karel Čapek", - "Ladislav Smoljak", - }, - 1, - "Audience napsal Václav Havel jako součást Vaněkovy trilogie.", - }, - { - "Jaký je žánr díla?", - { - "Epos", - "Jednoaktové drama", - "Lyrická báseň", - "Detektivní román", - }, - 1, - "Jde o jednoaktovou divadelní hru s dialogem dvou postav.", - }, - { - "Kde se děj odehrává?", - { - "Na ministerstvu", - "V kanceláři vedoucího skladu pivovaru", - "V divadle", - "V exilu", - }, - 1, - "Celá hra probíhá v kanceláři vedoucího skladu.", - }, - { - "Kdo je Ferdinand Vaněk?", - { - "Vedoucí skladu", - "Bývalý spisovatel přeřazený na manuální práci", - "Ministr", - "Hasič", - }, - 1, - "Vaněk je inteligent přeřazený do dělnické profese – alter ego Havla.", - }, - { - "Proč vedoucí Vaněka „předvolá“?", - { - "Kvůli inventuře", - "Aby ho ideologicky „ převýchovali“ a získali informace", - "Kvůli dovolené", - "Kvůli pivu zdarma", - }, - 1, - "Rozhovor je nátlak na poslušnost a spolupráci s mocí.", - }, - { - "Jak vedoucí vnímá svou pozici?", - { - "Jako mučedníka", - "Jako malého funkcionáře toužícího po kariéře", - "Jako disidenta", - "Jako umělce", - }, - 1, - "Vedoucí se přizpůsobuje systému a chce postup.", - }, - { - "Jak Vaněk reaguje na nátlak?", - { - "Okamžitě udává", - "Mlčí, ironizuje, nepodléhá", - "Odejde z práce", - "Napadne vedoucího", - }, - 1, - "Vaněk odmítá hrát hru moci, i když riskuje problémy.", - }, - { - "Co je typické pro Havlovy hry s Vaněkem?", - { - "Historický realismus 19. století", - "Groteskní situace a jazyk moci", - "Pohádková fantasy", - "Přírodní lyrika", - }, - 1, - "Havel ukazuje absurditu režimu skrze banální rozhovory.", - }, - { - "Kdy hra vznikla / poprvé vyšla?", - { - "1948", - "1975", - "1989", - "2000", - }, - 1, - "Audience patří k Vaněkově trilogii z normalizačního období (1975).", - }, - { - "Jaké další hry tvoří Vaněkovu trilogii kromě Audience?", - { - "Hamlet a Macbeth", - "Protest a Vyrozumění", - "R.U.R. a Bílá nemoc", - "Čekání na Godota a Endgame", - }, - 1, - "Trilogie: Audience, Protest, Vyrozumění.", - }, - { - "Proč je hra „absurdní“?", - { - "Protože se dějí zázraky", - "Protože vážný nátlak probíhá v banální situaci skladu", - "Protože je bez dialogu", - "Protože je v rýmu", - }, - 1, - "Absurdita je v rozporu mezi tématem a prostředím.", - }, - { - "Co symbolizuje pivovar / sklad?", - { - "Exkluzivní elita", - "Běžné pracovní prostředí, kde se testuje loajalita", - "Církev", - "Škola", - }, - 1, - "Moc se prosazuje i v obyčejné fabrice.", - }, - { - "Jak vedoucí mluví o „pravdě“?", - { - "Jasně a otevřeně", - "Používá ideologické fráze a ospravedlňuje se", - "V latině", - "Vůbec nemluví", - }, - 1, - "Vedoucí opakuje fráze, ale neumí nést morální odpovědnost.", - }, - { - "Proč Vaněk nechce „spolupracovat“?", - { - "Neví jak", - "Odmítá kompromis se lží a strachem", - "Chce být vedoucím", - "Je mu jedno", - }, - 1, - "Hrdina volí svědomí před kariérním nebo materiálním klidem.", - }, - { - "Jaký vztah mají oba muži k alkoholu v hře?", - { - "Nepijí", - "Pivo je součástí prostředí a uvolnění napětí", - "Pijí jen Vaněk", - "Pivo zakazují", - }, - 1, - "Pivovar jako prostředí ovlivňuje tón rozhovoru.", - }, - { - "Co hrozí Vaněkovi, pokud neuspokojí vedoucího?", - { - "Pouze pokuta", - "Další perzekuce, problémy v práci i rodině", - "Okamžitá sláva", - "Povýšení", - }, - 1, - "Normalizační režim trestal odmítnutí spolupráce.", - }, - { - "Které téma Havel v Audience NEřeší primárně?", - { - "Morální odpovědnost", - "Jazyk moci", - "Kosmické cestování", - "Strach z autorit", - }, - 2, - "Hra je společenská groteska, ne sci-fi.", - }, - { - "Jak končí hra typicky v interpretaci?", - { - "Vítězstvím vedoucího", - "Bez jasného „happy endu“ – napětí a Vaněkovo trvání na svém", - "Svatbou", - "Válka", - }, - 1, - "Zůstává konflikt mezi mocí a svědomím.", - }, - { - "Proč je Audience maturitní četbou?", - { - "Kvůli pohádkovému ději", - "Ukazuje českou literaturu 20. století a disidentskou zkušenost", - "Je nejkratší kniha", - "Je bez témat", - }, - 1, - "Dílo reprezentuje Havla a období normalizace.", - }, - { - "Kdo je autorem termínu „slov odpovědnosti“ v kontextu Havla?", - { - "Shakespeare", - "Václav Havel", - "Orwell", - "Kafka", - }, - 1, - "Havel zdůrazňoval, že slova mají morální váhu.", - }, - { - "Jaký je tón dialogu?", - { - "Epický popis přírody", - "Napětí mezi frázemi moci a Vaněkovou ironií", - "Pouze monolog", - "Pouze pění", - }, - 1, - "Dialog odhaluje charakter obou postav.", - }, - { - "Vedoucí se bojí hlavně…", - { - "Přízraků", - "Ztráty postavení a problémů s nadřízenými", - "Vaněkova talentu na pivo", - "Cizinců", - }, - 1, - "Jeho kariéra závisí na ideologické spolehlivosti.", - }, - { - "Vaněk v hře představuje…", - { - "Typ spolupracovníka režimu", - "Typ člověka, který nezradí svědomí", - "Krále", - "Detektiva", - }, - 1, - "Vaněk je Havlovo alter ego disidenta.", - }, - { - "Kolik hlavních mluvících postav je v Audience?", - { - "Pět", - "Dvě", - "Deset", - "Žádná", - }, - 1, - "Dialog vedoucího a Vaněka tvoří jádro hry.", - }, - { - "Jak souvisí Audience s normalizací?", - { - "Vznikla v období po roce 1968 jako metafora tlaku režimu", - "Popisuje středověk", - "Je z roku 1848", - "Je americký western", - }, - 0, - "Hra reaguje na politickou situaci v Československu 70. let.", - }, - { - "Proč vedoucí opakuje fráze?", - { - "Nemá slovní zásobu", - "Nahrazuje nimi vlastní rozhodnutí a odpovědnost", - "Učí se latinu", - "Je básník", - }, - 1, - "Ideologický jazyk má ulevit od morální volby.", - }, - { - "Co Vaněk odmítá udělat?", - { - "Pracovat", - "Hrát roli informátora / ideologicky se „ přizpůsobit“", - "Pít pivo", - "Chodit do skladu", - }, - 1, - "Jde o odmítnutí spolupráce s mocí.", - }, - { - "Jaký literární směr je nejblíže Havlovu divadlu?", - { - "Romantismus", - "Divadlo absurdní / groteskní", - "Klasicismus", - "Naturalismus venkova", - }, - 1, - "Havel navazuje na absurdní drama, ale s českým politickým kontextem.", - }, - { - "Co je „audience“ v anglickém významu slova?", - { - "Publikum / jednání s nadřízeným", - "Hasičský sbor", - "Pivní sud", - "Soudní trest", - }, - 0, - "Název ironicky evokuje setkání, které je ve skutečnosti výslech.", - }, - { - "Která postava je víc „pro systém“?", - { - "Vaněk", - "Vedoucí skladu", - "Obě stejně", - "Ani jedna", - }, - 1, - "Vedoucí se snaží vyhovět nadřízeným.", - }, - { - "Jaké poselství je pro maturitu klíčové?", - { - "Poslušnost za každou cenu", - "Člověk může odmítnout lhát, i když za to platí", - "Práce je vždy důležitější než pravda", - "Fráze nahrazují etiku", - }, - 1, - "Hra obhajuje svědomí proti ideologickému nátlaku.", - }, - { - "V jakém žánru je Audience v katalogu maturitní četby?", - { - "Poezie", - "Drama", - "Próza", - "Epos", - }, - 1, - "V katalogu je uvedeno jako drama.", - }, -}; - -static const AssemblyItem book_audience_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Vaněk pracuje ve skladu pivovaru jako dělník", - "Vedoucí ho předvolá na rozhovor v kanceláři", - "Vedoucí tlakem a frázemi testuje Vaněkovo přizpůsobení", - "Vaněk odmítá ideologickou spolupráci", - "Napětí mezi kariérou vedoucího a Vaněkovým svědomím roste", - "Hra končí bez smíření – moc a disident zůstávají v konfliktu", - }, - 6, - }, -}; - -static const char *book_audience_plot_meaning[] = { - "Správné pořadí: Vaněk ve skladu → předvolání → nátlak vedoucího → Vaněkovo odmítnutí → eskalace napětí → nevyřešený konflikt.", -}; - -static const LitQ book_bajecna_leta_qs[] = { - { - "Kdo je autorem?", - { - "Viewegh", - "Poláček", - "Hašek", - "Havel", - }, - 0, - "Román napsal Michal Viewegh.", - }, - { - "Jaký je žánr?", - { - "Historický epos", - "Autobiograficky laděný humoristický román", - "Detektivka", - "Tragedie", - }, - 1, - "Dílo kombinuje vzpomínky s fikcí a humorem.", - }, - { - "Kdy kniha vyšla?", - { - "1989", - "1992", - "2005", - "1968", - }, - 1, - "Báječná léta pod psa vyšla v roce 1992.", - }, - { - "Kdo vypráví?", - { - "Otec v er-formě", - "Mladý Michal v ich-formě", - "Vševěd", - "Učitel", - }, - 1, - "Vypravěč je sám hrdina jako dospívající chlapec.", - }, - { - "V jakém období děj probíhá?", - { - "První republika", - "70.–80. léta normalizace", - "Středověk", - "Budoucnost", - }, - 1, - "Děj kopíruje dětství autora v normalizačním Československu.", - }, - { - "Co znamená „léta pod psa“?", - { - "Idylické dětství", - "Chaotické, těžké období s humorem", - "Vojenská služba", - "Studium v zahraničí", - }, - 1, - "Název ironicky označuje nepříliš slavné období života.", - }, - { - "Jaký tón knihy převládá?", - { - "Tragický bez humoru", - "Groteskní humor a sebeironie", - "Epická vážnost", - "Horor", - }, - 1, - "Viewegh typicky balí bolest do humoru.", - }, - { - "Kde hrdina tráví velkou část dětství?", - { - "Na statku v Texasu", - "Ve městě, doma a ve škole", - "V klášteře", - "Na lodi", - }, - 1, - "Prostředí je běžné město a rodinný byt.", - }, - { - "Jak je v knize zobrazena škola?", - { - "Jako ráj", - "Jako místo ideologie, strachu i trapasů", - "Chybí", - "Jen univerzita", - }, - 1, - "Škola je součást normalizační výchovy.", - }, - { - "Které téma patří k dílu?", - { - "Puberta a sexualita", - "Kosmické války", - "Rytířské turnaje", - "Lovec velryb", - }, - 0, - "Dospívání je ústřední.", - }, - { - "Jak vnímá hrdina rodiče?", - { - "Nezmíní je", - "Jako autority, se kterými bojuje i je miluje", - "Jako cizince", - "Jako detektivy", - }, - 1, - "Generační konflikt je typický.", - }, - { - "Co je typické pro Vieweghovu prózu?", - { - "Středověká mluva", - "Ich-forma, autobiografické prvky, humor", - "Pouze poezie", - "Beletrie bez postav", - }, - 1, - "Autor často čerpá z vlastního života.", - }, - { - "Jak kniha reaguje na normalizaci?", - { - "Oslavuje ji", - "Ironizuje fráze a všednost režimu", - "Ignoruje politiku úplně", - "Je manifestem strany", - }, - 1, - "Politika prosvítá školou a jazykem.", - }, - { - "Která postava NENÍ typická pro děj?", - { - "Spolužák", - "Rodič", - "Mladý vypravěč", - "Král Artuš", - }, - 3, - "Děj je realisticky autobiografický.", - }, - { - "Jaký vztah má k alkoholu v dospívání?", - { - "V knize neexistuje", - "Objevuje se jako součást „dospěláckého“ světa", - "Je jen u dospělých bez komentáře", - "Je zakázaný téma", - }, - 1, - "Hrdina zkouší hranice tabu.", - }, - { - "Co hrdina často prožívá?", - { - "Stud a trapasy", - "Věčný klid", - "Nadlidské moc", - "Středověké bitvy", - }, - 0, - "Pubertální stud je častý motiv.", - }, - { - "Jak končí kniha typicky?", - { - "Svatbou v kostele", - "Pokračováním v dalších dílech / otevřeným dospíváním", - "Smrtí všech", - "Válka", - }, - 1, - "Viewegh navazuje v dalších autobiografických knihách.", - }, - { - "Proč je kniha maturitní?", - { - "Je nejkratší", - "Reprezentuje českou prózu 90. let a generaci normalizace", - "Je v angličtině", - "Nemá postavy", - }, - 1, - "Patří k čtení generace Viewegha.", - }, - { - "Jaký jazyk autor používá?", - { - "Archaičtina", - "Spisovná čeština s hovorovými prvky", - "Cizí bez překladu", - "Pouze dialekt", - }, - 1, - "Styl je srozumitelný, hovorový, vtipný.", - }, - { - "Co je groteska v knize?", - { - "Pouze hrůza", - "Nadsázka a absurdní situace z běžného života", - "Pouze poezie", - "Historická přesnost", - }, - 1, - "Groteska zvyšuje humor i pravdivost.", - }, - { - "Jaký motiv NENÍ klíčový?", - { - "Rodina", - "Škola", - "Dospívání", - "Mýtus o Atlantidě", - }, - 3, - "Atlantida v díle nefiguruje.", - }, - { - "Kdo je cílový čtenář stylu?", - { - "Pouze historici", - "Široká veřejnost, zejména mladší", - "Jen linguisté", - "Jen děti předškoláci", - }, - 1, - "Kniha je bestsellerově čtivá.", - }, - { - "Jak hrdina vnímá „cool“ svět?", - { - "Nehraje roli", - "Touží po něm, napodobuje rock, kamarády", - "Je proti hudbě", - "Je dospělý", - }, - 1, - "Teenagerská identita je důležitá.", - }, - { - "Co odlišuje Viewegha od Poláčka?", - { - "Viewegh píše 90. léta autobiografii, Poláček meziválečný humor", - "Jsou totožní", - "Poláček píše sci-fi", - "Viewegh píše drama", - }, - 0, - "Období i styl se liší.", - }, - { - "Jaká forma vyprávění?", - { - "Drama", - "Ich-forma románu", - "Epos", - "Deník bez komentáře", - }, - 1, - "Vypravěč je „já“.", - }, - { - "Které prostředí dominuje?", - { - "Pouze příroda", - "Město, byt, škola", - "Pouze fabrika", - "Pouze cirkus", - }, - 1, - "Urbanizované dětství.", - }, - { - "Jak autor pracuje s časem?", - { - "Lineárně od narození po smrt v jednom roce", - "Kapitolami, epizodami vzpomínek", - "Jen jeden den", - "Bez času", - }, - 1, - "Koláž epizod tvoří celek.", - }, - { - "Co hrdina objevuje u holky / v lásce?", - { - "Nic", - "Stud, touhu, nedorozumění", - "Jen válku", - "Jen politiku", - }, - 1, - "Milostné epizody patří k pubertě.", - }, - { - "Jaký je vztah k autoritám?", - { - "Bezvýhradná poslušnost", - "Vzdor, ironie, občasná poslušnost", - "Vždy trest", - "Autority chybí", - }, - 1, - "Typický teen vs. rodiče/učitelé.", - }, - { - "Jaké poselství lze vyčíst?", - { - "Dětství v režimu lze vyprávět s humorem i pravdou", - "Normalizace neexistovala", - "Humor je zbytečný", - "Rodina vždy škodí", - }, - 0, - "Kniha spojuje paměť generace s humorem.", - }, - { - "Kolik quiz otázek má mít maturita pack?", - { - "5", - "28–32", - "100", - "1", - }, - 1, - "Stejně jako ostatní balíčky v projektu.", - }, - { - "Který autor napsal Báječná léta pod psa?", - { - "Michal Viewegh", - "Milan Kundera", - "Karel Čapek", - "Bohumil Hrabal", - }, - 0, - "Viewegh je autorem.", - }, -}; - -static const AssemblyItem book_bajecna_leta_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Dětství vypravěče v normalizaci", - "Školní a rodinné epizody", - "Puberta, kamarádi a první lásky", - "Konfrontace s ideologií a frázemi", - "Trapasy a groteskní situace", - "Dospívání směrem k dospělosti", - }, - 6, - }, -}; - -static const char *book_bajecna_leta_plot_meaning[] = { - "Pořadí: dětství → škola a rodina → puberta → ideologie → humor z trapasů → dospívání.", -}; - -static const LitQ book_bidnici_qs[] = { - { - "Kdo je autorem Bídníků?", - { - "Dickens", - "Hugo", - "Zola", - "Flaubert", - }, - 1, - "Victor Hugo napsal Les Misérables (Bídníci).", - }, - { - "Kdy román poprvé vyšel?", - { - "1789", - "1862", - "1900", - "1950", - }, - 1, - "Vydání 1862 je klíčové pro francouzskou literaturu.", - }, - { - "Kdo je Jean Valjean na začátku?", - { - "Kněz", - "Galejník pro krádež chleba", - "Král", - "Advokát", - }, - 1, - "Valjean strávil roky v galejích.", - }, - { - "Co udělá biskup Myriel?", - { - "Udá Valjeana", - "Daruje mu stříbrné svícny a zachrání ho před policií", - "Zabije Javerta", - "Pošle ho zpět do galejí", - }, - 1, - "Milosrdenství biskupa změní Valjeanův život.", - }, - { - "Proč Valjean mění identitu?", - { - "Pro zábavu", - "Aby mohl začít nový život a pomáhat druhým", - "Javert ho požádá", - "Kvůli loterii", - }, - 1, - "Nová identita umožní podnikání a charitu.", - }, - { - "Kdo je Javert?", - { - "Valjeanův přítel", - "Policejní inspektor posedlý dopadením Valjeana", - "Biskup", - "Marius", - }, - 1, - "Javert ztělesňuje zákon bez milosrdenství.", - }, - { - "Co se stane Fantine?", - { - "Stane se královnou", - "Kvůli dceři Cosette chudoba a prostituce, umírá", - "Vede revoluci", - "Je s Javertem", - }, - 1, - "Fantine je oběť společnosti.", - }, - { - "Kdo vychovává Cosette?", - { - "Thénardierovi ji mučí, pak ji vezme Valjean", - "Javert", - "Marius od narození", - "Nikdo", - }, - 0, - "Valjean Cosette vykoupí a miluje jako dcera.", - }, - { - "Kdo je Marius?", - { - "Starý hostinský", - "Mladý revolucionář, zamiluje se do Cosette", - "Biskup", - "Galejník", - }, - 1, - "Marius se účastní barikád.", - }, - { - "Kde probíhá revoluční boj?", - { - "Versailles", - "Barikády v Paříži (1832)", - "Londýn", - "Marseille", - }, - 1, - "Historická vsuvka – povstání 1832.", - }, - { - "Jak Valjean zachrání Marius?", - { - "Nechá ho na barikádě", - "Odnese ho stokami z bojiště", - "Javert pomůže", - "Marius uteče sám", - }, - 1, - "Slavná scéna v pařížských stokách.", - }, - { - "Proč Javert spáchá sebevraždu?", - { - "Valjean ho zabije", - "Nezvládne, že Valjean mu prokazuje dobro – kolaps morálky zákona", - "Marius ho obviní", - "Hlad", - }, - 1, - "Javert nemůže sladit zákon s realitou Valjeanovy goodness.", - }, - { - "Jak Valjean končí?", - { - "Na trůně", - "Umírá v klidu, Cosette a Marius mu odpouštějí", - "V galejích", - "V exilu jako zločinec", - }, - 1, - "Závěr je vyznání a smrt starého muže.", - }, - { - "Kdo jsou Thénardierovi?", - { - "Šlechtici", - "Lakomí, krutí hostinští využívající Cosette", - "Kněží", - "Učitelé", - }, - 1, - "Představují spodinu bez morálky.", - }, - { - "Jaký je hlavní konflikt Valjean vs. Javert?", - { - "Sport", - "Milosrdenství a nový život vs. nemilosrdný zákon", - "Náboženství vs. věda", - "Láska vs. hudba", - }, - 1, - "Centrální morální osa románu.", - }, - { - "Co symbolizují stříbrné svícny?", - { - "Bohatství", - "Milosrdenství a důvěru, která spouští spásu", - "Válku", - "Krádež", - }, - 1, - "Biskup dá Valjeanovi i „duši“.", - }, - { - "Jaký žánr román nejlépe vystihuje?", - { - "Pohádka", - "Historicko-společenský epický román", - "Sci-fi", - "Detektivka", - }, - 1, - "Rozsáhlý děj s historií Francie.", - }, - { - "Kde se odehrává většina děje?", - { - "Praha", - "Paříž a okolí", - "New York", - "Moskva", - }, - 1, - "Paříž je hlavní prostředí.", - }, - { - "Co Valjean dělá jako boháč?", - { - "Pouze holdí peníze", - "Vede továrnu, pomáhá chudým, stará se o Cosette", - "Stane se policistou", - "Pálí knihy", - }, - 1, - "Je dobrodinou i otcem.", - }, - { - "Kdo Éponine?", - { - "Dcera Thénardierových, miluje Marius, oběť barikád", - "Sestra Cosette", - "Javertova žena", - "Královna", - }, - 0, - "Éponine je tragická postava lásky.", - }, - { - "Proč je román maturitní?", - { - "Je nejkratší", - "Klasika světové literatury o spravedlnosti a chudobě", - "Bez témat", - "Jen poezie", - }, - 1, - "Hugo patří k kanonu.", - }, - { - "Jaký překladatel bývá uváděn v CZ maturitě?", - { - "Nezval", - "Pavlousková", - "Nevrla", - "Gössell", - }, - 1, - "V katalogu je Pavlousková.", - }, - { - "Co je „bídníci“ v titulu?", - { - "Pouze zločinci", - "Chudí a opozedníci společnosti", - "Šlechtici", - "Kněží", - }, - 1, - "Les misérables = trpící, chudí.", - }, - { - "Jak Hugo pracuje s historií?", - { - "Ignoruje ji", - "Vkládá historické kapitoly a reálné události", - "Píše budoucnost", - "Jen mýty", - }, - 1, - "Román je i historický obraz.", - }, - { - "Která postava NENÍ z Bídníků?", - { - "Valjean", - "Javert", - "Hamlet", - "Fantine", - }, - 2, - "Hamlet je Shakespeare.", - }, - { - "Co Marius neví dlouho?", - { - "Že Valjean zachránil jeho život", - "Že existuje Paříž", - "Že miluje Cosette", - "Nic", - }, - 0, - "Tajemství Valjeanovy oběti se odhalí později.", - }, - { - "Jaký motiv lásky je v díle?", - { - "Pouze komický", - "Rodičovská (Valjean–Cosette), romantická (Marius–Cosette)", - "Chybí", - "Jen platonická u Javerta", - }, - 1, - "Láska je motor obětí.", - }, - { - "Co reprezentuje barikáda?", - { - "Dovolená", - "Naděje mladých na spravedlivější svět i oběť", - "Obchod", - "Církev", - }, - 1, - "Revoluční idealismus Mariusovy generace.", - }, - { - "Proč Valjean uniká Javertovi opakovaně?", - { - "Magie", - "Identita, úkryty, milosrdenství druhých", - "Javert nechce chytit", - "Válka", - }, - 1, - "Dlouhý pronásledovací motiv.", - }, - { - "Jaké poselství je typické?", - { - "Zlo vždy vyhrává", - "I spadlý člověk může jednat morálně a měnit životy", - "Zákon je vždy spravedlivý", - "Chudoba neexistuje", - }, - 1, - "Spása skrze milosrdenství.", - }, - { - "Kolik hlavních dějových linií román spojuje?", - { - "Jednu bez vedlejších", - "Valjean, Fantine/Cosette, Marius, Javert a další", - "Jen Marius", - "Jen Javert", - }, - 1, - "Epická stavba s mnoha linemi.", - }, - { - "Jak končí vztah Cosette a Valjeana?", - { - "Cosette ho nenávidí", - "Odpustí a miluje ho jako otce", - "Valjean ji opustí navždy bez slova", - "Javert je oddá", - }, - 1, - "Emocionální závěr u lůžka Valjeana.", - }, -}; - -static const AssemblyItem book_bidnici_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Valjean propuštěn z galejí a setká se s biskupem Myrelem", - "Valjean vychovává továrnu a přebírá Cosette", - "Fantine umírá, Javert pronásleduje Valjeana", - "Marius na barikádách, Valjean zachrání Marius stokami", - "Javert propadne po selhání morálky zákona", - "Valjean umírá v míru u Cosette a Marius", - }, - 6, - }, -}; - -static const char *book_bidnici_plot_meaning[] = { - "Pořadí: galeje a biskup → Cosette a továrna → Fantine a pronásledování → barikády a záchrana → Javert → Valjeanova smrt.", -}; - -static const LitQ book_bila_nemoc_qs[] = { - { - "Kdo napsal Bílou nemoc?", - { - "Hašek", - "Čapek", - "Havel", - "Poláček", - }, - 1, - "Karel Čapek, drama z roku 1937.", - }, - { - "Jaký je žánr?", - { - "Pohádka", - "Politické drama", - "Epos", - "Opera", - }, - 1, - "Drama s allegorickým významem.", - }, - { - "Co je bílá nemoc?", - { - "Barva sněhu", - "Smrtelná epidemie s bílými skvrnami", - "Druh květiny", - "Zbran", - }, - 1, - "Nemoc je středem děje.", - }, - { - "Kdo má lék?", - { - "Maršál", - "Dr. Galén", - "Sigmund prodává", - "Nikdo", - }, - 1, - "Galén zdědí/vyvinou lék.", - }, - { - "Proč lék není hromadně nasazen?", - { - "Nefunguje", - "Moc preferuje válku a zisk ze zbrojení", - "Galén odmítá", - "Chybí voda", - }, - 1, - "Politici nechtějí „mír“ bez války.", - }, - { - "Kdo je Maršál?", - { - "Lékař", - "Vůdce státu militarista", - "Kněz", - "Učitel", - }, - 1, - "Maršál symbolizuje válečnou moc.", - }, - { - "Kdo je Sigmund?", - { - "Pacient", - "Obchodník se zbraněmi", - "Galénův bratr", - "Básník", - }, - 1, - "Zbrojař profituje z konfliktu.", - }, - { - "Jak drama reaguje na dobu?", - { - "Ignoruje politiku", - "Varuje před fašismem a válkou (kontext 30. let)", - "Popisuje středověk", - "Sci-fi bez témat", - }, - 1, - "Čapek psal v hrozící krizi.", - }, - { - "Jak Galén jedná?", - { - "Cynicky", - "Idealisticky, chce léčit", - "Jako Maršál", - "Ne léčí", - }, - 1, - "Galén je morální protiklad moci.", - }, - { - "Co symbolizuje nemoc allegoricky?", - { - "Jen medicína", - "Nakažlivé totalitní/myšlenkové nebezpečí", - "Pouze chřipka", - "Sport", - }, - 1, - "Často čteno jako metafora fašismu.", - }, - { - "Kdy hra vyšla?", - { - "1920", - "1937", - "1948", - "2000", - }, - 1, - "Rok 1937 – před válkou.", - }, - { - "Jak končí hra typicky?", - { - "Všichni uzdraveni", - "Tragicky – válka a smrt, varování marné", - "Svatba", - "Komický tanec", - }, - 1, - "Pesimistický závěr.", - }, - { - "Které téma NENÍ klíčové?", - { - "Válka vs. humanita", - "Lékařská etika", - "Kosmické cesty", - "Politický cynismus", - }, - 2, - "Děj je zemský a politický.", - }, - { - "Kdo jsou oběti?", - { - "Jen šlechtici", - "Chudí a běžní lidé, zejména mladí", - "Jen vojáci", - "Nikdo", - }, - 1, - "Nemoc zasahuje společnost.", - }, - { - "Jak Maršál vnímá nemoc?", - { - "Chce ji okamžitě vymýtit léky", - "Využívá ji pro moc a válku", - "Odchází do kláštera", - "Stává se lékařem", - }, - 1, - "Válka je pro něj důležitější.", - }, - { - "Co Galén požaduje?", - { - "Peníze za vše", - "Nasazení léku a mír", - "Válku", - "Zákaz medicíny", - }, - 1, - "Humanitní řešení.", - }, - { - "Jaký je tón hry?", - { - "Pouze veselý", - "Satirický i tragický", - "Bez dialogu", - "Pouze lyrický", - }, - 1, - "Čapek kombinuje satiru s vážností.", - }, - { - "Souvislost s R.U.R.?", - { - "Stejný autor Čapek", - "Stejný děj", - "Obě napsal Shakespeare", - "Žádná", - }, - 0, - "Čapek napsal obě dramata.", - }, - { - "Proč je Bílá nemoc maturitní?", - { - "Nejkratší", - "České meziválečné drama s aktuálními tématy", - "Bez myšlenky", - "Pouze komedie", - }, - 1, - "Patří k Čapkovu kanonu.", - }, - { - "Kdo Galénovi brání?", - { - "Pacienti", - "Politicko-ekonomická moc", - "Jeho lék", - "Učitelé", - }, - 1, - "Systém nechce „klid“.", - }, - { - "Jak se nemoc šíří?", - { - "Jen po vodě", - "Epidemicky, panika roste", - "Jen v zimě", - "Nešíří se", - }, - 1, - "Epidemie je motiv strachu.", - }, - { - "Co Millionáři v dramatu?", - { - "Léčí", - "Reprezentují elitu indiferentní nebo zainteresovanou", - "Jsou děti", - "Neexistují", - }, - 1, - "Elita je součást kritiky.", - }, - { - "Galénův otec symbolizuje…", - { - "Válku", - "Vědeckou tradici a naději léku", - "Cirkus", - "Policii", - }, - 1, - "Odkaz otce je klíč k léku.", - }, - { - "Jaký jazyk hry?", - { - "Středověký", - "Spisovný dialog, publicistický přesah", - "Cizí bez překladu", - "Pouze pění", - }, - 1, - "Typický Čapek dialog.", - }, - { - "Co je hlavní konflikt?", - { - "Láska trojúhelník", - "Humanita (léčba) vs. moc (válka)", - "Sport", - "Rodinná komedie", - }, - 1, - "Ústřední osa.", - }, - { - "Která postava je militarista?", - { - "Galén", - "Maršál", - "Galénův pacient dítě", - "Kněz", - }, - 1, - "Maršál vede stát k válce.", - }, - { - "Jak publikum vnímalo hru v 30. letech?", - { - "Jako varování před evropskou krizí", - "Jako dětskou pohádku", - "Jako historii starověku", - "Jako vědecký manuál", - }, - 0, - "Současníci vnímali politický subtext.", - }, - { - "Co se stane s Galénem?", - { - "Stane se králem", - "Je obětí systému / tragický osud (v závislosti na inscenaci textu)", - "Emigruje bohatý", - "Zničí lék", - }, - 1, - "Galén nemůže prosadit dobro.", - }, - { - "Allegorie vs. realismus?", - { - "Hra je jen realismus bez symbolu", - "Kombinuje reálnou epidemii s politickou metaforou", - "Jen pohádka", - "Jen dokument", - }, - 1, - "Dvojí rovina významu.", - }, - { - "Jaké poselství pro maturitu?", - { - "Válka je vždy dobrá", - "Lidskost a rozum musí předcházet moci a zisku", - "Nemoci neexistují", - "Lékaři jsou zbyteční", - }, - 1, - "Humanistické varování Čapka.", - }, - { - "Žánr v katalogu maturit?", - { - "Poezie", - "Drama", - "Próza", - "Epos", - }, - 1, - "Uvedeno jako drama.", - }, - { - "Kdo není autorem Bílé nemoci?", - { - "Karel Čapek", - "Josef Čapek", - "Karel Čapek napsal hru", - "Karel Čapek dramatik", - }, - 1, - "Autor je Karel, ne Josef (byť bratři).", - }, -}; - -static const AssemblyItem book_bila_nemoc_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Vypukne bílá nemoc a panika roste", - "Galén má lék, moc váhá kvůli válce", - "Maršál a zbrojaři tlačí na konflikt", - "Galén se snaží prosadit humanitní řešení", - "Společnost a elita lék zablokují", - "Tragický závěr – válka a smrt převažují", - }, - 6, - }, -}; - -static const char *book_bila_nemoc_plot_meaning[] = { - "Pořadí: epidemie → lék Galéna → tlak moci → boj Galéna → blokace → tragédie.", -}; - -static const LitQ book_bylo_nas_pet_qs[] = { - { - "Autor Bylo nás pět?", - { - "Viewegh", - "Poláček", - "Hašek", - "Neruda", - }, - 1, - "Karel Poláček.", - }, - { - "Kdy vyšlo?", - { - "1926", - "1945", - "1990", - "1890", - }, - 0, - "Meziválečné vydání.", - }, - { - "Kolik sourozenců?", - { - "Tři", - "Pět dětí v rodině", - "Deset", - "Jedno", - }, - 1, - "Název odkazuje na pět dětí.", - }, - { - "Kdo vypráví?", - { - "Otec", - "Jaromír v ich-formě", - "Učitel", - "Vševěd", - }, - 1, - "Nejmladší bratr vypravěč.", - }, - { - "Žánr?", - { - "Tragedie", - "Humoristický román o dětství", - "Sci-fi", - "Epos", - }, - 1, - "Poláček humor.", - }, - { - "Prostředí?", - { - "Pražský palác", - "Maloměsto/rodinný domov", - "Luna", - "Moře", - }, - 1, - "Venkov/město.", - }, - { - "Tón?", - { - "Bez humoru", - "Laskavý humor, groteska", - "Horor", - "Epická vážnost", - }, - 1, - "Typický Poláček.", - }, - { - "Téma rodiny?", - { - "Chybí", - "Sounáležitost, generace, chudoba i radost", - "Jen bohatství", - "Jen válka", - }, - 1, - "Rodina je střed.", - }, - { - "Škola v knize?", - { - "Neexistuje", - "Epizody strachu a legrace", - "Jen univerzita", - "Jen internát", - }, - 1, - "Školní historky.", - }, - { - "Poláček vs. Viewegh?", - { - "Poláček meziválečí, Viewegh normalizace", - "Totéž", - "Viewegh starší", - "Poláček sci-fi", - }, - 0, - "Různá éra.", - }, - { - "Jazyk?", - { - "Archaičtina", - "Hovorový humor spisovně", - "Němčina", - "Latina", - }, - 1, - "Srozumitelná čeština.", - }, - { - "Proč maturitní?", - { - "Nejdelší", - "Klasika českého humoru a dětství", - "Cizí jazyk", - "Bez postav", - }, - 1, - "Kanón české prózy.", - }, - { - "Jaromír je…", - { - "Nejstarší", - "Nejmladší vypravěč", - "Učitel", - "Cizinec", - }, - 1, - "Perspektiva nejmladšího.", - }, - { - "Postava kněze?", - { - "Typ venkovského duchovního v epizodách", - "Hlavní hrdina války", - "Neexistuje", - "Sci-fi", - }, - 0, - "Součást maloměsta.", - }, - { - "Chudoba?", - { - "Ne", - "Prosvítá humorně, ne depresivně", - "Hlavní téma hrůzy", - "Ignorována", - }, - 1, - "Poláček neidealizuje, ale nezesmutňuje.", - }, - { - "Forma?", - { - "Drama", - "Epizodický román", - "Poezie", - "Deník bez děje", - }, - 1, - "Kapitoly epizod.", - }, - { - "Co děti zažívají?", - { - "Jen politiku", - "Hry, školu, sousedské historky", - "Jen válku", - "Nic", - }, - 1, - "Dětský svět.", - }, - { - "Groteska?", - { - "Ne", - "Ano, nadsázka situací", - "Pouze tragédie", - "Pouze básně", - }, - 1, - "Poláčkův styl.", - }, - { - "Identita autora?", - { - "Poláček židovský původ – jemně v prostředí", - "Neznámá", - "Sci-fi", - "Bez vlivu", - }, - 0, - "Kontext biografie.", - }, - { - "Sourozenci Ondřej?", - { - "Nepostava", - "Starší bratr v rodině", - "Král", - "Pes", - }, - 1, - "Součást pěti.", - }, - { - "Hela?", - { - "Sestra", - "Cizí stát", - "Učitel", - "Nemoc", - }, - 0, - "Sourozenec.", - }, - { - "Motiv domova?", - { - "Silný – bezpečí i pořádek", - "Slabý", - "Neexistuje", - "Jen hotel", - }, - 0, - "Domov jako centrum.", - }, - { - "Kdo NENÍ Poláček?", - { - "Autor humoru", - "Autor Bylo nás pět", - "Hašek autor této knihy", - "Spisovatel", - }, - 2, - "Hašek psal Švejka.", - }, - { - "Vyprávěcí forma?", - { - "Er", - "Ich (Jaromír)", - "Druhá osoba", - "Bez vypravěče", - }, - 1, - "Dětské já.", - }, - { - "Cíl humoru?", - { - "Ponižovat děti", - "Humanizovat dětství a rodinu", - "Propaganda", - "Strach", - }, - 1, - "Laskavost.", - }, - { - "Epizoda s psem/cirkusem?", - { - "Typické kapitoly maloměstského života", - "Ne v knize", - "Jen ve filmu", - "Sci-fi", - }, - 0, - "Maloměstské epizody.", - }, - { - "Období děje?", - { - "Středověk", - "Meziválečí / Poláčkovo dětství", - "Budoucnost", - "Antika", - }, - 1, - "Autobiografické prvky.", - }, - { - "Proč ich-forma?", - { - "Autenticita dětského pohledu", - "Náhodou", - "Pouze u Poláčka zakázáno", - "Kvůli překladu", - }, - 0, - "Dítě vidí jinak.", - }, - { - "Konec knihy?", - { - "Epizodický, bez jedné akce", - "Jedna bitva", - "Svatba Jaromíra", - "Apokalypsa", - }, - 0, - "Koláž vzpomínek.", - }, - { - "Poselství?", - { - "Dětství a rodina stojí za humorné vyprávění", - "Rodina škodí", - "Humor je hřích", - "Děti neposlouchat", - }, - 0, - "Teplo a humor.", - }, - { - "Žánr v katalogu?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Rok vydání 1926 znamená?", - { - "Meziválečná literatura", - "Normalizace", - "Socialismus 50. let", - "Středověk", - }, - 0, - "První republika kontext.", - }, -}; - -static const AssemblyItem book_bylo_nas_pet_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Rodina pěti dětí v maloměstě", - "Jaromírovy školní a domácí epizody", - "Humorné situace se sousedy a učiteli", - "Sourozenecké hry a drobné konflikty", - "Rodiče udržují domov navzdory chudobě", - "Dětství jako koláž vzpomínek", - }, - 6, - }, -}; - -static const char *book_bylo_nas_pet_plot_meaning[] = { - "Pořadí: rodina → škola/domov → sousedé → sourozenci → rodiče → vzpomínkový celek.", -}; - -static const LitQ book_cekani_na_godota_qs[] = { - { - "Autor?", - { - "Beckett", - "Ionesco", - "Shakespeare", - "Čapek", - }, - 0, - "Samuel Beckett.", - }, - { - "Žánr?", - { - "Opera", - "Absurdní drama", - "Epos", - "Detektivka", - }, - 1, - "Klíčové dílo absurdního divadla.", - }, - { - "Kolik dějství?", - { - "Jedno", - "Dvě (opakující se struktura)", - "Pět", - "Deset", - }, - 1, - "Dvě dějství podobně.", - }, - { - "Kdo čeká?", - { - "Hamlet", - "Vladimír a Estragon", - "Godot sám", - "Nikdo", - }, - 1, - "Dvojice tramps.", - }, - { - "Přijde Godot?", - { - "Ano hned", - "Ne (aspoň v průběhu hry)", - "Ano v epilogu", - "Je to Estragon", - }, - 1, - "Godot je nedosažitelný.", - }, - { - "Kde se děj odehrává?", - { - "Paříž salón", - "Silnice u stromu", - "Luna", - "Praha", - }, - 1, - "Minimalistické jeviště.", - }, - { - "Kdo je Pozzo?", - { - "Bůh", - "Pán vedoucí Lucka na provaze", - "Kněz", - "Hasič", - }, - 1, - "Objeví se v obou dějstvích.", - }, - { - "Lucky?", - { - "Král", - "Nosič Pozzova, monolog", - "Godot", - "Strom", - }, - 1, - "Slavný chaotický monolog.", - }, - { - "Rok premiéry?", - { - "1850", - "1952", - "1989", - "1600", - }, - 1, - "1952 Paříž.", - }, - { - "Jazyk hry?", - { - "Bez slov", - "Triviální dialog, filozofické otázky", - "Pouze zpěv", - "Latina", - }, - 1, - "Paradox hluboké banality.", - }, - { - "Co dělají Didi a Gogo?", - { - "Válka", - "Čekají, hádají se, hraje hry", - "Pilí zlato", - "Učí školu", - }, - 1, - "Rutina čekání.", - }, - { - "Chlapec?", - { - "Přináší zprávu od Godota", - "Zabije Pozza", - "Je Godot", - "Neexistuje", - }, - 0, - "Posel.", - }, - { - "Strom v druhém dějství?", - { - "Mizí", - "Má listí – čas uběhl", - "Hoří", - "Promění se v dům", - }, - 1, - "Jediná změna prostředí.", - }, - { - "Téma absurdního divadla?", - { - "Jasný happy end", - "Smysl života nejistý, opakování", - "Historická přesnost", - "Pouze komedie slapstick", - }, - 1, - "Existenciální prázdnota.", - }, - { - "Beckett – národnost?", - { - "Irsko / psal francouzsky i anglicky", - "Jen český", - "Jen ruský", - "Jen německý", - }, - 0, - "Irský autor.", - }, - { - "Překlad maturita?", - { - "Ouředník", - "Nevrla", - "Nezval", - "Gössell", - }, - 0, - "V katalogu Ouředník.", - }, - { - "Proč maturitní?", - { - "Nejdelší", - "Zásadní drama 20. stol.", - "Bez významu", - "Pouze film", - }, - 1, - "Kanón světového divadla.", - }, - { - "Godot symbol?", - { - "Konkrétní člověk", - "Naděje/Bůh/smysl, který nepřijde", - "Strom", - "Pes", - }, - 1, - "Interpretace otevřená.", - }, - { - "Opakování dějství?", - { - "Stejná struktura – absurdita rutiny", - "Totálně jiný děj", - "Jen jedno", - "Opera", - }, - 0, - "Cyklus čekání.", - }, - { - "Estragonovy boty?", - { - "Epizoda pomoci a starosti", - "Nezmíněny", - "Hlavní zbraň", - "Godot", - }, - 0, - "Lidská péče v prázdnu.", - }, - { - "Pozzo slepne?", - { - "Ve druhém dějství – křehkost moci", - "Ne", - "Hned na začátku", - "Lucky", - }, - 0, - "Proměna postav.", - }, - { - "Monolog Luckyho?", - { - "Chaotická „věda“ a rétorika", - "Krátké ano", - "Zpěv opery", - "Mlčení", - }, - 0, - "Satira slov.", - }, - { - "Vladimír vs Estragon?", - { - "Didi víc přemýšlí, Gogo fyzicky trpí", - "Totéž", - "Jsou bratři králové", - "Nepřátelé", - }, - 0, - "Doplňují se.", - }, - { - "Konflikt?", - { - "Bitva", - "Spíš vnitřní – nuda, strach, čekání", - "Detektivní", - "Soudní", - }, - 1, - "Minimum vnějšího děje.", - }, - { - "Konec hry?", - { - "Godot přijde", - "Opět rozhodnutí odejít a zůstat čekat", - "Svatba", - "Válka", - }, - 1, - "Otevřený cyklus.", - }, - { - "Ionesco vs Beckett?", - { - "Obě absurdní drama, jiná díla", - "Totéž kniha", - "Ionesco napsal Godota", - "Beckett Revizor", - }, - 0, - "Stejný směr, jiní autoři.", - }, - { - "Co NENÍ v Godotovi?", - { - "Dialog", - "Čekání", - "Epická bitva", - "Strom", - }, - 2, - "Bez epické akce.", - }, - { - "Poselství?", - { - "Život může být čekáním bez jistoty", - "Vždy přijde spása", - "Čekání zbytečné vůbec neřešit", - "Godot je hrdina", - }, - 0, - "Existenciální otázka.", - }, - { - "Forma?", - { - "Báseň", - "Divadelní hra", - "Román", - "Esej", - }, - 1, - "Drama.", - }, - { - "Titulní jméno Godot?", - { - "Vyslovuje se, nikdo nepřichází", - "Hlavní mluvící postava", - "Strom", - "Pes", - }, - 0, - "Absence je pointa.", - }, - { - "Druhé dějství podobné prvnímu?", - { - "Ano – opakování s malými změnami", - "Ne", - "Je to operní finále", - "Je kratší o polovinu", - }, - 0, - "Struktura absurdní rutiny.", - }, -}; - -static const AssemblyItem book_cekani_na_godota_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Vladimír a Estragon čekají u stromu", - "Přicházejí Pozzo a Lucky", - "Monolog a rozhovory, Godot nejde", - "Chlapec: Godot nepřijde zítra", - "Druhé dějství – opět čekání", - "Rozhodnutí odejít, ale zůstávají v cyklu", - }, - 6, - }, -}; - -static const char *book_cekani_na_godota_plot_meaning[] = { - "Pořadí: čekání → Pozzo/Lucky → zpráva → druhé dějství → opakování → cyklus čekání.", -}; - -static const LitQ book_ceske_nebe_qs[] = { - { - "Autoři?", - { - "Svěrák a Smoljak", - "Čapek bratři", - "Shakespeare", - "Viewegh", - }, - 0, - "Dvojice autorů Cimrmanova divadla.", - }, - { - "Žánr?", - { - "Tragedie", - "Komické drama / fraška", - "Epos", - "Sci-fi", - }, - 1, - "Humor divadla Jára Cimrmana.", - }, - { - "Co je „české nebe“?", - { - "Meteorologický atlas", - "Parodické téma o české zemi a duchu", - "Bible", - "Učebnice", - }, - 1, - "Metafora vlasti v grotesce.", - }, - { - "Kdy hra vznikla?", - { - "1890", - "1976", - "2000", - "1942", - }, - 1, - "Součást Cimrmanova divadla.", - }, - { - "Jára Cimrman?", - { - "Skutečný král", - "Fiktivní český génius divadla", - "Hasič", - "Německý spisovatel", - }, - 1, - "Centrální postava značky.", - }, - { - "Styl humoru?", - { - "Bez vtipu", - "Pseudověda, paradox, groteska", - "Pouze tragédie", - "Horor", - }, - 1, - "Typické Cimrmanovo.", - }, - { - "Divadlo?", - { - "Národní bez Smoljaka", - "Divadlo Jára Cimrmana", - "Broadway", - "Antika", - }, - 1, - "Základní kontext.", - }, - { - "Proč maturitní?", - { - "Nejkratší", - "České drama konce 20. stol., kultura", - "Anglicky", - "Bez textu", - }, - 1, - "Reprezentuje českou komedii.", - }, - { - "Parodie?", - { - "Vážná historie bez nadsázky", - "Nadsázka českých dějin a mýtů", - "Jen sci-fi", - "Jen poezie", - }, - 1, - "Historie jako gag.", - }, - { - "Smoljak role?", - { - "Spoluautor", - "Nepiš", - "Shakespeare", - "Překladatel Godota", - }, - 0, - "Spolu se Svěrákm.", - }, - { - "Svěrák role?", - { - "Spoluautor", - "Victor Hugo", - "Beckett", - "Nezval", - }, - 0, - "Spoluautor.", - }, - { - "Tón?", - { - "Pouze smutek", - "Lehkost, wordplay", - "Naturalismus", - "Operní", - }, - 1, - "Komický dialog.", - }, - { - "Politický subtext?", - { - "Groteska může metaforicky reagovat na éru", - "Přímý manifest", - "Ne", - "Jen válka", - }, - 0, - "Normalizační kontext jemně.", - }, - { - "Forma?", - { - "Román", - "Divadelní hra", - "Báseň", - "Esej", - }, - 1, - "Drama v katalogu.", - }, - { - "Postavy historické?", - { - "Groteskně parodované", - "Přesně dokumentární", - "Chybí", - "Jen cizinci", - }, - 0, - "Ne učebnice.", - }, - { - "Cílové publikum?", - { - "Diváci divadla, maturanti", - "Jen děti", - "Jen vědci", - "Nikdo", - }, - 0, - "Divadelní text.", - }, - { - "Co NENÍ Cimrman?", - { - "Značka divadla", - "Fiktivní postava", - "Reálný panovník", - "Humor", - }, - 2, - "Cimrman není reálná historická osoba.", - }, - { - "České nebe vs Vyšetřování ztráty třídní knihy?", - { - "Obě Smoljak/Svěrák", - "Obě Shakespeare", - "Stejný název", - "Obě poezie", - }, - 0, - "Stejný autorský tým.", - }, - { - "Jazyk?", - { - "Středověká čeština bez humoru", - "Spisovná čeština, vtipné repliky", - "Němčina", - "Latina", - }, - 1, - "Srozumitelný humor.", - }, - { - "Hlavní děj?", - { - "Lineární válka", - "Souvislý skečový průběh parodie nebe/dějin", - "Detektivka", - "Lyrika", - }, - 1, - "Fraškovitá stavba.", - }, - { - "Smysl nebe v titulu?", - { - "Astronomie", - "Symbol vlasti a duchovního", - "Jen počasí", - "Cizina", - }, - 1, - "Metafora.", - }, - { - "Inscenace?", - { - "Původně DJC Žižkov", - "Globe London", - "Antika", - "Jen radio", - }, - 0, - "Cimrmanovo divadlo.", - }, - { - "Vztah k historii?", - { - "Respekt bez vtipu", - "Hra s historií, ne lekce", - "Přesný učebnicový text", - "Zakázaná", - }, - 1, - "Parodie.", - }, - { - "Ensemble?", - { - "Jeden herec", - "Soubor postav / herecký soubor", - "Pouze orchestr", - "Film", - }, - 1, - "Divadelní forma.", - }, - { - "Maturita – co znát?", - { - "Autory, žánr, Cimrman, parodii", - "Jen rok 1066", - "Jen anglicky", - "Nic", - }, - 0, - "Základní kontext.", - }, - { - "Groteska?", - { - "Ano", - "Ne", - "Jen tragédie", - "Jen dokument", - }, - 0, - "Cimrman styl.", - }, - { - "Konec hry?", - { - "Komické finále ve stylu souboru", - "Hamletova smrt", - "Bitva", - "Ticho", - }, - 0, - "Fraška.", - }, - { - "Poselství?", - { - "Humor o identitě bez pompy", - "Nacionalismus vážně", - "Nenávist", - "Bez témat", - }, - 0, - "Sebeironie národa.", - }, - { - "Katalog žánr?", - { - "Drama", - "Poezie", - "Próza", - "Opera", - }, - 0, - "Drama.", - }, - { - "Rok 1976?", - { - "Normalizace", - "Středověk", - "Budoucnost", - "1848", - }, - 0, - "Kontext vzniku.", - }, - { - "Typická replika styl?", - { - "Dlouhá pseudovědecká úvaha s pointou", - "Bez dialogu", - "Jen pění", - "Latinská mše", - }, - 0, - "Cimrmanovský projev.", - }, -}; - -static const AssemblyItem book_ceske_nebe_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Uvedení do parodie „českého nebe“", - "Groteskní obrazy dějin", - "Cimrmanovské výklady a gagy", - "Satira na národní mýty", - "Souborové scénky", - "Komické finále frašky", - }, - 6, - }, -}; - -static const char *book_ceske_nebe_plot_meaning[] = { - "Pořadí: úvod → parodie dějin → gagy → satira → scénky → finále.", -}; - -static const LitQ book_dekameron_qs[] = { - { - "Autor Dekameronu?", - { - "Dante", - "Boccaccio", - "Petrarca", - "Shakespeare", - }, - 1, - "Giovanni Boccaccio.", - }, - { - "Kdy vznik?", - { - "1350 kolem", - "1800", - "1900", - "500 př. n. l.", - }, - 0, - "Středověká renesance.", - }, - { - "Kolik novel?", - { - "10", - "100", - "1000", - "1", - }, - 1, - "Deset dní po deseti.", - }, - { - "Rámec?", - { - "Bitva", - "Únik Florencie před morem na venkov", - "Luna", - "Praha", - }, - 1, - "Mor jako rámec.", - }, - { - "Kolik vypravěčů v rámu?", - { - "Deset mladých", - "Jeden král", - "Sto", - "Nikdo", - }, - 0, - "5 mužů, 5 žen typicky.", - }, - { - "Žánr?", - { - "Epos", - "Sbírka novel s rámcem", - "Drama", - "Poezie", - }, - 1, - "Novelistický cyklus.", - }, - { - "Jazyk originálu?", - { - "Latina", - "Italština (vernacular)", - "Řečtina", - "Francouzština", - }, - 1, - "Vernakulární italština.", - }, - { - "Téma novel?", - { - "Pouze válka", - "Láska, lest, humor, společnost", - "Pouze náboženství", - "Pouze sci-fi", - }, - 1, - "Rozmanitost.", - }, - { - "Překlad maturita?", - { - "Krátký", - "Nezval", - "Nevrla", - "Skoumal", - }, - 0, - "V katalogu Krátký.", - }, - { - "Florencie?", - { - "Místo moru a odchodu", - "Nezmíněna", - "Pouze vesnice", - "Amerika", - }, - 0, - "Historická Florencie.", - }, - { - "Humanismus?", - { - "Světský zájem o člověka", - "Ne", - "Pouze teologie", - "Stoicismus", - }, - 0, - "Renesanční přístup.", - }, - { - "Satira?", - { - "Na kněze, měšťany, lidské slabosti", - "Ne", - "Pouze na krále", - "Zakázaná", - }, - 0, - "Často kritické.", - }, - { - "Fortuna?", - { - "Motiv štěstí/osudu v příbězích", - "Postava Godota", - "Ne", - "Jen město", - }, - 0, - "Středověký motiv.", - }, - { - "Erotika?", - { - "Součást některých novel", - "Neexistuje", - "Celá kniha bez lásky", - "Zakázáno", - }, - 0, - "Provokativní pro dobu.", - }, - { - "Proč maturitní?", - { - "Klasika světové prózy", - "Nejkratší", - "Bez rámce", - "Jen české", - }, - 0, - "Kanón.", - }, - { - "Dante vs Boccaccio?", - { - "Obě italské, různá díla", - "Totéž", - "Boccaccio Božská komedie", - "Dante Dekameron", - }, - 0, - "Trecento literatura.", - }, - { - "Struktura dne?", - { - "10 novel denně", - "1 ročně", - "100 denně", - "0", - }, - 0, - "Deset dní.", - }, - { - "Pampinea?", - { - "Jedna z vypravěček v rámu", - "Mor", - "Město", - "Pes", - }, - 0, - "Jméno v rámu.", - }, - { - "Venkovské sídlo?", - { - "Útočiště před morem", - "Vězení", - "Boj", - "Nebe", - }, - 0, - "Kontext rámce.", - }, - { - "Novela vs román?", - { - "Kratší příběh v souboru", - "Totéž", - "Pouze báseň", - "Epos", - }, - 0, - "Forma.", - }, - { - "Kritika církve?", - { - "Ano v některých příbězích", - "Ne", - "Pouze chvála", - "Zakázáno", - }, - 0, - "Světský pohled.", - }, - { - "Renesance?", - { - "Raná renesance Itálie", - "Baroko", - "Romantismus", - "Existencialismus", - }, - 0, - "Období.", - }, - { - "Vyprávění v rámu?", - { - "Střídání vypravěčů po dnech", - "Jeden monolog", - "Bez slov", - "Opera", - }, - 0, - "Organizace.", - }, - { - "Co NENÍ Dekameron?", - { - "100 novel", - "Rámec s morem", - "Shakespearova tragédie", - "Italská próza", - }, - 2, - "Shakespeare jinak.", - }, - { - "Laskavý humor?", - { - "Často", - "Nikdy", - "Pouze horor", - "Pouze epos", - }, - 0, - "Lehkost i drsnost.", - }, - { - "Petrarca?", - { - "Současník, jiná díla", - "Autor Dekameronu", - "Čech", - "Beckett", - }, - 0, - "Kontext trecenta.", - }, - { - "Poselství?", - { - "Život je rozmanitý – příběhy mapují společnost", - "Jen mor", - "Jen válka", - "Bez smyslu", - }, - 0, - "Encyklopedie příběhů.", - }, - { - "Krátký překlad?", - { - "Český překlad v maturitě", - "Anglický autor", - "Neexistuje", - "Latina", - }, - 0, - "Katalog.", - }, - { - "Žánr katalog?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Rámec končí?", - { - "Návrat do města po moru", - "Válka", - "Apokalypsa", - "Ne", - }, - 0, - "Uzavření úniku.", - }, - { - "Typ hrdinky?", - { - "Často chytrá, aktivní žena", - "Pouze pasivní", - "Neexistuje", - "Jen král", - }, - 0, - "Renesanční typy.", - }, -}; - -static const AssemblyItem book_dekameron_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Mor sužuje Florencii", - "Deset mladých odchází na venkov", - "Každý den vyprávějí novely", - "Střídání témat lásky a lsti", - "Deset dní po deseti příbězích", - "Návrat k životu po krizi", - }, - 6, - }, -}; - -static const char *book_dekameron_plot_meaning[] = { - "Pořadí: mor → únik → vyprávění → témata → 100 novel v rámci → konec úniku.", -}; - -static const LitQ book_den_trifidu_qs[] = { - { - "Autor?", - { - "Wyndham", - "Bradbury", - "Orwell", - "Collins", - }, - 0, - "John Wyndham.", - }, - { - "Rok?", - { - "1951", - "1984", - "2000", - "1890", - }, - 0, - "Poválečné sci-fi.", - }, - { - "Co jsou trifidy?", - { - "Ptáci", - "Mobilní rostliny s jedovatými lashmi", - "Lidé", - "Auta", - }, - 1, - "Uměle vyšlechtěné rostliny.", - }, - { - "Proč většina oslepne?", - { - "Válka", - "Sledování zeleného meteorického roje", - "Mor", - "Hlad", - }, - 1, - "Klíčová katastrofa.", - }, - { - "Hrdina Bill?", - { - "Biolog se zavázanýma očima v nemocnici", - "Hasič", - "Král", - "Trifid", - }, - 0, - "Přežije díky obvazům.", - }, - { - "Josella?", - { - "Partnerka, spisovatelka", - "Trifid", - "Generál", - "Neexistuje", - }, - 0, - "Důležitá postava.", - }, - { - "Coker?", - { - "Organizátor přeživších", - "Trifid", - "Dítě", - "Meteor", - }, - 0, - "Pragmatik.", - }, - { - "Kolonel?", - { - "Vojenský vůdce komunity", - "Rostlina", - "Billův bratr", - "Kněz", - }, - 0, - "Struktura moci.", - }, - { - "Žánr?", - { - "Postapokalyptické sci-fi", - "Pohádka", - "Epos", - "Lyrika", - }, - 0, - "Katastrofa + věda.", - }, - { - "Překlad?", - { - "Kořán", - "Nezval", - "Nevrla", - "Skoumal", - }, - 0, - "Katalog Kořán.", - }, - { - "Prostředí?", - { - "Británie", - "Pouze Mars", - "Praha", - "Antarktida", - }, - 0, - "Anglie.", - }, - { - "Trifidy proč nebezpečné?", - { - "Jed a pohyb", - "Jen hezké", - "Nejsou", - "Zpívají", - }, - 0, - "Zabíjejí slepé.", - }, - { - "Ostrov na konci?", - { - "Naděje na adaptaci lidstva", - "Ne v knize", - "Smrt všech", - "Trifidí království", - }, - 0, - "Finále na ostrově.", - }, - { - "Téma?", - { - "Přežití, morálka, příroda", - "Jen láska", - "Jen sport", - "Středověk", - }, - 0, - "Katastrofický román.", - }, - { - "Wyndham styl?", - { - "Realistické sci-fi", - "Pouze fantasy", - "Bez děje", - "Poezie", - }, - 0, - "„Logical disaster“.", - }, - { - "Proč maturitní?", - { - "Klasické sci-fi", - "Nejkratší", - "Bez témat", - "Jen film", - }, - 0, - "Kanón žánru.", - }, - { - "Bill v nemocnici?", - { - "Operace očí, bandáže zachrání zrak", - "Slepý navždy hned", - "Trifid", - "Ne", - }, - 0, - "Výchozí situace.", - }, - { - "Komunity přeživších?", - { - "Boj o jídlo, pořádek, strach", - "Raj", - "Neexistují", - "Jen armáda", - }, - 0, - "Společenský kolaps.", - }, - { - "Náboženský fanatismus?", - { - "Objevuje se u některých skupin", - "Ne", - "Celá kniha modlitby", - "Zakázáno", - }, - 0, - "Kritika reakcí.", - }, - { - "Trifidí původ?", - { - "Laboratoř / olej", - "Nebe", - "Dinosauři", - "Magie", - }, - 0, - "Světová závislost na oleji.", - }, - { - "Co NENÍ?", - { - "Meteoritní slepota", - "Trifidy", - "Hamlet", - "Přežití", - }, - 2, - "Hamlet jiné.", - }, - { - "Josella role?", - { - "Emoční partnerství s Bill", - "Generál", - "Trifid", - "Meteor", - }, - 0, - "Lidský vztah.", - }, - { - "Finále tón?", - { - "Otevřená naděje i nejistota", - "Všichni mrtví", - "Svatba", - "Komunismus", - }, - 0, - "Adaptace.", - }, - { - "Er-forma?", - { - "Bill vypravěč", - "Ich Anne", - "Vševěd", - "Bez vypravěče", - }, - 0, - "Masen vypráví.", - }, - { - "Katalog žánr?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Den trifidů titul?", - { - "První den dominance trifidů", - "Pondělí", - "Vánoce", - "Den D", - }, - 0, - "Začátek katastrofy.", - }, - { - "Slepí lidé?", - { - "Bezbranní vůči trifidům", - "Silnější", - "Neexistují", - "Vidí", - }, - 0, - "Dramatická situace.", - }, - { - "Věda v knize?", - { - "Bill biolog – racionalita", - "Ne", - "Pouze magie", - "Zakázána", - }, - 0, - "Vědecký hrdina.", - }, - { - "Poselství?", - { - "Civilizace křehká, příroda může převrátit", - "Vždy vítězí", - "Trifidi neexistují", - "Slepota výhoda", - }, - 0, - "Varování.", - }, - { - "Film?", - { - "Existují adaptace", - "Neexistuje nikdy", - "Zakázáno", - "Jen opera", - }, - 0, - "Kultovní.", - }, - { - "Kořán?", - { - "Český překladatel", - "Autor", - "Trifid", - "Postava", - }, - 0, - "Překlad.", - }, - { - "Vztah k 1984?", - { - "Jiné sci-fi, jiný autor", - "Totéž", - "Orwell Wyndham", - "Stejný děj", - }, - 0, - "Různá díla.", - }, -}; - -static const AssemblyItem book_den_trifidu_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Zelený roj oslepí lidstvo", - "Bill Masen přežívá se zrakem", - "Chaos a trifidi zabíjejí slepé", - "Bill a Josella hledají bezpečí", - "Konflikty komunit a kolonel", - "Únik na ostrov a nejistá budoucnost", - }, - 6, - }, -}; - -static const char *book_den_trifidu_plot_meaning[] = { - "Pořadí: slepota → Bill → trifidi → útěk → komunity → ostrov.", -}; - -static const LitQ book_denik_anny_frankove_qs[] = { - { - "Autorka?", - { - "Anne Franková", - "Viewegh", - "Brontë", - "Collins", - }, - 0, - "Anne Franková.", - }, - { - "Forma?", - { - "Deník", - "Epos", - "Drama", - "Báseň", - }, - 0, - "Deníkové zápisy.", - }, - { - "Kde úkryt?", - { - "Amsterdam", - "Praha", - "Berlín", - "Paříž", - }, - 0, - "Nizozemsko.", - }, - { - "Období zápisů?", - { - "1942–1944", - "1914–1918", - "1989", - "1600", - }, - 0, - "Válka.", - }, - { - "Proč v úkrytu?", - { - "Pronásledování Židů", - "Dovolená", - "Sport", - "Škola", - }, - 0, - "Holocaust.", - }, - { - "Kitty?", - { - "Vymyšlená adresátka deníku", - "Sestra", - "Učitelka", - "Německá officer", - }, - 0, - "Deník píše „milé Kitty“.", - }, - { - "Otto Frank?", - { - "Otec, přežil", - "Gestapo", - "Neexistuje", - "Anne nepíše", - }, - 0, - "Jediný z rodiny v úkrytu často přežil.", - }, - { - "Margot?", - { - "Starší sestra", - "Matka", - "Trifid", - "Učitel", - }, - 0, - "Sestra Anny.", - }, - { - "Spoluúkrytí?", - { - "Van Pels (Daans v některých vydáních)", - "Nikdo", - "Jen Anne", - "Sto lidí", - }, - 0, - "Další rodina v bytě.", - }, - { - "Miep Gies?", - { - "Pomáhala potravinami", - "Gestapo", - "Anne", - "Hitler", - }, - 0, - "Ochránkyně.", - }, - { - "Tón deníku?", - { - "Osobní, dospívající, i humor", - "Pouze veselý", - "Bez emocí", - "Latina", - }, - 0, - "Autentický hlas.", - }, - { - "Odhalení?", - { - "1944, deportace", - "Nikdy", - "1940", - "1990", - }, - 0, - "Tragický zlom.", - }, - { - "Osud Anny?", - { - "Auschwitz, Belsen, smrt 1945", - "Přežila", - "Emigrace USA", - "Neznámý", - }, - 0, - "Historický fakt.", - }, - { - "Vydání deníku?", - { - "Otto po válce", - "Anne za života knižně", - "Hitler", - "Ne", - }, - 0, - "Otec vydal.", - }, - { - "Proč maturitní?", - { - "Svědectví Holocaustu", - "Nejdelší", - "Fikce", - "Bez témat", - }, - 0, - "Důležité svědectví.", - }, - { - "Ich-forma?", - { - "Anne píše o sobě", - "Er", - "Vševěd", - "Bez já", - }, - 0, - "Deník.", - }, - { - "Konflikty v úkrytu?", - { - "Těsná izolace, neshody", - "Ne", - "Válka venku ne", - "Jen sport", - }, - 0, - "Psychická zátěž.", - }, - { - "Sny Anny?", - { - "Spisovatelka, svoboda", - "Voják", - "Ne", - "Královna", - }, - 0, - "Ambice.", - }, - { - "Holocaust?", - { - "Genocida Židů", - "Sport", - "Ne", - "Pouze fikce", - }, - 0, - "Kontext.", - }, - { - "Co NENÍ?", - { - "Deník", - "Úkryt", - "Hamlet", - "Anne", - }, - 2, - "Hamlet drama.", - }, - { - "Jazyk originálu?", - { - "Holština / němčina verze", - "Čeština originál", - "Latina", - "Ruština", - }, - 0, - "Anne psala nizozemsky.", - }, - { - "Téma dospívání?", - { - "Tělo, láska, identita v úkrytu", - "Ne", - "Pouze politika", - "Pouze jídlo", - }, - 0, - "Dvojí rovina.", - }, - { - "Strach?", - { - "Stálý – krok, prozrazení", - "Ne", - "Jen venku", - "Neexistuje", - }, - 0, - "Atmosféra.", - }, - { - "Naděje?", - { - "Deník udržuje naději", - "Ne", - "Pouze deprese", - "Zakázáno", - }, - 0, - "Lidská síla.", - }, - { - "Katalog žánr?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Achterhuis?", - { - "Zadní dům/úkryt", - "Město", - "Loď", - "Hora", - }, - 0, - "Prostor úkrytu.", - }, - { - "Edith?", - { - "Matka Anny", - "Sestra", - "Gestapo", - "Kitty", - }, - 0, - "Rodina.", - }, - { - "Poselství?", - { - "Oběť války, hlas obyčejného dítěte", - "Válka dobrá", - "Deník zbytečný", - "Ne", - }, - 0, - "Paměť.", - }, - { - "Upravené vydání?", - { - "Různé verze textu existují", - "Ne", - "Jen fikce", - "Bez Anne", - }, - 0, - "Věda o textu.", - }, - { - "Citace slavná?", - { - "„Lidé jsou v jádru dobří“ (parafráze)", - "Bez myšlenek", - "Jen sport", - "Latina", - }, - 0, - "Známá věta.", - }, - { - "Rok 1947?", - { - "První vydání", - "Narození", - "Konec války deníku", - "1989", - }, - 0, - "Publikace.", - }, - { - "Žánr memoáry?", - { - "Autobiografický deník", - "Román", - "Epos", - "Komik", - }, - 0, - "Ne fikce.", - }, -}; - -static const AssemblyItem book_denik_anny_frankove_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Anne dostane deník a jde do úkrytu", - "Život v tajném bytě s rodinou", - "Konflikty, strach a dospívání", - "Záznamy o naději a realitě", - "Úkryt prozrazen 1944", - "Deportace a smrt Anny, vydání deníku otcem", - }, - 6, - }, -}; - -static const char *book_denik_anny_frankove_plot_meaning[] = { - "Pořadí: deník → úkryt → život v izolaci → psaní → prozrazení → osud a vydání.", -}; - -static const LitQ book_jekyll_hyde_qs[] = { - { - "Autor?", - { - "Stevenson", - "Poe", - "Wilde", - "Swift", - }, - 0, - "R. L. Stevenson.", - }, - { - "Rok?", - { - "1886", - "1950", - "1600", - "2000", - }, - 0, - "Viktoriánská literatura.", - }, - { - "Hyde?", - { - "Zločinná alter ego Jekylla", - "Utterson", - "Lékař", - "Král", - }, - 0, - "Protipól.", - }, - { - "Jekyll?", - { - "Vědec experimentující se sebou", - "Hyde vždy", - "Detektiv", - "Ne", - }, - 0, - "Hrdina/tragičnost.", - }, - { - "Utterson?", - { - "Advokát vyšetřující Hyde", - "Hyde", - "Oběť", - "Sluha", - }, - 0, - "Rámcová postava.", - }, - { - "Lanyon?", - { - "Kolega, zemře šokem", - "Hyde", - "Policie", - "Ne", - }, - 0, - "Svědek pravdy.", - }, - { - "Carew?", - { - "Zavražděn Hyde", - "Utterson", - "Jekyll vždy", - "Ne", - }, - 0, - "Noční vražda.", - }, - { - "Lekce?", - { - "Mění Jekyll na Hyde", - "Léčí mor", - "Ne", - "Jen víno", - }, - 0, - "Klíč experimentu.", - }, - { - "Prostředí?", - { - "Londýn", - "Praha", - "Skotsko venkov", - "Mars", - }, - 0, - "Město.", - }, - { - "Žánr?", - { - "Horor/psychologická novela", - "Pohádka", - "Epos", - "Komik", - }, - 0, - "Gotika.", - }, - { - "Překlad?", - { - "Kořán", - "Nezval", - "Nevrla", - "Gössell", - }, - 0, - "Katalog.", - }, - { - "Proč maturitní?", - { - "Klasika o dvojí identitě", - "Nejkratší", - "Bez témat", - "Jen film", - }, - 0, - "Kanón.", - }, - { - "Moralita?", - { - "Věda bez etiky vede ke zkáze", - "Věda vždy dobrá", - "Ne", - "Hyde hrdina", - }, - 0, - "Poselství.", - }, - { - "Hyde vzhled?", - { - "Odpudivý, zvířecký", - "Krásný", - "Ne", - "Stejný jako Jekyll", - }, - 0, - "Symbol zla.", - }, - { - "Jekyll končí?", - { - "Sebevražda jako Hyde v laboratoři", - "Svatba", - "Král", - "Utterson", - }, - 0, - "Tragédie.", - }, - { - "Utterson čte?", - { - "Dopisy Lanyon a Jekyll", - "Deník Anne", - "Bible", - "Nic", - }, - 0, - "Vysvětlení.", - }, - { - "Poole?", - { - "Sluha znepokojený laboratoří", - "Hyde", - "Policista", - "Ne", - }, - 0, - "Domácí.", - }, - { - "Téma dvojí identity?", - { - "Centrální", - "Ne", - "Pouze sport", - "Pouze láska", - }, - 0, - "Jádro.", - }, - { - "Victoriánská doba?", - { - "Pokrytectví a moralita", - "Ne", - "Antika", - "Budoucnost", - }, - 0, - "Kontext.", - }, - { - "Co NENÍ?", - { - "Hyde", - "Jekyll", - "Hamlet", - "Utterson", - }, - 2, - "Shakespeare.", - }, - { - "Er-forma?", - { - "Utterson a vypravěč", - "Jen ich Anne", - "Bez vypravěče", - "Drama", - }, - 0, - "Próza.", - }, - { - "Novela délka?", - { - "Kratší próza", - "Epos", - "1000 stran", - "Báseň", - }, - 0, - "Novela.", - }, - { - "Gotický prvek?", - { - "Mlha, násilí, tajemno", - "Ne", - "Pouze komedie", - "Opera", - }, - 0, - "Atmosféra.", - }, - { - "Hyde bez Jekyll?", - { - "Ne, jsou spojeni", - "Ano navždy", - "Neexistuje", - "Utterson", - }, - 0, - "Identita.", - }, - { - "Experiment motiv?", - { - "Odpoutat zlo od dobrého já", - "Bohatství", - "Sport", - "Ne", - }, - 0, - "Vědecká pýcha.", - }, - { - "Poselství?", - { - "Člověk nese zlo v sobě", - "Zlo neexistuje", - "Hyde je vzor", - "Věda bez hranic je vždy dobrá", - }, - 0, - "Etické varování.", - }, - { - "Katalog?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Stevenson národnost?", - { - "Skotský autor", - "Český", - "Francouz", - "Němec", - }, - 0, - "Skotsko.", - }, - { - "Carew vražda?", - { - "Hyde klackem", - "Utterson", - "Nehoda", - "Ne", - }, - 0, - "Brutální.", - }, - { - "Jekyll dopis?", - { - "Vysvětluje pravdu Uttersonovi", - "Ne", - "Hyde píše", - "Gestapo", - }, - 0, - "Závěrečné odhalení.", - }, - { - "Adaptace?", - { - "Mnoho filmů", - "Ne", - "Zakázáno", - "Jen opera", - }, - 0, - "Kultovní.", - }, - { - "Kořán?", - { - "Překladatel", - "Hyde", - "Autor", - "Utterson", - }, - 0, - "CZ překlad.", - }, -}; - -static const AssemblyItem book_jekyll_hyde_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Utterson zjišťuje podivného Hyde", - "Hyde zavraždí Carewa", - "Utterson pátrá u Jekyll", - "Lanyon šok a smrt", - "Poole volá Uttersona – chaos v domě", - "Jekyllův dopis a smrt – odhalení identity", - }, - 6, - }, -}; - -static const char *book_jekyll_hyde_plot_meaning[] = { - "Pořadí: Hyde na scéně → vražda → pátrání → Lanyon → laboratoř → dopis a konec.", -}; - -static const LitQ book_edison_qs[] = { - { - "Autor Edison?", - { - "Nezval", - "Seifert", - "Hrubín", - "Vrchlický", - }, - 0, - "Vítězslav Nezval.", - }, - { - "Žánr?", - { - "Poema / poezie", - "Román", - "Drama", - "Esej", - }, - 0, - "Poezie v katalogu.", - }, - { - "Rok?", - { - "1927", - "1948", - "1890", - "2000", - }, - 0, - "Meziválečí.", - }, - { - "O kom báseň?", - { - "T. A. Edison", - "Einstein", - "Beckett", - "Hugo", - }, - 0, - "Vynálezce.", - }, - { - "Směr?", - { - "Poetismus", - "Realismus 19 st", - "Romantismus", - "Socialistický", - }, - 0, - "Devětsil.", - }, - { - "Devětsil?", - { - "Umělecká skupina", - "Edison firma", - "Město", - "Postava", - }, - 0, - "Kontext.", - }, - { - "Téma světla?", - { - "Žárovka, symbol poznání", - "Ne", - "Pouze tma", - "Sport", - }, - 0, - "Motiv.", - }, - { - "Forma?", - { - "Volná skladba obrazů", - "Sonety striktně", - "Prozaický román", - "Drama", - }, - 0, - "Moderní poezie.", - }, - { - "Edison realita?", - { - "Historický vynálezce", - "Fiktivní", - "Nezval", - "Král", - }, - 0, - "USA vynálezce.", - }, - { - "Proč maturitní?", - { - "Česká avantgarda", - "Nejdelší", - "Bez stylu", - "Jen próza", - }, - 0, - "Nezval kanón.", - }, - { - "Poetismus charakter?", - { - "Hra, obrazy, město", - "Epická vážnost", - "Bez obrazů", - "Pouze politika", - }, - 0, - "Směr.", - }, - { - "Jazyk?", - { - "Expresivní, obrazný", - "Archaičtina", - "Latina", - "Bez metafor", - }, - 0, - "Nezval.", - }, - { - "Technika v básně?", - { - "Obdiv a poetizace", - "Ne", - "Pouze odsouzení", - "Nezmíněna", - }, - 0, - "Téma.", - }, - { - "Nezval jiná díla?", - { - "Abeceda, Valerie, atd.", - "Hamlet", - "1984", - "Dekameron", - }, - 0, - "Bohatá tvorba.", - }, - { - "Ich vs er?", - { - "Lyrický subjekt obdivuje", - "Epický román", - "Drama", - "Deník", - }, - 0, - "Lyrika.", - }, - { - "Groteska?", - { - "Poetismus ji používá", - "Ne", - "Pouze real", - "Horor", - }, - 0, - "Styl.", - }, - { - "Co NENÍ?", - { - "Poezie", - "Edison téma", - "Nezval", - "Realistický venkovský román", - }, - 3, - "Je poema.", - }, - { - "Motiv vynálezu?", - { - "Tvůrčí síla člověka", - "Ne", - "Zlo", - "Nuda", - }, - 0, - "Obdiv.", - }, - { - "Katalog žánr?", - { - "Poezie", - "Próza", - "Drama", - "Opera", - }, - 0, - "Poezie.", - }, - { - "Obrazy?", - { - "Kinematografické skoky", - "Ne", - "Jen rým", - "Proza", - }, - 0, - "Poetismus.", - }, - { - "Edison žárovka?", - { - "Symbol světla", - "Ne", - "Postava", - "Město", - }, - 0, - "Známý vynález.", - }, - { - "Meziválečí?", - { - "Kontext vzniku", - "Středověk", - "Normalizace", - "Antika", - }, - 0, - "1927.", - }, - { - "Surrealismus vliv?", - { - "Jemně v poetismu", - "Ne", - "Jen realism", - "Zakázáno", - }, - 0, - "Avantgarda.", - }, - { - "Čtení maturita?", - { - "Autor, směr, téma Edison", - "Jen rok narození Edison", - "Jen anglicky", - "Nic", - }, - 0, - "Základ.", - }, - { - "Laboratoř?", - { - "Místo tvoření v obrazu", - "Ne", - "Praha", - "Nebe", - }, - 0, - "Metafora.", - }, - { - "Poselství?", - { - "Modernita a tvůrčí energie", - "Technika zlá vždy", - "Bez smyslu", - "Antitechnika", - }, - 0, - "Obdiv k tvorbě.", - }, - { - "Délka?", - { - "Delší skladba", - "Epos 12 knih", - "Jedna slova", - "Román", - }, - 0, - "Poema.", - }, - { - "Překlad?", - { - "Originál česky Nezval", - "Anglicky autor", - "Latina", - "Ne", - }, - 0, - "Česká báseň.", - }, - { - "Seifert vs Nezval?", - { - "Obě česká poezie, jiní", - "Totéž", - "Seifert Edison", - "Nezval Švejk", - }, - 0, - "Různí.", - }, - { - "Rým?", - { - "Volná skladba – rým volný", - "Pouze blankvers", - "Bez jazyka", - "Proza", - }, - 0, - "Moderní forma.", - }, - { - "Edison firma?", - { - "Může být zmíněna obrazně", - "Hlavní děj román", - "Ne", - "Hamlet", - }, - 0, - "Kontext vynálezce.", - }, -}; - -static const AssemblyItem book_edison_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Nezval představí Edisona jako mýtus vynálezce", - "Obrazy laboratoře a světla", - "Poetistické obrazy techniky", - "Hra jazykem a metaforami", - "Oslava tvůrčí energie", - "Finální skladba obrazů modernity", - }, - 6, - }, -}; - -static const char *book_edison_plot_meaning[] = { - "Pořadí: mýtus Edison → světlo/laboratoř → obrazy → jazyk → tvůrčí síla → celek poemy.", -}; - -static const LitQ book_farma_zvirat_qs[] = { - { - "Autor?", - { - "Orwell", - "Bradbury", - "Havel", - "Swift", - }, - 0, - "George Orwell.", - }, - { - "Rok?", - { - "1945", - "1984", - "1953", - "1862", - }, - 0, - "Po válce.", - }, - { - "Alegorie?", - { - "Sovětská revoluce a Stalin", - "Středověk", - "USA", - "Ne", - }, - 0, - "Zvířata = lidé.", - }, - { - "Old Major?", - { - "Vize revoluce", - "Diktátor", - "Jones", - "Kůň", - }, - 0, - "Marx/Lenin obraz.", - }, - { - "Jones?", - { - "Původní pán farmy", - "Prase", - "Kůň", - "Ne", - }, - 0, - "Czar/kapitalista.", - }, - { - "Napoleon vs Snowball?", - { - "Rivalové mezi prasaty", - "Bratři v klidu", - "Ne", - "Lidé", - }, - 0, - "Stalin/Trockij obraz.", - }, - { - "Squealer?", - { - "Propaganda", - "Kůň", - "Jones", - "Ne", - }, - 0, - "Překrucuje pravdu.", - }, - { - "Boxer?", - { - "Obětavý kůň, prodán jatky", - "Prase", - "Pes", - "Ne", - }, - 0, - "Proletariát.", - }, - { - "Pravidla?", - { - "Postupně měněna prasaty", - "Ne", - "Stálá", - "Jen jedno", - }, - 0, - "Manipulace.", - }, - { - "Benjamin?", - { - "Cynický osel", - "Optimista", - "Diktátor", - "Ne", - }, - 0, - "Skeptik.", - }, - { - "Konec?", - { - "Prasata jako lidé u stolu", - "Raj", - "Jones vrácen", - "Ne", - }, - 0, - "Totalita.", - }, - { - "Žánr?", - { - "Alegorická antiutopie", - "Pohádka bez významu", - "Epos", - "Lyrika", - }, - 0, - "Satira.", - }, - { - "Překlad?", - { - "Gössell", - "Nezval", - "Kořán", - "Nevrla", - }, - 0, - "Katalog.", - }, - { - "1984 vs Farma?", - { - "Orwell obě, jiné téma", - "Bradbury", - "Stejný děj", - "Ne", - }, - 0, - "Dva romány.", - }, - { - "Animalismus?", - { - "Ideologie revoluce", - "Náboženství", - "Ne", - "Sport", - }, - 0, - "Ideologie.", - }, - { - "Větrný mlýn?", - { - "Snowballův plán, Napoleon zničí", - "Ne", - "Jones", - "Nebe", - }, - 0, - "Industrializace.", - }, - { - "Psí garda?", - { - "Napoleonova stráž", - "Ne", - "Boxer", - "Ne", - }, - 0, - "Represe.", - }, - { - "Milk and apples?", - { - "Prasata si přisvojí", - "Ne", - "Všichni", - "Zakázáno", - }, - 0, - "Privilegia elity.", - }, - { - "Proč maturitní?", - { - "Klasika alegorie", - "Nejkratší", - "Bez smyslu", - "Jen film", - }, - 0, - "Kanón.", - }, - { - "Co NENÍ?", - { - "Napoleon", - "Boxer", - "Hamlet", - "Squealer", - }, - 2, - "Shakespeare.", - }, - { - "Er-forma?", - { - "Ano", - "Ich Anne", - "Drama", - "Ne", - }, - 0, - "Próza.", - }, - { - "Satira?", - { - "Ano politická", - "Ne", - "Pouze pohádka", - "Horor", - }, - 0, - "Orwell.", - }, - { - "Boxer motto?", - { - "Budu tvrději pracovat", - "Ne", - "Válka", - "Spím", - }, - 0, - "Známá věta.", - }, - { - "Jatky?", - { - "Boxer prodán", - "Raj", - "Ne", - "Snowball", - }, - 0, - "Zrada.", - }, - { - "Lidská tvář?", - { - "Závěrečná scéna", - "Ne", - "Jones", - "Ne", - }, - 0, - "Pointa.", - }, - { - "Všichni rovni?", - { - "Slogan zneužitý", - "Ne", - "Vždy platí", - "Ne", - }, - 0, - "Paradox.", - }, - { - "Moses vrabec?", - { - "Příběh Cukrové hory – opium", - "Ne", - "Hrdina", - "Ne", - }, - 0, - "Náboženství.", - }, - { - "Poselství?", - { - "Revolution může zkazit", - "Revolution vždy dobrá", - "Ne", - "Zvířata ne", - }, - 0, - "Varování.", - }, - { - "Katalog?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Farm Manor?", - { - "Původní název", - "Ne", - "Praha", - "Ne", - }, - 0, - "Anglie.", - }, - { - "Orwell jméno?", - { - "Eric Blair", - "Nezval", - "Hugo", - "Ne", - }, - 0, - "Skutečné jméno.", - }, - { - "Battle of Cowshed?", - { - "Obrana farmy", - "Ne", - "Boxer", - "Ne", - }, - 0, - "Válka.", - }, -}; - -static const AssemblyItem book_farma_zvirat_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Old Major vyzve ke vzpouře", - "Jones svržen, Animalismus", - "Snowball a Napoleon soupeří", - "Napoleon se zmocní moci", - "Útlak, propaganda, Boxer jatky", - "Prasata nelze od lidí rozeznat", - }, - 6, - }, -}; - -static const char *book_farma_zvirat_plot_meaning[] = { - "Pořadí: vize → revoluce → rivalita → diktatura → útlak → zrada ideálů.", -}; - -static const LitQ book_gulliverovy_cesty_qs[] = { - { - "Autor?", - { - "Swift", - "Defoe", - "Orwell", - "Hugo", - }, - 0, - "Jonathan Swift.", - }, - { - "Rok?", - { - "1726", - "1984", - "1600", - "1900", - }, - 0, - "18. století.", - }, - { - "Kolik cest?", - { - "Čtyři", - "Jedna", - "Deset", - "Sto", - }, - 0, - "Struktura knihy.", - }, - { - "Lilliput?", - { - "Země malých", - "Obři", - "Koně", - "Nebe", - }, - 0, - "První cesta.", - }, - { - "Brobdingnag?", - { - "Země obřů", - "Malí", - "Luna", - "Praha", - }, - 0, - "Druhá cesta.", - }, - { - "Laputa?", - { - "Létající ostrov vědců", - "Ne", - "Jatky", - "Ne", - }, - 0, - "Třetí cesta.", - }, - { - "Houyhnhnm?", - { - "Rozumní koně", - "Yahoové", - "Lilliputi", - "Ne", - }, - 0, - "Čtvrtá cesta.", - }, - { - "Yahoo?", - { - "Bestiální lidé", - "Koně", - "Králové", - "Ne", - }, - 0, - "Satira lidstva.", - }, - { - "Satira?", - { - "Ano hlavní", - "Ne", - "Pouze pohádka", - "Horor", - }, - 0, - "Swift.", - }, - { - "Překlad?", - { - "Skoumal", - "Nezval", - "Kořán", - "Nevrla", - }, - 0, - "Katalog.", - }, - { - "Ich-forma?", - { - "Gulliver vypravěč", - "Er", - "Bez já", - "Drama", - }, - 0, - "Cestopis.", - }, - { - "Vejce válka?", - { - "Lilliput satira", - "Ne", - "Brobdingnag", - "Ne", - }, - 0, - "Politické spory.", - }, - { - "Gulliver konec?", - { - "Odcizen od lidí po cestě 4", - "Král", - "Ne", - "Raj", - }, - 0, - "Tragi-komický.", - }, - { - "Proč maturitní?", - { - "Klasika satiry", - "Nejkratší", - "Bez smyslu", - "Jen film", - }, - 0, - "Kanón.", - }, - { - "Osvícenství?", - { - "Kontext kritiky", - "Středověk", - "Ne", - "Budoucnost", - }, - 0, - "18. st.", - }, - { - "Co NENÍ?", - { - "Gulliver", - "Lilliput", - "Hamlet", - "Yahoo", - }, - 2, - "Shakespeare.", - }, - { - "Brobdingnag král?", - { - "Kritizuje Evropu", - "Ne", - "Malý", - "Ne", - }, - 0, - "Perspektiva.", - }, - { - "Relativita?", - { - "Velikost mění pohled", - "Ne", - "Ne", - "Ne", - }, - 0, - "Motiv.", - }, - { - "Swift Ir?", - { - "Irský satirik", - "Čech", - "Němec", - "Ne", - }, - 0, - "Anglicky psal.", - }, - { - "Cestopis forma?", - { - "Fiktivní cestopis", - "Epos", - "Drama", - "Lyrika", - }, - 0, - "Žánr.", - }, - { - "Laputa věda?", - { - "Odtržená absurdní", - "Ne", - "Užitečná", - "Ne", - }, - 0, - "Satira vědy.", - }, - { - "Houyhnhnm společnost?", - { - "Rozumnější než lidé", - "Ne", - "Yahoo", - "Ne", - }, - 0, - "Inverze.", - }, - { - "Gulliver rodina?", - { - "Po návratu cizí", - "Ne", - "Ne", - "Ne", - }, - 0, - "Závěr.", - }, - { - "Katalog?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Politická satira?", - { - "Ano", - "Ne", - "Pouze láska", - "Sport", - }, - 0, - "Swift.", - }, - { - "První cesta délka?", - { - "Jedna část knihy", - "Celá kniha", - "Ne", - "Ne", - }, - 0, - "Struktura.", - }, - { - "Velikost Gulliver v Lilliput?", - { - "Obří", - "Malý", - "Stejný", - "Ne", - }, - 0, - "Relativita.", - }, - { - "Velikost v Brobdingnag?", - { - "Malý", - "Obří", - "Ne", - "Ne", - }, - 0, - "Opak.", - }, - { - "Poselství?", - { - "Kritika lidské pýchy a společnosti", - "Lidé dokonalí", - "Ne", - "Válka dobrá", - }, - 0, - "Satira.", - }, - { - "Adaptace?", - { - "Filmy, zkrácené verze", - "Ne", - "Zakázáno", - "Ne", - }, - 0, - "Kultovní.", - }, - { - "Skoumal?", - { - "Překladatel", - "Gulliver", - "Swift", - "Ne", - }, - 0, - "CZ.", - }, - { - "Defoe Robinson?", - { - "Jiný autor cest", - "Swift Robinson", - "Totéž", - "Ne", - }, - 0, - "Rozdíl.", - }, -}; - -static const AssemblyItem book_gulliverovy_cesty_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Gulliver ztroskotá u Lilliputu", - "Cesta mezi obry Brobdingnagu", - "Létající ostrov Laputa", - "Země Houyhnhnmů a Yahoů", - "Gulliver zidealizuje koně", - "Návrut a odcizení od lidí", - }, - 6, - }, -}; - -static const char *book_gulliverovy_cesty_plot_meaning[] = { - "Pořadí: Lilliput → Brobdingnag → Laputa → Houyhnhnm → idealizace → návrat.", -}; - -static const LitQ book_hamlet_qs[] = { - { - "Autor?", - { - "Shakespeare", - "Molière", - "Beckett", - "Goethe", - }, - 0, - "William Shakespeare.", - }, - { - "Žánr?", - { - "Tragédie", - "Komedie", - "Epos", - "Báseň", - }, - 0, - "Drama.", - }, - { - "Kde děj?", - { - "Elsinore, Dánsko", - "Praha", - "Řím", - "Londýn", - }, - 0, - "Hrad.", - }, - { - "Hamlet?", - { - "Princ pomstychtivý", - "Král", - "Klaun", - "Ne", - }, - 0, - "Hrdina.", - }, - { - "Claudius?", - { - "Vrah otce, nový král", - "Hamlet", - "Horatio", - "Ne", - }, - 0, - "Antagonista.", - }, - { - "Duch?", - { - "Volá k pomstě", - "Ne", - "Ophelia", - "Ne", - }, - 0, - "Začátek akce.", - }, - { - "Ophelia?", - { - "Zblázní se, utopí", - "Královna", - "Vrah", - "Ne", - }, - 0, - "Tragédie.", - }, - { - "Polonius?", - { - "Rádce, zabit Hamletem", - "Král", - "Ne", - "Ne", - }, - 0, - "Intriky.", - }, - { - "Horatio?", - { - "Věrný přítel", - "Vrah", - "Ne", - "Ne", - }, - 0, - "Svědek.", - }, - { - "Být či nebýt?", - { - "Monolog o existenci", - "Ne", - "Konec", - "Ne", - }, - 0, - "Slavný monolog.", - }, - { - "Předstírané šílenství?", - { - "Hamletova taktika", - "Ne", - "Ophelia", - "Ne", - }, - 0, - "Strategie.", - }, - { - "Laertes?", - { - "Bratr Ophelie, duel", - "Král", - "Ne", - "Ne", - }, - 0, - "Souboj.", - }, - { - "Gertrude?", - { - "Matka, provdá se za Claudius", - "Ne", - "Ne", - "Ne", - }, - 0, - "Rodina.", - }, - { - "Rok?", - { - "Kolem 1601", - "1989", - "500", - "2000", - }, - 0, - "Renesance.", - }, - { - "Překlad?", - { - "Nevrla", - "Hilský", - "Nezval", - "Kořán", - }, - 0, - "Katalog Nevrla.", - }, - { - "Konec?", - { - "Hamlet, Claudius, Gertrude mrtví", - "Svatba", - "Raj", - "Ne", - }, - 0, - "Krvavé finále.", - }, - { - "Představení hry?", - { - "Past na Claudia", - "Ne", - "Ne", - "Ne", - }, - 0, - "Odhalení viny.", - }, - { - "Yorick?", - { - "Lebka klauna – memento mori", - "Král", - "Ne", - "Ne", - }, - 0, - "Symbol.", - }, - { - "Proč maturitní?", - { - "Největší tragédie", - "Nejkratší", - "Bez smyslu", - "Jen film", - }, - 0, - "Kanón.", - }, - { - "Co NENÍ?", - { - "Hamlet", - "Claudius", - "Romeo hlavní zde", - "Ophelia", - }, - 2, - "Romeo jiná hra.", - }, - { - "Blankvers?", - { - "Ne rýmovaný verš", - "Proza", - "Ne", - "Ne", - }, - 0, - "Forma.", - }, - { - "Rosenkranz a Guildenstern?", - { - "Vyslanci, zahynou", - "Ne", - "Ne", - "Ne", - }, - 0, - "Intriky.", - }, - { - "Norwegian Fortinbras?", - { - "Nástup moci na konci", - "Ne", - "Ne", - "Ne", - }, - 0, - "Politika.", - }, - { - "Téma pomsty?", - { - "Centrální", - "Ne", - "Sport", - "Ne", - }, - 0, - "Osud.", - }, - { - "Filozofie?", - { - "Hamlet přemýšlí", - "Ne", - "Ne", - "Ne", - }, - 0, - "Renesance.", - }, - { - "Katalog?", - { - "Drama", - "Próza", - "Poezie", - "Opera", - }, - 0, - "Drama.", - }, - { - "Shakespeare jazyk?", - { - "Anglicky", - "Česky originál", - "Latina", - "Ne", - }, - 0, - "Originál.", - }, - { - "Divadlo Globe?", - { - "Kontext", - "Ne", - "Ne", - "Ne", - }, - 0, - "Elisabethan.", - }, - { - "Poselství?", - { - "Mstivost a nejistota vedou ke zkáze", - "Pomsta vždy dobrá", - "Ne", - "Ne", - }, - 0, - "Tragédie.", - }, - { - "Hilský?", - { - "Jiný překlad Shakespeare", - "Hamlet autor", - "Ne", - "Ne", - }, - 0, - "Romeo Hilský.", - }, - { - "Ofélie květiny?", - { - "Symbol šílenství", - "Ne", - "Ne", - "Ne", - }, - 0, - "Scéna.", - }, - { - "Jed?", - { - "Claudius otráví meč i víno", - "Ne", - "Ne", - "Ne", - }, - 0, - "Finále.", - }, -}; - -static const AssemblyItem book_hamlet_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Duch vyzve Hamleta k pomstě", - "Hamlet předstírá šílenství a váhá", - "Past divadelní hrou", - "Hamlet zabije Polonia", - "Ophelia umírá, Hamlet se vrací", - "Duel a smrt hlavních postav", - }, - 6, - }, -}; - -static const char *book_hamlet_plot_meaning[] = { - "Pořadí: duch → šílenství → hra v hře → Polonius → Ophelia → finální masakr.", -}; - -static const LitQ book_havran_qs[] = { - { - "Autor?", - { - "Poe", - "Whitman", - "Orwell", - "Nezval", - }, - 0, - "Edgar Allan Poe.", - }, - { - "Rok?", - { - "1845", - "1600", - "1920", - "2000", - }, - 0, - "19. století.", - }, - { - "Žánr?", - { - "Balada / báseň", - "Román", - "Drama", - "Esej", - }, - 0, - "Poezie.", - }, - { - "Refrén?", - { - "Nevermore (Nikdy více)", - "To be", - "451", - "Godot", - }, - 0, - "Havran opakuje.", - }, - { - "Kdo vypráví?", - { - "Truchlící muž ich", - "Havran ich", - "Lenore", - "Vševěd", - }, - 0, - "Subjekt.", - }, - { - "Lenore?", - { - "Mrtvá milovaná", - "Havran", - "Královna", - "Ne", - }, - 0, - "Motiv.", - }, - { - "Kdy děj?", - { - "Půlnoc, prosinec", - "Poledne", - "Léto", - "Ne", - }, - 0, - "Atmosféra.", - }, - { - "Havran kde?", - { - "Na bustě Pallas", - "V lese", - "V moři", - "Ne", - }, - 0, - "Obraz.", - }, - { - "Pallas?", - { - "Busta bohyně moudrosti", - "Město", - "Lenore", - "Ne", - }, - 0, - "Symbol.", - }, - { - "Tón?", - { - "Temný, melancholický", - "Veselý", - "Komický", - "Ne", - }, - 0, - "Gotika.", - }, - { - "Struktura?", - { - "Strofy s refrénem", - "Proza", - "Drama", - "Ne", - }, - 0, - "Forma.", - }, - { - "Vypravěč stav?", - { - "Klesá do beznaděje", - "Radost", - "Ne", - "Ne", - }, - 0, - "Psychika.", - }, - { - "Proč maturitní?", - { - "Klasika poezie", - "Nejdelší román", - "Bez smyslu", - "Jen film", - }, - 0, - "Kanón.", - }, - { - "Gotika?", - { - "Ano", - "Ne", - "Realismus", - "Ne", - }, - 0, - "Směr.", - }, - { - "Co NENÍ?", - { - "Havran", - "Lenore", - "Hamlet celá hra", - "Nevermore", - }, - 2, - "Hamlet drama.", - }, - { - "Poe národnost?", - { - "Americký", - "Český", - "Irský", - "Ne", - }, - 0, - "USA.", - }, - { - "Katalog?", - { - "Poezie", - "Próza", - "Drama", - "Opera", - }, - 0, - "Poezie.", - }, - { - "Havran symbol?", - { - "Vzpomínka, zlo, bezmoc", - "Ne", - "Láska", - "Ne", - }, - 0, - "Interpretace.", - }, - { - "Otázky vypravěče?", - { - "Na havrana o Lenore a smyslu", - "Ne", - "Sport", - "Ne", - }, - 0, - "Dialog.", - }, - { - "Konec?", - { - "Vypravěč v beznaději", - "Svatba", - "Raj", - "Ne", - }, - 0, - "Tma.", - }, - { - "Rým?", - { - "Použit", - "Ne", - "Proza", - "Ne", - }, - 0, - "Balada.", - }, - { - "December?", - { - "Zmíněno – zima", - "Ne", - "Ne", - "Ne", - }, - 0, - "Atmosféra.", - }, - { - "Tapeta?", - { - "Gotický pokoj", - "Ne", - "Ne", - "Ne", - }, - 0, - "Prostředí.", - }, - { - "Anděl Lenore?", - { - "Vypravěč se ptá", - "Ne", - "Ne", - "Ne", - }, - 0, - "Strofa.", - }, - { - "Poselství?", - { - "Ztráta a beznaděj lze vyjádřit symbolem", - "Radost", - "Ne", - "Ne", - }, - 0, - "Téma.", - }, - { - "Poe jiná díla?", - { - "Jiná básně, povídky", - "Hamlet", - "1984", - "Ne", - }, - 0, - "Autor.", - }, - { - "Mluví havran víc?", - { - "Jen Nevermore", - "Dlouhé monology", - "Ne", - "Ne", - }, - 0, - "Refrén.", - }, - { - "Ich-forma?", - { - "Ano", - "Er", - "Bez já", - "Ne", - }, - 0, - "Lyrika.", - }, - { - "Balada charakter?", - { - "Příběh + lyrické", - "Epos", - "Ne", - "Ne", - }, - 0, - "Žánr.", - }, - { - "Čtení maturita?", - { - "Autor, refrén, symbolika", - "Jen překlad", - "Ne", - "Ne", - }, - 0, - "Základ.", - }, - { - "Knocking?", - { - "Zpočátku klepání", - "Ne", - "Ne", - "Ne", - }, - 0, - "Začátek.", - }, - { - "Bust?", - { - "Socha Pallas", - "Lenore", - "Ne", - "Ne", - }, - 0, - "Detail.", - }, -}; - -static const AssemblyItem book_havran_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Vypravěč truchlí v půlnočním pokoji", - "Klepání a příchod havrana", - "Havran usedne na bustu Pallas", - "Vypravěč klade otázky o Lenore", - "Havran opakuje Nevermore", - "Beznaděj vypravěče roste do konce", - }, - 6, - }, -}; - -static const char *book_havran_plot_meaning[] = { - "Pořadí: truchlení → klepání → havran → otázky → refrén → beznaděj.", -}; - -static const LitQ book_hladove_hry_qs[] = { - { - "Autorka?", - { - "Collins", - "Rowling", - "Orwell", - "Viewegh", - }, - 0, - "Suzanne Collins.", - }, - { - "Rok?", - { - "2008", - "1984", - "1950", - "1862", - }, - 0, - "První díl.", - }, - { - "Panem?", - { - "Dystopický stát", - "Praha", - "Ne", - "Ne", - }, - 0, - "Prostředí.", - }, - { - "Katniss?", - { - "Hrdinka z Distraktu 12", - "Kapitol", - "Ne", - "Ne", - }, - 0, - "Ich.", - }, - { - "Peeta?", - { - "Chlapec z Pece, péká chleba", - "Kapitol", - "Ne", - "Ne", - }, - 0, - "Partner.", - }, - { - "Hladové hry?", - { - "Boj na smrt na TV", - "Sport", - "Ne", - "Ne", - }, - 0, - "Koncept.", - }, - { - "12 okresů?", - { - "Pod Kapitolem", - "Ne", - "Ne", - "Ne", - }, - 0, - "Struktura.", - }, - { - "Haymitch?", - { - "Mentor, vítěz", - "Ne", - "Ne", - "Ne", - }, - 0, - "Postava.", - }, - { - "Mockingjay pin?", - { - "Symbol od Madge/symbol odporu", - "Ne", - "Ne", - "Ne", - }, - 0, - "Motiv.", - }, - { - "Předstíraná láska?", - { - "Strategie v aréně", - "Ne", - "Ne", - "Ne", - }, - 0, - "Peeta+Katniss.", - }, - { - "Gale?", - { - "Přítel doma", - "Kapitol", - "Ne", - "Ne", - }, - 0, - "Love triangle.", - }, - { - "Effie?", - { - "Escort Kapitolu", - "Ne", - "Ne", - "Ne", - }, - 0, - "Postava.", - }, - { - "Cinna?", - { - "Stylista Katniss", - "Ne", - "Ne", - "Ne", - }, - 0, - "Podpora.", - }, - { - "Překlad?", - { - "Dušek", - "Nezval", - "Kořán", - "Nevrla", - }, - 0, - "Katalog.", - }, - { - "Žánr?", - { - "Dystopický YA román", - "Epos", - "Drama", - "Lyrika", - }, - 0, - "Próza.", - }, - { - "Aréna I. díl?", - { - "Lesní aréna", - "Moře", - "Ne", - "Ne", - }, - 0, - "Boj.", - }, - { - "Rue?", - { - "Tribut z 11, smrt", - "Ne", - "Ne", - "Ne", - }, - 0, - "Emoce.", - }, - { - "Kapitol?", - { - "Bohaté centrum", - "Chudé", - "Ne", - "Ne", - }, - 0, - "Moc.", - }, - { - "Vítězství I. díl?", - { - "Katniss a Peeta oba", - "Jen Gale", - "Ne", - "Ne", - }, - 0, - "Pravidlo změněno.", - }, - { - "Proč maturitní?", - { - "Moderní dystopie", - "Nejstarší", - "Bez témat", - "Ne", - }, - 0, - "Čtení.", - }, - { - "Co NENÍ?", - { - "Katniss", - "Peeta", - "Hamlet", - "Haymitch", - }, - 2, - "Shakespeare.", - }, - { - "Téma média?", - { - "Hry jako show", - "Ne", - "Ne", - "Ne", - }, - 0, - "Kritika.", - }, - { - "Lov?", - { - "Katniss dovednost", - "Ne", - "Ne", - "Ne", - }, - 0, - "Přežití.", - }, - { - "Prim?", - { - "Mladší sestra", - "Ne", - "Ne", - "Ne", - }, - 0, - "Motiv.", - }, - { - "Do volunteer?", - { - "Katniss místo Prim", - "Ne", - "Ne", - "Ne", - }, - 0, - "Začátek.", - }, - { - "Sponzoři?", - { - "Posílají dárky", - "Ne", - "Ne", - "Ne", - }, - 0, - "Pravidla.", - }, - { - "Katalog titul?", - { - "Hladové hry – I. Aréna smrti", - "1984", - "Ne", - "Ne", - }, - 0, - "Katalog.", - }, - { - "Poselství?", - { - "Moc a zábava z utrpení jsou nebezpečné", - "Hry dobré", - "Ne", - "Ne", - }, - 0, - "Dystopie.", - }, - { - "Snow president?", - { - "Vůdce Kapitolu", - "Ne", - "Ne", - "Ne", - }, - 0, - "Antagonista.", - }, - { - "Berries?", - { - "Finále – hrozba sebevraždy", - "Ne", - "Ne", - "Ne", - }, - 0, - "Vítězství.", - }, - { - "Ich-forma?", - { - "Katniss", - "Er", - "Ne", - "Ne", - }, - 0, - "Vypravěč.", - }, - { - "Trilogie?", - { - "3 knihy celkem", - "1", - "10", - "Ne", - }, - 0, - "Série.", - }, -}; - -static const AssemblyItem book_hladove_hry_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Katniss se přihlásí místo Prim", - "Příprava v Kapitolu a trénink", - "Vstup do arény Hladových her", - "Boj o přežití a smrt Rue", - "Strategie s Peetou a sponzory", - "Vítězství obou a provokace Kapitolu", - }, - 6, - }, -}; - -static const char *book_hladove_hry_plot_meaning[] = { - "Pořadí: dobrovolnice → Kapitol → aréna → přežití → Peeta → vítězství.", -}; - -static const LitQ book_hlava_xxii_qs[] = { - { - "Autor?", - { - "Heller", - "Remarque", - "Hemingway", - "Orwell", - }, - 0, - "Joseph Heller.", - }, - { - "Rok?", - { - "1961", - "1945", - "1984", - "2000", - }, - 0, - "Poválečný román.", - }, - { - "Yossarian?", - { - "Bombardér toužící utéct", - "Generál", - "Ne", - "Ne", - }, - 0, - "Hrdina.", - }, - { - "Catch-22?", - { - "Pravidlová past – nemůžeš být prohlážen bláznem", - "Letadlo", - "Ne", - "Ne", - }, - 0, - "Titul.", - }, - { - "Válka?", - { - "WWII", - "Vietnam", - "Ne", - "Ne", - }, - 0, - "Kontext.", - }, - { - "Pianosa?", - { - "Italská základna fikce", - "Praha", - "Ne", - "Ne", - }, - 0, - "Místo.", - }, - { - "M&M?", - { - "Milieu prodává na černém trhu", - "Ne", - "Ne", - "Ne", - }, - 0, - "Postava.", - }, - { - "Cathcart?", - { - "Zvyšuje nálety", - "Ne", - "Ne", - "Ne", - }, - 0, - "Důstojník.", - }, - { - "Snowden?", - { - "Smrt odhalí absurditu", - "Ne", - "Ne", - "Ne", - }, - 0, - "Scéna.", - }, - { - "Doc Daneeka?", - { - "„Mrtvý“ na papíře", - "Ne", - "Ne", - "Ne", - }, - 0, - "Byrokracie.", - }, - { - "Žánr?", - { - "Anti válečný absurdní román", - "Pohádka", - "Epos", - "Lyrika", - }, - 0, - "Próza.", - }, - { - "Překlad?", - { - "Jindra", - "Nezval", - "Dušek", - "Nevrla", - }, - 0, - "Katalog.", - }, - { - "Nelineární?", - { - "Ano čas skáče", - "Ne", - "Lineární", - "Ne", - }, - 0, - "Forma.", - }, - { - "Humor?", - { - "Černý ironický", - "Ne", - "Slapstick", - "Ne", - }, - 0, - "Styl.", - }, - { - "Proč maturitní?", - { - "Klasika 20. stol.", - "Nejkratší", - "Bez smyslu", - "Ne", - }, - 0, - "Kanón.", - }, - { - "Co NENÍ?", - { - "Yossarian", - "Catch-22", - "Hamlet", - "M&M", - }, - 2, - "Shakespeare.", - }, - { - "Remarque vs Heller?", - { - "Obě válka, jiný styl", - "Totéž", - "Remarque Catch", - "Ne", - }, - 0, - "Různí.", - }, - { - "Nately?", - { - "Zamilovaný, tragicky", - "Ne", - "Ne", - "Ne", - }, - 0, - "Postava.", - }, - { - "Nálety?", - { - "Opakující se nebezpečné", - "Ne", - "Ne", - "Ne", - }, - 0, - "Motiv.", - }, - { - "Desertace?", - { - "Yossarian chce", - "Ne", - "Ne", - "Ne", - }, - 0, - "Cíl.", - }, - { - "Er-forma?", - { - "Ano", - "Ich Katniss", - "Ne", - "Ne", - }, - 0, - "Próza.", - }, - { - "Absurdita?", - { - "Byrokracie války", - "Ne", - "Ne", - "Ne", - }, - 0, - "Téma.", - }, - { - "Katalog?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "22?", - { - "Číslo v pasti", - "Ne", - "Ne", - "Ne", - }, - 0, - "Titul.", - }, - { - "Snowden v letadle?", - { - "Krvavá smrt", - "Ne", - "Ne", - "Ne", - }, - 0, - "Trauma.", - }, - { - "Otrava?", - { - "Yossarian v nemocnici", - "Ne", - "Ne", - "Ne", - }, - 0, - "Epizody.", - }, - { - "Poselství?", - { - "Válka a byrokracie jsou absurdní", - "Válka slavná", - "Ne", - "Ne", - }, - 0, - "Anti válka.", - }, - { - "Série?", - { - "Jedna kniha (+ sequel)", - "10", - "Ne", - "Ne", - }, - 0, - "Hlava XXII.", - }, - { - "Ironie?", - { - "Hlavní prostředek", - "Ne", - "Ne", - "Ne", - }, - 0, - "Styl.", - }, - { - "Jindra?", - { - "Překladatel", - "Yossarian", - "Ne", - "Ne", - }, - 0, - "CZ.", - }, - { - "Konec?", - { - "Yossarian se rozhodne utéct", - "Válka slaví", - "Ne", - "Ne", - }, - 0, - "Únik.", - }, - { - "Letectvo?", - { - "Bombardéry", - "Ne", - "Ne", - "Ne", - }, - 0, - "Armáda.", - }, -}; - -static const AssemblyItem book_hlava_xxii_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Yossarian na základně Pianosa", - "Opakované nebezpečné nálety", - "Catch-22 blokuje prohlášení blázna", - "Smrt přátel včetně Snowdena", - "Byrokratické absurdity a M&M", - "Rozhodnutí utéct z armády", - }, - 6, - }, -}; - -static const char *book_hlava_xxii_plot_meaning[] = { - "Pořadí: základna → nálety → Catch-22 → smrti → absurdita → útěk.", -}; - -static const LitQ book_chram_matky_bozi_qs[] = { - { - "Autor?", - { - "Hugo", - "Dickens", - "Zola", - "Flaubert", - }, - 0, - "Victor Hugo.", - }, - { - "Rok?", - { - "1831", - "1862", - "1600", - "2000", - }, - 0, - "Romantismus.", - }, - { - "Katedrála?", - { - "Notre-Dame Paříž", - "Praha", - "Ne", - "Ne", - }, - 0, - "Titul.", - }, - { - "Quasimodo?", - { - "Zvoník hrbáč", - "Kněz", - "Král", - "Ne", - }, - 0, - "Hrdina.", - }, - { - "Esmeralda?", - { - "Cikánská tanečnice", - "Kněžka", - "Ne", - "Ne", - }, - 0, - "Oběť.", - }, - { - "Frollo?", - { - "Arciděkan posedlý Esmeraldou", - "Quasimodo", - "Ne", - "Ne", - }, - 0, - "Antagonista.", - }, - { - "Phoebus?", - { - "Kapitán, svůdník", - "Zvoník", - "Ne", - "Ne", - }, - 0, - "Postava.", - }, - { - "Gringoire?", - { - "Básník, manžel Esmeraldy formálně", - "Ne", - "Ne", - "Ne", - }, - 0, - "Postava.", - }, - { - "Quasimodo chrání?", - { - "Esmeraldu v katedrále", - "Ne", - "Ne", - "Ne", - }, - 0, - "Útočiště.", - }, - { - "Konec Esmeralda?", - { - "Poprava", - "Královna", - "Ne", - "Ne", - }, - 0, - "Tragédie.", - }, - { - "Konec Quasimoda?", - { - "Umírá u Esmeraldy", - "Král", - "Ne", - "Ne", - }, - 0, - "Láska.", - }, - { - "Konec Frolla?", - { - "Smrt", - "Svatba", - "Ne", - "Ne", - }, - 0, - "Pád.", - }, - { - "Překlad?", - { - "Tomášková", - "Pavlousková", - "Nezval", - "Nevrla", - }, - 0, - "Katalog.", - }, - { - "Bídníci Hugo?", - { - "Jiný román 1862", - "Totéž", - "Ne", - "Ne", - }, - 0, - "Různá díla.", - }, - { - "Proč maturitní?", - { - "Klasika romantismu", - "Nejkratší", - "Bez smyslu", - "Ne", - }, - 0, - "Kanón.", - }, - { - "Co NENÍ?", - { - "Quasimodo", - "Esmeralda", - "Hamlet", - "Frollo", - }, - 2, - "Shakespeare.", - }, - { - "Gotika?", - { - "Architektura i atmosféra", - "Ne", - "Ne", - "Ne", - }, - 0, - "Motiv.", - }, - { - "Cikáni?", - { - "Předsudky společnosti", - "Ne", - "Ne", - "Ne", - }, - 0, - "Téma.", - }, - { - "Er-forma?", - { - "Ano", - "Ich", - "Ne", - "Ne", - }, - 0, - "Próza.", - }, - { - "Paříž 15. st?", - { - "Historické pozadí", - "Ne", - "Ne", - "Ne", - }, - 0, - "Setting.", - }, - { - "Zvon?", - { - "Quasimodo zvoní", - "Ne", - "Ne", - "Ne", - }, - 0, - "Symbol.", - }, - { - "Soud Esmeralda?", - { - "Křivé obvinění", - "Ne", - "Ne", - "Ne", - }, - 0, - "Nespravedlnost.", - }, - { - "Phoebus žije?", - { - "Přežije cynicky", - "Ne", - "Ne", - "Ne", - }, - 0, - "Kontrast.", - }, - { - "Katalog?", - { - "Próza", - "Drama", - "Poezie", - "Opera", - }, - 0, - "Próza.", - }, - { - "Romantismus?", - { - "Směr autora", - "Realismus", - "Ne", - "Ne", - }, - 0, - "19. st.", - }, - { - "Architektura?", - { - "Hugo obdiv ke katedrále", - "Ne", - "Ne", - "Ne", - }, - 0, - "Téma.", - }, - { - "Poselství?", - { - "Předsudky ničí, krása duše counts", - "Vzhled vše", - "Ne", - "Ne", - }, - 0, - "Humanita.", - }, - { - "Disney?", - { - "Adaptace existuje", - "Ne", - "Zakázáno", - "Ne", - }, - 0, - "Kultura.", - }, - { - "Jehan?", - { - "Bratr Frolla, piják", - "Ne", - "Ne", - "Ne", - }, - 0, - "Postava.", - }, - { - "Utok na katedrálu?", - { - "Quasimodo brání", - "Ne", - "Ne", - "Ne", - }, - 0, - "Scéna.", - }, - { - "Titul CZ?", - { - "Chrám Matky Boží", - "Bídníci", - "Ne", - "Ne", - }, - 0, - "Notre-Dame.", - }, - { - "Hugo národnost?", - { - "Francouz", - "Čech", - "Ne", - "Ne", - }, - 0, - "Francie.", - }, -}; - -static const AssemblyItem book_chram_matky_bozi_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Gringoire a Esmeralda ve středověké Paříži", - "Frollo se zamiluje do Esmeraldy", - "Quasimodo ji zachrání do chrámu", - "Soud a odsouzení Esmeraldy", - "Poprava a Quasimodo brání marně", - "Smrt hlavních postav u katedrály", - }, - 6, - }, -}; - -static const char *book_chram_matky_bozi_plot_meaning[] = { - "Pořadí: setkání → Frollo → útočiště → soud → poprava → smrt u chrámu.", -}; - -static const LitQ book_jak_jsem_vyhral_valku_qs[] = { - { - "Kdo je autorem románu Jak jsem vyhrál válku?", - { - "Joseph Heller", - "Patrick Ryan", - "Ernest Hemingway", - "Kurt Vonnegut", - }, - 1, - "Román napsal irský spisovatel Patrick Ryan; vyšel v roce 1963.", - }, - { - "Kdo vypráví příběh a jakou hodnost má?", - { - "Seržant Clapper", - "Poručík Ernest Goodbody", - "Generál britské armády", - "Vojín Spool", - }, - 1, - "Vypravěčem je poručík Goodbody v ich-formě; jeho naivita je klíčem k satiře.", - }, - { - "Jaký žánr román reprezentuje?", - { - "Historický epos", - "Satirický válečný román / černá komedie", - "Detektivka", - "Romantický milostný příběh", - }, - 1, - "Dílo paroduje válečné memoáry a používá ironii i černý humor.", - }, - { - "V jakém období se děj odehrává?", - { - "1. světová válka", - "2. světová válka", - "Válka ve Vietnamu", - "Fiktivní budoucnost", - }, - 1, - "Děj sleduje britskou armádu během druhé světové války.", - }, - { - "Proč je Goodbody typickým antihrdinou?", - { - "Je statečný a skromný", - "Je naivní, neschopný a nechápe absurditu kolem sebe", - "Je zrádce", - "Je generál bez chyb", - }, - 1, - "Goodbody věří vlastnímu idealismu, zatímco čtenář vidí jeho směšnost i nekompetenci.", - }, - { - "Jakou roli hraje seržant Clapper?", - { - "Romantický partner", - "Cynický protiklad naivního Goodbodyho", - "Německý zajatec", - "Válečný correspondent", - }, - 1, - "Clapper reprezentuje praktický, skeptický pohled na válku oproti Goodbodyho iluzím.", - }, - { - "Co satira v románu nejčastěji kritizuje?", - { - "Sport a zábavu", - "Heroické mýty, hierarchii a absurditu vojenského systému", - "Venkovský život", - "Školství", - }, - 1, - "Ryan vystavuje posměchu slavnostní válečné rétoriky a neschopnosti velení.", - }, - { - "Jak funguje ironie titulu Jak jsem vyhrál válku?", - { - "Goodbody skutečně porazil Němce sám", - "Titul je vážný hold hrdinovi", - "Vypravěč si myslí, že válku vyhrál, ale čtenář ví, že jde o absurditu", - "Jde o dokumentární reportáž", - }, - 2, - "Goodbody prezentuje chaos jako vítězství; titul je satirický kontrast k realitě.", - }, - { - "Který režisér zfilmoval román a kdy?", - { - "Stanley Kubrick, 1964", - "Mike Nichols, 1967", - "Steven Spielberg, 1998", - "Roman Polanski, 1971", - }, - 1, - "Film z roku 1967 režíroval Mike Nichols; v roli Musgravea účinkoval i John Lennon.", - }, - { - "Co je typické pro vyprávění v ich-formě u Goodbodyho?", - { - "Objektivní chronika bez komentáře", - "Vypravěč sám nechápe, jak směšný je", - "Pohled třetí osoby vševědoucí", - "Střídání deníkových zápisů mnoha hrdinů", - }, - 1, - "Goodbody popisuje události vážně a idealisticky; ironii vytváří odstup mezi ním a čtenářem.", - }, - { - "Jaký tón převládá v románu?", - { - "Patetický heroismus", - "Ironický a černohumorý", - "Lyricismus a nostalgie", - "Horor bez komentáře", - }, - 1, - "Tragické situace jsou často podány s nadhledem a výsměchem.", - }, - { - "S jakým americkým románem se dílo často srovnává?", - { - "Starý muž a moře", - "Chaplinova válka", - "Chytil-22 (Catch-22)", - "Bílá vrána", - }, - 2, - "Obě díla satiricky zpracovávají absurditu moderní války (Ryan 1963, Heller 1961).", - }, - { - "Co Goodbody typicky zdůrazňuje ve svých výkladech?", - { - "Bezútěšnou realitu fronty", - "Řád, čest a smysl vojenské služby", - "Nenávist ke všem nadřízeným", - "Desertérství", - }, - 1, - "Jeho idealismus kontrastuje s chaosem, který popisuje.", - }, - { - "Jak román vztahuje k propagandě?", - { - "Propagandu oslavuje", - "Ukazuje, jak naivní víra v oficiální rétoriku odporuje zkušenosti", - "Nezmiňuje ji", - "Popisuje jen německou propagandu", - }, - 1, - "Goodbody přebírá klíčová slova o čestné válce; satira je demaskuje.", - }, - { - "Kde román nejčastěji situuje děj?", - { - "Jen v Londýně", - "V prostředí britské armády v Evropě a severní Africe", - "Pouze v Pacifiku", - "V budoucní koloni Marsu", - }, - 1, - "Děj sleduje pohyby jednotky v rámci válečných operací mimo Velkou Británii.", - }, - { - "Co je „černý humor“ v kontextu díla?", - { - "Vtipy bez souvislosti s dějem", - "Komický odstup od tragických situací", - "Pouze slovní hříčky", - "Dětská komedie", - }, - 1, - "Smrt a absurdita jsou podány tak, že vyvolávají smích i pohoršení zároveň.", - }, - { - "Proč čtenář nedůvěřuje Goodbodyho hodnocení situací?", - { - "Goodbody lže vědomě", - "Je nekompetentní a slepý k vlastním chybám", - "Příběh nemá vypravěče", - "Jde o pohádku", - }, - 1, - "Nespolehlivý vypravěč je základ satirického efektu.", - }, - { - "Jak v románu působí vojenská hierarchie?", - { - "Jako dokonalý meritokratický systém", - "Jako zdroj absurdit a neschopnosti", - "Vůbec se neobjevuje", - "Jako romantická idealizace", - }, - 1, - "Velení a byrokracie často zhoršují situaci jednotky.", - }, - { - "Kdo z následujících patří k Goodbodyho jednotce?", - { - "Winston Smith", - "Spool", - "Jay Gatsby", - "Heathcliff", - }, - 1, - "Spool je jedním z vojáků v absurdních situacích oddílu.", - }, - { - "Jaké poselství lze z románu vyčíst?", - { - "Válka je slavná a smysluplná", - "Glorifikace války je nebezpečná iluze", - "Vojáci jsou vždy hrdinové", - "Satira je bez myšlenky", - }, - 1, - "Dílo varuje před naivním přijímáním válečných mýtů.", - }, - { - "V jakém jazyce původně román vyšel?", - { - "Česky", - "Anglicky", - "Německy", - "Francouzsky", - }, - 1, - "Patrick Ryan psal anglicky; český překlad nese titul Jak jsem vyhrál válku.", - }, - { - "Co charakterizuje Goodbodyho styl vyprávění?", - { - "Vědecká přesnost", - "Oficiální, sebejistý tón důstojníka", - "Pouze dialogy bez komentáře", - "Básnická próza", - }, - 1, - "Goodbody mluví jako někdo, kdo věří vlastní důležitosti a správnosti.", - }, - { - "Jak filmová adaptace ovlivnila povědomí o knize?", - { - "Knihu zcela potlačila", - "Pomohla dílo prosadit i mimo literární kruhy", - "Změnila žánr na horor", - "Natáčela se před vydáním knihy", - }, - 1, - "Film z konce 60. let s hvězdným obsazením zvýšil popularitu románu.", - }, - { - "Co je typické pro válečné rozkazy v díle?", - { - "Vždy logické a účinné", - "Často nesmyslné nebo kontraproduktivní", - "Nejsou zmíněny", - "Vydává je jen Goodbody", - }, - 1, - "Absurdita rozkazů ilustruje ztrátu smyslu války v praxi.", - }, - { - "Jaký kontrast tvoří jádro komiky románu?", - { - "Bohatí vs. chudí", - "Goodbodyho idealismus vs. chaotická realita", - "Město vs. venkov", - "Muži vs. ženy bez válečného kontextu", - }, - 1, - "Rozdíl mezi tím, co Goodbody tvrdí, a tím, co se děje, je zdrojem satiry.", - }, - { - "Proč se román hodí k maturitní četbě?", - { - "Je jen dětskou knihou", - "Spojuje historický kontext 2. sv. války s žánrem satiry a vyprávění", - "Neobsahuje postavy", - "Je encyklopedie zbraní", - }, - 1, - "Učí číst ironii, nespolehlivého vypravěče a historicko-společenský kontext.", - }, - { - "Jak Ryan pracuje s válečným hrdinstvím?", - { - "Oslavuje je bez výhrad", - "Demaskuje ho jako prázdnou frázi", - "Ignoruje frontu", - "Popisuje jen námořnictvo", - }, - 1, - "Hrdinské selfi Goodbodyho je parodií tradičních válečných autobiografií.", - }, - { - "Co znamená „antimilitarismus“ v interpretaci knihy?", - { - "Oslava armády", - "Kritika války a její glorifikace", - "Neutralita bez názoru", - "Propagace zbraní", - }, - 1, - "Satira podkopává důvody chválit válku jako morální nebo smysluplnou.", - }, - { - "Které téma NENÍ středem románu?", - { - "Absurdita války", - "Naivita vypravěče", - "Viktorianská společenská etiketa na venkově", - "Vojenská hierarchie", - }, - 2, - "Román je válečná satira, ne venkovský společenský román 19. století.", - }, - { - "Jak končí dojem z Goodbodyho „vítězství“?", - { - "Čtenář i vypravěč sdílejí hrdinský pocit", - "Čtenář chápe, že „vítězství“ je iluze vypravěče", - "Goodbody odhalí, že celou dobu lhal", - "Válka se v knize vůbec nekončí popisem", - }, - 1, - "Závěrečný efekt stojí na ironii mezi Goodbodyho sebevědomím a realitou války.", - }, -}; - -static const AssemblyItem book_jak_jsem_vyhral_valku_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Goodbody nastupuje do služby jako naivní poručík", - "Jednotka plní absurdní rozkazy na frontě", - "Clapper a vojáci reagují cynicky na chaos", - "Operace se hroutí kvůli nekompetenci velení", - "Goodbody přesto hodnotí dění jako úspěch", - "Vypravěč tvrdí, že válku „vyhrál“", - }, - 6, - }, -}; - -static const char *book_jak_jsem_vyhral_valku_plot_meaning[] = { - "Správné pořadí: nástup poručíka → absurdní rozkazy → cynická reakce jednotky → neúspěch operací → Goodbodyův klamný optimismus → ironický titul o vítězství.", -}; - -static const LitQ book_jana_eyrova_qs[] = { - { - "Kdo napsal Jana Eyrovou a kdy román poprvé vyšel?", - { - "Emily Brontëová, 1846", - "Charlotte Brontëová, 1847", - "Jane Austenová, 1815", - "Mary Shelley, 1818", - }, - 1, - "Román vydala Charlotte Brontëová v roce 1847 pod pseudonymem Currer Bell.", - }, - { - "Kdo vypráví příběh?", - { - "Edward Rochester", - "Jane Eyreová v ich-formě", - "Vševědoucí vypravěč", - "St. John Rivers", - }, - 1, - "Jane retrospektivně vypráví svůj život od dětství po sňatek.", - }, - { - "Kde Jane strádá v dětství u příbuzných?", - { - "Thornfield", - "Gateshead Hall", - "Lowood", - "Moor House", - }, - 1, - "U paní Reedové v Gateshead je Jane ponižována a vyloučena.", - }, - { - "Jak se jmenuje škola, kam Jane posílají?", - { - "Lowood Institution", - "Hogwarts", - "Thornfield Academy", - "Rivers College", - }, - 0, - "V Lowood zažívá tvrdé podmínky, ale poznává Helen Burns.", - }, - { - "Kdo je Helen Burns?", - { - "Rochesterova manželka", - "Janeina přítelkyně z Lowood, vzor pokory", - "Guvernantka Adèle", - "Sestra St. Johna", - }, - 1, - "Helen učí Jane snášet utrpení s křesťanskou pokorou; brzy umírá na tuberkulózu.", - }, - { - "Jakou funkci má Jane v Thornfieldu?", - { - "Ekonomka", - "Guvernantka Adèle", - "Kuchařka", - "Učitelka v sirotčinci", - }, - 1, - "Rochester ji najímá jako vychovatelku své francouzské chráněnky Adèle.", - }, - { - "Co Jane opakovaně slyší v Thornfieldu v noci?", - { - "Zvony kostela", - "Tajemné smíchání a zvuky z místnosti v patře", - "Lovec na jeleny", - "Piano Berthy", - }, - 1, - "Gotický prvek: zvuky pocházejí od Berthy Masonové, uvězněné manželky.", - }, - { - "Kdo je Bertha Mason?", - { - "Janeina sestra", - "Rochesterova právní manželka, drží se v ústraní", - "Paní Reedová", - "Služka Grace Poole", - }, - 1, - "Rochester ji tají; její existence brání Janeinu sňatku.", - }, - { - "Co se stane v den svatby Jane a Rochestera?", - { - "Obřad proběhne bez problémů", - "Právník odhalí, že Rochester je již ženatý", - "Jane uteče bez vysvětlení", - "Thornfield shoří", - }, - 1, - "Mason prozradí manželství s Berthou; obřad je zastaven.", - }, - { - "Proč Jane opouští Thornfield po odhalení?", - { - "Chce bohatství jinde", - "Dodržuje morálku a odmítá být milenkou", - "Nenávidí Adèle", - "Rochester ji vyhodí", - }, - 1, - "Jane trvá na rovnosti a čistém svědomí, i když miluje Rochester.", - }, - { - "Kdo Jane po cestě zachrání a kam ji vezou?", - { - "Rochester do Londýna", - "St. John Rivers a sestry do Moor House", - "Paní Reed do Gateshead", - "Mason do Jamajky", - }, - 1, - "Diana, Mary a St. John ji najdou vyčerpanou u dveří.", - }, - { - "Jaký vztah k Jane má St. John Rivers?", - { - "Nabízí sňatek bez lásky jako misijní partnerku", - "Je její biologický otec", - "Chce ji vydat za Masona", - "Je Rochesterův bratr", - }, - 0, - "St. John je asketický duchovní; Jane odmítá chladný sňatek z povinnosti.", - }, - { - "Co Jane dědí po strýci Johnu?", - { - "Thornfield", - "20000 liber", - "Nic", - "Lowood", - }, - 1, - "Dědictví ji finančně osvobodí a umožní rozdělit peníze se sourozenci Riversovými.", - }, - { - "Co se stane s Thornfieldem?", - { - "Bertha ho zapálí; Rochester oslepne a zmrzačí se", - "Zůstane nedotčen", - "Koupí ho St. John", - "Jane ho prodá", - }, - 0, - "Požár zabije Berthu; Rochester při záchraně služebnictva utrpí zranění.", - }, - { - "Jak román končí?", - { - "Jane zůstane sama", - "Jane se vrací k Rochesterovi a berou se", - "Jane odjíždí s St. Johnem do Indie", - "Rochester umírá", - }, - 1, - "Jane nachází Rochester v Ferndean; sňatek je rovnocenný a morálně čistý.", - }, - { - "Jaký žánrový prvek představuje dětství a cesta k dospělosti Jane?", - { - "Detektivka", - "Bildungsroman", - "Epos", - "Utopie", - }, - 1, - "Román sleduje formování charakteru a svědomí hrdinky.", - }, - { - "Co symbolizuje Bertha Mason v interpretacích?", - { - "Jen náhodná postava", - "Potlačenou ženskou vzpouru a temnou stránku viktoriánské reality", - "Janeinu sestru dvojče", - "Anděla strážného", - }, - 1, - "Bertha je často čtena jako gotický symbol útlaku a zla v domácnosti.", - }, - { - "Jak Jane reaguje na Rochesterovu nabídku milenectví?", - { - "Přijme ji", - "Odmítne a odchází", - "Požádá o rozvod", - "Zavolá policii", - }, - 1, - "Jane nechce žít v nelegálním vztahu, i za cenu utrpení.", - }, - { - "Kdo je Adèle?", - { - "Berthina sestra", - "Rochesterova chráněnka, pupil Jane", - "Služka Grace", - "Dcera St. Johna", - }, - 1, - "Adèle je důvod Janeina zaměstnání; Rochester tvrdí, že není jeho dcera.", - }, - { - "Jaký je vztah Jane k náboženství?", - { - "Bezvýhradně přijímá St. Johnův asketismus", - "Hledá vlastní morální kompas mezi pokorou a vůlí", - "Je ateistka bez etiky", - "Nenávidí křesťanství", - }, - 1, - "Jane odmítá extrémní sebeobětování St. Johna, ale ctí svědomí a spravedlnost.", - }, - { - "Proč je Jane důležitá pro feministickou literaturu?", - { - "Je pasivní hrdinka", - "Požaduje rovnost, nezávislost a respekt v lásce", - "Odmítá vzdělání", - "Je jen ozdobou boháče", - }, - 1, - "Její věta o rovnosti duší je klíčová pro interpretaci románu.", - }, - { - "Kdo je paní Reed?", - { - "Janeina teta, která ji od malička nemiluje", - "Rochesterova sestra", - "Učitelka v Lowood", - "Berthina matka", - }, - 0, - "Na smrtelné posteli se paní Reed částečně kají a přiznává vinu.", - }, - { - "Co Jane vidí v červeném pokoji v Gateshead?", - { - "Pouze nábytek", - "Místo, kde strádá a má děsivé vize", - "Třídu s dětmi", - "Knihovnu Rochesterovu", - }, - 1, - "Červený pokoj je děsivým symbolem dětství a vyloučení.", - }, - { - "Jak Rochester poprvé potká Jane?", - { - "Na plese v Londýně", - "Když spadne z koně na močálech", - "V kostele", - "V Lowood", - }, - 1, - "Setkání na cestě k Thornfieldu je typické romantické „známení“.", - }, - { - "Které prostředí NENÍ v románu výrazně zastoupeno?", - { - "Sirotčinec a škola", - "Thornfield a močály", - "Pařížský salon 18. století", - "Ferndean po požáru", - }, - 2, - "Děj je situován do anglického venkova a domů 19. století.", - }, - { - "Co znamená gotický prvek v Thornfieldu?", - { - "Realistický popis bez napětí", - "Tajemno, hrozba a temná minulost rodiny", - "Komický prvek bez významu", - "Pouze popis architektury", - }, - 1, - "Tajná manželka, požár a noční zvuky budují napětí a symboliku.", - }, - { - "Proč Jane odmítne St. Johnův sňatek?", - { - "Nemá peníze", - "Necítí lásku a nechce být jen nástrojem mise", - "Miluje Masona", - "St. John je ženatý", - }, - 1, - "Jane chce manželství z city, ne jen službu a oběť.", - }, - { - "Jak se mění Rochester na konci?", - { - "Je bohatší než dříve", - "Je slepý a závislý; vztah s Jane je vyrovnanější", - "Stává se knězem", - "Odjíždí do Indie", - }, - 1, - "Fyzická zranitelnost Rochesterovi srovnává pozici s Janinou.", - }, - { - "Jaký je hlavní konflikt románu?", - { - "Válka o trůn", - "Láska a morálka vs. společenské a právní překážky", - "Honba za pokladem", - "Vědecký experiment", - }, - 1, - "Jane musí sladit vášeň, svědomí a touhu po nezávislosti.", - }, - { - "Které tvrzení o románu je správné?", - { - "Jane končí jako Rochesterova milenka", - "Jane zůstává věrná svým zásadám a dosahuje šťastného konce", - "Rochester se nikdy neožení", - "Bertha je vymyšlená Jane", - }, - 1, - "Finální sňatek je odměnou za morální integritu hrdinky.", - }, -}; - -static const AssemblyItem book_jana_eyrova_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Dětství u paní Reedové a škola Lowood", - "Jane nastupuje jako guvernantka do Thornfieldu", - "Láska k Rochesterovi a příprava svatby", - "Odhalení manželství s Berthou Masonovou", - "Jane odchází a najde útočiště u Riversů", - "Návrat k osleplému Rochesterovi a sňatek", - }, - 6, - }, -}; - -static const char *book_jana_eyrova_plot_meaning[] = { - "Správné pořadí: dětství a Lowood → Thornfield a láska → zmařená svatba → odchod → Rivers a dědictví → požár a šťastný konec u Ferndean.", -}; - -static const LitQ book_ivan_denisovic_qs[] = { - { - "Kdo napsal Jeden den Ivana Denisoviče?", - { - "Dostojevskij", - "Alexandr Solovjov (Solženicyn)", - "Tolstoj", - "Bulgakov", - }, - 1, - "Solženicyn román publikoval v roce 1962; sám strávil roky v táborech.", - }, - { - "Jaký časový rozsah děj pokrývá?", - { - "Celý život hrdiny", - "Jeden den v táboře", - "Jeden rok", - "24 hodin v Moskvě", - }, - 1, - "Forma jednoho dne zvýrazňuje opakující se útlak i drobné radosti.", - }, - { - "Kde se děj odehrává?", - { - "V Moskvě", - "V pracovním táboře SHIZ-84 na Sibiři", - "V Paříži", - "Na frontě 2. sv. války", - }, - 1, - "Tábor v mrazivém lednu 1951 je hlavním prostředím.", - }, - { - "Za co je Šuchov v táboře?", - { - "Za vraždu", - "Za údajnou spolupráci s Němci (desertérství)", - "Za krádež banky", - "Za protisovětskou agitaci", - }, - 1, - "Šuchov byl odsouzen na 10 let; obvinění je typické pro dobu represí.", - }, - { - "Kdo vede Šuchovovu brigádu?", - { - "Der", - "Tiurin", - "Fetiukov", - "Stalin", - }, - 1, - "Tiurin je zkušený velitel, který umí jednat s dozory i chránit muže.", - }, - { - "Co je hlavní prací brigády v popisovaný den?", - { - "Těžba uhlí v dole", - "Stavba zdi v mrazu", - "Pěstování brambor", - "Výroba zbraní", - }, - 1, - "Vězni staví zeď z cihel; práce venku v mrazu je fyzicky krutá.", - }, - { - "Proč je pro Šuchova důležité jídlo?", - { - "Je gurmán", - "Kalorie znamenají přežití; každá lžíce má cenu", - "Chce vařit pro dozory", - "Nesmí jíst", - }, - 1, - "Táborový denní režim stojí na hladu a boji o porci.", - }, - { - "Kdo je Fetiukov a jak končí?", - { - "Velitel tábora", - "Vězeň, který se plazí; skončí v kobce", - "Kněz", - "Šuchovův bratr", - }, - 1, - "Fetiukov lichotí moci, ale stejně je potrestán – systém je nelítostný.", - }, - { - "Co symbolizuje Alyoška baptista?", - { - "Zradu", - "Víru a vnitřní svobodu uprostřed útlaku", - "Bohatství", - "Dozor", - }, - 1, - "Alyoška nachází smysl v modlitbě a morálce, ne v systému.", - }, - { - "Jak Šuchov zachází s cihlami a prací?", - { - "Pracuje nedbalě", - "Pečlivě, s hrdostí řemeslníka – zachovává důstojnost", - "Odmítá pracovat", - "Kradne cihly", - }, - 1, - "Kvalitní práce je forma sebeúcty v degradujících podmínkách.", - }, - { - "Co je kobka v táboře?", - { - "Restaurace", - "Trestová cela v mrazu", - "Knihovna", - "Nemocnice", - }, - 1, - "Hrozba kobky udržuje strach; Fetiukov ji za den navštíví.", - }, - { - "Proč román vyvolal senzaci v SSSR?", - { - "Byl první schválenou prózou o gulagu", - "Byl komiksovou adaptací", - "Popisoval budoucnost", - "Nebyl vůbec publikován", - }, - 0, - "Chruščovova otopa umožnila publikaci; téma bylo dříve tabu.", - }, - { - "Jaký je tón vyprávění?", - { - "Patetický heroismus", - "Střízlivý, věcný, bez zbytečné patetiky", - "Groteskní komedie", - "Pohádkový", - }, - 1, - "Solženicyn popisuje fakta chladně; emoce vyrůstají z detailů.", - }, - { - "Co Šuchov považuje na konci dne?", - { - "Za nejhorší den života", - "Za téměř šťastný den – přežil, jedl, pracoval", - "Za den svatby", - "Za den propuštění", - }, - 1, - "Závěrečná ironie: v táboře stačí malé věci k pocitu „štěstí“.", - }, - { - "Kdo je Der?", - { - "Vězeň", - "Dozorce, představitel moci", - "Lékař", - "Tiurinův bratr", - }, - 1, - "Der reprezentuje bezcitnou administrativu trestu.", - }, - { - "Jaký žánr nejlépe vystihuje dílo?", - { - "Sci-fi", - "Realistická gulagovská novela", - "Romantický epos", - "Detektivka", - }, - 1, - "Dílo dokumentuje zkušenost tábora realistickou formou.", - }, - { - "Co je brigáda v táboře?", - { - "Politická strana", - "Pracovní skupina vězňů pod velitelem", - "Rodina dozorců", - "Církevní společenství", - }, - 1, - "Solidarita v brigádě může zlepšit šanci na přežití.", - }, - { - "Proč Buynovsky trpí?", - { - "Je nemocný", - "Konfrontuje dozory jako bývalý důstojník", - "Je dítě", - "Neumí pracovat", - }, - 1, - "Jeho hrdost a vzdělání ho v systému tábora trestají.", - }, - { - "Jak román vztahuje k totalitě?", - { - "Totalitu oslavuje", - "Ukazuje dehumanizaci a strach v každodennosti", - "Nezmiňuje politiku", - "Popisuje jen přírodu", - }, - 1, - "Tábor je mikrokosmos stalinistického útlaku.", - }, - { - "Kdy autor sám strávil v táborech?", - { - "Nikdy", - "Po 2. sv. válce (kritika Stalina v dopise)", - "Za carismu", - "V 90. letech", - }, - 1, - "Solženicyn byl odsouzen za kritiku režimu; psal z vlastní zkušenosti.", - }, - { - "Co Šuchov dělá s chlebem a porcí?", - { - "Vyhazuje je", - "Šetří, plánuje, chrání před krádeží", - "Dává dozorcům", - "Nejí", - }, - 1, - "Jídlo je táborová měna i symbol přežití.", - }, - { - "Jaký význam má mrazivé počasí?", - { - "Jen kulisa", - "Další nepřítel vězňů, zvyšuje fyzické utrpení", - "Nezmiňuje se", - "Slouží k odpočinku", - }, - 1, - "Mráz při práci na zdi je součástí trestu.", - }, - { - "Která postava reprezentuje „plazení se“?", - { - "Tiurin", - "Fetiukov", - "Šuchov", - "Alyoška", - }, - 1, - "Fetiukov lichotí a ponižuje se, stejně ale neunikne trestu.", - }, - { - "Co znamená „dignita v nouzi“ u Šuchova?", - { - "Povýšení do dozoru", - "Lidskost v detailech – práce, pořádek, slušnost", - "Vzdor v podobě vraždy", - "Úplná apatie", - }, - 1, - "Šuchov si udržuje sebeúctu, i když systém ji ničí.", - }, - { - "Jaký Nobelův význam má Solženicyn?", - { - "Za poezii", - "Za literaturu (1970)", - "Za mír 2000", - "Nedostal Nobelovu cenu", - }, - 1, - "Nobelova cena za literaturu 1970; autor ji přijal až 1974.", - }, - { - "Proč forma „jednoho dne“ funguje?", - { - "Den je nudný bez děje", - "Opakuje se každý den; jeden den ukazuje celý mechanismus útlaku", - "Den je fiktivní", - "Den trvá rok", - }, - 1, - "Monotónnost je horší než jednorázová katastrofa.", - }, - { - "Co NENÍ typické pro román?", - { - "Popis práce a jídla", - "Naturalistické popisy mučíren", - "Postavy vězňů", - "Mrazivé počasí", - }, - 1, - "Dílo spíše věcně popisuje každodennost než explicitní mučení.", - }, - { - "Jak Tiurin pomáhá brigádě?", - { - "Zrazuje ji", - "Vyjednává materiál, chrání muže před zbytečnými tresty", - "Nevede ji", - "Prodává je", - }, - 1, - "Tiurin je praktický vůdce v nelidském systému.", - }, - { - "Jaký je vztah Šuchova k Alyoškovi?", - { - "Nenávist", - "Respekt k víře, i když sám není věřící", - "Sourozenec", - "Dozor", - }, - 1, - "Na konci dne si Šuchov vyslechne Alyoškovo slovo o smyslu.", - }, - { - "Jaké poselství román přináší?", - { - "Tábor je dobrodružství", - "I v totálním systému záleží na lidskosti, solidaritě a vnitřní svobodě", - "Vězni si zaslouží trest", - "Práce není důležitá", - }, - 1, - "Malé vítězství a morálka jsou formou odporu proti dehumanizaci.", - }, -}; - -static const AssemblyItem book_ivan_denisovic_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Ranní budíček a kontrola v barracích", - "Šuchov bojuje o jídlo a teplo", - "Brigáda odchází stavět zeď v mrazu", - "Tiurin vyjednává cihly a chrání partu", - "Fetiukov končí v kobce; Buynovsky je bit", - "Večer: Šuchov považuje den za téměř dobrý", - }, - 6, - }, -}; - -static const char *book_ivan_denisovic_plot_meaning[] = { - "Správné pořadí: ráno v táboře → jídlo a příprava → práce na zdi → vedení Tiurina → tresty → večerní reflexe Šuchova.", -}; - -static const LitQ book_jmeno_ruze_qs[] = { - { - "Kdo je autorem Jména růže?", - { - "Dan Brown", - "Umberto Eco", - "Dante Alighieri", - "Italo Calvino", - }, - 1, - "Eco vydal román v roce 1980; je to jeho první bestseller.", - }, - { - "Kdy a kde se děj odehrává?", - { - "1327, benediktinský klášter v Itálii", - "1789, Paříž", - "2000, Řím", - "1066, Anglie", - }, - 0, - "Děj je v době středověkých sporů o moc církve a chudobu.", - }, - { - "Kdo vypráví příběh?", - { - "William z Baskervillu", - "Starý Adso z Melku vzpomíná na mládí", - "Opat Abo", - "Jorge z Burgosu", - }, - 1, - "Adso jako stařec zapisuje události z roku 1327.", - }, - { - "Kdo je William z Baskervillu?", - { - "Opat", - "Františkánský mnich a logik, detektiv", - "Templář", - "Vesnický kovář", - }, - 1, - "William připomíná Sherlocka Holmese – dedukce a pozorování.", - }, - { - "Proč William přijede do kláštera?", - { - "Za lovem", - "Jako vyslanec při jednání o chudobě františkánů", - "Za trestem", - "Kvůli svatbě", - }, - 1, - "Politicko-církevní jednání je rámec pro detektivní děj.", - }, - { - "Co se děje v klášteře?", - { - "Nic neobvyklého", - "Série záhadných smrtí mnichů", - "Pouze stavba katedrály", - "Válka s Turky", - }, - 1, - "Vraždy souvisejí s knihovnou a zakázanými texty.", - }, - { - "Co je klíčové místo tajemství?", - { - "Kuchyně", - "Labyrint klášterní knihovny", - "Hřbitov ve městě", - "Vinný sklep bez knih", - }, - 1, - "Knihovna je geometricky složitá a střežená.", - }, - { - "Kdo je Jorge z Burgosu?", - { - "Mladý novic", - "Slepý stařec, fanatický odpůrce nebezpečných knih", - "Williamův bratr", - "Král", - }, - 1, - "Jorge zastupuje extrémní cenzuru a strach ze vědění.", - }, - { - "Proč je nebezpečná kniha o smíchu?", - { - "Je prázdná", - "Jorge ji považuje za heretickou; Aristotelova komedie", - "Je v němčině", - "Je příliš krátká", - }, - 1, - "Motiv druhé knihy Poetiky – smích podkopává autoritu.", - }, - { - "Jak vraždy souvisí s knihami?", - { - "Vůbec", - "Oběti četly nebo hledaly zakázaný spis", - "Knihy jsou jen kulisa", - "Vraždí dozorce", - }, - 1, - "Detektivní linka vede ke knihovně a k cenzurovanému textu.", - }, - { - "Kdo je Adsova dívka z vesnice?", - { - "Opatova sestra", - "Prostá dívka, symbol světa mimo klášter", - "Inkvisitorka", - "Rytířka", - }, - 1, - "Krátký milostný epizod ukazuje Adsovi jiný život než mnich.", - }, - { - "Jak román končí?", - { - "Svatba v klášteře", - "Požár kláštera; knihovna i mnoho knih zahyne", - "William se stane papežem", - "Klášter zůstane nedotčen", - }, - 1, - "Zničení knihovny je tragickým vrcholem.", - }, - { - "Jaký žánr dominuje?", - { - "Sci-fi", - "Historická detektivka s filosofickými rovinami", - "Milostný román bez děje", - "Bajka", - }, - 1, - "Eco míchá detektivku, historii a reflexi nad interpretací.", - }, - { - "Co znamená název Jméno růže?", - { - "Jasný symbol v textu", - "Záměrně nejednoznačný symbol – krása, tajemství, smrt", - "Jméno vraha", - "Název kláštera", - }, - 1, - "Eco říká, že růže je tajemství bez jedné definice.", - }, - { - "Kdo režíroval známou filmovou adaptaci?", - { - "Spielberg", - "Jean-Jacques Annaud", - "Fellini", - "Kubrick", - }, - 1, - "Film z roku 1986; Williama hraje Sean Connery.", - }, - { - "Jak William řeší záhady?", - { - "Náhodou", - "Logikou, pozorováním a znalostí středověku", - "Magickými formulí", - "Pouze modlitbou", - }, - 1, - "Dedukční metoda je vědomá narážka na detektivní literaturu.", - }, - { - "Co je inkvizice v kontextu děje?", - { - "Sport", - "Církevní soud proti heretikům", - "Klášterní kuchyně", - "Knihovní systém", - }, - 1, - "Bernard Gui a strach z kacířství prostupují atmosférou.", - }, - { - "Které téma Eco zdůrazňuje?", - { - "Nebezpečí cenzury a fanatismu", - "Oslava války", - "Moderní technologie", - "Sport", - }, - 0, - "Boj o knihy je bojem o moc nad myšlením.", - }, - { - "Kdo je Salvatore?", - { - "Opat", - "Postava mluvící smíšenými jazyky, spojená se zločinem", - "Williamův učitel", - "Rytíř bez role", - }, - 1, - "Salvatore patří k postavám temné minulosti kláštera.", - }, - { - "Proč je román postmoderní?", - { - "Ignoruje historii", - "Hrá si s intertextem, výkladem a nejistotou významu", - "Je bez děje", - "Má jen obrázky", - }, - 1, - "Eco jako sémiotik pracuje s vrstvami významů a citacemi.", - }, - { - "Jaký vztah má Adso k Williamovi?", - { - "Nepřítel", - "Učedník a vypravěč, obdivuje mistra", - "Bratr", - "Dozorce", - }, - 1, - "Adso učí se pozorovat svět i víru.", - }, - { - "Co reprezentuje labyrint?", - { - "Jen architekturu", - "Složitost poznání a nebezpečí hledání pravdy", - "Dětskou hru", - "Zahradu", - }, - 1, - "Vstup do knihovny je metaforou nebezpečného vědění.", - }, - { - "Který spor prostupuje klášterem?", - { - "Fotbal vs. hokej", - "Chudoba a moc františkánů vs. papežský dvůr", - "Válka se Vikingy", - "Rozvod krále", - }, - 1, - "Historický rámec 1327 vysvětluje přítomnost William a Bernarda.", - }, - { - "Proč maturanti čtou Jméno růže?", - { - "Je nejkratší kniha", - "Spojuje děj, historii, detektivku a filosofické otázky", - "Nemá postavy", - "Je učebnice chemie", - }, - 1, - "Román učí číst vrstevnatě a historicky.", - }, - { - "Jak William reaguje na Jorgeho fanatismus?", - { - "Souhlasí", - "Odhaluje logicky souvislosti zločinů", - "Utíká hned první den", - "Stane se opatem", - }, - 1, - "William demaskuje pachatele dedukcí.", - }, - { - "Co Adso na konci lituje?", - { - "Že neviděl růži", - "Ztráty knih, mistra i mládí v klášteře", - "Že se nestal králem", - "Že nehrál fotbal", - }, - 1, - "Vzpomínka je smutná i poučná – vědění může zahynout.", - }, - { - "Který prvek NENÍ typický pro román?", - { - "Středověké prostředí", - "Vesmírné lodě", - "Knihovna", - "Inkvisice", - }, - 1, - "Děj je pevně středověký, bez sci-fi.", - }, - { - "Jak Eco pracuje s intertextem?", - { - "Citace Bible, Aristotela, středověkých pramenů", - "Nepoužívá reference", - "Jen moderní pop", - "Jen české písně", - }, - 0, - "Román je plný odkazů na teologii, filosofii a literaturu.", - }, - { - "Kdo je Remigio?", - { - "Opat", - "Mnich s temnou minulostí heretického bratrstva", - "Adsova matka", - "Papež", - }, - 1, - "Remigio je zapleten do zločinů a strachu z odhalení.", - }, - { - "Jaké poselství lze vyčíst z požáru?", - { - "Knihy jsou zbytečné", - "Fanatismus a tajemství ničí i to, co chtěly chránit", - "Oheň je náhodný", - "Požár ničí jen jídlo", - }, - 1, - "Klášter a knihovna hoří – knowledge a moc končí v popelu.", - }, -}; - -static const AssemblyItem book_jmeno_ruze_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "William a Adso přijíždějí do kláštera", - "Začínají umírat mniši za záhadných okolností", - "Pátrání vede do labyrintu knihovny", - "Odhalí se souvislost se zakázanou knihou o smíchu", - "Jorge a konflikt o cenzuru vyústí v tragédii", - "Požár zničí klášter; Adso vzpomíná po letech", - }, - 6, - }, -}; - -static const char *book_jmeno_ruze_plot_meaning[] = { - "Správné pořadí: příjezd → vraždy → knihovna → Aristotelova komedie → Jorge → požár a vzpomínka Adsova.", -}; - -static const LitQ book_kalibuv_zlocin_qs[] = { - { - "Kdo napsal Kalibův zločin?", - { - "Němcová", - "Karel Václav Rais", - "Nezval", - "Hašek", - }, - 1, - "Rais patří k vrcholu české realistické prózy konce 19. století.", - }, - { - "Kde se děj odehrává?", - { - "Praha", - "Podkrkonoší, chalupa Kalibů", - "Morava", - "Slovensko", - }, - 1, - "Horské prostředí ovlivňuje charakter postav i atmosféru.", - }, - { - "Kdo je Frantík?", - { - "Kalibův syn z prvního manželství", - "Sousedův syn", - "Kněz", - "Karlův bratr", - }, - 0, - "Frantík je obětí Karlina týrání a Kalibovy slabosti.", - }, - { - "Jaká je Karla?", - { - "Laskavá macecha", - "Sobecká, panovačná druhá žena", - "Cizí panna", - "Učitelka", - }, - 1, - "Karla chce ovládat domácnost a odstranit Frantíka z cesty.", - }, - { - "Kdo brání Frantíkovi nejvíc?", - { - "Karla", - "Babka (Kalibova matka)", - "Kněz", - "Starosta", - }, - 1, - "Babička je jediná, kdo Frantíka aktivně chrání.", - }, - { - "Proč je Kaliba tragická postava?", - { - "Je zlý tyran od začátku", - "Je dobrácký, ale slabý – neubrání syna", - "Je bohatý magnát", - "Je cizinec", - }, - 1, - "Jeho selhání jako otce vede k nejhoršímu činu.", - }, - { - "Jak román končí?", - { - "Svatbou Frantíka", - "Kaliba v afektu syna ubije; tragédie rodiny", - "Karla odchází bohatá", - "Frantík dědí statek", - }, - 1, - "Zločin je vrchol dlouhodobého napětí v chalupě.", - }, - { - "Jaký žánr dílo reprezentuje?", - { - "Sci-fi", - "Venkovský realistický román / tragédie", - "Bajka", - "Detektivka", - }, - 1, - "Rais popisuje reálné venkovské poměry a psychologii.", - }, - { - "Co je hlavním zdrojem konfliktu?", - { - "Válka", - "Majetek, moc v domácnosti a vztah macechy k synovi", - "Magie", - "Politika", - }, - 1, - "Chalupa a sňatek Karly spouštějí boj o místo ve vztahu.", - }, - { - "Kdy román poprvé vyšel?", - { - "1892", - "1948", - "2001", - "1850", - }, - 0, - "Vydání spadá do období českého realismu.", - }, - { - "Jak Rais vykresluje venkov?", - { - "Idylicky bez problémů", - "Realisticky – chudoba, tvrdost, morální tlak", - "Jako město", - "Jako poušť", - }, - 1, - "Venkov není ráj; je prostředím sociálního a rodinného napětí.", - }, - { - "Proč Frantík trpí?", - { - "Je nemocný", - "Karla ho ponižuje, otec nezasáhne dostatečně", - "Je v exilu", - "Je bohatý", - }, - 1, - "Systematický útlak v domácnosti je jádrem děje.", - }, - { - "Co symbolizuje chalupa?", - { - "Cizí zem", - "Rodinný majetek a uzavřený svět konfliktu", - "Škola", - "Kostel", - }, - 1, - "V chalupě se soustřeďuje veškeré napětí rodiny.", - }, - { - "Jaký vztah mají Kaliba a Karla?", - { - "Manželé; Karla dominuje", - "Sourozenci", - "Nepřátelé bez sňatku", - "Strýc a neteř", - }, - 0, - "Kaliba si Karlu vzal jako druhou manželku po smrti první ženy.", - }, - { - "Co je typické pro Raisovu prózu?", - { - "Fantastické prvky", - "Psychologický realismus a venkovské prostředí", - "Sci-fi", - "Pouze poezie", - }, - 1, - "Rais je známý realistickými venkovskými romány.", - }, - { - "Proč je titul Kalibův zločin?", - { - "Zločin spáchá Frantík", - "Hlavní viníkem finálního násilí je otec Kaliba", - "Zločin spáchá babka", - "Jde o krádež krav", - }, - 1, - "Titul ukazuje na otce, který sáhne k nejhoršímu činu.", - }, - { - "Jak vesnice reaguje na rodinu?", - { - "Ignoruje ji", - "Je svědkem a morálním soudem venkovské komunity", - "Odchází z kraje", - "Staví divadlo", - }, - 1, - "Společenský tlak okolí je součástí realismu.", - }, - { - "Které téma NENÍ středem románu?", - { - "Rodinný útlak", - "Macecha a syn", - "Vesmírná kolonizace", - "Slabost otce", - }, - 2, - "Dílo je uzavřené venkovské drama 19. století.", - }, - { - "Jak lze označit Frantíka?", - { - "Antihrdina zla", - "Oběť a postava vyvolávající soucit", - "Komik", - "Vesnický boháč", - }, - 1, - "Čtenář sleduje jeho trápení a touhu po spravedlnosti.", - }, - { - "Co předchází zločinu?", - { - "Okamžitá radost", - "Dlouhodobé napětí, hádky a útlak", - "Válka", - "Povodeň bez děje", - }, - 1, - "Tragédie je logickým vyústěním situace v chalupě.", - }, - { - "Jak Rais pracuje s jazykem?", - { - "Archaičtina bez smyslu", - "Spisovná čeština s prvky venkovského prostředí", - "Cizím jazykem", - "Pouze dialogy anglicky", - }, - 1, - "Jazyk odpovídá realistickému stylu doby.", - }, - { - "Proč je dílo v maturitní četbě?", - { - "Je nejkratší", - "Ukázka českého realismu a rodinné tragédie", - "Je komiks", - "Nemá děj", - }, - 1, - "Učí číst psychologii postav a historický kontext venkova.", - }, - { - "Kdo je Vojtěch Kaliba?", - { - "Syn Frantík", - "Hospodář, otec Frantíka, manžel Karly", - "Soudce", - "Učitel", - }, - 1, - "Kaliba je středem morálního pádu příběhu.", - }, - { - "Jaký motiv sdílí s jinými realistickými díly?", - { - "Kritika městské elity bez venkova", - "Tvrdý život venkovského obyvatelstva", - "Pouze humor", - "Fantasy", - }, - 1, - "Rais navazuje na tradici zobrazování venkova (V.M. Karel, Němcová v jiném tónu).", - }, - { - "Co Kaliba typicky neumí?", - { - "Orat", - "Postavit se rozhodně Karlě ve prospěch syna", - "Vařit", - "Spát", - }, - 1, - "Jeho slabost je klíčová pro vývoj tragédie.", - }, - { - "Jaký osud čeká rodinu po zločinu?", - { - "Šťastný návrat normy", - "Morální a právní následky tragédie", - "Emigrace do Ameriky", - "Svatba Frantíka", - }, - 1, - "Zločin ničí rodinu – realistický důsledek násilí.", - }, - { - "Která postava reprezentuje starší generaci ochrany?", - { - "Karla", - "Babka", - "Frantík", - "Soused", - }, - 1, - "Babka stojí proti Karlě v ochraně vnuka.", - }, - { - "Co je afekt u Kaliby?", - { - "Plánovaná vražda", - "Náhlé emoční vypětí vedoucí k ubíjení syna", - "Radost", - "Spánek", - }, - 1, - "Zločin není chladně promyšlený, ale výbuch bezmoci.", - }, - { - "Jaký kontrast tvoří jádro díla?", - { - "Bohatí vs. chudí ve městě", - "Dobráckost otce vs. strašný čin proti synovi", - "Moře vs. hory bez děje", - "Humor vs. humor", - }, - 1, - "Kontrast zvyšuje tragický efekt.", - }, - { - "Co čtenář má cítit vůči Frantíkovi?", - { - "Opovržení", - "Soucit a pochopení jeho beznaděje", - "Smích", - "Nezájem", - }, - 1, - "Frantík je emocionálním středem čtenářské reakce.", - }, -}; - -static const AssemblyItem book_kalibuv_zlocin_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Kaliba žije s druhou ženou Karlou a synem Frantíkem", - "Karla týrá Frantíka; babka ho brání", - "Napětí v chalupě roste; otec je pasivní", - "Frantík se vzepře nebo konflikt vyhrotí", - "Kaliba v afektu syna ubije", - "Rodina čelí tragickému následku zločinu", - }, - 6, - }, -}; - -static const char *book_kalibuv_zlocin_plot_meaning[] = { - "Správné pořadí: rodina na chalupě → útlak Frantíka → eskalace → vyhrocení → zločin otce → tragický konec.", -}; - -static const LitQ book_kniska_karla_kryla_qs[] = { - { - "Kdo je autorem Kníšky?", - { - "Halík", - "Karel Kryl", - "Hrabal", - "Okudař", - }, - 1, - "Kryl je autorem textů i skladatel písní; Kníška je sbírka jeho poezie.", - }, - { - "V jakém historickém kontextu texty vznikají?", - { - "První republika bez krizí", - "Po srpnu 1968 a normalizaci", - "Středověk", - "Rok 1989 jen", - }, - 1, - "Krylovy texty reagují na okupaci a potlačení svobody.", - }, - { - "Jaký žánr Kníška reprezentuje?", - { - "Román", - "Protestní poezie a písně", - "Drama", - "Encyklopedie", - }, - 1, - "Jde o lyrické texty určené i ke zpěvu.", - }, - { - "Proč Kryl emigroval?", - { - "Za obchodem", - "Kvůli represím a nemožnosti svobodně tvořit", - "Za sportem", - "Bez důvodu", - }, - 1, - "Po okupaci emigroval do Německa; písně zůstaly symbolem odporu doma.", - }, - { - "Co znamená píseň Bratříčku, zavírej vrátka?", - { - "Výzva k zábavě", - "Varování před nebezpečím a zradou", - "Popis přírody", - "Návod na vaření", - }, - 1, - "Bratříčku oslovuje národ a varuje před odevzdáním svobody.", - }, - { - "Jak Kryl pracuje s metaforou?", - { - "Vůbec", - "Politické dění vyjadřuje obrazy (král, blázen, zima)", - "Pouze přímou reportáží", - "Jen cizím jazykem", - }, - 1, - "Alegorie umožňuje obcházet cenzuru a mluvit k čtenáři i posluchači.", - }, - { - "Co je samizdat v kontextu Kryla?", - { - "Oficiální tisk", - "Nepovolené šíření textů mimo cenzuru", - "Film", - "Rozhlas státu", - }, - 1, - "Písně a texty kolovaly neoficiálně v normalizaci.", - }, - { - "Jaký tón převládá?", - { - "Bezbřehý optimismus", - "Ironie, bolest, morální naléhavost", - "Pouze humor bez smyslu", - "Prázdná popisnost", - }, - 1, - "Kryl spojuje osobní i kolektivní zklamání s nadějí na svědomí.", - }, - { - "Kdo je „král“ v písních?", - { - "Historická postava bez významu", - "Alegorie moci, často groteskní a pokrytecké", - "Dítě", - "Sportovec", - }, - 1, - "Král symbolizuje režim nebo autoritu, která zklame.", - }, - { - "Proč maturita zahrnuje Kníšku?", - { - "Je nejdelší román", - "Ukazuje poezii 20. stol. v politickém kontextu", - "Nemá význam", - "Je v angličtině", - }, - 1, - "Učí číst lyrický text v souvislosti s dějinami.", - }, - { - "Co je normalizace?", - { - "Období svobody 1968", - "Upevnění komunistické moci po okupaci 1968", - "První světová válka", - "Sametová revoluce", - }, - 1, - "Normalizace potlačila reformy Pražského jara.", - }, - { - "Jak Kryl vnímá mlčení lidí?", - { - "Chválí ho", - "Vnímá ho jako morální selhání", - "Nezmiňuje", - "Považuje za hrdinství", - }, - 1, - "Motiv viny davu a kompromisu se opakuje.", - }, - { - "Kdy Kryl zemřel?", - { - "1994", - "1968", - "2005", - "1848", - }, - 0, - "Karel Kryl zemřel v roce 1994; po listopadu 89 se vrátil do veřejného života.", - }, - { - "Jak se liší píseň a báseň v Kníšce?", - { - "Písně mají refrén a hudební formu", - "Nic se neliší", - "Básně jsou jen pro děti", - "Písně nemají text", - }, - 0, - "Mnoho textů známe i z Krylova zpěvu s kytarou.", - }, - { - "Co symbolizuje zima nebo tma v textech?", - { - "Jen počasí", - "Temnota doby, strach, útlak", - "Radost", - "Léto", - }, - 1, - "Obrazné prostředí odpovídá politické situaci.", - }, - { - "Které téma NENÍ typické?", - { - "Svoboda a útlak", - "Emigrace", - "Vesmírné války", - "Ironie vůči moci", - }, - 2, - "Kryl píše o české realitě 20. století, ne sci-fi.", - }, - { - "Co je protest song?", - { - "Píseň oslavující moc", - "Hudební projev odporu nebo kritiky", - "Jen instrumentál", - "Anthem sportu", - }, - 1, - "Kryl je v Česku symbolem autorské protestní písně.", - }, - { - "Jak čtenář chápe alegorii Král a klaun?", - { - "Jako groteskní obraz moci a pravdy", - "Jako cookbook", - "Bez významu", - "Jako vědecký článek", - }, - 0, - "Postavy stojí pro reálné politické vztahy.", - }, - { - "Proč exilové vydání 1972?", - { - "Kryl nemohl oficiálně publikovat v normalizaci", - "Kniha byla zakázaná jen v Německu", - "Neexistuje", - "Bylo to dětské vydání", - }, - 0, - "V totalitě vyšly texty v zahraničí nebo samizdatově.", - }, - { - "Jaký nástroj Kryl typicky doprovází?", - { - "Kytara", - "Harfa bez hlasu", - "Jen klavír klasické", - "Žádný", - }, - 0, - "Kryl je známý jako kytarista a zpěvák.", - }, - { - "Co znamená morální odpovědnost v textech?", - { - "Každý nese díl viny za stav společnosti", - "Nikdo není odpovědný", - "Jen vláda USA", - "Jen církev", - }, - 0, - "Kryl apeluje na svědomí jednotlivce i národa.", - }, - { - "Jak pracuje s biblickými narážkami?", - { - "Vůbec", - "Obrazy dobra, zla a křižovatky osudu", - "Jen jako encyklopedie", - "Jako vtip bez smyslu", - }, - 1, - "Biblické motivy zvyšují váhu morálních otázek.", - }, - { - "Co je typické pro jazyk Kníšky?", - { - "Úderné, obrazné, s refrénem", - "Suchý úřední styl", - "Pouze archaismy", - "Anglicky", - }, - 0, - "Lyrika je hutná a zapamatovatelná.", - }, - { - "Jak reaguje na srpnovou okupaci 1968?", - { - "Ignoruje", - "Texty reflektují zradu, bolest a ztrátu naděje jara", - "Oslavuje okupaci", - "Píše jen o lásce", - }, - 1, - "Okupace je východiskem protestního tónu sbírky.", - }, - { - "Kdo je adresátem „bratříčku“?", - { - "Jeden bratr v rodině", - "Symbolicky národ, blízký člověk, varovaný před nebezpečím", - "Cizinec", - "Král", - }, - 1, - "Oslovení je intimní i kolektivní.", - }, - { - "Proč jsou texty stále aktuální?", - { - "Mluví o univerzální svobodě a svědomí", - "Jsou zastaralé", - "Nejsou čitelné", - "Jsou jen hudební", - }, - 0, - "Otázky moci a odvahy mluvit platí i mimo 70. léta.", - }, - { - "Co NENÍ charakteristika Kryla?", - { - "Protest", - "Emigrace", - "Oficiální pochvala normalizace", - "Ironie", - }, - 2, - "Kryl normalizaci kritizoval, ne oslavoval.", - }, - { - "Jak vnímat emigranta v písních?", - { - "Postavu bez emocí", - "Člověka v konfliktu domov–svoboda–vina", - "Vždy boháče", - "Vždy zrádce", - }, - 1, - "Exil je v Krylových textech bolestný i morálně složitý.", - }, - { - "Co spojuje Kníšku s další českou lyricou 20. stol.?", - { - "Nic", - "Tradici disidentské a protestní kultury", - "Pouze humor", - "Pouze sci-fi", - }, - 1, - "Kryl stojí vedle Hrabala, Holanů apod. v jiných žánrech, ale v politické lyrice je ikonou.", - }, - { - "Jaký efekt má refrén v písních?", - { - "Ztěžuje čtení", - "Upevňuje poselství a zapamatovatelnost", - "Nemá funkci", - "Je jen v angličtině", - }, - 1, - "Opakování (např. varování) je hudebně i významově klíčové.", - }, -}; - -static const AssemblyItem book_kniska_karla_kryla_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Pražské jaro a naděje na svobodu", - "Okupace vojsky a konec reform", - "Kryl emigruje; texty kolují v samizdatu", - "Kníška v exilu sbírá protestní poezii", - "Písně varují před mlčením a zradou", - "Dílo zůstává symbolem morálního odporu", - }, - 6, - }, -}; - -static const char *book_kniska_karla_kryla_plot_meaning[] = { - "Správné pořadí: jaro 68 → okupace → exil → sbírka → varování v textech → trvalý význam protestní kultury.", -}; - -static const LitQ book_komu_zvoni_hrana_qs[] = { - { - "Kdo napsal Komu zvoní hrana?", - { - "Faulkner", - "Ernest Hemingway", - "Steinbeck", - "Fitzgerald", - }, - 1, - "Román vyšel v roce 1940; Hemingway sledoval válku jako novinář.", - }, - { - "Kdy a kde se děj odehrává?", - { - "Španělská občanská válka, hory u Madridu", - "2. sv. válka v Normandii", - "Vietnam", - "První sv. válka v Itálii", - }, - 0, - "Děj je v roce 1937 v oblasti Guadarrama.", - }, - { - "Kdo je Robert Jordan?", - { - "Frankistický generál", - "Americký dobrovolník, expert na demolice", - "Španělský kněz", - "Novinář bez úkolu", - }, - 1, - "Jordan má za úkol odpálit most.", - }, - { - "Co znamená titul románu?", - { - "Popis kostela", - "Citát Donne: smrt každého se týká všech", - "Jméno mostu", - "Název písně bez významu", - }, - 1, - "Titul vyjadřuje solidaritu a lidskou propojenost.", - }, - { - "Kdo je Maria?", - { - "Jordanova láska, oběť války", - "Frankistická špionka", - "Generálka", - "Jordanova sestra", - }, - 0, - "Maria prožila traumu; v Jordanovi nachází lásku.", - }, - { - "Jaký je vztah Pabla a Pilar?", - { - "Sourozenci", - "Manželé; Pablo je vůdce, Pilar silnější morálně", - "Nepřátelé bez vazby", - "Důstojníci", - }, - 1, - "Pablo postupně couvá z boje; Pilar drží partu.", - }, - { - "Co má Jordan udělat?", - { - "Postavit most", - "Odpálit most za úsvitu", - "Ukrást letadlo", - "Podepsat mír", - }, - 1, - "Most má zdržet fašistický postup během útoku.", - }, - { - "Proč je úkol riskantní?", - { - "Nikdo nehlídá", - "Partyzáni jsou rozdělení, Pablo sabotuje, nepřítel blízko", - "Jordan je nemocný", - "Most neexistuje", - }, - 1, - "Vnitřní rozpory party zvyšují nebezpečí.", - }, - { - "Kdo je Anselmo?", - { - "Starý průvodce, ctí morálku války", - "Fašista", - "Jordanův bratr z USA", - "Pilot", - }, - 0, - "Anselmo pomáhá Jordanovi a trpí kvůli zabíjení.", - }, - { - "Co se stane El Sordovi?", - { - "Stane se králem", - "Je obklíčen a padne v boji", - "Emigruje", - "Zradí republiku", - }, - 1, - "El Sordo a jeho muži umírají hrdinsky na kopci.", - }, - { - "Jak Jordan končí?", - { - "Svatba v Madridu", - "Zraněn u mostu; zůstává, aby zdržel nepřítele", - "Utíká do USA", - "Stává se generálem", - }, - 1, - "Finální oběť je morální i praktická.", - }, - { - "Jaký styl je typický pro Hemingwaye?", - { - "Dlouhé patetické věty", - "Střídmý jazyk, dialog, „iceberg“ – hodně pod hladinou", - "Pouze poezie", - "Groteskní humor", - }, - 1, - "Emoce jsou často pod textem, ne v patosu.", - }, - { - "Na čí straně Jordan bojuje?", - { - "Frankisté", - "Republikáni / demokratická strana", - "Neutralita", - "Nacisté Německa", - }, - 1, - "Jordan je v mezinárodní brigádě na straně republiky.", - }, - { - "Proč Pablo ukradne výbušniny?", - { - "Chce zmařit nebezpečný útok a zachránit partu", - "Chce být bohatý", - "Na příkaz Jordana", - "Pro zábavu", - }, - 0, - "Pablo jedná sobecky z strachu o přežití.", - }, - { - "Co symbolizuje most?", - { - "Jen stavba", - "Spojení úkolu, oběti a vojenského plánu", - "Kostel", - "Hranice bez děje", - }, - 1, - "Most je středem napětí celého románu.", - }, - { - "Jaký je význam lásky Jordan–Maria?", - { - "Bez vlivu na děj", - "Dává Jordanovi lidský smysl i bolest ztráty", - "Komický prvek", - "Past od fašistů", - }, - 1, - "Láska kontrastuje s brutalitou války.", - }, - { - "Kdo režíroval slavnou filmovou adaptaci?", - { - "Sam Wood (1943)", - "Spielberg", - "Kubrick", - "Nolan", - }, - 0, - "Film z 40. let s Gary Cooperem a Ingrid Bergmanovou.", - }, - { - "Co je mezinárodní brigáda?", - { - "Frankistická armáda", - "Dobrovolníci z ciziny bojující za republiku", - "Nevládní organizace dnes", - "Pouze španělští kněží", - }, - 1, - "Jordan reprezentuje cizince v španělské válce.", - }, - { - "Proč maturanti čtou román?", - { - "Je nejkratší", - "Spojuje válku, etiku, styl modernismu a historii Španělska", - "Nemá postavy", - "Je komiks", - }, - 1, - "Dílo je klíčové pro Hemingwaye i 20. století.", - }, - { - "Jak Pilar vnímá Pabla?", - { - "Obdivuje jeho statečnost vždy", - "Kritizuje jeho zbabělost, ale zůstává v partě", - "Nezná ho", - "Je to cizinec", - }, - 1, - "Pilar je duší party; Pablo je její protiklad.", - }, - { - "Co Jordan cítí k zabíjení?", - { - "Radost", - "Morální tíhu; válka není abstraktní", - "Nic", - "Pouze nudu", - }, - 1, - "Jordan přemýšlí o smrti i když plní rozkaz.", - }, - { - "Které téma NENÍ středem?", - { - "Oběť pro věc", - "Solidarita", - "Vesmírná kolonizace", - "Láska ve válce", - }, - 2, - "Román je realistická válečná próza.", - }, - { - "Kde party zimuje?", - { - "V jeskyni v horách", - "V Paříži", - "Na lodi", - "V paláci", - }, - 0, - "Jeskyně je útočiště i místem intimity a plánů.", - }, - { - "Co se stane s výbušninami po Pablově krádeži?", - { - "Jordan získá náhradu a plán pokračuje", - "Úkol končí hned", - "Frankisté je najdou", - "Maria je odpálí", - }, - 0, - "Parta získá materiál zpět (Pablo částečně pomůže).", - }, - { - "Jaký význam má smrt El Sorda pro děj?", - { - "Žádný", - "Ukazuje neúprosnost války a cenu odporu", - "Komický", - "Znamená konec války", - }, - 1, - "Scéna na kopci je vrchol tragismu.", - }, - { - "Co Jordan přemýšlí o otci?", - { - "Otec byl republikán", - "Otec se střelil; Jordan řeší sebevraždu a smysl", - "Otec byl král", - "Nezmiňuje otce", - }, - 1, - "Rodinná minulost ovlivňuje Jordanův pohled na smrt.", - }, - { - "Proč „komu zvoní hrana“ v maturitní interpretaci?", - { - "Jen o kostelech", - "O tom, že smrt a osud jednoho se dotýkají celku", - "O hudbě", - "O mostě", - }, - 1, - "Donneova myšlenka propojuje hrdiny s lidstvem.", - }, - { - "Jak Hemingway vykresluje fašisty?", - { - "Jako abstraktní nepřítele války", - "Jako konkrétní vojenskou hrozbu bez patosu", - "Jako kamarády", - "Vůbec", - }, - 1, - "Nepřítel je reálný, válka je konkrétní.", - }, - { - "Co Maria symbolizuje?", - { - "Obnovu života a naděje po zlu", - "Jen špionáž", - "Bohatství", - "Válku", - }, - 0, - "Maria je zraněná, ale milující protiváha války.", - }, - { - "Jaký je hlavní konflikt románu?", - { - "Sportovní soutěž", - "Plnění nebezpečného úkolu vs. lidský vztah a strach", - "Soudní proces", - "Detektivní hádanka bez války", - }, - 1, - "Jordan musí sladit povinnost, lásku a smrt.", - }, -}; - -static const AssemblyItem book_komu_zvoni_hrana_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Jordan se připojí k partyzánům v horách", - "Seznámí se s Marií a plánuje odpálení mostu", - "Pablo ukradne výbušniny; napětí v partě", - "El Sordo padne v boji s fašisty", - "Jordan odpálí most, ale je zraněn", - "Zůstává na místě, aby zdržel nepřítele", - }, - 6, - }, -}; - -static const char *book_komu_zvoni_hrana_plot_meaning[] = { - "Správné pořadí: příjezd k partě → láska a plán → sabotáž Pabla → smrt El Sorda → most → Jordanova oběť.", -}; - -static const LitQ book_kral_oidipus_qs[] = { - { - "Kdo napsal Krále Oidipa?", - { - "Euripides", - "Sofokles", - "Aischylos", - "Homér", - }, - 1, - "Sofokles je jeden ze tří velkých athénských tragiků.", - }, - { - "Kde se děj odehrává?", - { - "Sparta", - "Théby", - "Athény", - "Troja", - }, - 1, - "Théby jsou postiženy morem a prokletím.", - }, - { - "Jaký problém trápí Théby na začátku?", - { - "Válka s Persy", - "Mor a neznámý viník zločinu", - "Hladomor bez moru", - "Povodeň", - }, - 1, - "Lidé žádají Oidipa, aby město zachránil.", - }, - { - "Co slíbil Oidipus občanům?", - { - "Nové hradby", - "Najde viníka vraždy krále Láia a město vysvobodí", - "Odejde do exilu hned", - "Zruší bohy", - }, - 1, - "Král se zavazuje trestat vraha bývalého krále.", - }, - { - "Kdo je Tiresias?", - { - "Vrah", - "Slepý větec, který zná pravdu", - "Oidipův syn", - "Cizí voják", - }, - 1, - "Tiresias odhalí, že viníkem je sám Oidipus.", - }, - { - "Proč Oidipus nejdřív Tiresia neposlouchá?", - { - "Je hluchý", - "Pýcha – odmítá obvinění", - "Spí", - "Tiresias nemluví", - }, - 1, - "Oidipus je netrpělivý a arogantní vůči věštci.", - }, - { - "Koho Oidipus obviní z intriky?", - { - "Kréóna", - "Chór", - "Posla", - "Sama sebe", - }, - 0, - "Domnívá se, že Kréón usiluje o trůn.", - }, - { - "Co odhalí posel z Korintu?", - { - "Oidipus není syn korintského krále Polyba", - "Oidipus je bůh", - "Iokasté je cizinka", - "More skončilo", - }, - 0, - "Oidipus byl adoptován; začne pátrat po pravých rodičích.", - }, - { - "Kdo byl Laios?", - { - "Oidipův syn", - "Bývalý král Théb, Oidipův biologický otec", - "Kréónův otec", - "Pastýř bez role", - }, - 1, - "Věštba předpověděla, že syn Láia zabije otce.", - }, - { - "Co Oidipus udělal na křižovatce?", - { - "Pomohl starci", - "V afektu zabil cestovatele (Láia)", - "Koupil koně", - "Modlil se", - }, - 1, - "Neznal otce; spor o průjezd vedl k vraždě.", - }, - { - "Kdo je Sfinga v mýtu?", - { - "Had", - "Bytost s hádankou; Oidipus ji porazil", - "Kréónova žena", - "Chór", - }, - 1, - "Vítězství nad Sfingou učinilo Oidipa králem.", - }, - { - "Kdo se stane Oidipovou manželkou?", - { - "Antigona", - "Iokasté – vlastní matka", - "Cizí princezna", - "Tiresias", - }, - 1, - "Oidipus se oženil s vdovou po Láiovi, aniž znal vztah.", - }, - { - "Co je anagnórisis?", - { - "Hudba chóru", - "Poznání pravdy hrdinou", - "Vstup na jeviště", - "Konec hry", - }, - 1, - "Oidipus pochopí, že splnil věštbu.", - }, - { - "Jak Iokasté reaguje na podezření?", - { - "Radost", - "Popírá, pak spáchá sebevraždu", - "Utíká do Korintu", - "Zabije Oidipa", - }, - 1, - "Iokasté chápe dřív a nevydrží pravdu.", - }, - { - "Co Oidipus udělá po poznání?", - { - "Oslaví svatbu", - "Vydloubne si oči a žádá vyhnanství", - "Stane se bohem", - "Obviní chór", - }, - 1, - "Symbolické potrestání – viděl, ale neviděl pravdu.", - }, - { - "Kdo převezme moc na konci?", - { - "Kréón", - "Oidipus navždy", - "Tiresias", - "Laios", - }, - 0, - "Kréón zůstává jako vládce; Oidipus odchází.", - }, - { - "Co je hamartia u Oidipa?", - { - "Nemoc", - "Tragická chyba – pýcha, netrpělivost, touha po pravdě bez snášení", - "Línost", - "Zrada Kréóna", - }, - 1, - "Hrdina není zlý, ale má tragickou vadu charakteru.", - }, - { - "Jaký význam má chór?", - { - "Komický intermezzo", - "Komentuje děj a reakce obce", - "Hraje hlavní roli", - "Neobjevuje se", - }, - 1, - "Chór thébských stařců vyjadřuje city města.", - }, - { - "Co je katarze?", - { - "Smích diváka", - "Očistný efekt strachu a soucitu", - "Hudba bez děje", - "Scéna bez významu", - }, - 1, - "Aristoteles tragédii vysvětluje právě katarzí.", - }, - { - "Proč nelze věštbě uniknout?", - { - "Bohové a osud jsou silnější než lidské plány", - "Věštba je vtip", - "Oidipus neposlouchal", - "Laios žije", - }, - 0, - "Tragédie ukazuje osudovost mýtu.", - }, - { - "Které pravidlo antické tragédie dodržuje hra?", - { - "Jednota času, místa a děje", - "Pět dějství bez pravidel", - "Pouze komické prvky", - "Bez chóru", - }, - 0, - "Děj se soustředí na den odhalení v Thébách.", - }, - { - "Co znamená „oidipovský komplex“ u Freuda?", - { - "Sofoklovo pojmenování", - "Moderní psychoanalytický pojem odvozený od mýtu, ne od Sofokla", - "Chór", - "Věštba", - }, - 1, - "Freud použil jméno; antická hra má jiný kontext.", - }, - { - "Kdo zabil Sfingu?", - { - "Kréón", - "Oidipus správnou hádankou", - "Iokasté", - "Posel", - }, - 1, - "Vítězství nad Sfingou přineslo korunu.", - }, - { - "Proč Oidipus pátrá po vrahovi Láia?", - { - "Neví, že hledá sám sebe", - "Ví od začátku", - "Na příkaz Kréóna bez důvodu", - "Kvůli pokladu", - }, - 0, - "Ironie tragédie – trestá sám sebe.", - }, - { - "Jaký kontrast tvoří Oidipus?", - { - "Bohatý vs. chudý", - "Vidí svět, ale ne pravdu o sobě; pak slepý, ale chápe", - "Mladý vs. starý bez významu", - "Muž vs. žena bez děje", - }, - 1, - "Motiv slepota–vidění je klíčový.", - }, - { - "Které tvrzení o Iokasté je správné?", - { - "Je Oidipova dcera", - "Je Oidipova matka i manželka", - "Je Kréónova dcera bez vztahu", - "Je bohyně", - }, - 1, - "Incest je jádrem odhalení.", - }, - { - "Co je peripetie?", - { - "Obrat osudu hrdiny od štěstí k neštěstí", - "Úvod hry", - "Píseň chóru", - "Smích", - }, - 0, - "Od slavného krále k prokletému vyhnanci.", - }, - { - "Proč maturita zahrnuje Krále Oidipa?", - { - "Je nejnovější román", - "Základ tragédie, mýtu a dramaturgie", - "Je komiks", - "Bez významu", - }, - 1, - "Učí strukturu tragédie a antické mytologie.", - }, - { - "Jak končí Oidipus v této hře?", - { - "Na trůnu navždy", - "Odchází do vyhnanství, zničen poznáním", - "Svatba s novou ženou", - "Vítězí nad bohy", - }, - 1, - "Finále je pokání a vyhnanství (pokračuje v Oidipovi v Kolónu).", - }, - { - "Jaké poselství tragédie nese?", - { - "Člověk musí poznat sám sebe, i za cenu bolesti", - "Pýcha vždy vyhrává", - "Bohové neexistují", - "Lži jsou lepší", - }, - 0, - "Poznání pravdy je morální i existenciální nutnost.", - }, -}; - -static const AssemblyItem book_kral_oidipus_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Théby trpí morem; Oidipus slíbí najít viníka", - "Tiresias obviní Oidipa; král to odmítá", - "Posel a pastýř odhalí Oidipovu minulost", - "Oidipus pozná, že zabil otce a vzal si matku", - "Iokasté spáchá sebevraždu", - "Oidipus oslepí sám sebe a odchází do vyhnanství", - }, - 6, - }, -}; - -static const char *book_kral_oidipus_plot_meaning[] = { - "Správné pořadí: mor a slib → Tiresias → odhalení rodu → anagnórisis → smrt Iokasté → sebeztrestání a exil.", -}; - -static const LitQ book_krysar_qs[] = { - { - "Kdo napsal Krysaře?", - { - "Neruda", - "Viktor Dyk", - "Hašek", - "Čapek", - }, - 1, - "Dyk vydal novelu v roce 1915; patří k české moderně.", - }, - { - "Na jaké legendě novela staví?", - { - "O Vlastovi", - "O krysaři z Hameln", - "O Ikarovi", - "O Golemovi", - }, - 1, - "Porýnská pověst o muži, který odvedl děti píšťalou.", - }, - { - "Kdo je hlavní hrdina?", - { - "Sepp Jörgen", - "Krysař – cizinec s píšťalou", - "Bonifác", - "Konšel", - }, - 1, - "Krysař přichází do města a řeší problém krys.", - }, - { - "Proč město Krysaře najme?", - { - "Kvůli povodni", - "Město sužují krysy", - "Chce tanec", - "Hledá krále", - }, - 1, - "Krysy ohrožují obyvatele; Krysař slíbí pomoc.", - }, - { - "Co měšťané udělají po vyhnání krys?", - { - "Zaplatí slíbenou odměnu", - "Odmítnou zaplatit dohodnutou cenu", - "Odejdou z města", - "Postaví sochu", - }, - 1, - "Zrada slova spouští pomstu.", - }, - { - "Koho Krysař miluje?", - { - "Agnes", - "Kristýnku", - "Vdovu konšela", - "Nikoho", - }, - 1, - "Láska ke Kristýnce je intimní linie novely.", - }, - { - "Kdo je Sepp Jörgen?", - { - "Krysařův nepřítel", - "Prostý rybář, věrný a přeživší", - "Král", - "Krysa", - }, - 1, - "Sepp představuje jiný, ne měšťanský svět.", - }, - { - "Jak Krysař pomstí zradu?", - { - "Soudní žalobou", - "Píšťalou odvede děti z města", - "Spálí radnici", - "Odejde bez reakce", - }, - 1, - "Legendární scéna odchodu dětí za pišťalou.", - }, - { - "Proč je novela alegorická?", - { - "Popisuje jen historii", - "Měšťanská zrada a odplata vypovídá o morálce společnosti", - "Je bez významu", - "Je učebnice chemie", - }, - 1, - "Dyk čte legendu i v kontextu války a pokrytectví.", - }, - { - "Jaký je styl Dykovy prózy?", - { - "Úřední report", - "Lyrizovaná, rytmická prósa s refrény", - "Sci-fi", - "Detektivka", - }, - 1, - "Text působí téměř jako báseň v próze.", - }, - { - "Co symbolizuje píšťala?", - { - "Jen hudební nástroj", - "Moc nad lidmi – nejdřív krysy, pak děti", - "Kříž", - "Mince", - }, - 1, - "Píšťala je nástroj svodu i trestu.", - }, - { - "Kdy novela vznikla?", - { - "1915", - "1848", - "1989", - "2000", - }, - 0, - "Vznik v první světové válce ovlivňuje alegorické čtení.", - }, - { - "Kdo jsou měšťané v díle?", - { - "Idealní občané", - "Sobečtí, nedodrží slovo", - "Vojáci", - "Cizinci", - }, - 1, - "Kolektivní vina města je jádrem.", - }, - { - "Jak končí vztah Krysař–Kristýnka?", - { - "Svatbou", - "Tragicky – láska se mísí s osudem pomsty", - "Bez kontaktu", - "Komedií", - }, - 1, - "Osobní i kolektivní tragédie se proplétají.", - }, - { - "Kde se děj odehrává?", - { - "Praha", - "Hameln (Hamelyn)", - "Vídeň", - "Paříž", - }, - 1, - "Německé město v legendě i u Dyka.", - }, - { - "Proč je Krysař cizinec?", - { - "Bez důvodu", - "Outsider odhaluje morálku uzavřené komunity", - "Je místní kněz", - "Je král", - }, - 1, - "Přichází zvenku a mění osud města.", - }, - { - "Co je tématem zrady?", - { - "Politická jen v moderně", - "Porušení daného slova a smlouvy", - "Zrada v kartách", - "Sport", - }, - 1, - "Město nezaplatí – morální i smluvní porušení.", - }, - { - "Který prvek NENÍ typický?", - { - "Legenda", - "Lyrizace", - "Vesmírná válka", - "Alegorie", - }, - 2, - "Novela je komorní legendární příběh.", - }, - { - "Jak Dyk pracuje s opakováním?", - { - "Refrénovité motivy a věty", - "Nepoužívá", - "Jen v angličtině", - "Nahodile", - }, - 0, - "Opakování zvyšuje rytmus a napětí.", - }, - { - "Kdo je Bonifác?", - { - "Rival, měšťanská postava", - "Krysa", - "Rybář", - "Vdova", - }, - 0, - "Bonifác patří k městskému prostředí a rivalitám.", - }, - { - "Proč maturita zahrnuje Krysaře?", - { - "Nejdelší román", - "Ukázka moderní lyrizované prózy a alegorie", - "Bez stylu", - "Jen historie", - }, - 1, - "Učí číst legendu i symboliku.", - }, - { - "Co znamená kolektivní vina?", - { - "Vina jednoho vojáka", - "Celé město nesou odpovědnost za zradu", - "Vina Krysaře", - "Bez viny", - }, - 1, - "Měšťané jednají společně proti Krysařovi.", - }, - { - "Jaký kontrast tvoří Sepp Jörgen?", - { - "Měšťan vs. prostý člověk mimo pokrytectví", - "Bohatý vs. chudý bez morálky", - "Dítě vs. dospělý", - "Válka vs. mír bez děje", - }, - 0, - "Rybář představuje jinou hodnotovou osu.", - }, - { - "Co je er-forma v novelě?", - { - "Vypravěč „on“", - "Vypravěč neviditelný, děj sledujeme zvenku er-formou Dykova stylu", - "Dyk používá vypravěče třetí osoby s lyrickým nádechem", - "Jen dialogy", - }, - 2, - "Novela je psána er-formou s poetickým jazykem.", - }, - { - "Jak interpretovat novelu ve válce 1914–18?", - { - "Ignorovat kontext", - "Zrada slibů může odkazovat na politickou zradu a malost", - "Jen dětská pohádka", - "Reklama", - }, - 1, - "Contemporary readers viděli paralely s válkou.", - }, - { - "Kdo přežije katastrofu dětí?", - { - "Všichni měšťané", - "Sepp Jörgen a dospělí; děti odcházejí", - "Nikdo", - "Jen Krysař", - }, - 1, - "Legenda: děti mizí; dospělí zůstávají s vinou.", - }, - { - "Co je právo na odměnu?", - { - "Krysař nemá nárok", - "Etický dluh města za vykonanou službu", - "Jen daň", - "Pokuta", - }, - 1, - "Nezaplacení je start pomsty.", - }, - { - "Jaký žánr nejlépe sedí?", - { - "Novela / lyrizovaná próza", - "Epos", - "Sci-fi", - "Učebnice", - }, - 0, - "Krátké hutné dílo s poetickým jazykem.", - }, - { - "Co čtenář cítí vůči městu?", - { - "Obdiv", - "Odsudek pokrytectví", - "Nezájem", - "Smích bez děje", - }, - 1, - "Měšťané si zaslouží morální soud.", - }, - { - "Jaké poselství novela nese?", - { - "Slovo a smlouva mají cenu; zrada se mstí", - "Krysy jsou roztomilé", - "Cizinci jsou vždy zlí", - "Láska vždy vyhrává", - }, - 0, - "Dyk varuje před malostí a nečestností.", - }, -}; - -static const AssemblyItem book_krysar_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Krysař přichází do Hamelnu a slíbí vyhnat krysy", - "Píšťalou vyžene krysy z města", - "Měšťané odmítnou zaplatit dohodnutou odměnu", - "Krysař miluje Kristýnku; město ho zradí", - "Krysař znovu hraje na píšťalu – odvádí děti", - "Město zůstává s vinou a tragickým následkem", - }, - 6, - }, -}; - -static const char *book_krysar_plot_meaning[] = { - "Správné pořadí: příchod → vyhnání krys → nezaplacení → láska a zrada → odchod dětí → vina města.", -}; - -static const LitQ book_kulicka_qs[] = { - { - "Kdo napsal Kuličku?", - { - "Zola", - "Guy de Maupassant", - "Flaubert", - "Hugo", - }, - 1, - "Maupassant patří k mistrem francouzské novely.", - }, - { - "Kdy a kde se děj odehrává?", - { - "Po válce 1870/71, cesta z Rouenu", - "Za revoluce 1789", - "V 21. století", - "V Itálii", - }, - 0, - "Měšťané utíkají z okupovaného Rouenu.", - }, - { - "Kdo je Kulička?", - { - "Kněžka", - "Prostitutka Elisabeth Roussetová", - "Generálka", - "Učitelka", - }, - 1, - "Kulička je přezdívka podle postavy.", - }, - { - "Proč cestují ve voze?", - { - "Na dovolenou", - "Utíkají před okupací do Havra", - "Na svatbu", - "Do Paříže za móou", - }, - 1, - "Společná cesta spojuje různé společenské vrstvy.", - }, - { - "Co brání voze v odjezdu?", - { - "Pruský důstojník nepropustí bez „ústupku“ Kuličky", - "Kolo", - "Sníh", - "Stávka", - }, - 0, - "Důstojník chce noc s Kuličkou.", - }, - { - "Jak se měšťané chovají na začátku k Kuličce?", - { - "S úctou", - "Pohrdavě, nechtějí sedět vedle „ nízké “ ženy", - "Neznají ji", - "Obdivují ji", - }, - 1, - "Společenská předsudek je silný.", - }, - { - "Proč nakonec tlačí na Kuličku?", - { - "Aby vařila", - "Aby šla k důstojníkovi a umožnila odjezd", - "Aby platila", - "Aby zpívala", - }, - 1, - "Vlastní zájem přebije morální řeči.", - }, - { - "Co udělá Kulička?", - { - "Odmítne navždy", - "Obětuje se pro ostatní a jde k Prusům", - "Utéká sama", - "Zavolá policii", - }, - 1, - "Je statečnější než „slušní“ cestující.", - }, - { - "Jak měšťané reagují po odjezdu?", - { - "Děkují s úctou", - "Jedí a opět ji pohrdají, posmívají se", - "Pláčou", - "Vrací peníze", - }, - 1, - "Pointa odhaluje jejich pokrytectví.", - }, - { - "Jaký žánr novela reprezentuje?", - { - "Realismus / naturalismus", - "Fantasy", - "Sci-fi", - "Epos", - }, - 0, - "Maupassant realisticky kritizuje společnost.", - }, - { - "Co je ironie v díle?", - { - "Kulička je nejhorší", - "Nej„morálnější“ v chování je prostitutka", - "Prusové jsou hrdinové", - "Jeptišky jsou bohaté", - }, - 1, - "Obrácení hodnot je jádrem novely.", - }, - { - "Kdo jsou jeptišky ve voze?", - { - "Vojáci", - "Náboženské sestry, také jedou z města", - "Pruské špionky", - "Rodina Kuličky", - }, - 1, - "Jedí Kuliččiny sendviče, ale nepodpoří ji morálně.", - }, - { - "Co symbolizuje společná jízda?", - { - "Uzavřený mikrokosmos francouzské společnosti", - "Sport", - "Náhodu", - "Vesmír", - }, - 0, - "Voze je jevištěm sociální kritiky.", - }, - { - "Jak Maupassant pracuje s pointou?", - { - "Bez závěru", - "Ostrý závěr demaskuje postavy", - "Pouze happy end", - "Nevysvětlí", - }, - 1, - "Závěrečná scéna s jídlem a posměchem je slavná.", - }, - { - "Kdo je Loiseau?", - { - "Pruský důstojník", - "Obchodník, typ pokrytce", - "Kuliččin otec", - "Kočí", - }, - 1, - "Loiseau je jedním z nejposměšnějších měšťanů.", - }, - { - "Proč maturita zahrnuje Kuličku?", - { - "Nejdelší román", - "Ukázka novely, ironie a společenské kritiky", - "Bez děje", - "Komiks", - }, - 1, - "Krátké dílo s velkým významem.", - }, - { - "Co je vlastenectví ve voze?", - { - "Upřímná oběť", - "Často rétorika maskující strach a sobectví", - "Nezmiňuje se", - "Pouze u Kuličky falešné", - }, - 1, - "Měšťané mluví o vlasti, ale chtějí jen uniknout.", - }, - { - "Které téma NENÍ středem?", - { - "Pokrytectví", - "Oběť prostitutky", - "Vesmírná kolonizace", - "Válka a okupace", - }, - 2, - "Novela je sociální satira 19. století.", - }, - { - "Jak vypravěč hodnotí Kuličku?", - { - "Objektivně s ironií vůči ostatním", - "Nenávidí ji", - "Je to Kulička", - "Bez postoje", - }, - 0, - "Er-forma odhaluje pokrytectví elity.", - }, - { - "Co Kulička přinese do vozu?", - { - "Jídlo – sendviče sdílené s jeptiškami", - "Zbraně", - "Pruskou uniformu", - "Nic", - }, - 0, - "Jídlo je detail ukazující její štědrost.", - }, - { - "Jak končí novela emocionálně?", - { - "Kulička slaví", - "Kulička pláče; ostatní jedí a posmívají se", - "Všichni se usmíří", - "Prusové vítězí", - }, - 1, - "Krutá pointa zvyšuje sociální kritiku.", - }, - { - "Kde poprvé vyšla Kulička?", - { - "Ve sbírce Večery na Médanu (1880)", - "V Lidových novinách 2000", - "V antice", - "V angličtině 1700", - }, - 0, - "Maupassant debutoval v této sbírce s Zolou.", - }, - { - "Co je naturalistický prvek?", - { - "Důraz na prostředí, třídu a determinaci chování", - "Magie", - "Bohové", - "Pouze humor", - }, - 0, - "Společenské postavení formuje jednání postav.", - }, - { - "Proč odmítá Kulička nejdřív důstojníka?", - { - "Vlastenecký postoj – nechce spát s okupantem", - "Nemá čas", - "Miluje Loiseaua", - "Je nemocná", - }, - 0, - "Její hrdost je silnější než u ostatních.", - }, - { - "Co měšťané dělají, když tlačí na Kuličku?", - { - "Modlí se s ní", - "Manipulují – morální nátlak pro vlastní prospěch", - "Platí jí", - "Jedou pěšky", - }, - 1, - "Hypocrisie vrcholí společným nátlakem.", - }, - { - "Jaký kontrast tvoří jádro novely?", - { - "Bohatí vs. chudí bez morálky", - "Prostitutka s ctností vs. „ctnostní“ měšťané bez morálky", - "Muži vs. ženy bez války", - "Prus vs. Francie bez lidí", - }, - 1, - "Obrácení etických rolí je klíčové.", - }, - { - "Kdo je Comtesse de Bréville?", - { - "Šlechtice ve voze", - "Kulička", - "Kočí", - "Pruská generálka", - }, - 0, - "Patří k elitě, která Kuličku opovrhuje.", - }, - { - "Co znamená oběť Kuličky?", - { - "Nic", - "Zachrání cestu ostatním, ale nikdo jí neděkuje", - "Zradí vlast", - "Získá titul", - }, - 1, - "Oběť je společensky neoceněná.", - }, - { - "Jak Maupassant ovlivnil prózu?", - { - "Krátká novela s pointou – vzor pro realismus", - "Vynalezl sci-fi", - "Psal jen poezii", - "Bez vlivu", - }, - 0, - "Kulička je učebnicový příklad novely.", - }, - { - "Jaké poselství novela nese?", - { - "Společenská morálka bývá pokrytecká", - "Prostituce je vždy špatná", - "Válka je dobrá", - "Elita je vždy spravedlivá", - }, - 0, - "Maupassant demaskuje falešné mravní kategorie.", - }, -}; - -static const AssemblyItem book_kulicka_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Měšťané a Kulička nastupují do vozu z Rouenu", - "Pruský důstojník zadrží odjezd", - "Kulička odmítá důstojníka; ostatní ji pohrdají", - "Hlad a strach rostou ve voze", - "Kulička obětuje se pro ostatní", - "Po odjezdu ji měšťané opět opovrhují a posmívají se", - }, - 6, - }, -}; - -static const char *book_kulicka_plot_meaning[] = { - "Správné pořadí: společná cesta → zadržení → pohrdání → nátlak → oběť → krutá pointa s pokrytectvím.", -}; - -static const LitQ book_kvety_zla_qs[] = { - { - "Kdo napsal Květy zla?", - { - "Verlaine", - "Charles Baudelaire", - "Rimbaud", - "Hugo", - }, - 1, - "Baudelaire vydal sbírku v roce 1857.", - }, - { - "Proč byla sbírka senzační i soudní?", - { - "Byla příliš krátká", - "Obvinění z nemravnosti a obscénnosti", - "Byla v latině", - "Nebyla publikována", - }, - 1, - "Soud přispěl k slávě sbírky.", - }, - { - "Co znamená „spleen“ u Baudelaira?", - { - "Radost", - "Melancholie, nuda, existenciální tíha", - "Hlad", - "Válka", - }, - 1, - "Spleen je klíčový motiv moderní duše.", - }, - { - "Jaký je vztah krásy a zla v titulu?", - { - "Zlo je ošklivé vždy", - "Krása může vyrůstat i z hříchu a temnoty", - "Titul nemá význam", - "Jde o zahradnictví", - }, - 1, - "Baudelaire estetizuje i temné stránky života.", - }, - { - "Kdo je flanér?", - { - "Voják", - "Pozorovatel města, chodec moderní metropole", - "Kněz", - "Král", - }, - 1, - "Flanér prochází Paříží a sbírá dojmy.", - }, - { - "Co symbolizuje báseň Albatros?", - { - "Sport", - "Umělce na souši – nemohoucího mimo svůj živel", - "Válku", - "Jídlo", - }, - 1, - "Albatros na palubě je groteskní; ve vzduchu krásný.", - }, - { - "Jaký žánr sbírka reprezentuje?", - { - "Epos", - "Moderní lyrická poezie / symbolism", - "Drama", - "Román", - }, - 1, - "Květy zla jsou vrchol francouzské moderny.", - }, - { - "Kde se básně nejčastěji odehrávají?", - { - "Venkov bez města", - "Moderní město, ulice, vnitřní svět", - "Vesmír", - "Středověký hrad", - }, - 1, - "Paříž a psychika jsou dvě scény.", - }, - { - "Co je synestézie v poezii?", - { - "Gramatická chyba", - "Propojení smyslů v obrazech", - "Rým bez významu", - "Proza", - }, - 1, - "Baudelaire slučuje barvy, vůně a zvuky.", - }, - { - "Proč maturita zahrnuje Květy zla?", - { - "Nejdelší román", - "Základ moderní poezie a symbolu", - "Bez významu", - "Jen historie", - }, - 1, - "Učí číst symbol a moderní lyriku.", - }, - { - "Jak Baudelaire vnímá ženu v cyklech?", - { - "Jen idealizace", - "Směs touhy, bolesti, hříchu a krásy", - "Bez zmínky", - "Pouze matka", - }, - 1, - "Ženské figury jsou složité symboly.", - }, - { - "Co je démonismus?", - { - "Náboženská oslava", - "Přitažlivost zla a temných sil", - "Věda", - "Sport", - }, - 1, - "Baudelaire zkoumá pokušení a hřích.", - }, - { - "Který básník patří ke stejné tradici?", - { - "Homér", - "Verlaine, Mallarmé (symbolisté)", - "Hašek", - "Rais", - }, - 1, - "Baudelaire předchází francouzský symbolism.", - }, - { - "Co znamená cyklus ve sbírce?", - { - "Náhodný soubor", - "Tematicky spojené básně (Spleen, Víno…)", - "Jeden epos", - "Drama", - }, - 1, - "Sbírka má vnitřní strukturu.", - }, - { - "Jaký je vztah k náboženství?", - { - "Jednoduchá víra", - "Pochybnost, konflikt víry a hříchu", - "Bez tématu", - "Pouze modlitby", - }, - 1, - "Moderní krize víry prostupuje lyrikou.", - }, - { - "Které téma NENÍ typické?", - { - "Spleen", - "Město", - "Vesmírné operace", - "Smyslnost", - }, - 2, - "Baudelaire píše o moderním člověku, ne sci-fi.", - }, - { - "Co je „krása v modernitě“?", - { - "Jen antické ideály", - "Hledání estetického i v odpudivém a obyčejném", - "Odmítání umění", - "Pouze příroda", - }, - 1, - "Baudelaire reformuluje estetiku 19. století.", - }, - { - "Jak sbírka ovlivnila Evropu?", - { - "Vůbec", - "Vzor pro symbolismus a moderní poezii", - "Zakázala poezii", - "Jen Francii bez vlivu", - }, - 1, - "Vliv na Mallarmého, Verlaine, i českou modernu.", - }, - { - "Co je báseň Holka s košíkem?", - { - "Politický manifest", - "Obraz mladé dělnice – krása v prostém", - "Epos", - "Vtip", - }, - 1, - "Typický baudelaireovský obraz moderního města.", - }, - { - "Jaký jazyk básně používají?", - { - "Pouze archaismy", - "Hutné obrazy, rytmus, symbol", - "Úřední styl", - "Bez metafor", - }, - 1, - "Jazyk je koncentrovaný a obrazný.", - }, - { - "Proč „květy“ a „zlo“ v titulu?", - { - "Paradox krásy v hříchu a temnotě", - "Zahradnický katalog", - "Náhodný název", - "Jméno postavy", - }, - 0, - "Titul shrnuje estetiku sbírky.", - }, - { - "Kdy Baudelaire žil?", - { - "1821–1867", - "1900–1950", - "1600–1650", - "1990–2020", - }, - 0, - "Patří k druhé polovině 19. století.", - }, - { - "Co čtenář cítí u motivu smrti?", - { - "Nic", - "Tíhu, tajemství, někdy i krásu", - "Pouze smích", - "Sport", - }, - 1, - "Smrt je častý lyrický motiv.", - }, - { - "Jak číst symbol ve sbírce?", - { - "Jen doslovně", - "Obraz má víc vrstev (city, společnost, víra)", - "Ignorovat", - "Jako matematiku", - }, - 1, - "Symbolismus vyžaduje interpretaci.", - }, - { - "Co je moderní metropole pro Baudelaira?", - { - "Ráj", - "Prostor anonymity, vzrušení i spleenu", - "Venkov", - "Klášter", - }, - 1, - "Město formuje moderní vnímání.", - }, - { - "Jaký vztah má sbírka k umění?", - { - "Umění není téma", - "Básně o tvorbě, umělci, albatrosovi", - "Jen malířství bez poezie", - "Zákaz umění", - }, - 1, - "Reflexe umění je součástí cyklu.", - }, - { - "Proč byl soud důležitý?", - { - "Zničil básníka", - "Přitáhl pozornost k nové estetice", - "Bez efektu", - "Vynesl trest smrti", - }, - 1, - "Skandál pomohl prosadit moderní poezii.", - }, - { - "Co NENÍ charakteristika Květů zla?", - { - "Symbol", - "Spleen", - "Realistický venkovský román bez poezie", - "Město", - }, - 2, - "Jde o lyrickou sbírku, ne prózu.", - }, - { - "Jak Baudelaire pracuje s vínem?", - { - "Cyklus Víno – únik, inspirace, iluze", - "Nezmiňuje", - "Pouze reklama", - "Jako jediné téma", - }, - 0, - "Víno je symbol i v cyklech sbírky.", - }, - { - "Jaké poselství sbírka má pro čtenáře?", - { - "Moderní člověk prožívá krásu i temnotu současně", - "Poezie je zbytečná", - "Vraťte se do středověku", - "Jen morální poučka", - }, - 0, - "Květy zla otevírají moderní vnímání světa.", - }, -}; - -static const AssemblyItem book_kvety_zla_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Baudelaire sbírá básně moderního města a duše", - "Vydání 1857 a skandál soudní", - "Cyklus Spleen vyjadřuje melancholii", - "Obrazy žen, umění a démonismu", - "Symbol krásy v temnotě (Květy zla)", - "Trvalý vliv na symbolismus a moderní poezii", - }, - 6, - }, -}; - -static const char *book_kvety_zla_plot_meaning[] = { - "Správné pořadí: tvorba sbírky → skandál → spleen a cykly → témata → estetika titulu → literární odkaz.", -}; - -static const LitQ book_kytice_qs[] = { - { - "Kdo sestavil Kytici?", - { - "Neruda", - "Karel Jaromír Erben", - "Nezval", - "Vrchlický", - }, - 1, - "Erben vydal sbírku balad v polovině 19. století.", - }, - { - "Jaký žánr Kytice reprezentuje?", - { - "Román", - "Baladická sbírka", - "Drama", - "Encyklopedie", - }, - 1, - "Jednotlivé balady jsou samostatné příběhy.", - }, - { - "Co je typické pro baladu?", - { - "Dlouhý klidný popis", - "Dramatický děj, tragédie, morální poučka", - "Sci-fi", - "Bez rýmu", - }, - 1, - "Balada má napětí a často krutý konec.", - }, - { - "O čem je balada Vodník?", - { - "O rybáři bez děje", - "O vodníkovi, který bere lidi do vody", - "O válce", - "O Praze", - }, - 1, - "Vodník je klasická postava lidové pověry.", - }, - { - "Co dělá Polednice?", - { - "Vaří oběd", - "Trestá děti, které jsou na poli v poledne", - "Učí v škole", - "Staví most", - }, - 1, - "Balada Polednice varuje před poledním horkem a neposlušností.", - }, - { - "Která balada obsahuje lišku Bystroušku?", - { - "Vrba", - "Svatební košile", - "Morana", - "Lilie", - }, - 1, - "Liška pomáhá proti vodníkovi v této baladě.", - }, - { - "Co je morální poučka?", - { - "Závěrečné poučení pro čtenáře", - "Titul knihy", - "Jméno postavy", - "Refrén bez smyslu", - }, - 0, - "Erben často uzavírá baladu poučkou.", - }, - { - "Proč Erben upravoval lidové pověsti?", - { - "Náhodně", - "Sjednotil je poeticky a morálně pro sbírku", - "Z ničil", - "Přeložil z angličtiny", - }, - 1, - "Erben je umělecky přetvořil, ne jen zapsal.", - }, - { - "Jaký verš je typický?", - { - "Slavný verš s rytmem a refrénem", - "Proza", - "Blank verse anglicky", - "Bez verše", - }, - 0, - "Hudebnost jazyka je charakteristická.", - }, - { - "O čem je balada Vrba?", - { - "O matce a dětech u vrbového proutí", - "O králi", - "O vesmíru", - "O sportu", - }, - 0, - "Vrba je známá refrénovitá balada o rodině.", - }, - { - "Kdy vyšla Kytice poprvé v podstatě v dnešní podobě?", - { - "1853", - "2000", - "1700", - "1920", - }, - 0, - "Druhé vydání 1853 obsahuje většinu balad.", - }, - { - "Jaký literární směr Erben reprezentuje?", - { - "Realismus bez romantismu", - "Romantismus a národní obrození", - "Sci-fi", - "Postmoderna", - }, - 1, - "Erben navazuje na lidovou tradici v romantické poezii.", - }, - { - "Co je nadpřirozeno v Kytici?", - { - "Nic", - "Vodníci, polednice, kouzla, smrt personifikovaná", - "Jen technologie", - "Vesmír", - }, - 1, - "Lidová víra prostupuje baladami.", - }, - { - "Proč maturita zahrnuje Kytici?", - { - "Nejdelší román", - "Základ české balady a lidové tradice", - "Bez významu", - "Jen anglicky", - }, - 1, - "Učí baladu, verš a interpretaci lidových motivů.", - }, - { - "Co je balada Morana?", - { - "O jarní bohyni smrti/zimy", - "O autu", - "O Praze", - "O škole", - }, - 0, - "Morana je personifikace konce zimy / smrti.", - }, - { - "Jak Erben pracuje s přírodou?", - { - "Ignoruje", - "Příroda je živá, symbolická, někdy hrozící", - "Jen město", - "Bez obrazů", - }, - 1, - "Krajina je součástí děsu i krásy.", - }, - { - "Které téma se opakuje?", - { - "Vina a trest", - "Vesmírné lety", - "Politika 21. století", - "Sport", - }, - 0, - "Porušení zákazu často vede k tragédii.", - }, - { - "Co je balada Lilie?", - { - "Milostná idyla bez smrti", - "Příběh s motivem hřbitova a mrtvých", - "Komická hra", - "Epos", - }, - 1, - "Lilie patří k temnějším baladám sbírky.", - }, - { - "Kdo je Erben mimo Kytice?", - { - "Sběratel lidových písní, historik, publicista", - "Jen malíř", - "Politik bez literatury", - "Cizinec", - }, - 0, - "Erben byl významná osobnost obrození.", - }, - { - "Jaký kontrast tvoří Svatební košile?", - { - "Vodník vs. chytrá liška", - "Bohatí vs. chudí bez děje", - "Válka vs. mír", - "Praha vs. Brno", - }, - 0, - "Liška Bystrouška přechytračí vodníka.", - }, - { - "Co znamená refrén ve Vrbě?", - { - "Opakování zvyšuje napětí a hudebnost", - "Chyba tisku", - "Anglický text", - "Bez významu", - }, - 0, - "Refrén je součást baladické formy.", - }, - { - "Který prvek NENÍ typický?", - { - "Tragický konec", - "Poučka", - "Vesmírná opera", - "Nadpřirozeno", - }, - 2, - "Kytice je lidová a krajinná poezie.", - }, - { - "Jak číst baladu Zlatý kolovrat?", - { - "Jako pohádku bez násilí", - "Tragický příběh s trestem za zločin", - "Sci-fi", - "Reportáž", - }, - 1, - "Balada obsahuje kruté motivy lidové pověsti.", - }, - { - "Co spojuje Kytici s národním obrozením?", - { - "Cizí jazyk", - "České motivy, identita, lidová tradice", - "Bez národního významu", - "Pouze němčina", - }, - 1, - "Sbírka je kulturním symbolem národa.", - }, - { - "Jak Erben uzavírá balady?", - { - "Bez závěru", - "Morální poučkou nebo pointou", - "Reklamou", - "Anglicky", - }, - 1, - "Poučka vysvětluje etický význam.", - }, - { - "Co je balada Holoubek?", - { - "Milostná píseň s tragickým rozměrem", - "Učebnice", - "Román", - "Fejeton", - }, - 0, - "Holoubek patří k známým baladám Kytice.", - }, - { - "Jaký vztah má dítě k dospělým v baladách?", - { - "Vždy poslušné bez děje", - "Neposlušnost často vede k trestu", - "Bez dětí", - "Jen komedie", - }, - 1, - "Varování rodičům a dětem je časté.", - }, - { - "Proč jsou balady stále živé?", - { - "Univerzální motivy strachu, viny, lásky", - "Zastaralé", - "Nečitelné", - "Bez jazyka", - }, - 0, - "Erbenova forma je nadčasová.", - }, - { - "Co je slavný verš?", - { - "Rytmická forma vhodná pro recitaci a píseň", - "Prozaický odstavec", - "Anglický sonet", - "Bez rytmu", - }, - 0, - "Verš podporuje hudebnost Kytice.", - }, - { - "Jaké poselství Kytice často nese?", - { - "Respektuj zákony přírody a morálky, jinak hrozí trest", - "Vše je dovoleno", - "Pouze humor", - "Bez etiky", - }, - 0, - "Balady varují před pýchou, neposlušností a zlem.", - }, -}; - -static const AssemblyItem book_kytice_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Erben sbírá a upravuje lidové pověsti", - "Skládá balady do sbírky Kytice", - "Postavy poruší zákaz nebo pád do hříchu", - "Nadpřirozeno nebo osud trestá viníky", - "Tragický konec balady", - "Morální poučka pro čtenáře", - }, - 6, - }, -}; - -static const char *book_kytice_plot_meaning[] = { - "Správné pořadí: inspirace lidovou tradicí → sbírka → vina → trest → tragédie → poučka (typická struktura erbenovské balady).", -}; - -static const LitQ book_lakomec_qs[] = { - { - "Kdo napsal Lakomce?", - { - "Racine", - "Molière", - "Corneille", - "Hugo", - }, - 1, - "Molière uvedl hru v roce 1668.", - }, - { - "Jaký typ komedie to je?", - { - "Komedie charakterů", - "Tragedie", - "Opera", - "Epos", - }, - 0, - "Harapagon ztělesňuje extrémní lakotu.", - }, - { - "Kdo je Harapagon?", - { - "Král", - "Lakomý otec posedlý penězi", - "Voják", - "Kněz", - }, - 1, - "Titulní postava je synonymem pro lakotu.", - }, - { - "Co Harapagon nejvíc miluje?", - { - "Děti", - "Truhlu s penězi", - "Umění", - "Přírodu", - }, - 1, - "Peníze jsou nad rodinou i láskou.", - }, - { - "Koho miluje Elise?", - { - "Harapagona", - "Valéra", - "Cléanta", - "Marianu", - }, - 1, - "Valér je sluha, ale i milenec Elise.", - }, - { - "Koho miluje Cléante?", - { - "Frosinu", - "Marianu", - "Elise", - "Harapagona", - }, - 1, - "Syn chce sňatek s Marianou.", - }, - { - "Co Harapagon plánuje s Marianou?", - { - "Oženit se s ní sám", - "Poslat ji do kláštera", - "Prodat dům", - "Nic", - }, - 0, - "Starý lakomec chce mladou manželku.", - }, - { - "Kdo je Frosina?", - { - "Služka", - "Prostřednice sňatků využívající lakotu", - "Královna", - "Dcera", - }, - 1, - "Frosina manipuluje Harapagonem.", - }, - { - "Co se stane s truhlou?", - { - "Zmizí", - "Harapagon ji ztratí, pak ji najdou – vrchol komiky", - "Spálí ji", - "Dá ji chudým", - }, - 1, - "Scéna s ukradenou truhlou je slavná.", - }, - { - "Jak hra končí?", - { - "Tragedií", - "Happy endem – svatby, návrat peněz", - "Harapagon umírá", - "Válka", - }, - 1, - "Molièrovy komedie často končí smířením.", - }, - { - "Jaký je Valér?", - { - "Hloupý sluha", - "Chytrý, lstivý milenec Elise", - "Král v převleku", - "Harapagonův bratr", - }, - 1, - "Valér ovládá situaci v domě.", - }, - { - "Proč maturita zahrnuje Lakomce?", - { - "Nejdelší román", - "Klasická komedie, satira, drama", - "Bez děje", - "Sci-fi", - }, - 1, - "Učí strukturu komedie a charakterového typu.", - }, - { - "Kdy Molière žil?", - { - "17. století", - "19. století", - "Antika", - "21. století", - }, - 0, - "Molière působil za Ludvíka XIV.", - }, - { - "Co satira kritizuje?", - { - "Lakotu a měšťanské mravy", - "Vesmír", - "Sport", - "Pouze krále", - }, - 0, - "Harapagon je groteskní exemplum lakotce.", - }, - { - "Kolik aktů má hra?", - { - "Pět", - "Jeden", - "Deset", - "Dva", - }, - 0, - "Klasická pětaktová struktura.", - }, - { - "Které téma NENÍ středem?", - { - "Peníze vs. láska", - "Sňatky dětí", - "Vesmírná válka", - "Rodinný konflikt", - }, - 2, - "Hra je komedie o měšťanské domácnosti.", - }, - { - "Co Harapagon šetří?", - { - "Na vše – jídlo, svatbu, štěstí dětí", - "Nic", - "Jen na knihy", - "Jen na krále", - }, - 0, - "Lakota proniká celým životem.", - }, - { - "Jak funguje komedie charakterů?", - { - "Postava má jednu přehnanou vlastnost", - "Bez postav", - "Jen akce", - "Tragedie", - }, - 0, - "Harapagon = lakota v extrému.", - }, - { - "Kdo ukradne truhlu (v ději)?", - { - "Harapagon sám ji „ztratí“ – komplikovaná intrika", - "Král", - "Marianna", - "Nikdo", - }, - 0, - "Ztráta pokladu vyvolá groteskní scénu.", - }, - { - "Jaký jazyk hra používá?", - { - "Rýmovaná próza (veršovaná próza)", - "Pouze proza", - "Latin", - "Bez textu", - }, - 0, - "Molière používá alexandríny v próze.", - }, - { - "Co chtějí děti od otce?", - { - "Pouze peníze", - "Svolení ke sňatkům z lásky", - "Vypovězení", - "Trůn", - }, - 1, - "Generační konflikt je motor děje.", - }, - { - "Kdo je Anselme na konci?", - { - "Postava odhalená jako Valérova rodina – řeší sňatky", - "Vrah", - "Cizinec bez role", - "Harapagon", - }, - 0, - "Zápletky se rozuzlí identitou Anselma.", - }, - { - "Proč je Lakomec stále populární?", - { - "Univerzální humor a typ lakotce", - "Zastaralý", - "Bez humoru", - "Jen ve Francii", - }, - 0, - "Chamtivost je věčné téma.", - }, - { - "Jak Molière pracuje s happy endem?", - { - "Vše se vyřeší sňatky a smířením", - "Všichni umřou", - "Bez závěru", - "Válka", - }, - 0, - "Klasická komická katarze.", - }, - { - "Co je matchmaker Frosina?", - { - "Prostřednice sňatků", - "Voják", - "Lakomec", - "Král", - }, - 0, - "Využívá Harapagonovy touhy.", - }, - { - "Jaký kontrast tvoří jádro hry?", - { - "Láska mladých vs. lakota starého otce", - "Moře vs. hory", - "Válka vs. mír bez rodiny", - "Praha vs. Brno", - }, - 0, - "Peníze vs. city je hlavní osa.", - }, - { - "Kde se děj odehrává?", - { - "Paříž, měšťanský dům", - "Venkov bez domu", - "Londýn", - "Praha", - }, - 0, - "Měšťanské prostředí 17. století.", - }, - { - "Co Harapagon odmítá platit?", - { - "Vše možné – i sluhy, hostinu, svatbu", - "Nic", - "Jen daně", - "Jen králi", - }, - 0, - "Šetří na každém kroku.", - }, - { - "Jaké poselství hra nese?", - { - "Lakota ničí rodinu i štěstí", - "Šetři vždy", - "Peníze jsou vše", - "Bez morálky", - }, - 0, - "Satira varuje před extrémní chamtivostí.", - }, -}; - -static const AssemblyItem book_lakomec_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Harapagon vládne domu lakotou", - "Děti chtějí sňatky z lásky", - "Harapagon touží po Marianně a penězích", - "Ztráta truhly a komické pátrání", - "Odhalení identit a intrik (Valér, Anselme)", - "Happy end – svatby a smíření", - }, - 6, - }, -}; - -static const char *book_lakomec_plot_meaning[] = { - "Správné pořadí: lakota otce → konflikt s dětmi → Harapagon a Marianna → truhla → rozuzlení → svatby.", -}; - -static const LitQ book_lolita_qs[] = { - { - "Kdo napsal Lolitu?", - { - "Kafka", - "Vladimir Nabokov", - "Orwell", - "Hemingway", - }, - 1, - "Nabokov román dokončil v americkém exilu.", - }, - { - "Kdo vypráví příběh?", - { - "Lolita", - "Humbert Humbert", - "Quilty", - "Charlotte", - }, - 1, - "Humbert píše svou verzi pro soudní proces.", - }, - { - "Jak se jmenuje dívka a její přezdívka?", - { - "Dolores Haze – Lolita", - "Jane Eyre", - "Maria", - "Anna Karenina", - }, - 0, - "Lolita je Humbertova přezdívka pro Dolores.", - }, - { - "Kde Humbert poprvé potká Lolitu?", - { - "V Ramsdale u Hazových", - "V Paříži", - "V Rusku", - "V Londýně", - }, - 0, - "Humbert bydlí u rodiny Haze.", - }, - { - "Co udělá Humbert s Charlotte?", - { - "Ožení se s ní, aby byl blízko Lolité", - "Zabije ji hned", - "Ignoruje", - "Prodá dům", - }, - 0, - "Sňatek je součást manipulace.", - }, - { - "Jak Charlotte umírá?", - { - "Autonehoda po odhalení Humbertových dopisů", - "Stářím", - "Válka", - "Quilty", - }, - 0, - "Charlotte běží před autem po bouřce.", - }, - { - "Kdo je Clare Quilty?", - { - "Policista", - "Spisovatel, stínový rival, únosce", - "Lolitin otec", - "Humbertův bratr", - }, - 1, - "Quilty pronásleduje pár a Lolitu si vezme.", - }, - { - "Jaký je vztah Humbert–Lolita?", - { - "Rovnocenná láska", - "Manipulace dospělého a oběť", - "Otcovský bez problému", - "Sourozenci", - }, - 1, - "Román demaskuje Humbertovu rétoriku.", - }, - { - "Proč je Humbert nespolehlivý vypravěč?", - { - "Lže a estetizuje zločin", - "Mluví pravdu vždy", - "Nemluví", - "Je dítě", - }, - 0, - "Čtenář musí číst proti vypravěči.", - }, - { - "Jak končí Lolita?", - { - "Šťastně s Humbertem", - "Dolores umírá po těžkém životě; Humbert zabije Quiltyho", - "Quilty vyhrává svatbou", - "Všichni se smíří", - }, - 1, - "Tragický konec oběti i vypravěče.", - }, - { - "Kdy román vyšel?", - { - "1955", - "1847", - "2000", - "1914", - }, - 0, - "První vydání v Paříži u Olympia Press.", - }, - { - "Jaký žánr román reprezentuje?", - { - "Moderní/controverzní román, road novel", - "Pohádka", - "Epos", - "Učebnice", - }, - 0, - "Spojuje cestu, psychologii a jazykovou hru.", - }, - { - "Co je Annabel Leigh?", - { - "Humbertova dětská láska (aluzce na Poe)", - "Lolitiná sestra", - "Quiltyho manželka", - "Auto", - }, - 0, - "Motiv ztracené dětské lásky vysvětluje obsesi.", - }, - { - "Proč maturita zahrnuje Lolitu?", - { - "Bez kontroverze", - "Moderní próza, vypravěč, etika čtení", - "Nejkratší", - "Jen humor", - }, - 1, - "Učí kriticky číst nespolehlivého vypravěče.", - }, - { - "Které téma je středem?", - { - "Manipulace a moc", - "Vesmírná válka", - "Venkovský realismus", - "Antická tragédie", - }, - 0, - "Děj staví na Humbertově kontrole nad dívkou.", - }, - { - "Jak Nabokov pracuje s jazykem?", - { - "Chudý styl", - "Bohatý, hříčkový, anglicky s wordplay", - "Bez stylu", - "Pouze česky", - }, - 1, - "Jazyk je součást estetiky i ironie.", - }, - { - "Co NENÍ typické?", - { - "Cesty po USA", - "Skandální téma", - "Středověký rytíř", - "Quilty", - }, - 2, - "Děj je moderní americký.", - }, - { - "Kdo je Rita?", - { - "Žena po Lolité na cestách", - "Lolita", - "Soudkyně", - "Učitelka", - }, - 0, - "Humbert s Ritou cestuje po ztrátě Lolity.", - }, - { - "Jak číst román eticky?", - { - "Oslavovat Humberta", - "Vidět oběť a demaskovat vypravěčovu rétoriku", - "Ignorovat Lolitu", - "Jen disney", - }, - 1, - "Interpretace zdůrazňuje Dolores, ne romantizaci.", - }, - { - "Co Humbert dělá Quiltymu na konci?", - { - "Odpustí", - "Zastřelí ho", - "Ožení se s ním", - "Ignoruje", - }, - 1, - "Vrchní scéna je groteskní konfrontace.", - }, - { - "Jaký film režíroval Kubrick?", - { - "Lolita (1962)", - "1984", - "Barry Lyndon", - "Shining", - }, - 0, - "Kubrick natočil adaptaci v roce 1962.", - }, - { - "Co je road novel struktura?", - { - "Cesty autem po Americe", - "Jen jeden dům", - "Vesmír", - "Antika", - }, - 0, - "Motel, silnice, útěk před společností.", - }, - { - "Proč byl román cenzurován?", - { - "Obsah pedofilie a morální kontroverze", - "Příliš krátký", - "Bez jazyka", - "V latině", - }, - 0, - "Mnoho zemí knihu zpočátku odmítlo.", - }, - { - "Kdo je obětí v interpretaci?", - { - "Humbert", - "Dolores Haze", - "Quilty", - "Charlotte", - }, - 1, - "Moderní čtení zdůrazňuje Lolitu jako oběť.", - }, - { - "Co je intertext u Nabokova?", - { - "Reference na Poe, literaturu", - "Bez referencí", - "Jen Bible", - "Sport", - }, - 0, - "Annabel Leigh odkazuje na Poeovu báseň.", - }, - { - "Jak Humbert ospravedlňuje činy?", - { - "Krásnou řečí a literárními aluzemi", - "Přiznáním viny bez slov", - "Mlčením", - "Bez slov", - }, - 0, - "Rétorika je součástí manipulace.", - }, - { - "Kde Humbert končí?", - { - "Ve vězení, píše deník", - "Na trůně", - "V exilu bohatý", - "U Lolity šťastný", - }, - 0, - "Vyprávění je z vězení před soudem.", - }, - { - "Jaký kontrast Nabokov vytváří?", - { - "Krásný jazyk vs. morálně otřesný obsah", - "Bez kontrastu", - "Jen humor", - "Jen válka", - }, - 0, - "Estetika vs. etika je klíč interpretace.", - }, - { - "Co Dolores dělá po útěku od Humberta?", - { - "Žije s Quiltym, později těžký osud, manžel Dick", - "Stane se královnou", - "Vraždí", - "Nic", - }, - 0, - "Lolitain dospělý osud je tragický.", - }, - { - "Jaké poselství lze vyčíst při kritickém čtení?", - { - "Glorifikace zločinu", - "Varování před manipulací a nespolehlivým vypravěčem", - "Bez významu", - "Oslava dětství", - }, - 1, - "Román je literární, ne morální apologie Humberta.", - }, -}; - -static const AssemblyItem book_lolita_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Humbert přijde do Ramsdale k Hazovým", - "Sňatek s Charlotte; Lolita v jeho moci", - "Charlotteina smrt; cesty s Lolitou", - "Quilty Lolitu odvede", - "Humbert hledá Lolitu; najde ji těhotnou a chudou", - "Zabije Quiltyho; píše deník ve vězení", - }, - 6, - }, -}; - -static const char *book_lolita_plot_meaning[] = { - "Správné pořadí: Ramsdale → Charlotte → cesty → Quilty → setkání s Dolores → Quiltyho smrt a deník.", -}; - -static const LitQ book_maj_qs[] = { - { - "Kdo napsal Máj?", - { - "Erben", - "Karel Hynek Mácha", - "Neruda", - "Vrchlický", - }, - 1, - "Mácha dokončil skladbu krátce před smrtí v roce 1836.", - }, - { - "Jaký žánr Máj reprezentuje?", - { - "Realistický román", - "Lyricko-epická romantická skladba", - "Drama", - "Encyklopedie", - }, - 1, - "Máj je básnické dílo s dějem i lyrickými částmi.", - }, - { - "Kdo je Vilém?", - { - "Král", - "Vězeň, milenec Jarmily, zabil jejího otce", - "Hajný", - "Vandrák", - }, - 1, - "Vilém je hlavní postava tragického děje.", - }, - { - "Co udělá Jarmila?", - { - "Utíká s Vilémem", - "Utopí se v jezeře", - "Zabije Viléma", - "Stane se královnou", - }, - 1, - "Jarmila volí smrt po Vilémově zločinu.", - }, - { - "Proč Vilém zabil hajného?", - { - "V afektu – otec Jarmily bránil lásce", - "Pro peníze", - "Na rozkaz", - "Náhodou bez důvodu", - }, - 0, - "Vilém reaguje na konflikt s otcem milenky.", - }, - { - "Jak Vilém končí?", - { - "Svatba", - "Poprava (šibenice)", - "Exil", - "Trůn", - }, - 1, - "Trest za vraždu je poprava.", - }, - { - "Kdo je vandrák?", - { - "Putující postava s lyrickými komentáři", - "Vilém po útěku", - "Hajný", - "Bůh", - }, - 0, - "Vandrák propojuje osudy a přírodu.", - }, - { - "Co symbolizuje máj?", - { - "Jen měsíc", - "Jaro, láska, krása, ale i smrt a osud", - "Válka", - "Město", - }, - 1, - "Titulní symbol prostupuje skladbou.", - }, - { - "Jak příroda reaguje na zločin?", - { - "Ignoruje", - "Bouře, hrom, personifikace", - "Slunce bez změny", - "Jen sníh", - }, - 1, - "Romantická personifikace krajiny.", - }, - { - "Kdy Máj vyšel?", - { - "1836", - "1850", - "2000", - "1700", - }, - 0, - "Posmrtné vydání téhož roku jako Máchaova smrt.", - }, - { - "Jaký směr Mácha reprezentuje?", - { - "Realismus", - "Romantismus", - "Naturalismus", - "Postmoderna", - }, - 1, - "Máj je vrchol českého romantismu.", - }, - { - "Co je intercalare?", - { - "Lyrická vložka ve skladbě", - "Postava", - "Kapitola románu", - "Refrén bez smyslu", - }, - 0, - "Vložky vězeň, vandrák přerušují děj.", - }, - { - "Kde se děj částečně odehrává?", - { - "Krajina kolem Doksy a jezera", - "Praha bez přírody", - "Moře", - "Vesmír", - }, - 0, - "Mácha inspirován krajinou Máchova jezera.", - }, - { - "Proč maturita zahrnuje Máj?", - { - "Nejdelší román", - "Základ českého romantismu a verše", - "Bez významu", - "Proza", - }, - 1, - "Učí skladbu, symbol a romantické motivy.", - }, - { - "Které téma je středem?", - { - "Láska, vina, trest, smrt", - "Sport", - "Politika 21. stol.", - "Vesmír", - }, - 0, - "Tragický milostný příběh s trestem.", - }, - { - "Kdo je hajný?", - { - "Otec Jarmily, oběť Viléma", - "Vilém", - "Vandrák", - "Král", - }, - 0, - "Hajný brání vztahu dcery s Vilémem.", - }, - { - "Jak Mácha pracuje s jazykem?", - { - "Hudební verš, obrazy, personifikace", - "Úřední styl", - "Proza", - "Anglicky", - }, - 0, - "Skladba je známá rytmem a obrazností.", - }, - { - "Co je lyricko-epická skladba?", - { - "Spojení epického děje a lyrických pasáží", - "Jen epos", - "Jen epigram", - "Drama", - }, - 0, - "Máj má děj i lyrické monology.", - }, - { - "Který prvek NENÍ typický?", - { - "Příroda", - "Osud", - "Sci-fi vesmír", - "Vina", - }, - 2, - "Máj je romantická krajina a cit.", - }, - { - "Jak končí Jarmila?", - { - "Šťastně", - "Smrt v jezeře", - "Svatba s hajným", - "Exil", - }, - 1, - "Tragický konec milenky.", - }, - { - "Co vězeň ve vězení dělá?", - { - "Lyrické úvahy o osudu", - "Sport", - "Vládne", - "Vaří", - }, - 0, - "Vilém jako vězeň medituje nad životem.", - }, - { - "Jaký vliv má Máj na českou literaturu?", - { - "Ikona romantismu", - "Bez vlivu", - "Jen pro děti", - "Zakázaný", - }, - 0, - "Nejznámější česká báseň.", - }, - { - "Co je sbor jeskyň?", - { - "Personifikovaná příroda", - "Divadlo", - "Armáda", - "Město", - }, - 0, - "Romantický obraz přírody.", - }, - { - "Kdy Mácha zemřel?", - { - "1836 (mladý)", - "1900", - "1950", - "2000", - }, - 0, - "Mácha zemřel velmi mladý.", - }, - { - "Jaký kontrast tvoří skladba?", - { - "Krása máje vs. smrt a trest", - "Humor vs. humor", - "Město vs. město", - "Bez kontrastu", - }, - 0, - "Láska a krása kontrastují s vraždou a šibenicí.", - }, - { - "Co je romantický osud?", - { - "Postavy nemohou uniknout následkům činů", - "Happy end vždy", - "Bez děje", - "Komický", - }, - 0, - "Vilém platí za zločin.", - }, - { - "Jak číst personifikaci?", - { - "Příroda odráží city a morálku", - "Bez významu", - "Jen věda", - "Sport", - }, - 0, - "Krajina je účastníkem děje.", - }, - { - "Která postava NENÍ v Máji?", - { - "Vilém", - "Jarmila", - "Harapagon", - "Vandrák", - }, - 2, - "Harapagon je Molière.", - }, - { - "Jaké poselství skladba nese?", - { - "Láska a krása jsou křehké; vina má cenu", - "Vražda bez následků", - "Pouze humor", - "Bez etiky", - }, - 0, - "Romantická tragédie varuje před násilím.", - }, -}; - -static const AssemblyItem book_maj_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Vilém miluje Jarmilu; konflikt s hajným", - "Vilém zabije hajného", - "Jarmila se utopí v jezeře", - "Vilém je chycen a ve vězení", - "Poprava na šibenici", - "Vandrák a příroda uzavírají meditaci nad osudem", - }, - 6, - }, -}; - -static const char *book_maj_plot_meaning[] = { - "Správné pořadí: láska a konflikt → vražda → Jarmilina smrt → vězení → poprava → lyrický epilog vandrat a přírody.", -}; - -static const LitQ book_maly_princ_qs[] = { - { - "Kdo napsal Malého prince?", - { - "Camus", - "Saint-Exupéry", - "Sartre", - "Proust", - }, - 1, - "Saint-Exupéry knihu napsal v exilu v USA.", - }, - { - "Kdo vypráví příběh?", - { - "Malý princ sám bez dospělého", - "Pilot havarovaný v poušti", - "Liška", - "Král", - }, - 1, - "Pilot vzpomíná na setkání s princem.", - }, - { - "Odkud Malý princ pochází?", - { - "Z Paříže", - "Z asteroidu B-612", - "Z Marsu", - "Z Egypta", - }, - 1, - "Malá planetka s růží a sopkami.", - }, - { - "Co učí liška?", - { - "Letět", - "Ochočení a odpovědnost za vztah", - "Vařit", - "Válku", - }, - 1, - "Slavná scéna ochočení na Zemi.", - }, - { - "Co znamená „co je důležité, oči nevidí“?", - { - "Vidění je zbytečné", - "Podstata věcí je skrytá – láska, vztah", - "Jen fyzika", - "Bez významu", - }, - 1, - "Princ chápe po odchodu od lišky.", - }, - { - "Proč princ opustil růži?", - { - "Nerozuměl jí a chtěl poznat svět", - "Nenáviděl ji", - "Král nařídil", - "Bez důvodu", - }, - 0, - "Růže byla náročná; princ lituje později.", - }, - { - "Kdo je lampář?", - { - "Postava na planetce – absurdita dospělých povinností", - "Pilot", - "Had", - "Vlk", - }, - 0, - "Lampář zapíná a vypíná lampu – satira.", - }, - { - "Kdy kniha vyšla?", - { - "1943", - "1850", - "2000", - "1789", - }, - 0, - "Vydání během 2. světové války.", - }, - { - "Jaký žánr kniha reprezentuje?", - { - "Philosophická pohádka / alegorie", - "Detektivka", - "Epos", - "Učebnice", - }, - 0, - "Děti i dospělí čtou různé vrstvy.", - }, - { - "Co dělá had?", - { - "Pomáhá princi vrátit se (k odchodu)", - "Kouše pilota", - "Staví most", - "Učí matematiku", - }, - 0, - "Had symbolizuje návrat „domů“.", - }, - { - "Proč maturita zahrnuje Malého prince?", - { - "Nejdelší román", - "Alegorie, styl, filosofické otázky", - "Bez významu", - "Jen pro malé děti", - }, - 1, - "Učí číst symbol a satiru dospělých.", - }, - { - "Kdo ilustroval knihu?", - { - "Autor sám", - "Picasso", - "Bez obrázků", - "Dalí", - }, - 0, - "Saint-Exupéry kreslil prince.", - }, - { - "Co satirují planety?", - { - "Dospělé profese a marnost moci", - "Pouze děti", - "Sport", - "Vesmír bez smyslu", - }, - 0, - "Král, domýšlivec, pijan atd.", - }, - { - "Které téma NENÍ středem?", - { - "Přátelství a smysl", - "Odpovědnost", - "Vesmírná válka flotil", - "Láska k růži", - }, - 2, - "Kniha není sci-fi o válkách.", - }, - { - "Kde se pilot a princ setkají?", - { - "V poušti po havárii", - "V Paříži", - "Na lodi", - "V lese", - }, - 0, - "Sahara je místo setkání.", - }, - { - "Co je odpovědnost za růži?", - { - "Péče o to, co jsme si vybrali milovat", - "Zahodit růži", - "Ignorovat", - "Prodat", - }, - 0, - "Princ pochopí až po lišce.", - }, - { - "Jak autor zemřel?", - { - "Za 2. sv. války jako pilot", - "Stářím 2000", - "V poušti knihou", - "Neznámo", - }, - 0, - "Saint-Exupéry zmizel při letu 1944.", - }, - { - "Co je geograf?", - { - "Zapisuje řeky, ale nevidí svět", - "Pilot", - "Princ", - "Had", - }, - 0, - "Další typ dospělého bez zkušenosti.", - }, - { - "Jak končí princ?", - { - "Odchází (had); tělo zmizí, pilot smutní", - "Zůstává s pilotem navždy", - "Stává se králem", - "Vládne Zemi", - }, - 0, - "Závěr je tajemný a smutný.", - }, - { - "Proč je kniha pro dospělé?", - { - "Alegorie smyslu života", - "Pouze obrázky", - "Bez textu", - "Jen strach", - }, - 0, - "Filosofické otázky pod povrchem pohádky.", - }, - { - "Co je domýšlivec?", - { - "Postava toužící po obdivu", - "Liška", - "Růže", - "Pilot", - }, - 0, - "Satira marnivosti.", - }, - { - "Jaký jazyk kniha používá?", - { - "Jednoduchý, poetický, dialogy", - "Úřední", - "Bez dialogů", - "Latin", - }, - 0, - "Přístupné dětem i hluboké.", - }, - { - "Co pilot kreslí?", - { - "Boa constrictor a beránek (had a krabička)", - "Auto", - "Mapu", - "Nic", - }, - 0, - "Začátek knihy – kresba beránka v krabici.", - }, - { - "Kdo je král?", - { - "Vládne všemu, ale sám na planetě", - "Princ", - "Liška", - "Had", - }, - 0, - "Absurdita moci bez poddaných.", - }, - { - "Jaký symbol je růže?", - { - "Láska, křehkost, odpovědnost", - "Válka", - "Peníze", - "Sport", - }, - 0, - "Princ se učí milovat a pečovat.", - }, - { - "Co znamená B-612?", - { - "Číslo asteroidu prince", - "Letadlo", - "Kód války", - "Město", - }, - 0, - "Malá planeta je domovem.", - }, - { - "Jak číst satiru dospělých?", - { - "Kritika prázdných rolí a zapomínání na podstatu", - "Oslava moci", - "Bez významu", - "Jen děti", - }, - 0, - "Princ vidí svět očima dítěte.", - }, - { - "Proč je liška důležitá?", - { - "Učí vztah a jedinečnost", - "Zabíjí prince", - "Bez role", - "Pilot", - }, - 0, - "Klíčová scéna ochočení.", - }, - { - "Jaké poselství kniha nese?", - { - "Hledej smysl, pečuj o vztazích, nejeď jen na vzhled", - "Moc je vše", - "Dospělí jsou vždy moudří", - "Bez morálky", - }, - 0, - "Pohádka pro reflexi života.", - }, -}; - -static const AssemblyItem book_maly_princ_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Pilot havaruje v poušti", - "Setkání s Malým princem z B-612", - "Princ vypráví o růži a cestách mezi planetami", - "Na Zemi potká lišku a pochopí ochočení", - "Návrat k pilotovi; odpovědnost za růži", - "Princ odchází s hadem; pilot postrádá přítele", - }, - 6, - }, -}; - -static const char *book_maly_princ_plot_meaning[] = { - "Správné pořadí: havárie → setkání → planety a růže → liška → poušť → odchod prince.", -}; - -static const LitQ book_marysa_qs[] = { - { - "Kdo napsal Maryšu?", - { - "Čapek", - "Alois a Vilém Mrštíkové", - "Nemcová", - "Hašek", - }, - 1, - "Bratři Mrštíkové uvedli hru v roce 1894.", - }, - { - "Jaký žánr Maryša reprezentuje?", - { - "Realistické drama", - "Opera", - "Epos", - "Sci-fi", - }, - 0, - "Hra je dialogová venkovská tragédie.", - }, - { - "Kdo je Maryša?", - { - "Mladá vdova na venkově", - "Královna", - "Učitelka", - "Voják", - }, - 0, - "Titulní hrdinka je v konfliktu s okolím.", - }, - { - "Koho miluje Maryša?", - { - "Vávru", - "Filipa", - "Metoděje", - "Tchyni", - }, - 1, - "Filip je její milenec.", - }, - { - "Kdo chce Maryšu za ženu?", - { - "Filip", - "Vávra – bohatý sedlák", - "Kněz", - "Soudce", - }, - 1, - "Vávra touží po ní i po statku.", - }, - { - "Kdo Maryšu nejvíc týrá?", - { - "Filip", - "Tchyně", - "Metoděj", - "Vesnice bez nikoho", - }, - 1, - "Tchyně je krutá a panovačná.", - }, - { - "Co je středem konfliktu?", - { - "Válka", - "Láska, majetek, pomluvy, soud", - "Vesmír", - "Sport", - }, - 1, - "Venkovský sociální drama.", - }, - { - "Kde se děj odehrává?", - { - "Moravský venkov", - "Praha", - "Moře", - "Paříž", - }, - 0, - "Prostředí hospody a dvora.", - }, - { - "Jak hra končí?", - { - "Happy end svatbou", - "Tragicky – Maryša je zničena procesem a okolím", - "Vávra vítězí šťastně", - "Filip král", - }, - 1, - "Oběť prohrává s pomluvami a systémem.", - }, - { - "Kdo je Metoděj?", - { - "Kněz", - "Sedlák Vávra", - "Soudce", - "Tchyně", - }, - 0, - "Kněz reprezentuje morální rovinu.", - }, - { - "Proč maturita zahrnuje Maryšu?", - { - "Nejdelší román", - "České realistické drama a venkov", - "Bez děje", - "Komiks", - }, - 1, - "Učí drama, dialog a sociální kontext.", - }, - { - "Co je venkovská mluva?", - { - "Autentické dialogy moravského venkova", - "Anglicky", - "Bez dialogů", - "Latin", - }, - 0, - "Mrštíkové pracují s nářečím.", - }, - { - "Které téma NENÍ středem?", - { - "Vdovství", - "Pomluva", - "Vesmírná flotila", - "Majetek", - }, - 2, - "Hra je realistická venkovská.", - }, - { - "Co Vávra představuje?", - { - "Chudobu", - "Bohatství a tlak na sňatek", - "Kněze", - "Dítě", - }, - 1, - "Ekonomický motiv sňatku.", - }, - { - "Jak Mrštíkové vykreslují vesnici?", - { - "Realisticky – pomluvy, soud", - "Idylicky", - "Bez lidí", - "Futuristicky", - }, - 0, - "Společenská kritika venkova.", - }, - { - "Kdy hra vznikla?", - { - "1894", - "2000", - "1700", - "1948", - }, - 0, - "Konec 19. století.", - }, - { - "Co je proces v hře?", - { - "Soudní líčení s Maryšou", - "Sport", - "Svatba", - "Válka", - }, - 0, - "Společenské odsouzení vrcholí soudem.", - }, - { - "Jaký vztah má Filip k Maryši?", - { - "Láska, ale slabší než tlak okolí", - "Nenávist", - "Sourozenec", - "Kněz", - }, - 0, - "Láska nestačí proti systému.", - }, - { - "Proč je Maryša obětí?", - { - "Systém pomluv, tchyně a majetku ji zničí", - "Vlastní volba bez tlaku", - "Válka", - "Magie", - }, - 0, - "Tragédie bez viny hrdinky.", - }, - { - "Co je realistické drama?", - { - "Každodenní konflikt bez nadpřirozena", - "Pohádka", - "Epos", - "Opera", - }, - 0, - "Mrštíkové zobrazují reálný venkov.", - }, - { - "Kdo jsou autoři – vztah?", - { - "Bratři", - "Otec a syn", - "Cizinci", - "Jeden autor", - }, - 0, - "Alois a Vilém Mrštíkové.", - }, - { - "Jaký kontrast tvoří jádro?", - { - "Láska Maryši–Filip vs. tlak Vávry a tchyně", - "Moře vs. hory", - "Praha vs. Brno", - "Humor vs. humor", - }, - 0, - "Osobní city vs. sociální moc.", - }, - { - "Co symbolizuje majetek?", - { - "Tlak na vdovu", - "Nic", - "Vesmír", - "Sport", - }, - 0, - "Statky a sňatky řídí osudy.", - }, - { - "Jak končí Vávra?", - { - "Není absolutní vítěz – morálně problematický", - "Král", - "Emigrace", - "Neznámo", - }, - 0, - "Interpretace ukazuje prázdnotu „vítězství“.", - }, - { - "Proč je tchyně důležitá?", - { - "Zdroj útlaku v domě", - "Pomáhá Maryši", - "Neobjevuje se", - "Královna", - }, - 0, - "Rodinný tyran.", - }, - { - "Jaká je role kněze?", - { - "Moralita a soud společnosti", - "Voják", - "Milující", - "Soudce sám", - }, - 0, - "Metoděj komentuje morálku.", - }, - { - "Co NENÍ charakteristika hry?", - { - "Dialog", - "Venkov", - "Vesmírná opera", - "Tragédie", - }, - 2, - "Maryša je uzavřené venkovské drama.", - }, - { - "Jak čtenář vnímá Maryšu?", - { - "Soucit k oběti", - "Opovržení", - "Smích", - "Nezájem", - }, - 0, - "Hrdinka evokuje empatii.", - }, - { - "Jaké poselství hra nese?", - { - "Společnost může zničit jedince pomluvou a tlakem", - "Venkov je ráj", - "Bohatství šťastí", - "Bez etiky", - }, - 0, - "Realistická kritika morálky venkova.", - }, -}; - -static const AssemblyItem book_marysa_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Maryša jako vdova pod tlakem tchyně", - "Láska k Filipovi; Vávra usiluje o sňatek", - "Konflikt na venkově a v hospodě", - "Pomluvy a společenské odsouzení", - "Soudní proces s Maryšou", - "Tragický konec – Maryša prohrává", - }, - 6, - }, -}; - -static const char *book_marysa_plot_meaning[] = { - "Správné pořadí: vdovství a útlak → Filip a Vávra → konflikt → pomluvy → soud → tragédie Maryši.", -}; - -static const LitQ book_modlitba_pro_katerinu_qs[] = { - { - "Kdo napsal Modlitbu pro Katherinu Horovitzovou?", - { - "Seifert", - "František Halas", - "Holan", - "Nezval", - }, - 1, - "Halas vydal skladbu v roce 1939.", - }, - { - "Kdy báseň vznikla?", - { - "1939 – začátek okupace", - "1989", - "1848", - "2000", - }, - 0, - "Reaguje na válečnou situaci Čech a Moravy.", - }, - { - "Kdo je Katherina Horovitzová?", - { - "Postava z Lustigova románu, oběť holocaustu", - "Královna", - "Halasova sestra", - "Vymyšlená bez kontextu", - }, - 0, - "Halas reaguje na Lustigův příběh.", - }, - { - "Jaký žánr dílo reprezentuje?", - { - "Válečná lyrika / modlitební skladba", - "Román", - "Komedie", - "Epos", - }, - 0, - "Lyrika s modlitební formou.", - }, - { - "Proč „modlitba“ v titulu?", - { - "Apel na Boha i lidskost za oběť", - "Katolická mše text", - "Bez významu", - "Vtip", - }, - 0, - "Modlitba je forma i morální výzva.", - }, - { - "Jaký kontext 2. sv. války?", - { - "Okupace, tábory, genocida", - "Mír", - "První republika bez krize", - "Vesmír", - }, - 0, - "Báseň vzniká v době nacistické hrozby.", - }, - { - "Co je typické pro Halasovu lyriku?", - { - "Intimní, naléhavý jazyk", - "Suchý humor", - "Sci-fi", - "Bez emocí", - }, - 0, - "Halas patří k lyrickým modernistům.", - }, - { - "Proč maturita zahrnuje skladbu?", - { - "Nejdelší román", - "Válečná poezie a etická reflexe", - "Bez významu", - "Jen humor", - }, - 1, - "Učí číst lyriku v historickém kontextu.", - }, - { - "Kdo je Arnošt Lustig v souvislosti?", - { - "Autor románu inspirujícího Halase", - "Básník Modlitby", - "Okupant", - "Král", - }, - 0, - "Lustig psal o Katherině Horovitzové.", - }, - { - "Co básnický subjekt dělá?", - { - "Modlí se / apeluje za oběť", - "Válku oslavuje", - "Vaří", - "Sportuje", - }, - 0, - "Hlas básníka je svědectvím.", - }, - { - "Jaký tón převládá?", - { - "Vážný, bolestný, někdy nadějný", - "Komický", - "Bezbřehý optimismus", - "Prázdný", - }, - 0, - "Válečná lyrika bez kýče.", - }, - { - "Co je holocaust v kontextu?", - { - "Genocida Židů", - "Sport", - "Povodeň", - "Revolution 1989", - }, - 0, - "Katherina reprezentuje oběti.", - }, - { - "Které téma NENÍ středem?", - { - "Oběť", - "Válka", - "Vesmírná kolonizace", - "Modlitba", - }, - 2, - "Skladba je válečná lyrika.", - }, - { - "Jak Halas individualizuje utrpení?", - { - "Jménem konkrétní ženy", - "Bez jmen", - "Jen statistiky", - "Humorem", - }, - 0, - "Konkrétní jméno zvyšuje sílu.", - }, - { - "Co je etická odpovědnost umělce?", - { - "Mluvit za oběti", - "Mlčet", - "Oslavovat moc", - "Bez etiky", - }, - 0, - "Básník je svědek doby.", - }, - { - "Jaký verš Halas používá?", - { - "Volný verš moderní lyriky", - "Antický hexametr", - "Proza", - "Bez verše", - }, - 0, - "Moderní forma odpovídá obsahu.", - }, - { - "Kdy Halas zemřel?", - { - "1949", - "1939", - "2000", - "1890", - }, - 0, - "Halas patří k meziválečné generaci.", - }, - { - "Co je naděje v modlitbě?", - { - "Tenká, ale přítomná – víra v lidskost", - "Absentní vždy", - "Jen politika", - "Sport", - }, - 0, - "Napětí mezi bezmocí a apellem.", - }, - { - "Jak číst skladbu historicky?", - { - "V kontextu okupace a holocaustu", - "Bez kontextu", - "Jako pohádku", - "Jako sci-fi", - }, - 0, - "Historie je klíč interpretace.", - }, - { - "Co NENÍ charakteristika Halase?", - { - "Lyrika", - "Válečné téma", - "Groteskní humor bez vážnosti", - "Modernismus", - }, - 2, - "Modlitba je vážná skladba.", - }, - { - "Proč konkrétní jméno v titulu?", - { - "Oběť není anonymní statistika", - "Náhodné", - "Reklama", - "Město", - }, - 0, - "Individualizace zvyšuje etický tlak.", - }, - { - "Jak skladba souvisí s Prokletým věkem?", - { - "Halas je autorem obou", - "Bez souvislosti", - "Stejný autor Lustig", - "Opera", - }, - 0, - "Halas napsal i Prokletý věk – válečná lyrika.", - }, - { - "Co je addresát modlitby?", - { - "Bůh / transcendentní instance i čtenář", - "Jen sportovec", - "Nikdo", - "Okupant", - }, - 0, - "Modlitba směřuje nad člověka.", - }, - { - "Jaký kontrast skladba nese?", - { - "Modlitba za život vs. realita smrti", - "Humor vs. humor", - "Město vs. město", - "Bez kontrastu", - }, - 0, - "Napětí víry a hrůzy.", - }, - { - "Co čtenář má cítit?", - { - "Soucit a morální odpovědnost", - "Smích", - "Nezájem", - "Pouze strach bez smyslu", - }, - 0, - "Lyrika apeluje na svědomí.", - }, - { - "Kde Halas patří v literatuře?", - { - "Česká meziválečná moderna", - "Baroko", - "Antika", - "Bez období", - }, - 0, - "Spolu s Seifertem, Holanem apod.", - }, - { - "Proč „Horovitzová“?", - { - "Identita oběti holocaustu", - "Náhodné jméno", - "Město", - "Růže", - }, - 0, - "Židovská oběť v kontextu genocidy.", - }, - { - "Jak skladba končí emocionálně?", - { - "Naléhavost modlitby trvá", - "Radostná párty", - "Bez emocí", - "Reklama", - }, - 0, - "Otevřený apel, ne uzavřený happy end.", - }, - { - "Co je válečná lyrika?", - { - "Poezie reagující na válku a útlak", - "Jen romantismus", - "Sport", - "Epos", - }, - 0, - "Modlitba je typická ukázka.", - }, - { - "Jaké poselství skladba nese?", - { - "Pamatuj na oběti, nestrác humanitu v době zla", - "Válka je slavná", - "Oběti jsou čísla", - "Bez morálky", - }, - 0, - "Etický apel Halasovy poezie.", - }, -}; - -static const AssemblyItem book_modlitba_pro_katerinu_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Okupace a hrůza 2. světové války", - "Halas čte příběh Katheriny Horovitzové", - "Básník promlouvá modlitbou k oběti", - "Apel na Boha a lidskost", - "Individualizace utrpení jednoho jména", - "Výzva čtenáři neztratit morální compass", - }, - 6, - }, -}; - -static const char *book_modlitba_pro_katerinu_plot_meaning[] = { - "Správné pořadí: válečný kontext → inspirace → modlitba → apel → jméno oběti → etické poselství.", -}; - -static const LitQ book_most_kwai_qs[] = { - { - "Kdo napsal Most přes řeku Kwai?", - { - "Hemingway", - "Pierre Boulle", - "Remarque", - "Orwell", - }, - 1, - "Boulle vydal román v roce 1952.", - }, - { - "Kde se děj odehrává?", - { - "Francie", - "Barmská/thajská džungle – Burma Railway", - "Pacifik", - "Londýn", - }, - 1, - "Zajatci staví železnici pro Japonce.", - }, - { - "Kdo je Colonel Nicholson?", - { - "Japonský generál", - "Britský důstojník posedlý stavbou mostu", - "Americký Shears", - "Lékař", - }, - 1, - "Nicholson chce „pořádný“ most pro britskou armádu.", - }, - { - "Proč Nicholson staví most pro nepřítele?", - { - "Zrada", - "Hrdost, disciplína, iluze že most bude britský", - "Náhodou", - "Bez důvodu", - }, - 1, - "Paradox – pomáhá okupantům z pocitu česti.", - }, - { - "Kdo je Shears?", - { - "Zajatec, utekl, účastní se sabotáže", - "Japonský velitel", - "Nicholson", - "Most", - }, - 0, - "Shears reprezentuje praktický odpor.", - }, - { - "Co má sabotážní tým udělat?", - { - "Postavit most", - "Zničit most", - "Ukrást vlak", - "Podepsat mír", - }, - 1, - "Most má padnout před použitím.", - }, - { - "Kdo je Saito?", - { - "Japonský velitel tábora", - "Brit", - "Shears", - "Lékař", - }, - 0, - "Saito tlačí na dokončení mostu.", - }, - { - "Jak román/film končí?", - { - "Most stojí navždy slavně", - "Most exploduje; Nicholson padne v absurditě", - "Mír", - "Shears král", - }, - 1, - "Sabotáž a Nicholsonův zlom.", - }, - { - "Kdy vyšel román?", - { - "1952", - "1940", - "2000", - "1890", - }, - 0, - "Po 2. světové válce.", - }, - { - "Jaký žánr?", - { - "Válečný / antiwar román", - "Pohádka", - "Detektivka", - "Sci-fi", - }, - 0, - "Kritika absurdity války.", - }, - { - "Proč maturita zahrnuje dílo?", - { - "Nejkratší", - "2. sv. válka, etika, kolaborace", - "Bez děje", - "Komiks", - }, - 1, - "Učí historii a morální paradox.", - }, - { - "Co je Burma Railway?", - { - "Železnice stavěná zajatci za okupace", - "Metro v Londýně", - "Vesmír", - "Most v Praze", - }, - 0, - "Tisíce zajatců zemřelo.", - }, - { - "Kdo režíroval slavný film?", - { - "David Lean", - "Spielberg", - "Kubrick", - "Nolan", - }, - 0, - "Film 1957 získal Oscary.", - }, - { - "Co je Clipton?", - { - "Lékař kritizující Nicholsona", - "Most", - "Shears", - "Saito", - }, - 0, - "Clipton vidí šílenství situace.", - }, - { - "Které téma NENÍ středem?", - { - "Vojenská hrdost", - "Sabotáž", - "Vesmírná válka", - "Zajatecký tábor", - }, - 2, - "Děj je v jihovýchodní Asii 2. sv. války.", - }, - { - "Co symbolizuje most?", - { - "Absurdita pomoci nepříteli", - "Láska", - "Mír", - "Sport", - }, - 0, - "Most = morální kolaps Nicholsona.", - }, - { - "Jak Boulle pracuje s perspektivou?", - { - "Britové i Japonci", - "Jen Japonci", - "Bez postav", - "Jen Shears", - }, - 0, - "Román střídá pohledy.", - }, - { - "Proč je Nicholson tragický?", - { - "Má čest, ale slouží nepříteli", - "Je zločinec od začátku", - "Komik", - "Dítě", - }, - 0, - "Tragédie dobré intence.", - }, - { - "Co Shears představuje?", - { - "Přežití a praktický odpor", - "Kolaboraci", - "Kněze", - "Most", - }, - 0, - "Utíká a vrací se ničit.", - }, - { - "Jaký kontrast tvoří jádro?", - { - "Stavba vs. sabotáž mostu", - "Moře vs. hory", - "Praha vs. Brno", - "Humor", - }, - 0, - "Nicholson vs. Shears.", - }, - { - "Co je antiwar poselství?", - { - "Válka ničí rozum a morálku", - "Válka slavná", - "Bez poselství", - "Propaganda", - }, - 0, - "Most ukazuje degradaci.", - }, - { - "Kdo hraje Nicholsona ve filmu?", - { - "Alec Guinness", - "Connery", - "Cooper", - "Brando", - }, - 0, - "Guinness – ikonická role.", - }, - { - "Co je železniční smrt?", - { - "Přezdívka brutalitě stavby", - "Vlak", - "Film", - "Komiks", - }, - 0, - "Extrémní úmrtnost zajatců.", - }, - { - "Jak Nicholson reaguje na sabotáž?", - { - "V finále zasáhne proti – tragický zlom", - "Pomůže hned", - "Spí", - "Utíká", - }, - 0, - "Umírá u vlastního díla.", - }, - { - "Proč Boulle psal francouzsky?", - { - "Francouzský autor", - "Anglicky jen", - "Česky", - "Německy", - }, - 0, - "Boulle je francouzský spisovatel.", - }, - { - "Co Joyce dělá?", - { - "Součást sabotážního týmu", - "Velitel Japonců", - "Nicholsonova žena", - "Most", - }, - 0, - "Mladý důstojník v akci.", - }, - { - "Jak číst kolaboraci?", - { - "Ne vždy zrada – i iluze a hrdost", - "Vždy zlo", - "Vždy dobro", - "Bez významu", - }, - 0, - "Nicholson není karikatura zla.", - }, - { - "Co NENÍ charakteristika?", - { - "Válka", - "Most", - "Pohádkový happy end", - "Tábor", - }, - 2, - "Dílo je vážné antiwar.", - }, - { - "Jaký historický fakt stojí za dějem?", - { - "Stavba železnice zajatci v Asii", - "Normandie", - "Pearl Harbor", - "Berlín", - }, - 0, - "Burma Railway je reálná.", - }, - { - "Jaké poselství román nese?", - { - "Válečná hrdost může vést k absurdní sebedestrukci", - "Stavět mosty pro nepřítele", - "Bez morálky", - "Jen akce", - }, - 0, - "Varování před slepou disciplínou.", - }, -}; - -static const AssemblyItem book_most_kwai_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Britští zajatci v táboře u Kwai", - "Nicholson organizuje stavbu mostu", - "Shears utekne a vrací se se sabotážním týmem", - "Most se blíží k dokončení", - "Sabotážní akce proti mostu", - "Most padne; Nicholson umírá v paradoxu hrdosti", - }, - 6, - }, -}; - -static const char *book_most_kwai_plot_meaning[] = { - "Správné pořadí: tábor → stavba → Shears → dokončování → sabotáž → zničení mostu a Nicholsonův konec.", -}; - -static const LitQ book_stanice_zoo_qs[] = { - { - "O čem kniha My děti ze stanice ZOO především vypovídá?", - { - "O válečném hrdinství", - "O drogové závislosti dospívajících v Berlíně", - "O středověké legendě", - "O venkovské idyle", - }, - 1, - "Jde o svědectví o heroinové scéně Západního Berlína 70. let.", - }, - { - "Kdo je Christiane F.?", - { - "Fiktivní detektivka", - "Skutečná dívka, jejíž zpověď kniha zaznamenává", - "Policistka na stanici Zoo", - "Autorka sci-fi románů", - }, - 1, - "Christiane Felscherinow vypráví vlastní zkušenost; text vznikl z rozhovorů.", - }, - { - "Kde se děj především odehrává?", - { - "V Praze 90. let", - "V Západním Berlíně 70. let kolem stanice Zoo", - "V New Yorku za prohibice", - "V Paříži za komuny", - }, - 1, - "Centrem je drogová scéna kolem berlínského Bahnhof Zoo.", - }, - { - "Jak kniha vznikla?", - { - "Jako čistá fikce bez předlohy", - "Z novinářských rozhovorů s Christiane", - "Jako deník napsaný ve vězení", - "Jako básnická sbírka", - }, - 1, - "Kai Hermann a Horst Rieck zaznamenali její výpověď reportážním stylem.", - }, - { - "Kdo je Detlef?", - { - "Christianeina matka", - "Její přítel, také závislý", - "Dealer s heroinem", - "Sociální pracovník", - }, - 1, - "Detlef patří k nejbližším osobám v příběhu závislosti.", - }, - { - "Čím se Christiane často živí, aby měla na dávku?", - { - "Prací v knihovně", - "Prostitucí", - "Studiem medicíny", - "Prodejem obrazů", - }, - 1, - "Text ukazuje, jak závislost vede k prostituci mladistvých.", - }, - { - "Jaká droga je v knize ústřední?", - { - "Alkohol", - "Heroin", - "Nikotin", - "Kofein", - }, - 1, - "Příběh sleduje propad do heroinové závislosti.", - }, - { - "Jaký je žánr knihy?", - { - "Rytířský román", - "Dokumentární próza / autentická zpověď", - "Antická tragédie", - "Science fiction", - }, - 1, - "Nejde o klasickou fikci, ale o svědectví založené na rozhovorech.", - }, - { - "Co symbolizuje stanice Zoo?", - { - "Školní úspěch", - "Centrum drogové scény a úpadku", - "Turistickou atrakci bez stinné stránky", - "Sídlo vlády", - }, - 1, - "Bahnhof Zoo je místem obchodu s drogami i tělem.", - }, - { - "Jak kniha působí na čtenáře především?", - { - "Jako návod k užívání drog", - "Jako varovné svědectví o závislosti", - "Jako komedie o dospívání", - "Jako detektivka s happy endem", - }, - 1, - "Síla textu je v autenticitě a v zobrazení propadu bez zkrášlení.", - }, - { - "Jaká je role matky v příběhu?", - { - "Je hlavní dealerkou", - "Snaží se dceru zachránit, ale často je bezmocná", - "O dceru nestojí", - "Vede drogový gang", - }, - 1, - "Rodina vidí problém, ale systém i závislost ji přerůstají.", - }, - { - "Proč text není „hrdinský“ příběh o překonání?", - { - "Protože Christiane vyhrává olympiádu", - "Protože ukazuje realitu závislosti bez romantizace", - "Protože chybí postavy", - "Protože je to jen seznam vtipů", - }, - 1, - "Dokumentárnost odmítá falešné happy endy a heroizaci.", - }, - { - "Která formulace nejlépe vystihuje vyprávění?", - { - "Er-forma vševědoucího historika", - "Ich-forma Christiane v reportážním stylu", - "Veršovaná epopej", - "Soubor sonetů", - }, - 1, - "Čtenář slyší její hlas; novináři text sestavili z rozhovorů.", - }, - { - "Co kniha ukazuje o institucích (škola, policie, sociální péče)?", - { - "Všechny problémy okamžitě vyřeší", - "Často nestíhají nebo zasahují pozdě", - "Neexistují", - "Jsou hlavními dealery", - }, - 1, - "Instituce jsou přítomné, ale závislost a scéna je přerůstají.", - }, - { - "Jak začíná Christianina cesta k drogám typicky v knize?", - { - "Povinnou školní praxí v nemocnici", - "Přes party scénu, kamarády a experimentování", - "Studiem teologie", - "Prací v bance", - }, - 1, - "Propad jde od subkultury a experimentů k heroinu.", - }, - { - "Proč je kniha stále čtená ve škole / k maturitě?", - { - "Protože je krátká pohádka", - "Protože otevírá témata závislosti, dospívání a společnosti", - "Protože nemá žádný obsah", - "Protože je to jen cestopis", - }, - 1, - "Nabízí silné společenské svědectví a látku k diskusi.", - }, - { - "Co znamená „dokumentárnost“ u této knihy?", - { - "Že jde o soudní spis bez příběhu", - "Že staví na autentické výpovědi a faktech ze života", - "Že nemá žádné postavy", - "Že je to výhradně fikční fantasy", - }, - 1, - "Autenticita je základní rys žánru i účinku textu.", - }, - { - "Jak text zachází s moralizováním?", - { - "Káže dlouhé kázání bez příběhu", - "Varuje především skrze konkrétní svědectví, ne skrze pohádku", - "Vyzdvihuje drogy jako řešení", - "Ignoruje důsledky", - }, - 1, - "Síla je v ukázání důsledků, ne v abstraktním kázání.", - }, - { - "Kdo knihu „napsal“ ve smyslu literární podoby?", - { - "Jen anonymní dav", - "Christiane vypráví; Hermann a Rieck text zaznamenali a sestavili", - "Jen Tennessee Williams", - "Jen Karel Čapek", - }, - 1, - "Jde o spolupráci svědkyně a novinářů.", - }, - { - "Co je typickým důsledkem závislosti v knize?", - { - "Okamžité zbohatnutí bez rizika", - "Ztráta zdraví, vztahů a bezpečného dětství", - "Zisk Nobelovy ceny", - "Přestěhování na farmu bez problémů", - }, - 1, - "Text ukazuje totální rozklad běžného života.", - }, - { - "Proč název odkazuje na stanici ZOO?", - { - "Protože kniha je o zvířatech v kleci doslova", - "Protože Bahnhof Zoo je klíčové místo scény, o níž Christiane mluví", - "Protože jde o průvodce zoo", - "Protože se odehrává jen v Praze", - }, - 1, - "Stanice je reálným i symbolickým centrem příběhu.", - }, - { - "Jaká je perspektiva vyprávění vůči drogové scéně?", - { - "Zvenčí jako suchá statistika bez lidí", - "Zevnitř – očima dospívající závislé", - "Jen z pohledu policie", - "Jen z pohledu dealerů jako hrdinů", - }, - 1, - "Ich-forma dává intimní a šokující pohled zevnitř.", - }, - { - "Která teze je s knihou v souladu?", - { - "Závislost je jen „špatná nálada“", - "Závislost ničí tělo, vztahy i budoucnost", - "Drogová scéna je bezpečná zábava", - "Prostituce s drogami nesouvisí", - }, - 1, - "Celý text je litanií důsledků závislosti.", - }, - { - "Jak kniha pracuje s časem dospívání?", - { - "Ukazuje spokojené stáří důchodců", - "Ukazuje zkrácené / ztracené dětství a dospívání", - "Ignoruje věk postav", - "Odehrává se jen ve školní lavici bez konfliktů", - }, - 1, - "Christiane a její okolí přicházejí o běžné dospívání.", - }, - { - "Co je „scéna“ v kontextu knihy?", - { - "Divadelní představení ve Národním", - "Sociální prostředí party, drog a stanice Zoo", - "Sportovní turnaj", - "Školní sbor", - }, - 1, - "Scéna označuje subkulturu, v níž se Christiane pohybuje.", - }, - { - "Proč je Detlef důležitý pro motivaci děje?", - { - "Je učitelem matematiky", - "Vztah s ním je součástí společného propadu do závislosti", - "Je prezidentem", - "V knize se nevyskytuje", - }, - 1, - "Partnerský vztah je svázán se společným užíváním a přežitím.", - }, - { - "Která formulace nejlépe vystihuje společenský rozměr knihy?", - { - "Jde jen o soukromý deníček bez kontextu", - "Osobní zpověď odhaluje širší problém města a doby", - "Jde o receptář kuchyně", - "Jde o portréty panovníků", - }, - 1, - "Individuální osud ukazují jako symptom společenské krize.", - }, - { - "Jaký je typický vztah Christiane k „normálnímu“ světu (škola, domov)?", - { - "Bezproblémové začlenění", - "Narůstající odcizení a konflikty", - "Vede školu jako ředitelka", - "Nezná domov ani školu", - }, - 1, - "Závislost ji odděluje od běžných jistot dospívání.", - }, - { - "Proč text není fantasy ani alegorie o zvířatech?", - { - "Protože Zoo je jen metafora bez reality", - "Protože jde o reálné svědectví z berlínské drogové scény", - "Protože autor neexistuje", - "Protože kniha nemá děj", - }, - 1, - "Nepleťte si ji se Skleněnou zoologickou zahradou T. Williamse ani s bajkou.", - }, - { - "Co by měl čtenář pochopit jako hlavní varování?", - { - "Že drogy jsou vždy neškodná zábava", - "Že závislost rychle ovládne život a okolí často nestíhá pomoci", - "Že stačí jedna party bez následků", - "Že instituce vždy zachrání každého včas", - }, - 1, - "Kniha ukazuje, jak rychle a totálně závislost přeroste člověka i pomoc okolí.", - }, -}; - -static const AssemblyItem book_stanice_zoo_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Christiane vyrůstá a vstupuje do berlínské party scény", - "Začne experimentovat s drogami a propadá heroinu", - "S Detlefem sdílí závislost a život kolem stanice Zoo", - "Prostitucí a krádežemi shání peníze na dávky", - "Rodina a instituce se snaží zasáhnout, často bezmocně", - "Svědectví ukazuje následky závislosti bez zkrášlení", - }, - 6, - }, -}; - -static const char *book_stanice_zoo_plot_meaning[] = { - "Správné pořadí: vstup do scény → heroin → vztah a Zoo → shánění dávek → zásahy okolí → svědectví o důsledcích.", -}; - -static const LitQ book_na_ceste_qs[] = { - { - "Kdo je autorem románu Na cestě?", - { - "Allen Ginsberg", - "Jack Kerouac", - "William S. Burroughs", - "Ernest Hemingway", - }, - 1, - "Román napsal Jack Kerouac; vyšel v roce 1957 a stal se manifestem beat generation.", - }, - { - "Jak se jmenuje anglický originál knihy?", - { - "The Road", - "On the Road", - "Down the Road", - "Off the Road", - }, - 1, - "Originální název je On the Road – „na cestě“, v pohybu.", - }, - { - "Kdo je vypravěč příběhu?", - { - "Dean Moriarty", - "Sal Paradise", - "Carlo Marx", - "Old Bull Lee", - }, - 1, - "Sal Paradise vypráví v ich-formě o svých cestách a o Deanovi.", - }, - { - "Na koho reálně naráží postava Deana Moriartyho?", - { - "Na Neal Cassadyho", - "Na Ernesta Hemingwaye", - "Na F. S. Fitzgeralda", - "Na Jacka Londona", - }, - 0, - "Dean Moriarty je literární obraz Neal Cassadyho, Kerouacova přítele a vzoru neklidu.", - }, - { - "Jaké hnutí román nejvíc reprezentuje?", - { - "Romantismus", - "Beat generation", - "Socialistický realismus", - "Existencialismus Sartreův", - }, - 1, - "Na cestě je klíčovým textem beat generation – odmítání konformity a hledání života.", - }, - { - "Co je „spontánní próza“ v Kerouacově pojetí?", - { - "Přesně strukturovaný epos", - "Rychlý, rytmický proud řeči blízký jazzu", - "Úřední styl", - "Pouze dialogy", - }, - 1, - "Kerouac psal rychle, s jazzovým rytmem; vzdává se klasické pevné kompozice.", - }, - { - "Jakou roli hraje jazz v románu?", - { - "Jen kulisa bez významu", - "Rytmus života, hudby i stylu vyprávění", - "Symbol války", - "Náboženský obřad", - }, - 1, - "Jazz ovlivňuje beatnický život i Kerouacovu prózu – rychlost, improvizace, extáze.", - }, - { - "Proti čemu beatnici v románu nejvíc vystupují?", - { - "Proti cestování", - "Proti konformní poválečné společnosti a prázdnému materialismu", - "Proti demokracii", - "Proti literatuře", - }, - 1, - "Hrdinové utíkají před nudou, kariérou a „normálním“ životem bez autenticity.", - }, - { - "Co je typickým prostorem děje?", - { - "Pouze jeden byt v New Yorku", - "Silnice, auta, vlaky a města USA (a cesta do Mexika)", - "Středověký hrad", - "Vesnická idyla", - }, - 1, - "Chronotopem románu je cesta – Amerika jako nekonečná silnice a setkání.", - }, - { - "Jaký vztah mají Sal a Dean?", - { - "Jsou bratři", - "Sal obdivuje Deana, Dean je hybatelem neklidných cest", - "Jsou nepřátelé", - "Dean je Salův učitel latině", - }, - 1, - "Sal je pozorovatel a společník; Dean přitahuje svou energií, ale také ničí vztahy kolem sebe.", - }, - { - "Jak Dean Moriarty obvykle jedná k ženám?", - { - "Je věrný jedné partnerce", - "Je vášnivý, ale nestálý a často opouští rodiny", - "Ženy v románu vůbec nejsou", - "Je asketa", - }, - 1, - "Dean prožívá intenzivní vztahy s Marylou, Camille a dalšími, ale nedokáže zůstat.", - }, - { - "Kdo je Carlo Marx v románu?", - { - "Policista", - "Beatnický básník, obraz Allena Ginsberga", - "Deanův otec", - "Mexický farmář", - }, - 1, - "Carlo Marx představuje Ginsberga – intelektuála a básníka z beat scény.", - }, - { - "Kdo je Old Bull Lee?", - { - "Námořní kapitán", - "Literární obraz Williama S. Burroughse", - "Salův strýc", - "Kněz", - }, - 1, - "Old Bull Lee je Kerouacova verze Burroughse – excentrický spisovatel na jihu USA.", - }, - { - "Proč Sal opakovaně vyráží na cestu?", - { - "Kvůli vojenské službě", - "Hledá zkušenost, extázi a autentický život", - "Je to trest soudu", - "Musí doručovat poštu", - }, - 1, - "Sal touží po „IT“ – okamžiku, kdy život dává smysl; cesta je jeho metoda hledání.", - }, - { - "Jak román obvykle končí jednotlivé etapy cest?", - { - "Vždy šťastným sňatkem", - "Vyčerpáním, rozchody a návratem k psaní či klidu", - "Vítězstvím ve válce", - "Dědictvím milionů", - }, - 1, - "Za extází cesty přichází únava, prázdné noci a vystřízlivění – svoboda má cenu.", - }, - { - "Kam Sal s Deanem mimo USA také cestují?", - { - "Do Antarktidy", - "Do Mexika (a další cesty po Americe)", - "Do Marsu", - "Pouze do Kanady", - }, - 1, - "Mezi významné úseky patří jízda do Mexika – jiná kultura, drogy, pocit svobody.", - }, - { - "Co znamená beatnické „IT“?", - { - "Iniciály autora", - "Extatický okamžik plnosti a pravdy", - "Název auta", - "Zkratka pro cenzuru", - }, - 1, - "„IT“ je stav, kdy člověk prožije život naplno – jazz, noc, řeč, extáze.", - }, - { - "Jaký je vztah románu k autobiografii?", - { - "Čistá fantasy bez reálií", - "Silně autobiografický – postavy odpovídají reálným beatníkům", - "Historický román o středověku", - "Detektivka", - }, - 1, - "Kerouac zpracoval skutečné cesty a přátele; román je fikcionalizovaným deníkem.", - }, - { - "Které téma NENÍ pro Na cestě typické?", - { - "Touha po svobodě", - "Přátelství a neklid", - "Kritika prázdné konformity", - "Středověké rytířské turnaje", - }, - 3, - "Román je o moderní Americe a beatnících, ne o rytířském středověku.", - }, - { - "Jak Sal vydělává na živobytí (mimo cesty)?", - { - "Jako spisovatel a občas brigádník", - "Jako soudce", - "Jako farář", - "Jako astronaut", - }, - 0, - "Sal píše a občas pracuje; cesty financuje různými krátkodobými příjmy.", - }, - { - "Proč je Dean pro ostatní tak přitažlivý?", - { - "Má neomezené bohatství", - "Je plný energie, spontánnosti a radosti z okamžiku", - "Je nejlepší student na univerzitě", - "Je generál armády", - }, - 1, - "Dean žije rychle, mluví zmateně ale vášnivě a láme pravidla – fascinuje i ničí.", - }, - { - "Jaký stín má beatnická svoboda v románu?", - { - "Žádný – vše je idyla", - "Vyčerpání, osamění, rozpad vztahů a deprese", - "Vězení za jazz", - "Ztráta paměti", - }, - 1, - "Neustálý pohyb nevyplní vždy prázdnotu; hrdinové často končí u únavy a smutku.", - }, - { - "V jakém roce román poprvé vyšel?", - { - "1929", - "1957", - "1984", - "2001", - }, - 1, - "Kniha vyšla v roce 1957 a rychle ovlivnila americkou kulturu.", - }, - { - "Jaký jazykový styl je typický?", - { - "Strohé věty bez emocí", - "Dlouhé věty, slang, rytmus mluvené řeči", - "Středověká čeština", - "Pouze rýmované verše", - }, - 1, - "Kerouac napodobuje mluvený jazyk, jazzový flow a rychlé sledy obrazů.", - }, - { - "Co je hlavní strukturou románu?", - { - "Jeden den v jedné místnosti", - "Série cest a setkání bez klasické zápletky", - "Přesný detektivní úkol", - "Epos o jedné bitvě", - }, - 1, - "Román nemá tradiční děj; skládá se z epizod na cestách.", - }, - { - "Jaký význam má přátelství Sal–Dean?", - { - "Jen náhodné setkání", - "Jádro románu – inspirace, svoboda i zklamání", - "Obchodní partnerství", - "Vztah učitele a žáka v latině", - }, - 1, - "Sal bez Deana necestuje stejně; Dean je symbolem i problémem beatnického života.", - }, - { - "Proč je Na cestě důležitá pro maturitu?", - { - "Je technický manuál", - "Ukazuje beat generation, styl i témata poválečné Ameriky", - "Je encyklopedie rostlin", - "Je zákoník", - }, - 1, - "U maturity jde o autora, kontext, postavy, styl spontánní prózy a témata svobody.", - }, - { - "Které město je častým výchozím bodem Salových cest?", - { - "New York", - "Praha", - "Paříž", - "Tokio", - }, - 0, - "Sal žije mezi New Yorkem a cestami po zbytku USA; město je start i návrat.", - }, - { - "Jak Dean často financuje svůj neklid?", - { - "Krádeže bank", - "Krátké práce, přátelé, manželky, auta", - "Výhra v loterii pokaždé", - "Státní dotace na poezii", - }, - 1, - "Dean žije od ruky k ruce – auta, práce, vztahy; stabilní kariéru nemá.", - }, - { - "Co Kerouac románem nejspíš vyjadřuje?", - { - "Oslavu konformity", - "Touhu po autentickém životě a varování před prázdnou svobodou", - "Návod na daňové úniky", - "Historii antiky", - }, - 1, - "Román slaví cestu a okamžik, ale ukazuje i vyhoření a nenasytnost pohybu.", - }, - { - "Která postava nepatří k beat scéně v románu?", - { - "Sal Paradise", - "Dean Moriarty", - "Carlo Marx", - "Napoleon Bonaparte", - }, - 3, - "Napoleon v románu nevystupuje; ostatní jména patří ke Kerouacově beatnické partě.", - }, -}; - -static const AssemblyItem book_na_ceste_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Sal potká Deana Moriartyho a obdivuje jeho energii", - "Společně vyrážejí na první velké cesty po Americe", - "Noční jízdy, jazz, bary a vztahy s ženami", - "Cesta do Mexika a další opakované výjezdy", - "Deanův neklid ničí vztahy, Sal se unavuje", - "Sal se vrací k psaní a bilancuje cesty", - }, - 6, - }, -}; - -static const char *book_na_ceste_plot_meaning[] = { - "Správné pořadí: setkání s Deanem → první cesty → jazz a vztahy → Mexiko a další jízdy → vyčerpání → návrat a bilance.", -}; - -static const LitQ book_na_zapadni_fronte_qs[] = { - { - "Kdo napsal Na západní frontě klid?", - { - "Thomas Mann", - "Erich Maria Remarque", - "Franz Kafka", - "Ernest Hemingway", - }, - 1, - "Autorem je Erich Maria Remarque; román vyšel v roce 1929.", - }, - { - "Kdo vypravuje příběh?", - { - "Kantorek", - "Paul Bäumer", - "Kat", - "Generál", - }, - 1, - "Paul Bäumer vypráví v ich-formě o frontě a o sobě.", - }, - { - "Kde se děj odehrává?", - { - "Na východní frontě za 2. světové", - "Na západní frontě 1. světové války", - "V Praze za protektorátu", - "Ve Vietnamu", - }, - 1, - "Román sleduje německé vojáky na západní frontě první světové války.", - }, - { - "Kdo je Kat?", - { - "Paulův učitel", - "Zkušený starší kamarád ve squatu", - "Francouzský generál", - "Paulova sestra", - }, - 1, - "Katczinsky je mazaný čtyřicátník, který pomáhá přežít a udržuje morálku.", - }, - { - "Jak Paul a spolužáci přišli k armádě?", - { - "Byli verbováni násilím", - "Nechali se strhnout Kantorekovou propagandou", - "Byli odsouzeni soudem", - "Byli cizinci", - }, - 1, - "Učitel Kantorek je nabádal k dobrovolnému odchodu – „železný mladý muž“.", - }, - { - "Co symbolizuje Kantorek?", - { - "Moudrého mentora", - "Válečnou propagandu a lži z domova", - "Lékařskou etiku", - "Náboženský mír", - }, - 1, - "Kantorek reprezentuje romantizaci války, kterou fronta vyvrací.", - }, - { - "Jak Paul vnímá Himmelstosse na začátku?", - { - "Jako hrdinu", - "Jako tyrana ve výcviku", - "Jako otce", - "Jako lékaře", - }, - 1, - "Himmelstoss šikanuje rekruty; později fronta i jeho mění.", - }, - { - "Co se stane Kemmerichovi?", - { - "Stane se generálem", - "Umírá po amputaci; Paul je u něj", - "Desertuje", - "Síní Nobelovu cenu", - }, - 1, - "Kemmerichova smrt je jedna z prvních tvrdých lekcí – boty přejdou Müllerovi.", - }, - { - "Proč Müller chce Kemmerichovy boty?", - { - "Sbírá umění", - "Na frontě je praktické vybavení důležitější než sentiment", - "Je obchodník", - "Nenávidí Kemmericha", - }, - 1, - "Román ukazuje, jak válka redukuje vztahy na přežití a věci.", - }, - { - "Co Paul prožije v zákopu s francouzským vojákem?", - { - "Šachovou partii", - "Zabije Duvala a lituje – vidí v něm člověka, ne nepřítele", - "Svatbu", - "Kněžské vysvěcení", - }, - 1, - "Scéna s Duvelem zhumanizuje „nepřítele“ a zdůrazní absurditu války.", - }, - { - "Jak Paul reaguje na návštěvu domova?", - { - "Cítí se jako hrdina", - "Cítí se cizí; civilisté nechápou frontu", - "Zůstane navždy doma", - "Stane se ministrem", - }, - 1, - "Matka, otcové, učitelé žijí v jiném světě – Paul už mezi nimi nepatří.", - }, - { - "Co je hlavní hodnotou ve squatu?", - { - "Kariéra", - "Kamarádství a solidarita", - "Sběr medailí", - "Psaní básní pro tisk", - }, - 1, - "Vojáci si dělí jídlo, kryjí se a vydrží jen díky sobě navzájem.", - }, - { - "Jak končí Kat?", - { - "Generál armády", - "Umírá – Paul ho nese a přitom Kat dostává střelu do hlavy", - "Emigruje do USA", - "Stane se učitelem", - }, - 1, - "Smrt Kata je pro Paula zlom – ztrácí poslední pevnou oporu.", - }, - { - "Jaký je původní německý název a co znamená?", - { - "Im Osten alles Neu", - "Im Westen nichts Neues – na západě nic nového", - "Kein Krieg", - "Der Frieden", - }, - 1, - "Vojenská zpráva hlásí klid – ironie vůči masovému mýlu o velkých zprávách z fronty.", - }, - { - "Jak zemře Paul Bäumer?", - { - "Ve stáří doma", - "Krátce před koncem války – klidně, téměř bez bolesti", - "V duelu", - "V letecké nehodě jako pilot", - }, - 1, - "Paul padne v říjnu 1918; report zní, že na západě není nic nového.", - }, - { - "Které téma román nejvíc zdůrazňuje?", - { - "Slávu války", - "Zničení mladé generace a nesmysl války", - "Růst hospodářství", - "Středověké rytířství", - }, - 1, - "Remarque ukazuje fyzické i psychické zničení a prázdnotu válečných hesel.", - }, - { - "Co je typickým prostředím děje?", - { - "Salóny a plesy", - "Zákopy, dělostřelectvo, plynové útoky", - "Univerzitní kampus", - "Moře a piráti", - }, - 1, - "Chronotopem je fronta – bláto, kryty, hlod, strach.", - }, - { - "Jak román líčí autoritu armády?", - { - "Jako vždy spravedlivou", - "Jako součást systému, který žere lidi", - "Jako neexistující", - "Jako komedii bez násilí", - }, - 1, - "Disciplína, šikana i absurdita rozkazů patří k obrazu války.", - }, - { - "Proč Paul nemůže „normálně“ studovat?", - { - "Nemá peníze", - "Válka ho odtrhla od mládí a znalostí", - "Je v exilu", - "Je slepý od narození", - }, - 1, - "Paul říká, že jeho generace stojí před propastí – válka jim vzala budoucnost.", - }, - { - "Co znamená „ztráta generace“?", - { - "Emigrace do Ameriky", - "Mladí muži zničeni dřív, než stihnou dospět do života", - "Ztráta knih", - "Demografický baby boom", - }, - 1, - "Termín popisuje trauma 1. světové války – mrtví i psychicky zlomení.", - }, - { - "Jak je zobrazeno násilí?", - { - "Romanticky", - "Věcně, drsně, bez glorifikace", - "Jen jako metafora", - "Vůbec se neobjevuje", - }, - 1, - "Remarque popisuje zranění, strach a smrt matter-of-fact stylem.", - }, - { - "Kdo je Tjaden?", - { - "Paulův spolužák a voják ve squatu", - "Ruský car", - "Lékař", - "Novinář", - }, - 0, - "Tjaden patří k Paulově partě – typický „malý“ voják fronty.", - }, - { - "Proč je román důležitý pro maturitu?", - { - "Je učebnicí chemie", - "Ukazuje 1. světovou válku, ich-formu a antiválečná témata", - "Je právní kód", - "Je atlas", - }, - 1, - "U maturity: autor, kontext, postavy, vypravěč, témata a jazyk.", - }, - { - "Jaký vztah mají vojáci k rozkazům?", - { - "Vždy je chápou jako smysluplné", - "Často vidí absurditu, ale poslušnost je nutná k přežití", - "Vždy desertují", - "Rozkazy neexistují", - }, - 1, - "Paul poslouchá, ale uvnitř ví, že mnoho bojů nemá logiku.", - }, - { - "Co Paul cítí k lidem doma, kteří válku oslavují?", - { - "Obdiv", - "Hořkost a vztek – nechápou realitu", - "Lhostejnost bez emocí", - "Radost", - }, - 1, - "Kantorek a podobní mluví o cti, zatímco vojáci umírají v blátě.", - }, - { - "Jaký je styl vyprávění?", - { - "Epický vypravěč bez já", - "Ich-forma, přímá zkušenost Paula", - "Dopisový deník cizí osoby", - "Drama bez prózy", - }, - 1, - "Paulův hlas dává románu autenticitu a subjektivní tíhu.", - }, - { - "Které tvrzení o Müllerovi je správné?", - { - "Je Paulův učitel", - "Je spolužák; praktický, chce Kemmerichovy boty", - "Je francouzský špion", - "Je námořník", - }, - 1, - "Müller reprezentuje tvrdost fronty – přežití je důležitější než sentiment.", - }, - { - "Co není typické pro Remarqueův obraz fronty?", - { - "Strach a únava", - "Kamarádství", - "Glorifikace hrdinských bitev bez krve", - "Smrt kamarádů", - }, - 2, - "Román právě boj proti slavnostnímu obrazu války.", - }, - { - "Kdy román poprvé vyšel?", - { - "1914", - "1929", - "1945", - "2000", - }, - 1, - "Vydání 1929 – meziválečí reakce na trauma 1. světové války.", - }, - { - "Jaký význam má závěr s Paulovou smrtí?", - { - "Válka je vítězstvím", - "Jednotlivec je obětí systému; zpráva o „klidu“ je krutá ironie", - "Paul se stane legendou", - "Válka pokračuje věčně v textu", - }, - 1, - "Paul umírá těsně před koncem – osobní ztráta vs. anonymní válečná zpráva.", - }, - { - "Která postava NEPATŘÍ k Paulově partě?", - { - "Kat", - "Kropp", - "Kantorek jako voják v partě", - "Tjaden", - }, - 2, - "Kantorek zůstává doma jako symbol propagandy, ne bojuje v jejich squatu.", - }, -}; - -static const AssemblyItem book_na_zapadni_fronte_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Kantorek nabádá mladíky k odchodu na frontu", - "Výcvik u Himmelstosse a první ztráty (Kemmerich)", - "Život ve squatu, Kat jako opora", - "Paul zabije francouzského vojáka Duvala", - "Návštěva domova a odcizení", - "Smrt Kata a Paulova smrt krátce před koncem války", - }, - 6, - }, -}; - -static const char *book_na_zapadni_fronte_plot_meaning[] = { - "Správné pořadí: propaganda → výcvik a ztráty → fronta s Katem → Duval → domov → smrt Kata a Paula.", -}; - -static const LitQ book_navsteva_stare_damy_qs[] = { - { - "Kdo napsal Návštěvu staré dámy?", - { - "Brecht", - "Friedrich Dürrenmatt", - "Goethe", - "Kafka", - }, - 1, - "Švýcarský dramatik; hra 1956.", - }, - { - "Jak se jmenuje městečko?", - { - "Güllen", - "Verona", - "Praha", - "Gütersloh", - }, - 0, - "Fiktivní Güllen je v zoufalé ekonomické situaci.", - }, - { - "Kdo přijede jako miliardářka?", - { - "Claire Zachanassian", - "Lady Catherine", - "Helena Glory", - "Julie", - }, - 0, - "Claire se vrací po letech jako neuvěřitelně bohatá.", - }, - { - "Kdo je Alfred Ill?", - { - "Starosta", - "Obchodník, bývalý Clairein milenec", - "Kněz", - "Robot", - }, - 1, - "Ill kdysi zradil Claire – nyní je terč pomsty.", - }, - { - "Co Claire nabídne městu?", - { - "Miliardu, pokud Ill zemře", - "Bezplatnou školu", - "Armádu", - "Nic", - }, - 0, - "Podmínka je Illova smrt – obec má rozhodnout.", - }, - { - "Proč Claire nenávidí Illa?", - { - "Kdysi ji opustil a zničil reputaci (s falešnými svědky)", - "Ill ji okradl o dům", - "Ill je cizinec", - "Bez důvodu", - }, - 0, - "Mladá Claire byla ponižována – Ill zaplatil svědky.", - }, - { - "Jak reagují občané zpočátku?", - { - "Odmítnou peníze", - "Protestují morálně, ale brzy kupují na dluh", - "Utečou", - "Zavraždí Claire", - }, - 1, - "Hypokrizie – nejdřív cti, pak nákupy na úvěr.", - }, - { - "Kdo Ill varuje?", - { - "Nikdo", - "Ill sám cítí, že město ho obětuje", - "Claire", - "Císař", - }, - 1, - "Ill postupně chápe, že Güllen ho odsoudí.", - }, - { - "Jak Ill zemře?", - { - "Přirozeně ve spánku", - "Obec ho odsoudí a zabije (justiční fraška)", - "V autonehodě", - "Na frontě", - }, - 1, - "Město formálně „soudí“ a popraví Illa pro miliardu.", - }, - { - "Jaký je žánr?", - { - "Tragikomedie / drama", - "Pohádka", - "Sci-fi román", - "Epos", - }, - 0, - "Dürrenmatt mísí grotesku, humor a tragédii.", - }, - { - "Co symbolizují nákupy občanů?", - { - "Prospěch za cenu morálky", - "Dobročinnost", - "Sport", - "Vědu", - }, - 0, - "Každý si koupí na dluh – už přijal Illovu smrt.", - }, - { - "Kdo jsou Klodi a Lobi?", - { - "Claireini slepí pomocníci", - "Illovi synové", - "Starostovi psi", - "Lékaři", - }, - 0, - "Groteskní postavy Claireina doprovodu.", - }, - { - "Proč je hra důležitá pro maturitu?", - { - "Učí chemii", - "Dürrenmatt, morálka, pomsta, tragikomedie", - "Je mapa", - "Je cookbook", - }, - 1, - "U maturity: děj, postavy, témata kolektivní viny.", - }, - { - "Kdy hra vznikla?", - { - "1956", - "1836", - "1595", - "2020", - }, - 0, - "Poválečná reflexe bohatství a morálky.", - }, - { - "Jak starosta mluví o cti?", - { - "Zpočátku odmítá, pak mlčí a přijme", - "Vždy odmítá", - "Je Illův bratr", - "Neexistuje", - }, - 0, - "Politik typicky capituluje před penězi.", - }, - { - "Co učitel ztělesňuje?", - { - "Intelektuální protest, který selže", - "Vítězství morálky", - "Válku", - "Roboty", - }, - 0, - "Učitel chápe problém, ale neodolá systému.", - }, - { - "Které téma NENÍ typické?", - { - "Pomsta", - "Kolektivní vina", - "Vesmírná válka robotů", - "Materiální zkaženost", - }, - 2, - "Roboti nejsou téma Dürrenmattovy hry.", - }, - { - "Proč Claire nepotřebuje peníze?", - { - "Už je nejbohatší – jde o pomstu", - "Je chudá", - "Je dítě", - "Peníze neexistují", - }, - 0, - "Nabízí miliardu městu, ne sobě – chce spravedlnost.", - }, - { - "Jak končí hra?", - { - "Ill přežije", - "Ill je mrtvý, město bohatne – morální prohra", - "Güllen shoří", - "Claire se provdá za Illa", - }, - 1, - "Tragikomická pointa – ekonomický „ráj“ na vraždě.", - }, - { - "Kde Dürrenmatt pochází / působí?", - { - "Švýcarsko", - "Rusko", - "Česko", - "Japonsko", - }, - 0, - "Friedrich Dürrenmatt je švýcarský autor.", - }, - { - "Co je groteska v Návštěvě?", - { - "Absurdní poměr ceny a morálky", - "Pouze romantika", - "Realismus bez humoru", - "Pohádka pro děti", - }, - 0, - "Miliarda za život – groteskní obchod.", - }, - { - "Kdo je Ill v obci?", - { - "Respektovaný občan, kandidát na starostu", - "Cizinec", - "Dítě", - "Kněz", - }, - 0, - "Právě jeho „cti“ je obětováno.", - }, - { - "Jak občané ospravedlňují zločin?", - { - "Ekonomickou nouzí a kolektivním rozhodnutím", - "Náboženstvím", - "Válka", - "Náhodou", - }, - 0, - "Chudoba Güllenu je Dürrenmattova motivace.", - }, - { - "Která postava NENÍ v Návštěvě?", - { - "Claire", - "Ill", - "Švejk", - "Starosta", - }, - 2, - "Švejk je Haškův hrdina.", - }, - { - "Kolik dějství má hra?", - { - "3", - "5", - "1", - "12", - }, - 0, - "Klasická třídělná dramatická stavba.", - }, - { - "Co Ill cítí v průběhu hry?", - { - "Stále větší osamění a strach", - "Radost", - "Nic", - "Vítězství", - }, - 0, - "Ill ví, že město už rozhodlo.", - }, - { - "Jaký kontrast hra vystavuje?", - { - "Chudoba vs. miliarda; morálka vs. peníze", - "Moře vs. hory", - "Den vs. noc", - "Práce vs. lenost", - }, - 0, - "Základní konflikt Návštěvy staré dámy.", - }, - { - "Proč je Ill „starý“ v titulku?", - { - "Claire je starší dáma vracející se pomstít mladistvé křivdě", - "Ill je stařec", - "Titul ne souvisí", - "Jde o babičku Illa", - }, - 0, - "Návštěva bohaté starší ženy mění osud města.", - }, - { - "Které dílo NENÍ Dürrenmattovo?", - { - "Návštěva staré dámy", - "Fyzici", - "R.U.R.", - "Ministryně", - }, - 2, - "R.U.R. napsal Karel Čapek.", - }, - { - "Jaký morální test hra klade?", - { - "Zda společnost prodá život za peníze", - "Zda umíte plavat", - "Zda znáte latinu", - "Zda vaříte", - }, - 0, - "Güllen selže – universalní varování.", - }, -}; - -static const AssemblyItem book_navsteva_stare_damy_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Claire Zachanassian přijede do Güllenu", - "Nabídne miliardu za Illovu smrt", - "Občané protestují, ale začnou nakupovat na dluh", - "Ill chápe, že je odsouzen", - "Město Illa formálně odsoudí", - "Ill zemře, Güllen dostane miliardu", - }, - 6, - }, -}; - -static const char *book_navsteva_stare_damy_plot_meaning[] = { - "Správné pořadí: příjezd Claire → nabídka → nákupy → Illův strach → soud → smrt a peníze.", -}; - -static const LitQ book_nebe_nezna_vyvolenych_qs[] = { - { - "Kdo napsal Nebe nezná vyvolených?", - { - "Erich Maria Remarque", - "Hemingway", - "Hrabal", - "Kafka", - }, - 0, - "Remarque po válce a emigrantských tématech.", - }, - { - "Kdy román vyšel?", - { - "1961", - "1929", - "1945", - "2000", - }, - 0, - "Německy Der Himmel kennt keine Günstlinge.", - }, - { - "Kdo je Ravic?", - { - "Německý emigrant a lékař", - "Francouzský generál", - "Nacista", - "Dítě", - }, - 0, - "Ravic uprchl před režimem a pracuje v Paříži ilegálně.", - }, - { - "Kdo je Joan Madou?", - { - "Ravicova milovaná", - "Gestapanka", - "Královna", - "Učitelka", - }, - 0, - "Joan je křehká postava lásky ve válce.", - }, - { - "Kde se děj převážně odehrává?", - { - "Paříž a okolí emigrace", - "Praha 1348", - "Verona", - "Moskva", - }, - 0, - "Emigrantská Paříž za 2. světové války.", - }, - { - "Co znamená titul?", - { - "Bohatí vyhrávají", - "Osud nešetří nikoho – nebe nemá oblíbence", - "Nebe je modré", - "Titul bez významu", - }, - 1, - "I láska a dobré úmysly končí tragicky.", - }, - { - "Jaký je vztah k Na západní frontě klid?", - { - "Stejný autor – válka a ztráta", - "Stejný děj", - "Kafka napsal oba", - "Bez souvislosti", - }, - 0, - "Remarque pokračuje v humanistických válečných tématech.", - }, - { - "Proč je Ravic v nebezpečí?", - { - "Emigrant bez dokladů, hrozí gestapo", - "Je bohatý", - "Je král", - "Je na dovolené", - }, - 0, - "Bezpapírovost znamená neustálý strach.", - }, - { - "Kdo je Boris Morosow?", - { - "Ravicův přítel v emigraci", - "Nacista", - "Joanin bratr", - "Robot", - }, - 0, - "Boris sdílí osud uprchlíků.", - }, - { - "Jak román končí pro Joan?", - { - "Šťastně v Americe", - "Tragicky umírá", - "Stane se lékařkou", - "Vdá se za jiného", - }, - 1, - "Tragický konec potvrzuje titul – osud nešetří.", - }, - { - "Jaký je hlavní konflikt?", - { - "Láska a přežití vs. válka a pronásledování", - "Sport", - "Robotí vzpoura", - "Středověké turnaje", - }, - 0, - "Emigranti hledají lidskost uprostřed války.", - }, - { - "Proč je román důležitý pro maturitu?", - { - "Učí chemii", - "Remarque, 2. sv. válka, emigrace, láska, osud", - "Je atlas", - "Je cookbook", - }, - 1, - "U maturity: autor, postavy, témata, kontext.", - }, - { - "Jak Ravic pomáhá lidem?", - { - "Jako lékař i v ilegalitě", - "Jako generál", - "Jako kněz", - "Nepomáhá", - }, - 0, - "Lékařská etika přetrvává navzdory riziku.", - }, - { - "Co je typické pro Remarqueův styl?", - { - "Prožitková ich/er próza, jednoduchost a cit", - "Pouze humor Haška", - "Drama Shakespeara", - "Sci-fi", - }, - 0, - "Remarque píše srozumitelně o těžkých tématech.", - }, - { - "Které téma NENÍ typické?", - { - "Emigrace", - "Láska", - "Vzpoura robotů R.U.R.", - "Válka", - }, - 2, - "Roboti nepatří k Remarqueovi.", - }, - { - "Co hrozí emigrantům?", - { - "Zatčení, udání, deportace", - "Pouze daň", - "Sport", - "Nic", - }, - 0, - "Gestapo a kolaborace – stálý strach.", - }, - { - "Jaký je vztah Ravic–Joan?", - { - "Láska v nestabilním světě", - "Sourozenci", - "Nepřátelé", - "Učitel–žák", - }, - 0, - "Krátké štěstí uprostřed nejistoty.", - }, - { - "Která postava NENÍ v románu?", - { - "Ravic", - "Joan", - "Paul Bäumer jako hlavní hrdina tohoto románu", - "Boris", - }, - 2, - "Paul Bäumer je hrdina Na západní frontě klid.", - }, - { - "Co symbolizuje „vyvolení“ v titulku?", - { - "Iluzi, že osud někoho chrání", - "Sportovní tým", - "Náboženský řád", - "Banku", - }, - 0, - "Nikdo není chráněn – ani milenci.", - }, - { - "Jaká válka formuje děj?", - { - "2. světová", - "Thirty years war only", - "Antická", - "Budoucí sci-fi", - }, - 0, - "Nacismus a emigrace jsou klíčové.", - }, - { - "Kde Remarque často situoval emigranty?", - { - "Západní Evropa (Paříž)", - "Antarktida", - "Měsíc", - "Pouze Berlín", - }, - 0, - "Paříž je centrum exilu v románu.", - }, - { - "Jaký tón má závěr?", - { - "Tragický", - "Čistá komedie", - "Beletrie pro děti", - "Technický manuál", - }, - 0, - "Remarque neustále balancuje naději a ztrátu.", - }, - { - "Co je „bezpapírovost“?", - { - "Stav ilegality bez ochrany státu", - "Bohatství", - "Vojenský řád", - "Umění", - }, - 0, - "Bez dokladů jsi vydán na milost okolností.", - }, - { - "Které dílo NENÍ Remarqueovo?", - { - "Nebe nezná vyvolených", - "Na západní frontě klid", - "Proměna", - "Tři kamarádi", - }, - 2, - "Proměnu napsal Kafka.", - }, - { - "Jak vyprávění funguje?", - { - "Er-forma, soustředěná na prožitky", - "Drama pěti dějství", - "Epos", - "Pouze dopisy", - }, - 0, - "Remarque využívá klasickou prózu.", - }, - { - "Proč Joan patří k „křehkým“ postavám?", - { - "Osud ji zasáhne tvrdě navzdory lásce", - "Je nezranitelná", - "Je robot", - "Je generál", - }, - 0, - "Joan ztělesňuje zranitelnost ve válce.", - }, - { - "Co emigrantská komunita sdílí?", - { - "Strach, pomoc, osud", - "Pouze bohatství", - "Válku proti robotům", - "Sport", - }, - 0, - "Solidarita i zrada – reálný exil.", - }, - { - "Jaký humanismus Remarque prosazuje?", - { - "Soucit s oběťmi války a pronásledování", - "Válka je sláva", - "Pouze moc", - "Technokracie", - }, - 0, - "Lidé na útěku zůstávají lidmi.", - }, - { - "Které období autor prožil?", - { - "1. i 2. světová válka, emigrace", - "Středověk", - "Antika", - "Jen 21. století", - }, - 0, - "Remarque znal válku i exil z vlastní zkušenosti.", - }, - { - "Co čtenář má po dočtení cítit?", - { - "Váhu osudu a křehkosti míru", - "Pouze smích", - "Návod na daň", - "Nic", - }, - 0, - "Román je varování i elegie.", - }, -}; - -static const AssemblyItem book_nebe_nezna_vyvolenych_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Ravic jako emigrant v Paříži", - "Seznámení s Joan a láska", - "Ilegální lékařská pomoc a strach z gestapa", - "Přátelství s Borisem, útěky a úkryty", - "Krátké štěstí milenců", - "Tragický osud Joan – nebe nešetří", - }, - 6, - }, -}; - -static const char *book_nebe_nezna_vyvolenych_plot_meaning[] = { - "Správné pořadí: exil → láska → ilegalita → přátelství → štěstí → tragický konec.", -}; - -static const LitQ book_o_mysich_a_lidech_qs[] = { - { - "Kdo napsal O myších a lidech?", - { - "Hemingway", - "John Steinbeck", - "Fitzgerald", - "Twain", - }, - 1, - "Steinbeck, 1937 – klasika americké sociální prózy.", - }, - { - "Kdo je Lennie Small?", - { - "Silný muž s mentálním postižením", - "Majitel ranch", - "Kněz", - "Detektiv", - }, - 0, - "Lennie je fyzicky silný, ale důvěřivý a neschopný.", - }, - { - "Kdo je George?", - { - "Lennieho ochránce a přítel", - "Curley", - "Šerif", - "Lékař", - }, - 0, - "George Lennie vede a chrání ho.", - }, - { - "O jaký sen usilují?", - { - "Vlastní farma a „žít ze své půdy“", - "Let do vesmíru", - "Královský trůn", - "Robotí továrna", - }, - 0, - "Sen o králících a soběstačnosti.", - }, - { - "Proč Lennie miluje měkké zvířata?", - { - "Rád je hladí, ale neovládá sílu", - "Nenávidí zvířata", - "Je veterinář", - "Je alergický", - }, - 0, - "Nešťastně zabíjí myši i psa – sila bez kontroly.", - }, - { - "Kdo je Curley?", - { - "Agresivní syn majitele ranch", - "Lennieho bratr", - "Učitel", - "Emigrant", - }, - 0, - "Curley provokuje Lennieho.", - }, - { - "Co se stane Curleyově ruce?", - { - "Lennie ji zlomí v sebeobraně", - "Spadne z koně", - "Amputace v nemocnici", - "Nic", - }, - 0, - "Lennie v panice zmačká Curleyovu ruku.", - }, - { - "Kdo je Crooks?", - { - "Černý stableman vyloučený rasismem", - "Majitel", - "Curley", - "George", - }, - 0, - "Crooks žije sám v stáji – téma osamělosti.", - }, - { - "Kdo je Candy?", - { - "Starý dělník se starým psem", - "Dítě", - "Curleyova žena", - "Kněz", - }, - 0, - "Carlson Candyho psa zastřelí – předobraz konce.", - }, - { - "Proč Carlson zastřelí Candyho psa?", - { - "Je starý a trpí – „milosrdné“ zabití", - "Pes kousl", - "Pes byl bohatý", - "Na rozkaz", - }, - 0, - "Scéna předznamenává Georgeovo rozhodnutí.", - }, - { - "Co Lennie udělá Curleyově ženě?", - { - "Omylem ji zabije při hladění vlasů", - "Ožení se s ní", - "Uteče s ní", - "Nic", - }, - 0, - "Tragická náhoda – Lennie nechápe sílu.", - }, - { - "Jak George končí s Lenniem?", - { - "Zastřelí ho milosrdně, než ho lynch mob", - "Opustí ho", - "Pošle do vězení", - "Neudělá nic", - }, - 0, - "George zabije Lennie sám – akt lásky a bolesti.", - }, - { - "Kdy román vyšel?", - { - "1937", - "1957", - "1915", - "2005", - }, - 0, - "Období Velké krize.", - }, - { - "Kde se děj odehrává?", - { - "Kalifornie, ranch", - "Praha", - "Verona", - "Sibiř", - }, - 0, - "Migrantní dělníci na farmě.", - }, - { - "Jaký je hlavní konflikt?", - { - "Sen vs. realita; Lennieho neschopnost", - "Válka robotů", - "Královský spor", - "Detektivka", - }, - 0, - "Přátelství a sen narazí na tragédii.", - }, - { - "Proč je román důležitý pro maturitu?", - { - "Učí chemii", - "Steinbeck, Velká krize, postavy, sen, tragédie", - "Je atlas", - "Je cookbook", - }, - 1, - "U maturity: autor, postavy, témata osamělosti.", - }, - { - "Které téma NENÍ typické?", - { - "Osamělost", - "Přátelství", - "Vzpoura robotů", - "Sen o farmě", - }, - 2, - "Roboti nejsou Steinbeck.", - }, - { - "Co znamená název (od Burns)?", - { - "Plány myší i lidí často zmaří osud", - "Myši vládnou světu", - "Lidé jsou myši", - "Bez významu", - }, - 0, - "Parafráze básně – křehkost plánů.", - }, - { - "Jak Curleyova žena trpí?", - { - "Osamělostí na ranchi", - "Bohatstvím", - "Mocí", - "Nic", - }, - 0, - "Chce mluvit, sní o slávě – tragická postava.", - }, - { - "Kdo je Slim?", - { - "Respektovaný dělník na ranchi", - "Majitel banky", - "Nacista", - "Dítě", - }, - 0, - "Slim chápe Georgeovo rozhodnutí na konci.", - }, - { - "Jaký je styl Steinbecka?", - { - "Realismus, soucit, jednoduchost", - "Groteska Haška", - "Sci-fi", - "Epos", - }, - 0, - "Steinbeck píše o chudých s empatií.", - }, - { - "Která postava NENÍ v románu?", - { - "Lennie", - "George", - "Winston Smith", - "Candy", - }, - 2, - "Winston je z 1984.", - }, - { - "Proč George s Lenniem cestuje?", - { - "Hledají práci jako migranti", - "Jsou králové", - "Studují", - "Jsou na dovolené", - }, - 0, - "Velká krize – tuláci od ranch k ranchi.", - }, - { - "Co Lennie opakuje?", - { - "Georgeovy instrukce a sen o farmě", - "Latinské modlitby", - "Rozkazy Curleye", - "Nic", - }, - 0, - "Lennie se učí, co dělat „když se něco stane“.", - }, - { - "Jak končí sen o farmě?", - { - "Ztroskotá – Lennie i sen mrtví", - "Uskuteční se", - "Koupí město", - "Stane se sci-fi", - }, - 0, - "Tragédie – sen zůstane nedosažitelný.", - }, - { - "Které dílo NENÍ Steinbeckovo?", - { - "O myších a lidech", - "Na východ od ráje", - "Grapes of Wrath (Hrozny hněvu)", - "Revizor", - }, - 3, - "Revizor je Gogol.", - }, - { - "Co představuje psí zabití?", - { - "Předfiguraci milosrdného zabití Lennieho", - "Komediální vtip", - "Sport", - "Náboženský obřad", - }, - 0, - "Steinbeck připravuje čtenáře na konec.", - }, - { - "Jaký je vztah k Velké krizi?", - { - "Román zobrazuje chudobu a migraci", - "Ignoruje ekonomiku", - "Je fantasy", - "Je středověk", - }, - 0, - "Kontext 30. let je klíčový.", - }, - { - "Proč George neuteče s Lenniem?", - { - "Ví, že Lennie opakovat chybu – musí jednat", - "Nemá nohy", - "Je bohatý", - "Lennie je generál", - }, - 0, - "George přijme zodpovědnost – tragický akt.", - }, - { - "Jaký pocit zanechá závěr?", - { - "Soucit a bolest", - "Čistou radost", - "Smích bez důvodu", - "Nic", - }, - 0, - "Klasická americká tragédie chudých.", - }, -}; - -static const AssemblyItem book_o_mysich_a_lidech_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "George a Lennie přijdou na ranch", - "Sen o farmě, setkání s Curleyem", - "Lennie zlomí Curleyovu ruku", - "Carlson zastřelí Candyho psa", - "Lennie zabije Curleyovu ženu", - "George Lennie milosrdně zastřelí", - }, - 6, - }, -}; - -static const char *book_o_mysich_a_lidech_plot_meaning[] = { - "Správné pořadí: ranch → konflikt s Curleyem → ruka → pes → smrt ženy → milosrdná střela.", -}; - -static const LitQ book_obraz_doriana_graye_qs[] = { - { - "Kdo napsal Obraz Doriana Graye?", - { - "Dickens", - "Oscar Wilde", - "Austen", - "Brontë", - }, - 1, - "Wilde, irský autor, estet a dramatik.", - }, - { - "Co je zvláštní na Dorianově portrétu?", - { - "Stárne a kazí se místo Doriana", - "Je prázdný", - "Mění autora", - "Je fotografie", - }, - 0, - "Dorian zůstává mladý, vina se hromadí v obraze.", - }, - { - "Kdo portrét maluje?", - { - "Basil Hallward", - "Lord Henry", - "Sibyl", - "James", - }, - 0, - "Basil obdivuje Dorianovu krásu.", - }, - { - "Kdo Doriana morally kazí?", - { - "Lord Henry Wotton", - "Basil", - "Sibyl", - "Kněz", - }, - 0, - "Henry hlásá hedonismus a cynismus.", - }, - { - "Kdo je Sibyl Vane?", - { - "Herečka, kterou Dorian zničí", - "Malířka", - "Královna", - "Basilova sestra", - }, - 0, - "Dorian ji opustí – ona spáchá sebevraždu.", - }, - { - "Co Dorian přeje u portrétu?", - { - "Aby stárl obraz místo něj", - "Aby zmizel", - "Aby byl bohatý", - "Aby byl král", - }, - 0, - "Faustovská touha – splní se groteskně.", - }, - { - "Jak Dorian skrývá stárnutí?", - { - "Portrét schovává v pokoji", - "Operace", - "Kouzlo bez obrazu", - "Ne skrývá", - }, - 0, - "Obraz je tajné zrcadlo duše.", - }, - { - "Co se stane Basilovi?", - { - "Dorian ho zavraždí", - "Basil se stane králem", - "Emigruje", - "Nic", - }, - 0, - "Basil konfrontuje Doriana – Dorian ho zabije.", - }, - { - "Kdo hledá pomstu?", - { - "James Vane, bratr Sibylin", - "Lord Henry", - "Basil", - "Sibyl", - }, - 0, - "James pronásleduje Doriana.", - }, - { - "Jak román končí?", - { - "Dorian bodne portrét a sám zemře stařec", - "Šťastná svatba", - "Dorian vládne", - "Obraz zmizí", - }, - 0, - "Katharsis – vina se vrátí na Doriana.", - }, - { - "Jaký je žánr?", - { - "Philosophický/gotický román", - "Válečný román", - "Sci-fi", - "Bajka", - }, - 0, - "Gotický prvek portrétu + estetická filozofie.", - }, - { - "Co znamená estetismus?", - { - "Umění a krása jako nejvyšší hodnota", - "Válka", - "Robotika", - "Asketa", - }, - 0, - "Wilde a Henry ztělesňují „umění pro umění“.", - }, - { - "Proč je kniha důležitá pro maturitu?", - { - "Učí chemii", - "Wilde, symbolika portrétu, morálka, estetika", - "Je atlas", - "Je cookbook", - }, - 1, - "U maturity: autor, postavy, symboly, témata.", - }, - { - "Kdy román poprvé vyšel?", - { - "1890/1891", - "1929", - "2000", - "1595", - }, - 0, - "Victoriánská éra, skandál kvůli morálce.", - }, - { - "Které téma NENÍ typické?", - { - "Krása a vina", - "Portrét jako zrcadlo", - "Vzpoura robotů", - "Hedonismus", - }, - 2, - "Roboti nejsou Wilde.", - }, - { - "Jak lord Henry mluví?", - { - "Epigramy, paradox, cynismus", - "Prostě bez stylu", - "Jen latinsky", - "Německy", - }, - 0, - "Wildeovy aforismy jsou slavné.", - }, - { - "Co Dorian sbírá?", - { - "Morální prach – skandály, zločiny", - "Známky", - "Roboty", - "Mapy", - }, - 0, - "Hedonismus vede k degeneraci.", - }, - { - "Kdo je James Vane?", - { - "Sibylin bratr", - "Malíř", - "Lord", - "Basil", - }, - 0, - "Pomsta za sestru.", - }, - { - "Jaký kontrast román staví?", - { - "Krása navenek vs. hnus duše", - "Moře vs. hory", - "Den vs. noc", - "Práce vs. lenost", - }, - 0, - "Základní gothic premise.", - }, - { - "Která postava NENÍ v románu?", - { - "Dorian", - "Henry", - "Elizabeth Bennet", - "Basil", - }, - 2, - "Elizabeth je Austenová.", - }, - { - "Co symbolizuje opium?", - { - "Únik a morální propad", - "Sport", - "Věda", - "Náboženský rituál", - }, - 0, - "Dorian hledá rozkoše v temnotě.", - }, - { - "Jak Wilde kritizuje společnost?", - { - "Přes hypokrizii a estetickou masku", - "Oslavou války", - "Bez myšlenky", - "Pouze humorem Haška", - }, - 0, - "Victoriánská puritánství vs. skrytá shniloba.", - }, - { - "Které dílo NENÍ Wildovo?", - { - "Obraz Doriana Graye", - "How I Became a Happy Ghost – ne; Importance of Being Earnest", - "Revizor", - "Ballad of Reading Gaol", - }, - 2, - "Revizor je Gogol.", - }, - { - "Proč Basil umírá?", - { - "Konfrontuje Doriana s pravdou o portrétu", - "Náhodou", - "Válka", - "Starost", - }, - 0, - "Dorian zabije svědka své duše.", - }, - { - "Jak vypadá Dorian navenek roky?", - { - "Stále mladý a krásný", - "Okamžitě starý", - "Jako dítě", - "Jako zvíře", - }, - 0, - "Zatímco obraz nesou věk a viny.", - }, - { - "Co čtenář má pochopit z konce?", - { - "Vina se nedá věčně přenést na obraz", - "Krása vítězí vždy", - "Umění je zbytečné", - "Nic", - }, - 0, - "Moralita se vrátí – Dorian platí.", - }, - { - "Jaký je vztah Basil–Dorian?", - { - "Basil obdivuje, Dorian zrazuje", - "Nepřátelé od začátku", - "Bratři", - "Učitel latiny", - }, - 0, - "Basilova láska ke kráse končí tragicky.", - }, - { - "Kde se děj odehrává?", - { - "Londýn a okolí", - "Praha", - "Verona", - "Sibiř", - }, - 0, - "Společenský život victoriánské metropole.", - }, - { - "Co je gotický prvek?", - { - "Prokletý portrét a tajemný pokoj", - "Robot", - "Válka", - "Komunismus", - }, - 0, - "Gotika: nadprirodzeno, vina, hrůza.", - }, - { - "Jak Wilde v románu pracuje s estetikou?", - { - "Klade krásu a umění proti morálce a pokání", - "Odmítá umění úplně", - "Píše jen učebnici", - "Popisuje pouze válku", - }, - 0, - "Lord Henry a Dorian ztělesňují estetismus – cena je morální shniloba.", - }, -}; - -static const AssemblyItem book_obraz_doriana_graye_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Basil maluje portrét, Dorian se setká s lordem Henrym", - "Dorian přeje, aby stárl obraz místo něj", - "Vztah se Sibyl Vane a její smrt", - "Dorian žije hedonisticky, obraz se kazí", - "Dorian zavraždí Basila", - "Dorian bodne portrét a sám zemře", - }, - 6, - }, -}; - -static const char *book_obraz_doriana_graye_plot_meaning[] = { - "Správné pořadí: portrét a Henry → přání → Sibyl → degenerace → vražda Basila → konec s portrétem.", -}; - -static const LitQ book_obsluhoval_jsem_qs[] = { - { - "Kdo napsal Obsluhoval jsem anglického krále?", - { - "Hašek", - "Bohumil Hrabal", - "Kundera", - "Neruda", - }, - 1, - "Hrabal, 1971 – jedna z maturitních četeb.", - }, - { - "Kdo vypravuje?", - { - "Jan Ditě, číšník", - "Anglický král", - "Švejk", - "Kafka", - }, - 0, - "Ich-forma Ditieho vzpomínek.", - }, - { - "Proč je v názvu „anglický král“?", - { - "Ditie obsluhuje i symboly moci (včetně exilového krále)", - "Děj je jen v Anglii", - "Ditie je král", - "Bez souvislosti", - }, - 0, - "Ironický titul – servírování mocných v historii.", - }, - { - "Jaké období román pokrývá?", - { - "20. století v Čechách", - "Středověk", - "Antika", - "Budoucnost", - }, - 0, - "Republika, protektorát, poválečí režimy.", - }, - { - "Co Ditie nejvíc touží?", - { - "Po uznání a velikosti", - "Po klidu v klášteře", - "Po válce", - "Po robotice", - }, - 0, - "Malý člověk chce být viděn a důležitý.", - }, - { - "Kdo je Líza?", - { - "Ditieho milovaná", - "Německá generálka", - "Učitelka", - "Robot", - }, - 0, - "Líza je spojena s Ditieho životem a vinou.", - }, - { - "Jaký je Hrabalův styl?", - { - "Dlouhé věty, groteska, humor", - "Strohý realismus bez obrazů", - "Hexametr", - "Drama", - }, - 0, - "Typická hrabalovská poetika.", - }, - { - "Kde Ditie pracuje?", - { - "V hotelech a hostincích", - "V dole", - "Na moři", - "V klášteře", - }, - 0, - "Číšnická dráha = pohled zdola.", - }, - { - "Co je kolaborace v románu?", - { - "Služba mocným v protektorátu", - "Sport", - "Věda", - "Nemoc", - }, - 0, - "Ditie se potácí mezi přežitím a morálkou.", - }, - { - "Kdo je Tichý Šimon?", - { - "Poválečný soudce Ditieho", - "Král", - "Německý generál", - "Dítě", - }, - 0, - "Symbol účtování po válce.", - }, - { - "Jak román pracuje s dějinami?", - { - "Anekdoticky z perspektivy servisu", - "Ignoruje je", - "Jen učebnicově", - "Sci-fi", - }, - 0, - "Velké dějiny v malých hotelových scénách.", - }, - { - "Proč je kniha důležitá pro maturitu?", - { - "Učí chemii", - "Hrabal, 20. stol., ich-forma, groteska, témata", - "Je atlas", - "Je cookbook", - }, - 1, - "U maturity: autor, kontext, Ditie, styl.", - }, - { - "Které téma NENÍ typické?", - { - "Touha po uznání", - "Dějiny zdola", - "Vzpoura robotů R.U.R.", - "Vinna", - }, - 2, - "Roboti nejsou Hrabal.", - }, - { - "Co je groteska u Hrabala?", - { - "Smích vedle hrůzy", - "Pouze pohádka", - "Bez humoru", - "Jen válka", - }, - 0, - "Typický Hrabalův mix.", - }, - { - "Jak Ditie vzpomíná?", - { - "Ve vzpomínkách číšníka na konci života", - "Jako dítě", - "Jako robot", - "Bez já", - }, - 0, - "Retrospektivní ich-forma.", - }, - { - "Která postava NENÍ Hrabalova?", - { - "Ditě", - "Miloš Hrma", - "Líza", - "Tichý Šimon", - }, - 1, - "Miloš Hrma je z Ostře sledovaných vlaků.", - }, - { - "Co symbolizuje hotel?", - { - "Jeviště setkání s mocí", - "Vězení", - "Kostel", - "Lesk bez významu", - }, - 0, - "Místo, kde malý člověk servíruje velkým.", - }, - { - "Jak končí Ditieho touha po velikosti?", - { - "Ironicky a tragicky – malost zůstane", - "Stane se králem", - "Vítězí vždy", - "Bez pointy", - }, - 0, - "Hrabal demaskuje iluzi slávy.", - }, - { - "Kdy román vyšel?", - { - "1971", - "1921", - "1890", - "2015", - }, - 0, - "Poválečná reflexe v normalizační době.", - }, - { - "Co je pikareskní rys?", - { - "Putování a epizody „lišáka“", - "Epos", - "Tragedie", - "Lyrika", - }, - 0, - "Ditie prochází místy a režimy.", - }, - { - "Jaký vztah k protektorátu?", - { - "Moralní krize servírování okupantům", - "Ignorace", - "Pouze hrdinství", - "Sci-fi", - }, - 0, - "Kolaborace jako téma.", - }, - { - "Které dílo NENÍ Hrabalovo?", - { - "Obsluhoval jsem anglického krále", - "Ostře sledované vlaky", - "Revizor", - "Příliš hlučná samota", - }, - 2, - "Revizor je Gogol.", - }, - { - "Proč ich-forma?", - { - "Subjektivní vinna a vzpomínka", - "Objektivní učebnice", - "Bez vypravěče", - "Drama", - }, - 0, - "Ditie sám bilancuje život.", - }, - { - "Co Ditie „obsluhuje“ metaforicky?", - { - "Moc a dějiny bez vlastní velikosti", - "Pouze jídlo", - "Roboty", - "Hvězdy", - }, - 0, - "Servis = podřízenost vůči moci.", - }, - { - "Jak Hrabal líčí malého člověka?", - { - "S humorem i soucitem", - "S nenávistí", - "Bez charakteru", - "Jako hrdinu války", - }, - 0, - "Typický Hrabalův přístup.", - }, - { - "Co je motiv syna / dítěte?", - { - "Naděje a ztráta v Ditieho životě", - "Robot", - "Král", - "Učitel", - }, - 0, - "Osobní rovina vedle historické.", - }, - { - "Jaký kontrast Hrabal používá?", - { - "Velké dějiny vs. hotelový servis", - "Moře vs. hory", - "Den vs. noc", - "Práce vs. lenost", - }, - 0, - "Základní poetika knihy.", - }, - { - "Kde se děj odehrává?", - { - "Čechy (hotely, okolí)", - "Verona", - "Londýn celý román", - "Mars", - }, - 0, - "České dějiny 20. století.", - }, - { - "Co čtenář má po dočtení?", - { - "Pochopení Hrabalovy grotesky a historie zdola", - "Návod na servis", - "Chemii", - "Nic", - }, - 0, - "Maturitní cíl – kontext a témata.", - }, - { - "Jak Ditie vnímá sebe?", - { - "Chce být velký, často je směšný", - "Vždy hrdina", - "Robot", - "Císař", - }, - 0, - "Tragičnost i komika ega.", - }, -}; - -static const AssemblyItem book_obsluhoval_jsem_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Mladý Ditě začíná jako číšník", - "Vzestup v hotelech, setkání s mocí", - "Protektorát – obsluha okupantů", - "Líza a osobní i politické krize", - "Poválečné soudy a Tichý Šimon", - "Bilance života malého člověka", - }, - 6, - }, -}; - -static const char *book_obsluhoval_jsem_plot_meaning[] = { - "Správné pořadí: začátky → vzestup → protektorát → Líza → soud → bilance.", -}; - -static const LitQ book_oliver_twist_qs[] = { - { - "Kdo napsal Oliver Twist?", - { - "Austen", - "Charles Dickens", - "Wilde", - "Brontë", - }, - 1, - "Dickens, 1837–1839 – sociální román.", - }, - { - "Kdo je Oliver?", - { - "Sirotek v Londýně", - "Král", - "Generál", - "Robot", - }, - 0, - "Hrdina nevinnosti v chudobě.", - }, - { - "Co Oliver řekne v sirotčinci?", - { - "Prosím, pane, chci ještě (jídla)", - "Chci válku", - "Jsem král", - "Nic", - }, - 0, - "Slavná scéna trestu za prosbu.", - }, - { - "Kdo je Fagin?", - { - "Vůdce gangu zlodějů", - "Kněz", - "Oliverův otec", - "Lékař", - }, - 0, - "Vychovává děti ke krádežím.", - }, - { - "Kdo je Bill Sikes?", - { - "Brutální lupič", - "Učitel", - "Brownlow", - "Dodger", - }, - 0, - "Násilník, partner Nancy.", - }, - { - "Kdo je Nancy?", - { - "Dívka z gangu, pomůže Oliverovi", - "Královna", - "Faginova sestra", - "Učitelka", - }, - 0, - "Tragická postava – zradí gang, zaplatí životem.", - }, - { - "Kdo je pan Brownlow?", - { - "Dobrodinec, který Olivera zachrání", - "Fagin", - "Sikes", - "Monks", - }, - 0, - "Symbol dobra střední třídy.", - }, - { - "Kdo je Monks?", - { - "Oliverův nevlastní bratr, chce ho zničit", - "Kněz", - "Dodger", - "Brownlow", - }, - 0, - "Intriky kvůli dědictví.", - }, - { - "Kdo je Artful Dodger?", - { - "Šikovný mladý zloděj ve Faginově gangu", - "Policista", - "Král", - "Lékař", - }, - 0, - "Vede Olivera do kriminality.", - }, - { - "Jak končí Oliver?", - { - "Šťastně u Brownlowa, pravda o původu", - "Vězení", - "Smrt", - "Gang navždy", - }, - 0, - "Dickensovský happy-end spravedlnosti.", - }, - { - "Jaký je hlavní konflikt?", - { - "Nevinnost vs. chudoba a kriminalita", - "Robotí válka", - "Středověk", - "Detektivka bez sociálního", - }, - 0, - "Sociální román 19. století.", - }, - { - "Proč maturita?", - { - "Dickens, sociální kritika, postavy", - "Chemie", - "Atlas", - "Cookbook", - }, - 0, - "Klasická světová literatura.", - }, - { - "Kde děj?", - { - "Londýn", - "Praha", - "Verona", - "Paříž", - }, - 0, - "Victoriánský Londýn.", - }, - { - "Které téma NENÍ typické?", - { - "Chudoba", - "Gang", - "Vzpoura robotů", - "Identita", - }, - 2, - "Čapek roboti ne.", - }, - { - "Co Dickens kritizuje?", - { - "Sirotčince a chudobu", - "Sport", - "Hudbu", - "Vědu", - }, - 0, - "Sociální nespravedlnost.", - }, - { - "Co se stane Nancy?", - { - "Sikes ji zabije", - "Stane se královnou", - "Emigruje", - "Nic", - }, - 0, - "Tragédie za pomoc Oliverovi.", - }, - { - "Která postava NENÍ v románu?", - { - "Fagin", - "Oliver", - "Elizabeth Bennet", - "Sikes", - }, - 2, - "Austenová.", - }, - { - "Jaký styl Dickens?", - { - "Realismus, sentiment, humor", - "Sci-fi", - "Epos", - "Drama antické", - }, - 0, - "Typický Dickens.", - }, - { - "Co je Oliverův původ?", - { - "Tajemství bohaté rodiny – odhaleno", - "Vždy chudý bez vysvětlení", - "Robot", - "Cizinec", - }, - 0, - "Intriky Monse.", - }, - { - "Kdy vyšel román?", - { - "1837–1839", - "1929", - "2000", - "1595", - }, - 0, - "Seriálové vydávání.", - }, - { - "Které dílo NENÍ Dickens?", - { - "Oliver Twist", - "David Copperfield", - "Revizor", - "Great Expectations", - }, - 2, - "Gogol.", - }, - { - "Proč Oliver unikne Faginovi?", - { - "Brownlow a Nancy pomáhají", - "Sám je generál", - "Kouzlo", - "Nikdy neunikne", - }, - 0, - "Boj dobra a zla.", - }, - { - "Co je victoriánská kritika?", - { - "Odhalení chudoby pod průmyslem", - "Oslava války", - "Sci-fi", - "Bez tématu", - }, - 0, - "Kontext 19. stol.", - }, - { - "Jak Fagin končí?", - { - "Poprava – trest za zločin", - "Král", - "Bohatý", - "Emigrace", - }, - 0, - "Dickensův morální soud.", - }, - { - "Co symbolizuje Oliver?", - { - "Nevinnost v špinavém světě", - "Válka", - "Robot", - "Nemoc", - }, - 0, - "Centrální metafora.", - }, - { - "Jak vyprávění?", - { - "Er-forma", - "Ich Oliver", - "Drama", - "Lyrika", - }, - 0, - "Klasický roman.", - }, - { - "Co je Dodger?", - { - "Mladý zloděj", - "Pes", - "Král", - "Učitel", - }, - 0, - "Artful = vychytralý.", - }, - { - "Jaký tón?", - { - "Sociální kritika + sentiment", - "Pouze horor", - "Beletrie bez emocí", - "Učebnice", - }, - 0, - "Dickens mísí slzy a humor.", - }, - { - "Proč sirotčinec?", - { - "Ukazuje krutost vůči dětem", - "Idyla", - "Sport", - "Věda", - }, - 0, - "Úvodní instituce zla.", - }, - { - "Co čtenář po dočtení?", - { - "Chápe Dickensovu sociální linii", - "Chemii", - "Nic", - "Mapu", - }, - 0, - "Maturitní cíl.", - }, -}; - -static const AssemblyItem book_oliver_twist_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Oliver v sirotčinci a prosba o jídlo", - "Útěk do Londýna, Faginův gang", - "Brownlow Olivera zachrání", - "Nancy pomáhá, Sikes ji zabije", - "Odhalení Monsových intrik", - "Oliverův happy-end a identita", - }, - 6, - }, -}; - -static const char *book_oliver_twist_plot_meaning[] = { - "Správné pořadí: sirotčinec → gang → Brownlow → Nancy → Monks → happy-end.", -}; - -static const LitQ book_ostre_sledovane_vlaky_qs[] = { - { - "Kdo napsal Ostře sledované vlaky?", - { - "Hašek", - "Bohumil Hrabal", - "Remarque", - "Kafka", - }, - 1, - "Hrabal, 1965 – film J. Menzela (1966).", - }, - { - "Kdo vypravuje?", - { - "Miloš Hrma", - "Hubička", - "Švejk", - "Ditě", - }, - 0, - "Ich-forma mladého výpravčího.", - }, - { - "Kdy a kde děj?", - { - "Protektorát, malá železniční stanice", - "1. sv. válka fronta", - "Regency Anglie", - "Verona", - }, - 0, - "Okupace a železnice.", - }, - { - "Co jsou „ostře sledované vlaky“?", - { - "Vlaky se zbraněmi pro frontu", - "Turistické vlaky", - "Vlaky do školy", - "Metro", - }, - 0, - "Němci hlídají dopravu materiálu.", - }, - { - "Kdo je Hubička?", - { - "Starší výpravčí, svůdník", - "Generál", - "Kněz", - "Dítě", - }, - 0, - "Hubička razítkuje tělo telegrafistky.", - }, - { - "Co je groteskní scéna s razítky?", - { - "Hubička obtiskne razítka na Zdeniččino tělo", - "Vlaky explodují", - "Miloš se stane králem", - "Nic", - }, - 0, - "Typická hrabalovská groteska.", - }, - { - "Proč Miloš pokusí sebe zabít?", - { - "Sexuální selhání a stud", - "Válka skončila", - "Rád", - "Na rozkaz", - }, - 0, - "Trauma dospívání ve válce.", - }, - { - "Kdo Miloše „zasvětí“?", - { - "Virginia / Viktoria Freie", - "Zdenička", - "Hubička", - "Přednosta", - }, - 0, - "Sexuální iniciace před finále.", - }, - { - "Jak končí novela?", - { - "Miloš se vrhne pod vlak (sabotáž/akt)", - "Svatba", - "Mír 1945 slavnostně", - "Miloš emigruje", - }, - 0, - "Malý čin odboje – kontroverzní hrdinství.", - }, - { - "Jaký je tón?", - { - "Groteska, humor, smrt", - "Pouze idyla", - "Epos", - "Učebnice", - }, - 0, - "Hrabal mísí erotiku, smích a válku.", - }, - { - "Kdo je přednosta?", - { - "Vedoucí stanice, holubi", - "Německý generál", - "Milošův otec", - "Robot", - }, - 0, - "Komická autorita stanice.", - }, - { - "Proč maturita?", - { - "Hrabal, protektorát, groteska, film", - "Chemie", - "Atlas", - "Cookbook", - }, - 0, - "Klasická česká maturitní četba.", - }, - { - "Které téma NENÍ typické?", - { - "Iniciace", - "Válka", - "Robotí vzpoura", - "Odboj", - }, - 2, - "R.U.R. je jiné dílo.", - }, - { - "Jaký film vznikl?", - { - "J. Menzel, Oscar 1967", - "Disney", - "Bez filmu", - "Hollywood 2020", - }, - 0, - "Slavná adaptace Hrabal–Menzel.", - }, - { - "Co je Zdenička?", - { - "Telegrafistka", - "Generálka", - "Královna", - "Učitelka", - }, - 0, - "Objekt Hubičkova žertu.", - }, - { - "Jak Miloš vnímá válku?", - { - "Přes osobní tělo a malou stanici", - "Jako generál", - "Ignoruje", - "Sci-fi", - }, - 0, - "Mikrokosmos okupace.", - }, - { - "Která postava NENÍ v novelě?", - { - "Miloš", - "Hubička", - "Josef Švejk jako výpravčí", - "Přednosta", - }, - 2, - "Švejk je Hašek.", - }, - { - "Co je ich-forma?", - { - "Vypráví Miloš", - "Er bez já", - "Drama", - "Epos", - }, - 0, - "Subjektivní pohled mladíka.", - }, - { - "Jaký kontrast Hrabal staví?", - { - "Sex a smrt / válka", - "Moře hory", - "Den noc", - "Práce lenost", - }, - 0, - "Základ grotesky.", - }, - { - "Kdy vyšlo?", - { - "1965", - "1921", - "1890", - "2010", - }, - 0, - "Před pražským jarem.", - }, - { - "Co symbolizuje vlak?", - { - "Válku a cíl činu", - "Pouze dopravu", - "Lásku", - "Nemoc", - }, - 0, - "Finále na kolejích.", - }, - { - "Které dílo NENÍ Hrabal?", - { - "Ostře sledované vlaky", - "Obsluhoval jsem anglického krále", - "Proměna", - "Příliš hlučná samota", - }, - 2, - "Kafka.", - }, - { - "Jak německá moc vystupuje?", - { - "Okupanti na stanici", - "Nepřítomní", - "Přátelé", - "Děti", - }, - 0, - "Kontext protektorátu.", - }, - { - "Co je „malé hrdinství“?", - { - "Ironický čin obyčejného mladíka", - "Generál vítězí", - "Bez činu", - "Robot", - }, - 0, - "Hrabal demýtizuje velké hrdiny.", - }, - { - "Proč groteska?", - { - "Válka je absurdní – smích i hrůza", - "Bez důvodu", - "Pohádka", - "Reklama", - }, - 0, - "Hrabalova poetika.", - }, - { - "Jaký věk má Miloš?", - { - "Mladý dospívající", - "Stařec", - "Dítě 5 let", - "Generál", - }, - 0, - "Iniciační věk.", - }, - { - "Co předchází finále?", - { - "Zkušenost s Virginii", - "Svatba", - "Mír", - "Exil", - }, - 0, - "Sexuální dospělost před činem.", - }, - { - "Jak čtenář chápe závěr?", - { - "Odvaha i absurdita malého činu", - "Čisté vítězství", - "Komise bez významu", - "Nic", - }, - 0, - "Otevřená interpretace odboje.", - }, - { - "Kde stanice?", - { - "České okolí (fiktivní stanice)", - "Paříž", - "Sibiř", - "Afrika", - }, - 0, - "Protektorátní krajina.", - }, - { - "Co NENÍ motiv?", - { - "Razítka", - "Vlaky", - "Středověké turnaje", - "Stud", - }, - 2, - "Turnaje nepatří sem.", - }, -}; - -static const AssemblyItem book_ostre_sledovane_vlaky_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Miloš nastoupí na stanici", - "Hubička a razítka, groteska", - "Milošův stud a pokus o sebevraždu", - "Léčení a setkání s Virginii", - "Sexuální iniciace", - "Miloš a vlak – ostře sledovaný čin", - }, - 6, - }, -}; - -static const char *book_ostre_sledovane_vlaky_plot_meaning[] = { - "Správné pořadí: stanice → Hubička → pokus → Virginie → iniciace → vlak.", -}; - -static const LitQ book_svejk_qs[] = { - { - "Kdo napsal Osudy dobrého vojáka Švejka za světové války?", - { - "Karel Čapek", - "Jaroslav Hašek", - "Bohumil Hrabal", - "Franz Kafka", - }, - 1, - "Autorem je Jaroslav Hašek; román zůstal nedokončený jeho smrtí v roce 1923.", - }, - { - "Proč je román nedokončený?", - { - "Autor ho záměrně nechal otevřený", - "Hašek zemřel dřív, než stihl dílo dokončit", - "Zákaz cenzury", - "Chybí poslední kapitola v tiskárně", - }, - 1, - "Hašek zemřel v roce 1923; kniha končí uprostřed Švejkova putování.", - }, - { - "Kdo je hlavní hrdina?", - { - "Nadporučík Lukáš", - "Josef Švejk", - "Poručík Dub", - "Bretschneider", - }, - 1, - "Josef Švejk je „dobrý voják“, který absurdní svět boří zdánlivou hloupostí.", - }, - { - "Co je Švejkování?", - { - "Vojenská disciplína", - "Předstíraná naivita a poslušnost, která systém rozbíjí", - "Pouze alkoholismus", - "Vlastenecká propaganda", - }, - 1, - "Švejk plní rozkazy tak, že je jejich absurdita zřejmá – chytrá maska hloupého.", - }, - { - "Kdo je nadporučík Lukáš?", - { - "Švejkův nadřízený a pán", - "Rakouský císař", - "Lékař", - "Novinář", - }, - 0, - "Lukáš Švejka „vlastní“ a často trpí důsledky jeho historek.", - }, - { - "Proč Švejk skončí v blázinci na začátku?", - { - "Zlodějna", - "Kvůli absurdním odpovědím na vojenské otázky – simuluje nebo projevuje blbost", - "Vražda", - "Desertace", - }, - 1, - "Scéna s rakouskými vs. ruskými monarchy satiricky ukazuje Švejkův „pacifismus“.", - }, - { - "Kdo je policejní rada Bretschneider?", - { - "Švejkův kamarád", - "Provokatér, který v hospodách vylákává „velezrady“", - "Kněz", - "Generál", - }, - 1, - "Bretschneider sbírá důkazy proti hostům – satira na politickou policii.", - }, - { - "Kdo je poručík Dub?", - { - "Maďarský patriot a donašeč", - "Švejkův bratr", - "Lékař", - "Císař", - }, - 0, - "Dub je kariérista, nenávidí Čechy a rád udává – karikatura vlastence.", - }, - { - "Jaký je vztah románu k 1. světové válce?", - { - "Oslavuje hrdinství", - "Satiricky ukazuje absurditu a nesmysl války", - "Ignoruje válku", - "Je pohádkou", - }, - 1, - "Hašek míří proti romantizaci války a monarchie.", - }, - { - "Kde Švejk často vypráví historky?", - { - "V kosmu", - "V hospodě, na marši, u autorit", - "Jen v kostele", - "Jen na soudu", - }, - 1, - "Dialog a anekdota jsou jádrem stylu – Švejk mluví a tím rozbíjí moc.", - }, - { - "Kdo je polní kurát Otto Katz?", - { - "Asketa", - "Pijan, hráč, „patriot“ s pochybnou minulostí", - "Generál", - "Dítě", - }, - 1, - "Katz satiricky zobrazuje církev a vlastenectví v armádě.", - }, - { - "Jaký stát je prostředím děje?", - { - "Československo 1938", - "Rakousko-Uhersko za 1. světové války", - "Sovětský svaz", - "Napoleonská Francie", - }, - 1, - "Švejk slouží císařské armádě – český malý člověk v mocnostech monarchie.", - }, - { - "Co je typickým stavebním prvkem textu?", - { - "Jeden souvislý thriller", - "Anekdota za anekdotou, odbočky a dialogy", - "Epický hexametr", - "Drama bez prózy", - }, - 1, - "Pikareskní forma – epizody a historky místo klasické zápletky.", - }, - { - "Proč Švejk nosí vozík s invalidou?", - { - "Je trest", - "Satirická epizoda – služba a absurdita", - "Je to sport", - "Je generál", - }, - 1, - "Mnoho epizod zesměšňuje vojenskou službu a nařízení.", - }, - { - "Jak Hašek líčí českého vojáka?", - { - "Jako slavného hrdinu", - "Jako chytrého přeživšího v absurdním systému", - "Jako zrádce vždy", - "Jako neviditelného", - }, - 1, - "Švejk reprezentuje českou zkušenost v cizí armádě – humor a odpor.", - }, - { - "Které téma NENÍ typické?", - { - "Satira na byrokracii", - "Válečný nonsens", - "Absolutní vážnost hrdinských eposů bez ironie", - "Hospodské historky", - }, - 2, - "Román je antihrdinský a komický, ne slavnostní epos.", - }, - { - "Jaký význam má humor v románu?", - { - "Jen zábava bez myšlenky", - "Odhaluje absurditu moci a války", - "Obhajuje válku", - "Nahrazuje děj úplně", - }, - 1, - "Smích je u Haška zbraní – čtenář vidí nesmysl systému.", - }, - { - "Kdo je Švejkův „nepřítel“ mezi důstojníky?", - { - "Lukáš vždy", - "Často Dub a různé kariéristy", - "Nikdo", - "Jen císař osobně", - }, - 1, - "Dub a podobní reprezentují malichernou moc a donášení.", - }, - { - "Co symbolizuje hospoda U kalicha?", - { - "Místo exekuce", - "Prostor lidové selské moudrosti a ironie", - "Banka", - "Škola", - }, - 1, - "Hospoda je kontrast k úředním a vojenským institucím.", - }, - { - "Jak Švejk reaguje na rozkazy?", - { - "Vždy desertuje", - "Poslušně je plní, ale způsobem, který odhalí absurditu", - "Ignoruje je úplně", - "Píše básně", - }, - 1, - "Zdánlivá poslušnost je forma odporu – jádro švejkování.", - }, - { - "Proč je román důležitý pro maturitu?", - { - "Je chemická tabulka", - "Česká klasika: satira, válka, styl anekdot, Švejk", - "Je mapa Evropy", - "Je zákoník", - }, - 1, - "U maturity: Hašek, kontext 1. sv. války, postavy, humor, švejkování.", - }, - { - "Kdy román vycházel?", - { - "1890", - "1921–1923", - "1968", - "2010", - }, - 1, - "První díly za Haškova života, dokončení zabránila smrt.", - }, - { - "Jaký je vztah k autobiografii?", - { - "Hašek sám znal armádu a absurditu války – silné autobiografické rysy", - "Čistá sci-fi", - "Antická legenda", - "Beletrie bez reálií", - }, - 0, - "Hašek prošel armádou a světem hospod – zkušenost v textu cítit.", - }, - { - "Co je pikareskní román?", - { - "Román o jednom dni", - "Putování rošťáka/lišáka epizodami", - "Lyrika", - "Tragedie", - }, - 1, - "Švejk prochází místy a situacemi, sbírá historky.", - }, - { - "Která postava je provokatér?", - { - "Bretschneider", - "Švejk", - "Lukáš", - "Katz", - }, - 0, - "Policejní rada Bretschneider vylákává výroky pro represi.", - }, - { - "Jak končí dílo v originálu?", - { - "Švejk vítězí nad válkou", - "Nedokončené – Švejk stále na cestě / ve válce", - "Svatba", - "Mír 1918 slavnostně", - }, - 1, - "Nedokončenost patří k osudu knihy – válka a putování pokračují.", - }, - { - "Co satiricky zobrazuje postava Katze?", - { - "Církev a vlastenectví v armádě", - "Vědu", - "Sport", - "Školství", - }, - 0, - "Polní kurát Katz je komická figura faráře-vojáka.", - }, - { - "Jaký jazyk je typický?", - { - "Knihovní archaismus", - "Hovorová čeština, argot, dialog", - "Latina celá kniha", - "Angličtina", - }, - 1, - "Hašek používá živou mluvu, hospodské výrazy a ironii.", - }, - { - "Které tvrzení o Lukášovi je správné?", - { - "Je Švejkův nadřízený, často trpí důsledky Švejkových akcí", - "Je císař", - "Je vždy klidný a bohatý", - "Nepozná Švejka", - }, - 0, - "Lukáš je „pán“ Švejka v systému služby – komický pár.", - }, - { - "Co Hašek kritizuje nejvíc?", - { - "Pouze počasí", - "Válku, monarchii, byrokracii a falešné vlastenectví", - "Pouze zemědělství", - "Sport", - }, - 1, - "Satira míří na mocenské struktury a válečný nonsens.", - }, - { - "Které dílo NENÍ Haškovo?", - { - "Osudy dobrého vojáka Švejka", - "Povídky z kapes", - "Ostro sledované vlaky", - "Dobrý voják Švejk – divadlo", - }, - 2, - "Ostře sledované vlaky napsal Bohumil Hrabal, ne Hašek.", - }, -}; - -static const AssemblyItem book_svejk_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Švejk a absurdní výslech – cesta do blázince", - "Hospoda, Bretschneider a Švejkův návrat k službě", - "Švejk u nadporučíka Lukáše v Praze", - "Cesta do Budějovic a další epizody na cestě", - "Služba u polního kuráta Katze a fronta", - "Putování pokračuje – román zůstává nedokončen", - }, - 6, - }, -}; - -static const char *book_svejk_plot_meaning[] = { - "Správné pořadí: blázinec → hospoda a služba → Lukáš → cesta na jih → Katz a fronta → nedokončené putování.", -}; - -static const LitQ book_pan_much_qs[] = { - { - "Kdo napsal Pána much?", - { - "Orwell", - "William Golding", - "Hemingway", - "Twain", - }, - 1, - "Lord of the Flies, 1954.", - }, - { - "Kdo je Ralph?", - { - "Zvolený vůdce, lastura", - "Lovec", - "Kněz", - "Učitel", - }, - 0, - "Snaží se udržet oheň a pravidla.", - }, - { - "Kdo je Jack?", - { - "Vůdce lovců, tyran", - "Ralphův bratr", - "Piggy", - "Simon", - }, - 0, - "Rozštěpuje skupinu.", - }, - { - "Kdo je Piggy?", - { - "Inteligentní, brýle", - "Generál", - "Pilot", - "Dospělý", - }, - 0, - "Symbol rozumu – tragicky zabit.", - }, - { - "Co je lastura?", - { - "Symbol moci a řeči na shromáždění", - "Zbraň", - "Loď", - "Jídlo", - }, - 0, - "Kdo drží lasturu, mluví.", - }, - { - "Co je „bestie“?", - { - "Strach a zlo v lidech, ne zvíře", - "Skutečný drak", - "Loď", - "Piggy", - }, - 0, - "Simon to pochopí jako projekci.", - }, - { - "Co se stane Simonovi?", - { - "Zabit v transu jako „bestie“", - "Král", - "Uteče", - "Lékař", - }, - 0, - "Lynč v nočním šílenství.", - }, - { - "Co je pán much?", - { - "Prase hlava na kůlu – symbol zla", - "Ralph", - "Loď", - "Lastura", - }, - 0, - "Titulní obraz degenerace.", - }, - { - "Jak končí Ralph?", - { - "Zachráněn námořníkem, pláč", - "Král ostrova", - "Smrt", - "S Jackem spřátelen", - }, - 0, - "Návrat civilizace – uvědomění zla.", - }, - { - "Jaký je žánr?", - { - "Alegorický román", - "Válečný", - "Sci-fi roboti", - "Bajka", - }, - 0, - "Alegorie lidské přirozenosti.", - }, - { - "Proč maturita?", - { - "Symboly, postavy, témata moci", - "Chemie", - "Atlas", - "Cookbook", - }, - 0, - "Častá maturitní četba.", - }, - { - "Co oheň?", - { - "Záchrana i ničení lesa", - "Bez významu", - "Jen hra", - "Nemoc", - }, - 0, - "Jack nechá hasnout signál.", - }, - { - "Kdo je Roger?", - { - "Krutý chlapec", - "Mírotvorce", - "Pilot", - "Kněz", - }, - 0, - "Překračuje morální hranice.", - }, - { - "Které téma NENÍ?", - { - "Moc", - "Strach", - "Robotí vzpoura", - "Civilizace vs. divokost", - }, - 2, - "R.U.R. jiné.", - }, - { - "Kdy vyšlo?", - { - "1954", - "1929", - "1836", - "2001", - }, - 0, - "Poválečná reflexe.", - }, - { - "Která postava NENÍ?", - { - "Ralph", - "Jack", - "Švejk", - "Piggy", - }, - 2, - "Hašek.", - }, - { - "Co brýle?", - { - "Oheň z brýlí – věda", - "Móda", - "Hra", - "Nic", - }, - 0, - "Piggy bez brýlí bezmocný.", - }, - { - "Jak Jack maluje tváře?", - { - "Maska divokosti a násilí", - "Sport", - "Nemoc", - "Bez významu", - }, - 0, - "Symbol odpoutání od morálky.", - }, - { - "Které dílo NENÍ Golding?", - { - "Pán much", - "1984", - "Inheritors", - "Pincher Martin", - }, - 1, - "Orwell.", - }, - { - "Co alegorie?", - { - "Ostrov = společnost bez moci", - "Historický dokument", - "Bez významu", - "Cookbook", - }, - 0, - "Chlapci = lidstvo.", - }, - { - "Proč letadlo?", - { - "Válka – chlapci uvízli", - "Turistika", - "Sci-fi", - "Bez kontextu", - }, - 0, - "Evakuace, nehoda.", - }, - { - "Co Piggyho smrt?", - { - "Pád civilizace na ostrově", - "Komise", - "Radost", - "Nic", - }, - 0, - "Roger zabije kamenem.", - }, - { - "Jak vyprávění?", - { - "Er-forma", - "Ich Ralph", - "Drama", - "Lyrika", - }, - 0, - "Klasický roman.", - }, - { - "Co námořní důstojník?", - { - "Návrat adult civilizace", - "Bestie", - "Jack", - "Piggy", - }, - 0, - "Ironický konec – dospělí také válčí.", - }, - { - "Jaký konflikt Ralph–Jack?", - { - "Řád vs. lov a moc", - "Láska", - "Sport", - "Jazyk", - }, - 0, - "Demokracie vs. tyranie.", - }, - { - "Co Simon dělá?", - { - "Hledá pravdu o bestii", - "Generál", - "Pilot", - "Učitel", - }, - 0, - "Mystik, oběť davu.", - }, - { - "Jaký tón?", - { - "Temný realismus, alegorie", - "Pouze komedie", - "Idyla", - "Učebnice", - }, - 0, - "Golding varuje před zlem v lidech.", - }, - { - "Proč „muchy“?", - { - "Hniloba prase hlavy", - "Sport", - "Láska", - "Nemoc", - }, - 0, - "Obraz morálního rozkladu.", - }, - { - "Co čtenář po dočtení?", - { - "Chápe symboliku a téma zla", - "Chemii", - "Nic", - "Mapu", - }, - 0, - "Maturitní interpretace.", - }, - { - "Kde děj?", - { - "Tropický ostrov", - "Praha", - "Londýn", - "Verona", - }, - 0, - "Izolovaný mikrokosmos.", - }, -}; - -static const AssemblyItem book_pan_much_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Chlapci uvízli na ostrově, Ralph vůdce", - "Oheň a pravidla vs. Jackovi lovci", - "Strach z bestie roste", - "Simon zabit, Piggy zabit", - "Jack přebírá moc, hon na Ralpha", - "Záchrana námořníkem", - }, - 6, - }, -}; - -static const char *book_pan_much_plot_meaning[] = { - "Správné pořadí: ostrov → oheň vs. lov → bestie → Simon a Piggy → hon → námořník.", -}; - -static const LitQ book_pan_prstenu_qs[] = { - { - "Kdo napsal Pána prstenů?", - { - "C. S. Lewis", - "J. R. R. Tolkien", - "Rowling", - "Martin", - }, - 1, - "Tolkien, 1954–55 – zakladatel moderní fantasy.", - }, - { - "Kdo nese Prsten?", - { - "Frodo Pytlík", - "Gandalf", - "Sauron", - "Aragorn", - }, - 0, - "Hobit Frodo je zvolen nositelem.", - }, - { - "Co je cíl výpravy?", - { - "Zničit Prsten v Hoře osudu", - "Ukrást Prsten Sauronovi navždy", - "Prodat Prsten", - "Schovat v Kraji", - }, - 0, - "Jediná cesta zničit Saurona.", - }, - { - "Kdo je Sam?", - { - "Frodův věrný společník", - "Čaroděj", - "Ork", - "Král", - }, - 0, - "Sam podporuje Froda až do Mordoru.", - }, - { - "Kdo je Gandalf?", - { - "Istari, čaroděj, mentor", - "Hobit", - "Trpaslík", - "Ent", - }, - 0, - "Gandalf organizuje Společenstvo.", - }, - { - "Kdo je Gollum?", - { - "Smeagol, posedlý Prstenem", - "Král Gondoru", - "Elf", - "Ent", - }, - 0, - "Prsten ho zničil – guide i hrozba.", - }, - { - "Co je Společenstvo?", - { - "Skupina na zničení Prstenu", - "Armáda Saurona", - "Hospoda", - "Škola", - }, - 0, - "Různé rasy – elf, trpaslík, lidé, hobiti.", - }, - { - "Kde Frodo bydlí?", - { - "Kraj (Shire)", - "Mordor", - "Rivendell navždy", - "Moria", - }, - 0, - "Hobití kraj – idyla vs. temnota.", - }, - { - "Kdo je Sauron?", - { - "Temný pán Mordoru", - "Hobit", - "Král Rohanu", - "Ent", - }, - 0, - "Vládce Prstenu moci.", - }, - { - "Co Boromir?", - { - "Touží po Prstenu, zradí, pokání", - "Vždy zlý", - "Hobit", - "Elf", - }, - 0, - "Moc korumpuje i dobré.", - }, - { - "Kdo je Aragorn?", - { - "Dědic trůnu Gondoru", - "Ork", - "Gollum", - "Sam", - }, - 0, - "Strider – král v návratu.", - }, - { - "Jak končí Prsten?", - { - "Zničen v Hoře osudu (Gollum pád)", - "Sauron nosí navždy", - "Frodo vládne", - "Zmizí", - }, - 0, - "Gollum ukousne prst – pád do lávy.", - }, - { - "Proč maturita?", - { - "Fantasy epos, postavy, témata moci", - "Chemie", - "Atlas", - "Cookbook", - }, - 0, - "Často zkrácená maturitní verze.", - }, - { - "Které téma NENÍ?", - { - "Přátelství", - "Moc", - "Robotí R.U.R.", - "Oběť", - }, - 2, - "Čapek.", - }, - { - "Co Mordor?", - { - "Sauronova říše", - "Hobití kraj", - "Rivendell", - "Londýn", - }, - 0, - "Cíl výpravy.", - }, - { - "Kdy vyšlo?", - { - "1954–1955", - "1929", - "1836", - "2010", - }, - 0, - "Poválečná fantasy.", - }, - { - "Která postava NENÍ?", - { - "Frodo", - "Gandalf", - "Elizabeth Bennet", - "Aragorn", - }, - 2, - "Austen.", - }, - { - "Co Hobit?", - { - "Malý lid milující mír", - "Ork", - "Ent", - "Balrog", - }, - 0, - "Frodo a Sam jsou hobiti.", - }, - { - "Které dílo NENÍ Tolkien?", - { - "Pán prstenů", - "Hobit", - "Revizor", - "Silmarillion", - }, - 2, - "Gogol.", - }, - { - "Co Hora osudu?", - { - "Sammath Naur – zničení Prstenu", - "Hobití kopec", - "Věž", - "Hospoda", - }, - 0, - "V Mordoru.", - }, - { - "Jak vyprávění?", - { - "Er-forma epos", - "Ich Frodo celé", - "Drama", - "Lyrika", - }, - 0, - "Epický roman.", - }, - { - "Co elf Legolas a trpaslík Gimli?", - { - "Členové Společenstva", - "Orkové", - "Sauronovi", - "Hobiti", - }, - 0, - "Symbol smíření ras.", - }, - { - "Proč Frodo odchází na konci?", - { - "Rány Prstenu – odplutí do Undying Lands", - "Král", - "Smrt v boji", - "Zůstane v Kraji", - }, - 0, - "Epilog – oběť nositele.", - }, - { - "Co „Jeden prsten“?", - { - "Věta Sauronovy moci", - "Sport", - "Jídlo", - "Mapa", - }, - 0, - "Slavný verš Prstenu.", - }, - { - "Jaký konflikt?", - { - "Dobro vs. Sauron, pokušení moci", - "Láska Romeo", - "Revizor", - "Švejk", - }, - 0, - "Základ fantasy eposu.", - }, - { - "Co Rivendell?", - { - "Elfí útočiště Elronda", - "Mordor", - "Kraj", - "Moria", - }, - 0, - "Zde vzniká Společenstvo.", - }, - { - "Co Moria?", - { - "Trpasličí doly, Balrog", - "Hobití kraj", - "Mordor", - "Rohan", - }, - 0, - "Gandalf pád s Balrogem.", - }, - { - "Jaký tón?", - { - "Epická fantasy, mýtus", - "Realismus Dickens", - "Groteska Hrabal", - "Satira", - }, - 0, - "Tolkien buduje svět.", - }, - { - "Co čtenář po dočtení?", - { - "Chápe postavy, Prsten, témata", - "Chemii", - "Nic", - "Mapu ČR", - }, - 0, - "Maturitní přehled.", - }, - { - "Kdo režíroval slavný film?", - { - "Peter Jackson (2001–2003)", - "Menzel", - "Disney", - "N/A 1920", - }, - 0, - "Kulturní doplněk k maturitě.", - }, -}; - -static const AssemblyItem book_pan_prstenu_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Frodo zdědí Prsten, odchod z Kraje", - "Společenstvo v Rivendell", - "Cesta – Moria, rozpad společenstva", - "Frodo a Sam k Mordoru", - "Gollum vede, pokušení moci", - "Prsten zničen v Hoře osudu", - }, - 6, - }, -}; - -static const char *book_pan_prstenu_plot_meaning[] = { - "Správné pořadí: Kraj → Společenstvo → cesta → Frodo a Sam → Gollum → Hora osudu.", -}; - -static const LitQ book_petr_a_lucie_qs[] = { - { - "Kdo napsal Petra a Lucii?", - { - "Seifert", - "Vítězslav Nezval", - "Hrabal", - "Neruda", - }, - 1, - "Nezval, 1929 – vrchol poetistické prózy.", - }, - { - "Jaký směr román reprezentuje?", - { - "Poetismus", - "Socialistický realismus", - "Romantismus Erben", - "Beat generation", - }, - 0, - "Česká avantgarda 20. let.", - }, - { - "Kde se děj odehrává?", - { - "Praha", - "Verona", - "Londýn", - "Mordor", - }, - 0, - "Město procházek a metafor.", - }, - { - "Kdo jsou hlavní hrdinové?", - { - "Petr a Lucie", - "Romeo a Julie", - "Frodo a Sam", - "Švejk a Lukáš", - }, - 0, - "Mladí milenci v poetistické Praze.", - }, - { - "Jaký je tón začátku?", - { - "Radost, hra, obrazy", - "Válka", - "Groteska Haška", - "Sci-fi", - }, - 0, - "Poetismus slaví život a město.", - }, - { - "Jak končí Lucie?", - { - "Umírá (nemoc) – tragický konec", - "Královna", - "Emigrace", - "Svatba bez smutku", - }, - 0, - "Idyla praskne realitou.", - }, - { - "Co je poetismus?", - { - "Avantgarda – radost, metafora, město", - "Válka", - "Realismus 19. stol.", - "Robotika", - }, - 0, - "Devětsil, Nezval, Teige…", - }, - { - "Proč maturita?", - { - "Nezval, poetismus, Praha, styl", - "Chemie", - "Atlas", - "Cookbook", - }, - 0, - "Česká maturitní četba.", - }, - { - "Jaký styl Nezval?", - { - "Poetické obrazy, hra se slovy", - "Strohý realismus", - "Hexametr antický", - "Drama", - }, - 0, - "Próza i poezie splývají.", - }, - { - "Které téma NENÍ?", - { - "Láska", - "Město", - "Robotí vzpoura", - "Mládí", - }, - 2, - "R.U.R.", - }, - { - "Kdy vyšlo?", - { - "1929", - "1957", - "1890", - "2010", - }, - 0, - "Meziválečí avantgarda.", - }, - { - "Kdo Nezval?", - { - "Devětsil, surrealismus později", - "Hašek Švejk", - "Kafka", - "Gogol", - }, - 0, - "Klíčová osobnost avantgardy.", - }, - { - "Jak vyprávění?", - { - "Er-forma poetistická", - "Ich Petr celé", - "Drama", - "Epos", - }, - 0, - "Lyrizovaná próza.", - }, - { - "Co Praha v románu?", - { - "Prostor snů a procházek", - "Pouze mapa", - "Vězení", - "Vesnice", - }, - 0, - "Poetistické město.", - }, - { - "Která postava NENÍ?", - { - "Petr", - "Lucie", - "Winston Smith", - "—", - }, - 2, - "Orwell.", - }, - { - "Jaký kontrast?", - { - "Poetistická radost vs. smrt", - "Moře hory", - "Den noc", - "Práce lenost", - }, - 0, - "Křehkost štěstí.", - }, - { - "Které dílo NENÍ Nezval?", - { - "Petr a Lucie", - "Akrobat", - "Revizor", - "Poetistické manifesty", - }, - 2, - "Gogol.", - }, - { - "Co láska v románu?", - { - "Hra, sen, cit", - "Politika", - "Válka", - "Obchod", - }, - 0, - "Centrum poetismu.", - }, - { - "Proč tragický konec?", - { - "Realita nemoci vs. idyla", - "Válka", - "Náhodná věta", - "Bez důvodu", - }, - 0, - "Nezval neničí iluzi.", - }, - { - "Co Devětsil?", - { - "Umělecká skupina avantgardy", - "Armáda", - "Banka", - "Kostel", - }, - 0, - "Kontext Nezvala.", - }, - { - "Jaký jazyk?", - { - "Bohaté metafory, obrazy", - "Úřední", - "Latina", - "Argot", - }, - 0, - "Poetistická próza.", - }, - { - "Co Petr prožívá?", - { - "Lásku a ztrátu Lucie", - "Válku", - "Roboty", - "Král", - }, - 0, - "Hrdina citu.", - }, - { - "Jak román vnímat u maturity?", - { - "Autor, směr, děj, styl, témata", - "Jen datum", - "Jen mapa", - "Ignorovat", - }, - 0, - "Komplexní četba.", - }, - { - "Co NENÍ poetismus?", - { - "Radost z obrazu a města", - "Věčná válka", - "Hra", - "Avantgarda", - }, - 1, - "Poetismus je radostný.", - }, - { - "Kdo surrealismus u Nezvala?", - { - "Pozdější fáze tvorby", - "Neexistuje", - "Jen Švejk", - "Jen Kafka", - }, - 0, - "Po poetismu surrealismus.", - }, - { - "Co Lucie symbolizuje?", - { - "Křehké mládí a krása", - "Moc", - "Robot", - "Válka", - }, - 0, - "Oběť času a nemoci.", - }, - { - "Jaký věk autor?", - { - "Meziválečná generace", - "Středověk", - "Antika", - "21. stol.", - }, - 0, - "1900–1958 Nezval.", - }, - { - "Co čtenář po dočtení?", - { - "Chápe poetismus a Nezvala", - "Chemii", - "Nic", - "Mapu", - }, - 0, - "Maturitní cíl.", - }, - { - "Který pár je z Nezvala?", - { - "Petr a Lucie", - "Romeo a Julie", - "Elizabeth a Darcy", - "Frodo a Sam", - }, - 0, - "Titulní hrdinové.", - }, - { - "Proč „poetický román“?", - { - "Próza s poetickými prostředky a obrazností", - "Pouze verše", - "Učebnice", - "Zákoník", - }, - 0, - "Lyrizace prózy – obrazy, metafora, rytmus vět.", - }, -}; - -static const AssemblyItem book_petr_a_lucie_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Petr a Lucie se seznámí v Praze", - "Procházky, radost a poetistické obrazy", - "Láska roste – hra a sen", - "Prozaická realita – nemoc Lucie", - "Petr prožívá ztrátu", - "Tragický konec – Lucie umírá", - }, - 6, - }, -}; - -static const char *book_petr_a_lucie_plot_meaning[] = { - "Správné pořadí: seznámení → radost → láska → nemoc → ztráta → smrt Lucie.", -}; - -static const LitQ book_poe_povidky_qs[] = { - { - "Kdo napsal Havrana a další povídky?", - { - "Dickens", - "Edgar Allan Poe", - "Twain", - "Hemingway", - }, - 1, - "Poe – zakladatel detektivky a hororu.", - }, - { - "Co opakuje havran v básni?", - { - "Nevermore (Už nikdy)", - "Hello", - "War", - "Love", - }, - 0, - "Jediné slovo – symbol věčného smutku.", - }, - { - "O čem je Havran?", - { - "Truchlení za Lenore", - "Válka", - "Robot", - "Svatba", - }, - 0, - "Gotická báseň v komnatě.", - }, - { - "Kdo je Dupin?", - { - "Detektiv v povídkách", - "Vrah", - "Král", - "Havran", - }, - 0, - "Předchůdce Sherlocka Holmese.", - }, - { - "O čem je Amontillado?", - { - "Pomsta zazděním ve sklepě", - "Láska", - "Detektivka na lodi", - "Sci-fi", - }, - 0, - "Montresor zabije Fortunata.", - }, - { - "O čem je Srdce prozrazuje?", - { - "Vrah slyší bušení srdce pod podlahou", - "Láska", - "Válka", - "Cookbook", - }, - 0, - "Psychologický horor viny.", - }, - { - "O čem je Jáma a kyvadlo?", - { - "Mučení inkvizicí", - "Svatba", - "Detektivka", - "Komise", - }, - 0, - "Strach a smrt.", - }, - { - "O čem je Fall of the House of Usher?", - { - "Rod Usherů a zhroucení domu", - "Švejk", - "Praha", - "Robot", - }, - 0, - "Gotický dům = rod.", - }, - { - "Jaký je Poe styl?", - { - "Gotika, psychologie, napětí", - "Realismus Dickens", - "Poetismus", - "Hašek", - }, - 0, - "Temnota a logika.", - }, - { - "Proč maturita?", - { - "Havran, horor, detektivka, symboly", - "Chemie", - "Atlas", - "Cookbook", - }, - 0, - "Světová maturitní četba.", - }, - { - "Které téma NENÍ?", - { - "Strach", - "Vina", - "Robotí R.U.R.", - "Monomanie", - }, - 2, - "Čapek.", - }, - { - "Co „princip jednoty účinku“?", - { - "Poe estetika – jeden dojem v díle", - "Válka", - "Cookbook", - "Mapa", - }, - 0, - "Krátká forma, silný efekt.", - }, - { - "Kdy Poe žil?", - { - "1809–1849", - "1929", - "2000", - "1595", - }, - 0, - "19. století USA.", - }, - { - "Která postava NENÍ Poe?", - { - "Dupin", - "Montresor", - "Elizabeth Bennet", - "Usher", - }, - 2, - "Austen.", - }, - { - "Co gotika u Poe?", - { - "Tma, hrob, hrůza", - "Komise", - "Idyla", - "Sport", - }, - 0, - "Základ hororu.", - }, - { - "Které dílo NENÍ Poe?", - { - "Havran", - "Amontillado", - "Revizor", - "Beruška", - }, - 2, - "Gogol.", - }, - { - "Jak Havran končí?", - { - "Pták zůstává, beznaděj", - "Svatba", - "Vítězství", - "Pták letí", - }, - 0, - "Stín na duši.", - }, - { - "Co detektivní povídka Poe?", - { - "Logika, deduction", - "Pouze magie", - "Válka", - "Cookbook", - }, - 0, - "Dupin řeší zločin.", - }, - { - "Jaký jazyk Havran?", - { - "Rytmická báseň, gotická", - "Prozaický zákoník", - "Dialog divadla", - "Hašek", - }, - 0, - "Lyrika + horor.", - }, - { - "Co monomanie?", - { - "Posedlost jednou myšlenkou", - "Láska", - "Sport", - "Mír", - }, - 0, - "Vrah v Srdci prozrazuje.", - }, - { - "Kde Poe působil?", - { - "USA", - "Čechy", - "Rusko", - "Antika", - }, - 0, - "Americký autor.", - }, - { - "Co čtenář u maturity?", - { - "Zná Havrana, horor, detektivku", - "Jen mapu", - "Chemii", - "Nic", - }, - 0, - "Výběr povídek.", - }, - { - "Co Lenore?", - { - "Mrtvá milovaná v Havranovi", - "Detektiv", - "Král", - "Robot", - }, - 0, - "Důvod smutku.", - }, - { - "Jaký kontrast Poe?", - { - "Rozum vs. šílenství", - "Moře hory", - "Den noc", - "Práce lenost", - }, - 0, - "Psychika na hranici.", - }, - { - "Co Fortunato?", - { - "Oběť v Amontillado", - "Detektiv", - "Havran", - "Král", - }, - 0, - "Opilý, zazděný.", - }, - { - "Proč povídky?", - { - "Krátká forma, silný účinek", - "Bez důvodu", - "Jen básně", - "Jen román", - }, - 0, - "Poe mistr povídky.", - }, - { - "Co symbol havran?", - { - "Smrt, beznaděj", - "Láska", - "Mír", - "Bohatství", - }, - 0, - "Černý pták.", - }, - { - "Jak vyprávění hororu?", - { - "Často ich-forma vina", - "Epos", - "Bez já", - "Drama", - }, - 0, - "Subjektivní strach.", - }, - { - "Co NENÍ Poe povídka?", - { - "Havran (báseň)", - "Amontillado", - "Oliver Twist", - "Usher", - }, - 2, - "Dickens román.", - }, - { - "Jaký tón?", - { - "Temnota, napětí", - "Pouze komedie", - "Idyla", - "Učebnice", - }, - 0, - "Gotický horor.", - }, -}; - -static const AssemblyItem book_poe_povidky_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Havran: muž truchlí za Lenore", - "Pták přiletí do komnaty", - "Otázky a odpověď „Nevermore“", - "Narůstající zoufalství", - "Stín ptáka nad duší", - "Beznaděj bez útěchy", - }, - 6, - }, -}; - -static const char *book_poe_povidky_plot_meaning[] = { - "Správné pořadí (Havran): smutek → přílet → Nevermore → zoufalství → stín → beznaděj.", -}; - -static const LitQ book_povidky_z_kapes_qs[] = { - { - "Kdo napsal Povídky z jedné a druhé kapsy?", - { - "Jaroslav Hašek", - "Karel Čapek", - "Franz Kafka", - "Bohumil Hrabal", - }, - 1, - "Autorem je Karel Čapek; první svazek vyšel 1929, druhý 1932.", - }, - { - "Jaký je základní žánr souboru?", - { - "Historický epos", - "Detektivní a humoristické povídky", - "Lyrická skladba", - "Tragédie", - }, - 1, - "Čapek kombinuje detektivní zápletku s humorem a parodií.", - }, - { - "Jak jsou povídky rámovány?", - { - "Deníkem jednoho hrdiny", - "Vyprávěním přátel u stolu v kavárně", - "Úředním protokolem", - "Hexametrem", - }, - 1, - "Rámec tvoří společnost, která si předává krátké historky.", - }, - { - "Proč název „z kapes“?", - { - "Jde výhradně o krádeže kapesníků", - "Jde o drobné příběhy, které si lze „vytáhnout z kapsy“ u stolu", - "Autor psal jen v kapse kabátu", - "Jde o učebnici šití", - }, - 1, - "Metafora malých, unosných povídek vhodných k vyprávění.", - }, - { - "Co Čapek u detektivek často zpochybňuje?", - { - "Existenci kaváren", - "Všemocnost čisté logiky a dedukce", - "Pravopis", - "Existenci Prahy", - }, - 1, - "Příběhy ukazují, že náhoda a lidský detail často překonají „geniální“ rozum.", - }, - { - "Kdo je komisař Mejzlík?", - { - "Hlavní hrdina všech povídek bez výjimky", - "Detektiv v detektivních povídkách cyklu, parodie sherlockovského typu", - "Čapekův bratr", - "Postava z R.U.R.", - }, - 1, - "Mejzlík reprezentuje přehnanou logiku, kterou Čapek ironizuje.", - }, - { - "Která povídka patří k známým z kapsy?", - { - "Modrá chrysantéma", - "Havran", - "Babička", - "Hamlet", - }, - 0, - "Modrá chrysantéma je jedna z proslulých detektivních miniatur.", - }, - { - "Jaký je typický tón sbírky?", - { - "Pouze tragický patos", - "Humoristický, bystrý, ironický", - "Pouze horor", - "Úřednický bez emocí", - }, - 1, - "Typický je čapkovský humor a nadhled nad žánrem.", - }, - { - "Kdy vyšly oba svazky zhruba?", - { - "1836 a 1840", - "1929 a 1932", - "2001 a 2005", - "1415 a 1420", - }, - 1, - "Obě kapsy vznikly v meziválečné prvorepublikové době.", - }, - { - "Co je typické pro pointu povídky?", - { - "Žádné vyřešení", - "Překvapení, vtip nebo banální lidský detail", - "Pouze matematický důkaz bez vtipu", - "Povinný sňatek", - }, - 1, - "Čapek rád obrátí očekávání čtenáře v závěru.", - }, - { - "Jak souvisí sbírka s ostatním Čapkovým dílem?", - { - "Nesouvisí vůbec", - "Humanismus, hra s žánrem, ironie – stejný duch jako u jiných próz", - "Je to jen překlad Twaina", - "Je to pokračování R.U.R.", - }, - 1, - "Čapek znovu spojuje zábavu s myšlenkou o člověku a společnosti.", - }, - { - "Co čtenář při čtení typicky dělá?", - { - "Jen počítá stránky", - "Spoluuhádá záhadu a nechá se překvapit pointou", - "Učí se latinku", - "Ignoruje děj", - }, - 1, - "Detektivní linka zve k aktivnímu čtení, parodie ho pak přechytračí.", - }, - { - "Které prostředí rámce převažuje?", - { - "Venkov 19. století", - "Praha první republiky – kavárna, společnost", - "Vesmír", - "Středověký hrad", - }, - 1, - "Rámec odpovídá pražské meziválečné inteligenci.", - }, - { - "Co NENÍ charakteristika cyklu?", - { - "Humor", - "Parodie detektivky", - "Jediný souvislý román o jedné rodině", - "Krátká forma", - }, - 2, - "Jde o soubor samostatných povídek spojených rámcem.", - }, - { - "Jak Čapek vnímá detektivní žánr?", - { - "Bezvýhradně ho opakuje", - "Hraje si s ním, demýtizuje geniálního detektiva", - "Zakazuje záhady", - "Píše jen dokumenty", - }, - 1, - "Mejzlík a pointy ukazují limity „stoprocentní“ logiky.", - }, - { - "Které dílo NENÍ Čapek?", - { - "Povídky z kapes", - "R.U.R.", - "Revizor", - "Válka s mloky", - }, - 2, - "Revizor je Gogolova komedie.", - }, - { - "Kolik „kapes“ má plný název díla?", - { - "Jednu", - "Dvě – z jedné a z druhé kapsy", - "Deset", - "Žádnou", - }, - 1, - "Maturitní četba zahrnuje oba svazky.", - }, - { - "Co je Levkoj v kontextu sbírky?", - { - "Postava z R.U.R.", - "Název jedné z povídek v cyklu", - "Čapekův bratr", - "Detektivní pes", - }, - 1, - "Levkoj patří k známým povídkám z kapsy.", - }, - { - "Jaký kontrast tvoří jádro detektivních povídek?", - { - "Moře vs. hory", - "Chladná dedukce vs. náhoda a lidskost", - "Praha vs. Brno", - "Den vs. noc bez významu", - }, - 1, - "Čapek staví proti sobě rozum a obyčejnou realitu.", - }, - { - "Proč je dílo v maturitní četbě?", - { - "Je nejkratší kniha v knihovně", - "Čapek, parodie, forma povídky, humanismus", - "Bez témat a postav", - "Je to atlas", - }, - 1, - "U maturity se ptá na autora, rámec, žánr a typické povídky.", - }, - { - "Kdo NENÍ typická postava kapsy?", - { - "Komisař Mejzlík", - "Vypravěč u stolu", - "Frodo Pytlík", - "Pachatel v minipříběhu", - }, - 2, - "Frodo je z Tolkienova eposu.", - }, - { - "Co znamená humanismus u Čapka zde?", - { - "Zájem o obyčejného člověka, soucit, nadhled", - "Popírání humoru", - "Jen politická propaganda", - "Odmítání prózy", - }, - 0, - "I v detektivce jde o lidi, ne jen o rébus.", - }, - { - "Jaká forma vyprávění v jednotlivých povídkách?", - { - "Výhradně divadelní dialog bez vypravěče", - "Krátká próza, často ich- nebo er-forma v rámci vyprávění u stolu", - "Pouze sonety", - "Operní libreto", - }, - 1, - "Každá miniatura má klasickou povídkovou stavbu.", - }, - { - "Co je Uspání v kontextu díla?", - { - "Povídka z druhé kapsy", - "Čapekův dramatický spis", - "Název kavárny", - "Postava z Bílé nemoci", - }, - 0, - "Uspání patří k povídkám druhého svazku.", - }, - { - "Jaký vztah má sbírka k Sherlocku Holmesovi?", - { - "Žádný – Čapek neznal detektivky", - "Parodický – ironizuje dedukci a „geniální“ detektiva", - "Holmes je hlavní hrdina", - "Jde o Holmesův deník", - }, - 1, - "Mejzlík a pointy reagují na konvence žánru.", - }, - { - "Které téma NENÍ typické?", - { - "Náhoda a omyl", - "Lidská povaha v malém", - "Vzpoura robotů", - "Ironie vůči jistotám", - }, - 2, - "Robotí vzpoura patří k R.U.R.", - }, - { - "Co je hlavní kouzlo formátu?", - { - "Extrémní délka románu", - "Krátkost, vtip, nápad, překvapivá pointa", - "Bez děje", - "Pouze popis krajiny", - }, - 1, - "Povídka z kapsy má být lehká a zapamatovatelná.", - }, - { - "Jak maturita obvykle testuje dílo?", - { - "Jen rok narození autora", - "Autor, rámec, žánr, Mejzlík, známé povídky, témata", - "Jen počet stran", - "Jen cizí jazyk originálu", - }, - 1, - "Čeká se přehled o cyklu a charakteristice Čapkovy parodie.", - }, - { - "Který autor je současník Čapka v české próze?", - { - "Bohumil Hrabal (jiná generace)", - "Karel Čapek sám", - "Homér", - "Dante", - }, - 0, - "Hrabal patří později; u maturity jde o meziválečný Čapek.", - }, - { - "Jaký závěr lze vyvodit z celého cyklu?", - { - "Logika vždy zvítězí nad náhodou", - "Pravda bývá prozaická; humor a humanismus jsou důležité", - "Detektivka je nevhodný žánr", - "Kavárny je třeba zakázat", - }, - 1, - "Čapek oslavuje bystrost, ale i lidskost a nadhled.", - }, -}; - -static const AssemblyItem book_povidky_z_kapes_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Přátelé sedí u stolu v kavárně", - "Jeden vypravěč přednese detektivní historku", - "Nabízejí se stopy a logické úvahy", - "Zvrat – náhoda nebo banální detail", - "Pointa povídky", - "Společnost reaguje humorem a pokračuje vyprávěním", - }, - 6, - }, -}; - -static const char *book_povidky_z_kapes_plot_meaning[] = { - "Správné pořadí: kavárenský rámec → přednes povídky → stopy a dedukce → zvrat → pointa → reakce společnosti.", -}; - -static const LitQ book_promena_qs[] = { - { - "Kdo napsal Proměnu?", - { - "Franz Kafka", - "Jaroslav Hašek", - "Karel Čapek", - "Erich Maria Remarque", - }, - 0, - "Novela je jedním z nejznámějších Kafkových textů; vyšla 1915.", - }, - { - "Co se stane Gregorovi Samsovi na začátku?", - { - "Vyhrá loterii", - "Probudí se proměněný v obrovského hmyz", - "Odjede do války", - "Stane se králem", - }, - 1, - "Slavná úvodní věta líčí bizarní proměnu bez vysvětlení.", - }, - { - "Jaké povolání má Gregor před proměnou?", - { - "Lékař", - "Obchodní cestující", - "Učitel", - "Kněz", - }, - 1, - "Gregor dře pro rodinu jako obchodník – práce ho vyčerpává.", - }, - { - "Kdo je Grete?", - { - "Gregorova manželka", - "Gregorova sestra", - "Sousedka", - "Prokuristka", - }, - 1, - "Grete se nejprve stará o bratra, později ho odmítá.", - }, - { - "Proč je Gregor pro rodinu důležitý (před proměnou)?", - { - "Je slavný herec", - "Je hlavní živitel rodiny", - "Je politik", - "Je dědic hradu", - }, - 1, - "Rodina je na jeho platu závislá – otec, matka, sestra.", - }, - { - "Jak reaguje otec na Gregora-hmyz?", - { - "Objímá ho", - "Násilně ho zaplaší – mimo jiné jablko", - "Ignoruje navždy", - "Pošle ho do školy", - }, - 1, - "Otec představuje autoritu a hrubou sílu vůči „nestvůře“.", - }, - { - "Co symbolizuje jablko zabodnuté do Gregora?", - { - "Lásku", - "Otcovské násilí, vinu a odcizení", - "Svatou hostii", - "Sport", - }, - 1, - "Jablko zraní Gregora a dlouho v něm zůstává – obraz odcizení.", - }, - { - "Jak se mění vztah Grete k Gregorovi?", - { - "Vždy milující", - "Od péče k odmítnutí a požadavku „se zbavit ho“", - "Grete se promění v hmyz", - "Grete odejde do kláštera hned", - }, - 1, - "Grete na konci prosí rodiče, aby se Gregora zbavili.", - }, - { - "Kdo jsou podnájemníci?", - { - "Gregorovi přátelé", - "Cizí lidé v bytě, kteří zhorší finanční tlak", - "Policisté", - "Lékaři", - }, - 1, - "Podnájemníci jsou svědky „ostudy“ a urychlí krizi.", - }, - { - "Jaký je styl vyprávění?", - { - "Rychlý humor Haška", - "Er-forma, věcný tón u absurdní události", - "Pouze dialogy divadla", - "Epický zpěv", - }, - 1, - "Kafka kontrastuje chladný jazyk s hrůzou situace.", - }, - { - "Kde Gregor většinou pobývá?", - { - "Na ulici", - "Ve svém pokoji, často za zavřenými dveřmi", - "V lese", - "Na moři", - }, - 1, - "Izolace v pokoji zdůrazňuje odcizení od rodiny.", - }, - { - "Jak Gregor umírá?", - { - "Na popravišti", - "Sám, vyčerpán – rodina cítí úlevu", - "V boji", - "V autonehodě", - }, - 1, - "Po smrti rodina plánuje světlejší budoucnost – krutá ironie.", - }, - { - "Co je hlavní téma Proměny?", - { - "Válečná sláva", - "Odcizení, užitečnost člověka a rozpad rodinných vazeb", - "Růst tržní ekonomiky", - "Středověké rytířství", - }, - 1, - "Gregor je milován, dokud vydělává; jako hmyz je odpad.", - }, - { - "Proč Gregor nemůže hned jít do práce?", - { - "Proměna v hmyz", - "Je na dovolené", - "Je bohatý", - "Je v jiné zemi", - }, - 0, - "Právě proměna spouští konflikt s prokuristou a rodinou.", - }, - { - "Kdo přichází do bytu jako reprezentant práce?", - { - "Prokurista", - "Švejk", - "Romeo", - "Domin", - }, - 0, - "Prokurista je tlak firmy – Gregor musí vysvětlovat absenci.", - }, - { - "Jak matka reaguje na Gregora?", - { - "Vždy klidně objímá", - "Rozpolcená – soucit i strach, omdlévání", - "Nikdy se o něj nezajímá", - "Stane se hmyzem", - }, - 1, - "Matka trpí mezi synem a realitou bytu.", - }, - { - "Co znamená kafkaovský svět?", - { - "Idyla", - "Absurdita, vina bez důvodu, byrokratický tlak", - "Pouze komedie", - "Historický dokument", - }, - 1, - "Proměna je ukázkou existenciální absurdity bez vysvětlení.", - }, - { - "Jak rodina končí po Gregorově smrti?", - { - "Truchlí navždy", - "Plánuje světlou budoucnost (s výhledem na sestřin sňatek)", - "Emigruje", - "Zbankrotuje", - }, - 1, - "Závěr je ironický – Gregorova smrt uvolní cestu „normálnímu“ životu.", - }, - { - "Který prvek NENÍ v Proměně typický?", - { - "Rodinný byt", - "Proměna těla", - "Vysvětlení příčiny proměny vědou", - "Odcizení", - }, - 2, - "Kafka příčinu nevysvětluje – to je součást absurdity.", - }, - { - "Jak Gregor slyší hudbu (housle)?", - { - "Nesnáší ji", - "Grete hraje – Gregor je dojat, lidskost v něm rezonuje", - "Je hluchý", - "Hudba nefiguruje", - }, - 1, - "Scéna s houslemi ukazuje zbytky Gregorovy citlivosti.", - }, - { - "Proč je novela důležitá pro maturitu?", - { - "Učí účetnictví", - "Kafka, symbolika, témata, styl – klasika světové literatury", - "Je atlas", - "Je cookbook", - }, - 1, - "U maturity: autor, děj, postavy, symboly, témata odcizení.", - }, - { - "V jakém roce vyšla Proměna?", - { - "1915", - "1929", - "1949", - "2005", - }, - 0, - "Text vznikl v Kafkově tvůrčím období první světové války.", - }, - { - "Která věta patří k úvodu Proměny?", - { - "Call me Ishmael", - "Jednoho rána, když se ze spánku probudil, proměnil se Gregor Samsa v obrovského brouka", - "Vánoce nebyly bílé", - "Dvě ulice Prahy", - }, - 1, - "Slavný začátek v českých překladech obvykle „hmyz/brouk“.", - }, - { - "Jaká forma vyprávění je v Proměně?", - { - "Ich-forma", - "Er-forma (třetí osoba)", - "Drama", - "Epistolární", - }, - 1, - "Kafka vypráví o Gregorovi v třetí osobě – er-forma.", - }, - { - "Co podnájemníci dělají při hře na housle?", - { - "Tleskají", - "Projevují netrpělivost – Gregor chce Grete bránit", - "Odejdou hned první den", - "Stanou se hmyzem", - }, - 1, - "Konflikt vyhrotí Gregorovo vyloupení z pokoje.", - }, - { - "Jak otec vypadá po Gregorově proměně?", - { - "Mladne", - "Zpočátku zlomený, později energický při potrestání Gregora", - "Zmizí", - "Je v nemocnici", - }, - 1, - "Otec se znovu postaví do role autority.", - }, - { - "Které téma souvisí s prací?", - { - "Gregor = hodnota jen jako výdělek", - "Gregor je nezaměstnaný od narození", - "Práce nefiguruje", - "Gregor je král", - }, - 0, - "Když nemůže pracovat, rodina ho vnímá jako břemeno.", - }, - { - "Jaký žánr je Proměna?", - { - "Novela / absurdní próza", - "Historický román", - "Bajka o zvířatech", - "Učebnice", - }, - 0, - "Krátký prózní útvar s fantastickým prvkem – novela.", - }, - { - "Co NENÍ postava Proměny?", - { - "Grete", - "Otec", - "Winston Smith", - "Matka", - }, - 2, - "Winston Smith je z Orwellova 1984, ne z Kafky.", - }, -}; - -static const AssemblyItem book_promena_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Gregor se probudí proměněný v hmyz", - "Prokurista a rodina zjišťují, že nemůže do práce", - "Grete pečuje, Gregor je izolován v pokoji", - "Otec zraní Gregora jablkem", - "Podnájemníci a hádky – Gregor vyloupen", - "Gregor umírá, rodina plánuje nový začátek", - }, - 6, - }, -}; - -static const char *book_promena_plot_meaning[] = { - "Správné pořadí: proměna → tlak práce → péče Grete → jablko → podnájemníci → smrt a „úleva“ rodiny.", -}; - -static const LitQ book_pycha_a_predsudek_qs[] = { - { - "Kdo napsal Pýchu a předsudek?", - { - "Charlotte Brontëová", - "Jane Austenová", - "George Eliot", - "Virginia Woolfová", - }, - 1, - "Román vyšel 1813 a je Austenovou nejznámější prózou.", - }, - { - "Kolik sester má rodina Bennetů (dcer)?", - { - "2", - "5", - "10", - "1", - }, - 1, - "Pět sester – Elizabeth, Jane, Mary, Kitty, Lydia.", - }, - { - "Kdo je Elizabeth Bennet?", - { - "Nejstarší sestra", - "Druhá nejstarší, bystrá hrdinka románu", - "Služka", - "Vévodkyně", - }, - 1, - "Elizabeth je inteligentní a ironická protagonista.", - }, - { - "Kdo je Fitzwilliam Darcy?", - { - "Chudý kněz", - "Bohatý aristokrat, Bingleyho přítel", - "Wickhamův otec", - "Farmář", - }, - 1, - "Darcy působí na Elizabeth povýšeně – pýcha.", - }, - { - "Kdo je Charles Bingley?", - { - "Elizabethin strýc", - "Bohatý muž, který miluje Jane", - "Vrah", - "Král", - }, - 1, - "Bingley pronajme Netherfield a zamiluje se do Jane.", - }, - { - "Proč Darcy zpočátku odjede a oddálí Bingleyho?", - { - "Myslí si, že Jane nemiluje Bingleyho a rodina není vhodná", - "Nemá peníze", - "Je nemocný", - "Nenávidí Anglii", - }, - 0, - "Darcy jedná z pýchy a „ochrany“ přítele.", - }, - { - "Kdo je George Wickham?", - { - "Darcymu důvěryhodný důstojník", - "Okouzlující důstojník s temnou minulostí vůči Darcymu", - "Kněz", - "Lékař", - }, - 1, - "Wickham lže o Darcym – Elizabeth uvěří předsudku.", - }, - { - "Co Elizabeth odmítne od Darcyho?", - { - "První nabídku k sňatku – uražena jeho způsobem", - "Dědictví", - "Dům", - "Knihu", - }, - 0, - "Slavná scéna – Darcy se nabídne hrdě, Elizabeth odmítne.", - }, - { - "Co změní Elizabethin názor na Darcyho?", - { - "Dopis vysvětlující Wickhamovu minulost a Darcyho činy", - "Peníze", - "Hrozba", - "Kouzlo", - }, - 0, - "Po dopise Elizabeth přehodnotí předsudky.", - }, - { - "Co udělá Lydia?", - { - "Uteče s Wickhamem – skandál rodiny", - "Stane se královnou", - "Založí školu", - "Odejde do kláštera", - }, - 0, - "Lydiin útěk ohrozí pověst celé rodiny.", - }, - { - "Kdo pomůže Wickhamovu sňatku s Lydií?", - { - "Darcy (tajně)", - "Elizabeth", - "Paní Bennet", - "Wickham sám", - }, - 0, - "Darcy platí a jedná – projev dobrého srdce.", - }, - { - "Jak román končí?", - { - "Elizabeth a Darcy se vezmou, Bingley a Jane také", - "Všichni zůstanou sami", - "Elizabeth uteče", - "Darcy zbankrotuje", - }, - 0, - "Klasický happy-end po sebepoznání.", - }, - { - "Jaký je styl Austenové?", - { - "Ironický společenský realismus", - "Gotický horor", - "Sci-fi", - "Epos", - }, - 0, - "Jemná ironie vůči společnosti a postavám.", - }, - { - "Proč paní Bennet tlačí na sňatky?", - { - "Majetek rodiny přejde synovi – dcery potřebují partii", - "Nenávidí děti", - "Je královna", - "Zákaz práce", - }, - 0, - "Ekonomická realita regency – sňatek jako jistota.", - }, - { - "Kde se Bingley poprvé objeví?", - { - "Netherfield – sousedství Bennetů", - "Paříž", - "Verona", - "Praha", - }, - 0, - "Pronajatý statek spustí děj a plesy.", - }, - { - "Kdo je pan Collins?", - { - "Mrzký dědic statku, nabádá k sňatku", - "Darcy", - "Wickham", - "Bingley", - }, - 0, - "Collins je komická postava servility vůči Lady Catherine.", - }, - { - "Které téma NENÍ typické?", - { - "Pýcha a předsudek", - "Sňatek a třída", - "Vzpoura robotů", - "Sebepoznání", - }, - 2, - "Roboti jsou z R.U.R., ne od Austenové.", - }, - { - "Proč je román důležitý pro maturitu?", - { - "Učí chemii", - "Austen, společnost, postavy, ironie, sňatek", - "Je atlas", - "Je zákoník", - }, - 1, - "U maturity: autor, děj, Elizabeth vs. Darcy, témata.", - }, - { - "Kdy román vyšel?", - { - "1813", - "1929", - "1595", - "2001", - }, - 0, - "Regency období, počátek 19. století.", - }, - { - "Jak Elizabeth vidí Darcyho na začátku?", - { - "Okamžitě ideální", - "Povýšeného a nepříjemného – předsudek", - "Jako chudého", - "Jako dítě", - }, - 1, - "První dojem u plesu formuje její názor.", - }, - { - "Kdo je Lady Catherine de Bourgh?", - { - "Darcyho příbuzná, autoritativní patronka", - "Elizabethina sestra", - "Wickhamova manželka", - "Služka", - }, - 0, - "Lady Catherine představuje starou aristokracii.", - }, - { - "Co je Netherfield?", - { - "Statek, který Bingley pronajme", - "Léčebna", - "Vězení", - "Loď", - }, - 0, - "Místo setkání společnosti a začátku lásky Jane.", - }, - { - "Jaký vztah mají Jane a Bingley?", - { - "Nenávist", - "Jemná vzájemná láska", - "Sourozenec", - "Učitel–žák", - }, - 1, - "Jane a Bingley jsou kontrast k Elizabeth–Darcy konfliktu.", - }, - { - "Co znamená název?", - { - "Darcyho pýcha a Elizabethin předsudek brání lásce", - "Pouze válka", - "Pouze počasí", - "Geografie", - }, - 0, - "Obě vlastnosti se musí překonat.", - }, - { - "Která postava NENÍ Bennetová?", - { - "Elizabeth", - "Jane", - "Emma Woodhouse", - "Lydia", - }, - 2, - "Emma je hrdinka jiného Austenova románu.", - }, - { - "Jak vyprávění funguje?", - { - "Er-forma s ironickým odstupem", - "Ich-forma Elizabeth", - "Drama", - "Epos", - }, - 0, - "Vypravěč často sdílí Elizabethin pohled, ale s ironií.", - }, - { - "Proč Darcy pomůže s Lydií?", - { - "Láska k Elizabeth a pocit odpovědnosti", - "Nenávidí Wickhama jen ze sportu", - "Zákaz", - "Náhodou", - }, - 0, - "Darcy jedná diskrétně – charakter se ukáže činy.", - }, - { - "Které dílo NENÍ Austenovo?", - { - "Pýcha a předsudek", - "Emma", - "Na západní frontě klid", - "Mansfieldské panství", - }, - 2, - "Remarque napsal válečný román.", - }, - { - "Jak Elizabeth reaguje na druhou Darcyho nabídku?", - { - "Přijme – po změně obou", - "Odmítne navždy", - "Uteče", - "Pošle Wickhama", - }, - 0, - "Oba se poučili – sňatek z lásky.", - }, - { - "Jak Austen ironicky líčí paní Bennet?", - { - "Jako hysterickou matku fixovanou na sňatky dcer", - "Jako vzornou vědkyni", - "Jako válečnou hrdinku", - "Jako královnu", - }, - 0, - "Paní Bennet komicky tlačí na vdání, protože ekonomicky jinou jistotu nemá.", - }, -}; - -static const AssemblyItem book_pycha_a_predsudek_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Bingley přijede do Netherfield, ples a setkání", - "Elizabeth soudí Darcyho pýchou, Wickham lže", - "Darcy se nabídne – Elizabeth odmítne", - "Darcyho dopis a nové pochopení", - "Lydia uteče s Wickhamem, Darcy pomůže", - "Elizabeth a Darcy se sblíží a vezmou se", - }, - 6, - }, -}; - -static const char *book_pycha_a_predsudek_plot_meaning[] = { - "Správné pořadí: Bingley a ples → předsudky → první nabídka → dopis → Lydia → happy-end.", -}; - -static const LitQ book_rur_qs[] = { - { - "Kdo napsal R.U.R.?", - { - "Jaroslav Hašek", - "Karel Čapek", - "Alois Jirásek", - "Franz Kafka", - }, - 1, - "Drama napsal Karel Čapek; premiéra 1921.", - }, - { - "Co znamená zkratka R.U.R.?", - { - "Rossum's Universal Robots", - "Republika umělých robotů", - "Rudá uniforma robotů", - "Rakouské ústřední rozhlas", - }, - 0, - "Název továrny Rossum's Universal Robots.", - }, - { - "Kdo slovo „robot“ prosadil do světových jazyků?", - { - "Karel Čapek s bratrem Josefem", - "Hašek", - "Kafka", - "Shakespeare", - }, - 0, - "Josef Čapek navrhl slovo robot od robota (dřina).", - }, - { - "Kdo je Harry Domin?", - { - "Robot", - "Ředitel továrny", - "Prezident státu", - "Kněz", - }, - 1, - "Domin řídí R.U.R. a věří v moc techniky.", - }, - { - "Proč přijede Helena Gloryová?", - { - "Koupit roboty pro válku", - "Jako idealistka chce roboty „osvobodit“", - "Je lékařka", - "Je učitelka", - }, - 1, - "Helena brojí proti zneužití robotů – humanitní motiv.", - }, - { - "Co udělá dr. Gall?", - { - "Zničí továrnu", - "Upraví roboty tak, aby měli city a duši", - "Stane se prezidentem", - "Odejde do kláštera", - }, - 1, - "Gallova změna urychlí vzpouru – roboti cítí bolest a hněv.", - }, - { - "Kdo je Alquist?", - { - "Obchodník", - "Stavitel – jediný člověk, který ještě dře rukama", - "Robot", - "Novinář", - }, - 1, - "Alquist přežije jako symbol manuální práce a lidskosti.", - }, - { - "Jak skončí lidstvo v dramatu?", - { - "Vítězí nad roboty", - "Roboti vyhubí lidi (kromě Alquista)", - "Emigruje na Mars", - "Nikdy neumírá", - }, - 1, - "Vzpoura robotů je apokalypsa – zůstane jen Alquist.", - }, - { - "Kdo je Busman?", - { - "Robot", - "Obchodní ředitel – myslí na zisk", - "Helenin otec", - "Voják", - }, - 1, - "Busman reprezentuje kapitalistickou logiku prodeje robotů.", - }, - { - "Jak drama končí?", - { - "Všichni lidé se vrátí", - "Alquist objeví lásku robotů Primuse a Heleny – naděje na nový začátek", - "Roboti se vypnou navždy", - "Továrna exploduje bez pointy", - }, - 1, - "Robotí pár miluje se – možná nová „lidskost“.", - }, - { - "Jaký je žánr R.U.R.?", - { - "Lyrika", - "Drama / sci-fi", - "Román", - "Epos", - }, - 1, - "Jde o divadelní hru s futuristickým tématem.", - }, - { - "Proč lidé v dramatu leniví?", - { - "Roboti dělají veškerou práci", - "Jsou nemocní", - "Zákaz práce", - "Jsou na dovolené", - }, - 0, - "Závislost na robotech oslabí lidstvo – varování Čapka.", - }, - { - "Co je hlavní varování hry?", - { - "Nechat vědu bez etiky a člověka bez práce", - "Nepoužívat elektřinu", - "Zakázat divadlo", - "Vypěstovat více brambor", - }, - 0, - "Čapek varuje před mechanizací života a ztrátou lidskosti.", - }, - { - "Kdy byla premiéra?", - { - "1914", - "1921", - "1948", - "1989", - }, - 1, - "Premiéra v Národním divadle 1921.", - }, - { - "Kdo je Rossum v názvu?", - { - "Vynálezce robotů (legenda firmy)", - "Robot Primus", - "Helenin bratr", - "Císař", - }, - 0, - "Old Rossum – vědec, od něj odvozeno jméno továrny.", - }, - { - "Proč roboti povstávají?", - { - "Náhodou", - "Kvůli bolesti, vykořisťování a Gallovým úpravám", - "Na rozkaz Domin", - "Kvůli počasí", - }, - 1, - "Roboti získají duši a odmítají být otroky.", - }, - { - "Která postava je idealistka?", - { - "Helena Gloryová", - "Busman", - "Domin", - "Alquist", - }, - 0, - "Helena přijede bránit roboty – etický hlas.", - }, - { - "Co je typické pro Čapkovo drama?", - { - "Filozofické otázky v moderní formě", - "Pouze historická kronika", - "Beletrie bez dialogu", - "Pouze komedie bez myšlenky", - }, - 0, - "Čapek spojuje zábavu s varováním před technikou.", - }, - { - "Které téma NENÍ v R.U.R.?", - { - "Vzpoura robotů", - "Lidskost a láska", - "Středověké rytířství", - "Zodpovědnost vědy", - }, - 2, - "Hra je futuristická, ne rytířská.", - }, - { - "Kdo přežije mezi lidmi?", - { - "Domin", - "Busman", - "Alquist", - "Helena Gloryová (člověk)", - }, - 2, - "Alquist zůstane jako poslední člověk pracující rukama.", - }, - { - "Jak se jmenují roboti v závěrečné naději?", - { - "Primus a Helena (robot)", - "Romeo a Julie", - "Švejk a Lukáš", - "Napoleon a Boxer", - }, - 0, - "Robot Primus a robotka Helena se milují – nový začátek.", - }, - { - "Proč je R.U.R. důležité pro maturitu?", - { - "Je mapa", - "Čapek, robot, témata, forma dramatu", - "Je cookbook", - "Je zákoník", - }, - 1, - "U maturity: autor, děj, postavy, slovo robot, témata.", - }, - { - "Kde se děj odehrává?", - { - "V továrně na roboty (ostrov)", - "V Praze na Václaváku", - "Ve středověku", - "Na Měsíci", - }, - 0, - "Ostrovní továrna R.U.R. je jeviště děje.", - }, - { - "Co prodává R.U.R.?", - { - "Knihy", - "Umělé dělníky – roboty", - "Potraviny", - "Auta", - }, - 1, - "Roboti slouží průmyslu i armádám po světě.", - }, - { - "Jaký vztah má Domin k Heleně?", - { - "Vezme si ji", - "Nepozná ji", - "Je to robot", - "Je to sestra", - }, - 0, - "Domin a Helena se sblíží – lidský vztah vedle robotů.", - }, - { - "Co Gallova změna způsobí?", - { - "Roboti jsou šťastnější otroci", - "Roboti cítí a vzpourou se", - "Roboti zmizí", - "Lidé pracují víc", - }, - 1, - "Duše robotů je katalyzátor revolty.", - }, - { - "Které dílo NENÍ Čapkovo?", - { - "R.U.R.", - "Válka s mloky", - "Osudy dobrého vojáka Švejka", - "Bílá nemoc", - }, - 2, - "Švejka napsal Hašek.", - }, - { - "Jaký je tón závěru?", - { - "Čistá apokalypsa bez naděje", - "Tragédie s glorií naděje v lásce robotů", - "Pouze fraška", - "Historický dokument", - }, - 1, - "Čapek končí optimistickým gestem – život pokračuje.", - }, - { - "Kdo myslí hlavně na obchod?", - { - "Busman", - "Alquist", - "Helena", - "Primus", - }, - 0, - "Busman počítá zisk z prodeje robotů.", - }, - { - "Co znamená „lidskost“ v R.U.R.?", - { - "Pouze biologie", - "Práce, soucit, láska – ne jen efektivita", - "Válka", - "Lenost", - }, - 1, - "Alquist a závěr ukazují, co přežije beyond techniky.", - }, -}; - -static const AssemblyItem book_rur_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Helena přijede do továrny R.U.R.", - "Domin ukazuje výrobu robotů a svět obchodu", - "Gall upraví roboty – získají city", - "Vzpoura robotů a vyhubení lidí", - "Zůstane Alquist jako poslední člověk", - "Láska robotů Primuse a Heleny – naděje", - }, - 6, - }, -}; - -static const char *book_rur_plot_meaning[] = { - "Správné pořadí: Helena v továrně → obchod s roboty → Gallova úprava → vzpoura → Alquist → Primus a Helena.", -}; - -static const LitQ book_revizor_qs[] = { - { - "Kdo napsal Revizora?", - { - "Puškin", - "Gogol", - "Tolstoj", - "Dostojevskij", - }, - 1, - "Nikolaj Vasiljevič Gogol; premiéra 1836.", - }, - { - "Jaký je žánr Revizora?", - { - "Satirická komedie", - "Historický román", - "Epos", - "Lyrika", - }, - 0, - "Jde o divadelní satiru na ruskou byrokracii.", - }, - { - "Proč se úředníci v městě vyděsí?", - { - "Přijde povodeň", - "Myslí si, že přijel revizor incognito", - "Vypukne válka", - "Zavřou divadlo", - }, - 1, - "Bobčinskij a Dobčinskij vidí Chlestakova v hospodě a šíří paniku.", - }, - { - "Kdo je Chlestakov?", - { - "Skutečný revizor", - "Chudý úředník, kterého berou za revizora", - "Císař", - "Generál", - }, - 1, - "Chlestakov využije omyl a nechá se obsypat penězi.", - }, - { - "Kdo jsou Bobčinskij a Dobčinskij?", - { - "Revizoři", - "Statkáři, kteří donesou zprávu o „revizorovi“", - "Chlestakovovi rodiče", - "Cizinci z Francie", - }, - 1, - "Dvojice komických statkářů spustí záměnu.", - }, - { - "Kdo je Skvoznik-Dmuchanovskij?", - { - "Městský hlava (gorodničij)", - "Chlestakovův sluha", - "Kuchař", - "Kněz", - }, - 0, - "Anton Antonovič vede radu a nejvíc se bál kontroly.", - }, - { - "Jak Chlestakov reaguje na pocty?", - { - "Uteče hned", - "Přijímá úplatky, pije a chvástá se", - "Obviní všechny z vraždy", - "Odevzdá majetek chudým", - }, - 1, - "Chlestakov rychle pochopí situaci a zneužije ji.", - }, - { - "Kdo je Osip?", - { - "Sluha Chlestakova", - "Revizor", - "Císař", - "Lékař", - }, - 0, - "Osip je praktický sluha, který situaci také využívá.", - }, - { - "Co úředníci nabízejí „revizorovi“?", - { - "Jen květiny", - "Peníze, dary, servilitu – úplatky", - "Nic", - "Jen modlitby", - }, - 1, - "Satira na korupci – každý uplatí revizora.", - }, - { - "Jak Chlestakov opouští město?", - { - "V koze", - "Po dopise a vydírání – odjede s penězi", - "Jako císař", - "Nikdy neodejde", - }, - 1, - "Chlestakov napíše urážlivý dopis a zmizí.", - }, - { - "Jak hra končí?", - { - "Chlestakov se stane hlavou", - "Přijde skutečný revizor – ticho a strach", - "Všichni se smějí", - "Město shoří", - }, - 1, - "Posel oznámí příjezd skutečného revizora – pointa.", - }, - { - "Kde se děj odehrává?", - { - "Petrohrad", - "Malé provinční rusko městečko", - "Paříž", - "Praha", - }, - 1, - "Provincie je typickým prostředím gogolovské satiry.", - }, - { - "Co je hlavní komický mechanismus?", - { - "Nedorozumění identity", - "Magie", - "Vesmírná válka", - "Detektivní stopa", - }, - 0, - "Chudý úředník = revizor – záměna identit.", - }, - { - "Proč je Revizor důležitý pro maturitu?", - { - "Učí chemii", - "Gogol, satira, korupce, forma komedie", - "Je atlas", - "Je kuchařka", - }, - 1, - "U maturity: autor, děj, postavy, satira, závěr.", - }, - { - "Kdy hra premiérovala?", - { - "1836", - "1918", - "1945", - "2000", - }, - 0, - "Premiéra 1836 v Petrohradě.", - }, - { - "Která postava NENÍ v Revizorovi?", - { - "Chlestakov", - "Skvoznik-Dmuchanovskij", - "Hamlet", - "Bobčinskij", - }, - 2, - "Hamlet je Shakespeare, ne Gogol.", - }, - { - "Co satira kritizuje?", - { - "Korupci a servilitu úřadů", - "Pouze počasí", - "Sport", - "Hudbu", - }, - 0, - "Gogol vystaví na posměch ruskou byrokracii.", - }, - { - "Kdo je Zemljanika?", - { - "Správce nemocnice", - "Císař", - "Chlestakovova žena", - "Revizor", - }, - 0, - "Další úředník, který se snaží uplatit „revizora“.", - }, - { - "Jaký je tón hry?", - { - "Satirická komedie s absurdní pointou", - "Pouze tragédie", - "Lyrika", - "Horor", - }, - 0, - "Smích a groteskní situace vedou k mravenčímu závěru.", - }, - { - "Co znamená strach z revizora?", - { - "Strach z kontroly moci shora", - "Strach z bouře", - "Strach z lásky", - "Strach z hudby", - }, - 0, - "Úředníci vědí, že by kontrola odhalila jejich hříchy.", - }, - { - "Proč Chlestakov píše urážlivý dopis?", - { - "Je opilý a drzý – satirická scéna", - "Je to revizor", - "Neví psát", - "Je to milostný dopis", - }, - 0, - "Chlestakov se chvástá a uráží město.", - }, - { - "Kolik dějství má Revizor?", - { - "3", - "5", - "12", - "1", - }, - 1, - "Gogolova komedie má pět dějství.", - }, - { - "Které téma NENÍ typické?", - { - "Korupce", - "Záměna identity", - "Vesmírná sci-fi", - "Strach z moci", - }, - 2, - "Revizor je realistická satira 19. století.", - }, - { - "Kdo donese zprávu o muži v hospodě?", - { - "Bobčinskij a Dobčinskij", - "Císař", - "Julie", - "Švejk", - }, - 0, - "Právě oni spustí lavinu omylů.", - }, - { - "Jak reaguje městská rada na „revizora“?", - { - "Ignoruje ho", - "Servilně ho hostí a uplatí", - "Zavře hradby", - "Odešle do exilu", - }, - 1, - "Všichni se snaží zalíbit a uplatit.", - }, - { - "Co Gogol ukazuje o morálce úředníků?", - { - "Jsou vzorní", - "Jsou korupční a zbabělí", - "Jsou svatí", - "Neexistují", - }, - 1, - "Satira odhaluje hnijící provincii.", - }, - { - "Jaký jazyk / prostředí?", - { - "Carské Rusko, úřednický svět", - "Antika", - "Budoucnost", - "Amerika", - }, - 0, - "Kontext je ruská provincie 19. století.", - }, - { - "Proč je závěr efektní?", - { - "Je tichý – skutečný revizor už je tu", - "Všichni tančí", - "Chlestakov se vrátí jako král", - "Nic se nestane", - }, - 0, - "Po komedii přijde tvrdá realita kontroly.", - }, - { - "Kdo je Chlestakov v profesi?", - { - "Chudý petrohradský úředník", - "Generál", - "Lékař", - "Učitel", - }, - 0, - "Není bohatý – právě proto je komické, že ho berou za mocného.", - }, - { - "Které dílo NENÍ Gogolovo?", - { - "Revizor", - "Mrtvé duše", - "Na západní frontě klid", - "Nos", - }, - 2, - "Remarque napsal Na západní frontě klid.", - }, -}; - -static const AssemblyItem book_revizor_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Bobčinskij a Dobčinskij vidí Chlestakova v hospodě", - "Město panikaří – myslí si, že je to revizor", - "Chlestakova vítají, uplatí a hostí", - "Chlestakov se chvástá a přijímá dary", - "Odjede s penězi a napíše urážlivý dopis", - "Přijede oznámení o skutečném revizorovi", - }, - 6, - }, -}; - -static const char *book_revizor_plot_meaning[] = { - "Správné pořadí: zpráva statkářů → panika → uctívání Chlestakova → chvástání → odjezd → skutečný revizor.", -}; - -static const LitQ book_romeo_a_julie_qs[] = { - { - "Kdo napsal Roméa a Julii?", - { - "Molière", - "William Shakespeare", - "Goethe", - "Dante", - }, - 1, - "Tragédie je jedním z nejznámějších Shakespeareových dramat.", - }, - { - "Kde se děj odehrává?", - { - "Paříž", - "Verona", - "Londýn", - "Praha", - }, - 1, - "Shakespeare zasadil příběh do italské Verony.", - }, - { - "Mezi kterými rody zuří spor?", - { - "Montecchi a Capuletové", - "Medici a Borgiové", - "Habsburkové a Přemyslovci", - "Starkové a Lannisteři", - }, - 0, - "Rodová nenávist je motor tragédie.", - }, - { - "Kdo je Romeo na začátku zamilovaný?", - { - "Do Julie hned", - "Do Rosaline", - "Do Nurse", - "Do Mercutia", - }, - 1, - "Romeo nejprve touží po Rosaline, pak potká Julii.", - }, - { - "Kde se Romeo a Julie poprvé setkají?", - { - "Na balu u Capuletů", - "V klášteře", - "Na popravišti", - "Na lodi", - }, - 0, - "Romeo přijde maskovaně na Capuletův večírek.", - }, - { - "Kdo je Mercutio?", - { - "Romeův přítel, vtipný a impulzivní", - "Julin otec", - "Kněz", - "Revizor", - }, - 0, - "Mercutio je často považován za nejživější postavu hry.", - }, - { - "Kdo zabije Mercutia?", - { - "Romeo", - "Tybalt", - "Julie", - "Nurse", - }, - 1, - "Tybalt v souboji zabije Mercutia – zlom děje.", - }, - { - "Co Romeo udělá poté?", - { - "Uteče do exilu bez pomsty", - "Zabije Tybalta a musí uprchnout z Verony", - "Ožení se s Rosaline", - "Stane se knězem", - }, - 1, - "Romeova pomsta vede k vyhnanství.", - }, - { - "Kdo sjedná tajný sňatek?", - { - "Friar Laurence", - "Tybalt", - "Mercutio", - "Chlestakov", - }, - 0, - "Františkán doufá, že sňatkem ukončí spor rodů.", - }, - { - "Kdo je Nurse?", - { - "Julie chůva a důvěrnice", - "Romeova matka", - "Královna", - "Vražedkyně", - }, - 0, - "Chůva pomáhá Julii s tajnou láskou.", - }, - { - "Proč má Julie brát lektvar?", - { - "Aby usnula jako mrtvá a vyhnula se sňatku s Parisem", - "Aby zabila Romea", - "Aby získala moc", - "Aby cestovala", - }, - 0, - "Friar Laurence plánuje falešnou smrt a sjednocení s Romeem.", - }, - { - "Proč Romeo bere jed?", - { - "Myslí si, že Julie je mrtvá", - "Je to trest soudu", - "Nurse mu ho dá", - "Chce spát", - }, - 0, - "Romeo se dozví o Julii smrti a v hrobce se zabije.", - }, - { - "Jak Julie umírá?", - { - "V souboji", - "Probodne se Romeovým dýkem v hrobce", - "Od lektvaru navždy", - "Stářím", - }, - 1, - "Julie se probudí, vidí mrtvého Romea a zabije se.", - }, - { - "Jak hra končí pro rody?", - { - "Válka pokračuje", - "Rodiče se usmíří nad těly milenců", - "Montecchi vyhrají", - "Capuletové zmizí", - }, - 1, - "Tragédie vede k poměření síly a smíření.", - }, - { - "Jaký je žánr?", - { - "Komedie", - "Tragédie", - "Pohádka", - "Učebnice", - }, - 1, - "Oba hlavní hrdinové umírají – klasická tragédie.", - }, - { - "Co je slavná „balkónová scéna“?", - { - "Romeo a Julie vyznávají lásku", - "Souboj Tybalta", - "Svatba", - "Poprava", - }, - 0, - "Julie na balkóně, Romeo dole – ikonický dialog.", - }, - { - "Kdo je Paris?", - { - "Nápadník Julie, kterého rodina preferuje", - "Romeův bratr", - "Král Verony", - "Mercutio", - }, - 0, - "Rodiče chtějí Julii provdat za Paris.", - }, - { - "Která replika patří k hře?", - { - "Být či nebýt", - "Romeo, Romeo, proč jsi Romeo?", - "Vánoce nebyly bílé", - "Vlk, vlko!", - }, - 1, - "Julie lamentuje nad Romeovým jménem a rodem.", - }, - { - "Proč je hra důležitá pro maturitu?", - { - "Učí účetnictví", - "Shakespeare, tragédie, postavy, jazyk, témata", - "Je mapa", - "Je cookbook", - }, - 1, - "U maturity: děj, postavy, citace, tragédie, láska a konflikt.", - }, - { - "Kdo je Tybalt?", - { - "Julin sestřenec, hašteřivý duelant", - "Kněz", - "Romeův otec", - "Chůva", - }, - 0, - "Tybalt nenávidí Montecchi a provokuje souboj.", - }, - { - "Co znamená téma osudu?", - { - "Postavy vnímají hvězdy a předtuchy", - "Nic", - "Pouze komedie", - "Ekonomika", - }, - 0, - "Shakespeare pracuje s pocitem nevyhnutelnosti.", - }, - { - "Kolik dějství má hra?", - { - "5", - "3", - "12", - "1", - }, - 0, - "Klasická pětaktová struktura tragédie.", - }, - { - "Která postava NENÍ v Roméovi a Julii?", - { - "Mercutio", - "Tybalt", - "Othello", - "Nurse", - }, - 2, - "Othello je jiné Shakespeareovo drama.", - }, - { - "Jaký kontrast hra zdůrazňuje?", - { - "Láska vs. rodová nenávist", - "Práce vs. lenost", - "Věda vs. víra", - "Moře vs. hory", - }, - 0, - "Osobní cit stojí proti kolektivní nenávisti.", - }, - { - "Proč Friar Laurence plán selže?", - { - "Nedorozumění, zpoždění zprávy, unáhlení Romea", - "Julie nechce Romea", - "Tybalt přežije", - "Verona neexistuje", - }, - 0, - "Tragédie je i o náhodě – dopis k Romeo nedorazí včas.", - }, - { - "Kdy vznikla hra?", - { - "Kolem 1595 (renesance)", - "1850", - "1920", - "Antika", - }, - 0, - "Shakespeare píše na konci 16. století.", - }, - { - "Kdo je Benvolio?", - { - "Romeův příbuzný, snaží se mířit konflikty", - "Julin otec", - "Vrah", - "Císař", - }, - 0, - "Benvolio je klidnější protiklad Tybaltovi.", - }, - { - "Které tvrzení je správné?", - { - "Julie je mladší než okolí často předpokládá – ale statečná", - "Julie je královna", - "Romeo nikdy nemiluje", - "Hra končí svatbou", - }, - 0, - "Julie roste v odvaze – od balkónu po rozhodnutí o lektvaru.", - }, - { - "Co NENÍ typické téma?", - { - "Láska", - "Nenávist rodů", - "Industrializace robotů", - "Smrt milenců", - }, - 2, - "Roboti patří k R.U.R., ne k Shakespeareovi.", - }, - { - "Jaký jazyk Shakespeare používá?", - { - "Básnický dialog, metafora, rytmus", - "Pouze próza bez obrazů", - "Češtinu", - "Latinské legrámy", - }, - 0, - "Tragédie kombinuje verš a prózu, bohaté obrazy.", - }, -}; - -static const AssemblyItem book_romeo_a_julie_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Romeo potká Julii na Capuletově večírku", - "Tajný sňatek u Friar Laurence", - "Tybalt zabije Mercutia, Romeo zabije Tybalta", - "Romeo v exile, plán s lektvarem", - "Julie „umírá“, Romeo se zabije v hrobce", - "Julie se probudí a umírá – rody se usmíří", - }, - 6, - }, -}; - -static const char *book_romeo_a_julie_plot_meaning[] = { - "Správné pořadí: setkání → sňatek → souboj a vyhnanství → lektvar → Romeo v hrobce → Julie a smíření rodů.", -}; - -static const LitQ book_romeo_julie_a_tma_qs[] = { - { - "Kdo je autorem novely Romeo, Julie a tma?", - { - "Jan Skácel", - "Jan Otčenášek", - "Arnošt Lustig", - "Jiří Wolker", - }, - 1, - "Novelu napsal Jan Otčenášek; vyšla v roce 1962.", - }, - { - "V jakém období se děj odehrává?", - { - "První republika 1920", - "Protektorát Čechy a Morava, léta 1941–1942", - "Poválečná normalizace", - "Listopad 1989", - }, - 1, - "Děj je zasazen do okupované Prahy krátce po vypuknutí války.", - }, - { - "Kdo je Ester?", - { - "Pavlova sestra", - "Židovská dívka skrývaná u Sedlákových", - "Učitelka němčiny", - "Německá studentka", - }, - 1, - "Ester je pronásledovaná Židovka, která žije v utajení u Hanky Sedlákové.", - }, - { - "Kdo je hlavní hrdina a jaký je jeho věk?", - { - "Petr – dospělý odbojář", - "Pavel – student gymnázia", - "Major Hugo – voják", - "Strýc Sedlák – lékař", - }, - 1, - "Pavel je mladý gymnazista, který prožívá první vážnou lásku.", - }, - { - "Proč je vztah Pavla a Ester nebezpečný?", - { - "Rodiče nesouhlasí se sňatkem", - "Ester je v utajení a kontakt s ní ohrožuje všechny", - "Pavel je vdaný", - "Škola zakazuje chození", - }, - 1, - "Každé setkání s ukrytou Židovkou může vést k zatčení a transportu.", - }, - { - "Na co odkazuje název Romeo, Julie a tma?", - { - "Na operu v Národním divadle", - "Na milostný příběh proti nepřátelskému světu za okupace", - "Na básnickou sbírku Wolkerovu", - "Na film z roku 1968", - }, - 1, - "Otčenášek přenáší motiv zakázané lásky do podmínek holocaustu.", - }, - { - "Kde se Pavel s Ester tajně schází?", - { - "Na Václavském náměstí", - "V bytě Sedlákových / u okna (paralela s balkonem)", - "V Terezíně", - "Na venkově u strýce", - }, - 1, - "Schůzky probíhají skrytě v domě, kde Ester bydlí; evokuje to slavnou scénu Shakespeara.", - }, - { - "Jakou roli hraje Petr?", - { - "Německý důstojník", - "Pavlova strýc, zapojený do odboje", - "Hankin otec", - "Rabín", - }, - 1, - "Petr reprezentuje odpor proti okupaci a varuje Pavla před lehkomyslností.", - }, - { - "Co se stalo s Esterinou rodinou?", - { - "Emigrovala do USA", - "Byla deportována / zlikvidována nacisty", - "Přestěhovala se na venkov legálně", - "Přešla na křesťanství a byla ušetřena", - }, - 1, - "Ester je jedna z mála přeživších z rodiny; ostatní padli oběť persekuci.", - }, - { - "Jak reaguje Pavelův otec na synovu lásku?", - { - "Radostně ji podporuje", - "Bojí se následků a chce syna ochránit", - "Udá syna gestapu", - "Neřeší to", - }, - 1, - "Otec chápe nebezpečí okupace a snaží se Pavla držet stranou rizika.", - }, - { - "Jaký literární text ve škole připomíná vztah hrdinů?", - { - "Babička", - "Romeo a Julie", - "Kytice", - "1984", - }, - 1, - "Shakespearova tragédie slouží jako přímý vzor i kontrast k pražskému ději.", - }, - { - "Co symbolizuje „tma“ v názvu?", - { - "Jen noční schůzky", - "Okupaci, strach, utajení i bezperspektivnost", - "Výpadek elektřiny", - "Zimní období", - }, - 1, - "Tma znamená temnou dobu dějin i nejistotu milenců.", - }, - { - "Jak Hanka pomáhá Ester?", - { - "Získá pro ni falešné doklady sama", - "Skrývá ji doma a tají před okolím", - "Provda ji Němcům", - "Posílá ji do Švýcarska", - }, - 1, - "Rodina Sedlákových riskuje trest, když u sebe drží pronásledovanou dívku.", - }, - { - "Jaký je hlavní konflikt novely?", - { - "Třídní boj dělníků", - "Láska a lidskost vs. rasistický totalitní režim", - "Sportovní rivalita", - "Náboženská reformace", - }, - 1, - "Osobní vztah naráží na politiku genocidy a strach z udání.", - }, - { - "Jaký žánr dílo nejlépe vystihuje?", - { - "Sci-fi novela", - "Milostná novela s válečným a existenčním pozadím", - "Detektivka", - "Satirická groteska", - }, - 1, - "Jádrem je milostný příběh zasazený do doby holocaustu.", - }, - { - "Proč Pavel riskuje setkávání s Ester?", - { - "Kvůli penězům", - "Z lásky a přesvědčení, že lidskost má smysl", - "Na příkaz školy", - "Aby získal vyznamenání", - }, - 1, - "Pavel jedná z citu i morální povinnosti vůči pronásledované.", - }, - { - "Co hrozí rodině, která skrývá Žida?", - { - "Jen pokuta", - "Zatčení, koncentrák nebo poprava", - "Přestup na jinou školu", - "Nic – bylo to běžné", - }, - 1, - "Pomoc pronásledovaným byla za okupace trestná smrtí.", - }, - { - "Jak novela končí pro Pavla?", - { - "Emigruje do Anglie", - "Umírá při pokusu zachránit / následovat Ester", - "Žení se s Hankou", - "Stává se knězem", - }, - 1, - "Pavel zvolí osud milenky a platí za to životem – tragický závěr.", - }, - { - "Co se stane s Ester na konci?", - { - "Přežije v ilegalitě", - "Je odvedena transportem (Terezín)", - "Vdá se za Němce", - "Odjede s Pavlem", - }, - 1, - "Utajení selže; Ester je chycena perzekučním mechanismem.", - }, - { - "Které téma v díle NENÍ dominantní?", - { - "Láska za války", - "Oběť a odvaha", - "Rasismus a genocida", - "Humor sitcomu z 90. let", - }, - 3, - "Novela je vážná, tragická; nejde o komediální formu.", - }, - { - "Jak je vyprávění pojaté?", - { - "Deníkové zápisky Ester", - "Er-forma soustředěná na Pavla", - "Epická báseň", - "Drama s replikami", - }, - 1, - "Vypravěč sleduje hlavně Pavlovy prožitky a rozhodnutí.", - }, - { - "Proč je školní prostředí důležité?", - { - "Ukazuje normální život mládí v nenormální době", - "Je to sci-fi laboratoř", - "Slouží jen jako kulisa bez významu", - "Popisuje výuku latině", - }, - 0, - "Gymnázium zdůrazňuje kontrast mezi mládím a okupačním terorem.", - }, - { - "Jaký vztah má novela k české literatuře 60. let?", - { - "Patří k reflexi holocaustu a morálky za války", - "Je čistě experimentální text", - "Je překlad z ruštiny", - "Je dětská knížka", - }, - 0, - "Otčenášek přispěl k vážné próze o druhé světové válce.", - }, - { - "Co znamená motiv okna / balkonu?", - { - "Reklamu na okna", - "Naději na setkání a paralelu s Julií", - "Pohled do Terezína", - "Vězení", - }, - 1, - "Okno umožňuje tajné schůzky a odkazuje ke Shakespearovi.", - }, - { - "Kdo je Hanka vůči Ester?", - { - "Sestra", - "Spolužačka a ochránkyně v domě", - "Gestapák v přestrojení", - "Učitelka", - }, - 1, - "Hanka je blízká Ester i Pavlovi a stojí mezi nimi a nebezpečím.", - }, - { - "Jak funguje strach z udání v díle?", - { - "Vůbec se neobjevuje", - "Prolíná rodinnými hádkami i rozhodnutími postav", - "Je jen v epilogu", - "Týká se jen Němců", - }, - 1, - "Atmosféra podezíravosti ovlivňuje každý krok hrdinů.", - }, - { - "Jaký rozdíl je mezi Pavlem a Julií z Shakespeara?", - { - "Pavel je dospělý král", - "Pavel jedná v reálné totalitní hrozící smrti milionů", - "Pavel nemiluje", - "Pavel je Němec", - }, - 1, - "Historický kontext genocidy zvyšuje sázky oproti renesanční tragédii.", - }, - { - "Proč Otčenášek volil milostnou formu?", - { - "Aby čtenáře citově vtáhl do osudu jednotlivců", - "Aby napsal učebnici dějepisu", - "Aby parodoval romantiku", - "Aby vydal cookbook", - }, - 0, - "Osobní příběh zosobňuje oběť holocaustu lépe než statistika.", - }, - { - "Jaké poselství dílo nejspíš nese?", - { - "Lidskost má cenu i za cenu největšího rizika", - "Válka je hra", - "Láska vždy končí svatbou", - "Okupace neexistovala", - }, - 0, - "Pavel a Ester ukazují morální volbu tváří v tvář zlu.", - }, - { - "Která postava reprezentuje aktivní odpor?", - { - "Pavelův otec jako gestapák", - "Strýc Petr", - "Hankin pes", - "Německý turista", - }, - 1, - "Petr je vázán na odbojové prostředí a realitu nebezpečí.", - }, -}; - -static const AssemblyItem book_romeo_julie_a_tma_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Pavel na gymnáziu za okupace čte Romea a Julii", - "Seznámí se s Ester skrytou u Sedlákových", - "Navazují tajný milostný vztah u okna", - "Petr a rodina varují před rostoucím nebezpečím", - "Ester je prozrazena a odvedena transportem", - "Pavel ji následuje a umírá", - }, - 6, - }, -}; - -static const char *book_romeo_julie_a_tma_plot_meaning[] = { - "Správné pořadí: škola a Shakespear → seznámení s Ester → tajná láska → varování → transport → Pavlova smrt.", -}; - -static const LitQ book_rozmarne_leto_qs[] = { - { - "Kdo napsal Rozmarné léto?", - { - "Karel Čapek", - "Vladislav Vančura", - "Ota Pavel", - "Jan Neruda", - }, - 1, - "Autorem je Vančura, dílo vyšlo 1926.", - }, - { - "Kde se děj zčásti odehrává?", - { - "Pražský hrad", - "Venkov u rybníka / maloměstí", - "Tatra", - "Paříž", - }, - 1, - "Léto tráví hrdinové na venkově u vody.", - }, - { - "Kdo je major Hugo?", - { - "Kněz", - "Bývalý důstojník, jeden ze tří přátel", - "Rybář Pepča", - "Německý turista", - }, - 1, - "Hugo je vitální organizátor prázdnin.", - }, - { - "Kým je Roch?", - { - "Malíř", - "Vědec a intelektuál mezi přáteli", - "Soudce", - "Poštmistr", - }, - 1, - "Roch představuje vědeckou, někdy směšnou erudici.", - }, - { - "Co dělá Hampl?", - { - "Učí dějepis", - "Malíř, pozorovatel děje", - "Lovec", - "Lékař", - }, - 1, - "Hampl maluje a komentuje dění.", - }, - { - "Jaký žánr dílo nejlépe vystihuje?", - { - "Sci-fi", - "Poetická novela s groteskou", - "Detektivka", - "Epická báseň", - }, - 1, - "Vančura kombinuje lyriku a humor.", - }, - { - "Co se stane Pepči?", - { - "Vdá se za Huga", - "Utone v rybníce", - "Odchází do Prahy", - "Stane se malířkou", - }, - 1, - "Tragické utopení naruší idylu léta.", - }, - { - "Proč je léto „rozmarné“?", - { - "Je zima", - "Kolísá mezi lehkostí, humorem a smutnými zvraty", - "Trvá jeden den", - "Je to sci-fi", - }, - 1, - "Nálada se mění od radosti k tragédii.", - }, - { - "Jaký jazyk je typický pro Vančuru?", - { - "Úřednický", - "Poetický, obrazný, kolážovitý", - "Archaičtina bez obrazů", - "Anglický slang", - }, - 1, - "Styl je výrazově bohatý a hudební.", - }, - { - "Kdo je soudkyně v díle?", - { - "Pepčina matka", - "Místní autorita, která soudí pomluvy", - "Hugova sestra", - "Rochova žena", - }, - 1, - "Soudkyně zosobňuje maloměstskou morálku.", - }, - { - "Jaký vztah mají tři muži?", - { - "Jsou bratři", - "Přátelé na prázdninách s rozdílnými charaktery", - "Nepřátelé", - "Spolupracovníci továrny", - }, - 1, - "Jejich interakce tvoří jádro humoru.", - }, - { - "Co symbolizuje rybník?", - { - "Průmysl", - "Léto, odpočinek, ale i nebezpečí vody", - "Válka", - "Škola", - }, - 1, - "Rybník je centrum dění i místo tragédie.", - }, - { - "Jak končí Rochova anabáze?", - { - "Stane se králem", - "Je vykázán / opouští místo po konfliktech", - "Zůstane navždy", - "Oženě se s Pepčou", - }, - 1, - "Roch musí odejít – jeden z groteskních vrcholů.", - }, - { - "Které téma v díle najdeme?", - { - "Kosmické války", - "Maloměstské pomluvy a letní nálada", - "Detektivní vyšetřování v Praze", - "Hladové hry", - }, - 1, - "Dílo je zrcadlem provinčního světa.", - }, - { - "Vančura patří do které literární skupiny?", - { - "Realismus 19. století", - "Avantgarda (Devětsil)", - "Romantismus", - "Normalizace", - }, - 1, - "Vančura byl výrazná avantgardní osobnost.", - }, - { - "Jak je vyprávění pojaté?", - { - "Drama s replikami", - "Er-forma s lyrickými odbočkami", - "Deník", - "Scénář filmu", - }, - 1, - "Vypravěč vytváří obrazné výjevy.", - }, - { - "Co je groteska v Rozmarném létě?", - { - "Pouze realismus", - "Nadsazené, absurdní situace v komickém světle", - "Horor bez humoru", - "Historický dokument", - }, - 1, - "Humor vychází z kontrastů a detailů.", - }, - { - "Proč se Roch stává terčem posměchu?", - { - "Je bohatý", - "Je pedantský vědec v lehkém letním světě", - "Je dítě", - "Je Němec", - }, - 1, - "Jeho vědeckost naráží na prázdninovou atmosféru.", - }, - { - "Jaká je role faráře / místních?", - { - "Vedou válku", - "Dotvářejí obraz maloměsta", - "Jsou hlavní hrdinové", - "Neobjevují se", - }, - 1, - "Podpůrné postavy vytvářejí prostředí.", - }, - { - "Jaký kontrast dílo nabízí?", - { - "Léto vs. smrt", - "Pouze humor", - "Pouze politika", - "Sci-fi vs. western", - }, - 0, - "Idyla léta je narušena Pepčinou smrtí.", - }, - { - "Kdy Vančura zemřel?", - { - "1926", - "1942 (poprava nacisty)", - "1989", - "1891", - }, - 1, - "Spisovatel padl za protinacistický odpor.", - }, - { - "Co NENÍ typické pro Vančurův styl?", - { - "Koláž", - "Lyrická próza", - "Suchý úřednický jazyk bez obrazů", - "Groteska", - }, - 2, - "Vančura je naopak obrazný a poetický.", - }, - { - "Jak major Hugo jedná?", - { - "Pasivně", - "Energicky, organizuje, rozhoduje", - "Jako kněz", - "Jako dítě", - }, - 1, - "Hugo táhne děj svou aktivitou.", - }, - { - "Proč je dílo vhodné k maturitě?", - { - "Krátké, bohaté na styl a témata", - "Je učebnice", - "Je komiks", - "Nemá děj", - }, - 0, - "Ukazuje avantgardní prózu i společenský obraz.", - }, - { - "Jaký vztah k přírodě dílo má?", - { - "Příroda chybí", - "Příroda je lyricky vykreslena", - "Jen město", - "Pouze továrna", - }, - 1, - "Krajina je součástí poetiky.", - }, - { - "Co následuje po Pepčině smrti?", - { - "Válka světová hned", - "Tíživější tón, rozchod letní idyly", - "Svatba", - "Nic se nemění", - }, - 1, - "Tragédie změní náladu knihy.", - }, - { - "Která postava maluje?", - { - "Roch", - "Hampl", - "Hugo", - "Pepča", - }, - 1, - "Hampl je malíř.", - }, - { - "Jak se dílo liší od realistické novely?", - { - "Experimentuje s jazykem a groteskou", - "Je to přesný reportážní zápis", - "Je to báseň v jedné větě", - "Je to drama", - }, - 0, - "Vančura je avantgardní autor.", - }, - { - "Jaký je vztah k humoru?", - { - "Humor chybí", - "Humor je důležitý, i když je děj tragický", - "Pouze slovní hříčka bez děje", - "Jen slapstick", - }, - 1, - "Komické scény koexistují se smutnými.", - }, - { - "Co znamená „rozmarné“ v kontextu postav?", - { - "Vědecká přesnost", - "Náladovost, lehkost, občasná lehkomyslnost", - "Vojenská disciplína", - "Náboženská zbožnost", - }, - 1, - "Léto uvolňuje pravidla a rozproudí vášně i konflikty.", - }, -}; - -static const AssemblyItem book_rozmarne_leto_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Tři přátelé přijedou na léto k rybníku", - "Probíhají komické konflikty (Roch vs. okolí)", - "Léto plné pomluv, lázní a radovánek", - "Pepča se utopí v rybníce", - "Roch je vykázán z místa", - "Léto končí, idyla je narušena", - }, - 6, - }, -}; - -static const char *book_rozmarne_leto_plot_meaning[] = { - "Správné pořadí: příjezd → konflikty → letní dění → utopení Pepči → odchod Rocha → konec léta.", -}; - -static const LitQ book_ruze_pro_algernon_qs[] = { - { - "Kdo napsal Růži pro Algernona?", - { - "Isaac Asimov", - "Daniel Keyes", - "Ray Bradbury", - "Orwell", - }, - 1, - "Autorem je Daniel Keyes.", - }, - { - "Jakou formu má novela?", - { - "Drama", - "Deníkové zápisy Charlieho", - "Epická báseň", - "Dopisy", - }, - 1, - "Text simuluje Charlieho rostoucí jazykové i myšlenkové schopnosti.", - }, - { - "Kdo je Algernon?", - { - "Pes", - "Laboratorní myš", - "Charlieův bratr", - "Profesor", - }, - 1, - "Myš prošla stejnou operací jako Charlie.", - }, - { - "Kde Charlie pracuje na začátku?", - { - "V bance", - "V pekárně", - "Na univerzitě", - "V nemocnici", - }, - 1, - "Kolegové se mu smějí, ale nechává si to líbit.", - }, - { - "Co vědci Charlieovi slibují?", - { - "Zázračnou dietu", - "Operaci zvýšení inteligence", - "Cestu na Měsíc", - "Sňatek", - }, - 1, - "Experiment má zvýšit IQ.", - }, - { - "Kdo je Alice Kinnian?", - { - "Vědkyně", - "Učitelka dospělých, podporuje Charlieho", - "Charlieho sestra", - "Sestra Nemura", - }, - 1, - "Alice je etickou oporou příběhu.", - }, - { - "Co se děje s Charlieho IQ po operaci?", - { - "Klesá hned", - "Rychle roste na génius", - "Nemění se", - "Klesá na nulu", - }, - 1, - "Charlie začne chápat svět i minulost bolestně jasně.", - }, - { - "Proč se kolegové z pekárny od Charlieho vzdalují?", - { - "Bojí se jeho inteligence a cizího", - "Dostal funkci ředitele", - "Odešel do vězení", - "Ne – stále ho milují", - }, - 0, - "Charlie už mezi nimi nemá místo.", - }, - { - "Co odhalí vzpomínky na matku?", - { - "Lásku bez podmínek", - "Trauma, stud a odmítání postiženého syna", - "Emigraci", - "Nobelovu cenu", - }, - 1, - "Rodinná minulost bolí.", - }, - { - "Co se stane s Algernonem?", - { - "Žije navěky", - "Inteligence klesá a myš umírá", - "Uteče", - "Stane se člověkem", - }, - 1, - "Pokles předpovídá Charlieův osud.", - }, - { - "Jak Charlie reaguje na Algernonovu smrt?", - { - "Radost", - "Položí květiny – odtud název", - "Zapomene", - "Zničí laboratoř", - }, - 1, - "Soucit s myší je vrchol jeho humanity.", - }, - { - "Proč Charlie konfliktuje s Nemurem?", - { - "Kvůli fotbalu", - "Vědec je arogantní, Charlie vidí chyby experimentu", - "Kvůli jídlu", - "Kvůli manželce", - }, - 1, - "Charlie chápe vědu hlouběji než tvůrce experimentu.", - }, - { - "Jak se mění Charlieův jazyk v deníku?", - { - "Beze změny", - "Od pravopisných chyb k vědecké přesnosti a zpět", - "Do latině", - "Do němčiny", - }, - 1, - "Jazyk je měřítkem inteligence.", - }, - { - "Jak skončí Charlie?", - { - "Je prezident", - "Inteligence klesá, vrací se do pekárny, umírá v ústavu", - "Emigruje", - "Ožení se a žije šťastně", - }, - 1, - "Tragický pád po vrcholu.", - }, - { - "Co téma etiky zdůrazňuje?", - { - "Experiment bez rizika je v pořádku", - "Lidský život není jen IQ", - "Věda je vždy zlá", - "Deník je neetický", - }, - 1, - "Keyes kritizuje redukci člověka na číslo.", - }, - { - "Který žánr sedí nejlépe?", - { - "Sci-fi s psychologickým jádrem", - "Historický román", - "Pohádka", - "Detektivka", - }, - 0, - "Vědecký základ + hluboká psychologie.", - }, - { - "Proč Charlie miloval učení už jako postižený?", - { - "Ne – nenáviděl", - "Toužil být chytřejší a „normální“", - "Chtěl být bohatý", - "Musel na rozkaz", - }, - 1, - "Motivace je touha po přijetí.", - }, - { - "Co znamená „normální“ pro Charlieho?", - { - "Být bohatý", - "Být přijat společností jako rovnocenný", - "Být slavný", - "Nečíst", - }, - 1, - "Společenské normy jsou klíčové.", - }, - { - "Jaký vztah k Alice?", - { - "Nikdy se nevidí", - "Láska, která komplikuje Charlieho proměnu", - "Sourozenci", - "Nepřátelé", - }, - 1, - "Alice miluje Charlieho jako člověka, ne jen IQ.", - }, - { - "Co Charlie objeví o „inteligentních“?", - { - "Jsou vždy milí", - "Mohou být stejně krutí a osamělí", - "Neexistují", - "Jsou všichni vědci", - }, - 1, - "Vysoké IQ neřeší morálku.", - }, - { - "Kde se vrací na konci?", - { - "Do vesmíru", - "Do pekárny / ústavu", - "Do školy", - "Do vězení", - }, - 1, - "Kruhový návrat k počátku.", - }, - { - "Jaký film/novela ocenění?", - { - "Ignorováno", - "Nezískala Nobelovu cenu, ale je světově známá", - "Pouze v ČR", - "Jen divadlo", - }, - 1, - "Dílo je klasikou světové literatury.", - }, - { - "Co NENÍ hlavní téma?", - { - "Inteligence a identita", - "Etika vědy", - "Soucit", - "Kosmické války", - }, - 3, - "Děj je psychologický, ne space opera.", - }, - { - "Proč deník funguje jako forma?", - { - "Čtenář vidí proměnu zevnitř", - "Je to úřední protokol", - "Je to poezie", - "Je to horor", - }, - 0, - "Subjektivní záznam je autentický.", - }, - { - "Kdo se směje na začátku?", - { - "Charlie sám", - "Kolegové z pekárny", - "Nikdo", - "Algernon", - }, - 1, - "Charlie nerozumí posměchu plně.", - }, - { - "Co Charlie chápe po operaci o posměchu?", - { - "Nic", - "Bolest a ponižování minulosti", - "Je to lichotka", - "Je to věda", - }, - 1, - "Vhled bolí víc než nevědomost.", - }, - { - "Jaký symbol mají květiny?", - { - "Vítězství", - "Úcta k malému tvorovi a vlastnímu úpadku", - "Svatba", - "Válka", - }, - 1, - "Růže pro Algernona = soucit.", - }, - { - "Jaký je tón závěru?", - { - "Čistá radost", - "Tragický, dojemný", - "Komický bez smutku", - "Ironický satira", - }, - 1, - "Charlie se vrací k mentálnímu stavu a umírá osamělý.", - }, - { - "Co Keyes kritizuje?", - { - "Pekárny", - "Přehnanou důvěru ve vědu bez humanity", - "Deníky", - "Myši", - }, - 1, - "Experiment má cenu v lidských životech.", - }, - { - "Kolik otázek má maturitní test z knihy typicky?", - { - "0", - "Desítky faktů o ději, postavách, tématech", - "Jen autor", - "Jen rok", - }, - 1, - "Dílo je bohaté na postavy a témata.", - }, -}; - -static const AssemblyItem book_ruze_pro_algernon_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Charlie pracuje v pekárně a píše deník", - "Podstoupí operaci zvýšení inteligence", - "IQ roste, odhalí bolest minulosti", - "Algernonova inteligence klesá a myš umírá", - "Charlie chápe vlastní úpadek", - "Vrací se k původnímu stavu a umírá", - }, - 6, - }, -}; - -static const char *book_ruze_pro_algernon_plot_meaning[] = { - "Správné pořadí: pekárna → operace → vzestup → Algernon → úpadek → návrat a smrt.", -}; - -static const LitQ book_saturnin_qs[] = { - { - "Kdo napsal Saturnina?", - { - "Čapek", - "Zdeněk Jirotka", - "Hašek", - "Němcová", - }, - 1, - "Autorem je Jirotka, kniha 1942.", - }, - { - "Kdo je Saturnin?", - { - "Pes", - "Sluha s neobvyklými nápady", - "Učitel", - "Policista", - }, - 1, - "Saturnin je hlavní komická postava.", - }, - { - "Kdo vypráví?", - { - "Saturnin", - "Člen rodiny (syn)", - "Teta", - "Učitel", - }, - 1, - "Ich-forma mladého vypravěče.", - }, - { - "Jaký je žánr?", - { - "Tragedie", - "Humoristická novela", - "Sci-fi", - "Básnická skladba", - }, - 1, - "Dílo je komické od začátku do konce.", - }, - { - "Kde se děj odehrává?", - { - "Venkov", - "Praha – rodinný byt a okolí", - "Moře", - "Amerika", - }, - 1, - "Pražské prostředí je typické.", - }, - { - "Jak Saturnin řeší problémy?", - { - "Vždy logicky", - "Vynalézavě, často absurdně", - "Vůbec", - "Volá policii", - }, - 1, - "Jeho metody jsou zdrojem humoru.", - }, - { - "Kdo je teta?", - { - "Saturninova manželka", - "Příbuzná v domě, komické konflikty", - "Učitelka", - "Sousedka bez role", - }, - 1, - "Teta často stojí proti Saturninovi.", - }, - { - "Co je pan učitel?", - { - "Hrdina bez humoru", - "Pedantská postava, terč satiry", - "Saturninův bratr", - "Němec", - }, - 1, - "Učitel představuje malichernou autoritu.", - }, - { - "Jaký humor převažuje?", - { - "Černý bez radosti", - "Situační a slovní", - "Horor", - "Politická satira bez vtipu", - }, - 1, - "Nedorozumění a dialogy jsou klíč.", - }, - { - "Proč je Saturnin tajemný?", - { - "Je špion", - "Jeho minulost a motivy jsou nejasné", - "Je duch", - "Je robot", - }, - 1, - "Autor nechává prostor pro dohady.", - }, - { - "Co jsou lumpárny?", - { - "Vážné zločiny", - "Nezbednosti / žertíky", - "Vědecké experimenty", - "Válka", - }, - 1, - "Součást humoru a dětského světa.", - }, - { - "Kdy kniha vyšla?", - { - "1942", - "1890", - "2005", - "1968", - }, - 0, - "Saturnin vyšel za války.", - }, - { - "Má kniha pokračování?", - { - "Ne, nikdy", - "Ano, další díly o Saturninovi", - "Je to trilogie Tolkinova", - "Je to drama", - }, - 1, - "Jirotka Saturnina rozvinul v dalších knihách.", - }, - { - "Jak reaguje rodina na Saturnina?", - { - "Okamžitě ho vyhodí", - "Kombinace obdivu, vzteku a závislosti", - "Neznají ho", - "Udají ho", - }, - 1, - "Saturnin je nepostradatelný i nebezpečný.", - }, - { - "Co NENÍ typické?", - { - "Lehký tón", - "Absurdní situace", - "Stálá politická allegorie jako u 1984", - "Dialogy", - }, - 2, - "Saturnin je především humor, ne dystopie.", - }, - { - "Jaká role mají sousedé?", - { - "Žádná", - "Přidávají komické konflikty", - "Vedou válku", - "Jsou detektivové", - }, - 1, - "Sousedské vztahy rozproudí děj.", - }, - { - "Proč je dílo populární u maturit?", - { - "Krátké, čtivé, jasné postavy", - "Bez děje", - "Jen poezie", - "Cizí jazyk", - }, - 0, - "Snadno se shrnuje děj i humor.", - }, - { - "Jaký je vztah vypravěče a Saturnina?", - { - "Nenávist", - "Fascinace a spolupráce v lumpárnách", - "Manželé", - "Učitel–žák", - }, - 1, - "Vypravěč Saturnina často obdivuje.", - }, - { - "Co Saturnin „umí“ nejlépe?", - { - "Mlčet", - "Vymýšlet nečekaná řešení", - "Vařit jen polévku", - "Létat", - }, - 1, - "Je mistr improvizace.", - }, - { - "Jak končí většina epizod?", - { - "Tragedií", - "Rozuzlením komického chaosu", - "Válka", - "Transport", - }, - 1, - "Formát je episodický humor.", - }, - { - "Který autor je blízký žánrem?", - { - "Jirotka – humor próza", - "Shakespeare – tragédie", - "Borovský – elegie", - "Vančura – groteska bez humoru", - }, - 0, - "Jirotka je klasik českého humoru.", - }, - { - "Co znamená jméno Saturnin?", - { - "Náhodné", - "Evokuje starověk / tajemno (ironicky)", - "Německý generál", - "Pes", - }, - 1, - "Jméno dodává postavě patos i komiku.", - }, - { - "Jaký jazyk?", - { - "Archaičtina", - "Spisovná čeština s hovorovými prvky", - "Angličtina", - "Latině", - }, - 1, - "Čtivé, přirozené dialogy.", - }, - { - "Je Saturnin zlý?", - { - "Ano, vrah", - "Ne – spíš rošťák a vynálezce chaosu", - "Anděl", - "Historická postava", - }, - 1, - "Je sympatický provokatér.", - }, - { - "Co děti v knize?", - { - "Neexistují", - "Účastní se lumpáren", - "Vedou válku", - "Jsou dospělí", - }, - 1, - "Dětský svět doplňuje humor.", - }, - { - "Hlavní konflikt?", - { - "Saturnin vs. pořádek domácnosti", - "Napoleon vs. Wellington", - "Věda vs. víra", - "Detektiv vs. vrah", - }, - 0, - "Sluha bourá klid rodiny.", - }, - { - "Tón knihy?", - { - "Depresivní", - "Optimistický humor", - "Naturalismus", - "Epický smutek", - }, - 1, - "Čtenář se má bavit.", - }, - { - "Adaptace?", - { - "Film/seriál v ČR známé", - "Nikdy", - "Opera Wagner", - "Balet", - }, - 0, - "Saturnin je známý i z obrazovky.", - }, - { - "Co si odnést k maturitě?", - { - "Postavy, humor, typ sluhy v literatuře", - "Jen rok vydání", - "Jen Praha mapa", - "Nic", - }, - 0, - "Dílo je o charakteru Saturnina a stylu.", - }, - { - "Saturnin pracuje pro?", - { - "Císaře", - "Pražskou rodinu", - "Školu", - "Cirkus", - }, - 1, - "Rodinný sluha je jádro děje.", - }, -}; - -static const AssemblyItem book_saturnin_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Rodina najme sluhu Saturnina", - "Saturnin rozpoutá lumpárny a chaos", - "Konflikty s tetou a učitelem", - "Sousedé řeší absurdní situace", - "Saturnin vše „vyřeší“ po svém", - "Klid je jen na chvíli – humor pokračuje", - }, - 6, - }, -}; - -static const char *book_saturnin_plot_meaning[] = { - "Správné pořadí: nástup Saturnina → lumpárny → konflikty → sousedé → improvizované řešení → pokračující chaos.", -}; - -static const LitQ book_sluha_dvou_panu_qs[] = { - { - "Kdo napsal Sluhu dvou pánů?", - { - "Molière", - "Carlo Goldoni", - "Shakespeare", - "Gogol", - }, - 1, - "Goldoni je italský autor komedií.", - }, - { - "Jak se jmenuje sluha?", - { - "Figaro", - "Truffaldino", - "Saturnin", - "Svejk", - }, - 1, - "Truffaldino je hlavní komická postava.", - }, - { - "Kolik pánů slouží?", - { - "Jeden", - "Dva současně (tajně)", - "Deset", - "Žádného", - }, - 1, - "Dvojí služba je zdroj záměn.", - }, - { - "Kdo je Beatrice?", - { - "Služka bez role", - "Dívka v převleku muže hledající Florinda", - "Pantalonova žena", - "Královna", - }, - 1, - "Beatrice hraje roli Federiga.", - }, - { - "Kdo je Florindo?", - { - "Sluha", - "Milovník Beatrice", - "Doktor", - "Vojevoda", - }, - 1, - "Florindo je jeden z „pánů“.", - }, - { - "Co je commedia dell'arte?", - { - "Tragedie", - "Italská komedie s typovými postavami", - "Opera", - "Epos", - }, - 1, - "Tradice Arlecchina, Pantalone atd.", - }, - { - "Kdo je Pantalone?", - { - "Mladý hrdina", - "Lakomý stařec, typ dell'arte", - "Sluha", - "Kněz", - }, - 1, - "Pantalone je klasická maska.", - }, - { - "Kdo je Brighella?", - { - "Hospodský pomáhající záměnám", - "Král", - "Beatricin otec v převleku", - "Němec", - }, - 0, - "Brighella organizuje část komplikací.", - }, - { - "Kdo je Smeraldina?", - { - "Služka, milá Truffaldina", - "Beatrice", - "Vdova", - "Učitelka", - }, - 0, - "Služební pár kontrastuje k šlechtě.", - }, - { - "Proč Truffaldino slouží dvěma?", - { - "Chce být bohatý – dvojí plat", - "Nevědomky / lstivě", - "Na rozkaz císaře", - "Kvůli pomstě", - }, - 1, - "Chce profit, riskuje odhalení.", - }, - { - "Co se zaměňuje?", - { - "Jen jídlo", - "Dopisy, zavazadla, peníze", - "Nic", - "Jen domy", - }, - 1, - "Záměny pohánějí děj.", - }, - { - "Jak končí hra?", - { - "Všichni umírají", - "Rozuzlení, sňatky, happy end", - "Válka", - "Transport", - }, - 1, - "Klasická komedie končí sblížením.", - }, - { - "Kde se děj odehrává?", - { - "Praha", - "Benátky", - "Moskva", - "Londýn", - }, - 1, - "Benátské prostředí.", - }, - { - "Goldoni reformoval?", - { - "Tragedii", - "Dell'arte směrem k psané komedii", - "Operu", - "Epos", - }, - 1, - "Goldoni stabilizoval text hry.", - }, - { - "Jaký humor?", - { - "Pouze slovní", - "Situační, fyzický, záměny", - "Horor", - "Bez humoru", - }, - 1, - "Rychlé komické situace.", - }, - { - "Beatrice proč v převleku?", - { - "Sport", - "Hledá Florinda a cestuje bezpečně", - "Je to trest", - "Neví", - }, - 1, - "Převlek je motor děje.", - }, - { - "Truffaldino a Smeraldina?", - { - "Nepřátelé", - "Milenci ze služebnictva", - "Sourozenci", - "Pantalone", - }, - 1, - "Paralelní milostná linka.", - }, - { - "Co hrozí při odhalení?", - { - "Vtip končí", - "Truffaldino může být potrestán / komické chaosy", - "Nic", - "Válka", - }, - 1, - "Hrozba odhalení drží napětí.", - }, - { - "Typ hry pro maturitu?", - { - "Drama – komedie", - "Lyrika", - "Epika bez dialogů", - "Pohádka", - }, - 0, - "Jde o divadelní text.", - }, - { - "Kdo je Arlecchino v tradici?", - { - "Předchůdce sluhy/loutny", - "Král", - "Vědec", - "Kněz", - }, - 0, - "Truffaldino vychází z typu sluhy.", - }, - { - "Proč služba dvěma pánům vtipná?", - { - "Logická", - "Obě strany chtějí jídlo/dopisy ve stejný čas", - "Bez děje", - "Tragická", - }, - 1, - "Fyzický komický stres.", - }, - { - "Goldoni žil kdy?", - { - "18. století", - "20. století", - "Antika", - "21. století", - }, - 0, - "Goldoni 1707–1793.", - }, - { - "Hlavní téma?", - { - "Válka", - "Láska, lstivost, třídní hra", - "Věda", - "Detektivka", - }, - 1, - "Komedie lásky a identit.", - }, - { - "Pantalone je typicky?", - { - "Mladý milovník", - "Lakomý stařec", - "Sluha", - "Voják", - }, - 1, - "Ekonomický humor.", - }, - { - "Co NENÍ v dell'arte?", - { - "Typové postavy", - "Improvizace tradice", - "Vždy tragický konec", - "Masky", - }, - 2, - "Komedie končí obvykle happy endem.", - }, - { - "Florindo a Beatrice na konci?", - { - "Rozchod", - "Spojení / sňatek", - "Smrt", - "Emigrace", - }, - 1, - "Milenci se najdou.", - }, - { - "Truffaldino na konci?", - { - "Oběsí se", - "Obvykle vítězí lstí, získá Smeraldinu", - "Zmizí", - "Stane se králem", - }, - 1, - "Sluha často „vyhrává“ komedii.", - }, - { - "Proč maturita?", - { - "Klasická komedie, jasná struktura", - "Bez postav", - "Jen poezie", - "Cizí bez překladu", - }, - 0, - "České překlady jsou standardem.", - }, - { - "Jaký rytmus hry?", - { - "Pomalý", - "Rychlý, gradace záměn", - "Bez děje", - "Epický", - }, - 1, - "Komedie graduje ke koci.", - }, - { - "Co čtenář/ divák sleduje?", - { - "Chemii", - "Sled záměn kvůli dvojí službě", - "Válku", - "Básně", - }, - 1, - "Mechanismus dvou pánů je jádro.", - }, -}; - -static const AssemblyItem book_sluha_dvou_panu_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Truffaldino najme službu u prvního pána", - "Tajně slouží i druhému", - "Beatrice v převleku hledá Florinda", - "Záměny dopisů a jídla", - "Hrozí odhalení dvojí služby", - "Happy end – páry spolu, chaos rozuzlen", - }, - 6, - }, -}; - -static const char *book_sluha_dvou_panu_plot_meaning[] = { - "Správné pořadí: první pán → druhý pán → převlek Beatrice → záměny → hrozba odhalení → happy end.", -}; - -static const LitQ book_smrt_krasnych_srncu_qs[] = { - { - "Kdo napsal Smrt krásných srnců?", - { - "Vančura", - "Ota Pavel", - "Hrabal", - "Němcová", - }, - 1, - "Ota Pavel, vydání 1971.", - }, - { - "Jaká forma díla?", - { - "Jedna novela", - "Soubor autobiografických povídek", - "Drama", - "Básnická skladba", - }, - 1, - "Kniha je soubor povídek.", - }, - { - "Kde dětství probíhá?", - { - "Praha centrum", - "Příbramsko / okolí", - "Siberie", - "Itálie", - }, - 1, - "Pavel vyrůstal v tomto kraji.", - }, - { - "Čím je otec známý?", - { - "Učitelem", - "Holičem, rybářem, sportovcem", - "Knězem", - "Politiem", - }, - 1, - "Otec je ústřední postava vzpomínek.", - }, - { - "Co prožívá otec za války?", - { - "Dovolenou", - "Koncentrační tábor", - "Ministerskou funkci", - "Emigraci", - }, - 1, - "Tábor je traumatická linka.", - }, - { - "Co znamená titulní povídka?", - { - "Lovecký zážitek po válce – smrt srn", - "Smrt ryb", - "Smrt ve městě", - "Sci-fi", - }, - 0, - "Srnci symbolizují krásu zničenou.", - }, - { - "Jaký tón převažuje?", - { - "Humor i dojetí", - "Pouze horor", - "Bez emocí", - "Politický manifest", - }, - 0, - "Pavel mísí vtip a smutek.", - }, - { - "Rybaření v knize?", - { - "Chybí", - "Důležitý motiv radosti a vztahu s otcem", - "Jen sport pro armádu", - "Zakázané", - }, - 1, - "Ryby a voda jsou obrazem svobody.", - }, - { - "Kdo vypráví?", - { - "Otec", - "Ota Pavel jako vzpomínající", - "Němec", - "Učitel", - }, - 1, - "Autobiografický vypravěč.", - }, - { - "Proč je dílo v maturitě?", - { - "Česká próza 20. st., paměť války", - "Bez témat", - "Jen humor bez hloubky", - "Cizí jazyk", - }, - 0, - "Spojuje válku, rodinu, přírodu.", - }, - { - "Jak matka funguje?", - { - "Bez role", - "Drží rodinu při otci v táboře", - "Je Němka", - "Je lovec", - }, - 1, - "Matka je opora domácnosti.", - }, - { - "Bratři v knize?", - { - "Neexistují", - "Antonín, Jiří – součást rodiny", - "Jen cizinci", - "Vědci", - }, - 1, - "Rodinné vztahy jsou důležité.", - }, - { - "Příroda je?", - { - "Nepřítel", - "Útočiště a radost dětství", - "Jen kulisa", - "Město", - }, - 1, - "Les a voda kontrastují s válkou.", - }, - { - "Humor Pavla?", - { - "Chybí", - "Dětský pohled, groteskní detaily", - "Pouze slovní hříčka", - "Nadávky", - }, - 1, - "Humor je laskavý i hořký.", - }, - { - "Kdy Pavel zemřel?", - { - "1973", - "1990", - "1950", - "2000", - }, - 0, - "Spisovatel zemřel relativně mladý.", - }, - { - "Co NENÍ téma?", - { - "Válka a tábor", - "Rodina", - "Rybaření", - "Kosmické kolonie", - }, - 3, - "Dílo je zakořeněné v českém venkově.", - }, - { - "Otec se vrací z tábora?", - { - "Ano, rodina to prožívá", - "Ne, nikdy", - "Je to fikce bez války", - "Emigruje", - }, - 0, - "Návrat otce je silný moment.", - }, - { - "Jazyk Pavla?", - { - "Úřednický", - "Hovorový, živý, obrazný", - "Archaičtina", - "Angličtina", - }, - 1, - "Pavel píše s nadhledem.", - }, - { - "Další kniha Pavla?", - { - "Zlatí úhoři", - "1984", - "Babička", - "Kytice", - }, - 0, - "Zlatí úhoři navazují na rybářské motivy.", - }, - { - "Proč „krásní“ srnci?", - { - "Oškliví", - "Krása zvěře kontrastuje s její smrtí", - "Ironie bez smyslu", - "Reklama", - }, - 1, - "Titul zdůrazňuje ztrátu krásy.", - }, - { - "Dětský vypravěč?", - { - "Vidí svět nevině i s bolestí", - "Je dospělý generál", - "Je Němec", - "Nevidí válku", - }, - 0, - "Dětská perspektiva je typická.", - }, - { - "Sport u Pavla?", - { - "Hokej, fotbal vzpomínky", - "Jen šachy", - "Nic", - "Pouze box", - }, - 0, - "Otec sportuje, syn obdivuje.", - }, - { - "Kniha vyšla za?", - { - "Normalizace 1971", - "1890", - "2010", - "1940", - }, - 0, - "Vydání v 70. letech.", - }, - { - "Emoce čtenáře?", - { - "Smích i dojetí", - "Pouze nuda", - "Strach horor", - "Bez reakce", - }, - 0, - "Pavel je mistr nálady.", - }, - { - "Vztah k Hrabalovi?", - { - "Oba humor + všednost", - "Identičtí", - "Bez paralely", - "Hrabal napsal srnce", - }, - 0, - "Generačně blízcí, různý styl.", - }, - { - "Lovecký motiv?", - { - "Etika lovu po válce", - "Vesmír", - "Politika strany", - "Škola", - }, - 0, - "Titulní povídka reflektuje poválečný lov.", - }, - { - "Co si pamatovat o otci?", - { - "Slaboch", - "Silná, tragická, obdivuhodná postava", - "Villain", - "Cizinec", - }, - 1, - "Otec je hrdina vzpomínek.", - }, - { - "Proč autobiografie?", - { - "Autenticita paměti", - "Fikce bez základu", - "Překlad", - "Sborová poezie", - }, - 0, - "Vychází z Pavlova života.", - }, - { - "Krátce: jádro knihy?", - { - "Rodina, válka, příroda, humor", - "Detektivka", - "Sci-fi", - "Opera", - }, - 0, - "To jsou hlavní osy.", - }, - { - "Pavel byl také?", - { - "Fotbalový komentátor / novinář", - "Král", - "Německý spisovatel", - "Malíř", - }, - 0, - "Pavel pracoval v médiích.", - }, -}; - -static const AssemblyItem book_smrt_krasnych_srncu_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Dětství Oty a rodina holiče", - "Rybaření, sport, radosti", - "Otec odveden do tábora", - "Matka drží domácnost", - "Otec se vrací, válka končí", - "Titulní lov – smrt krásných srnců", - }, - 6, - }, -}; - -static const char *book_smrt_krasnych_srncu_plot_meaning[] = { - "Správné pořadí: dětství → radosti → tábor → doma bez otce → návrat → povídka o srncích.", -}; - -static const LitQ book_sofiina_volba_qs[] = { - { - "Kdo napsal Sofiinu volbu?", - { - "Hemingway", - "William Styron", - "Styron není – Keyes", - "Kundera", - }, - 1, - "Styron, román 1979.", - }, - { - "Kdo vypráví?", - { - "Sophie", - "Stingo – mladý spisovatel", - "Nathan", - "Němec", - }, - 1, - "Stingo je svědek příběhu Sophie.", - }, - { - "Kdo je Sophie?", - { - "Američanka", - "Polská přeživší holocaustu", - "Německá voják", - "Učitelka", - }, - 1, - "Sophie prošla koncentráky.", - }, - { - "Kdo je Nathan?", - { - "Sophiein stabilní manžel", - "Vášnivý, psychicky nemocný milenec", - "Stingův otec", - "Rabín", - }, - 1, - "Nathan je geniální i nebezpečný.", - }, - { - "Co znamená „Sofiina volba“?", - { - "Výběr školy", - "Rozhodnutí, které dítě nechat žít v Auschwitzi", - "Volby prezidenta", - "Výběr jídla", - }, - 1, - "Sophie musela zvolit mezi Janem a Evou.", - }, - { - "Kde žijí v USA?", - { - "Brooklyn", - "Praha", - "Paříž", - "Siberie", - }, - 0, - "Poválečný New York / Brooklyn.", - }, - { - "Jak končí Sophie?", - { - "Šťastně", - "S Nathanem sebevraždou", - "Emigrace", - "S Stingem", - }, - 1, - "Tragický konec milenců.", - }, - { - "Proč Sophie trpí?", - { - "Bez důvodu", - "Vina z holocaustu a volby", - "Jen láska", - "Sport", - }, - 1, - "Trauma ji ničí.", - }, - { - "Co Stingo dělá?", - { - "Píše, pozoruje pár", - "Vede Auschwitz", - "Je doktor", - "Je dítě", - }, - 0, - "Mladý autor hledá materiál i lásku.", - }, - { - "Jaký žánr?", - { - "Psychologický román s historickým flashbackem", - "Pohádka", - "Sci-fi", - "Komedie", - }, - 0, - "Spojení lásky a holocaustu.", - }, - { - "Děti Sophie?", - { - "Jan a Eva", - "Tom a Jerry", - "Nick a Daisy", - "Žádné", - }, - 0, - "Obě padly oběti režimu.", - }, - { - "Nathanova nemoc?", - { - "Schizofrenie / psychóza", - "Chřipka", - "Slepota", - "Bez nemoci", - }, - 0, - "Jeho chování je nepředvídatelné.", - }, - { - "Proč je dílo kontroverzní?", - { - "Lehkost", - "Zobrazuje extrémní etické dilema", - "Bez holocaustu", - "Komiks", - }, - 1, - "Volba matky je otřesná.", - }, - { - "Flashbacky kam?", - { - "Do Polska / Auschwitz", - "Do Marsu", - "Do středověku", - "Nikam", - }, - 0, - "Minulost vysvětluje přítomnost.", - }, - { - "Téma viny?", - { - "Chybí", - "Přeživší cítí vinu za volby", - "Jen politika", - "Sport", - }, - 1, - "Sophie nemůže odpustit sobě.", - }, - { - "Film?", - { - "Natáčen s Meryl Streep", - "Neexistuje", - "Cartoon", - "Silent", - }, - 0, - "Film 1982, oscarové role.", - }, - { - "Stingo pochází?", - { - "Z amerického Jihu", - "Z Čech", - "Z Německa", - "Z Marsu", - }, - 0, - "Jižanské kořeny vypravěče.", - }, - { - "Co NENÍ téma?", - { - "Holocaust", - "Láska a destrukce", - "Trauma", - "Kosmické války", - }, - 3, - "Děj je realistický.", - }, - { - "Sophie na začátku?", - { - "Šťastná bez minulosti", - "Krásná, tajemná, traumatizovaná", - "Dítě", - "Generál", - }, - 1, - "Stingo je okouzlen.", - }, - { - "Proč maturita?", - { - "Etické otázky, historie, postavy", - "Jen milostná novela bez hloubky", - "Bez děje", - "Jen autor", - }, - 0, - "Dílo je náročné na rozbor.", - }, - { - "Jak Styron líčí holocaust?", - { - "Legračně", - "Přes Sophieiny vzpomínky – osobně", - "Bez detailů", - "Jen statistika", - }, - 1, - "Individuální osud.", - }, - { - "Co následuje po odhalení volby?", - { - "Nic", - "Hlubší pochopení Sophieina pádu", - "Svatba", - "Válka", - }, - 1, - "Climax vysvětluje psychiku.", - }, - { - "Nathan Sophie?", - { - "Nenávidí", - "Miluje vášnivě i tyransky", - "Nezná", - "Je bratr", - }, - 1, - "Vztah je toxický.", - }, - { - "Alkohol u Sophie?", - { - "Nepije", - "Utišuje trauma", - "Jen voda", - "Povinnost", - }, - 1, - "Sebedestrukce.", - }, - { - "Poselství?", - { - "Etické limity nelze zjednodušit", - "Holocaust nebyl", - "Láska vše vyřeší", - "Volba neexistuje", - }, - 0, - "Román ukazuje nemožná rozhodnutí.", - }, - { - "Kdy vyšlo?", - { - "1979", - "1942", - "2000", - "1890", - }, - 0, - "Konec 70. let.", - }, - { - "Překlad v ČR?", - { - "Nenadál aj.", - "Bez překladu", - "Shakespeare", - "Hašek", - }, - 0, - "České vydání známé.", - }, - { - "Stingo a Sophie?", - { - "Stingo ji miluje, ona volí Nathana", - "Sňatek", - "Sourozenci", - "Nic", - }, - 0, - "Neukojená láska vypravěče.", - }, - { - "Struktura?", - { - "Současnost + retrospektivy", - "Jen básně", - "Drama jedné scény", - "Epos", - }, - 0, - "Střídání časů.", - }, - { - "Proč „volba“ otřásá?", - { - "Malicherná", - "Matka rozhoduje o životě dítěte", - "Vtip", - "Sport", - }, - 1, - "Nejtěžší morální situace.", - }, -}; - -static const AssemblyItem book_sofiina_volba_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Stingo pozná Sophie a Nathana", - "Vztah páru je vášnivý a nebezpečný", - "Sophie vypráví o válce a Auschwitzi", - "Odhalí se Sofiina volba mezi dětmi", - "Trauma a Nathanova nemoc eskalují", - "Sophie a Nathan spáchají sebevraždu", - }, - 6, - }, -}; - -static const char *book_sofiina_volba_plot_meaning[] = { - "Správné pořadí: seznámení → milostný trojúhelník → flashbacky → volba → eskalace → sebevražda.", -}; - -static const LitQ book_fuks_qs[] = { - { - "Kdo je hlavní postava románu a jaké je jeho povolání?", - { - "Pan Kopfrkingl – zaměstnanec krematoria", - "Willi Reinke – nacistický důstojník", - "Dr. Bettelheim – psychiatr", - "Pan Kopfrkingl – ředitel školy", - }, - 0, - "Hlavní postavou je pan Kopfrkingl, spořádaný zaměstnanec krematoria, který svou práci vnímá jako poslání.", - }, - { - "V jakém prostředí pan Kopfrkingl pracuje?", - { - "V nemocnici", - "V krematoriu", - "V divadle", - "Ve škole", - }, - 1, - "Kopfrkingl pracuje v krematoriu, kde má na starosti zpopelňování zemřelých.", - }, - { - "V jaké historické době se děj románu odehrává?", - { - "Za první republiky", - "Za protektorátu Čechy a Morava (před a během 2. světové války)", - "Po roce 1989", - "V 19. století", - }, - 1, - "Román se odehrává v době nastupujícího nacismu a protektorátu, který umožňuje Kopfrkinglovu proměnu.", - }, - { - "Jak se proměňuje hlavní hrdina v průběhu příběhu?", - { - "Z laskavého spořádaného muže v chladnokrevného vraha a fanatika", - "Z vraha v kajícníka", - "Z chudáka v boháče", - "Vůbec se nemění", - }, - 0, - "Kopfrkingl se postupně mění v člověka, který vraždí své blízké a ospravedlňuje to vyšším dobrem.", - }, - { - "Jaký je vztah pana Kopfrkingla k jeho rodině na začátku knihy?", - { - "Nenávidí je", - "Je starostlivý, zdvořilý a především spořádaný", - "S rodinou se nezná", - "Týrá je", - }, - 1, - "Na začátku působí jako vzorný manžel a otec, posedlý řádem a zdvořilostí.", - }, - { - "Jak se jmenuje manželka pana Kopfrkingla a jaký je jejich vztah?", - { - "Marie – milují se", - "Lakmé – formálně zdvořilý, chladný vztah", - "Zina – nenávidí se", - "Julie – jsou rozvedení", - }, - 1, - "Manželka se jmenuje Lakmé. Jejich vztah je spíš zdvořilá forma než opravdová láska.", - }, - { - "Jaký je vztah pana Kopfrkingla k dětem, Zině a Mílovi?", - { - "Miluje je víc než sebe", - "Chová se k nim odtažitě, jako k součásti řádu", - "Nevidí je", - "Jsou adoptované", - }, - 1, - "K dětem je odměřený; vnímá je spíš jako součást svého spořádaného světa než jako milované bytosti.", - }, - { - "Kdo je Willi Reinke a jakou roli hraje v proměně hlavního hrdiny?", - { - "Soused z krematoria", - "Německý úředník a bývalý voják, který Kopfrkingla ovlivní", - "Kopfrkinglův bratr", - "Lékař v nemocnici", - }, - 1, - "Reinke je Němec, který v Kopfrkinglovi probudí touhu po árijském původu a kariéře.", - }, - { - "Jak Willi Reinke ovlivňuje Kopfrkinglovo smýšlení?", - { - "Přesvědčí ho, aby se přidal k nacistům a byl „lepší“", - "Nabádá ho k odchodu do zahraničí", - "Učí ho tibetštinu", - "Nijak ho neovlivní", - }, - 0, - "Reinke v něm posiluje antisemitismus a touhu po moci a uznání v novém režimu.", - }, - { - "Jaký je Kopfrkinglův vztah ke krematoriu a smrti obecně?", - { - "Bojí se jich", - "Má je rád, kremaci vnímá jako krásný obřad osvobození", - "Nechce tam pracovat", - "Je mu to lhostejné", - }, - 1, - "Smrt a kremace jsou pro něj estetickým a filozofickým rituálem, ne něčím hrůzným.", - }, - { - "Jak pan Kopfrkingl vnímá a popisuje proces kremace?", - { - "Jako nutné zlo", - "Jako vznešený, očistný obřad, o kterém rád mluví", - "Jako hroznou povinnost", - "Nikdy o něm nemluví", - }, - 1, - "Kopfrkingl o kremaci hovoří básnivě a s nadšením, což ostře kontrastuje s hrůzou jeho činů.", - }, - { - "Jaká je symbolika krematoria v celém románu?", - { - "Symbol naděje", - "Smrt, odlidštění a zvrácená ideologie, která z lidí dělá jen těla", - "Symbol lásky", - "Symbol mládí", - }, - 1, - "Krematorium je ústředním symbolem – odhaluje chladnou mašinerii smrti, do níž se ideologie snaží proměnit člověka.", - }, - { - "Co symbolizuje Kopfrkinglova záliba v tibetské Knize mrtvých?", - { - "Jeho touhu po vědění a zvrácenou víru ve vlastní výjimečnost", - "Historický zájem o Asii", - "Strach ze smrti", - "Lásku k manželce", - }, - 0, - "Kopfrkingl si z ní vybírá jen to, co se hodí k ospravedlnění jeho činů a jeho pocitu vyvolenosti.", - }, - { - "Jak se v knize projevuje motiv buddhismu a reinkarnace?", - { - "Kopfrkingl jimi ospravedlňuje smrt jako „osvobození duše“", - "Postavy se modlí k Bohu", - "Nikde se neobjevuje", - "Je to hlavní téma manželky", - }, - 0, - "Reinkarnace a „osvobození od utrpení“ se v jeho mysli zvrhávají v právo zabíjet.", - }, - { - "Jak Kopfrkingl zneužívá filozofické a náboženské myšlenky?", - { - "Ospravedlňuje jimi vlastní vraždy jako službu vyššímu dobru", - "Pomáhá jimi druhým", - "Odmítá je", - "Používá je jen v práci", - }, - 0, - "Z vznešených idejí si staví masku, za kterou skrývá krutost a touhu po moci.", - }, - { - "Jak se postupně mění Kopfrkinglova mluva a způsob vyjadřování?", - { - "Začíná mluvit vulgárně", - "Mění se v patetickou, ráznou řeč plnou frází o řádu a osvobození", - "Přestane mluvit", - "Od začátku mluví jen německy", - }, - 1, - "Jeho zdvořilá mluvnost se postupně mění v ideologické fráze a bezcitný patos.", - }, - { - "Jaké opakující se fráze nebo návyky pana Kopfrkingla si všímáš?", - { - "Neustále se ptá na počasí", - "Opakuje „to je takové“, „vidíte“ a lpí na zdvořilosti", - "Zpívá si", - "Mluví jen o jídle", - }, - 1, - "Opakující se fráze a zdvořilostní obraty vytvářejí rytmus, který je čím dál tím děsivější.", - }, - { - "Jaký je vypravěčský styl románu (ich-forma, er-forma)?", - { - "Er-forma bez vnitřního světa", - "Ich-forma – vypráví sám Kopfrkingl", - "Deníková forma", - "Forma dopisů", - }, - 1, - "Ich-forma je klíčová: čtenář sleduje svět zkreslený Kopfrkinglovou myslí a sám postupně propadá jeho logice.", - }, - { - "Jak se v knize projevuje černý humor a groteska?", - { - "Vážné scény jsou líčeny s odstupem a absurditou", - "Kniha je čistě vážná", - "Humor je jediný žánr", - "V knize se neprojevuje", - }, - 0, - "Groteskní kontrast mezi slavnostním vyprávěním a hrůzou vytváří mrazivý černý humor.", - }, - { - "Jak kontrastuje banalita každodenního života s hrůzností činů?", - { - "Vůbec nesouvisí", - "Všední detaily a zdvořilost činí hrůzu ještě děsivější", - "Hrůza je potlačena", - "Den je popsán jen jednou", - }, - 1, - "Fuks zesiluje otřes tím, že vraždění je popisováno stejně klidně jako ranní káva nebo kremace.", - }, - { - "Jak se v knize projevuje antisemitismus?", - { - "Od začátku otevřeně", - "Postupně, nejdřív v náznacích a vlivem Reinkeho", - "Nikdy", - "Jen mimochodem v závěru", - }, - 1, - "Kopfrkinglův antisemitismus se rodí pozvolna a je živen dobovou atmosférou i Reinkem.", - }, - { - "Jak nacistická ideologie postupně prostupuje Kopfrkinglovo myšlení?", - { - "Odmítá ji", - "Přijímá ji jako vyšší řád a ospravedlnění vlastní výjimečnosti", - "Nerozumí jí", - "Zajímá ho jen hudba", - }, - 1, - "Ideologie se mu stává nástrojem kariéry i vnitřním ospravedlněním vražd.", - }, - { - "Jak se mění Kopfrkinglův vztah k manželce kvůli jejímu původu?", - { - "Začne ji milovat víc", - "Odcizí se jí, protože je židovského původu", - "Nijak se nemění", - "Odstěhují se od sebe", - }, - 1, - "Kvůli jejímu původu ji přestane vnímat jako rovnocennou a nakonec ji zabije.", - }, - { - "Co se stane s Kopfrkinglovou rodinou ve druhé polovině románu?", - { - "Odstěhují se", - "Kopfrkingl svou ženu i děti zabije", - "Všichni přežijí", - "Zachrání je Reinke", - }, - 1, - "Pod vlivem ideologie Kopfrkingl vyvraždí vlastní rodinu a považuje to za „osvobození“.", - }, - { - "Jak Kopfrkingl zdůvodňuje vraždu vlastní ženy?", - { - "Zlobila se na něj", - "Že je židovského původu a překáží jeho kariéře", - "Že ho podváděla", - "Nijak ji nezdůvodňuje", - }, - 1, - "Svou ženu zabije mimo jiné proto, že je židovského původu, tedy „méněcenná“ pro nový režim.", - }, - { - "Jakým způsobem Kopfrkingl vraždí své blízké?", - { - "Ve zlosti a afektu", - "Chladně a s pocitem, že je „osvobozuje od utrpení“", - "Omylem", - "Na příkaz úřadů", - }, - 1, - "Vraždí klidně, jako by vykonával bohulibý úkon, a svou krutost si vykládá jako soucit.", - }, - { - "Jak souvisí přesvědčení o „osvobození“ s jeho vražednými činy?", - { - "Dává mu zdání vyššího smyslu, kterým si vraždy ospravedlňuje", - "Nemá s nimi nic společného", - "Brání mu v zabíjení", - "Je to jen náhodná fráze", - }, - 0, - "Zvrácená víra v osvobození od utrpení mu slouží jako mravní alibi pro vraždy.", - }, - { - "Jaký je vztah pana Kopfrkingla k postavě Dr. Bettelheima?", - { - "Obdivuje ho a rád s ním mluví", - "Nenávidí ho", - "Nikdy se nepotkají", - "Je to jeho nadřízený", - }, - 0, - "S doktorem Bettelheimem vede Kopfrkingl své „filozofické“ rozhovory o smrti a lidskosti.", - }, - { - "Jak se mění společenské postavení pana Kopfrkingla v době okupace?", - { - "Upadá", - "Stoupá – díky režimu a touze po árijském původu", - "Nemění se", - "Odchází do penze", - }, - 1, - "Spolu s nacistickou mocí roste i Kopfrkinglova kariéra a sebevědomí.", - }, - { - "Jaký je symbolický význam jména Kopfrkingl?", - { - "Zdánlivě úřednické, ale zní hrozivě – naznačuje zvrácenost", - "Je to běžné české jméno", - "Znamená „laskavý“", - "Je to pseudonym", - }, - 0, - "Zvukomalebné jméno působí úředně a zároveň hrozivě, což podtrhuje dvojí tvář postavy.", - }, - { - "Jak funguje motiv masek, divadla a přetvářky?", - { - "Postavy nosí masky dobroty, pod nimiž se skrývá krutost", - "V knize jsou jen skutečné divadelní masky", - "Motiv se neobjevuje", - "Masky symbolizují lásku", - }, - 0, - "Přetvářka a předstíraná spořádanost jsou ústřední – zlo se tváří jako slušnost.", - }, - { - "Jaký je vztah mezi soukromým a kolektivním šílenstvím doby?", - { - "Kopfrkinglovo osobní šílenství roste spolu s ideologií doby", - "Nijak nesouvisí", - "Doba je klidná a šťastná", - "Lidé režim jednomyslně odmítají", - }, - 0, - "Fuks ukazuje, jak se individuální porucha napojí na kolektivní ideologii a čerpá z ní sílu.", - }, -}; - -static const AssemblyItem book_fuks_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Kopfrkingl je spořádaným zaměstnancem krematoria", - "Seznámí se s Willim Reinkem", - "Začne věřit v árijskou nadřazenost", - "Postupně se odcizí své rodině", - "Zabije ženu a děti jako „osvobození“", - "Na konci se považuje za vtělení Dalajlámy", - }, - 6, - }, -}; - -static const char *book_fuks_plot_meaning[] = { - "Správné pořadí: spořádaný úředník → setkání s Reinkem → árijská ideologie → odcizení rodině → vraždy → přesvědčení o vlastní božskosti.", -}; - -static const LitQ book_stare_recke_baje_qs[] = { - { - "Kdo sestavil Staré řecké báje (české vydání)?", - { - "Homér", - "Eduard Petiška", - "Neruda", - "Čapek", - }, - 1, - "Petiška moderně převyprávěl mýty.", - }, - { - "Jaká forma?", - { - "Původní řecká tragédie", - "Prozaické převyprávění mýtů", - "Sci-fi", - "Opera", - }, - 1, - "Pro mládež a školy.", - }, - { - "Kdo vládne bohům?", - { - "Poseidon", - "Zeus", - "Hádés", - "Apollo", - }, - 1, - "Zeus je nejvyšší.", - }, - { - "Co udělal Prométheus?", - { - "Zničil svět", - "Daroval lidem oheň", - "Vybudoval Prahu", - "Napsal Bibli", - }, - 1, - "Za to byl potrestán.", - }, - { - "Herakles je známý?", - { - "Dvanácti úkoly", - "Jedinou písničkou", - "Bez činů", - "Jako král Čech", - }, - 0, - "Labours of Heracles.", - }, - { - "Odysseus?", - { - "Cesta z Troje domů na Ithaku", - "Byl v Praze", - "Nemý", - "Bůh", - }, - 0, - "Odysseia motiv.", - }, - { - "Perseus?", - { - "Zabil Medúzu", - "Vynalezl kolo", - "Byl sluha", - "Němec", - }, - 0, - "Hrdina s hlavou Medúzy.", - }, - { - "Theseus?", - { - "Minotaur v labyrintu", - "Americký sen", - "Box", - "Kněz", - }, - 0, - "Krétský mýtus.", - }, - { - "Orfeus?", - { - "Sestoupil do podsvětí za Eurydikou", - "Válka", - "Fotbal", - "Bez hudby", - }, - 0, - "Mýtus o lásce a hudbě.", - }, - { - "Hádés?", - { - "Podsvětí", - "Moře", - "Nebe", - "Škola", - }, - 0, - "Realm of dead.", - }, - { - "Poseidon?", - { - "Moře a zemětřesení", - "Oheň", - "Válka", - "Láska", - }, - 0, - "Bůh moře.", - }, - { - "Hubris znamená?", - { - "Pokoru", - "Pýchu trestanou bohy", - "Lásku", - "Mír", - }, - 1, - "Časté téma mýtů.", - }, - { - "Proč mýty vznikaly?", - { - "Vysvětlení světa a morálky", - "Reklama", - "Sport", - "Bez důvodu", - }, - 0, - "Funkce mýtu.", - }, - { - "Petiška styl?", - { - "Srozumitelný moderní jazyk", - "Archaičtina bez smyslu", - "Angličtina", - "Šifra", - }, - 0, - "Přístupné mládeži.", - }, - { - "Troja v mýtech?", - { - "Válka o Helenu", - "Česká vesnice", - "Sci-fi", - "Neexistuje", - }, - 0, - "Ilias souvislost.", - }, - { - "Pandora?", - { - "Otevřela skříňku zla", - "Královna Prahy", - "Sluha", - "Němka", - }, - 0, - "Mýtus o zlu ve světě.", - }, - { - "Narcis?", - { - "Zamilovaný do vlastního odrazu", - "Generál", - "Rybář", - "Učitel", - }, - 0, - "Slovo narcismus.", - }, - { - "Sisyfos?", - { - "Trest – valit kámen", - "Král štěstí", - "Bůh", - "Dítě", - }, - 0, - "Absurdní trest.", - }, - { - "Antické bohyně?", - { - "Athéna – moudrost", - "Jen muži", - "Bez jmen", - "Pouze Héra", - }, - 0, - "Bohové i bohyně.", - }, - { - "Co NENÍ v sbírce?", - { - "Řecké mýty", - "Antická hrdinství", - "České pohádky Boženy Němcové jako jádro", - "Bohové", - }, - 2, - "Jde o řeckou mytologii.", - }, - { - "Eurynomé / stvoření?", - { - "Kosmogonické mýty na začátku", - "Chybí", - "Jen válka", - "Jen comedy", - }, - 0, - "Od chaosu k bohům.", - }, - { - "Maturita – proč?", - { - "Základ evropské kultury", - "Bez významu", - "Jen jména", - "Jen mapa", - }, - 0, - "Odkaz na antiku.", - }, - { - "Ikaros?", - { - "Let voskových křídel – pád", - "Vítězství", - "Mořeplavec bez pádu", - "Kněz", - }, - 0, - "Varování před pýchou.", - }, - { - "Afrodita?", - { - "Láska a krása", - "Válka", - "Moudrost", - "Lovec", - }, - 0, - "Bohyně.", - }, - { - "Dionýsos?", - { - "Víno, extáze", - "Moře", - "Podsvětí", - "Kování", - }, - 0, - "Bůh.", - }, - { - "Téma osudu?", - { - "Moira – nevyhnutelné", - "Neexistuje", - "Jen sci-fi", - "Jen humor", - }, - 0, - "Řekové věřili v osud.", - }, - { - "Petiška profese?", - { - "Spisovatel, dramatik", - "Německý voják", - "Sportovec", - "Malíř", - }, - 0, - "Český autor.", - }, - { - "Medúza?", - { - "Z oka petrifikace", - "Anděl", - "Učitelka", - "Rybářka", - }, - 0, - "Perseus ji porazil.", - }, - { - "Pro mládež?", - { - "Ano, čtivé převyprávění", - "Ne, jen pro vědce", - "Bez textu", - "Jen obrazky", - }, - 0, - "Školní klasika.", - }, - { - "Hlavní hodnota?", - { - "Poznání antické mytologie", - "Návod na vaření", - "Geografie USA", - "Programování", - }, - 0, - "Kulturní přehled.", - }, -}; - -static const AssemblyItem book_stare_recke_baje_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Mýty o vzniku světa a bohů", - "Příběhy Prométhea a pokušení lidí", - "Hrdinské úkoly (Herakles, Perseus)", - "Odysseova cesta a válka u Troje", - "Láska, hubris a tresty bohů", - "Soubor mýtů jako obraz řecké mysli", - }, - 6, - }, -}; - -static const char *book_stare_recke_baje_plot_meaning[] = { - "Správné pořadí: kosmogonie → bohové → hrdinské mýty → Odysseus/Troja → morální lekce → kulturní celek.", -}; - -static const LitQ book_starec_a_more_qs[] = { - { - "Kdo napsal Stařce a moře?", - { - "Fitzgerald", - "Ernest Hemingway", - "Melville", - "Styron", - }, - 1, - "Hemingway, 1952.", - }, - { - "Kdo je Santiago?", - { - "Mladý pirát", - "Starý kubánský rybář", - "Učitel", - "Němec", - }, - 1, - "Hlavní hrdina.", - }, - { - "Kolik dní bez úlovku?", - { - "84 dní smůly", - "1 den", - "1000", - "0", - }, - 0, - "Dlouhá série neúspěchu.", - }, - { - "Kdo je Manolin?", - { - "Chlapec, který se stará o Santiaga", - "Žralok", - "Marlin", - "Král", - }, - 0, - "Shoři / Manolin.", - }, - { - "Co Santiago chytí?", - { - "Sardinky", - "Obří marlina", - "Krab", - "Nic", - }, - 1, - "Souboj trvá dny.", - }, - { - "Kde probíhá souboj?", - { - "Na moři daleko od břehu", - "V lese", - "V Praze", - "Na souši", - }, - 0, - "Otevřené moře.", - }, - { - "Co marlin symbolizuje?", - { - "Pouze jídlo", - "Krásu, sílu, respekt hrdiny", - "Zlo", - "Boha", - }, - 1, - "Santiago marlina obdivuje.", - }, - { - "Co zničí úlovek?", - { - "Bouře", - "Žraloci", - "Policie", - "Manolin", - }, - 1, - "Cestou zpět žraloci.", - }, - { - "Jak Santiago končí?", - { - "Vítězí bohatý", - "Přiveze jen kostru – morální vítězství", - "Umírá moře", - "Emigruje", - }, - 1, - "Fyzická porážka, duch statečný.", - }, - { - "Nobelova cena?", - { - "Hemingway ji dostal mj. za toto dílo", - "Nikdy", - "Melville", - "Keyes", - }, - 0, - "1954 Nobel.", - }, - { - "Fráze o porážce?", - { - "Člověk může být zničen, ale ne poražen", - "Válka je mír", - "Bůh mrtvý", - "Bez fráze", - }, - 0, - "Klíčové poselství.", - }, - { - "Lvi ve snu?", - { - "Symbol mládí Afriky / síly", - "Realita", - "Nepřítel", - "Žraloci", - }, - 0, - "Santiago o nich sní.", - }, - { - "Styl Hemingwaye?", - { - "Krátké věty, málo adjektiv", - "Dlouhé periodické věty", - "Verš", - "Drama", - }, - 0, - "Iceberg theory.", - }, - { - "Délka?", - { - "Novela – kratší než román", - "Epos", - "Báseň", - "Trilogie", - }, - 0, - "Kompaktní dílo.", - }, - { - "Kubánské prostředí?", - { - "Havana, rybářská vesnice", - "New York", - "Paříž", - "Siberie", - }, - 0, - "Karibik.", - }, - { - "Manolin na konci?", - { - "Plánuje znovu rybařit se Santiagem", - "Zapomene", - "Umírá", - "Odchází", - }, - 0, - "Naděje v generaci.", - }, - { - "Téma osamění?", - { - "Ano, stařec sám na moři", - "Ne", - "Jen komedie", - "Jen politika", - }, - 0, - "Existenciální osamění.", - }, - { - "Co NENÍ téma?", - { - "Houževnatost", - "Důstojnost", - "Kosmické války", - "Respekt k přírodě", - }, - 2, - "Realistická novela.", - }, - { - "Marlin vs Santiago?", - { - "Respekt soupeřů", - "Nenávist", - "Bez boje", - "Marlin vyhrává bohatství", - }, - 0, - "Rytířský souboj.", - }, - { - "Kostra ryby?", - { - "Ukazuje v přístavu – směs obdivu a smutku", - "Spálí se", - "Neexistuje", - "Jí se celá", - }, - 0, - "Symbol vítězství i ztráty.", - }, - { - "Hemingway život?", - { - "1899–1961, dobrodruh", - "2000", - "1700", - "Čech", - }, - 0, - "Americký autor.", - }, - { - "Překlad Vrba?", - { - "Český překlad známý", - "Neexistuje", - "Anglicky jen", - "Německy", - }, - 0, - "Maturitní seznam.", - }, - { - "Věk Santiaga?", - { - "Stařec – osmdesátky", - "Dítě", - "Dvacet", - "Sto padesát", - }, - 0, - "Titul.", - }, - { - "Návnada?", - { - "Sardinky, chytrost", - "Pouze síla", - "Magie", - "Nic", - }, - 0, - "Rybařské detaily.", - }, - { - "Bolest?", - { - "Santiago trpí, ale pokračuje", - "Bez bolesti", - "Komediální", - "Bez děje", - }, - 0, - "Fyzické vypětí.", - }, - { - "Náboženské prvky?", - { - "Kříž, bolest – možná paralely", - "Kázání", - "Bez ničeho", - "Opera", - }, - 0, - "Interpretace křesťanská.", - }, - { - "Pro maturitu?", - { - "Symbolika, styl, témata", - "Jen mapa", - "Jen autor rok", - "Nic", - }, - 0, - "Klasická maturitní četba.", - }, - { - "Hemingway válka?", - { - "1. sv. válka, novinář", - "Nebyl", - "Jen učitel", - "Král", - }, - 0, - "Zkušenost ovlivnila psaní.", - }, - { - "Tón závěru?", - { - "Hořkosladký – porážka i důstojnost", - "Čistá radost", - "Horor", - "Satira", - }, - 0, - "Tragédie i vítězství ducha.", - }, - { - "Co si Santiago říká?", - { - "Motivuje se sám – dialog", - "Mlčí vždy", - "Zpívá operu", - "Modlí se jen", - }, - 0, - "Vnitřní monolog.", - }, - { - "Proč Manolin nemůže chodit s Santiagem rybařit?", - { - "Rodiče ho přesvědčili, že Santiago je smolař", - "Santiago ho zakázal", - "Manolin je nemocný", - "Zákaz státu", - }, - 0, - "Chlapec by chtěl, ale rodina preferuje úspěšnější rybáře po sérii neúspěchů.", - }, - { - "Jak rybáři reagují na kostru marlina?", - { - "S úctou k Santiagově výkonu, i když z masa nic nezbylo", - "S opovržením bez výjimky", - "Vůbec ji nevidí", - "Spálí ji hned", - }, - 0, - "Kostra dokazuje, že marlina skutečně chytil – směs obdivu a soucitu.", - }, -}; - -static const AssemblyItem book_starec_a_more_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Santiago má dlouhou smůlu", - "Vyplouvá daleko na moře", - "Chytí obřího marlina", - "Třídenní souboj a vítězství", - "Žraloci sežerou maso cestou", - "Vrátí se s kostrou – Manolin u něj zůstane", - }, - 6, - }, -}; - -static const char *book_starec_a_more_plot_meaning[] = { - "Správné pořadí: smůla → vyplutí → marlin → souboj → žraloci → návrat a kostra.", -}; - -static const LitQ book_svaty_xaverius_qs[] = { - { - "Kdo napsal Svatého Xaveria?", - { - "Jirásek", - "Jakub Arbes", - "Neruda", - "Čapek", - }, - 1, - "Arbes, romantický autor.", - }, - { - "O kom román je?", - { - "O Napoleonovi", - "O sv. Františku Xaverském", - "O Svejkovi", - "O Gatsby", - }, - 1, - "Jezuitský misionář.", - }, - { - "Kdy Xaverský žil?", - { - "16. století (1506–1552)", - "20. st.", - "Antika", - "1990", - }, - 0, - "Historická postava.", - }, - { - "Kde působil?", - { - "Asie – Indie, Japonsko, Moluky", - "Pouze Praha", - "USA", - "Antarktida", - }, - 0, - "Misijní cesty.", - }, - { - "Žánr?", - { - "Historicko-romantický román", - "Sci-fi", - "Detektivka", - "Báseň", - }, - 0, - "Romantická epika.", - }, - { - "Arbes patří kam?", - { - "Český romantismus / realizmus přechod", - "Devětsil", - "Baroko", - "Postmoderna", - }, - 0, - "19. století.", - }, - { - "Ignác z Loyoly?", - { - "Zakladatel jezuitů, Xaveriův druh", - "Král", - "Němec", - "Rybář", - }, - 0, - "Spoluzakladatel řádu.", - }, - { - "Hlavní motiv?", - { - "Misionářská oddanost a dobrodružství", - "Lov srn", - "Detektivka", - "Komunismus", - }, - 0, - "Víra a cesty.", - }, - { - "Styl Arbesa?", - { - "Barvitý, romantický", - "Suchý úřednický", - "Bez obrazů", - "Pouze dialog", - }, - 0, - "Typický romantismus.", - }, - { - "Proč „svatý“?", - { - "Xaverský byl kanonizován", - "Fikce", - "Ironie", - "Bez důvodu", - }, - 0, - "Církevní světec.", - }, - { - "Kulturní střet?", - { - "Evropa vs. asijské kultury", - "Ne", - "Jen Praha", - "Jen sport", - }, - 0, - "Misie naráží na zvyky.", - }, - { - "Arbes jinak?", - { - "Publicista, pokrokové názory", - "Němec", - "Bez tvorby", - "Komik", - }, - 0, - "Aktivní v publicistice.", - }, - { - "Kdy vyšel román?", - { - "1869", - "1950", - "2000", - "1700", - }, - 0, - "19. st.", - }, - { - "Co NENÍ v díle?", - { - "Exotické cesty", - "Idealizace hrdiny", - "Pouze pražská realistická vesnice bez děje", - "Náboženské motivy", - }, - 2, - "Děj je exotický.", - }, - { - "Xaverský zemřel?", - { - "Na ostrově Sancian / v misii", - "V Praze hradě", - "V USA", - "Neumírá", - }, - 0, - "Historický konec.", - }, - { - "Romantický hrdina?", - { - "Obětuje se pro ideál", - "Cynik", - "Villain", - "Dítě", - }, - 0, - "Idealizovaná postava.", - }, - { - "Maturita – proč?", - { - "Česká romantická próza, historie", - "Bez významu", - "Jen jméno", - "Komiks", - }, - 0, - "Součást přehledu.", - }, - { - "Jezuité?", - { - "Řád, misie, vzdělání", - "Sportovní klub", - "Německá armáda", - "Bez role", - }, - 0, - "Kontext víry.", - }, - { - "Tón?", - { - "Dobrodružný i idealistický", - "Pouze komedie", - "Horor", - "Bez děje", - }, - 0, - "Romantická adventura.", - }, - { - "Arbes vs Jirásek?", - { - "Arbes romantik, Jirásek jiný styl", - "Totéž", - "Arbes není Čech", - "Jirásek napsal Xaveria", - }, - 0, - "Různí autoři.", - }, - { - "Pronásledování?", - { - "Misie naráží na nebezpečí", - "Neexistuje", - "Jen v Praze", - "Jen humor", - }, - 0, - "Konflikty na cestách.", - }, - { - "Historická přesnost?", - { - "Román idealizuje, ne učebnice", - "Dokument", - "Sci-fi", - "Bez děje", - }, - 0, - "Fikce s historickým jádrem.", - }, - { - "Hlavní poselství?", - { - "Oběť pro víru a lidstvo", - "Materialismus", - "Válka je dobrá", - "Bez morálky", - }, - 0, - "Etický ideal.", - }, - { - "Vyprávění?", - { - "Epická próza třetí osoba", - "Deník", - "Drama", - "Elegie", - }, - 0, - "Román.", - }, - { - "Exotika?", - { - "Barví prostředí", - "Chybí", - "Jen Praha", - "Jen moře u Kub", - }, - 0, - "Asie je klíčová.", - }, - { - "Kanonicita?", - { - "Xaverský uctíván církví", - "Ne", - "Vymyšlený", - "Antihero", - }, - 0, - "Světec.", - }, - { - "Délka?", - { - "Román", - "Jedna báseň", - "Bez textu", - "Pouze titul", - }, - 0, - "Epická rozsah.", - }, - { - "Arbes zemřel?", - { - "1914", - "2000", - "1800", - "1990", - }, - 0, - "Přelom 19./20. st.", - }, - { - "Souvislost s Kolakovicem?", - { - "Arbes psal i jiné romantické prózy", - "Ne", - "Stejná kniha", - "Bez", - }, - 0, - "Arbesova tvorba je širší.", - }, - { - "Čtenář si odnese?", - { - "Obraz misijní epochy a romantismu", - "Návod Excel", - "Mapu USA", - "Recept", - }, - 0, - "Kulturní a literární.", - }, - { - "S kým je Xaverský úzce spojen v historii jezuitů?", - { - "S Ignácem z Loyoly", - "S Napoleonem", - "S Havlíčkem", - "S Gatsbym", - }, - 0, - "Ignác z Loyoly byl spoluzakladatel řádu a Xaveriův blízký spolupracovník.", - }, - { - "Jak Arbes v románu pracuje s historickou postavou?", - { - "Idealizuje ji v duchu romantismu, ne jako suchou kroniku", - "Píše jen encyklopedii bez děje", - "Záměrně popírá existenci světce", - "Převádí ji do sci-fi", - }, - 0, - "Jde o romantickou fikci inspirovanou reálným misionářem.", - }, -}; - -static const AssemblyItem book_svaty_xaverius_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Xaverský vstupuje do jezuitů", - "Vydává se na misie do Asie", - "Kazí, léčí, navazuje kontakty", - "Naráží na kulturní a náboženské bariéry", - "Pokračuje v oběti a cestách", - "Umírá v misijní službě – světectví", - }, - 6, - }, -}; - -static const char *book_svaty_xaverius_plot_meaning[] = { - "Správné pořadí: jezuita → cesta do Asie → kázání → překážky → oběť → smrt světce.", -}; - -static const LitQ book_tereza_raquinova_qs[] = { - { - "Kdo napsal Terezu Raquinovou?", - { - "Hugo", - "Émile Zola", - "Flaubert", - "Maupassant", - }, - 1, - "Zola, naturalista.", - }, - { - "Kde děj?", - { - "Paříž, obchod u Seiny", - "Praha", - "Londýn", - "Venkov", - }, - 0, - "Městské prostředí.", - }, - { - "Kdo je Tereza?", - { - "Vdova po Camillovi na konci začátku", - "Manželka Camilla, milenka Laurenta", - "Policistka", - "Němka", - }, - 1, - "Ústřední postava.", - }, - { - "Camille?", - { - "Atlet", - "Slabý, chromý manžel", - "Detektiv", - "Král", - }, - 1, - "Oběť vraždy.", - }, - { - "Laurent?", - { - "Camillův přítel, milenec Terezy", - "Kněz", - "Dítě", - "Učitel", - }, - 0, - "Spoluviník.", - }, - { - "Jak Camille zemře?", - { - "Utopení při „hře“ u Seiny", - "Stářím", - "Válka", - "Nehoda auta", - }, - 0, - "Plánovaná vražda.", - }, - { - "Co po vraždě?", - { - "Klid", - "Vina, noční můry, nenávist", - "Bohatství bez problémů", - "Emigrace", - }, - 1, - "Manželé si ničí život.", - }, - { - "Madame Raquin?", - { - "Němá po mrtvici, svědkyně", - "Mrtvá hned", - "Vrah", - "Nevidí", - }, - 0, - "Děsivý svědek.", - }, - { - "Naturalismus?", - { - "Člověk určen prostředím a pudy", - "Pouze pohádka", - "Sci-fi", - "Bez teorie", - }, - 0, - "Zolův program.", - }, - { - "Jak končí?", - { - "Svatba dětí", - "Tereza a Laurent se zabijí / double suicide", - "Detektiv vyřeší", - "Camille žije", - }, - 1, - "Tragický konec.", - }, - { - "Žánr?", - { - "Naturalistický román", - "Komedie", - "Epos", - "Bajka", - }, - 0, - "Francouzský naturalismus.", - }, - { - "Proč sňatek T+L?", - { - "Láska", - "Chce získat dědictví / udržet aféru", - "Rozkaz matky", - "Nevědomky", - }, - 1, - "Praktický i vášnivý motiv.", - }, - { - "Hosté u mamky?", - { - "Pravidelná hra domina", - "Nikdo", - "Válka", - "Cirkus", - }, - 0, - "Rámec všednosti.", - }, - { - "Vina se projeví?", - { - "Halucinace Camilla", - "Ne", - "Jen radost", - "Sport", - }, - 0, - "Psychologický tlak.", - }, - { - "Zola patří?", - { - "Naturalisté", - "Romantici 18. st.", - "Beat generation", - "Česká avantgarda", - }, - 0, - "École naturaliste.", - }, - { - "Co NENÍ téma?", - { - "Vášeň a zločin", - "Vina", - "Determinismus", - "Kosmické války", - }, - 3, - "Realistický pařížský děj.", - }, - { - "Rok vydání?", - { - "1867", - "1990", - "1700", - "2005", - }, - 0, - "19. století.", - }, - { - "Seina?", - { - "Scéna vraždy", - "Nepodstatná", - "Hrad", - "Les", - }, - 0, - "Řeka.", - }, - { - "Tereza dětství?", - { - "Vychována u Raquinových", - "Sirotek u tety", - "Královna", - "Němec", - }, - 0, - "Utlačovaná pozice.", - }, - { - "Laurent před aférou?", - { - "Lenoch, malíř amatér", - "Generál", - "Kněz", - "Dítě", - }, - 0, - "Společenský typ.", - }, - { - "Maturita?", - { - "Naturalismus, psychologie viny", - "Bez významu", - "Jen jména", - "Komiks", - }, - 0, - "Klasická francouzská próza.", - }, - { - "Tón?", - { - "Temný, deterministický", - "Lehká komedie", - "Pohádka", - "Satira bez vážnosti", - }, - 0, - "Tragédie vášně.", - }, - { - "Camillova matka po mrtvici?", - { - "Ochrnutí, komunikace obtížná", - "Tančí", - "Mluví víc", - "Odchází", - }, - 0, - "Němý soudce.", - }, - { - "Policie?", - { - "Hrozí odhalení, napětí", - "Neexistuje", - "Hned zatýká", - "Komedie", - }, - 0, - "Detektivní prvek.", - }, - { - "Vztah T+L po svatbě?", - { - "Nenávist, mutual destruction", - "Idyla", - "Rozchod klidný", - "Děti", - }, - 0, - "Peklo manželství.", - }, - { - "Zola jiné dílo?", - { - "Nana, Germinal", - "1984", - "Gatsby", - "Saturnin", - }, - 0, - "Součást cyklu Rougon-Macquart.", - }, - { - "Determinismus znamená?", - { - "Osud formován prostředím", - "Svoboda bez limitů", - "Náhoda bez důsledků", - "Magie", - }, - 0, - "Naturalistická idea.", - }, - { - "Proč utopení?", - { - "Vypadá jako nehoda", - "Nemožné", - "Camille plavce", - "Na souši", - }, - 0, - "Lehké alibi.", - }, - { - "Čtenář cítí?", - { - "Tlak viny a dusno", - "Pouze smích", - "Nic", - "Jen radost", - }, - 0, - "Psychologický horor.", - }, - { - "Titulní postava?", - { - "Thérèse Raquin", - "Madame Bovary", - "Julie", - "Ester", - }, - 0, - "Jméno v titulu.", - }, - { - "Proč se Tereza a Laurent po vraždě nenávidí?", - { - "Vina je dusí – obviňují se a ničí aféru", - "Camille je stále naživu", - "Matka je proti", - "Policie je okamžitě zatýká", - }, - 0, - "Zločin je spojil, ale psychický tlak je rozdělí.", - }, - { - "Jakou roli hraje pravidelná hra domina u Raquinových?", - { - "Zdůrazňuje všednost, která kontrastuje s vášní a zločinem", - "Je hlavním motivem vraždy", - "Neobjevuje se v díle", - "Slouží jen jako komická epizoda bez významu", - }, - 0, - "Monotónní večery ukazují útlak a rutinu před explozí vášně.", - }, -}; - -static const AssemblyItem book_tereza_raquinova_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Tereza žije utlačeně s Camillem", - "Aféra s Laurentem", - "Vražda Camilla u Seiny", - "Sňatek viníků", - "Vina a halucinace", - "Sebevražda / zhoubný konec", - }, - 6, - }, -}; - -static const char *book_tereza_raquinova_plot_meaning[] = { - "Správné pořadí: útlak → aféra → vražda → svatba → vina → sebevražda.", -}; - -static const LitQ book_tezka_hodina_qs[] = { - { - "Kdo napsal Těžkou hodinu?", - { - "Seifert", - "Jiří Wolker", - "Havlíček", - "Neruda", - }, - 1, - "Wolker, 1922.", - }, - { - "Jaká forma?", - { - "Próza", - "Lyric poetry – sbírka", - "Drama", - "Epos", - }, - 1, - "Básnická sbírka.", - }, - { - "Wolker žil?", - { - "1900–1924", - "1890–1940", - "2000", - "1850", - }, - 0, - "Krátký život.", - }, - { - "Těžká hodina znamená?", - { - "Lehký večer", - "Krizový okamžik, bolest, zkoušku", - "Svatba", - "Dovolenou", - }, - 1, - "Metafora titulu.", - }, - { - "Hlavní témata?", - { - "Chudoba, válka, naděje", - "Sci-fi", - "Lov srn", - "Detektivka", - }, - 0, - "Proletářská lyrika.", - }, - { - "Wolker politicky?", - { - "Levicový, komunistické sympatie", - "Monarchista", - "Bez názorů", - "Cizí", - }, - 0, - "Revolutionary básník.", - }, - { - "Host do domu?", - { - "Další Wolkerova sbírka", - "Román", - "Film", - "Hra Goldoniho", - }, - 0, - "Související tvorba.", - }, - { - "Styl?", - { - "Volný verš, obraznost, emoce", - "Strofický epic", - "Proza dialog", - "Bez metafor", - }, - 0, - "Moderní lyrika.", - }, - { - "Proletář v básních?", - { - "Hrdina dělnické třídy", - "Nepřítel", - "Neexistuje", - "Král", - }, - 0, - "Třídní témata.", - }, - { - "Válka?", - { - "Zklamání, utrpení", - "Slavnost", - "Chybí", - "Vtip", - }, - 0, - "1. sv. válka ovlivnila generaci.", - }, - { - "Naděje?", - { - "Světlá budoucnost pro lid", - "Bez naděje", - "Pouze smutek", - "Emigrace", - }, - 0, - "Optimismus v těžké hodině.", - }, - { - "Wolker zemřel na?", - { - "Tuberkulózu", - "Válku v bitvě", - "Stáří", - "Autonehodu", - }, - 0, - "Mladá smrt.", - }, - { - "Generace?", - { - "Meziválečná avantgarda / levicová mládež", - "Baroko", - "2000", - "Středověk", - }, - 0, - "Kontext.", - }, - { - "Co NENÍ typické?", - { - "Sociální témata", - "Emoce", - "Lyrika", - "Naturalistický román o vraždě", - }, - 3, - "Wolker je básník.", - }, - { - "Báseň a obraz?", - { - "Vizuální metafory", - "Bez obrazů", - "Jen próza", - "Jen humor", - }, - 0, - "Symbolistické prvky.", - }, - { - "Maturita?", - { - "Témata, verš, autor", - "Jen rok", - "Mapa", - "Bez", - }, - 0, - "Poezie na seznamu.", - }, - { - "Čeština?", - { - "Spisovná, citlivá", - "Angličtina", - "Archaičtina bez smyslu", - "Němčina", - }, - 0, - "Wolkerova čeština.", - }, - { - "Influence?", - { - "Symbolismus, moderna", - "Antický epos", - "Bez", - "Hollywood", - }, - 0, - "Literární tradice.", - }, - { - "Tón sbírky?", - { - "Vážný, nadějí prodchnutý", - "Pure comedy", - "Horor", - "Bez emocí", - }, - 0, - "Krizové chvíle.", - }, - { - "Dělník?", - { - "Solidarita, úcta", - "Posměch", - "Neexistuje", - "Villain", - }, - 0, - "Proletářská poezie.", - }, - { - "Příroda?", - { - "Kontrast k městu/chudobě", - "Chybí", - "Jen vesmír", - "Jen moře", - }, - 0, - "Lyricismus.", - }, - { - "Wolker a Wolkerova ulice?", - { - "Praha pamatuje", - "Ne", - "Berlin", - "Nic", - }, - 0, - "Kult autora.", - }, - { - "Revolution?", - { - "Naděje v lepší společnost", - "Proti", - "Bez", - "Jen válka", - }, - 0, - "Ideály.", - }, - { - "Krátce: proč číst?", - { - "Pochopit meziválečnou levicovou lyriku", - "Návod k jídlu", - "Geografie", - "Sport", - }, - 0, - "Literární historie.", - }, - { - "Verš?", - { - "Volný i tradiční prvky", - "Jen rýmovaný sonet", - "Proza", - "Bez", - }, - 0, - "Flexibilní forma.", - }, - { - "Emoce?", - { - "Empatie k chudým", - "Chlad", - "Bez", - "Ironie sitcom", - }, - 0, - "Humanismus.", - }, - { - "Současníci?", - { - "Seifert, Nezval – jinak", - "Shakespeare", - "Keyes", - "Jirotka", - }, - 0, - "Česká poezie 20. st.", - }, - { - "Titulní metafora?", - { - "Hodina zkoušky života", - "Hodiny na věži", - "Školní hodina", - "Bez", - }, - 0, - "Symbol.", - }, - { - "Publikum?", - { - "Čtenář hledající smysl v bídě", - "Jen děti", - "Jen vědci", - "Bez", - }, - 0, - "Engaged poetry.", - }, - { - "Wolker věk smrti?", - { - "24 let", - "80", - "50", - "10", - }, - 0, - "Mladý autor.", - }, - { - "Jak souvisí Těžká hodina s Wolkerovou sbírkou Host do domu?", - { - "Jsou to blízké etapy jeho krátké tvorby – obě patří k maturitnímu přehledu", - "Host do domu je próza o mlokách", - "Nejsou nijak spojeny", - "Host do domu napsal Neruda", - }, - 0, - "Wolker je autorem obou básnických sbírek z raného 20. století.", - }, - { - "Proč je Wolker důležitý pro českou meziválečnou literaturu?", - { - "Spojuje cit, obraznost a levicové sociální téma v mladém věku", - "Psal jen německy", - "Nebyl publikován", - "Patří k baroku", - }, - 0, - "Krátký život, silná lyrika a angažovanost z něj dělají symbol generace.", - }, -}; - -static const AssemblyItem book_tezka_hodina_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Wolker vnímá bídu a válku", - "Přichází těžké hodiny zkoušky", - "Básně líčí proletářský život", - "Objevuje se naděje v solidaritě", - "Lyrika spojuje osobní a kolektivní", - "Světlo na konci těžké hodiny", - }, - 6, - }, -}; - -static const char *book_tezka_hodina_plot_meaning[] = { - "Správné pořadí: bída/válka → krize → proletář → naděje → lyrička syntéza → perspektiva.", -}; - -static const LitQ book_tyrolske_elegie_qs[] = { - { - "Kdo napsal Tyrolské elegie?", - { - "Neruda", - "Karel Havlíček Borovský", - "Wolker", - "Vrchlický", - }, - 1, - "Havlíček, 1855.", - }, - { - "Proč „tyrolské“?", - { - "Vznik v souvislosti s Havlíčkovým pobytem v Tyrolsku / Brixen", - "Popis hor bez politiky", - "Německá opera", - "Sport", - }, - 0, - "Autobiografický rámec.", - }, - { - "Hlavní funkce?", - { - "Satira Rakouska a reakce", - "Láska k přírodě bez politiky", - "Sci-fi", - "Cookbook", - }, - 0, - "Politická poezie.", - }, - { - "1848?", - { - "Revolution potlačena – téma elegií", - "Nezmíněno", - "Rok smrti Wolker", - "2000", - }, - 0, - "Kontext.", - }, - { - "Havlíček profese?", - { - "Novinář, satirik, básník", - "Holič", - "Pilot", - "Malíř", - }, - 0, - "Publicista.", - }, - { - "Forma?", - { - "Satirické elegie", - "Realistický román", - "Drama", - "Epos", - }, - 0, - "Lyric satire.", - }, - { - "Jazyk?", - { - "Ironický, hovorový, úderný", - "Archaičtina bez smyslu", - "Angličtina", - "Bez humoru", - }, - 0, - "Typický Havlíček.", - }, - { - "Císař?", - { - "Habsburská monarchie kritizována", - "Chválen bez ironie", - "Neexistuje", - "Americký", - }, - 0, - "Politická kritika.", - }, - { - "Havlíček zemřel?", - { - "1856", - "1924", - "2000", - "1700", - }, - 0, - "Krátce po elegiích.", - }, - { - "Vězení / cenzura?", - { - "Havlíček perzekvován", - "Ne", - "Vítěz", - "Bez", - }, - 0, - "Symbol odporu.", - }, - { - "Napoleon III.?", - { - "Politické aluze v elegiích", - "Hlavní hrdina románu", - "Ne", - "Český král", - }, - 0, - "Evropská politika.", - }, - { - "Co NENÍ?", - { - "Satira", - "Politika", - "Národní téma", - "Bezmyšlenkovitá poprvky bez kontextu", - }, - 3, - "Elegie jsou politické.", - }, - { - "Maturita?", - { - "Kontext obrození, satira", - "Jen mapa Tyrol", - "Bez", - "Komiks", - }, - 0, - "Klasická česká poezie.", - }, - { - "Elegie obvykle?", - { - "Smutek – Havlíček ironizuje žánr", - "Vždy svatba", - "Vždy sci-fi", - "Bez", - }, - 0, - "Inverze žánru.", - }, - { - "Čtenář?", - { - "Má znát historii 1848", - "Bez znalosti", - "Jen děti", - "Cizinci bez překladu", - }, - 0, - "Historický kontext.", - }, - { - "Národní buditel?", - { - "Ano", - "Ne", - "Němec", - "Bez role", - }, - 0, - "Havlíček v kánonu.", - }, - { - "Kde vycházely?", - { - "Tábor / ilegální tisk", - "New York", - "Moskva", - "Bez", - }, - 0, - "České vydání.", - }, - { - "Tón?", - { - "Ironický, kritický", - "Sladký bez obsahu", - "Horor", - "Bez", - }, - 0, - "Satirický.", - }, - { - "Havlíček a Borová?", - { - "Pseudonym / místo", - "Cizí země", - "Postava", - "Opera", - }, - 0, - "Autorovo jméno.", - }, - { - "Vztah k Vrchlickému?", - { - "Jiná generace a styl", - "Totéž", - "Vrchlický napsal elegie", - "Bez", - }, - 0, - "Různí básníci.", - }, - { - "Cíl satiry?", - { - "Reakční moc, absurdita", - "Chudí", - "Příroda", - "Sport", - }, - 0, - "Politická moc.", - }, - { - "Proč maturita?", - { - "Základ české satiry a obrození", - "Bez", - "Jen Tyrolsko mapa", - "Jen rok", - }, - 0, - "Kulturní memory.", - }, - { - "Básnický prostředek?", - { - "Ironie, personifikace", - "Bez", - "Jen rým", - "Proza", - }, - 0, - "Satirické figury.", - }, - { - "Havlíček legacy?", - { - "Symbol svobody slova", - "Zapomenut", - "Němec", - "Bez", - }, - 0, - "Národní autor.", - }, - { - "Revolution naděje?", - { - "Zklamání → satira", - "Splněno", - "Ne", - "2000", - }, - 0, - "Motivace elegií.", - }, - { - "Publikum 19. st.?", - { - "Čtenáři Národních listů aj.", - "Bez", - "Jen císař", - "Hollywood", - }, - 0, - "Publicistická síť.", - }, - { - "Překlad?", - { - "Originál česky", - "Anglicky jen", - "Bez", - "Latině", - }, - 0, - "Česká klasika.", - }, - { - "Počet elegií?", - { - "Cyklus básní (známý soubor)", - "Jedna věta", - "Román", - "Bez", - }, - 0, - "Sbírka.", - }, - { - "Vzdělání maturanta?", - { - "Historie 1848, satira", - "Jen biologie", - "Bez", - "Sport", - }, - 0, - "Interdisciplinární.", - }, - { - "Havlíček smrt?", - { - "Tuberkulóza / vyčerpání", - "Poprava elegií", - "2000", - "Neumírá", - }, - 0, - "Tragický konec autora.", - }, - { - "K čemu Havlíček Tyrolské elegie využívá?", - { - "K satirické a osobní reflexi exilu, politiky i národní situace", - "K popisu rybaření", - "K návodu na zeměměřičství", - "K psaní detektivky", - }, - 0, - "Elegie jsou politicko-lyrickou zbraní v době cenzury.", - }, - { - "Jaký význam má Brixen / Tyrolsko v kontextu sbírky?", - { - "Místo Havlíčkova vyhnanství, odkud píše s nadhledem na domov", - "Fiktivní planeta", - "Sídlo Gatsbyho", - "Lokalita bez souvislosti s autorem", - }, - 0, - "Autobiografický rámec vysvětluje název i tón elegií.", - }, -}; - -static const AssemblyItem book_tyrolske_elegie_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Revolution 1848 je potlačena", - "Havlíček v exile / Tyrolsku", - "Píše ironické elegie", - "Satirizuje Habsburky a reakci", - "Oslovuje český národ", - "Elegie jako zbraň publicisty", - }, - 6, - }, -}; - -static const char *book_tyrolske_elegie_plot_meaning[] = { - "Správné pořadí: porážka revoluce → exil → satirické elegie → kritika moci → národní apel → literární odkaz.", -}; - -static const LitQ book_valka_s_mloky_qs[] = { - { - "Kdo napsal Válku s mloky?", - { - "Hašek", - "Karel Čapek", - "Orwell", - "Vančura", - }, - 1, - "Čapek 1936.", - }, - { - "Co jsou mloci v knize?", - { - "Inteligentní obojživelníci", - "Lidé", - "Roboti", - "Ptáci", - }, - 0, - "Salamandři s vědomím.", - }, - { - "Kdo objeví mloky?", - { - "Captain van Toch", - "Gatsby", - "Svejk", - "Winston", - }, - 0, - "Tichomořský objev.", - }, - { - "Bondy?", - { - "Podnikatel znezužívající mloky", - "Kněz", - "Němec", - "Dítě", - }, - 0, - "Kapitalista.", - }, - { - "Žánr?", - { - "Antiutopická satira", - "Realistická vesnická novela", - "Lyrika", - "Historický román", - }, - 0, - "Čapkova satira.", - }, - { - "Forma?", - { - "Koláž – různé texty a styly", - "Jeden deník", - "Drama", - "Epos", - }, - 0, - "Montáž.", - }, - { - "Satira míří na?", - { - "Fašismus, militarismus, chamtivost", - "Jen rybaření", - "Lásku", - "Bez", - }, - 0, - "Politický subtext.", - }, - { - "Mloci se organizují?", - { - "Ano – stát, armáda", - "Ne", - "Jen jako domácí mazlíčci", - "Umírají hned", - }, - 0, - "Eskalace.", - }, - { - "Paralela s historií?", - { - "Nacistické Německo 30. let", - "Antika", - "2000", - "Bez", - }, - 0, - "Čapek varoval.", - }, - { - "Rok vydání?", - { - "1936", - "1949", - "1890", - "2005", - }, - 0, - "Před 2. sv. válkou.", - }, - { - "Jak končí?", - { - "Válka lidstva s mloky, hrozba zničení", - "Svatba", - "Mloci jako pets", - "Emigrace", - }, - 0, - "Apokalypsa.", - }, - { - "Čapek jiné?", - { - "R.U.R., Krakatit", - "Gatsby", - "Kytice", - "Saturnin", - }, - 0, - "Sci-fi a satira.", - }, - { - "Co NENÍ?", - { - "Satira", - "Varování", - "Koláž", - "Bezmyšlenkovitá pohádka bez politiky", - }, - 3, - "Politická alegorie.", - }, - { - "Mloci mluví?", - { - "Ano – jazyk, ideologie", - "Ne", - "Jen pes", - "Latině", - }, - 0, - "Inteligence.", - }, - { - "Ekonomika?", - { - "Obchod s mloky jako zbožím", - "Bez", - "Socialismus hotový", - "Bez peněz", - }, - 0, - "Kapitalismus.", - }, - { - "Maturita?", - { - "Satira, forma, kontext 30. let", - "Bez", - "Jen biologie mloků", - "Mapa", - }, - 0, - "Česká literatura.", - }, - { - "Tón?", - { - "Groteskní, varovný", - "Idyla", - "Bez humoru", - "Pure romance", - }, - 0, - "Černý humor.", - }, - { - "Věda?", - { - "Zneužita pro zisk", - "Chválena bez rizika", - "Ne", - "Zakázána", - }, - 0, - "Kritika.", - }, - { - "Lidstvo?", - { - "Krátkozraké, sebedestruktivní", - "Moudré", - "Neexistuje", - "Vždy vítězí", - }, - 0, - "Pesimismus.", - }, - { - "Tichomoří?", - { - "Počátek děje", - "Praha", - "Siberie", - "Měsíc", - }, - 0, - "Tahiti.", - }, - { - "Uniformy mloků?", - { - "Parodie fašismu", - "Ne", - "Bez", - "Sport", - }, - 0, - "Vizuální satira.", - }, - { - "Čapek smrt?", - { - "1938 před okupací", - "2000", - "1950", - "1890", - }, - 0, - "Autor nezažil válku.", - }, - { - "Kolážní efekt?", - { - "Ironie z různých perspektiv", - "Chaos bez smyslu", - "Bez", - "Jen báseň", - }, - 0, - "Forma = obsah.", - }, - { - "Brother Čapek?", - { - "Josef – umělec", - "Neexistuje", - "Shakespeare", - "Hitler", - }, - 0, - "Rodina Čapků.", - }, - { - "Varování?", - { - "Před totalitou a obchodem se zbraněmi", - "Před mloky v akváriu", - "Bez", - "Před školou", - }, - 0, - "Politické.", - }, - { - "Překlad?", - { - "Originál česky", - "Anglicky jen", - "Bez", - "Němec", - }, - 0, - "Český autor.", - }, - { - "Mloci vs R.U.R.?", - { - "Obě alegorie – jiný motiv", - "Totéž", - "Bez", - "R.U.R. o mlocích", - }, - 0, - "Čapkovo sci-fi.", - }, - { - "Čtenář 1936?", - { - "Chápal narážky na Evropu", - "Bez kontextu vždy", - "Děti", - "Bez", - }, - 0, - "Aktuální satira.", - }, - { - "Závěrečná válka?", - { - "Lidstvo v ohrožení", - "Mloci prohrají bez boje", - "Mír", - "Svatba", - }, - 0, - "Katastrofa.", - }, - { - "Hlavní myšlenka?", - { - "Lidská chamtivost zbrojí protivníka", - "Miluj mloky", - "Bez", - "Sport", - }, - 0, - "Etické varování.", - }, - { - "Kdo je Chief Salamander?", - { - "Vůdce mloků, který mluví jménem rostoucí moci", - "Kapitán van Toch", - "Pan Povondra", - "Gatsby", - }, - 0, - "Salamander reprezentuje organizovanou sílu zneužitých mloků.", - }, - { - "Proč je montážní forma pro Válku s mloky typická?", - { - "Napodobuje tisk a dokumenty – satira působí jako zpráva z reality", - "Je to náhodný experiment bez smyslu", - "Nahrazuje děj úplně", - "Patří k romantismu 18. st.", - }, - 0, - "Koláž zpráv, reklam a projevů zesiluje alegorii i humor.", - }, -}; - -static const AssemblyItem book_valka_s_mloky_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Objev inteligentních mloků", - "Obchod a chov mloků", - "Mloci budují civilizaci a armádu", - "Satira fašistoidní organizace", - "Konflikt lidstva s mloky", - "Hrozba zničení světa", - }, - 6, - }, -}; - -static const char *book_valka_s_mloky_plot_meaning[] = { - "Správné pořadí: objev → obchod → organizace mloků → militarizace → válka → apokalyptická hrozba.", -}; - -static const LitQ book_velky_cirkus_qs[] = { - { - "Kdo napsal Velký cirkus?", - { - "Ryan", - "Pierre Clostermann", - "Hemingway", - "Remarque", - }, - 1, - "Francouzský pilot.", - }, - { - "O čem kniha?", - { - "Vzdušné boje 2. sv. války v RAF", - "Cirkus artistů", - "Gatsby", - "Mloci", - }, - 0, - "Letectvo.", - }, - { - "Kdo vypráví?", - { - "Clostermann jako pilot", - "Němec", - "Dítě", - "Rybář", - }, - 0, - "Ich-forma.", - }, - { - "Velký cirkus znamená?", - { - "Metafora leteckého bojiště", - "Skutečný cirkus", - "Škola", - "Moře", - }, - 0, - "Chaos nebe.", - }, - { - "Kde slouží?", - { - "RAF – britské letectvo", - "Luftwaffe", - "Československé", - "Nikde", - }, - 0, - "Francouz u Spojenců.", - }, - { - "Letadla?", - { - "Spitfire, Typhoon aj.", - "Bez letadel", - "Jen balóny", - "Rakety", - }, - 0, - "Stíhačky.", - }, - { - "Žánr?", - { - "Válečné memoáry", - "Pohádka", - "Lyrika", - "Detektivka", - }, - 0, - "Autobiografická próza.", - }, - { - "Rok vydání?", - { - "1948", - "1936", - "2000", - "1890", - }, - 0, - "Po válce.", - }, - { - "Tón?", - { - "Autentický, napínavý, bez patosu", - "Pure komedie", - "Sci-fi", - "Bez", - }, - 0, - "Realismus.", - }, - { - "Clostermann národnost?", - { - "Francouz", - "Čech", - "Němec", - "Rus", - }, - 0, - "Free French.", - }, - { - "Co NENÍ?", - { - "Letectvo", - "Válka", - "Memoáry", - "Milostný román Gatsby", - }, - 3, - "Jiné dílo.", - }, - { - "Strach pilotů?", - { - "Ano, součást textu", - "Ne", - "Jen radost", - "Bez", - }, - 0, - "Psychologie.", - }, - { - "Kamarádství?", - { - "Mezi piloty RAF", - "Ne", - "Jen nepřátelé", - "Bez", - }, - 0, - "Spoluboj.", - }, - { - "Překlad Jedlička?", - { - "České vydání", - "Ne", - "Anglicky jen", - "Bez", - }, - 0, - "Maturitní seznam.", - }, - { - "Luftwaffe?", - { - "Nepřítel", - "Spojenec", - "Ne", - "Cirkus", - }, - 0, - "Německé letectvo.", - }, - { - "Glorifikace?", - { - "Spíše realistický popis", - "Bez boje", - "Pouze propaganda", - "Bez", - }, - 0, - "Memoáry.", - }, - { - "Maturita proč?", - { - "Válka z perspektivy pilota", - "Bez", - "Jen mapa", - "Komiks", - }, - 0, - "Historická próza.", - }, - { - "Technické detaily?", - { - "Letadla, mise", - "Bez", - "Jen láska", - "Kuchařka", - }, - 0, - "Autenticita.", - }, - { - "Po válce autor?", - { - "Politik, publicista", - "Zmizel", - "Dítě", - "Kněz", - }, - 0, - "Clostermann žil dlouho.", - }, - { - "Bitvy?", - { - "Nad Francií, Evropou", - "Antarktida", - "Měsíc", - "Bez", - }, - 0, - "Evropské nebe.", - }, - { - "Únava?", - { - "Fyzická i psychická", - "Ne", - "Bez", - "Jen sport", - }, - 0, - "Válka vydrží.", - }, - { - "Originální název?", - { - "Le Grand Cirque", - "1984", - "Saturnin", - "Gatsby", - }, - 0, - "Francouzsky.", - }, - { - "Spojenci?", - { - "Britové, Čechoslováci v RAF aj.", - "Nikdo", - "Jen Němci", - "Bez", - }, - 0, - "Koalice.", - }, - { - "Civilní?", - { - "Bombardování – oběti", - "Ne", - "Bez", - "Jen piloti", - }, - 0, - "Válka zasahuje vše.", - }, - { - "Forma?", - { - "Chronologické zápisky", - "Báseň", - "Drama", - "Koláž Čapek", - }, - 0, - "Memoáry.", - }, - { - "Clostermann věk války?", - { - "Mladý pilot", - "Generál 80 let", - "Dítě", - "Bez", - }, - 0, - "Mladý muž.", - }, - { - "Hlavní téma?", - { - "Odvaha a hrůza letecké války", - "Láska k moři", - "Mloci", - "Škola", - }, - 0, - "Letectvo.", - }, - { - "Čtenář?", - { - "Chápe 2. sv. válku z nebe", - "Bez", - "Jen děti", - "Bez historie", - }, - 0, - "Perspektiva.", - }, - { - "Konec války?", - { - "Vítězství Spojenců – v knize", - "Prohra RAF", - "Bez", - "2000", - }, - 0, - "Historický výsledek.", - }, - { - "Proč „cirkus“?", - { - "Akrobatické manévry, chaos soubojů", - "Klauni", - "Bez", - "Cirkus na zemi", - }, - 0, - "Metafora.", - }, - { - "Proč se kniha jmenuje Velký cirkus?", - { - "Metaforicky popisuje chaotické nebe a letecké bojiště 2. světové války", - "Je groteskní školní hra o třídní knize", - "Popisuje cirkus na Kubě", - "Jde o sbírku tyrolských elegií", - }, - 0, - "Titul vystihuje víření soubojů, nebezpečí a napětí ve vzduchu.", - }, - { - "Jak Clostermann líčí válečné zážitky?", - { - "Autenticky, bez patosu – strach, únava i odvaha pilotů", - "Jako pohádku bez nebezpečí", - "Jen statisticky bez emocí", - "Jako satiru na mloky", - }, - 0, - "Memoáry zachycují subjektivní pravdu stíhače v RAF.", - }, -}; - -static const AssemblyItem book_velky_cirkus_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Clostermann vstupuje do RAF", - "Výcvik a první mise", - "Intenzivní vzdušné souboje", - "Ztráty kamarádů a únava", - "Gradace Velkého cirkusu", - "Válka končí – bilance pilotova života", - }, - 6, - }, -}; - -static const char *book_velky_cirkus_plot_meaning[] = { - "Správné pořadí: nástup RAF → výcvik → souboje → ztráty → vrchol nebe → konec války.", -}; - -static const LitQ book_velky_gatsby_qs[] = { - { - "Kdo napsal Velkého Gatsbyho?", - { - "Hemingway", - "F. Scott Fitzgerald", - "Styron", - "Keyes", - }, - 1, - "Fitzgerald 1925.", - }, - { - "Vypravěč?", - { - "Gatsby", - "Nick Carraway", - "Tom", - "Daisy", - }, - 1, - "Nick je svědek.", - }, - { - "Gatsby miluje?", - { - "Jordan", - "Daisy Buchanan", - "Myrtle", - "Nick", - }, - 1, - "Dávná láska.", - }, - { - "Daisy je?", - { - "Vdaná za Toma Buchanan", - "Gatsbyho manželka", - "Sestra Nick", - "Učitelka", - }, - 0, - "Manželka Toma.", - }, - { - "Zelené světlo?", - { - "Symbol touhy po Daisy / budoucnosti", - "Reklama", - "Vlak", - "Bez", - }, - 0, - "Na konci doku.", - }, - { - "East Egg vs West Egg?", - { - "Staré vs. nové bohatství", - "Stejné", - "Evropa", - "Bez", - }, - 0, - "Třídní rozdíl.", - }, - { - "Gatsby bohatství?", - { - "Pašování / nejasný původ", - "Dědictví Toma", - "Státní plat", - "Bez", - }, - 0, - "Tajemství.", - }, - { - "Párty u Gatsbyho?", - { - "Velkolepé, ale osamělé", - "Ne", - "Malé", - "Bez", - }, - 0, - "Maska.", - }, - { - "Myrtle?", - { - "Milenka Toma, umírá under car", - "Manželka Gatsby", - "Nick", - "Bez", - }, - 0, - "Tragédie.", - }, - { - "Kdo zabije Gatsbyho?", - { - "George Wilson", - "Tom", - "Nick", - "Daisy", - }, - 0, - "Myrtlein manžel.", - }, - { - "Jak Gatsby zemře?", - { - "V bazénu – střela", - "Stářím", - "Moře", - "Válka", - }, - 0, - "Tragický konec.", - }, - { - "Nick na konci?", - { - "Odejde zpět na Midwest", - "S Daisy", - "Král", - "Bez", - }, - 0, - "Disiluze.", - }, - { - "Americký sen?", - { - "Kritika – iluze úspěchu", - "Bez tématu", - "Sci-fi", - "Bez", - }, - 0, - "Jádro románu.", - }, - { - "Tom Buchanan?", - { - "Arogantní boháč", - "Chudý", - "Kněz", - "Pilot", - }, - 0, - "Antagonista morálky.", - }, - { - "Jordan?", - { - "Golfistka, vztah s Nickem", - "Gatsbyho sestra", - "Wilson", - "Bez", - }, - 0, - "Vedlejší linie.", - }, - { - "Valley of Ashes?", - { - "Průmyslová chudoba mezi Eggs", - "Raj", - "Moře", - "Bez", - }, - 0, - "Kontrast.", - }, - { - "Eckleburg oči?", - { - "Billboard – symbol", - "Bez", - "Gatsby", - "Daisy", - }, - 0, - "Moderní symbol.", - }, - { - "Gatsby původní jméno?", - { - "James Gatz", - "Nick", - "Tom", - "Jay only", - }, - 0, - "Přetvoření identity.", - }, - { - "Daisy a Gatsby minulost?", - { - "Milovali se před válkou", - "Ne", - "Sourozenci", - "Bez", - }, - 0, - "Louisville.", - }, - { - "Auto accident?", - { - "Myrtle killed – zvrat", - "Bez", - "Gatsby wins", - "Bez", - }, - 0, - "Klíčová scéna.", - }, - { - "Kdo řídí auto?", - { - "Daisy (debata) – Gatsby chrání", - "Wilson", - "Nick", - "Bez", - }, - 0, - "Gatsby přebírá vinu.", - }, - { - "Žánr?", - { - "Modernistický román", - "Epos", - "Báseň", - "Drama", - }, - 0, - "Literature 20. st.", - }, - { - "Rok?", - { - "1925", - "1949", - "2000", - "1890", - }, - 0, - "Jazz age.", - }, - { - "Co NENÍ?", - { - "Kritika snu", - "Láska", - "Tragedie", - "Kosmické mloky", - }, - 3, - "Realistický USA.", - }, - { - "Nick a Gatsby?", - { - "Přátelství, obdiv", - "Nepřátelé", - "Bratři", - "Bez", - }, - 0, - "Nick vypráví.", - }, - { - "Gatsbyho pohřeb?", - { - "Skoro nikdo nepřijde", - "Národní slavnost", - "Bez", - "Tom only", - }, - 0, - "Osamělost.", - }, - { - "Překlad Dorůžka?", - { - "České vydání", - "Bez", - "Anglicky jen", - "Bez", - }, - 0, - "Maturita.", - }, - { - "Tón?", - { - "Elegický, kritický", - "Pure comedy", - "Horor", - "Bez", - }, - 0, - "Tragédie snu.", - }, - { - "Daisy hlas?", - { - "Symbol půvabu a prázdnoty", - "Bez", - "Sci-fi", - "Bez", - }, - 0, - "Motiv.", - }, - { - "Poselství?", - { - "Sen může být iluze ničící", - "Vždy vyhraj", - "Bez", - "Sport", - }, - 0, - "Fitzgeraldova kritika.", - }, - { - "Co symbolizují oči doktora T. J. Eckleburga?", - { - "Prázdný moralismus reklamní civilizace / „Bůh“ údolí popela", - "Gatsbyho majetek", - "Nickovu rodinu", - "Daisyin hlas", - }, - 0, - "Billboard je jedním z nejsilnějších obrazů románu.", - }, - { - "Proč Gatsby na konci zůstává osamělý i při velkých párty?", - { - "Hosté využívají lesk, ne jeho – touží jen po Daisy", - "Protože je neznámý", - "Protože je z chudiny", - "Protože je v exilu", - }, - 0, - "Párty maskují osamělost muže žijícího v iluzi minulosti.", - }, -}; - -static const AssemblyItem book_velky_gatsby_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Nick přijede na Long Island", - "Pozná Gatsbyho a párty", - "Gatsby chce Daisy zpět", - "Aféra, napětí s Tomem", - "Myrtleina smrt autem", - "Wilson zabije Gatsbyho – Nick odchází", - }, - 6, - }, -}; - -static const char *book_velky_gatsby_plot_meaning[] = { - "Správné pořadí: Nick → Gatsby → Daisy → konflikt → nehoda → smrt Gatsbyho.", -}; - -static const LitQ book_tridni_kniha_qs[] = { - { - "Kdo napsal hru?", - { - "Goldoni", - "Smoljak a Svěrák", - "Čapek", - "Vrchlický", - }, - 1, - "Cimrmanovo divadlo.", - }, - { - "Titul hry?", - { - "Vyšetřování ztráty třídní knihy", - "Sluha dvou pánů", - "Revizor", - "R.U.R.", - }, - 0, - "Maturitní název.", - }, - { - "Kde děj?", - { - "Škola – sborovna", - "Moře", - "RAF", - "Terezín", - }, - 0, - "Školní prostředí.", - }, - { - "Co zmizelo?", - { - "Třídní kniha", - "Gatsby", - "Marlin", - "Mloci", - }, - 0, - "Předmět vyšetřování.", - }, - { - "Žánr?", - { - "Komedie / parodie", - "Tragedie", - "Epos", - "Lyrika", - }, - 0, - "Humor.", - }, - { - "Cimrman?", - { - "Fiktivní génius divadla", - "Reálný učitel", - "Němec", - "Pilot", - }, - 0, - "Značka divadla.", - }, - { - "Humor?", - { - "Absurdní vyšetřování", - "Horor", - "Bez", - "Pure romance", - }, - 0, - "Parodie.", - }, - { - "Učitel Nechleb?", - { - "Postava z Cimrmanových her", - "Gatsby", - "Winston", - "Bez", - }, - 0, - "Komická figura.", - }, - { - "Satira?", - { - "Byrokracie, škola", - "Bez", - "Jen moře", - "Válka", - }, - 0, - "Společenská.", - }, - { - "Rok uvedení?", - { - "1967", - "1925", - "1869", - "2000", - }, - 0, - "Divadlo.", - }, - { - "Forma?", - { - "Divadelní dialogy", - "Román", - "Báseň", - "Memoáry", - }, - 0, - "Drama.", - }, - { - "Proč maturita?", - { - "Česká divadelní komedie", - "Bez", - "Jen mapa", - "Komiks", - }, - 0, - "Kultura.", - }, - { - "Třídní kniha symbol?", - { - "Řád, evidence, malichernost", - "Láska", - "Válka", - "Bez", - }, - 0, - "Škola.", - }, - { - "Co NENÍ?", - { - "Komedie", - "Parodie", - "Škola", - "Seriózní naturalistický román Zola", - }, - 3, - "Jiný žánr.", - }, - { - "Smoljak Svěrák?", - { - "Autorská dvojice", - "Piloti", - "Němci", - "Bez", - }, - 0, - "Cimrman.", - }, - { - "Vyšetřování?", - { - "Přehnané, detektivní parodie", - "Real NYPD", - "Bez", - "Sci-fi", - }, - 0, - "Komický děj.", - }, - { - "Publikum?", - { - "Směje se absurditě", - "Pláče", - "Bez", - "Spí", - }, - 0, - "Divadlo.", - }, - { - "Jazyk?", - { - "Hovorný, hříčky", - "Archaičtina", - "Angličtina", - "Bez", - }, - 0, - "Svěrák/Smoljak.", - }, - { - "Žáci?", - { - "Důvod existence knihy", - "Hrdinové bez školy", - "Ne", - "Piloti", - }, - 0, - "Kontext.", - }, - { - "Sborovna?", - { - "Místo děje", - "Moře", - "RAF", - "Bez", - }, - 0, - "Prostor.", - }, - { - "Další Cimrman?", - { - "Hospoda na mýtince aj.", - "Gatsby", - "1984", - "Bez", - }, - 0, - "Divadlo.", - }, - { - "Tón?", - { - "Lehký, absurdní", - "Tragický", - "Horor", - "Bez", - }, - 0, - "Komedie.", - }, - { - "Autorita ředitele?", - { - "Parodována", - "Bez", - "Vždy moudrá", - "Bez", - }, - 0, - "Satira.", - }, - { - "Detektivka prvky?", - { - "Podezření, výslech", - "Bez", - "Jen láska", - "Válka", - }, - 0, - "Parodie.", - }, - { - "Česká kultura?", - { - "Ikona", - "Neznámé", - "Bez", - "Německé", - }, - 0, - "Populární.", - }, - { - "Hra vs román?", - { - "Text pro divadlo", - "Epos", - "Bez", - "Lyrika", - }, - 0, - "Drama.", - }, - { - "Malichernost?", - { - "Velká věc z maličkosti", - "Bez", - "Válka", - "Bez", - }, - 0, - "Humor.", - }, - { - "Cimrman žil?", - { - "Fiktivně – vtip", - "2000", - "1890 real", - "Bez", - }, - 0, - "Mýtus.", - }, - { - "Maturita tip?", - { - "Děj, humor, smysl parodie", - "Jen rok", - "Bez", - "Mapa", - }, - 0, - "Interpretace.", - }, - { - "Závěr hry?", - { - "Rozuzlení komické", - "Všichni mrtví tragicky", - "Bez", - "Válka", - }, - 0, - "Komedie.", - }, - { - "O co jde v ději Třídní knihy?", - { - "O absurdní vyšetřování ztráty třídní knihy ve škole", - "O válku s mloky", - "O rybaření na Kubě", - "O jazz v Náchodsku", - }, - 0, - "Ztráta knihy spustí groteskní školní „vyšetřování“.", - }, - { - "Jaký humor je typický pro Třídní knihu?", - { - "Situační absurdita, byrokracie a jazykové hříčky", - "Naturalistický determinismus", - "Gotický horor", - "Epická báseň", - }, - 0, - "Smoljak–Svěrák pracují s pravidly, která přerostou smysl.", - }, -}; - -static const AssemblyItem book_tridni_kniha_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Zmizí třídní kniha", - "Ředitel zahájí vyšetřování", - "Učitelé jsou vyslýcháni", - "Absurdní důkazy a pomluvy", - "Cimrmanovské vysvětlení", - "Případ se uzavře komicky", - }, - 6, - }, -}; - -static const char *book_tridni_kniha_plot_meaning[] = { - "Správné pořadí: ztráta knihy → vyšetřování → výslechy → absurdita → vysvětlení → konec.", -}; - -static const LitQ book_zabijak_qs[] = { - { - "Kdo napsal Zabijáka?", - { - "Hugo", - "Émile Zola", - "Flaubert", - "Styron", - }, - 1, - "Zola 1870.", - }, - { - "Kde děj?", - { - "Paříž – tržnice Les Halles", - "Praha", - "Moře", - "RAF", - }, - 0, - "Masná tržnice.", - }, - { - "Florent?", - { - "Údajný vrah, bývalý učitel", - "Pilot", - "Sluha", - "Gatsby", - }, - 0, - "Titulní role.", - }, - { - "Proč zabiják?", - { - "Zabil muže v sebeobraně – odsouzen", - "Bez důvodu", - "Detektiv", - "Král", - }, - 0, - "Minulost.", - }, - { - "Lisa?", - { - "Tchyně, antagonistka", - "Manželka Florent", - "Daisy", - "Ester", - }, - 0, - "Konflikt.", - }, - { - "Quenu?", - { - "Řezník, manžel", - "Pilot", - "Učitel", - "Bez", - }, - 0, - "Rodina.", - }, - { - "Naturalismus?", - { - "Prostředí určuje osud", - "Bez", - "Sci-fi", - "Bez", - }, - 0, - "Zolův program.", - }, - { - "Halles?", - { - "Obrovská tržnice, maso, pach", - "Moře", - "Škola", - "Bez", - }, - 0, - "Prostředí.", - }, - { - "Florent sny?", - { - "Revoluce, spravedlnost", - "Bez", - "Jen láska", - "Sport", - }, - 0, - "Politika.", - }, - { - "Konflikt Florent–Lisa?", - { - "Moc v domě a na trhu", - "Bez", - "Přátelé", - "Bez", - }, - 0, - "Tlak.", - }, - { - "Jak končí Florent?", - { - "Znovu zatčen / zničen", - "Král", - "Šťastný", - "Emigrace", - }, - 0, - "Tragicky.", - }, - { - "Maso symbol?", - { - "Brutalita, kapitalismus", - "Bez", - "Láska", - "Bez", - }, - 0, - "Naturalistická metafora.", - }, - { - "Rok?", - { - "1870", - "1925", - "2000", - "1867 Tereza", - }, - 0, - "Zola.", - }, - { - "Tereza Raquin?", - { - "Jiné Zolino dílo", - "Totéž", - "Bez", - "Gatsby", - }, - 0, - "Stejný autor.", - }, - { - "Co NENÍ?", - { - "Naturalismus", - "Paříž", - "Tržnice", - "Kosmické mloky", - }, - 3, - "Jiné dílo.", - }, - { - "Dělníci Halles?", - { - "Sociální vrstva", - "Ne", - "Jen králové", - "Bez", - }, - 0, - "Realismus.", - }, - { - "Florent návrat?", - { - "Z trestu na trh", - "Z moře", - "Bez", - "RAF", - }, - 0, - "Děj.", - }, - { - "Atmosféra?", - { - "Těžká, pach, hlučnost", - "Idyla", - "Bez", - "Komedy", - }, - 0, - "Naturalismus.", - }, - { - "Maturita?", - { - "Zola, naturalismus, prostředí", - "Bez", - "Jen mapa", - "Bez", - }, - 0, - "Francouzská próza.", - }, - { - "Vyprávění?", - { - "Er-forma", - "Deník", - "Drama", - "Báseň", - }, - 0, - "Román.", - }, - { - "Lisa moc?", - { - "Manipuluje domácnost", - "Bez", - "Slabá", - "Bez", - }, - 0, - "Antagonista.", - }, - { - "Revoluce?", - { - "Florent idealista", - "Bez", - "Vždy vítězí", - "Bez", - }, - 0, - "Motiv.", - }, - { - "Zola cyklus?", - { - "Rougon-Macquart", - "Bez", - "1984", - "Bez", - }, - 0, - "Součást.", - }, - { - "Překlad Kárl?", - { - "České vydání", - "Bez", - "Anglicky", - "Bez", - }, - 0, - "Maturita.", - }, - { - "Tělo / maso?", - { - "Fyziologie města", - "Bez", - "Bez tématu", - "Bez", - }, - 0, - "Detail.", - }, - { - "Florent charakter?", - { - "Snílek i outsider", - "Král", - "Bez", - "Dítě", - }, - 0, - "Psychologie.", - }, - { - "Tón?", - { - "Temný naturalismus", - "Pure comedy", - "Bez", - "Pohádka", - }, - 0, - "Zola.", - }, - { - "Trh Halles?", - { - "Srdce děje", - "Okraj", - "Bez", - "Moře", - }, - 0, - "Prostředí.", - }, - { - "Determinismus?", - { - "Vina minulosti + prostředí", - "Svoboda bez limitů", - "Bez", - "Magie", - }, - 0, - "Teorie.", - }, - { - "Titul?", - { - "Odkaz na Florentovu minulost", - "Lovec srn", - "Bez", - "Pilot", - }, - 0, - "Zabiják.", - }, - { - "Proč se Florent nazývá „zabiják“?", - { - "V minulosti zabil muže a pyká trestem odnětí svobody", - "Pracuje jako řezník na Halles", - "Je detektiv z Paříže", - "Je fiktivní hrdina Hemingwaye", - }, - 0, - "Titul vychází z Florentovy vražedné minulosti, která ho pronásleduje.", - }, - { - "Co symbolizují pařížské Halles v románu?", - { - "Kapitalistický svět masa, těla a brutality města", - "Idylickou venkovskou přírodu", - "Klášterní ticho", - "Vzdušné souboje RAF", - }, - 0, - "Tržnice je naturalistickým prostředím, které formuje postavy i atmosféru.", - }, -}; - -static const AssemblyItem book_zabijak_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Florent se vrací z trestu", - "Bydlí u řezníka Quenua", - "Konflikt s Lisou na Halles", - "Politické sny a napětí", - "Florent se propadá", - "Znovu ztrácí svobodu / zničení", - }, - 6, - }, -}; - -static const char *book_zabijak_plot_meaning[] = { - "Správné pořadí: návrat → rodina → konflikt → sny → eskalace → pád Florenta.", -}; - -static const LitQ book_zbabelci_qs[] = { - { - "Kdo napsal Zbabělce?", - { - "Kundera", - "Josef Škvorecký", - "Hrabal", - "Otčenášek", - }, - 1, - "Škvorecký 1958.", - }, - { - "Kdo vypráví?", - { - "Danny Smiřický", - "Gatsby", - "Winston", - "Svejk", - }, - 0, - "Gymnazista.", - }, - { - "Kdy děj?", - { - "Květen 1945", - "1920", - "1989", - "1848", - }, - 0, - "Konec války.", - }, - { - "Kde?", - { - "Náchodsko", - "Long Island", - "Paříž Halles", - "Moře", - }, - 0, - "České pohraničí.", - }, - { - "Proč zbabělci?", - { - "Ironie – strach mládí v chaosu", - "Všichni hrdinové", - "Bez", - "Detektivka", - }, - 0, - "Titul.", - }, - { - "Jazz?", - { - "Dannyho vášeň, symbol svobody", - "Ne", - "Zakázáno bez významu", - "Bez", - }, - 0, - "Motiv.", - }, - { - "Škvorecký?", - { - "Později v exilu v Kanadě", - "Nikdy neodešel", - "Němec", - "Bez", - }, - 0, - "Osud autora.", - }, - { - "Cenzura?", - { - "Kniha u nás dlouho problematická", - "Bez", - "Vždy volná", - "Bez", - }, - 0, - "Normalizace.", - }, - { - "Žánr?", - { - "Autobiografický román", - "Báseň", - "Drama", - "Epos", - }, - 0, - "Próza.", - }, - { - "Danny věk?", - { - "Gymnazista – mládí", - "Starý", - "Dítě", - "Generál", - }, - 0, - "Perspektiva.", - }, - { - "Válka končí?", - { - "Chaos osvobození", - "Bez", - "1940", - "2000", - }, - 0, - "Květen.", - }, - { - "Lásky?", - { - "Lída, Irena aj.", - "Bez", - "Jen Gatsby", - "Bez", - }, - 0, - "Erotika.", - }, - { - "Co NENÍ?", - { - "Konec války", - "Jazz", - "Mládí", - "Kosmické mloky", - }, - 3, - "Jiné dílo.", - }, - { - "Tón?", - { - "Hovorový, ironický", - "Epický bez humoru", - "Bez", - "Opera", - }, - 0, - "Styl.", - }, - { - "Partyzáni?", - { - "Součást osvobození", - "Ne", - "Jen Němci", - "Bez", - }, - 0, - "Děj.", - }, - { - "Němci ustupují?", - { - "Ano", - "Ne", - "Bez", - "2000", - }, - 0, - "Květen 45.", - }, - { - "Maturita?", - { - "Generace 45, jazz, Škvorecký", - "Bez", - "Mapa", - "Bez", - }, - 0, - "Česká próza.", - }, - { - "Emigrace autora?", - { - "Po 68", - "Nikdy", - "1890", - "Bez", - }, - 0, - "Historie.", - }, - { - "Danny strach?", - { - "Válka, sex, budoucnost", - "Bez", - "Jen jazz", - "Bez", - }, - 0, - "Psychologie.", - }, - { - "Americká kultura?", - { - "Idealizace", - "Ne", - "Zakázáno bez motivu", - "Bez", - }, - 0, - "Jazz.", - }, - { - "Škvorecký jiné?", - { - "Mirákl, Tankový prapor", - "Gatsby", - "Bez", - "Wolker", - }, - 0, - "Tvorba.", - }, - { - "Vyprávění?", - { - "Er-forma", - "Deník", - "Drama", - "Báseň", - }, - 0, - "Román.", - }, - { - "Ironie?", - { - "Zbabělci – self-deprecation", - "Bez", - "Bez humoru", - "Bez", - }, - 0, - "Titul.", - }, - { - "Publikum?", - { - "Mladí i dospělí", - "Bez", - "Jen děti", - "Bez", - }, - 0, - "Generační.", - }, - { - "Okupace?", - { - "Končí – radost i chaos", - "Začíná", - "Bez", - "2000", - }, - 0, - "Květen.", - }, - { - "Jazyk?", - { - "Hovorová čeština", - "Angličtina", - "Bez", - "Latině", - }, - 0, - "Styl.", - }, - { - "Hrdinství?", - { - "Problematizováno", - "Jasné", - "Bez", - "Bez", - }, - 0, - "Antihero.", - }, - { - "Rok vydání?", - { - "1958", - "1945", - "2000", - "1869", - }, - 0, - "Exil.", - }, - { - "Náchod?", - { - "Reálné město", - "Fikce", - "USA", - "Bez", - }, - 0, - "Prostředí.", - }, - { - "Poselství?", - { - "Mladí v historickém zlomu", - "Bez", - "Válka je hra", - "Bez", - }, - 0, - "Generační novela.", - }, - { - "Jak Danny reaguje na konec války a příchod Sovětů?", - { - "S mísením naděje, strachu a ironie – generace na rozhraní", - "Bez emocí", - "Okamžitě emigruje", - "Stává se rybářem", - }, - 0, - "Román zachycuje psychiku mládí v květnu 1945.", - }, - { - "Proč je jazz ve Zbabělcích důležitý?", - { - "Symbol svobody, identity a jiného světa než ideologie", - "Jen kulisa bez významu", - "Zakázaný bez zmínky", - "Nahrazuje děj", - }, - 0, - "Dannyho vášeň pro jazz kontrastuje s politickým tlakem.", - }, -}; - -static const AssemblyItem book_zbabelci_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Danny žije okupaci a jazz", - "Květen 1945 – chaos", - "Osvobození a strach", - "Lásky a party", - "Setkání s realitou války", - "Závěr – mládí v nové době", - }, - 6, - }, -}; - -static const char *book_zbabelci_plot_meaning[] = { - "Správné pořadí: okupace → květen 45 → osvobození → vztahy → zrání → nová éra.", -}; - -static const LitQ book_zert_qs[] = { - { - "Kdo napsal Žert?", - { - "Škvorecký", - "Milan Kundera", - "Havel", - "Čapek", - }, - 1, - "Kundera 1967.", - }, - { - "Co Ludvík udělá?", - { - "Pošle žertovný postcard poslanci", - "Zavraždí", - "Uteče", - "Bez", - }, - 0, - "Trigger děje.", - }, - { - "Důsledek žertu?", - { - "Vyhoštění z KSČ, gulag práce", - "Nobelovka", - "Svatba", - "Bez", - }, - 0, - "Režim.", - }, - { - "Pomsta?", - { - "Na Zemanově milence Markétě", - "Na Tomovi", - "Bez", - "Na mlokovi", - }, - 0, - "Plán Ludvíka.", - }, - { - "Kdy děj?", - { - "50.–60. léta ČSSR", - "1945", - "1984", - "1890", - }, - 0, - "Socialismus.", - }, - { - "Zeman?", - { - "Poslanec, oběť", - "Pilot", - "Sluha", - "Gatsby", - }, - 0, - "Politik.", - }, - { - "Markéta?", - { - "Milenka, nástroj pomsty", - "Sestra", - "Bez", - "Němka", - }, - 0, - "Postava.", - }, - { - "Jak pomsta dopadne?", - { - "Ludvík neuspěje – ironie", - "Dokonalá", - "Bez", - "Smrt všech", - }, - 0, - "Kunderova ironie.", - }, - { - "Kundera styl?", - { - "Filosofické odbočky, struktura", - "Bez", - "Jen báseň", - "Bez", - }, - 0, - "Moderní román.", - }, - { - "Téma historie?", - { - "Osobní osud vs. ideologie", - "Bez", - "Sci-fi", - "Bez", - }, - 0, - "Jádro.", - }, - { - "Rok vydání?", - { - "1967", - "1958", - "2000", - "1949", - }, - 0, - "Před 68.", - }, - { - "Co NENÍ?", - { - "Politika", - "Pomsta", - "Ironie", - "Kosmické mloky", - }, - 3, - "Jiné dílo.", - }, - { - "Ludvík po trestu?", - { - "Manuální práce, outsider", - "Ministr", - "Bez", - "Král", - }, - 0, - "Stigma.", - }, - { - "Film?", - { - "1969 Jaromil Jireš", - "Bez", - "Gatsby", - "Bez", - }, - 0, - "Nová vlna.", - }, - { - "Kostra?", - { - "Přítel Ludvíka", - "Bez", - "Němec", - "Bez", - }, - 0, - "Postava.", - }, - { - "Helena?", - { - "Manželka Ludvíka", - "Bez", - "Daisy", - "Bez", - }, - 0, - "Rodina.", - }, - { - "Maturita?", - { - "Struktura, témata, kontext 50. let", - "Bez", - "Mapa", - "Bez", - }, - 0, - "Česká próza.", - }, - { - "Ironie?", - { - "Pomsta se obrátí proti pomstiteli", - "Bez", - "Bez humoru", - "Bez", - }, - 0, - "Závěr.", - }, - { - "Autor komentář?", - { - "Kundera přerušuje děj", - "Ne", - "Bez", - "Shakespeare", - }, - 0, - "Forma.", - }, - { - "KSČ?", - { - "Politická moc", - "Bez", - "Jazz klub", - "Bez", - }, - 0, - "Režim.", - }, - { - "Existenciální?", - { - "Smysl, náhoda, osud", - "Bez", - "Jen sport", - "Bez", - }, - 0, - "Filosofie.", - }, - { - "Kundera později?", - { - "Emigrace do Francie", - "Nikdy", - "1890", - "Bez", - }, - 0, - "Autor.", - }, - { - "Žert definice?", - { - "Drobnost s velkými důsledky", - "Válka", - "Bez", - "Láska only", - }, - 0, - "Titul.", - }, - { - "Markéta a Ludvík?", - { - "Aféra jako pomsta", - "Sourozenci", - "Bez", - "Bez", - }, - 0, - "Děj.", - }, - { - "Tón?", - { - "Ironický, vážný", - "Pure comedy", - "Bez", - "Pohádka", - }, - 0, - "Kundera.", - }, - { - "Struktura?", - { - "Retrospektivy, kapitoly", - "Jeden den", - "Bez", - "Báseň", - }, - 0, - "Román.", - }, - { - "Normalizace?", - { - "Kniha rezonovala", - "Bez", - "2000", - "Bez", - }, - 0, - "Kontext.", - }, - { - "Láska a moc?", - { - "Propleteno", - "Bez", - "Bez tématu", - "Bez", - }, - 0, - "Téma.", - }, - { - "Vypravěč?", - { - "Ludvík + autor", - "Nick", - "Bez", - "Bez", - }, - 0, - "Perspektivy.", - }, - { - "Poselství?", - { - "Historie ničí i drobné činy", - "Bez", - "Vždy vyhraj", - "Bez", - }, - 0, - "Kunderova myšlenka.", - }, - { - "Kdo je Kostka v Žertu?", - { - "Křesťanský intelektuál, s nímž Ludvík debatuje o smyslu", - "Velitel SNB", - "Rybář Santiago", - "Gatsby", - }, - 0, - "Kostka reprezentuje jinou etickou perspektivu než režim.", - }, - { - "Jak dopadne Ludvíkova pomsta skrze Helenu?", - { - "Neplní očekávání – ironie a selhání plánu", - "Dokonalý triumf", - "Helena zatčena hned", - "Ludvík emigruje bez důsledků", - }, - 0, - "Kundera ukazuje, že minulost nelze jednoduše „opravit“ pomstou.", - }, -}; - -static const AssemblyItem book_zert_plot[] = { - { - "Přetáhněte části příběhu do správného pořadí:", - { - "Ludvík pošle žertovný dopis", - "Trest – vyhoštění z strany, práce", - "Léta plynou – hořkost", - "Plán pomsty přes Markétu", - "Aféra a zklamání", - "Pomsta se nezdaří – ironický konec", - }, - 6, - }, -}; - -static const char *book_zert_plot_meaning[] = { - "Správné pořadí: žert → trest → léta → plán pomsty → Markéta → neúspěch pomsty.", -}; - -static const BookExPack book_ex_packs[BOOK_NODES] = { - {book_1984_qs, 32, book_1984_plot, book_1984_plot_meaning, 1}, - {book_fahrenheit451_qs, 32, book_fahrenheit451_plot, book_fahrenheit451_plot_meaning, 1}, - {book_audience_qs, 32, book_audience_plot, book_audience_plot_meaning, 1}, - {book_bajecna_leta_qs, 32, book_bajecna_leta_plot, book_bajecna_leta_plot_meaning, 1}, - {book_bidnici_qs, 32, book_bidnici_plot, book_bidnici_plot_meaning, 1}, - {book_bila_nemoc_qs, 32, book_bila_nemoc_plot, book_bila_nemoc_plot_meaning, 1}, - {book_bylo_nas_pet_qs, 32, book_bylo_nas_pet_plot, book_bylo_nas_pet_plot_meaning, 1}, - {book_cekani_na_godota_qs, 31, book_cekani_na_godota_plot, book_cekani_na_godota_plot_meaning, 1}, - {book_ceske_nebe_qs, 31, book_ceske_nebe_plot, book_ceske_nebe_plot_meaning, 1}, - {book_dekameron_qs, 31, book_dekameron_plot, book_dekameron_plot_meaning, 1}, - {book_den_trifidu_qs, 32, book_den_trifidu_plot, book_den_trifidu_plot_meaning, 1}, - {book_denik_anny_frankove_qs, 32, book_denik_anny_frankove_plot, book_denik_anny_frankove_plot_meaning, 1}, - {book_jekyll_hyde_qs, 32, book_jekyll_hyde_plot, book_jekyll_hyde_plot_meaning, 1}, - {book_edison_qs, 31, book_edison_plot, book_edison_plot_meaning, 1}, - {book_farma_zvirat_qs, 32, book_farma_zvirat_plot, book_farma_zvirat_plot_meaning, 1}, - {book_gulliverovy_cesty_qs, 32, book_gulliverovy_cesty_plot, book_gulliverovy_cesty_plot_meaning, 1}, - {book_hamlet_qs, 32, book_hamlet_plot, book_hamlet_plot_meaning, 1}, - {book_havran_qs, 32, book_havran_plot, book_havran_plot_meaning, 1}, - {book_hladove_hry_qs, 32, book_hladove_hry_plot, book_hladove_hry_plot_meaning, 1}, - {book_hlava_xxii_qs, 32, book_hlava_xxii_plot, book_hlava_xxii_plot_meaning, 1}, - {book_chram_matky_bozi_qs, 32, book_chram_matky_bozi_plot, book_chram_matky_bozi_plot_meaning, 1}, - {book_jak_jsem_vyhral_valku_qs, 30, book_jak_jsem_vyhral_valku_plot, book_jak_jsem_vyhral_valku_plot_meaning, 1}, - {book_jana_eyrova_qs, 30, book_jana_eyrova_plot, book_jana_eyrova_plot_meaning, 1}, - {book_ivan_denisovic_qs, 30, book_ivan_denisovic_plot, book_ivan_denisovic_plot_meaning, 1}, - {book_jmeno_ruze_qs, 30, book_jmeno_ruze_plot, book_jmeno_ruze_plot_meaning, 1}, - {book_kalibuv_zlocin_qs, 30, book_kalibuv_zlocin_plot, book_kalibuv_zlocin_plot_meaning, 1}, - {book_kniska_karla_kryla_qs, 30, book_kniska_karla_kryla_plot, book_kniska_karla_kryla_plot_meaning, 1}, - {book_komu_zvoni_hrana_qs, 30, book_komu_zvoni_hrana_plot, book_komu_zvoni_hrana_plot_meaning, 1}, - {book_kral_oidipus_qs, 30, book_kral_oidipus_plot, book_kral_oidipus_plot_meaning, 1}, - {book_krysar_qs, 30, book_krysar_plot, book_krysar_plot_meaning, 1}, - {book_kulicka_qs, 30, book_kulicka_plot, book_kulicka_plot_meaning, 1}, - {book_kvety_zla_qs, 30, book_kvety_zla_plot, book_kvety_zla_plot_meaning, 1}, - {book_kytice_qs, 30, book_kytice_plot, book_kytice_plot_meaning, 1}, - {book_lakomec_qs, 29, book_lakomec_plot, book_lakomec_plot_meaning, 1}, - {book_lolita_qs, 30, book_lolita_plot, book_lolita_plot_meaning, 1}, - {book_maj_qs, 29, book_maj_plot, book_maj_plot_meaning, 1}, - {book_maly_princ_qs, 29, book_maly_princ_plot, book_maly_princ_plot_meaning, 1}, - {book_marysa_qs, 29, book_marysa_plot, book_marysa_plot_meaning, 1}, - {book_modlitba_pro_katerinu_qs, 30, book_modlitba_pro_katerinu_plot, book_modlitba_pro_katerinu_plot_meaning, 1}, - {book_most_kwai_qs, 30, book_most_kwai_plot, book_most_kwai_plot_meaning, 1}, - {book_stanice_zoo_qs, 30, book_stanice_zoo_plot, book_stanice_zoo_plot_meaning, 1}, - {book_na_ceste_qs, 31, book_na_ceste_plot, book_na_ceste_plot_meaning, 1}, - {book_na_zapadni_fronte_qs, 31, book_na_zapadni_fronte_plot, book_na_zapadni_fronte_plot_meaning, 1}, - {book_navsteva_stare_damy_qs, 30, book_navsteva_stare_damy_plot, book_navsteva_stare_damy_plot_meaning, 1}, - {book_nebe_nezna_vyvolenych_qs, 30, book_nebe_nezna_vyvolenych_plot, book_nebe_nezna_vyvolenych_plot_meaning, 1}, - {book_o_mysich_a_lidech_qs, 30, book_o_mysich_a_lidech_plot, book_o_mysich_a_lidech_plot_meaning, 1}, - {book_obraz_doriana_graye_qs, 30, book_obraz_doriana_graye_plot, book_obraz_doriana_graye_plot_meaning, 1}, - {book_obsluhoval_jsem_qs, 30, book_obsluhoval_jsem_plot, book_obsluhoval_jsem_plot_meaning, 1}, - {book_oliver_twist_qs, 30, book_oliver_twist_plot, book_oliver_twist_plot_meaning, 1}, - {book_ostre_sledovane_vlaky_qs, 30, book_ostre_sledovane_vlaky_plot, book_ostre_sledovane_vlaky_plot_meaning, 1}, - {book_svejk_qs, 31, book_svejk_plot, book_svejk_plot_meaning, 1}, - {book_pan_much_qs, 30, book_pan_much_plot, book_pan_much_plot_meaning, 1}, - {book_pan_prstenu_qs, 30, book_pan_prstenu_plot, book_pan_prstenu_plot_meaning, 1}, - {book_petr_a_lucie_qs, 30, book_petr_a_lucie_plot, book_petr_a_lucie_plot_meaning, 1}, - {book_poe_povidky_qs, 30, book_poe_povidky_plot, book_poe_povidky_plot_meaning, 1}, - {book_povidky_z_kapes_qs, 30, book_povidky_z_kapes_plot, book_povidky_z_kapes_plot_meaning, 1}, - {book_promena_qs, 29, book_promena_plot, book_promena_plot_meaning, 1}, - {book_pycha_a_predsudek_qs, 30, book_pycha_a_predsudek_plot, book_pycha_a_predsudek_plot_meaning, 1}, - {book_rur_qs, 30, book_rur_plot, book_rur_plot_meaning, 1}, - {book_revizor_qs, 30, book_revizor_plot, book_revizor_plot_meaning, 1}, - {book_romeo_a_julie_qs, 30, book_romeo_a_julie_plot, book_romeo_a_julie_plot_meaning, 1}, - {book_romeo_julie_a_tma_qs, 30, book_romeo_julie_a_tma_plot, book_romeo_julie_a_tma_plot_meaning, 1}, - {book_rozmarne_leto_qs, 30, book_rozmarne_leto_plot, book_rozmarne_leto_plot_meaning, 1}, - {book_ruze_pro_algernon_qs, 30, book_ruze_pro_algernon_plot, book_ruze_pro_algernon_plot_meaning, 1}, - {book_saturnin_qs, 30, book_saturnin_plot, book_saturnin_plot_meaning, 1}, - {book_sluha_dvou_panu_qs, 30, book_sluha_dvou_panu_plot, book_sluha_dvou_panu_plot_meaning, 1}, - {book_smrt_krasnych_srncu_qs, 30, book_smrt_krasnych_srncu_plot, book_smrt_krasnych_srncu_plot_meaning, 1}, - {book_sofiina_volba_qs, 30, book_sofiina_volba_plot, book_sofiina_volba_plot_meaning, 1}, - {book_fuks_qs, 32, book_fuks_plot, book_fuks_plot_meaning, 1}, - {book_stare_recke_baje_qs, 30, book_stare_recke_baje_plot, book_stare_recke_baje_plot_meaning, 1}, - {book_starec_a_more_qs, 32, book_starec_a_more_plot, book_starec_a_more_plot_meaning, 1}, - {book_svaty_xaverius_qs, 32, book_svaty_xaverius_plot, book_svaty_xaverius_plot_meaning, 1}, - {book_tereza_raquinova_qs, 32, book_tereza_raquinova_plot, book_tereza_raquinova_plot_meaning, 1}, - {book_tezka_hodina_qs, 32, book_tezka_hodina_plot, book_tezka_hodina_plot_meaning, 1}, - {book_tyrolske_elegie_qs, 32, book_tyrolske_elegie_plot, book_tyrolske_elegie_plot_meaning, 1}, - {book_valka_s_mloky_qs, 32, book_valka_s_mloky_plot, book_valka_s_mloky_plot_meaning, 1}, - {book_velky_cirkus_qs, 32, book_velky_cirkus_plot, book_velky_cirkus_plot_meaning, 1}, - {book_velky_gatsby_qs, 32, book_velky_gatsby_plot, book_velky_gatsby_plot_meaning, 1}, - {book_tridni_kniha_qs, 32, book_tridni_kniha_plot, book_tridni_kniha_plot_meaning, 1}, - {book_zabijak_qs, 32, book_zabijak_plot, book_zabijak_plot_meaning, 1}, - {book_zbabelci_qs, 32, book_zbabelci_plot, book_zbabelci_plot_meaning, 1}, - {book_zert_qs, 32, book_zert_plot, book_zert_plot_meaning, 1} -}; - diff --git a/src/cetba_book_notes.inc b/src/cetba_book_notes.inc deleted file mode 100644 index 123ec27..0000000 --- a/src/cetba_book_notes.inc +++ /dev/null @@ -1,3865 +0,0 @@ -/* Generated from data/cetba JSON packs – do not edit by hand. */ - -typedef struct { - const char *title; - const char *const *lines; -} BookNoteSec; - -typedef struct { - const BookNoteSec *secs; - int nsec; -} BookNotePack; - -static const char *const book_1984_n0[] = { - "Autor: George Orwell (vl. jm. Eric Arthur Blair)", - "Žánr: antiutopický (dystopický) román", - "Poprvé vydáno: 1949", - "Děj: Londýn, provincie Letopočet 1, stát Oceánie", - "Vyprávění: v er-formě, po deníkových zápiscích Winstona Smithe", - NULL -}; - -static const char *const book_1984_n1[] = { - "Svět je rozdělen na tři supervelmoci: Oceánii, Eurasii a Východasii, které spolu vedou trvalou válku.", - "Vládne jediná strana (Angsoc) v čele s kultem Velkého bratra.", - "Ministerstvo pravdy – přepisuje historii a vyrábí „pravdu“.", - "Ministerstvo lásky – mučírny a likvidace nepohodlných.", - "Ministerstvo hojnosti – plánuje hospodářství a drží lidi v nedostatku.", - "Ministerstvo míru – vede válku.", - NULL -}; - -static const char *const book_1984_n2[] = { - "Winston Smith – hlavní hrdina, přepisuje historii, touží po svobodě.", - "Julie – mladá členka strany, Winstonova tajná láska.", - "O'Brien – člen vnitřní strany, předstírá odboj a Winstona zničí.", - "Emmanuel Goldstein – nepřítel státu, údajný vůdce Bratrstva.", - "Velký bratr – symbol všemocné moci strany.", - "Pan Charrington – zdánlivý obchodník, ve skutečnosti agent.", - NULL -}; - -static const char *const book_1984_n3[] = { - "Newspeak – uměle zjednodušovaný jazyk, který omezuje myšlení.", - "Dvojité myšlení – ochota věřit dvěma protikladným pravdám.", - "Zločin myšlení – už samotná zakázaná myšlenka.", - "Policie myšlení – tajná policie, která zatýká a mučí.", - "Bratrstvo – možná neexistující odbojová organizace.", - "Místnost 101 – nejhlubší mučírna, pro každého jeho největší strach.", - NULL -}; - -static const BookNoteSec book_1984_secs[] = { - {"O knize", book_1984_n0}, - {"Svět a strana", book_1984_n1}, - {"Postavy", book_1984_n2}, - {"Klíčové pojmy", book_1984_n3}, -}; - -static const char *const book_fahrenheit451_n0[] = { - "Autor: Ray Bradbury", - "Žánr: antiutopický (dystopický) sci-fi román", - "Poprvé vydáno: 1953", - "Děj/prostředí: anonymní americké město v blízké budoucnosti", - "Vyprávění/forma: er-forma, lyricky obrazný styl; český překlad Vítězslava Nezvala", - NULL -}; - -static const char *const book_fahrenheit451_n1[] = { - "Knihy jsou zakázané; hasiči pálí knihovny a domy, ne hasí požáry.", - "Lidé tráví čas u televizních „stěn“ a rychlých, prázdných pořadů.", - "Samostatné myšlení je podezřelé; společnost preferuje rychlou zábavu před hloubkou.", - "V pozadí hrozí válka; město působí sterilně a agresivně.", - "Odboj tvoří skrytí čtenáři a „pamatovači“, kteří uchovávají texty v paměti.", - "Román varuje před cenzurou, konformitou a odpoutáním od literatury.", - NULL -}; - -static const char *const book_fahrenheit451_n2[] = { - "Guy Montag – hasič, který přestane věřit systému pálení knih.", - "Clarisse McClellan – zvědavá dívka, probudí v Montagovi otázky.", - "Mildred Montagová – Guyova žena, závislá na televizi a prášcích.", - "Kapitán Beatty – šéf hasičů, vzdělaný obhájce ničení knih.", - "Profesor Faber – bývalý učitel, Montagův tajný rádce.", - "Granger – vůdce komunity pamatovačů literatury.", - NULL -}; - -static const char *const book_fahrenheit451_n3[] = { - "451 °F – symbol teploty hoření papíru a ničení knih.", - "Televizní stěny – náhrada skutečného života a dialogu.", - "Mechanický pes – technologie sledování a likvidace nepohodlných.", - "Oheň – nejdřív ničení, později i obnova (fénix).", - "Paměť – literatura přežívá v lidech, když zmizí knihy.", - "Svoboda myšlení – hlavní téma odporu proti režimu.", - NULL -}; - -static const BookNoteSec book_fahrenheit451_secs[] = { - {"O knize", book_fahrenheit451_n0}, - {"Doba a svět", book_fahrenheit451_n1}, - {"Postavy", book_fahrenheit451_n2}, - {"Klíčové pojmy a motivy", book_fahrenheit451_n3}, -}; - -static const char *const book_audience_n0[] = { - "Autor: Václav Havel", - "Žánr: drama (jednoaktovka, absurdní / groteskní)", - "Poprvé vydáno: 1975 (součást Vaněkovy trilogie)", - "Děj/prostředí: kancelář vedoucího skladu pivovaru", - "Vyprávění/forma: divadelní dialog, jedno dějství, jazyk moci vs. jazyk obyčejného člověka", - NULL -}; - -static const char *const book_audience_n1[] = { - "Dílo vzniklo v normalizačním období; metaforicky kritizuje totalitní společnost.", - "Hrdina Vaněk je bývalý spisovatel přeřazený na manuální práci.", - "Moc se projevuje v byrokracii, strachu a pokrytectví „nadřízených“.", - "Rozhovor není o práci, ale o testu loajality a ideologické poslušnosti.", - "Groteska: banální situace skrývá vážný tlak na svědomí jedince.", - "Havel rozvíjí téma „slov odpovědnosti“ a falešné ideologické fráze.", - NULL -}; - -static const char *const book_audience_n2[] = { - "Ferdinand Vaněk – bývalý spisovatel, dělník ve skladu pivovaru.", - "Vedoucí skladu (Šéf) – malý funkcionář toužící po kariéře, ideologicky nejistý.", - "Vaněkova manželka (zmíněna) – představuje tlak rodiny a strach ze ztráty výdělku.", - "Kolegové (nepřítomní) – symbol kolektivního dohledu.", - "Šéf jako typ – přizpůsobivý člověk, který opakuje fráze moci.", - "Vaněk jako typ disidenta – mlčí, ale nepodléhá.", - NULL -}; - -static const char *const book_audience_n3[] = { - "Audience – „audience u vedoucího“ = výslech, nátlak, pokus o spolupráci.", - "Hovory o pravdě – rozdíl mezi oficiální rétorikou a skutečným prožíváním.", - "Strach a kariéra – vedoucí se bojí, ale chce postup.", - "Práce vs. svědomí – Vaněk odmítá hrát ideologickou hru.", - "Groteska – vážné téma v banálním prostředí skladu.", - "Jazyk moci – prázdné fráze, které mají nahradit morální rozhodnutí.", - NULL -}; - -static const BookNoteSec book_audience_secs[] = { - {"O knize", book_audience_n0}, - {"Doba a svět", book_audience_n1}, - {"Postavy", book_audience_n2}, - {"Klíčové pojmy a motivy", book_audience_n3}, -}; - -static const char *const book_bajecna_leta_n0[] = { - "Autor: Michal Viewegh", - "Žánr: autobiograficky laděný humoristický román", - "Poprvé vydáno: 1992", - "Děj/prostředí: dětství a dospívání v 70.–80. letech v Československu", - "Vyprávění/forma: ich-forma, groteskní humor, koláž vzpomínek", - NULL -}; - -static const char *const book_bajecna_leta_n1[] = { - "Normalizace, šedivá všednost, ideologické fráze ve škole i doma.", - "Rodina střední třídy – tlak na slušnost, studium a „správné“ chování.", - "Kontrast mezi oficiální propagandou a soukromým životem.", - "Mladý hrdina objevuje sexualitu, alkohol, rockovou hudbu.", - "Společnost bez perspektivy, ale s černým humorem.", - "Typické vieweghovské sebeironické vyprávění.", - NULL -}; - -static const char *const book_bajecna_leta_n2[] = { - "Vypravěč / mladý Michal – pubertální hrdina, pozorovatel i aktér.", - "Rodiče – autoritativní otec, matka, generační střet.", - "Kamarádi a spolužáci – svět dospívání.", - "Učitelé – představitelé školní moci.", - "První lásky a holky – motív sebevědomí a trapasů.", - "Sousedé a příbuzní – groteskní epizody.", - NULL -}; - -static const char *const book_bajecna_leta_n3[] = { - "Autobiografický prvek – fikce vs. vzpomínka.", - "Humor a groteska – coping mechanismus éry.", - "Puberta – tělo, stud, touha být „cool“.", - "Ideologie vs. realita – škola, pionýr, fráze.", - "Rodina – láska, nátlak, generační rozdíly.", - "Název – „léta pod psa“ = chaotické období života.", - NULL -}; - -static const BookNoteSec book_bajecna_leta_secs[] = { - {"O knize", book_bajecna_leta_n0}, - {"Doba a svět", book_bajecna_leta_n1}, - {"Postavy", book_bajecna_leta_n2}, - {"Klíčové pojmy a motivy", book_bajecna_leta_n3}, -}; - -static const char *const book_bidnici_n0[] = { - "Autor: Victor Hugo", - "Žánr: historicko-společenský román (epický)", - "Poprvé vydáno: 1862", - "Děj/prostředí: Francie, především Paříž 19. století (restaurace, revoluce)", - "Vyprávění/forma: er-forma, mnoho dějových linií, historické vsuvky", - NULL -}; - -static const char *const book_bidnici_n1[] = { - "Společnost po Napoleonovi, chudoba, sociální nespravedlnost", - "Revoluční vlny (1832 – barikády v Paříži)", - "Církev, charity, ale i tvrdý úřad a policie", - "Téma milosrdenství vs. zákon", - "Paříž jako symbol metropole dobra i zla", - "Román o spáse duše a společenské změně", - NULL -}; - -static const char *const book_bidnici_n2[] = { - "Jean Valjean – bývalý galejník, který se polepší", - "Javert – policejní inspektor, zákon bez milosrdenství", - "Fantine – matka Cosette, oběť chudoby", - "Cosette – dívka, kterou Valjean vychovává", - "Marius – mladý revolucionář, Cosettin milenec", - "Thénardierovi – lakomí, krutí hostinští", - NULL -}; - -static const char *const book_bidnici_n3[] = { - "Milosrdenství biskupa Myrela – stříbrné svícny", - "Galeje a žlutý pas – stigma ex trestance", - "Barikády 1832 – revoluce mladých", - "Sewers / stoky – únik Marius a Valjean", - "Spravedlnost vs. zákon – Javertův kolaps", - "Láska a oběť – Fantine, Valjean, Marius", - NULL -}; - -static const BookNoteSec book_bidnici_secs[] = { - {"O knize", book_bidnici_n0}, - {"Doba a svět", book_bidnici_n1}, - {"Postavy", book_bidnici_n2}, - {"Klíčové pojmy a motivy", book_bidnici_n3}, -}; - -static const char *const book_bila_nemoc_n0[] = { - "Autor: Karel Čapek", - "Žánr: politické/allegorické drama", - "Poprvé vydáno: 1937", - "Děj/prostředí: fiktivní stát, epidemie neznámé nemoci", - "Vyprávění/forma: klasické drama, dialogy, satira i tragédie", - NULL -}; - -static const char *const book_bila_nemoc_n1[] = { - "Meziválečné napětí, hrozba fašismu a války", - "Epidemie „bílé nemoci“ – zabíjí hlavně mladé dospělé", - "Politici preferují zbrojení před léčbou", - "Společnost v strachu, hledá viníky", - "Allegorie: nemoc = morální a politická nakažlivost", - "Varování před válkou a lhostejností moci", - NULL -}; - -static const char *const book_bila_nemoc_n2[] = { - "Dr. Galén – lékař s lékem, idealista", - "Maršál – vůdce státu, touží po válce", - "Sigmund – obchodník se zbraněmi", - "Millionáři a politici – cynismus elity", - "Chudí pacienti – oběti systému", - "Galénův otec – vědec, odkaz léku", - NULL -}; - -static const char *const book_bila_nemoc_n3[] = { - "Bílá nemoc – neznámá epidemie, bílé skvrny na těle", - "Lék Galéna – funguje, ale není nasazen", - "Válka vs. léčba – priority moci", - "Allegorie fašismu – nakažlivá ideologie", - "Svědomí lékaře – služba lidem", - "Závěr – kolaps, varování nevyužito", - NULL -}; - -static const BookNoteSec book_bila_nemoc_secs[] = { - {"O knize", book_bila_nemoc_n0}, - {"Doba a svět", book_bila_nemoc_n1}, - {"Postavy", book_bila_nemoc_n2}, - {"Klíčové pojmy a motivy", book_bila_nemoc_n3}, -}; - -static const char *const book_bylo_nas_pet_n0[] = { - "Autor: Karel Poláček", - "Žánr: humoristický autobiograficky laděný román", - "Poprvé vydáno: 1926", - "Děj/prostředí: maloměsto / venkov, rodina pěti sourozenců", - "Vyprávění/forma: ich-forma (Jaromír), humorné epizody", - NULL -}; - -static const char *const book_bylo_nas_pet_n1[] = { - "První republika, idylické dětství s stínem chudoby", - "Rodina židovského původu – Poláček pracuje s humorem i identitou", - "Škola, hřiště, sousedé – uzavřený svět dětí", - "Generace rodičů vs. děti", - "Laskavý humor místo sentimentu", - "Typické poláčkovské groteskní situace", - NULL -}; - -static const char *const book_bylo_nas_pet_n2[] = { - "Jaromír – nejmladší, vypravěč", - "Sourozenci: Ondřej, Hela, Jindra, dále rodina", - "Rodiče – matka, otec, autorita i teplo domova", - "Učitelé, sousedé, kněz – venkovské typy", - "Kamarádi a spolužáci", - "Pes/circus epizody dle kapitol", - NULL -}; - -static const char *const book_bylo_nas_pet_n3[] = { - "Dětství – pohled dítěte na svět", - "Humor – i z chudoby a přísnosti", - "Rodina – pět dětí, sounáležitost", - "Maloměsto – komunita, klepy", - "Škola – strach, discipline, legrace", - "Poláčkův jazyk – hovorový, vtipný", - NULL -}; - -static const BookNoteSec book_bylo_nas_pet_secs[] = { - {"O knize", book_bylo_nas_pet_n0}, - {"Doba a svět", book_bylo_nas_pet_n1}, - {"Postavy", book_bylo_nas_pet_n2}, - {"Klíčové pojmy a motivy", book_bylo_nas_pet_n3}, -}; - -static const char *const book_cekani_na_godota_n0[] = { - "Autor: Samuel Beckett", - "Žánr: drama absurdní", - "Poprvé vydáno: 1952 (fr. En attendant Godot)", - "Děj/prostředí: neurčená krajina, strom, silnice", - "Vyprávění/forma: dialog dvou postav, minimální děj, český překlad Ouředník", - NULL -}; - -static const char *const book_cekani_na_godota_n1[] = { - "Poválečný existencialismus, ztráta smyslu", - "Absurdita života – čekání bez výsledku", - "Bez historického konkrétna – univerzální situace", - "Chudoba, triviální rozhovory, rutina", - "Godot nepřichází – nedosažitelná naděje", - "Vliv na divadlo 20. století", - NULL -}; - -static const char *const book_cekani_na_godota_n2[] = { - "Vladimír (Didi) – rozvážnější z dvojice", - "Estragon (Gogo) – fyzicky slabší, bolesti nohou", - "Pozzo – pán, vede na provaze Lucka", - "Lucky – nosič, „myslí“ v monologu", - "Chlapec – posel od Godota, Godot nepřijde", - "Godot – nikdy se neobjeví", - NULL -}; - -static const char *const book_cekani_na_godota_n3[] = { - "Čekání – metafora lidského stavu", - "Absurdita – opakování bez pointy", - "Strom – skromná krajina, listí v druhém dějství", - "Pomoc – Didi a Gogo si navzájem (boty, jídlo)", - "Čas – věty „najednou je večer“", - "Smysl života – otázka bez odpovědi", - NULL -}; - -static const BookNoteSec book_cekani_na_godota_secs[] = { - {"O knize", book_cekani_na_godota_n0}, - {"Doba a svět", book_cekani_na_godota_n1}, - {"Postavy", book_cekani_na_godota_n2}, - {"Klíčové pojmy a motivy", book_cekani_na_godota_n3}, -}; - -static const char *const book_ceske_nebe_n0[] = { - "Autoři: Zdeněk Svěrák, Ladislav Smoljak", - "Žánr: komické drama / fraška", - "Poprvé vydáno: 1976 (Divadlo Jára Cimrmana)", - "Děj/prostředí: parodické dějiny českého nebe", - "Vyprávění/forma: divadelní scény, humor, pastiše", - NULL -}; - -static const char *const book_ceske_nebe_n1[] = { - "Normalizace – ne přímá politika, ale metafora", - "„Nebe“ jako symbol vlasti / duchovního prostoru", - "Groteskní historie od pradávna po modernu", - "Cimrmanovský styl – pseudovědecký humor", - "Satira na národní mýty a malost", - "Spolupráce Svěrák–Smoljak", - NULL -}; - -static const char *const book_ceske_nebe_n2[] = { - "Jára Cimrman – „největší Čech“, v této hře v roli vypravěče/historika", - "Různí historičtí komici typy", - "Postavy z parodovaných dějin", - "Ensemble divadla", - "Vědci a vynálezci groteskně", - "Kolektivní humor bez jednoho hrdiny", - NULL -}; - -static const char *const book_ceske_nebe_n3[] = { - "Parodie dějin – české nebe jako téma", - "Cimrman – fiktivní génius", - "Národní identita s nadsázkou", - "Divadelní fraška – rychlé gagy", - "Smoljak/Svěrák dialog", - "Nebe vs. realita země", - NULL -}; - -static const BookNoteSec book_ceske_nebe_secs[] = { - {"O knize", book_ceske_nebe_n0}, - {"Doba a svět", book_ceske_nebe_n1}, - {"Postavy", book_ceske_nebe_n2}, - {"Klíčové pojmy a motivy", book_ceske_nebe_n3}, -}; - -static const char *const book_dekameron_n0[] = { - "Autor: Giovanni Boccaccio", - "Žánr: próza – sbírka novel (100 příběhů)", - "Poprvé vydáno: kolem 1350", - "Děj/prostředí: Florencie, morová rána, venkovský únik", - "Vyprávění/forma: rámcový příběh + jednotlivé novely, překlad Krátký", - NULL -}; - -static const char *const book_dekameron_n1[] = { - "Itálie 14. století, mor, společenská krize", - "Deset mládenců a mladenek odchází na venkov", - "Deset dní – každý den deset novel (100)", - "Světskost, humor, láska, lstivost", - "Kritika církve a měšťanů", - "Humanismus rané renesance", - NULL -}; - -static const char *const book_dekameron_n2[] = { - "Pampinea, Fiammetta, Filostrato aj. – vypravěči", - "Deset postav v rámcovém příběhu", - "Hrdinové jednotlivých novel – měšťané, kněží, milenci", - "Často chytré ženy a podvodníci", - "Rámcový narrátor kolektiv", - "Typy středověké společnosti", - NULL -}; - -static const char *const book_dekameron_n3[] = { - "Rámec – únik před morem", - "100 novel – rozmanitost života", - "Láska a erotika (místy provokativní)", - "Rozum a lest – přechytračení", - "Fortuna – štěstí/neštěstí", - "Renesanční světskost", - NULL -}; - -static const BookNoteSec book_dekameron_secs[] = { - {"O knize", book_dekameron_n0}, - {"Doba a svět", book_dekameron_n1}, - {"Postavy", book_dekameron_n2}, - {"Klíčové pojmy a motivy", book_dekameron_n3}, -}; - -static const char *const book_den_trifidu_n0[] = { - "Autor: John Wyndham", - "Žánr: postapokalyptický sci-fi román", - "Poprvé vydáno: 1951", - "Děj/prostředí: Británie po katastrofě, rostliny trifidy", - "Vyprávění/forma: er-forma, Bill Masen vypravěč; překlad Kořán", - NULL -}; - -static const char *const book_den_trifidu_n1[] = { - "Meteoritní roj oslepí většinu lidí", - "Trifidy – mobilní rostliny zabíjí slepé", - "Kolaps civilizace, boj o přežití", - "Malé komunity vs. chaos", - "Vědecké vysvětlení vs. nábožný strach", - "Otázka adaptace lidstva", - NULL -}; - -static const char *const book_den_trifidu_n2[] = { - "Bill Masen – biolog, přežije se zavázanýma očima", - "Josella – spisovatelka, partnerka", - "Coker – realista, organizátor", - "Colonel Jacques – vojenský vůdce", - "Děti a uprchlici", - "Trifidy jako „protivník“", - NULL -}; - -static const char *const book_den_trifidu_n3[] = { - "Trifidy – jedovaté lana, pohybují se", - "Slepota – masová katastrofa", - "Ostrov – únik a nový začátek", - "Sebeobrana a morálka", - "Sci-fi realismus Wyndhama", - "Příroda pomstychtivá", - NULL -}; - -static const BookNoteSec book_den_trifidu_secs[] = { - {"O knize", book_den_trifidu_n0}, - {"Doba a svět", book_den_trifidu_n1}, - {"Postavy", book_den_trifidu_n2}, - {"Klíčové pojmy a motivy", book_den_trifidu_n3}, -}; - -static const char *const book_denik_anny_frankove_n0[] = { - "Autor: Anne Franková", - "Žánr: deníková próza (memoáry)", - "Poprvé vydáno: 1947 (NL)", - "Děj/prostředí: Amsterdam, úkryt „Achterhuis“ 1942–1944", - "Vyprávění/forma: ich-forma deníkových záznamů", - NULL -}; - -static const char *const book_denik_anny_frankove_n1[] = { - "Nacistická okupace, pronásledování Židů", - "Rodina Frankových v tajném bytě", - "Deník jako únik a svědectví", - "Strach z prozrazení, nejistota", - "Růst dospívající Anny", - "Tragický osud po odhalení", - NULL -}; - -static const char *const book_denik_anny_frankove_n2[] = { - "Anne Franková – autorka, dospívající dívka", - "Otto Frank – otec", - "Edith Frank – matka", - "Margot – sestra", - "Van Pels/Daans – spoluúkrytí", - "Miep Gies – pomocnice", - NULL -}; - -static const char *const book_denik_anny_frankove_n3[] = { - "Holocaust – genocida", - "Úkryt – izolace", - "Deník Kitty – adresát", - "Dospívání v extremu", - "Naděje vs. realita", - "Svědectví historie", - NULL -}; - -static const BookNoteSec book_denik_anny_frankove_secs[] = { - {"O knize", book_denik_anny_frankove_n0}, - {"Doba a svět", book_denik_anny_frankove_n1}, - {"Postavy", book_denik_anny_frankove_n2}, - {"Klíčové pojmy a motivy", book_denik_anny_frankove_n3}, -}; - -static const char *const book_jekyll_hyde_n0[] = { - "Autor: Robert Louis Stevenson", - "Žánr: hororová / psychologická novela", - "Poprvé vydáno: 1886", - "Děj/prostředí: Londýn, viktoriánská Anglie", - "Vyprávění/forma: er-forma, právník Utterson jako rámcový pozorovatel; překlad Kořán", - NULL -}; - -static const char *const book_jekyll_hyde_n1[] = { - "Viktoriánská moralita a pokrytectví", - "Rozdělená osobnost – věda vs. etika", - "Londýn mlhový, noční násilí", - "Právo a pověst společnosti", - "Lekce o nezkrotné touze", - "Gotický horor", - NULL -}; - -static const char *const book_jekyll_hyde_n2[] = { - "Dr. Henry Jekyll – uznávaný vědec", - "Mr. Edward Hyde – ztělesnění zla a touhy", - "Gabriel John Utterson – advokát, vyšetřuje", - "Dr. Hastie Lanyon – kolega, šok z pravdy", - "Poole – sluha Jekyllův", - "Sir Danvers Carew – oběť Hyde", - NULL -}; - -static const char *const book_jekyll_hyde_n3[] = { - "Lekce / sérum – proměna", - "Dvojí identita – dobro vs. zlo", - "Hyde – menší, primitivní, násilný", - "Uttersonův výslech – detektivní linie", - "Dopisy Lanyon a Jekyll – vysvětlení", - "Sebedestrukce Jekylla", - NULL -}; - -static const BookNoteSec book_jekyll_hyde_secs[] = { - {"O knize", book_jekyll_hyde_n0}, - {"Doba a svět", book_jekyll_hyde_n1}, - {"Postavy", book_jekyll_hyde_n2}, - {"Klíčové pojmy a motivy", book_jekyll_hyde_n3}, -}; - -static const char *const book_edison_n0[] = { - "Autor: Vítězslav Nezval", - "Žánr: poetická skladba / poema", - "Poprvé vydáno: 1927", - "Děj/prostředí: poetický portrét vynálezce T. A. Edisona", - "Vyprávění/forma: volná skladba, obrazná moderní poezie", - NULL -}; - -static const char *const book_edison_n1[] = { - "Poetismus – hravost, obrazy, město", - "Obdiv k technice a modernitě", - "Edison jako symbol vynálezce", - "USA / industrializace v obrazu", - "Surreální a groteskní prvky", - "Skupina Devětsil", - NULL -}; - -static const char *const book_edison_n2[] = { - "Thomas Alva Edison – střed básně", - "Objevitel jako mýtus", - "Nezvalův lyrický subjekt", - "Technika personifikovaná", - "Dělníci a laboratoř", - "Kolektivní obraz doby", - NULL -}; - -static const char *const book_edison_n3[] = { - "Poetismus – Nezval", - "Světlo – žárovka, symbol", - "Vynález – kreativita", - "Moderní civilizace", - "Hra s jazykem a obrazy", - "Oslava i ironie techniky", - NULL -}; - -static const BookNoteSec book_edison_secs[] = { - {"O knize", book_edison_n0}, - {"Doba a svět", book_edison_n1}, - {"Postavy", book_edison_n2}, - {"Klíčové pojmy a motivy", book_edison_n3}, -}; - -static const char *const book_farma_zvirat_n0[] = { - "Autor: George Orwell", - "Žánr: alegorická antiutopická novela", - "Poprvé vydáno: 1945", - "Děj/prostředí: farma Manor, zvířecí revoluce", - "Vyprávění/forma: er-forma, alegorie na SSSR; překlad Gössell", - NULL -}; - -static const char *const book_farma_zvirat_n1[] = { - "Vzpoura proti panu Jonesovi", - "Pravidla Animalismu", - "Postupná moc prasat", - "Propaganda Squealer", - "Pracovní útlak ostatních", - "Proměna v totalitu", - NULL -}; - -static const char *const book_farma_zvirat_n2[] = { - "Napoleon – prase, diktátor", - "Snowball – prase, rival", - "Boxer – kůň, „I will work harder“", - "Squealer – prase, propaganda", - "Old Major – prase, vize revoluce", - "Benjamin – osel, skeptic", - NULL -}; - -static const char *const book_farma_zvirat_n3[] = { - "Alegorie – revoluce 1917", - "Pravidla sedm – mění se", - "„Všichni zvířata rovna“", - "Chytrá prasata vs. dělníci", - "Boxer – oběť systému", - "Lidská tvář prasat", - NULL -}; - -static const BookNoteSec book_farma_zvirat_secs[] = { - {"O knize", book_farma_zvirat_n0}, - {"Doba a svět", book_farma_zvirat_n1}, - {"Postavy", book_farma_zvirat_n2}, - {"Klíčové pojmy a motivy", book_farma_zvirat_n3}, -}; - -static const char *const book_gulliverovy_cesty_n0[] = { - "Autor: Jonathan Swift", - "Žánr: satirická novela / cestopis", - "Poprvé vydáno: 1726", - "Děj/prostředí: čtyři cesty Gullivera do fantastických zemí", - "Vyprávění/forma: ich-forma Gulliver; překlad Skoumal", - NULL -}; - -static const char *const book_gulliverovy_cesty_n1[] = { - "Anglie 18. století, osvícenství", - "Satira na politiku, vědu, válku", - "Lilliput – malí, politika", - "Brobdingnag – obři, perspektiva", - "Laputa – věda odtržená", - "Houyhnhnmové – koně rozumní", - NULL -}; - -static const char *const book_gulliverovy_cesty_n2[] = { - "Lemuel Gulliver – cestovatel, vypravěč", - "Lilliputié – malí lidé", - "Brobdingnaci – obři", - "Houyhnhnmové a Yahoové", - "Král Brobdingnagu", - "Kapitán a rodina Gulliver", - NULL -}; - -static const char *const book_gulliverovy_cesty_n3[] = { - "Satira – nadsázka společnosti", - "Relativita velikosti", - "Válka o vejce (Lilliput)", - "Rozum vs. bestialita (Yahoo)", - "Cestopis jako forma", - "Swiftova kritika Evropy", - NULL -}; - -static const BookNoteSec book_gulliverovy_cesty_secs[] = { - {"O knize", book_gulliverovy_cesty_n0}, - {"Doba a svět", book_gulliverovy_cesty_n1}, - {"Postavy", book_gulliverovy_cesty_n2}, - {"Klíčové pojmy a motivy", book_gulliverovy_cesty_n3}, -}; - -static const char *const book_hamlet_n0[] = { - "Autor: William Shakespeare", - "Žánr: tragédie (drama)", - "Poprvé vydáno: kolem 1601", - "Děj/prostředí: dánský hrad Elsinore", - "Vyprávění/forma: divadelní hra, blankvers; překlad Nevrla", - NULL -}; - -static const char *const book_hamlet_n1[] = { - "Předstírané šílenství, intriky", - "Duch krále, pomsta", - "Politika Claudius, Gertrude", - "Filosofické monology", - "Smrt a morálka", - "Renesanční individualismus", - NULL -}; - -static const char *const book_hamlet_n2[] = { - "Hamlet – princ, pomstychtivý", - "Claudius – strýc, vrah krále", - "Gertrude – matka", - "Polonius – rádce", - "Ophelia – dcera Polonia", - "Horatio – Hamletův přítel", - NULL -}; - -static const char *const book_hamlet_n3[] = { - "„Být či nebýt“", - "Duch otce", - "Předstírané šílenství", - "Pomsta a odklad", - "Opeliina smrt", - "Finále – duel, jed, smrt", - NULL -}; - -static const BookNoteSec book_hamlet_secs[] = { - {"O knize", book_hamlet_n0}, - {"Doba a svět", book_hamlet_n1}, - {"Postavy", book_hamlet_n2}, - {"Klíčové pojmy a motivy", book_hamlet_n3}, -}; - -static const char *const book_havran_n0[] = { - "Autor: Edgar Allan Poe", - "Žánr: balada / lyricko-epická báseň", - "Poprvé vydáno: 1845", - "Děj/prostředí: půlnoční komnata, mluvčí a havran", - "Vyprávění/forma: ich-forma, rým, refrain „Nevermore“", - NULL -}; - -static const char *const book_havran_n1[] = { - "Gotická atmosféra, tma, prosinec", - "Smrt milované Lenore", - "Mystický havran na bustě Pallas", - "Psychický rozpad vypravěče", - "Symbolika noční můry", - "Americká romantika", - NULL -}; - -static const char *const book_havran_n2[] = { - "Vypravěč – sám, truchlící", - "Havran – mluví jediné slovo", - "Lenore – mrtvá milovaná (zmínka)", - "Pallas – busta bohyně", - "Anděl / démon symbolicky", - "Nepřítomní hosté", - NULL -}; - -static const char *const book_havran_n3[] = { - "Nevermore – refrén beznaděje", - "Havran – paměť, zlo", - "Lenore – ztracená láska", - "Půlnoc – hranice života/smrti", - "Gotický interiér", - "Opakující se struktura strof", - NULL -}; - -static const BookNoteSec book_havran_secs[] = { - {"O knize", book_havran_n0}, - {"Doba a svět", book_havran_n1}, - {"Postavy", book_havran_n2}, - {"Klíčové pojmy a motivy", book_havran_n3}, -}; - -static const char *const book_hladove_hry_n0[] = { - "Autor: Suzanne Collins", - "Žánr: dystopický young adult román", - "Poprvé vydáno: 2008 (I. Aréna smrti)", - "Děj/prostředí: Panem, Kapitol, aréna", - "Vyprávění/forma: ich-forma Katniss; překlad Dušek", - NULL -}; - -static const char *const book_hladove_hry_n1[] = { - "Postapokalyptický stát Panem", - "Kapitol vládne 12 okresům", - "Hladové hry – televizní boj na smrt", - "Chudoba okresů vs. luxus Kapitolu", - "Rebelii potlačují", - "Survival a mediální show", - NULL -}; - -static const char *const book_hladove_hry_n2[] = { - "Katniss Everdeen – vypravěčka, lovkyně", - "Peeta Mellark – spoluhráč z Pece", - "Gale – přítel z Distraktu 12", - "Haymitch – vítěz, mentor", - "Effie Trinket – escort", - "Cinna – stylista", - NULL -}; - -static const char *const book_hladove_hry_n3[] = { - "Aréna – bojiště", - "Sponzoři – pomoc diváků", - "Předstíraná láska", - "Mockingjay symbol", - "Tribut – tributář", - "Odpor proti Kapitolu", - NULL -}; - -static const BookNoteSec book_hladove_hry_secs[] = { - {"O knize", book_hladove_hry_n0}, - {"Doba a svět", book_hladove_hry_n1}, - {"Postavy", book_hladove_hry_n2}, - {"Klíčové pojmy a motivy", book_hladove_hry_n3}, -}; - -static const char *const book_hlava_xxii_n0[] = { - "Autor: Joseph Heller", - "Žánr: anti válečný / absurdní román", - "Poprvé vydáno: 1961", - "Děj/prostředí: WWII, letecká základna Pianosa", - "Vyprávění/forma: er-forma, nelineární, ironie; překlad Jindra", - NULL -}; - -static const char *const book_hlava_xxii_n1[] = { - "Druhá světová válka – absurdita", - "Byrokracie armády", - "Opakující se nálety", - "Catch-22 logická past", - "Smrt Yossarianových přátel", - "Touha desertovat", - NULL -}; - -static const char *const book_hlava_xxii_n2[] = { - "Yossarian – bombardér, chce přežít", - "Colonel Cathcart – eskaluje nálety", - "Milieu Minderbinder – obchodník M&M", - "Doc Daneeka – „mrtvý“ doktor", - "Nately – mladý pilot", - "Snowden – smrt v letadle", - NULL -}; - -static const char *const book_hlava_xxii_n3[] = { - "Catch-22 – past pravidel", - "Absurdita války", - "Obchod s válkou (M&M)", - "Snowden „Au chaud“", - "Přežít vs. povinnost", - "Černý humor", - NULL -}; - -static const BookNoteSec book_hlava_xxii_secs[] = { - {"O knize", book_hlava_xxii_n0}, - {"Doba a svět", book_hlava_xxii_n1}, - {"Postavy", book_hlava_xxii_n2}, - {"Klíčové pojmy a motivy", book_hlava_xxii_n3}, -}; - -static const char *const book_chram_matky_bozi_n0[] = { - "Autor: Victor Hugo", - "Žánr: historicko-romantický román", - "Poprvé vydáno: 1831", - "Děj/prostředí: Paříž 15. století, katedrála Notre-Dame", - "Vyprávění/forma: er-forma, historické vsuvky; překlad Tomášková", - NULL -}; - -static const char *const book_chram_matky_bozi_n1[] = { - "Středověk, lidová slavnost i násilí", - "Církev a městská moc", - "Outsideri společnosti", - "Architektura jako hrdina", - "Láska, žárlivost, osud", - "Romantismus 19. st. pohled na minulost", - NULL -}; - -static const char *const book_chram_matky_bozi_n2[] = { - "Quasimodo – zvoník, hrbáč", - "Esmeralda – cikánská tanečnice", - "Claude Frollo – arciděkan, posedlost", - "Phoebus – kapitán, svůdník", - "Gringoire – básník", - "Jehan Frollo – bratr Claude", - NULL -}; - -static const char *const book_chram_matky_bozi_n3[] = { - "Katedrála – symbol dobra a útočiště", - "Quasimodo – vnější ošklivost, vnitřní dobro", - "Esmeralda – oběť předsudků", - "Frollo – posedlost a zlo", - "Soud a poprava", - "Gotická architektura", - NULL -}; - -static const BookNoteSec book_chram_matky_bozi_secs[] = { - {"O knize", book_chram_matky_bozi_n0}, - {"Doba a svět", book_chram_matky_bozi_n1}, - {"Postavy", book_chram_matky_bozi_n2}, - {"Klíčové pojmy a motivy", book_chram_matky_bozi_n3}, -}; - -static const char *const book_jak_jsem_vyhral_valku_n0[] = { - "Autor: Patrick Ryan (1925–1989), irský spisovatel", - "Žánr: satirický válečný román, černá komedie", - "Poprvé vydáno: 1963", - "Děj / prostředí: 2. světová válka, britská armáda (Evropa, severní Afrika)", - "Vyprávění / forma: ich-forma, vypravěč poručík Ernest Goodbody", - NULL -}; - -static const char *const book_jak_jsem_vyhral_valku_n1[] = { - "Román paroduje válečné memoáry a heroické mýty o druhé světové válce.", - "Goodbody věří v řád, čest a smysl války; realita je chaos a absurdita.", - "Jednotka plní nesmyslné rozkazy, trpí nekompetencí velení i vlastní naivitou.", - "Satira míří na vojenskou hierarchii, byrokracii a propagandistický jazyk.", - "Film Mikea Nicholse (1967) s Johnem Lennonem dílo zpopularizoval.", - "Tón je ironický: čtenář vidí pravdu, kterou vypravěč nechápe.", - NULL -}; - -static const char *const book_jak_jsem_vyhral_valku_n2[] = { - "Ernest Goodbody – naivní poručík, vypravěč, přesvědčen, že válku „vyhrál“.", - "Clapper – cynický seržant, praktický protiklad Goodbodyho idealismu.", - "Spool, Dooley, další vojáci – absurdní situace fronty a týlu.", - "Nadřízení důstojníci – často neschopní, kariérističtí nebo groteskní.", - "Goodbody jako antihrdina – „vítěz“ bez schopností i sebeironie.", - NULL -}; - -static const char *const book_jak_jsem_vyhral_valku_n3[] = { - "Satira války – výsměch slavnostním válečným příběhům.", - "Nespolehlivý vypravěč – Goodbody popisuje realitu zkresleně.", - "Černý humor – smrt a tragédie podány s nadhledem.", - "Absurdita rozkazů – vojenský systém funguje proti logice.", - "Ironie titulu – válku nikdo nevyhrál, natož Goodbody.", - "Antimilitarismus – skryté poselství proti glorifikaci války.", - NULL -}; - -static const BookNoteSec book_jak_jsem_vyhral_valku_secs[] = { - {"O knize", book_jak_jsem_vyhral_valku_n0}, - {"Doba a svět", book_jak_jsem_vyhral_valku_n1}, - {"Postavy", book_jak_jsem_vyhral_valku_n2}, - {"Klíčové pojmy", book_jak_jsem_vyhral_valku_n3}, -}; - -static const char *const book_jana_eyrova_n0[] = { - "Autor: Charlotte Brontëová (1816–1855), anglická spisovatelka", - "Žánr: romantický / viktoriánský román, bildungsroman", - "Poprvé vydáno: 1847", - "Děj / prostředí: Anglie 19. století (sirotčinec, Thornfield, močály)", - "Vyprávění / forma: ich-forma, retrospektivní vyprávění Jane Eyreové", - NULL -}; - -static const char *const book_jana_eyrova_n1[] = { - "Viktoriánská společnost: rigidní třídní a genderové normy, náboženská morálka.", - "Jane jako sirotek a guvernantka stojí na okraji společnosti bez majetku.", - "Román spojuje milostný příběh s otázkami svobody, důstojnosti a integrity.", - "Gotické prvky: Thornfield, tajemné zvuky, požár, temná minulost Rochesterova.", - "Brontëová kritizuje pokrytectví „slušné“ společnosti a útlak žen.", - "Happy end je podmíněn morální rovnováhou, ne jen vášní.", - NULL -}; - -static const char *const book_jana_eyrova_n2[] = { - "Jane Eyre – sirotka, guvernantka, hledá lásku i nezávislost.", - "Edward Rochester – majitel Thornfieldu, komplikovaná minulost, manželství s Berthou.", - "Bertha Mason – „bláznivá“ manželka v ústraní, gotický symbol útlaku.", - "St. John Rivers – chladný duchovní, nabízí Jane sňatek bez lásky.", - "Helen Burns, paní Reed, Bessie – dětství v Gateshead a Lowood.", - "Adèle – Rochesterova chráněnka, důvod Janeina pobytu v Thornfieldu.", - NULL -}; - -static const char *const book_jana_eyrova_n3[] = { - "Bildungsroman – dospívání a formování charakteru Jane.", - "Gotický román – tajemno Thornfieldu a Bertha Masonové.", - "Svoboda a rovnost – Jane odmítá být Rochesterovou milenkou.", - "Náboženská morálka – kontrast Heleniny pokory a Janeiny vůle.", - "Sociální třída – guvernantka mezi služkami a pány.", - "Požár Thornfieldu – katarsis a nový začátek vztahu.", - NULL -}; - -static const BookNoteSec book_jana_eyrova_secs[] = { - {"O knize", book_jana_eyrova_n0}, - {"Doba a svět", book_jana_eyrova_n1}, - {"Postavy", book_jana_eyrova_n2}, - {"Klíčové pojmy", book_jana_eyrova_n3}, -}; - -static const char *const book_ivan_denisovic_n0[] = { - "Autor: Alexandr Solovjov (Solženicyn), 1918–2008", - "Žánr: realistická próza, gulagovská novela", - "Poprvé vydáno: 1962 (časopis Nový svět)", - "Děj / prostředí: Sibiř, tábor SHIZ-84, leden 1951", - "Vyprávění / forma: er-forma, chronika jednoho dne vězně", - NULL -}; - -static const char *const book_ivan_denisovic_n1[] = { - "Stalinismus: trest za drobné „zločiny“, systém gulagů a nútěné práce.", - "Den vězně je řízen rozkazem, kamerou strachu a bojem o přežití.", - "Tábor není místo mučení popsaného naturalisticky, ale každodenní útlak.", - "Solidarita, lstivost i malé vítězství (jídlo, teplo) mají obrovskou cenu.", - "Novela otevřela v SSSR diskusi o gulagu; autor později dostal Nobelovu cenu.", - "Titulní hrdina je „obyčejný“ Rus, ne hrdina ideologie.", - NULL -}; - -static const char *const book_ivan_denisovic_n2[] = { - "Ivan Denisovič Šuchov – dělník, trest 10 let, zkušený táborový vězeň.", - "Tiurin – velitel brigády, tvrdý, ale brání svou partu.", - "Fetiukov – vězeň, který se plazí před mocí, končí v kobce.", - "Buynovsky – bývalý námořní důstojník, idealista, bitý dozorci.", - "Alyoška – baptistický vězeň, víra a pokora.", - "Der – dozorce, symbol bezcitné moci tábora.", - NULL -}; - -static const char *const book_ivan_denisovic_n3[] = { - "Gulag – systém sovětských pracovních táborů.", - "Jeden den – forma zdůrazňující monotónnost i tíhu času.", - "Brigáda – skupina vězňů, základ přežití a solidarity.", - "Kobka – trestová cela, hrozba pro každého.", - "Dignita v nouzi – Šuchov si zachovává lidskost v detailech.", - "Alyoškova víra – kontrast k ateistické moci i k pragmatismu.", - NULL -}; - -static const BookNoteSec book_ivan_denisovic_secs[] = { - {"O knize", book_ivan_denisovic_n0}, - {"Doba a svět", book_ivan_denisovic_n1}, - {"Postavy", book_ivan_denisovic_n2}, - {"Klíčové pojmy", book_ivan_denisovic_n3}, -}; - -static const char *const book_jmeno_ruze_n0[] = { - "Autor: Umberto Eco (1932–2016), italský sémiotik a spisovatel", - "Žánr: historická detektivka, postmoderní román", - "Poprvé vydáno: 1980 (Il nome della rosa)", - "Děj / prostředí: benediktinský klášter v severní Itálii, rok 1327", - "Vyprávění / forma: vzpomínka mnicha Adsona z Melku, er-forma", - NULL -}; - -static const char *const book_jmeno_ruze_n1[] = { - "Středověk: spor o chudobu (františkáni vs. papežský dvůr), inkvizice.", - "Klášter jako uzavřený svět knih, moci, tajemství a vražd.", - "Labyrint knihovny symbolizuje nebezpečí zakázaného vědění.", - "Eco kombinuje detektivku s filosofií, teologií a historií.", - "Film Jean-Jacques Annauda (1986) se Seanem Connerym.", - "Titulní růže – nejasný symbol krásy, tajemství a smrti.", - NULL -}; - -static const char *const book_jmeno_ruze_n2[] = { - "William z Baskervillu – františkán, logik, vzor Sherlocka Holmese.", - "Adso z Melku – mladý benediktin, vypravěč, Williamův učedník.", - "Jorge z Burgosu – slepý mnich, fanatik proti smíchu a heretickým knihám.", - "Opat Abo – vůdce kláštera, skrývá politické intriky.", - "Salvatore a Remigio – postavy zločinu a minulosti heresie.", - "Dívka z vesnice – Adsova krátká láska, symbol světa mimo klášter.", - NULL -}; - -static const char *const book_jmeno_ruze_n3[] = { - "Detektivní pátrání – série vražd kolem knihovny.", - "Labyrint knihovny – geometrie tajemství a moci.", - "Smích – Jorge považuje komedii Aristotelovu za nebezpečnou.", - "Heretické spisy – boj o to, co smí být čteno.", - "Sémiotika – Eco pracuje se znameními a výklady.", - "Požár kláštera – zničení knih i pravdy.", - NULL -}; - -static const BookNoteSec book_jmeno_ruze_secs[] = { - {"O knize", book_jmeno_ruze_n0}, - {"Doba a svět", book_jmeno_ruze_n1}, - {"Postavy", book_jmeno_ruze_n2}, - {"Klíčové pojmy", book_jmeno_ruze_n3}, -}; - -static const char *const book_kalibuv_zlocin_n0[] = { - "Autor: Karel Václav Rais (1857–1926), český realista", - "Žánr: venkovský realistický román, tragédie", - "Poprvé vydáno: 1892", - "Děj / prostředí: podkrkonošská vesnice, chalupa Kalibů", - "Vyprávění / forma: er-forma, psychologický realismus", - NULL -}; - -static const char *const book_kalibuv_zlocin_n1[] = { - "Konec 19. století: tvrdý venkovský život, majetek a rodinné vazby.", - "Chalupa je centrem konfliktu mezi Kalibou, druhou ženou a synem.", - "Rais zobrazuje venkov bez idealizace – chudoba, sobectví, tlak okolí.", - "Tragédie vyrůstá z postupného útlaku Frantíka a slabosti otce.", - "Motiv macechy Karly je klasický, ale zasazený do českého prostředí.", - "Zločin otce je vyústění dlouholetého napětí, ne náhlý impulz bez příčiny.", - NULL -}; - -static const char *const book_kalibuv_zlocin_n2[] = { - "Vojtěch Kaliba – slabý hospodář, dobrácký, ale neschopný bránit syna.", - "Karla – druhá manželka, panovačná, týrá Frantíka, chce mít moc v domě.", - "Frantík – syn z prvního manželství, oběť macechy, touží po spravedlnosti.", - "Babka – Kalibova matka, chrání vnuka před Karlou.", - "Vesnice – svědek rodinného konfliktu a morálního soudku.", - NULL -}; - -static const char *const book_kalibuv_zlocin_n3[] = { - "Realismus – věrný obraz venkova a psychologie.", - "Macecha – Karla jako zdroj útlaku.", - "Majetek a chalupa – ekonomický základ rodinného sporu.", - "Generační konflikt – babička, otec, syn proti Karlě.", - "Zločin z bezmoci – Kaliba ubije Frantíka v afektu.", - "Tragédie – nevyhnutelný pád rodiny.", - NULL -}; - -static const BookNoteSec book_kalibuv_zlocin_secs[] = { - {"O knize", book_kalibuv_zlocin_n0}, - {"Doba a svět", book_kalibuv_zlocin_n1}, - {"Postavy", book_kalibuv_zlocin_n2}, - {"Klíčové pojmy", book_kalibuv_zlocin_n3}, -}; - -static const char *const book_kniska_karla_kryla_n0[] = { - "Autor: Karel Kryl (1944–1994), písničkář a básník", - "Žánr: protestní poezie, autorská píseň, sbírka textů", - "Poprvé vydáno: 1972 (exil; texty z přelomu 60./70. let)", - "Děj / prostředí: Československo po srpnu 1968, normalizace, emigrace", - "Vyprávění / forma: lyrické básně a písně, metafora, ironie, refrén", - NULL -}; - -static const char *const book_kniska_karla_kryla_n1[] = { - "Po okupaci vojsky Varšavské smlouvy následuje normalizace a cenzura.", - "Kryl emigruje; písně kolují jako samizdat a symbol odporu.", - "Kníška sbírá texty propojující poezii s protest songem.", - "Motivy: svoboda, zrada, pokrytectví moci, vina mlčení.", - "Jazyk je úderný, obrazný, s biblickými a pohádkovými narážkami.", - "Dílo patří k pilířům české protestní kultury 20. století.", - NULL -}; - -static const char *const book_kniska_karla_kryla_n2[] = { - "Básnický subjekt – hlas svědka a moralisty proti moci.", - "Bratříčku (Bratříčku, zavírej vrátka) – oslovení národa, varování.", - "Král a blázen – alegorie moci a pravdy (např. píseň Král a klaun).", - "Anděl / ďábel – dobro a zlo v politice i v člověku.", - "Emigrant – ztráta domova, vina vyhnanství.", - "Dav mlčících – kolektivní strach a kompromis.", - NULL -}; - -static const char *const book_kniska_karla_kryla_n3[] = { - "Protest song – píseň jako nástroj odporu.", - "Alegorie – skryté politické významy v obrazech.", - "Normalizace – doba po 1968, proti ní Kryl brojí.", - "Emigrace – ztráta domova i možnosti mluvit doma.", - "Ironie – rozbití oficiální rétoriky.", - "Morální odpovědnost – kdo mlčí, také nese vinu.", - NULL -}; - -static const BookNoteSec book_kniska_karla_kryla_secs[] = { - {"O knize", book_kniska_karla_kryla_n0}, - {"Doba a svět", book_kniska_karla_kryla_n1}, - {"Postavy", book_kniska_karla_kryla_n2}, - {"Klíčové pojmy", book_kniska_karla_kryla_n3}, -}; - -static const char *const book_komu_zvoni_hrana_n0[] = { - "Autor: Ernest Hemingway (1899–1961), americký spisovatel", - "Žánr: válečný román, moderní próza", - "Poprvé vydáno: 1940", - "Děj / prostředí: španělská občanská válka 1937, hora Guadarrama", - "Vyprávění / forma: er-forma, střídmý „hemingwayovský“ styl", - NULL -}; - -static const char *const book_komu_zvoni_hrana_n1[] = { - "Občanská válka: republikáni vs. frankisté, mezinárodní brigády.", - "Robert Jordan je americký dobrovolník na straně republiky.", - "Úkol: odpálit most a zdržet fašistický postup.", - "Hora, jeskyně, partizáni – intimní svět uprostřed kruté války.", - "Titul cituje Donne: „Nikdo není sám o sobě ostrov… proto komu zvoní hrana, zvoní i tobě.“", - "Láska k Marii a smysl smrti v boji za svobodu.", - NULL -}; - -static const char *const book_komu_zvoni_hrana_n2[] = { - "Robert Jordan – americký dynamitář, intelektuál v uniformě.", - "Maria – mladá dívka osvobozená republikány, Jordanova láska.", - "Pablo – vůdce partyzánů, chladný realista, bojí se rizika.", - "Pilar – Pablova žena, silná, věrná republice.", - "Anselmo – starý průvodce, morální svědomí party.", - "El Sordo – vůdce další skupiny, statečný, padne v boji.", - NULL -}; - -static const char *const book_komu_zvoni_hrana_n3[] = { - "Most – symbol úkolu i oběti pro větší věc.", - "Solidarita – smrt jednoho se týká všech (Donne).", - "Hemingwayův styl – krátké věty, málo adjektiv, „iceberg“.", - "Občanská válka ve Španělsku – boj demokracie vs. fašismus.", - "Láska v době války – Maria jako naděje a křehkost.", - "Povinnost vs. strach – Jordanův vnitřní konflikt.", - NULL -}; - -static const BookNoteSec book_komu_zvoni_hrana_secs[] = { - {"O knize", book_komu_zvoni_hrana_n0}, - {"Doba a svět", book_komu_zvoni_hrana_n1}, - {"Postavy", book_komu_zvoni_hrana_n2}, - {"Klíčové pojmy", book_komu_zvoni_hrana_n3}, -}; - -static const char *const book_kral_oidipus_n0[] = { - "Autor: Sofokles (cca 496–406 př. n. l.), athénský tragik", - "Žánr: antická tragédie", - "Poprvé vydáno / uvedeno: kolem 429 př. n. l. (Athény)", - "Děj / prostředí: Théby, mýtus o králi Oidipovi", - "Vyprávění / forma: dramatická forma, jednota času a místa, chór", - NULL -}; - -static const char *const book_kral_oidipus_n1[] = { - "Antické Théby trpí morem; lidé hledají viníka.", - "Král Oidipus slíbil vysvobodit město od prokletí.", - "Tragédie stojí na neznalosti vlastní identity a osudu.", - "Bohové a věštba – člověk nemůže uniknout tomu, co je mu souzeno.", - "Jednota času, místa a děje – klasická pravidla antické tragédie.", - "Téma: poznání sebe sama stojí život i důstojnost.", - NULL -}; - -static const char *const book_kral_oidipus_n2[] = { - "Oidipus – král Théb, statečný, ale slepý k pravdě o sobě.", - "Iokasté – Oidipova manželka, ve skutečnosti matka.", - "Kréón – Iokastin bratr, racionální, obviňovaný z intrik.", - "Tiresias – slepý vědec, vidí pravdu dříve než král.", - "Posel z Korintu, pastýř – odhalují minulost Oidipa.", - "Chór thébských stařců – komentuje děj a morálku.", - NULL -}; - -static const char *const book_kral_oidipus_n3[] = { - "Věštba – Oidipus zabije otce a ožení se s matkou.", - "Hamartia – tragická chyba v pýše a netrpělivosti.", - "Anagnórisis – poznání pravdy o zločinech.", - "Peripetie – obrat od slávy k pádu.", - "Katarze – očista diváka strachem a soucitem.", - "Oidipovský komplex (Freud) – odvozený pojem, ne u Sofokla.", - NULL -}; - -static const BookNoteSec book_kral_oidipus_secs[] = { - {"O knize", book_kral_oidipus_n0}, - {"Doba a svět", book_kral_oidipus_n1}, - {"Postavy", book_kral_oidipus_n2}, - {"Klíčové pojmy", book_kral_oidipus_n3}, -}; - -static const char *const book_krysar_n0[] = { - "Autor: Viktor Dyk (1877–1931), český básník a prozaik", - "Žánr: novela, lyrizovaná próza, alegorie", - "Poprvé vydáno: 1915", - "Děj / prostředí: město Hameln (porýnská legenda o krysaři)", - "Vyprávění / forma: er-forma, rytmická prósa, refrénovité opakování", - NULL -}; - -static const char *const book_krysar_n1[] = { - "Dyk zpracovává středověkou německou pověst o krysaři z Hameln.", - "Vznik za 1. světové války; čte se i jako alegorie zrady a odplaty.", - "Měšťané jsou sobečtí, pokrytečtí, nedodrží slovo.", - "Krysař je cizinec – umělec, milenec i mstitel.", - "Láska ke Kristýnce je osobní rovina vedle viny města.", - "Jazyk je téměř básnický; opakují se klíčové věty a obrazy.", - NULL -}; - -static const char *const book_krysar_n2[] = { - "Krysař – cizinec s píšťalou, zbaví město krys, mstí se za zradu.", - "Kristýnka – dívka, kterou Krysař miluje.", - "Sepp Jörgen – rybář, prostý a věrný, přežije katastrofu.", - "Měšťané a konšelé – sobečtí, odmítnou zaplatit dohodnutou odměnu.", - "Agnes – matka Kristýnky, svět měšťanské morálky.", - "Bonifác – rival, představitel průměrnosti a závisti.", - NULL -}; - -static const char *const book_krysar_n3[] = { - "Píšťala – nástroj moci, svodu i trestu.", - "Zrada slova – město nezaplatí slíbenou cenu.", - "Alegorie – měšťanská malost a kolektivní vina.", - "Láska a smrt – vztah ke Kristýnce končí tragicky.", - "Cizinec – věčný outsider, který odhalí morálku společnosti.", - "Právo na odplatu – etický i právní dluh města.", - NULL -}; - -static const BookNoteSec book_krysar_secs[] = { - {"O knize", book_krysar_n0}, - {"Doba a svět", book_krysar_n1}, - {"Postavy", book_krysar_n2}, - {"Klíčové pojmy", book_krysar_n3}, -}; - -static const char *const book_kulicka_n0[] = { - "Autor: Guy de Maupassant (1850–1893), francouzský spisovatel", - "Žánr: realistická / naturalistická novela", - "Poprvé vydáno: 1880 (Večery na Médanu)", - "Děj / prostředí: Francie po prusko-francouzské válce, ústup z Rouenu", - "Vyprávění / forma: er-forma, ironický vypravěč, pointa", - NULL -}; - -static const char *const book_kulicka_n1[] = { - "Po porážce 1870/71: okupace, panika měšťanů, útěk z Rouenu.", - "Maupassant demaskuje pokrytectví „slušné“ společnosti.", - "Hrdinkou je prostitutka Elisabeth Roussetová – Kulička.", - "Morálka elity je pokrytecká: využijí ji, pak ji pohrdají.", - "Novela patří k vrcholům francouzského realismu 19. století.", - "Pointa je krutá – Kulička pláče, měšťané jedí a zpívají.", - NULL -}; - -static const char *const book_kulicka_n2[] = { - "Kulička (Elisabeth Roussetová) – prostitutka s upřímným charakterem.", - "Měšťané ve voze – obchodníci, šlechtici, demokrat, manželský pár.", - "Jeptišky – reprezentují náboženskou morálku, jedí Kuliččiny sendviče.", - "Pruský důstojník – žádá Kuliččinu „společnost“ za propuštění.", - "Loiseau – obchodník, nejvíc pokrytecký a posměšný.", - "Comtesse de Bréville – šlechtická dáma v hypocrisii.", - NULL -}; - -static const char *const book_kulicka_n3[] = { - "Pokrytectví – měšťané odsuzují, ale potřebují Kuličku.", - "Vlastenectví vs. sobectví – vlastenecké řeči kryjí strach.", - "Oběť – Kulička se obětuje pro ostatní.", - "Ironie – vypravěč odhaluje pravý charakter „slušných“.", - "Naturalismus – sociální a biologické determinace.", - "Pointa – ostrý závěr novelly.", - NULL -}; - -static const BookNoteSec book_kulicka_secs[] = { - {"O knize", book_kulicka_n0}, - {"Doba a svět", book_kulicka_n1}, - {"Postavy", book_kulicka_n2}, - {"Klíčové pojmy", book_kulicka_n3}, -}; - -static const char *const book_kvety_zla_n0[] = { - "Autor: Charles Baudelaire (1821–1867), francouzský básník", - "Žánr: moderní poezie, symbolistická sbírka", - "Poprvé vydáno: 1857 (soud za nemravnost)", - "Děj / prostředí: moderní město (Paříž), vnitřní svět básníka", - "Vyprávění / forma: lyrické básně, cykly (např. Spleen, Víno, Květy zla)", - NULL -}; - -static const char *const book_kvety_zla_n1[] = { - "Druhá polovina 19. století: industrializace, městská anonymita, krize víry.", - "Baudelaire vytváří „moderní“ estetiku krásy v ošklivém a hříšném.", - "Sbírka byla stíhána za obscénnost – symbol vzdoru proti puritanismu.", - "Motivy: smrt, smyslnost, nuda (spleen), umění, démonismus.", - "Vliv na symbolismus a moderní evropskou poezii.", - "Albatros, Holka s košíkem – ikonické básně cyklu.", - NULL -}; - -static const char *const book_kvety_zla_n2[] = { - "Básnický subjekt – flanér, vnímavý k městu i temnotě duše.", - "Ženy – milenky, coury, matky – objekty i symboly touhy a bolesti.", - "Démon / ďábel – vnitřní pokušení a krása zla.", - "Umělec – albatros, vězeň snů (básně o tvorbě).", - "Dav a město – anonymní moderní prostředí.", - "Stvořitel a stvoření – teologické pochybnosti.", - NULL -}; - -static const char *const book_kvety_zla_n3[] = { - "Spleen – nuda, melancholie, existenciální prázdnota.", - "Symbolismus – obraz nese víc významů (květy = krása i hřích).", - "Krása v modernitě – estetika i v odpudivém.", - "Flanér – chodec městem, pozorovatel.", - "Synestézie – smysly se prolínají (hudba–barva).", - "Cyklus básní – tematické celky ve sbírce.", - NULL -}; - -static const BookNoteSec book_kvety_zla_secs[] = { - {"O knize", book_kvety_zla_n0}, - {"Doba a svět", book_kvety_zla_n1}, - {"Postavy", book_kvety_zla_n2}, - {"Klíčové pojmy", book_kvety_zla_n3}, -}; - -static const char *const book_kytice_n0[] = { - "Autor: Karel Jaromír Erben (1811–1870)", - "Žánr: baladická sbírka, lidová epika v básnické formě", - "Poprvé vydáno: 1853 (druhé, rozšířené vydání)", - "Děj / prostředí: česká krajina, lidové pověsti a mýty", - "Vyprávění / forma: balady ve slavném verši, morální poučka", - NULL -}; - -static const char *const book_kytice_n1[] = { - "Romantismus a národní obrození: sběr lidové slovesnosti.", - "Erben převyprávěl pověsti s jednotnou morální a estetickou vizí.", - "Motivy: vina, trest, mateřství, smrt, příroda, křesťanská etika.", - "Prolínání reality a nadpřirozena (polednice, vodníci, liška Bystrouška).", - "Jazyk je hudební, rytmický, s refrénem a dialogy.", - "Kytice je vrcholem české baladické tradice.", - NULL -}; - -static const char *const book_kytice_n2[] = { - "Postavy z balad – matky, děti, milenci, královny (Vrba, Polednice…).", - "Vodník – děsivý pán vod, bere děti i dospělé.", - "Liška Bystrouška – chytrá, v baladě Svatební košile vítězí.", - "Karel a děti – Kytice obsahuje tragické rodinné osudy.", - "Polednice – trestá děti na poli v poledne.", - "Morana – personifikace smrti/zimy v baladě.", - NULL -}; - -static const char *const book_kytice_n3[] = { - "Balada – dramatický děj, tragický konec, poučka.", - "Lidová slovesnost – Erben přetváří lidové pověsti.", - "Motivem viny a odplaty – často porušení zákazu.", - "Nadpřirozeno – vodníci, polednice, kouzla.", - "Morální poučka – závěrečné poučení čtenáři.", - "Slavný verš – rytmus a refrény (např. Vrbo, rosteš…).", - NULL -}; - -static const BookNoteSec book_kytice_secs[] = { - {"O knize", book_kytice_n0}, - {"Doba a svět", book_kytice_n1}, - {"Postavy", book_kytice_n2}, - {"Klíčové pojmy", book_kytice_n3}, -}; - -static const char *const book_lakomec_n0[] = { - "Autor: Molière (Jean-Baptiste Poquelin, 1622–1673)", - "Žánr: divadelní komedie (komedie charakterů)", - "Poprvé vydáno / uvedeno: 1668", - "Děj / prostředí: pařížská měšťanská domácnost 17. století", - "Vyprávění / forma: drama, pětiaktová komedie, rýmovaná próza", - NULL -}; - -static const char *const book_lakomec_n1[] = { - "Klasicismus: pravidla jednoty, jasné typy postav, satira mravů.", - "Molière kritizuje lakotu, pokrytectví a měšťanskou chamtivost.", - "Harapagon je extrémní typ – komedie charakterů.", - "Rodina vs. otec: děti chtějí lásku, otec šetří i na štěstí.", - "Komedie končí happy endem – typické pro Molièra.", - "Hra je stále nejhranější francouzskou komedií.", - NULL -}; - -static const char *const book_lakomec_n2[] = { - "Harapagon – lakomec, otec, posedlý penězi.", - "Elise – Harapagonova dcera, miluje Valéra.", - "Cléante – Harapagonův syn, miluje Marianu.", - "Valér – sluha, miluje Elise, chytrý manipulátor.", - "Marianna – mladá dívka, objekt Harapagonových i Cléantových sňatků.", - "Frosina – matchmaker, využívá Harapagonovu lakotu.", - NULL -}; - -static const char *const book_lakomec_n3[] = { - "Komedie charakterů – jedna dominantní vlastnost (lakota).", - "Satira – výsměch mravům a společnosti.", - "Truhla s pokladem – Harapagonova posedlost.", - "Sňatky za peníze – konflikt generací.", - "Happy end – odhalení, smíření, svatby.", - "Valérova lst – sluha jako komický intrikán.", - NULL -}; - -static const BookNoteSec book_lakomec_secs[] = { - {"O knize", book_lakomec_n0}, - {"Doba a svět", book_lakomec_n1}, - {"Postavy", book_lakomec_n2}, - {"Klíčové pojmy", book_lakomec_n3}, -}; - -static const char *const book_lolita_n0[] = { - "Autor: Vladimir Nabokov (1899–1977), rusko-americký spisovatel", - "Žánr: moderní román, kontroverzní próza", - "Poprvé vydáno: 1955 (Paříž, Olympia Press)", - "Děj / prostředí: USA 40.–50. léta, cesty po amerických silnicích", - "Vyprávění / forma: ich-forma, Humbertův deník / vzpomínka", - NULL -}; - -static const char *const book_lolita_n1[] = { - "Román je psán jako Humbertův „svědectví“ – nespolehlivý vypravěč.", - "Lolita (Dolores Haze) je dívka; Humbert je dospělý s obsesí.", - "Kniha vyvolala skandál – etika, cenzura, interpretace.", - "Nabokov pracuje s jazykem, ironií, literárními aluzemi.", - "Road movie struktura – pronásledování, Quilty, útěk.", - "Tragický konec – Lolita umírá, Humbert vězí.", - NULL -}; - -static const char *const book_lolita_n2[] = { - "Humbert Humbert – vypravěč, intelektuál, pedofilní obsese.", - "Dolores Haze (Lolita) – dívka, oběť manipulace.", - "Charlotte Haze – Lolitiná matka, Humbert si ji chce vzít.", - "Clare Quilty – spisovatel, stínový protihráč, únos Lolity.", - "Annabel Leigh – Humbertova dětská láska (motiv vzpomínky).", - "Rita – žena po Lolité na cestách.", - NULL -}; - -static const char *const book_lolita_n3[] = { - "Nespolehlivý vypravěč – Humbert ospravedlňuje sebe.", - "Obsese a manipulace – moc dospělého nad dítětem.", - "Estetizace jazyka vs. morální hrůza – Nabokovova ironie.", - "Road novel – cesty po Americe.", - "Citace Poe, literatura – intertext.", - "Etická kontroverze – čtení jako demaskace, ne oslava.", - NULL -}; - -static const BookNoteSec book_lolita_secs[] = { - {"O knize", book_lolita_n0}, - {"Doba a svět", book_lolita_n1}, - {"Postavy", book_lolita_n2}, - {"Klíčové pojmy", book_lolita_n3}, -}; - -static const char *const book_maj_n0[] = { - "Autor: Karel Hynek Mácha (1810–1836)", - "Žánr: lyricko-epická skladba, romantická báseň", - "Poprvé vydáno: 1836 (posmrtně)", - "Děj / prostředí: jezero, hrad, krajina kolem Doksy, 19. století", - "Vyprávění / forma: veršovaná skladba, er-forma vypravěče + lyrické vložky", - NULL -}; - -static const char *const book_maj_n1[] = { - "Český romantismus: cit, příroda, osud, vina, krása a smrt.", - "Máj je vrchol české romantické poezie – hudební, obrazná skladba.", - "Děj: Jarmila se utopí, Vilém vrazí, poprava, vězeň, vandrák.", - "Příroda reaguje na zločin (bouře, hrom) – personifikace.", - "Intertext: Byron, Shelley, slovanský romantismus.", - "Máj jako symbol lásky, jara i smrti.", - NULL -}; - -static const char *const book_maj_n2[] = { - "Vilém – vězeň, vrah otce Jarmiliného, milenec Jarmily.", - "Jarmila – milenka, utopí se v jezeře.", - "Hajný – otec Jarmily, Vilém ho zabil v afektu.", - "Vězeň ve vězení – Vilém, lyrické monology.", - "Vandrák – putující poutník, komentář k osudu.", - "Sbor jeskyň – personifikovaná příroda.", - NULL -}; - -static const char *const book_maj_n3[] = { - "Romantismus – cit, osud, příroda, vina.", - "Lyricko-epická skladba – děj + lyrické pasáže.", - "Máj – symbol jara, lásky, obnovy i smrti.", - "Vina a trest – poprava, vězení.", - "Personifikace přírody – hrom, jezero, kraj.", - "Intercalare – lyrické vložky (např. vězeň, vandrák).", - NULL -}; - -static const BookNoteSec book_maj_secs[] = { - {"O knize", book_maj_n0}, - {"Doba a svět", book_maj_n1}, - {"Postavy", book_maj_n2}, - {"Klíčové pojmy", book_maj_n3}, -}; - -static const char *const book_maly_princ_n0[] = { - "Autor: Antoine de Saint-Exupéry (1900–1944), francouzský spisovatel a pilot", - "Žánr: philosophická pohádka / alegorická novela", - "Poprvé vydáno: 1943", - "Děj / prostředí: poušť, asteroid B-612, různé „planetky“", - "Vyprávění / forma: ich-forma pilota, ilustrace autora", - NULL -}; - -static const char *const book_maly_princ_n1[] = { - "Vznik za 2. světové války – téma smyslu, přátelství, odpovědnosti.", - "Malý princ cestuje planetami – satira dospělých (král, vain man, geographer).", - "Liška učí: „Ochoč si mě a budeš jedinečný.“", - "Růže na asteroidu – láska a odpovědnost.", - "Had a návrat – tajemství smrti / odchodu.", - "Kniha je nejpreloženější francouzskou knihou.", - NULL -}; - -static const char *const book_maly_princ_n2[] = { - "Malý princ – dítě z asteroidu B-612, hledá smysl.", - "Pilot – vypravěč, havaroval v poušti.", - "Růže – náročná, princ ji miluje a opouští.", - "Liška – moudrá, učí vztahy a odpovědnost.", - "Had – symbol odchodu, pomáhá princi.", - "Dospělí na planetách – král, domýšlivec, pijan, lampář, geograf.", - NULL -}; - -static const char *const book_maly_princ_n3[] = { - "„Co je důležité, oči nevidí.“ – podstata vs. vzhled.", - "Ochočení – vztah dává věcem jedinečnost.", - "Odpovědnost za růži – péče o to, co milujeme.", - "Satira dospělých – prázdné profese a moc.", - "Poušť – setkání pilota a prince.", - "Alegorie – dětská pohádka pro dospělé.", - NULL -}; - -static const BookNoteSec book_maly_princ_secs[] = { - {"O knize", book_maly_princ_n0}, - {"Doba a svět", book_maly_princ_n1}, - {"Postavy", book_maly_princ_n2}, - {"Klíčové pojmy", book_maly_princ_n3}, -}; - -static const char *const book_marysa_n0[] = { - "Autor: Alois a Vilém Mrštíkové (1854–1932 / 1863–1912)", - "Žánr: realistické drama, venkovská tragédie", - "Poprvé vydáno / uvedeno: 1894", - "Děj / prostředí: moravský venkov, hospoda, dvorec", - "Vyprávění / forma: divadelní hra, dialogy, venkovská mluva", - NULL -}; - -static const char *const book_marysa_n1[] = { - "Konec 19. století: venkov, společenské poměry, soudní proces.", - "Maryša – mladá vdova, týraná tchyní a okolím.", - "Láska k Filipovi kontrastuje s tlakem na sňatek s Vávrou.", - "Realistické drama bez patosu – sociální a morální konflikt.", - "Proces s Maryšou – oběť systému a pomluv.", - "Mrštíkové patří k vrcholu české realistické dramaturgie.", - NULL -}; - -static const char *const book_marysa_n2[] = { - "Maryša – mladá vdova, statečná, oběť pomluv a tchyně.", - "Filip – milenec Maryši, sedlák.", - "Vávra – bohatý sedlák, touží po Maryši a statku.", - "Maryšina tchyně – krutá, panovačná, ničí snahu vdovy.", - "Metoděj – kněz, morální autorita.", - "Sedláci a vesnice – soud a společenský tlak.", - NULL -}; - -static const char *const book_marysa_n3[] = { - "Realistické drama – všední konflikt bez idealizace.", - "Vdovství a majetek – ekonomický tlak na Maryšu.", - "Pomluva a soud – společenské odsouzení.", - "Venkovská mluva – autenticita dialogů.", - "Generační a rodinný útlak – tchyně.", - "Tragédie oběti – Maryša prohrává s systémem.", - NULL -}; - -static const BookNoteSec book_marysa_secs[] = { - {"O knize", book_marysa_n0}, - {"Doba a svět", book_marysa_n1}, - {"Postavy", book_marysa_n2}, - {"Klíčové pojmy", book_marysa_n3}, -}; - -static const char *const book_modlitba_pro_katerinu_n0[] = { - "Autor: František Halas (1901–1949), český básník", - "Žánr: moderní poezie, básnická skladba / cyklus", - "Poprvé vydáno: 1939 (Modlitba pro Katherinu Horovitzovou)", - "Děj / prostředí: 2. světová válka, okupace, koncentrační tábor (motiv)", - "Vyprávění / forma: volný verš, lyrický monolog, reflexe", - NULL -}; - -static const char *const book_modlitba_pro_katerinu_n1[] = { - "Vznik na počátku okupace – strach, útlak, lidská křehkost.", - "Inspirace románem Arnošta Lustiga o Katherině Horovitzové.", - "Halas modlí za oběť i za lidskost uprostřed nelidskosti.", - "Motivy: víra, naděje, bolest, smrt, odpovědnost básníka.", - "Patří k vrcholu české válečné lyriky.", - "Jazyk je intimní, naléhavý, bez patetického klišé.", - NULL -}; - -static const char *const book_modlitba_pro_katerinu_n2[] = { - "Básnický subjekt – hlas modlícího se svědka.", - "Katherina Horovitzová – oběť holocaustu, addresát modlitby.", - "Oběti tábora – kolektivní tvář utrpení.", - "Bůh / addresát modlitby – vztah víry v krizi.", - "Okupanti – nepřítomní, ale pociťovaní v strachu.", - "Čtenář – svědek morální výzvy.", - NULL -}; - -static const char *const book_modlitba_pro_katerinu_n3[] = { - "Modlitba – forma i obsah – apel na smysl a milosrdenství.", - "Holocaust – genocida, Katherina jako konkrétní jméno.", - "Válečná lyrika – reakce na 2. světovou válku.", - "Oběť – individualizace utrpení jednoho člověka.", - "Naděje vs. beznaděj – napětí skladby.", - "Etická odpovědnost umělce – mluvit za ty, kdo nemohou.", - NULL -}; - -static const BookNoteSec book_modlitba_pro_katerinu_secs[] = { - {"O knize", book_modlitba_pro_katerinu_n0}, - {"Doba a svět", book_modlitba_pro_katerinu_n1}, - {"Postavy", book_modlitba_pro_katerinu_n2}, - {"Klíčové pojmy", book_modlitba_pro_katerinu_n3}, -}; - -static const char *const book_most_kwai_n0[] = { - "Autor: Pierre Boulle (1912–1994), francouzský spisovatel", - "Žánr: válečný román, antiwar novela", - "Poprvé vydáno: 1952 (Le Pont de la Rivière Kwai)", - "Děj / prostředí: Burma Railway, 2. světová válka, thajsko-barmská džungle", - "Vyprávění / forma: er-forma, střídání perspektiv (Britové, Japonci)", - NULL -}; - -static const char *const book_most_kwai_n1[] = { - "Japonci nutí zajatce stavět most přes řeku Kwai.", - "Colonel Nicholson – posedlost „správným“ mostem pro armádu.", - "Shears – americký důstojník, útěk, sabotáž.", - "Konflikt: vojenská hrdost vs. realita války a smrti.", - "Slavný film Davida Leana (1957) s Alec Guinnessem.", - "Most je symbol absurdity války a kolaborace s nepřítelem.", - NULL -}; - -static const char *const book_most_kwai_n2[] = { - "Colonel Nicholson – britský důstojník, staví most pro Japonce z hrdosti.", - "Shears (Warden ve filmu) – únik, návrat se sabotážním týmem.", - "Colonel Saito – japonský velitel tábora.", - "Major Clipton – britský lékař, vidí absurditu.", - "Joyce – mladý důstojník v sabotážním týmu.", - "Zajatci – oběti práce na „železniční smrti“.", - NULL -}; - -static const char *const book_most_kwai_n3[] = { - "Burma Railway – brutální stavba, tisíce mrtvých.", - "Most Kwai – symbol kolaborace a šílenství.", - "Vojenská čest vs. loajalita – Nicholsonův paradox.", - "Sabotáž – Shearsův tým má most zničit.", - "Antiwar – válka degraduje morálku.", - "Film vs. kniha – podobné, ale rozdíly v detailu.", - NULL -}; - -static const BookNoteSec book_most_kwai_secs[] = { - {"O knize", book_most_kwai_n0}, - {"Doba a svět", book_most_kwai_n1}, - {"Postavy", book_most_kwai_n2}, - {"Klíčové pojmy", book_most_kwai_n3}, -}; - -static const char *const book_stanice_zoo_n0[] = { - "Autor: Christiane F. (Christiane Felscherinow; zaznamenali Kai Hermann a Horst Rieck)", - "Žánr: dokumentární próza / autentická zpověď", - "Poprvé vydáno: 1978 (Wir Kinder vom Bahnhof Zoo); česky My děti ze stanice ZOO", - "Děj / prostředí: Západní Berlín 70. let – stanice Zoo, drogová scéna", - "Vyprávění / forma: ich-forma Christiane, reportážní styl založený na rozhovorech", - NULL -}; - -static const char *const book_stanice_zoo_n1[] = { - "Západní Berlín 70. let: subkultura, heroin, prostitutce mladistvých.", - "Kniha vznikla z novinářských rozhovorů s Christiane Felscherinow.", - "Ukazuje propad od dětství a večírků k závislosti.", - "Stanice Zoo je centrem drogové scény a obchodu s tělem.", - "Text varuje před drogami skrze svědectví, bez pohádkového moralizování.", - "Patří k nejznámějším dokumentárním příběhům o závislosti dospívajících.", - NULL -}; - -static const char *const book_stanice_zoo_n2[] = { - "Christiane F. – vypravěčka, dospívající dívka závislá na heroinu.", - "Detlef – Christianin přítel, také závislý.", - "Matka Christiane – snaží se dceru zachránit, často bezmocně.", - "Kamarádi z party scény – vstupní brána k drogám.", - "Dealeři a klienti – součást ekonomie stanice Zoo.", - "Sociální pracovníci / policie – instituce na okraji příběhu.", - NULL -}; - -static const char *const book_stanice_zoo_n3[] = { - "Závislost – fyzické i sociální otroctví heroinu.", - "Stanice Zoo – symbol úpadku a trhu s drogami.", - "Prostituce – prostředek získání peněz na dávku.", - "Dokumentárnost – autentické svědectví, ne fikční „hrdinství“.", - "Dospívání – ztráta dětství v subkultuře.", - "Bezmoc okolí – rodina a instituce nestíhají pomáhat.", - NULL -}; - -static const BookNoteSec book_stanice_zoo_secs[] = { - {"O knize", book_stanice_zoo_n0}, - {"Doba a svět", book_stanice_zoo_n1}, - {"Postavy", book_stanice_zoo_n2}, - {"Klíčové pojmy", book_stanice_zoo_n3}, -}; - -static const char *const book_na_ceste_n0[] = { - "Autor: Jack Kerouac (vl. jm. Jean-Louis Lebris de Kérouac)", - "Žánr: román beat generation; autobiografické rysy", - "Poprvé vydáno: 1957 (anglicky On the Road; česky Na cestě)", - "Děj: opakované cesty po Spojených státech a do Mexika", - "Vyprávění: ich-forma; spontánní próza inspirovaná jazzem", - NULL -}; - -static const char *const book_na_ceste_n1[] = { - "Poválečná Amerika 40. a 50. let: konformita, spotřební společnost, studená válka.", - "Beat generation odmítá materialismus a hledá autentický život.", - "Silnice, auta a vlaky jsou symbolem svobody i neklidu.", - "Jazz, noční bary, drogy a sex patří k beatnickému stylu.", - "Cesta je zároveň únikem i hledáním smyslu – často bez pevné kotvy.", - "Kerouac zachycuje rytmus života rychlým, neupraveným stylem.", - NULL -}; - -static const char *const book_na_ceste_n2[] = { - "Sal Paradise – vypravěč, spisovatel, hledá zkušenost (Kerouac).", - "Dean Moriarty – neklidný, charismatický motor cest (Neal Cassady).", - "Marylou – Deanova mladá partnerka.", - "Camille / Galatea – další ženy v Deanově nestálém životě.", - "Carlo Marx, Old Bull Lee – přátelé z beat scény (Ginsberg, Burroughs).", - "Amerika – prostor nekonečných cest a setkání.", - NULL -}; - -static const char *const book_na_ceste_n3[] = { - "Beat generation – kulturní hnutí mladých umělců po válce.", - "Spontánní próza – rychlý proud řeči bez klasické kompozice.", - "Cesta – metafora svobody, touhy i vyčerpání.", - "Jazz – rytmus textu i životního stylu.", - "Konformita vs. autenticita – hlavní konflikt.", - "IT – beatnické slovo pro extatický okamžik plnosti.", - NULL -}; - -static const BookNoteSec book_na_ceste_secs[] = { - {"O knize", book_na_ceste_n0}, - {"Doba a svět", book_na_ceste_n1}, - {"Postavy", book_na_ceste_n2}, - {"Klíčové pojmy", book_na_ceste_n3}, -}; - -static const char *const book_na_zapadni_fronte_n0[] = { - "Autor: Erich Maria Remarque", - "Žánr: protiválečný román; generační próza", - "Poprvé vydáno: 1929 (německy Im Westen nichts Neues)", - "Děj: západní fronta 1. světové války, německá armáda", - "Vyprávění: ich-forma Paula Bäumera", - NULL -}; - -static const char *const book_na_zapadni_fronte_n1[] = { - "1. světová válka: zákopy, dělostřelectvo, plyn, strojová válka.", - "Mladí dobrovolníci byli sváděni učiteli k „slavnému boji za vlast“.", - "Fronta ničí tělo i duši; smrt je všední a bezcílná.", - "Domov už nechápe zkušenost vojáků – propast generací.", - "Kamarádství ve squatu je jedinou oporou proti absurditě.", - "Remarque míří proti romantizaci války.", - NULL -}; - -static const char *const book_na_zapadni_fronte_n2[] = { - "Paul Bäumer – vypravěč, student proměněný v cynického vojáka.", - "Stanislaus Katczinsky (Kat) – čtyřicátník, mazaný kamarád.", - "Albert Kropp, Müller, Leer, Tjaden – spolužáci z třídy.", - "Kantorek – učitel, který je nabádal k odchodu na frontu.", - "Himmelstoss – tyranský cvičitel, později zocelený frontou.", - "Francouzský voják Gérard Duval – Paul ho zabije v zákopu.", - NULL -}; - -static const char *const book_na_zapadni_fronte_n3[] = { - "Ztráta generace – mladí zničeni dřív, než začnou žít.", - "Zákop – symbol odlidštění a strachu.", - "Kamarádství – sdílení chleba, krytí, smích.", - "Propaganda vs. realita – Kantorek a fronta.", - "Odcizení od civilního světa – domov je cizí.", - "Antiválečné poselství – válka nemá smysl.", - NULL -}; - -static const BookNoteSec book_na_zapadni_fronte_secs[] = { - {"O knize", book_na_zapadni_fronte_n0}, - {"Doba a svět", book_na_zapadni_fronte_n1}, - {"Postavy", book_na_zapadni_fronte_n2}, - {"Klíčové pojmy", book_na_zapadni_fronte_n3}, -}; - -static const char *const book_navsteva_stare_damy_n0[] = { - "Autor: Friedrich Dürrenmatt", - "Žánr: tragická komedie / drama", - "Poprvé vydáno: 1956 (Die Physiker – ne, to je jiné; Návštěva 1956)", - "Děj: městečko Güllen, miliardářka Claire Zachanassian", - "Vyprávění: drama ve třech dějstvích", - NULL -}; - -static const char *const book_navsteva_stare_damy_n1[] = { - "Poválečné / moderní Evropa – chudoba provincie vs. bohatství.", - "Güllen upadá, obyvatelé touží po penězích.", - "Claire nabídne miliardu za smrt Alfreda Illa.", - "Morálka vs. materiální zkaženost.", - "Tragikomický tón – smích i hrůza.", - "Téma: vina, pomsta, kolektivní zločin.", - NULL -}; - -static const char *const book_navsteva_stare_damy_n2[] = { - "Claire Zachanassian – miliardářka, kdysi opuštěná Illem.", - "Alfred Ill – majitel obchodu, „respektovaný“ občan.", - "Starosta – mluví o cti, pak kapituluje.", - "Učitel – nejprve protestuje, pak mlčí.", - "Doktoři a občané Güllenu – kolektivní viník.", - "Slepí muži Klodi a Lobi – Claireini pomocníci.", - NULL -}; - -static const char *const book_navsteva_stare_damy_n3[] = { - "Miliarda – cena morálky města.", - "Pomsta – Claire chce Illovu smrt, ne peníze pro sebe.", - "Kolektivní vina – všichni koupí luxus na dluh.", - "Tragikomedie – groteskní situace.", - "Güllen – symbol zkažené společnosti.", - "Justice – Ill zemře „soudem“ obce.", - NULL -}; - -static const BookNoteSec book_navsteva_stare_damy_secs[] = { - {"O knize", book_navsteva_stare_damy_n0}, - {"Doba a svět", book_navsteva_stare_damy_n1}, - {"Postavy", book_navsteva_stare_damy_n2}, - {"Klíčové pojmy", book_navsteva_stare_damy_n3}, -}; - -static const char *const book_nebe_nezna_vyvolenych_n0[] = { - "Autor: Erich Maria Remarque", - "Žánr: román; emigrantská / láskyplná próza", - "Poprvé vydáno: 1961 (Der Himmel kennt keine Günstlinge)", - "Děj: 2. světová válka, emigranti v Paříži a okolí", - "Vyprávění: er-forma; prožitkový styl", - NULL -}; - -static const char *const book_nebe_nezna_vyvolenych_n1[] = { - "2. světová válka – útěk před nacismem, bezdomoví.", - "Paříž emigrantů, strach z gestapa a udání.", - "Láska v nestabilitě – Joan a Ravic.", - "Lékař bez papírů, ilegální praxe.", - "Humanismus vs. totalita.", - "Téma: osud, náhoda, křehkost štěstí.", - NULL -}; - -static const char *const book_nebe_nezna_vyvolenych_n2[] = { - "Ravic – německý emigrant, lékař v ilegalitě.", - "Joan Madou – jeho milovaná, křehká osud.", - "Boris Morosow – Ravicův přítel, společník osudu.", - "Policejní komisař – hrozba zatčení.", - "Emigrantská komunita – sdílený strach.", - "Bezdorf – místo Ravicova úkrytu (v díle).", - NULL -}; - -static const char *const book_nebe_nezna_vyvolenych_n3[] = { - "Emigrace – základní situace hrdinů.", - "Bezpapírovost – bezpráví a nejistota.", - "Láska ve válce – krátké štěstí.", - "Osud – nebe nezná vyvolené (titul).", - "Lékařská etika – Ravic pomáhá i v ilegalitě.", - "Tragický konec – Joanina smrt.", - NULL -}; - -static const BookNoteSec book_nebe_nezna_vyvolenych_secs[] = { - {"O knize", book_nebe_nezna_vyvolenych_n0}, - {"Doba a svět", book_nebe_nezna_vyvolenych_n1}, - {"Postavy", book_nebe_nezna_vyvolenych_n2}, - {"Klíčové pojmy", book_nebe_nezna_vyvolenych_n3}, -}; - -static const char *const book_o_mysich_a_lidech_n0[] = { - "Autor: John Steinbeck", - "Žánr: novela / sociální próza", - "Poprvé vydáno: 1937", - "Děj: Kalifornie za Velké krize, ranch a chudí dělníci", - "Vyprávění: er-forma; realistický, soucitný styl", - NULL -}; - -static const char *const book_o_mysich_a_lidech_n1[] = { - "Velká krize 30. let – chudoba, tuláci, práce na rancích.", - "Sen o vlastní půdě – „farma s králíky“.", - "Osamělost a přátelství mužů bez rodin.", - "Sociální bezpráví vůči slabším (Curleyova žena, Crooks).", - "Násilí a nešťastná náhoda ničí sen.", - "Téma: sen, přátelství, osamělost, lidskost.", - NULL -}; - -static const char *const book_o_mysich_a_lidech_n2[] = { - "George Milton – chytrý, opatruje Lennieho.", - "Lennie Small – silný, mentálně neschopný, miluje zvířata.", - "Curley – syn majitele, agresivní.", - "Curleyova žena – osamělá, nešťastná.", - "Crooks – černý stableman, vyloučený.", - "Candy – starý dělník se psem.", - NULL -}; - -static const char *const book_o_mysich_a_lidech_n3[] = { - "Sen o farmě – naděje a útěk.", - "Přátelství George–Lennie – ochrana slabšího.", - "Osamělost – ranch bez vazeb.", - "Neschopnost Lennie – tragický prvek.", - "Zabití psa / králíka – předznamenání konce.", - "Georgeovo rozhodnutí – milosrdná střela.", - NULL -}; - -static const BookNoteSec book_o_mysich_a_lidech_secs[] = { - {"O knize", book_o_mysich_a_lidech_n0}, - {"Doba a svět", book_o_mysich_a_lidech_n1}, - {"Postavy", book_o_mysich_a_lidech_n2}, - {"Klíčové pojmy", book_o_mysich_a_lidech_n3}, -}; - -static const char *const book_obraz_doriana_graye_n0[] = { - "Autor: Oscar Wilde", - "Žánr: philosophický / gotický román", - "Poprvé vydáno: 1890 (revidováno 1891)", - "Děj: Londýn fin de siècle, společnost a moralita", - "Vyprávění: er-forma; epigramy, estetika", - NULL -}; - -static const char *const book_obraz_doriana_graye_n1[] = { - "Victoriánská Anglie – puritanismus vs. estetismus.", - "Umění pro umění, hedonismus lorda Henryho.", - "Dvojí život Doriana – krása navenek, shniloba v obraze.", - "Skandály, opium, vražda – morální pokles.", - "Gotický prvek: portrét nesoucí viny.", - "Téma: krása, morálka, vina, umění.", - NULL -}; - -static const char *const book_obraz_doriana_graye_n2[] = { - "Dorian Gray – mladík neuvěřitelné krásy.", - "Basil Hallward – malíř, autor portrétu.", - "Lord Henry Wotton – cynický hedonista, vpliv.", - "Sibyl Vane – herečka, Dorianova první oběť.", - "James Vane – Sibylin bratr, pomsta.", - "Portrét – zrcadlo Dorianovy duše.", - NULL -}; - -static const char *const book_obraz_doriana_graye_n3[] = { - "Portrét – nese stárnutí a zločiny místo Doriana.", - "Estetismus – krása nad morálkou (Henry).", - "Hedonismus – hledání rozkoší.", - "Dvojí život – společenská maska.", - "Zrcadlo / obraz – symbol viny.", - "Závěr – Dorian bodne portrét, umírá sám.", - NULL -}; - -static const BookNoteSec book_obraz_doriana_graye_secs[] = { - {"O knize", book_obraz_doriana_graye_n0}, - {"Doba a svět", book_obraz_doriana_graye_n1}, - {"Postavy", book_obraz_doriana_graye_n2}, - {"Klíčové pojmy", book_obraz_doriana_graye_n3}, -}; - -static const char *const book_obsluhoval_jsem_n0[] = { - "Autor: Bohumil Hrabal", - "Žánr: román / novela s pikareskními rysy", - "Poprvé vydáno: 1971 (česky; různá vydání)", - "Děj: 20. století očima číšníka Dita", - "Vyprávění: ich-forma; hrabalovská řeč, groteska", - NULL -}; - -static const char *const book_obsluhoval_jsem_n1[] = { - "Od první republiky přes protektorát po poválečný socialismus.", - "Hotely a hostince jako jeviště dějin shora.", - "Ditie touží po uznání a „velikosti“.", - "Komplice s mocí, trest, normalizace.", - "Groteska mísí smích s tragédií.", - "Téma: malý člověk, dějiny, vinna, touha.", - NULL -}; - -static const char *const book_obsluhoval_jsem_n2[] = { - "Ditě (Jan Ditie) – vypravěč, číšník.", - "Líza – láska, spojená s Ditieho vzestupem.", - "Hoteloví hosté – politici, Němci, elita.", - "Tichý Šimon – poválečný soudce Ditieho osudu.", - "Protektorátní moc – pokušení kolaborace.", - "Dítě (syn) – naděje a ztráta.", - NULL -}; - -static const char *const book_obsluhoval_jsem_n3[] = { - "Pohled zdola – servis vidí moc zblízka.", - "Touha po velikosti – Ditieho motor.", - "Kolaborace – servírování mocným.", - "Groteska – Hrabalův humor i děs.", - "Hotel – mikrokosmos století.", - "Soud / Tichý Šimon – morální bilance.", - NULL -}; - -static const BookNoteSec book_obsluhoval_jsem_secs[] = { - {"O knize", book_obsluhoval_jsem_n0}, - {"Doba a svět", book_obsluhoval_jsem_n1}, - {"Postavy", book_obsluhoval_jsem_n2}, - {"Klíčové pojmy", book_obsluhoval_jsem_n3}, -}; - -static const char *const book_oliver_twist_n0[] = { - "Autor: Charles Dickens", - "Žánr: sociální román", - "Poprvé vydáno: 1837–1839 (seriálově)", - "Děj: Londýn 19. století, chudoba a kriminality", - "Vyprávění: er-forma; realistický, sentimentální styl", - NULL -}; - -static const char *const book_oliver_twist_n1[] = { - "Victoriánská Anglie – chudobinci, sirotčince.", - "Kriminalita, gangy, Faginova dílna.", - "Sociální kritika třídní nespravedlnosti.", - "Oliver jako symbol nevinnosti.", - "Od sirotčince k pravdě o původu.", - "Téma: chudoba, spravedlnost, identita.", - NULL -}; - -static const char *const book_oliver_twist_n2[] = { - "Oliver Twist – sirotek, dobré srdce.", - "Fagin – starý Žid, vede gang zlodějů.", - "Bill Sikes – brutální lupič.", - "Nancy – oběť, pomáhá Oliverovi.", - "Pan Brownlow – dobrodinec.", - "Monks – Oliverův nevlastní bratr.", - NULL -}; - -static const char *const book_oliver_twist_n3[] = { - "Sirotčinec – krutost systému.", - "„Prosím, pane, chci ještě“ – slavná scéna.", - "Gang – Fagin, Sikes, Artful Dodger.", - "Dědictví – tajemství Oliverova původu.", - "Nancy – oběť i statečnost.", - "Happy-end – spravedlnost pro Olivera.", - NULL -}; - -static const BookNoteSec book_oliver_twist_secs[] = { - {"O knize", book_oliver_twist_n0}, - {"Doba a svět", book_oliver_twist_n1}, - {"Postavy", book_oliver_twist_n2}, - {"Klíčové pojmy", book_oliver_twist_n3}, -}; - -static const char *const book_ostre_sledovane_vlaky_n0[] = { - "Autor: Bohumil Hrabal", - "Žánr: novela; válečná groteska", - "Poprvé vydáno: 1965", - "Děj: malá stanice v protektorátu", - "Vyprávění: ich-forma Miloše Hrmy", - NULL -}; - -static const char *const book_ostre_sledovane_vlaky_n1[] = { - "Protektorát Čechy a Morava – okupace, železnice.", - "Vlaky vezou zbraně – ostře sledované.", - "Sexuální nejistota a dospívání vs. válka.", - "Humor, razítka, absurdita.", - "Malý čin odboje na konci.", - "Téma: iniciace, zbabělost, odvaha.", - NULL -}; - -static const char *const book_ostre_sledovane_vlaky_n2[] = { - "Miloš Hrma – mladý výpravčí, vypravěč.", - "Výpravčí Hubička – svůdník, razítka na Zdeničce.", - "Zdenička – telegrafistka.", - "Přednosta stanice – holubi, autorita.", - "Virginia / Viktoria Freie – zasvěcení Miloše.", - "Němečtí důstojníci – moc okupace.", - NULL -}; - -static const char *const book_ostre_sledovane_vlaky_n3[] = { - "Iniciace – sexuální i odbojová.", - "Razítka – groteskní erotický motiv.", - "Ostře sledovaný vlak – cíl sabotáže.", - "Sebevražedný pokus – Milošův stud.", - "Groteska – smích a smrt.", - "Český malý hrdinství – ironie.", - NULL -}; - -static const BookNoteSec book_ostre_sledovane_vlaky_secs[] = { - {"O knize", book_ostre_sledovane_vlaky_n0}, - {"Doba a svět", book_ostre_sledovane_vlaky_n1}, - {"Postavy", book_ostre_sledovane_vlaky_n2}, - {"Klíčové pojmy", book_ostre_sledovane_vlaky_n3}, -}; - -static const char *const book_svejk_n0[] = { - "Autor: Jaroslav Hašek", - "Žánr: satirický pikareskní román; humor, anekdota", - "Poprvé vydáno: 1921–1923 (nedokončeno – autor zemřel 1923)", - "Děj: Rakousko-Uhersko za 1. světové války, cesta Josefa Švejka do armády", - "Vyprávění: er-forma; řetězec historek, dialogů a absurdních situací", - NULL -}; - -static const char *const book_svejk_n1[] = { - "1. světová válka a rozpadající se monarchie – absurdita rozkazů.", - "Armáda a byrokracie jako mašinerie hlouposti.", - "Český malý člověk přežívá lstí, „švejkováním“ a předstíranou naivitou.", - "Satira na vlastenectví, církev, špionáž a válečnou propagandu.", - "Praha, Budějovice, fronta – putování systémem.", - "Humor jako obrana proti nesmyslu moci.", - NULL -}; - -static const char *const book_svejk_n2[] = { - "Josef Švejk – dobrý voják, blbost jako strategie.", - "Nadporučík Lukáš – pán Švejka, často v nesnázích.", - "Polní kurát Otto Katz – pijan, hráč, „patriot“.", - "Poručík Dub – kariérista, donašeč, nenávidí Čechy.", - "Policejní rada Bretschneider – provokatér v hospodách.", - "Majitel císařských lázní Müller – další z autorit.", - NULL -}; - -static const char *const book_svejk_n3[] = { - "Švejkování – ironická poslušnost, přetvářka hloupého.", - "Anekdota – stavební jednotka textu.", - "Byrokracie – úřady, armáda, nesmyslné formuláře.", - "Satira – smích vede k odhalení absurdity.", - "Válka – nonsens, ne hrdinský epos.", - "Hospoda U kalicha – prostor lidové moudrosti.", - NULL -}; - -static const BookNoteSec book_svejk_secs[] = { - {"O knize", book_svejk_n0}, - {"Doba a svět", book_svejk_n1}, - {"Postavy", book_svejk_n2}, - {"Klíčové pojmy", book_svejk_n3}, -}; - -static const char *const book_pan_much_n0[] = { - "Autor: William Golding", - "Žánr: alegorický román", - "Poprvé vydáno: 1954", - "Děj: opuštěný ostrov po nehodě letadla", - "Vyprávění: er-forma; symbolický realismus", - NULL -}; - -static const char *const book_pan_much_n1[] = { - "Poválečná doba – chlapci bez dospělých.", - "Pokus o řád vs. divokost.", - "Strach z „bestie“ – projekce zla.", - "Oheň jako záchrana i ničení.", - "Pád civilizace na ostrově.", - "Téma: lidská přirozenost, moc, strach.", - NULL -}; - -static const char *const book_pan_much_n2[] = { - "Ralph – vůdce demokracie, lastura.", - "Jack – vůdce lovců, tyranie.", - "Piggy – rozum, brýle.", - "Simon – introvert, pravda o bestii.", - "Roger – krutost bez hranic.", - "Námořní důstojník – návrat civilizace.", - NULL -}; - -static const char *const book_pan_much_n3[] = { - "Lastura – volba, řád.", - "Oheň – signál vs. les v plamenech.", - "Bestie – strach uvnitř lidí.", - "Brýle – věda, rozum (Piggy).", - "Malování tváří – maska divokosti.", - "Pán much – prase hlava na kůlu.", - NULL -}; - -static const BookNoteSec book_pan_much_secs[] = { - {"O knize", book_pan_much_n0}, - {"Doba a svět", book_pan_much_n1}, - {"Postavy", book_pan_much_n2}, - {"Klíčové pojmy", book_pan_much_n3}, -}; - -static const char *const book_pan_prstenu_n0[] = { - "Autor: John Ronald Reuel Tolkien", - "Žánr: epická fantasy (román)", - "Poprvé vydáno: 1954–1955 (trilogie)", - "Děj: Středozem, válka proti Sauronovi", - "Vyprávění: er-forma; mýtus, epos", - NULL -}; - -static const char *const book_pan_prstenu_n1[] = { - "Fiktivní Středozem – Třetí věk.", - "Prsten moci – Sauron, Mordor.", - "Společenstvo – putování k Hoře osudu.", - "Témata: moc korumpuje, přátelství, oběť.", - "Hobití kraj vs. temnota.", - "Kulturní fenomén fantasy.", - NULL -}; - -static const char *const book_pan_prstenu_n2[] = { - "Frodo Pytlík – nositel Prstenu.", - "Sam – věrný společník.", - "Gandalf – čaroděj, mentor.", - "Aragorn – dědic Gondoru.", - "Gollum/Smeagol – posedlost Prstenem.", - "Společenstvo – Legolas, Gimli, Boromir…", - NULL -}; - -static const char *const book_pan_prstenu_n3[] = { - "Jeden prsten – moc Saurona.", - "Společenstvo prstenu – výprava.", - "Hora osudu – zničit Prsten.", - "Mordor – říše zla.", - "Hobit – malý hrdina.", - "Moc korumpuje – Boromir, Gollum.", - NULL -}; - -static const BookNoteSec book_pan_prstenu_secs[] = { - {"O knize", book_pan_prstenu_n0}, - {"Doba a svět", book_pan_prstenu_n1}, - {"Postavy", book_pan_prstenu_n2}, - {"Klíčové pojmy", book_pan_prstenu_n3}, -}; - -static const char *const book_petr_a_lucie_n0[] = { - "Autor: Vítězslav Nezval", - "Žánr: poetický / poetistický román", - "Poprvé vydáno: 1929", - "Děj: Praha 20. let, láska Petra a Lucie", - "Vyprávění: er-forma; poetistická obraznost, hra", - NULL -}; - -static const char *const book_petr_a_lucie_n1[] = { - "Poetismus – radost ze života, město, metafora.", - "Praha jako poetistické jeviště.", - "Láska jako hra a sen.", - "Citlivost vs. realita (nemoc, smrt).", - "Nezval a Devětsil – avantgarda.", - "Téma: láska, mládí, křehkost, obraz.", - NULL -}; - -static const char *const book_petr_a_lucie_n2[] = { - "Petr – mladý muž, zamilovaný.", - "Lucie – dívka, partnerka, křehká.", - "Praha – město procházek a snů.", - "Rodina / okolí – realita.", - "Poetistický svět – barvy, hra.", - "Osud – Luciina nemoc a konec.", - NULL -}; - -static const char *const book_petr_a_lucie_n3[] = { - "Poetismus – avantgardní směr 20. let.", - "Láska jako hra – lehkost i hloubka.", - "Praha – poetistický prostor.", - "Obraz a metafora – Nezvalův styl.", - "Tragický konec – Luciina smrt.", - "Cit – romantika moderní formy.", - NULL -}; - -static const BookNoteSec book_petr_a_lucie_secs[] = { - {"O knize", book_petr_a_lucie_n0}, - {"Doba a svět", book_petr_a_lucie_n1}, - {"Postavy", book_petr_a_lucie_n2}, - {"Klíčové pojmy", book_petr_a_lucie_n3}, -}; - -static const char *const book_poe_povidky_n0[] = { - "Autor: Edgar Allan Poe", - "Žánr: horor, detektivka, groteska (povídky)", - "Poprvé vydáno: různá vydání 19. století", - "Děj: povídky – temná psychika, tajemno", - "Vyprávění: ich/er forma; gotický styl", - NULL -}; - -static const char *const book_poe_povidky_n1[] = { - "Americká romantika 19. století – gotika.", - "Hrůza, vina, monomanie.", - "Detektivní logika (Dupin).", - "Symbolismus (Havran).", - "Smrt, hrobky, mučení.", - "Téma: psychika, strach, rozum vs. šílenství.", - NULL -}; - -static const char *const book_poe_povidky_n2[] = { - "Vypravěč Havran – truchlící muž.", - "Dupin – detektiv (Povídky o skandálu…).", - "Montresor – vrah v Amontillado.", - "Fortunato – oběť.", - "Roderick Usher – poslední z rodu.", - "Beruška – srdce v povídce.", - NULL -}; - -static const char *const book_poe_povidky_n3[] = { - "Gotický horor – hrad, hrob, tma.", - "Detektivní povídka – logika Dupina.", - "Monomanie – posedlost.", - "Symbol – havran „Nevermore“.", - "Princip jednoty účinku – Poe estetika.", - "Psychologický horor.", - NULL -}; - -static const BookNoteSec book_poe_povidky_secs[] = { - {"O knize", book_poe_povidky_n0}, - {"Doba a svět", book_poe_povidky_n1}, - {"Postavy", book_poe_povidky_n2}, - {"Klíčové pojmy", book_poe_povidky_n3}, -}; - -static const char *const book_povidky_z_kapes_n0[] = { - "Autor: Karel Čapek (1890–1938)", - "Žánr: detektivní a humoristické povídky (parodie žánru)", - "Poprvé vydáno: 1929 (z jedné kapsy) a 1932 (z druhé kapsy)", - "Děj: jednotlivé krátké případy; rámec vyprávění u stolu v kavárně", - "Forma: povídkový cyklus – přátelé si vyprávějí „historky z kapes“", - NULL -}; - -static const char *const book_povidky_z_kapes_n1[] = { - "První republika – pražská kavárenská společnost, inteligence.", - "Čapek si hraje s detektivkou: logika vs. náhoda a lidský detail.", - "Humor, humanismus, skepse vůči „stoprocentní“ dedukci.", - "Detektivní linie (komisař Mejzlík) paroduje sherlockovský styl.", - "Vyprávění ve společnosti jako rámec – každá povídka samostatný příběh.", - "Typická pointa: překvapení, vtip, malý lidský motiv rozhodne víc než rozum.", - NULL -}; - -static const char *const book_povidky_z_kapes_n2[] = { - "Vypravěči u stolu – rámec sbírky, přátelé v kavárně.", - "Policejní komisař Mejzlík – detektiv s přehnanou logikou.", - "Pachatelé, svědci a oběti – střídají se v jednotlivých povídkách.", - "Postavy z povídek jako Modrá chrysantéma, Levkoj, Uspání aj.", - "Čtenář – spoluřeší záhadu, Čapek ho často přechytračí.", - "Autorův ironický hlas – přítomný v komentáři k detektivce.", - NULL -}; - -static const char *const book_povidky_z_kapes_n3[] = { - "Parodie detektivky – Čapek demýtizuje geniálního detektiva.", - "Náhoda vs. logika – pravda bývá banálnější než dedukce.", - "Humanismus – zájem o obyčejného člověka, ne jen zločin.", - "Kavárenský rámec – sbližuje vypravěče i čtenáře.", - "Povídka z kapsy – drobný, vtipný příběh k „vytáhnutí“ u stolu.", - "Dvě kapsy – dva svazky, stejný princip, jiné miniaturky.", - NULL -}; - -static const BookNoteSec book_povidky_z_kapes_secs[] = { - {"O knize", book_povidky_z_kapes_n0}, - {"Doba a svět", book_povidky_z_kapes_n1}, - {"Postavy", book_povidky_z_kapes_n2}, - {"Klíčové pojmy", book_povidky_z_kapes_n3}, -}; - -static const char *const book_promena_n0[] = { - "Autor: Franz Kafka", - "Žánr: novela; absurdní / existenciální próza", - "Poprvé vydáno: 1915", - "Děj: byt rodiny Samsových v moderním městě", - "Vyprávění: er-forma; věcný chladný styl vs. hrůza proměny", - NULL -}; - -static const char *const book_promena_n1[] = { - "Počátek 20. století: rodina, práce, byrokracie jako povinnost.", - "Gregor je obchodní cestující a živitel – hodnota člověka = užitečnost.", - "Po proměně v hmyz se stává přítěží a objektem odporu.", - "Měšťanský byt je klec i jeviště rodinné krize.", - "Podnájemníci zhorší tlak na rodinu.", - "Téma: odcizení, vina, dehumanizace.", - NULL -}; - -static const char *const book_promena_n2[] = { - "Gregor Samsa – obchodní cestující proměněný v hmyz.", - "Grete – sestra; nejprve pečuje, později odmítá.", - "Otec – autoritativní, násilný (jablko).", - "Matka – soucit i strach.", - "Podnájemníci – cizí soudci „ostudy“.", - "Prokurista – symbol práce a tlaku.", - NULL -}; - -static const char *const book_promena_n3[] = { - "Proměna – ztráta lidské podoby i společenského místa.", - "Odcizení – cizí sobě i rodině.", - "Užitečnost – člověk = výdělek.", - "Jablko – zranění od otce, symbol viny.", - "Pokoj – izolace za dveřmi.", - "Smrt Gregora – „úleva“ pro rodinu.", - NULL -}; - -static const BookNoteSec book_promena_secs[] = { - {"O knize", book_promena_n0}, - {"Doba a svět", book_promena_n1}, - {"Postavy", book_promena_n2}, - {"Klíčové pojmy", book_promena_n3}, -}; - -static const char *const book_pycha_a_predsudek_n0[] = { - "Autor: Jane Austenová", - "Žánr: společenský / láskopisný román", - "Poprvé vydáno: 1813", - "Děj: anglická venkovská šlechta, rodina Bennettových", - "Vyprávění: er-forma; ironický vypravěč", - NULL -}; - -static const char *const book_pycha_a_predsudek_n1[] = { - "Regency Anglie – třída, sňatek, majetek, mravy.", - "Ženy často závislé na dobré partii.", - "Společenské plesy, návštěvy, pomluvy.", - "Pýcha a předsudek brání Elizabeth a Darcymu.", - "Austen ironicky kritizuje společnost.", - "Téma: láska, sebe poznání, třída.", - NULL -}; - -static const char *const book_pycha_a_predsudek_n2[] = { - "Elizabeth Bennet – bystrá hrdinka, odmítá předsudky.", - "Fitzwilliam Darcy – bohatý aristokrat, zpočátku haughty.", - "Jane Bennet – Elizabethina sestra, laskavá.", - "Charles Bingley – Darcyho přítel, miluje Jane.", - "Pan Wickham – okouzlující, ale nepoctivý.", - "Paní Bennet – matka tlačící na sňatky.", - NULL -}; - -static const char *const book_pycha_a_predsudek_n3[] = { - "Pýcha – Darcyho povýšenost.", - "Předsudek – Elizabethino souzení.", - "Sňatek – ekonomická i emocionální otázka.", - "Třída – bohatství a společenské postavení.", - "Ironie – Austenův styl.", - "Dopis – Darcy vysvětluje Wickhamovu minulost.", - NULL -}; - -static const BookNoteSec book_pycha_a_predsudek_secs[] = { - {"O knize", book_pycha_a_predsudek_n0}, - {"Doba a svět", book_pycha_a_predsudek_n1}, - {"Postavy", book_pycha_a_predsudek_n2}, - {"Klíčové pojmy", book_pycha_a_predsudek_n3}, -}; - -static const char *const book_rur_n0[] = { - "Autor: Karel Čapek", - "Žánr: drama (sci-fi); 3 dějství + předehra", - "Poprvé vydáno: 1920 (premiéra 1921, Národní divadlo)", - "Děj: továrna Rossum's Universal Robots na ostrově", - "Vyprávění: dramatická forma, dialogy", - NULL -}; - -static const char *const book_rur_n1[] = { - "Meziválečí: obavy z techniky, průmyslu a dehumanizace.", - "Slovo „robot“ (od robota = dřina) zavedli bratři Čapkové.", - "Roboti nahrazují lidi v práci i ve válce – lidé leniví.", - "Vzpoura robotů vyhubí lidstvo.", - "Zůstane Alquist a na konci naděje v robotí dvojici.", - "Téma: zodpovědnost vědy, lidskost, práce rukama.", - NULL -}; - -static const char *const book_rur_n2[] = { - "Harry Domin – ředitel R. U. R.", - "Helena Gloryová – idealistka, dcera prezidenta.", - "Dr. Gall – upravuje roboty, dává jim city.", - "Alquist – stavitel, jediný, kdo ještě pracuje rukama.", - "Busman – obchodní ředitel, myslí na zisk.", - "Primus a Helena (roboti) – nový pár na konci.", - NULL -}; - -static const char *const book_rur_n3[] = { - "Robot – umělý dělník; později s duší.", - "R. U. R. – Rossum's Universal Robots.", - "Továrna – hubris vědy a kapitalismu.", - "Vzpoura – důsledek vykořisťování.", - "Lidskost – láska, soucit, manuální práce.", - "Naděje – roboti Primus a Helena milují se.", - NULL -}; - -static const BookNoteSec book_rur_secs[] = { - {"O knize", book_rur_n0}, - {"Doba a svět", book_rur_n1}, - {"Postavy", book_rur_n2}, - {"Klíčové pojmy", book_rur_n3}, -}; - -static const char *const book_revizor_n0[] = { - "Autor: Nikolaj Vasiljevič Gogol", - "Žánr: satirická komedie (drama)", - "Poprvé vydáno: 1836 (premiéra v Petrohradě)", - "Děj: malé provinční městečko, záměna identity", - "Vyprávění: drama, 5 dějství", - NULL -}; - -static const char *const book_revizor_n1[] = { - "Carské Rusko 19. století – korupce úřadů.", - "Městská rada žije strachem z kontroly z Petrohradu.", - "Úplatky, lži a strach z revizora.", - "Chudý úředník Chlestakov využije omyl.", - "Satira na moc, lakotu a servilitu.", - "Známá replika: „Na co se díváte? Je to revizor!“", - NULL -}; - -static const char *const book_revizor_n2[] = { - "Chlestakov – chudý úředník přijatý za revizora.", - "Anton Antonovič Skvoznik-Dmuchanovskij – městský hlava.", - "Bobčinskij a Dobčinskij – statkáři, donáší o „revizorovi“.", - "Osip – Chlestakovův sluha.", - "Artěmij Filippovič Zemljanika – správce nemocnice.", - "Korobkin, Rastakovski – úředníci.", - NULL -}; - -static const char *const book_revizor_n3[] = { - "Revizor – kontrolor ze Sankt Petěrburgu; objekt strachu.", - "Záměna identity – komický i morální jádro.", - "Korupce – úřady nabízejí úplatky.", - "Satira – smích odhaluje hnijící systém.", - "Provincie vs. centrum – moc a strach.", - "Mlčení na konci – „prijímají revizora“ (skutečného).", - NULL -}; - -static const BookNoteSec book_revizor_secs[] = { - {"O knize", book_revizor_n0}, - {"Doba a svět", book_revizor_n1}, - {"Postavy", book_revizor_n2}, - {"Klíčové pojmy", book_revizor_n3}, -}; - -static const char *const book_romeo_a_julie_n0[] = { - "Autor: William Shakespeare", - "Žánr: tragédie (drama)", - "Poprvé vydáno: kolem 1595 (tištěno později)", - "Děj: Verona, spor rodu Montecchi a Capuletů", - "Vyprávění: drama v pěti dějstvích, dialogy a monology", - NULL -}; - -static const char *const book_romeo_a_julie_n1[] = { - "Renesanční Verona – rodové nenávisti a souboje.", - "Láska Romeo a Julie vs. rodinný konflikt.", - "Osud, náhoda a unáhlená rozhodnutí.", - "Mladí proti starším (Romeo, Julie vs. rodiče).", - "Jazyk: básnický, metaforický, kontrastní.", - "Téma: láska, nenávist, smrt, smíření rodů.", - NULL -}; - -static const char *const book_romeo_a_julie_n2[] = { - "Romeo Montecchi – vášnivý mladík, zamilovaný do Julie.", - "Julie Capulet – mladá dívka, statečnější než okolí.", - "Mercutio – Romeův přítel, vtipný, zabit Tybaltem.", - "Tybalt – Julin sestřenec, hašteřivý, zabije Mercutia.", - "Friar Laurence – františkán, sňatku a lektvaru.", - "Nurse – chůva, Julii blízká.", - NULL -}; - -static const char *const book_romeo_a_julie_n3[] = { - "Tragédie – pád hlavních hrdinů.", - "Nenávist rodů – Montecchi vs. Capuletové.", - "Osud (fate) – hvězdy, předtuchy.", - "Lektvar – falešná smrt Julie.", - "Balcony scene – slavný milenecký dialog.", - "Smíření – rodové usmíření až po smrti milenců.", - NULL -}; - -static const BookNoteSec book_romeo_a_julie_secs[] = { - {"O knize", book_romeo_a_julie_n0}, - {"Doba a svět", book_romeo_a_julie_n1}, - {"Postavy", book_romeo_a_julie_n2}, - {"Klíčové pojmy", book_romeo_a_julie_n3}, -}; - -static const char *const book_romeo_julie_a_tma_n0[] = { - "Autor: Jan Otčenášek (1924–1979)", - "Žánr: novela, milostný příběh za okupace", - "Poprvé vydáno: 1962", - "Děj: Praha za protektorátu, léta 1941–1942", - "Vyprávění: er-forma, soustředěný děj kolem Pavla a Ester", - NULL -}; - -static const char *const book_romeo_julie_a_tma_n1[] = { - "Německá okupace, pronásledování Židů, transporty do Terezína.", - "Škola funguje pod dohledem, ale studenti čtou i zakázané texty.", - "Skrývání pronásledovaných je trestné; každý soused může udat.", - "Láska mezi Čechem a Židovkou je vystavena strachu i smrti.", - "Paralela s Shakespearovým Romeem a Julií – milenci proti světu.", - "Tma v názvu = okupace, tajnost i nejistota osudu.", - NULL -}; - -static const char *const book_romeo_julie_a_tma_n2[] = { - "Pavel – gymnazista, zamiluje se do Ester, statečný až do konce.", - "Ester – židovská dívka v utajení u rodiny Sedlákových.", - "Hanka Sedláková – spolužačka, pomáhá skrývat Ester.", - "Petr – Pavlův strýc, účastník odboje, varuje před nebezpečím.", - "Pavelův otec – realista, bojí se následků pro syna i rodinu.", - "Učitelé a spolužáci – rámec školního světa za okupace.", - NULL -}; - -static const char *const book_romeo_julie_a_tma_n3[] = { - "Okupace – totalitní režim, který ničí lidské vztahy.", - "Utajení – Ester žije „v temnu“, bez oficiální identity.", - "Milostná paralela – Romeo a Julie v pražské podobě.", - "Oběť a statečnost – Pavel volí lásku před bezpečím.", - "Transport – symbol konečné ztráty naděje na společný život.", - "Etické dilema rodin – pomoc vs. strach z udání.", - NULL -}; - -static const BookNoteSec book_romeo_julie_a_tma_secs[] = { - {"O knize", book_romeo_julie_a_tma_n0}, - {"Doba a svět", book_romeo_julie_a_tma_n1}, - {"Postavy", book_romeo_julie_a_tma_n2}, - {"Klíčové pojmy", book_romeo_julie_a_tma_n3}, -}; - -static const char *const book_rozmarne_leto_n0[] = { - "Autor: Vladislav Vančura (1891–1942)", - "Žánr: poetická novela, groteska", - "Poprvé vydáno: 1926", - "Děj: léto na venkově u Rybníka, maloměstské prostředí", - "Vyprávění: er-forma, lyrický jazyk, koláž výjevů", - NULL -}; - -static const char *const book_rozmarne_leto_n1[] = { - "Meziválečné Československo, idylické léto plné humoru i tísně.", - "Tři muži – major Hugo, vědec Roch, malíř Hampl – sdílejí dovolenou.", - "Společenské rozdíly, místní pomluvy a letní nálada.", - "Vančura mísí poetiku s groteskními situacemi.", - "Příroda a rybník jako kulisa i symbol klidu.", - "Léto je „rozmarné“ – lehké, ale i nečekaně tragické.", - NULL -}; - -static const char *const book_rozmarne_leto_n2[] = { - "Major Hugo – bývalý důstojník, energický organizátor léta.", - "Roch – vědec, vzdělanec, často terč posměchu.", - "Hampl – malíř, pozorovatel, mírný ironik.", - "Pepča – mladá dívka, oběť utopení.", - "Místní obyvatelé – soudkyňa, farář, sousedé.", - "Tři přátelé tvoří komické i napjaté trojúhelníky.", - NULL -}; - -static const char *const book_rozmarne_leto_n3[] = { - "Groteska – nadsázka, absurdní detaily.", - "Poetika – obrazný, rytmický jazyk Vančury.", - "Léto jako rámec – svoboda vs. společenská klace.", - "Smrt Pepči – náhlý stín v rozmarném ději.", - "Pomluvy – maloměstská morálka.", - "Přátelství tří mužů – generační a charakterový kontrast.", - NULL -}; - -static const BookNoteSec book_rozmarne_leto_secs[] = { - {"O knize", book_rozmarne_leto_n0}, - {"Doba a svět", book_rozmarne_leto_n1}, - {"Postavy", book_rozmarne_leto_n2}, - {"Klíčové pojmy", book_rozmarne_leto_n3}, -}; - -static const char *const book_ruze_pro_algernon_n0[] = { - "Autor: Daniel Keyes (1927–2014)", - "Žánr: sci-fi novela / psychologická próza", - "Poprvé vydáno: 1966 (novela; povídka 1959)", - "Děj: USA, vědecký experiment na inteligenci", - "Forma: deníkové zápisy Charlieho Gordona", - NULL -}; - -static const char *const book_ruze_pro_algernon_n1[] = { - "Společnost hodnotí inteligenci jako měřítko lidské hodnoty.", - "Vědecký experiment na mozku – etické otázky.", - "Charlie začíná jako mentálně postižený, stává se géniem.", - "Osamělost inteligentního člověka mezi bývalými přáteli.", - "Algernon – laboratorní myš jako zrcadlo Charlieho osudu.", - "Příběh varuje před arogancí vědy i lidské krutosti.", - NULL -}; - -static const char *const book_ruze_pro_algernon_n2[] = { - "Charlie Gordon – hlavní hrdina, autora deníku.", - "Algernon – myš, první úspěšný experiment.", - "Dr. Strauss a profesor Nemur – vědci.", - "Alice Kinnian – učitelka, Charlieho opora.", - "Rose Gordon – matka, traumatický vztah k synovi.", - "Kolegové z pekárny – dříve se smějí, později se bojí.", - NULL -}; - -static const char *const book_ruze_pro_algernon_n3[] = { - "Deník – forma ukazuje vývoj jazyka a myšlení.", - "IQ vs. emoční inteligence – Charlie sílí, ale trpí.", - "Algernonův pokles – předzvěst Charlieho konce.", - "Květy pro Algernona – soucit a vděčnost.", - "Etika experimentu – souhlas a informovanost.", - "Osamělost – cena rychlého vědeckého pokroku.", - NULL -}; - -static const BookNoteSec book_ruze_pro_algernon_secs[] = { - {"O knize", book_ruze_pro_algernon_n0}, - {"Doba a svět", book_ruze_pro_algernon_n1}, - {"Postavy", book_ruze_pro_algernon_n2}, - {"Klíčové pojmy", book_ruze_pro_algernon_n3}, -}; - -static const char *const book_saturnin_n0[] = { - "Autor: Zdeněk Jirotka (1911–2003)", - "Žánr: humoristická novela", - "Poprvé vydáno: 1942", - "Děj: pražská rodina a sluha Saturnin", - "Vyprávění: ich-forma vypravěče (syn rodiny)", - NULL -}; - -static const char *const book_saturnin_n1[] = { - "Meziválečná / válečná Praha v lehkém, absurdním světle.", - "Saturnin dělá „všechno jinak“ a rozpoutá chaos.", - "Sousedé, teta a učitel doplňují komické situace.", - "Humor z nedorozumění a vynalézavosti.", - "Rodina se Saturninem musí řešit nečekané problémy.", - "Kniha je cult classic české humoristické prózy.", - NULL -}; - -static const char *const book_saturnin_n2[] = { - "Saturnin – tajemný, vynalézavý sluha, původ nejasný.", - "Vypravěč – mladý člen rodiny, pozorovatel.", - "Teta – bystrá, často v konfliktu se Saturninem.", - "Pan učitel – pedantský, terč satiry.", - "Sousedé – další zdroj komických situací.", - "Milouš – postava spojená s dětmi / lumpárnami.", - NULL -}; - -static const char *const book_saturnin_n3[] = { - "Sluha jako motor děje – Saturnin řídí absurditu.", - "Humor nedorozumění – místo logiky kreativní výmluvy.", - "Pražské prostředí – byt, sousedé, škola.", - "Lumpárny – dětské/nezbedné akce.", - "Rodinná idyla narušená sluhou.", - "Jazyk – hovorové, živé dialogy.", - NULL -}; - -static const BookNoteSec book_saturnin_secs[] = { - {"O knize", book_saturnin_n0}, - {"Doba a svět", book_saturnin_n1}, - {"Postavy", book_saturnin_n2}, - {"Klíčové pojmy", book_saturnin_n3}, -}; - -static const char *const book_sluha_dvou_panu_n0[] = { - "Autor: Carlo Goldoni (1707–1793)", - "Žánr: komedie dell'arte / prozaické drama", - "Poprvé uvedeno: 1746 (revize)", - "Děj: Benátky, sluha slouží dvěma pánům", - "Forma: divadelní hra – dialogy, komické záměny", - NULL -}; - -static const char *const book_sluha_dvou_panu_n1[] = { - "Italská komedie dell'arte – typové postavy, improvizace.", - "Sluha Truffaldino slouží současně dvěma pánům.", - "Záměny dopisů, peněz a identit.", - "Láska služebných párů vs. třídní bariéry.", - "Goldoni reformuje dell'arte směrem k psanému textu.", - "Rychlé tempo, fyzický humor, happy end.", - NULL -}; - -static const char *const book_sluha_dvou_panu_n2[] = { - "Truffaldino – lstivý sluha, slouží Beatrice i Florindovi.", - "Beatrice – dívka v mužském převleku hledá milého.", - "Florindo – benátský milovník Beatrice.", - "Pantalone – lakomý stařec, typ dell'arte.", - "Brighella – hospodský, pomáhá záměnám.", - "Smeraldina – služka, Truffaldinova milá.", - NULL -}; - -static const char *const book_sluha_dvou_panu_n3[] = { - "Commedia dell'arte – masky, typy, slapstick.", - "Dvojí služba – jádro komického konfliktu.", - "Převlek – Beatrice jako „pan Federigo“.", - "Záměny dopisů a zavazadel.", - "Služební láska – Truffaldino a Smeraldina.", - "Goldoni – literární komedie místo čisté improvizace.", - NULL -}; - -static const BookNoteSec book_sluha_dvou_panu_secs[] = { - {"O knize", book_sluha_dvou_panu_n0}, - {"Doba a svět", book_sluha_dvou_panu_n1}, - {"Postavy", book_sluha_dvou_panu_n2}, - {"Klíčové pojmy", book_sluha_dvou_panu_n3}, -}; - -static const char *const book_smrt_krasnych_srncu_n0[] = { - "Autor: Ota Pavel (1930–1973)", - "Žánr: autobiografické povídky / humoristická próza", - "Poprvé vydáno: 1971", - "Děj: vzpomínky na dětství a válku (Příbramsko)", - "Forma: soubor povídek spojených rodinou a přírodou", - NULL -}; - -static const char *const book_smrt_krasnych_srncu_n1[] = { - "Dětství v rodině holiče a rybářských vášní.", - "Protektorát – otec v koncentračním táboře.", - "Příroda, rybaření, sport jako únik i radost.", - "Humor i smutek v paměti na válku.", - "Motiv otce – silný, trpící, milovaný.", - "Titulní povídka o srnách a poválečném lovu.", - NULL -}; - -static const char *const book_smrt_krasnych_srncu_n2[] = { - "Ota (vypravěč) – chlapec, pozorovatel.", - "Otec – holič, rybář, sportovec, v táboře.", - "Maminka – drží rodinu.", - "Bratři – Antonín, Jiří.", - "Srnec / zvěř – symbol krásy i ztráty.", - "Místní rybáři a sousedé.", - NULL -}; - -static const char *const book_smrt_krasnych_srncu_n3[] = { - "Autobiografismus – Pavel píše z vlastní paměti.", - "Rybaření – metafora trpělivosti a štěstí.", - "Koncentrační tábor otce – stín války.", - "Humor dětství – nevinnost vs. realita.", - "Příroda – les, rybníky, srnci.", - "Titul – smrt krásných tvorů, poválečná doba.", - NULL -}; - -static const BookNoteSec book_smrt_krasnych_srncu_secs[] = { - {"O knize", book_smrt_krasnych_srncu_n0}, - {"Doba a svět", book_smrt_krasnych_srncu_n1}, - {"Postavy", book_smrt_krasnych_srncu_n2}, - {"Klíčové pojmy", book_smrt_krasnych_srncu_n3}, -}; - -static const char *const book_sofiina_volba_n0[] = { - "Autor: William Styron (1925–2006)", - "Žánr: psychologický román", - "Poprvé vydáno: 1979", - "Děj: USA po 2. sv. válce, vzpomínky na holocaust", - "Vyprávění: er-forma – Stingo, mladý spisovatel", - NULL -}; - -static const char *const book_sofiina_volba_n1[] = { - "Postava Sophie Zawistowska – polská přeživší Auschwitz.", - "Tajemství „Sofiina volba“ – které dítě poslat na smrt.", - "Vztah Sophie a Nathan Landau – vášnivý, destruktivní.", - "Téma viny, traumatu a antisemitismu v Americe.", - "Gradace k odhalení Sophieina rozhodnutí.", - "Silný etický a historický dopad.", - NULL -}; - -static const char *const book_sofiina_volba_n2[] = { - "Stingo – mladý jižanský spisovatel, vypravěč.", - "Sophie Zawistowska – krásná Polka, traumatizovaná.", - "Nathan Landau – geniální, schizofrenní milenec.", - "Jan a Eva – Sophieina děti v koncentráku.", - "Dr. Blackstock / doktoři – okrajové postavy.", - "Spolubydlící v Brooklynu.", - NULL -}; - -static const char *const book_sofiina_volba_n3[] = { - "Sofiina volba – morální dilema v Auschwitzi.", - "Trauma – noční můry, alkohol, sebepoškozování.", - "Nathan – láska a smrtelné nebezpečí.", - "Holocaust – flashbacky do Polska.", - "Vina přeživšího – proč právě já?", - "Americký South vs. evropská minulost.", - NULL -}; - -static const BookNoteSec book_sofiina_volba_secs[] = { - {"O knize", book_sofiina_volba_n0}, - {"Doba a svět", book_sofiina_volba_n1}, - {"Postavy", book_sofiina_volba_n2}, - {"Klíčové pojmy", book_sofiina_volba_n3}, -}; - -static const char *const book_fuks_n0[] = { - "Autor: Ladislav Fuks (1923–1994)", - "Žánr: psychologický román s prvky grotesky a hororu", - "Poprvé vydáno: 1967", - "Děj: Praha v době protektorátu (konec 30. let)", - "Vyprávění: ich-forma – vypráví sám pan Kopfrkingl", - NULL -}; - -static const char *const book_fuks_n1[] = { - "Děj se odehrává v protektorátu Čechy a Morava za nastupujícího nacismu.", - "Atmosféru tvoří strach, přizpůsobování a touha zalíbit se moci.", - "Krematorium je symbolem smrti a odlidštění.", - "Antisemitismus a árijská ideologie postupně prostupují společnost.", - "Obyčejný úředník se mění v nástroj zla.", - NULL -}; - -static const char *const book_fuks_n2[] = { - "Pan Kopfrkingl – zaměstnanec krematoria, vypravěč a vrah své rodiny.", - "Lakmé – jeho žena, židovského původu.", - "Zina a Mil – jeho děti.", - "Willi Reinke – Němec, který Kopfrkingla přivede k nacismu.", - "Dr. Bettelheim – lékař, s nímž Kopfrkingl rozmlouvá o smrti.", - NULL -}; - -static const char *const book_fuks_n3[] = { - "Krematorium – symbol smrti a zvrácené „očisty“.", - "Kniha mrtvých – tibetský text, který si Kopfrkingl překrucuje.", - "Reinkarnace a „osvobození“ – záminka pro vraždy.", - "Masky a přetvářka – zlo se tváří jako zdvořilost a řád.", - "Groteska a černý humor – hrůza podaná klidným, slavnostním tónem.", - "Voda a Vltava – motiv smrti a plynutí.", - NULL -}; - -static const BookNoteSec book_fuks_secs[] = { - {"O knize", book_fuks_n0}, - {"Doba a svět", book_fuks_n1}, - {"Postavy", book_fuks_n2}, - {"Klíčové motivy", book_fuks_n3}, -}; - -static const char *const book_stare_recke_baje_n0[] = { - "Autor: Eduard Petiška (1924–1987)", - "Žánr: moderní zpracování mýtů", - "Poprvé vydáno: 1959 (sbírka)", - "Děj: antické řecké mýty a pověsti", - "Forma: prózaické převyprávění pro mládež", - NULL -}; - -static const char *const book_stare_recke_baje_n1[] = { - "Od stvoření světa po hrdinské mýty.", - "Olympští bohové – Zeus, Héra, Poseidon…", - "Hrdinové – Herakles, Odysseus, Perseus.", - "Vysvětlení přírodních jevů a morálních lekcí.", - "Petiška modernizuje jazyk, zachovává jádro.", - "Základ antické kultury pro maturitu.", - NULL -}; - -static const char *const book_stare_recke_baje_n2[] = { - "Zeus – vládce bohů.", - "Héra – manželka, žárlivost.", - "Prométheus – oheň pro lidi, trest.", - "Herakles – dvanáct úkolů.", - "Odysseus – cesta domů z Troje.", - "Perseus, Theseus, Orfeus aj.", - NULL -}; - -static const char *const book_stare_recke_baje_n3[] = { - "Mýtus – posvátný příběh vysvětlující svět.", - "Hubris – pýcha trestaná bohy.", - "Moira – osud.", - "Hrdinské cesty – zkoušky charakteru.", - "Bohové antropomorfní – lidské vášně.", - "Petiška – srozumitelné vyprávění.", - NULL -}; - -static const BookNoteSec book_stare_recke_baje_secs[] = { - {"O knize", book_stare_recke_baje_n0}, - {"Doba a svět", book_stare_recke_baje_n1}, - {"Postavy", book_stare_recke_baje_n2}, - {"Klíčové pojmy", book_stare_recke_baje_n3}, -}; - -static const char *const book_starec_a_more_n0[] = { - "Autor: Ernest Hemingway (1899–1961)", - "Žánr: novela", - "Poprvé vydáno: 1952", - "Děj: kubánský rybář Santiago a moře", - "Vyprávění: er-forma, středně objektivní styl", - NULL -}; - -static const char *const book_starec_a_more_n1[] = { - "Santiago – starý rybář v smůle.", - "Souboj s obří marlinou na otevřeném moři.", - "Téma houževnatosti, důstojnosti, osamění.", - "Hemingwayův „kód hrdiny“ – čest i v porážce.", - "Shoři – chlapec, který rybáře miluje.", - "Symbolika moře, lva ze snů.", - NULL -}; - -static const char *const book_starec_a_more_n2[] = { - "Santiago – stařec, rybář.", - "Manolin (Shoři) – mladý pomocník.", - "Marlin – obří ryba, soupeř.", - "Žraloci – ničí úlovek.", - "Rybáři v přístavu – komunita.", - "Moře – pole i protivník.", - NULL -}; - -static const char *const book_starec_a_more_n3[] = { - "Kód hrdiny – statečnost tváří v tvář porážce.", - "Marlin – krása, síla, respekt.", - "Žraloci – nevyhnutelná ztráta.", - "Lvi ve snu – mládí a síla.", - "Osamění – starý muž na moři.", - "„Člověk není stvořen pro porážku“.", - NULL -}; - -static const BookNoteSec book_starec_a_more_secs[] = { - {"O knize", book_starec_a_more_n0}, - {"Doba a svět", book_starec_a_more_n1}, - {"Postavy", book_starec_a_more_n2}, - {"Klíčové pojmy", book_starec_a_more_n3}, -}; - -static const char *const book_svaty_xaverius_n0[] = { - "Autor: Jakub Arbes (1840–1914)", - "Žánr: historicko-romantický román", - "Poprvé vydáno: 1869 (román)", - "Děj: 16.–17. st., cesty sv. Františka Xaverského", - "Forma: epická próza s romantickými prvky", - NULL -}; - -static const char *const book_svaty_xaverius_n1[] = { - "František Xaverský – jezuitský misionář v Asii.", - "Arbes kombinuje historii, dobrodružství a idealismus.", - "Romantický hrdina šíří křesťanství.", - "Exotické prostředí – Indie, Japonsko, Maluku.", - "Vzory českého romantismu a pokrokové myšlenky.", - "Dílo je méně čtené, ale maturitní klasika.", - NULL -}; - -static const char *const book_svaty_xaverius_n2[] = { - "František Xaverský – hlavní hrdina, světec.", - "Ignác z Loyoly – zakladatel jezuitů.", - "Místní vládci a obyvatelé Asie.", - "Arbesův vypravěčský styl – barvitý.", - "Nepřátelé víry – pronásledování.", - "Společníci misie.", - NULL -}; - -static const char *const book_svaty_xaverius_n3[] = { - "Misionářství – šíření víry v exotickém světě.", - "Romantismus – idealizace, dobrodružství.", - "Historická postava – reálný Xaverský (1506–1552).", - "Kulturní střet Evropy a Asie.", - "Oběť a oddanost – světectví.", - "Arbes – pokrokový publicista.", - NULL -}; - -static const BookNoteSec book_svaty_xaverius_secs[] = { - {"O knize", book_svaty_xaverius_n0}, - {"Doba a svět", book_svaty_xaverius_n1}, - {"Postavy", book_svaty_xaverius_n2}, - {"Klíčové pojmy", book_svaty_xaverius_n3}, -}; - -static const char *const book_tereza_raquinova_n0[] = { - "Autor: Émile Zola (1840–1902)", - "Žánr: naturalistický román", - "Poprvé vydáno: 1867", - "Děj: Paříž, obchod s galanterii u Seiny", - "Vyprávění: er-forma, determinismus, psychologický tlak", - NULL -}; - -static const char *const book_tereza_raquinova_n1[] = { - "Tereza žije s manželstvím s chromým Camillem a tchyní.", - "Milostná aféra s Laurentem – společný zločin.", - "Utopení Camilla – vina a noční můry.", - "Sňatek Terezy a Laurenta – peklo místo štěstí.", - "Mamka Raquinová – němá svědkyně.", - "Naturalismus – prostředí a pudy řídí osud.", - NULL -}; - -static const char *const book_tereza_raquinova_n2[] = { - "Thérèse Raquin – hlavní hrdinka, utlačovaná, vášnivá.", - "Camille Raquin – nemotorný, slabý manžel.", - "Laurent – Laurentova touha po Tereze, lenoch.", - "Madame Raquin – matka Camilla, majitelka obchodu.", - "Michaud, Grivet – pravidelní hosté domu.", - "Policie / soud – hrozba odhalení.", - NULL -}; - -static const char *const book_tereza_raquinova_n3[] = { - "Naturalismus – člověk produkt dědičnosti a prostředí.", - "Criminelles trio – vražda z vášně.", - "Vina – halucinace mrtvého Camilla.", - "Mamka jako soudce – němý výčitka.", - "Seina – místo vraždy.", - "Determinismus – nelze uniknout následkům.", - NULL -}; - -static const BookNoteSec book_tereza_raquinova_secs[] = { - {"O knize", book_tereza_raquinova_n0}, - {"Doba a svět", book_tereza_raquinova_n1}, - {"Postavy", book_tereza_raquinova_n2}, - {"Klíčové pojmy", book_tereza_raquinova_n3}, -}; - -static const char *const book_tezka_hodina_n0[] = { - "Autor: Jiří Wolker (1900–1924)", - "Žánr: lyrická poezie, proletářská", - "Poprvé vydáno: 1922", - "Děj: reflexe války, revoluce, sociální bídy", - "Forma: básnické sbírky – volný verš i rým", - NULL -}; - -static const char *const book_tezka_hodina_n1[] = { - "Wolker – mladý komunistický básník.", - "Těžká hodina – metafora krizových momentů.", - "Témata: chudoba, válka, naděje proletariátu.", - "Influence symbolistů i moderny.", - "Předčasná smrt – tuberkulóza.", - "Sbírka Host do domu souvisí s tvorbou.", - NULL -}; - -static const char *const book_tezka_hodina_n2[] = { - "Jiří Wolker – básník, publicista.", - "Proletář / dělník v básních.", - "Matka, děti, chudina – postavy lyriky.", - "Revolutionary naděje – budoucnost.", - "Příroda jako kontrast městu.", - "Symbolická hodina zkoušky.", - NULL -}; - -static const char *const book_tezka_hodina_n3[] = { - "Proletářská poezie – třídní solidarita.", - "Těžká hodina – čas zkoušky, bolesti.", - "Válka – zklamání, utrpení.", - "Naděje – světlá budoucnost.", - "Symbolismus – obrazy, metafory.", - "Mladá smrt autora – mýtus.", - NULL -}; - -static const BookNoteSec book_tezka_hodina_secs[] = { - {"O knize", book_tezka_hodina_n0}, - {"Doba a svět", book_tezka_hodina_n1}, - {"Postavy", book_tezka_hodina_n2}, - {"Klíčové pojmy", book_tezka_hodina_n3}, -}; - -static const char *const book_tyrolske_elegie_n0[] = { - "Autor: Karel Havlíček Borovský (1821–1856)", - "Žánr: satirická politická poezie", - "Poprvé vydáno: 1855 (Tábor)", - "Děj: reakce na potlačení revoluce 1848–49", - "Forma: elegie – ironické, kritické básně", - NULL -}; - -static const char *const book_tyrolske_elegie_n1[] = { - "Havlíček – publicista, satirik, národní buditel.", - "Tyrolské elegie – posměch Rakousku po revoluci.", - "Napoleon III., Habsburkové, reakce.", - "Exil v Brixenu / Tyrolsko – autobiografický rámec.", - "Jazyk – hovorový, ironický, úderný.", - "Věznění a cenzura – Havlíček jako symbol odporu.", - NULL -}; - -static const char *const book_tyrolske_elegie_n2[] = { - "Karel Havlíček Borovský – básník, novinář.", - "Císař František Josef – terč satiry.", - "Rakouská monarchie – útlak.", - "Český národ – addresát naděje.", - "Napoleon III. – politické aluze.", - "Satirické personifikace.", - NULL -}; - -static const char *const book_tyrolske_elegie_n3[] = { - "Satira – výsměch moci.", - "Elegie – ironicky pojatý žánr.", - "Revolution 1848 – zmařená naděje.", - "Exil – zkušenost autora.", - "Národní obrození – kontext.", - "Publicistická funkce poezie.", - NULL -}; - -static const BookNoteSec book_tyrolske_elegie_secs[] = { - {"O knize", book_tyrolske_elegie_n0}, - {"Doba a svět", book_tyrolske_elegie_n1}, - {"Postavy", book_tyrolske_elegie_n2}, - {"Klíčové pojmy", book_tyrolske_elegie_n3}, -}; - -static const char *const book_valka_s_mloky_n0[] = { - "Autor: Karel Čapek (1890–1938)", - "Žánr: antiutopická satira / novela", - "Poprvé vydáno: 1936", - "Děj: svět a obchod s mloky (salamany)", - "Forma: koláž – články, vědecké zprávy, dialogy", - NULL -}; - -static const char *const book_valka_s_mloky_n1[] = { - "Inteligentní mloci na Tahiti – obchodní zázrak.", - "Civilizace mloky roste – hrozba pro lidstvo.", - "Satira fašismu, kapitalismu, militarismu.", - "Přímá paralela s hitlerovským Německem.", - "Čapek varuje před lidskou chamtivostí.", - "Konec – válka s mloky, jaderná hrozba.", - NULL -}; - -static const char *const book_valka_s_mloky_n2[] = { - "Pan Bondy – podnikatel s mloky.", - "Captain van Toch – objevitel.", - "Mloci – inteligentní, organizovaní.", - "Vědci, politici – krátkozrací.", - "Narrator / kolážní hlasy.", - "Lidstvo jako sebevrah.", - NULL -}; - -static const char *const book_valka_s_mloky_n3[] = { - "Salamandři / mloci – alegorie totalitního národa.", - "Koláž – montáž různých stylů.", - "Satira – groteskní eskalace.", - "Fašismus – uniformy, mluví, armáda mloků.", - "Ekonomie – mloci jako zboží a vojáci.", - "Varování před zneužitím vědy.", - NULL -}; - -static const BookNoteSec book_valka_s_mloky_secs[] = { - {"O knize", book_valka_s_mloky_n0}, - {"Doba a svět", book_valka_s_mloky_n1}, - {"Postavy", book_valka_s_mloky_n2}, - {"Klíčové pojmy", book_valka_s_mloky_n3}, -}; - -static const char *const book_velky_cirkus_n0[] = { - "Autor: Pierre Clostermann (1921–2006)", - "Žánr: válečné memoáry / autobiografická próza", - "Poprvé vydáno: 1948 (Le Grand Cirque)", - "Děj: 2. sv. válka, RAF, letecké souboje", - "Forma: ich-forma – zápisky francouzského stíhače", - NULL -}; - -static const char *const book_velky_cirkus_n1[] = { - "Clostermann – Francouz v britském RAF.", - "Stíhací letouny Spitfire, Typhoon.", - "Intenzita vzdušných bitev nad Evropou.", - "Strach, únava, kamarádství pilotů.", - "Velký cirkus = metafora bojiště nebe.", - "Válečná autenticita bez glorifikace.", - NULL -}; - -static const char *const book_velky_cirkus_n2[] = { - "Pierre Clostermann – pilot, vypravěč.", - "Spolubojovníci RAF – mezinárodní posádka.", - "Nepřátelské letectvo – Luftwaffe.", - "Velitelé a ground crew.", - "Civilní oběti bombardování.", - "Clostermann po válce – politik, pilot.", - NULL -}; - -static const char *const book_velky_cirkus_n3[] = { - "RAF – britské letectvo, spojenci.", - "Stíhačka – osobní zbraň i past.", - "Velký cirkus – metafora chaosu nebe.", - "Letecká válka – technika a odvaha.", - "Memoáry – subjektivní pravda.", - "Francouz v exilové armádě.", - NULL -}; - -static const BookNoteSec book_velky_cirkus_secs[] = { - {"O knize", book_velky_cirkus_n0}, - {"Doba a svět", book_velky_cirkus_n1}, - {"Postavy", book_velky_cirkus_n2}, - {"Klíčové pojmy", book_velky_cirkus_n3}, -}; - -static const char *const book_velky_gatsby_n0[] = { - "Autor: F. Scott Fitzgerald (1896–1940)", - "Žánr: modernistický román", - "Poprvé vydáno: 1925", - "Děj: Long Island, New York, „roaring twenties“", - "Vyprávění: ich-forma Nicka Carrawaye", - NULL -}; - -static const char *const book_velky_gatsby_n1[] = { - "Americký sen – bohatství, láska, iluze.", - "Jay Gatsby – tajemný milionář, párty.", - "Daisy Buchanan – dávná láska, vdaná za Toma.", - "Zelené světlo – symbol touhy.", - "Tragédie – Myrtle, Wilson, Gatsbyho smrt.", - "Kritika prázdného luxusu jazz age.", - NULL -}; - -static const char *const book_velky_gatsby_n2[] = { - "Jay Gatsby (James Gatz) – hlavní hrdina.", - "Nick Carraway – vypravěč, soused.", - "Daisy Buchanan – milovaná žena.", - "Tom Buchanan – bohatý, arogantní manžel.", - "Jordan Baker – golfistka, Nickova přítelkyně.", - "Myrtle a George Wilson – tragické vedlejší postavy.", - NULL -}; - -static const char *const book_velky_gatsby_n3[] = { - "Americký sen – slib úspěchu.", - "Zelené světlo na konci Daisyina doku.", - "Nové vs. staré peníze – East/West Egg.", - "Párty – maska osamělosti.", - "Iluze – Gatsby miluje idealizovanou Daisy.", - "Oko doktora T. J. Eckleburga – symbol.", - NULL -}; - -static const BookNoteSec book_velky_gatsby_secs[] = { - {"O knize", book_velky_gatsby_n0}, - {"Doba a svět", book_velky_gatsby_n1}, - {"Postavy", book_velky_gatsby_n2}, - {"Klíčové pojmy", book_velky_gatsby_n3}, -}; - -static const char *const book_tridni_kniha_n0[] = { - "Autoři: Ladislav Smoljak, Zdeněk Svěrák (Divadlo Járy Cimrmana)", - "Žánr: divadelní komedie", - "Poprvé uvedeno: 1967 (Cimrmanovo divadlo)", - "Děj: škola, vyšetřování zmizelé třídní knihy", - "Forma: dialogy, absurdní vyšetřování", - NULL -}; - -static const char *const book_tridni_kniha_n1[] = { - "Parodie detektivky v učitelské sborovně.", - "Třídní kniha – symbol školního řádu.", - "Cimrmanovský humor – malichernost vs. velkolepost.", - "Učitelé jako podezřelí i vyšetřovatelé.", - "Satira byrokracie a autority.", - "Jazykové hříčky Smoljaka a Svěráka.", - NULL -}; - -static const char *const book_tridni_kniha_n2[] = { - "Ředitel školy – vede vyšetřování.", - "Učitel Nechleb aj. – komické figury.", - "Učitelé sborovny – rivalita.", - "Jára Cimrman – rámec divadla (mýtus).", - "Žáci – nepřítomní, ale důvod knihy.", - "Vyšetřovatelé absurdní logiky.", - NULL -}; - -static const char *const book_tridni_kniha_n3[] = { - "Třídní kniha – záznam žáků, předmět sporu.", - "Parodie krimi – ztráta knihy jako zločin.", - "Cimrmanologie – fiktivní věda.", - "Sborovna – uzavřený svět.", - "Humor hlášek – jazyková komika.", - "Byrokracie – pravidlo nad smysl.", - NULL -}; - -static const BookNoteSec book_tridni_kniha_secs[] = { - {"O knize", book_tridni_kniha_n0}, - {"Doba a svět", book_tridni_kniha_n1}, - {"Postavy", book_tridni_kniha_n2}, - {"Klíčové pojmy", book_tridni_kniha_n3}, -}; - -static const char *const book_zabijak_n0[] = { - "Autor: Émile Zola (1840–1902)", - "Žánr: naturalistický román", - "Poprvé vydáno: 1870", - "Děj: Les Halles, pařížská tržnice, maso", - "Vyprávění: er-forma, determinismus, sociální prostředí", - NULL -}; - -static const char *const book_zabijak_n1[] = { - "Florent – bývalý učitel, údajný vrah.", - "Tržnice Halles – pach, maso, dělníci.", - "Florent vs. Lisa – tchyně, konflikt.", - "Politické sny – revoluce, represe.", - "Naturalismus – prostředí formuje charakter.", - "Titul Zabiják – Florentova minulost.", - NULL -}; - -static const char *const book_zabijak_n2[] = { - "Florent – hlavní hrdina, „zabiják“.", - "Lisa Quenu – tchyně, majitelka.", - "Quenu – řezník, manžel.", - "La Normande, Les Halles dělníci.", - "Police, revolucionáři.", - "Paříž – městský organismus.", - NULL -}; - -static const char *const book_zabijak_n3[] = { - "Naturalismus – dědictvost a prostředí.", - "Halles – symbol kapitalismu a těla.", - "Maso – metafora brutality.", - "Florent – sny o spravedlnosti.", - "Determinismus – osud z ložnice vraždy.", - "Zola – dokumentární detail trhu.", - NULL -}; - -static const BookNoteSec book_zabijak_secs[] = { - {"O knize", book_zabijak_n0}, - {"Doba a svět", book_zabijak_n1}, - {"Postavy", book_zabijak_n2}, - {"Klíčové pojmy", book_zabijak_n3}, -}; - -static const char *const book_zbabelci_n0[] = { - "Autor: Josef Škvorecký (1924–2012)", - "Žánr: autobiograficky laděný román", - "Poprvé vydáno: 1958 (v exilu)", - "Děj: květen 1945, Náchodsko, konec války", - "Vyprávění: er-forma – Danny Smiřický", - NULL -}; - -static const char *const book_zbabelci_n1[] = { - "Danny – gymnazista, jazz, holky, strach z války.", - "Nacisté ustupují, partyzáni, chaos osvobození.", - "Motiv zbabělosti vs. odvahy – ironie titulu.", - "Láska k jazzu a americké kultuře.", - "Škvorecký – censorship, později exil.", - "Jazyk hovorový, generační perspektiva.", - NULL -}; - -static const char *const book_zbabelci_n2[] = { - "Danny Smiřický – vypravěč, student.", - "Lída, Irena – dívky.", - "Němečtí vojáci, partyzáni.", - "Dannyho rodiče, učitelé.", - "Konopný – postava okolí.", - "Město Náchod – prostředí.", - NULL -}; - -static const char *const book_zbabelci_n3[] = { - "Květen 1945 – konec okupace.", - "Jazz – symbol svobody a identity.", - "Zbabělci – sebeironie, strach mládí.", - "Erotika a válka – kontrast.", - "Cenzura – kniha u nás později.", - "Exilový autor – svoboda slova.", - NULL -}; - -static const BookNoteSec book_zbabelci_secs[] = { - {"O knize", book_zbabelci_n0}, - {"Doba a svět", book_zbabelci_n1}, - {"Postavy", book_zbabelci_n2}, - {"Klíčové pojmy", book_zbabelci_n3}, -}; - -static const char *const book_zert_n0[] = { - "Autor: Milan Kundera (1929–2023)", - "Žánr: philosophický román", - "Poprvé vydáno: 1967", - "Děj: Československo 50.–60. let, pomsta za žert", - "Vyprávění: er-forma, retrospektivy, komentáře autora", - NULL -}; - -static const char *const book_zert_n1[] = { - "Ludvík Jahn – student, pošle žertovný dopis.", - "Poslanec Pavel Zeman – trest, vyhoštění z KSČ.", - "Pomsta na Zemanově milence Markétě.", - "Téma historie, osudu, ironie.", - "Kundera – formy románu, existenciální otázky.", - "Normalizace – kniha rezonovala i později.", - NULL -}; - -static const char *const book_zert_n2[] = { - "Ludvík Jahn – hlavní hrdina.", - "Markéta – Zemanova milenka, pomsta.", - "Pavel Zeman – poslanec, oběť žertu.", - "Kostra, Helena – další postavy.", - "Autorův komentář – rovina vypravěče.", - "Studenti, politická komise.", - NULL -}; - -static const char *const book_zert_n3[] = { - "Žert – drobnost s fatálními následky.", - "Komunistický režim 50. let.", - "Pomsta – kruhové dějiny.", - "Láska a moc.", - "Ironie osudu – Ludvík nevyhrává.", - "Kundera – román jako dialog s čtenářem.", - NULL -}; - -static const BookNoteSec book_zert_secs[] = { - {"O knize", book_zert_n0}, - {"Doba a svět", book_zert_n1}, - {"Postavy", book_zert_n2}, - {"Klíčové pojmy", book_zert_n3}, -}; - -static const BookNotePack book_note_packs[BOOK_NODES] = { - {book_1984_secs, 4}, - {book_fahrenheit451_secs, 4}, - {book_audience_secs, 4}, - {book_bajecna_leta_secs, 4}, - {book_bidnici_secs, 4}, - {book_bila_nemoc_secs, 4}, - {book_bylo_nas_pet_secs, 4}, - {book_cekani_na_godota_secs, 4}, - {book_ceske_nebe_secs, 4}, - {book_dekameron_secs, 4}, - {book_den_trifidu_secs, 4}, - {book_denik_anny_frankove_secs, 4}, - {book_jekyll_hyde_secs, 4}, - {book_edison_secs, 4}, - {book_farma_zvirat_secs, 4}, - {book_gulliverovy_cesty_secs, 4}, - {book_hamlet_secs, 4}, - {book_havran_secs, 4}, - {book_hladove_hry_secs, 4}, - {book_hlava_xxii_secs, 4}, - {book_chram_matky_bozi_secs, 4}, - {book_jak_jsem_vyhral_valku_secs, 4}, - {book_jana_eyrova_secs, 4}, - {book_ivan_denisovic_secs, 4}, - {book_jmeno_ruze_secs, 4}, - {book_kalibuv_zlocin_secs, 4}, - {book_kniska_karla_kryla_secs, 4}, - {book_komu_zvoni_hrana_secs, 4}, - {book_kral_oidipus_secs, 4}, - {book_krysar_secs, 4}, - {book_kulicka_secs, 4}, - {book_kvety_zla_secs, 4}, - {book_kytice_secs, 4}, - {book_lakomec_secs, 4}, - {book_lolita_secs, 4}, - {book_maj_secs, 4}, - {book_maly_princ_secs, 4}, - {book_marysa_secs, 4}, - {book_modlitba_pro_katerinu_secs, 4}, - {book_most_kwai_secs, 4}, - {book_stanice_zoo_secs, 4}, - {book_na_ceste_secs, 4}, - {book_na_zapadni_fronte_secs, 4}, - {book_navsteva_stare_damy_secs, 4}, - {book_nebe_nezna_vyvolenych_secs, 4}, - {book_o_mysich_a_lidech_secs, 4}, - {book_obraz_doriana_graye_secs, 4}, - {book_obsluhoval_jsem_secs, 4}, - {book_oliver_twist_secs, 4}, - {book_ostre_sledovane_vlaky_secs, 4}, - {book_svejk_secs, 4}, - {book_pan_much_secs, 4}, - {book_pan_prstenu_secs, 4}, - {book_petr_a_lucie_secs, 4}, - {book_poe_povidky_secs, 4}, - {book_povidky_z_kapes_secs, 4}, - {book_promena_secs, 4}, - {book_pycha_a_predsudek_secs, 4}, - {book_rur_secs, 4}, - {book_revizor_secs, 4}, - {book_romeo_a_julie_secs, 4}, - {book_romeo_julie_a_tma_secs, 4}, - {book_rozmarne_leto_secs, 4}, - {book_ruze_pro_algernon_secs, 4}, - {book_saturnin_secs, 4}, - {book_sluha_dvou_panu_secs, 4}, - {book_smrt_krasnych_srncu_secs, 4}, - {book_sofiina_volba_secs, 4}, - {book_fuks_secs, 4}, - {book_stare_recke_baje_secs, 4}, - {book_starec_a_more_secs, 4}, - {book_svaty_xaverius_secs, 4}, - {book_tereza_raquinova_secs, 4}, - {book_tezka_hodina_secs, 4}, - {book_tyrolske_elegie_secs, 4}, - {book_valka_s_mloky_secs, 4}, - {book_velky_cirkus_secs, 4}, - {book_velky_gatsby_secs, 4}, - {book_tridni_kniha_secs, 4}, - {book_zabijak_secs, 4}, - {book_zbabelci_secs, 4}, - {book_zert_secs, 4} -}; - diff --git a/src/cetba_catalog.inc b/src/cetba_catalog.inc deleted file mode 100644 index 3a861f6..0000000 --- a/src/cetba_catalog.inc +++ /dev/null @@ -1,98 +0,0 @@ -/* Generated from data/cetba-catalog.json – do not edit by hand. */ -#define BOOK_NODES 82 - -typedef struct { - const char *title; - const char *target; - const char *author; - const char *work; - const char *genre; - const char *translator; - int full; -} BookDef; - -static const BookDef book_defs[BOOK_NODES] = { - {"George Orwell – 1984", "cetba1984", "George Orwell", "1984", "Próza", "Šimečková", 1}, - {"Ray Bradbury – 451 stupňů Fahrenheita", "cetbastub", "Ray Bradbury", "451 stupňů Fahrenheita", "Próza", "Nezval", 0}, - {"Václav Havel – Audience", "cetbastub", "Václav Havel", "Audience", "Drama", NULL, 0}, - {"Michal Viewegh – Báječná léta pod psa", "cetbastub", "Michal Viewegh", "Báječná léta pod psa", "Próza", NULL, 0}, - {"Victor Hugo – Bídníci", "cetbastub", "Victor Hugo", "Bídníci", "Próza", "Pavlousková", 0}, - {"Karel Čapek – Bílá nemoc", "cetbastub", "Karel Čapek", "Bílá nemoc", "Drama", NULL, 0}, - {"Karel Poláček – Bylo nás pět", "cetbastub", "Karel Poláček", "Bylo nás pět", "Próza", NULL, 0}, - {"Samuel Beckett – Čekání na Godota", "cetbastub", "Samuel Beckett", "Čekání na Godota", "Drama", "Ouředník", 0}, - {"Zdeněk Svěrák, Ladislav Smoljak – České nebe", "cetbastub", "Zdeněk Svěrák, Ladislav Smoljak", "České nebe", "Drama", NULL, 0}, - {"Giovanni Boccaccio – Dekameron", "cetbastub", "Giovanni Boccaccio", "Dekameron", "Próza", "Krátký", 0}, - {"John Wyndham – Den trifidů", "cetbastub", "John Wyndham", "Den trifidů", "Próza", "Kořán", 0}, - {"Anne Franková – Deník Anne Frankové", "cetbastub", "Anne Franková", "Deník Anne Frankové", "Próza", NULL, 0}, - {"Robert Louis Stevenson – Dr. Jekyll a Mr. Hyde", "cetbastub", "Robert Louis Stevenson", "Dr. Jekyll a Mr. Hyde", "Próza", "Kořán", 0}, - {"Vítězslav Nezval – Edison", "cetbastub", "Vítězslav Nezval", "Edison", "Poezie", NULL, 0}, - {"George Orwell – Farma zvířat", "cetbastub", "George Orwell", "Farma zvířat", "Próza", "Gössell", 0}, - {"Jonathan Swift – Gulliverovy cesty", "cetbastub", "Jonathan Swift", "Gulliverovy cesty", "Próza", "Skoumal", 0}, - {"William Shakespeare – Hamlet", "cetbastub", "William Shakespeare", "Hamlet", "Drama", "Nevrla", 0}, - {"Edgar Allan Poe – Havran", "cetbastub", "Edgar Allan Poe", "Havran", "Poezie", NULL, 0}, - {"Suzanne Collins – Hladové hry – I. Aréna smrti", "cetbastub", "Suzanne Collins", "Hladové hry – I. Aréna smrti", "Próza", "Dušek", 0}, - {"Joseph Heller – Hlava XXII", "cetbastub", "Joseph Heller", "Hlava XXII", "Próza", "Jindra", 0}, - {"Victor Hugo – Chrám Matky Boží", "cetbastub", "Victor Hugo", "Chrám Matky Boží", "Próza", "Tomášková", 0}, - {"Patrick Ryan – Jak jsem vyhrál válku", "cetbastub", "Patrick Ryan", "Jak jsem vyhrál válku", "Próza", "Vrba", 0}, - {"Charlotte Brontëová – Jana Eyrová", "cetbastub", "Charlotte Brontëová", "Jana Eyrová", "Próza", "Polák", 0}, - {"Alexandr Solženicyn – Jeden den Ivana Denisoviče", "cetbastub", "Alexandr Solženicyn", "Jeden den Ivana Denisoviče", "Próza", "Machonin, Nováková", 0}, - {"Umberto Eco – Jméno růže", "cetbastub", "Umberto Eco", "Jméno růže", "Próza", "Frýbort", 0}, - {"Karel Václav Rais – Kalibův zločin", "cetbastub", "Karel Václav Rais", "Kalibův zločin", "Próza", NULL, 0}, - {"Karel Kryl – Kníška Karla Kryla", "cetbastub", "Karel Kryl", "Kníška Karla Kryla", "Poezie", NULL, 0}, - {"Ernest Hemingway – Komu zvoní hrana", "cetbastub", "Ernest Hemingway", "Komu zvoní hrana", "Próza", "Valja, Kobík", 0}, - {"Sofoklés – Král Oidipus", "cetbastub", "Sofoklés", "Král Oidipus", "Drama", "Stiebitz", 0}, - {"Viktor Dyk – Krysař", "cetbastub", "Viktor Dyk", "Krysař", "Próza", NULL, 0}, - {"Guy de Maupassant – Kulička", "cetbastub", "Guy de Maupassant", "Kulička", "Próza", "Guth", 0}, - {"Charles Baudelaire – Květy zla", "cetbastub", "Charles Baudelaire", "Květy zla", "Poezie", "Nezval", 0}, - {"Karel Jaromír Erben – Kytice", "cetbastub", "Karel Jaromír Erben", "Kytice", "Poezie", NULL, 0}, - {"Molière – Lakomec", "cetbastub", "Molière", "Lakomec", "Drama", "Mikeš", 0}, - {"Vladimir Nabokov – Lolita", "cetbastub", "Vladimir Nabokov", "Lolita", "Próza", "Kořínek", 0}, - {"Karel Hynek Mácha – Máj", "cetbastub", "Karel Hynek Mácha", "Máj", "Poezie", NULL, 0}, - {"Antoine de Saint-Exupéry – Malý princ", "cetbastub", "Antoine de Saint-Exupéry", "Malý princ", "Próza", "Stavinohová", 0}, - {"Alois Mrštík, Vilém Mrštík – Maryša", "cetbastub", "Alois Mrštík, Vilém Mrštík", "Maryša", "Drama", NULL, 0}, - {"Arnošt Lustig – Modlitba pro Kateřinu Horovitzovou", "cetbastub", "Arnošt Lustig", "Modlitba pro Kateřinu Horovitzovou", "Próza", NULL, 0}, - {"Pierre Boulle – Most přes řeku Kwai", "cetbastub", "Pierre Boulle", "Most přes řeku Kwai", "Próza", "Šup", 0}, - {"Christiane F. – My děti ze stanice ZOO", "cetbastub", "Christiane F.", "My děti ze stanice ZOO", "Próza", "Soukupová", 0}, - {"Jack Kerouac – Na cestě", "cetbastub", "Jack Kerouac", "Na cestě", "Próza", "Popel", 0}, - {"Erich Maria Remarque – Na západní frontě klid", "cetbastub", "Erich Maria Remarque", "Na západní frontě klid", "Próza", "Gel", 0}, - {"Friedrich Dürrenmatt – Návštěva staré dámy", "cetbastub", "Friedrich Dürrenmatt", "Návštěva staré dámy", "Drama", NULL, 0}, - {"Erich Maria Remarque – Nebe nezná vyvolených", "cetbastub", "Erich Maria Remarque", "Nebe nezná vyvolených", "Próza", "V. a K. Holubovi", 0}, - {"John Steinbeck – O myších a lidech", "cetbastub", "John Steinbeck", "O myších a lidech", "Próza", "Vendyš", 0}, - {"Oscar Wilde – Obraz Doriana Graye", "cetbastub", "Oscar Wilde", "Obraz Doriana Graye", "Próza", "Novák", 0}, - {"Bohumil Hrabal – Obsluhoval jsem anglického krále", "cetbastub", "Bohumil Hrabal", "Obsluhoval jsem anglického krále", "Próza", NULL, 0}, - {"Charles Dickens – Oliver Twist", "cetbastub", "Charles Dickens", "Oliver Twist", "Próza", "E. a E. Tilschovi", 0}, - {"Bohumil Hrabal – Ostře sledované vlaky", "cetbastub", "Bohumil Hrabal", "Ostře sledované vlaky", "Próza", NULL, 0}, - {"Jaroslav Hašek – Osudy dobrého vojáka Švejka za světové války", "cetbastub", "Jaroslav Hašek", "Osudy dobrého vojáka Švejka za světové války", "Próza", NULL, 0}, - {"William Golding – Pán much", "cetbastub", "William Golding", "Pán much", "Próza", "Kovályová", 0}, - {"J. R. R. Tolkien – Pán prstenů – Společenstvo prstenu", "cetbastub", "J. R. R. Tolkien", "Pán prstenů – Společenstvo prstenu", "Próza", "Pošustová", 0}, - {"Romain Rolland – Petr a Lucie", "cetbastub", "Romain Rolland", "Petr a Lucie", "Próza", "Zaorálek", 0}, - {"Edgar Allan Poe – Povídky", "cetbastub", "Edgar Allan Poe", "Povídky", "Próza", NULL, 0}, - {"Karel Čapek – Povídky z jedné a druhé kapsy", "cetbastub", "Karel Čapek", "Povídky z jedné a druhé kapsy", "Próza", NULL, 0}, - {"Franz Kafka – Proměna", "cetbastub", "Franz Kafka", "Proměna", "Próza", NULL, 0}, - {"Jane Austenová – Pýcha a předsudek", "cetbastub", "Jane Austenová", "Pýcha a předsudek", "Próza", "Poláčková", 0}, - {"Karel Čapek – R. U. R.", "cetbastub", "Karel Čapek", "R. U. R.", "Drama", NULL, 0}, - {"Nikolaj Vasiljevič Gogol – Revizor", "cetbastub", "Nikolaj Vasiljevič Gogol", "Revizor", "Drama", "Mahler, Suchařípa, Morávková", 0}, - {"William Shakespeare – Romeo a Julie", "cetbastub", "William Shakespeare", "Romeo a Julie", "Drama", "Hilský", 0}, - {"Jan Otčenášek – Romeo, Julie a tma", "cetbastub", "Jan Otčenášek", "Romeo, Julie a tma", "Próza", NULL, 0}, - {"Vladislav Vančura – Rozmarné léto", "cetbastub", "Vladislav Vančura", "Rozmarné léto", "Próza", NULL, 0}, - {"Daniel Keyes – Růže pro Algernon", "cetbastub", "Daniel Keyes", "Růže pro Algernon", "Próza", "Podaný", 0}, - {"Zdeněk Jirotka – Saturnin", "cetbastub", "Zdeněk Jirotka", "Saturnin", "Próza", NULL, 0}, - {"Carlo Goldoni – Sluha dvou pánů", "cetbastub", "Carlo Goldoni", "Sluha dvou pánů", "Drama", "Bezděková", 0}, - {"Ota Pavel – Smrt krásných srnců", "cetbastub", "Ota Pavel", "Smrt krásných srnců", "Próza", NULL, 0}, - {"William Styron – Sofiina volba", "cetbastub", "William Styron", "Sofiina volba", "Próza", "Nenadál", 0}, - {"Ladislav Fuks – Spalovač mrtvol", "cetbaFuks", "Ladislav Fuks", "Spalovač mrtvol", "Próza", NULL, 1}, - {"Eduard Petiška – Staré řecké báje a pověsti", "cetbastub", "Eduard Petiška", "Staré řecké báje a pověsti", "Próza", NULL, 0}, - {"Ernest Hemingway – Stařec a moře", "cetbastub", "Ernest Hemingway", "Stařec a moře", "Próza", "Vrba", 0}, - {"Jakub Arbes – Svatý Xaverius", "cetbastub", "Jakub Arbes", "Svatý Xaverius", "Próza", NULL, 0}, - {"Émile Zola – Tereza Raquinová", "cetbastub", "Émile Zola", "Tereza Raquinová", "Próza", NULL, 0}, - {"Jiří Wolker – Těžká hodina", "cetbastub", "Jiří Wolker", "Těžká hodina", "Poezie", NULL, 0}, - {"Karel Havlíček Borovský – Tyrolské elegie", "cetbastub", "Karel Havlíček Borovský", "Tyrolské elegie", "Poezie", NULL, 0}, - {"Karel Čapek – Válka s mloky", "cetbastub", "Karel Čapek", "Válka s mloky", "Próza", NULL, 0}, - {"Pierre Clostermann – Velký cirkus", "cetbastub", "Pierre Clostermann", "Velký cirkus", "Próza", "Jedlička", 0}, - {"F. Scott Fitzgerald – Velký Gatsby", "cetbastub", "F. Scott Fitzgerald", "Velký Gatsby", "Próza", "Dorůžka", 0}, - {"Ladislav Smoljak, Zdeněk Svěrák – Vyšetřování ztráty třídní knihy", "cetbastub", "Ladislav Smoljak, Zdeněk Svěrák", "Vyšetřování ztráty třídní knihy", "Drama", NULL, 0}, - {"Émile Zola – Zabiják", "cetbastub", "Émile Zola", "Zabiják", "Próza", "Kárl", 0}, - {"Josef Škvorecký – Zbabělci", "cetbastub", "Josef Škvorecký", "Zbabělci", "Próza", NULL, 0}, - {"Milan Kundera – Žert", "cetbastub", "Milan Kundera", "Žert", "Próza", NULL, 0}, -}; - diff --git a/src/changelog.c b/src/changelog.c deleted file mode 100644 index 39435bd..0000000 --- a/src/changelog.c +++ /dev/null @@ -1,234 +0,0 @@ -#include "graduately.h" - -#include - -/* ------------------------------------------------------------------ */ -/* What's new on the home page after an update */ -/* ------------------------------------------------------------------ */ - -/* The packaged notes live in changelog.txt next to style.css. After a - * published (or first) start whose commit is not the one the user last - * dismissed, the welcome page shows the newest entries. Dismissing stores - * APP_COMMIT in settings so the card stays gone until the next update. */ - -#define CHANGELOG_MAX_BLOCKS 3 - -typedef struct { - char *date; - GPtrArray *cs; - GPtrArray *en; -} ChangelogBlock; - -static struct { - GPtrArray *blocks; - char *seen; - GtkWidget *card; - GtkWidget *date; - GtkWidget *items; - gboolean loaded; -} cl; - -static gboolean same_build(const char *a, const char *b) { - size_t n; - - if (!a || !b || !a[0] || !b[0]) - return FALSE; - if (g_ascii_strcasecmp(a, b) == 0) - return TRUE; - n = MIN(strlen(a), strlen(b)); - return n >= 7 && g_ascii_strncasecmp(a, b, n) == 0; -} - -void changelog_set_seen(const char *sha) { - g_free(cl.seen); - cl.seen = (sha && sha[0]) ? g_strdup(sha) : NULL; -} - -const char *changelog_seen(void) { - return cl.seen ? cl.seen : ""; -} - -static void free_block(gpointer data) { - ChangelogBlock *b = data; - - if (!b) - return; - g_free(b->date); - if (b->cs) - g_ptr_array_free(b->cs, TRUE); - if (b->en) - g_ptr_array_free(b->en, TRUE); - g_free(b); -} - -static ChangelogBlock *new_block(const char *date) { - ChangelogBlock *b = g_new0(ChangelogBlock, 1); - - b->date = g_strdup(date ? date : ""); - b->cs = g_ptr_array_new_with_free_func(g_free); - b->en = g_ptr_array_new_with_free_func(g_free); - return b; -} - -static void load_changelog(void) { - gchar *text = NULL; - gchar **lines; - ChangelogBlock *cur = NULL; - guint i; - - if (cl.loaded) - return; - cl.loaded = TRUE; - cl.blocks = g_ptr_array_new_with_free_func(free_block); - - if (!g_file_get_contents(CHANGELOG_FILE, &text, NULL, NULL) || !text) - return; - - lines = g_strsplit(text, "\n", -1); - g_free(text); - - for (i = 0; lines[i]; i++) { - char *line = g_strstrip(lines[i]); - - if (!line[0] || line[0] == '#') - continue; - if (g_str_has_prefix(line, "---")) { - char *date = g_strstrip(line + 3); - - cur = new_block(date); - g_ptr_array_add(cl.blocks, cur); - continue; - } - if (!cur) - continue; - if (g_str_has_prefix(line, "cs:")) - g_ptr_array_add(cur->cs, g_strdup(g_strstrip(line + 3))); - else if (g_str_has_prefix(line, "en:")) - g_ptr_array_add(cur->en, g_strdup(g_strstrip(line + 3))); - } - g_strfreev(lines); -} - -static gboolean changelog_pending(void) { - load_changelog(); - if (!cl.blocks || cl.blocks->len == 0) - return FALSE; - return !same_build(APP_COMMIT, cl.seen); -} - -static GPtrArray *block_lines(const ChangelogBlock *b) { - GPtrArray *src; - - if (!b) - return NULL; - src = (app_lang == LANG_EN) ? b->en : b->cs; - if (src && src->len > 0) - return src; - return (b->cs && b->cs->len > 0) ? b->cs : b->en; -} - -static void fill_items(void) { - GtkWidget *child; - guint i, shown = 0; - - if (!cl.items) - return; - - while ((child = gtk_widget_get_first_child(cl.items))) - gtk_box_remove(GTK_BOX(cl.items), child); - - if (!cl.blocks) - return; - - for (i = 0; i < cl.blocks->len && shown < CHANGELOG_MAX_BLOCKS; i++) { - const ChangelogBlock *b = g_ptr_array_index(cl.blocks, i); - GPtrArray *lines = block_lines(b); - guint j; - - if (!lines || lines->len == 0) - continue; - if (shown == 0 && cl.date) - gtk_label_set_text(GTK_LABEL(cl.date), b->date ? b->date : ""); - if (shown > 0) { - GtkWidget *gap = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - gtk_widget_set_margin_top(gap, 8); - gtk_box_append(GTK_BOX(cl.items), gap); - } - for (j = 0; j < lines->len; j++) { - char *text = g_strdup_printf("• %s", - (const char *)lines->pdata[j]); - GtkWidget *row = gtk_label_new(text); - - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(row), TRUE); - gtk_label_set_xalign(GTK_LABEL(row), 0.0); - gtk_label_set_max_width_chars(GTK_LABEL(row), 52); - gtk_widget_add_css_class(row, "changelog-item"); - gtk_box_append(GTK_BOX(cl.items), row); - g_free(text); - } - shown++; - } -} - -void changelog_apply_lang(void) { - if (cl.card && gtk_widget_get_visible(cl.card)) - fill_items(); -} - -static void on_changelog_dismiss(GtkButton *btn, gpointer data) { - (void)btn; - (void)data; - changelog_set_seen(APP_COMMIT); - save_settings(); - if (cl.card) - gtk_widget_set_visible(cl.card, FALSE); -} - -GtkWidget *build_changelog_card(void) { - GtkWidget *card; - GtkWidget *head; - GtkWidget *title; - GtkWidget *date; - GtkWidget *items; - GtkWidget *dismiss; - - load_changelog(); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_widget_add_css_class(card, "changelog-card"); - gtk_widget_set_hexpand(card, TRUE); - gtk_widget_set_visible(card, changelog_pending()); - - head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); - gtk_box_append(GTK_BOX(card), head); - - title = gtk_label_new(NULL); - i18n_bind(title, "changelog_title", 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_set_hexpand(title, TRUE); - gtk_widget_add_css_class(title, "changelog-title"); - gtk_box_append(GTK_BOX(head), title); - - date = gtk_label_new(""); - gtk_widget_set_valign(date, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(date, "changelog-date"); - gtk_box_append(GTK_BOX(head), date); - - items = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_box_append(GTK_BOX(card), items); - - dismiss = gtk_button_new(); - i18n_bind(dismiss, "changelog_dismiss", 1); - gtk_widget_set_halign(dismiss, GTK_ALIGN_START); - gtk_widget_add_css_class(dismiss, "changelog-dismiss"); - g_signal_connect(dismiss, "clicked", G_CALLBACK(on_changelog_dismiss), NULL); - gtk_box_append(GTK_BOX(card), dismiss); - - cl.card = card; - cl.date = date; - cl.items = items; - fill_items(); - return card; -} diff --git a/src/chemie.c b/src/chemie.c deleted file mode 100644 index 5169e35..0000000 --- a/src/chemie.c +++ /dev/null @@ -1,604 +0,0 @@ -#include "graduately.h" - -/* Chemistry for Základy přírodopisných věd. - * Follows the secondary-school outline (RVP for vocational schools, - * přírodovědné vzdělávání, and the gymnasium general-chemistry track): - * general chemistry, inorganic chemistry, organic chemistry, biochemistry. */ - -NetLesson chem_lessons[SCI_N] = { - { .n_slides = 3, .unit_page = "chemunit1", .ex_page = "chemex1" }, - { .n_slides = 3, .unit_page = "chemunit2", .ex_page = "chemex2" }, - { .n_slides = 3, .unit_page = "chemunit3", .ex_page = "chemex3" }, - { .n_slides = 3, .unit_page = "chemunit4", .ex_page = "chemex4" }, - { .n_slides = 3, .unit_page = "chemunit5", .ex_page = "chemex5" }, - { .n_slides = 3, .unit_page = "chemunit6", .ex_page = "chemex6" }, - { .n_slides = 3, .unit_page = "chemunit7", .ex_page = "chemex7" }, - { .n_slides = 3, .unit_page = "chemunit8", .ex_page = "chemex8" }, -}; - -static GtkWidget *build_chem_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Atom", "Z čeho je látka", - "Tip: protonové číslo je počet protonů, ne elektronů.", - { - "Atom má jádro z protonů a neutronů a obal z elektronů.", - "Proton má kladný náboj, elektron záporný, neutron je bez náboje.", - "Protonové číslo Z udává počet protonů a určuje prvek.", - "Nukleonové číslo A je součet protonů a neutronů.", - NULL, - }, - }, - { - "2 / 3 • Tabulka", "Periody a skupiny", - "Tip: perioda je řádek, skupina je sloupec.", - { - "Periodická soustava řadí prvky podle rostoucího protonového čísla.", - "Prvky v jedné skupině mají podobné chemické vlastnosti.", - "Číslo periody souvisí s počtem obsazených slupek.", - "Vlevo jsou kovy, vpravo nekovy, mezi nimi polokovy.", - NULL, - }, - }, - { - "3 / 3 • Částice", "Atom, molekula, ion", - "Tip: kation vzniká ztrátou elektronů, anion jejich přijetím.", - { - "Prvek tvoří atomy se stejným protonovým číslem.", - "Molekula je částice ze dvou nebo více atomů spojených vazbou.", - "Ion je nabitá částice: kation je kladný, anion záporný.", - "Izotopy jednoho prvku se liší počtem neutronů, ne protonů.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[0], "chem_unit1", "chem_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co udává protonové číslo?", - {"Počet protonů v jádře", "Počet neutronů v jádře", - "Součet protonů a elektronů v molekule", "Hmotnost atomu v gramech"}, - 4, 0}, - {"Jaký náboj má elektron?", - {"Kladný", "Záporný", "Žádný", "Stejný jako neutron"}, - 4, 1}, - {"Co mají společného prvky v jedné skupině?", - {"Stejné nukleonové číslo", "Podobné chemické vlastnosti", - "Stejný počet neutronů", "Stejné skupenství za pokojové teploty"}, - 4, 1}, - {"Co je v periodické soustavě perioda?", - {"Sloupec prvků", "Řádek prvků", - "Jen skupina vzácných plynů", "Rozdíl protonů a neutronů"}, - 4, 1}, - }; - static const char *hints[] = { - "Z je počet protonů a zároveň pořadí prvku v tabulce.", - "Proton je kladný, elektron záporný, neutron neutrální.", - "Skupina je sloupec. Podobné vlastnosti plynou z podobného obalu.", - "Perioda je řádek. Číslo periody souvisí s obsazenými slupkami.", - }; - - return sci_mcq_page(0, 0, "chemunit1", "chem_ex1_title", "chem_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_chem_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Ionty", "Iontová vazba", - "Tip: NaCl je typická iontová sloučenina.", - { - "Iontová vazba vzniká přenosem elektronů mezi atomy.", - "Kov odevzdá elektrony a stane se kationtem, nekov je přijme jako anion.", - "Opačné náboje se přitahují a drží krystal pohromadě.", - "Iontové látky mají vysoké teploty tání a v tavenině vedou proud.", - NULL, - }, - }, - { - "2 / 3 • Sdílení", "Kovalentní vazba", - "Tip: ve vodě atomy elektrony sdílejí, nepředávají si je natrvalo.", - { - "Kovalentní vazba vzniká sdílením elektronového páru.", - "Jednoduchá vazba je jeden pár, dvojná dva, trojná tři.", - "Nepolární vazba spojuje atomy se stejnou elektronegativitou, třeba H2.", - "Polární vazba vzniká mezi atomy s různou elektronegativitou, třeba v H2O.", - NULL, - }, - }, - { - "3 / 3 • Kovy", "Kovová vazba", - "Tip: volné elektrony vysvětlují lesk i vodivost kovů.", - { - "V kovu jsou kationty obklopené sdílenými elektrony.", - "Elektrony se mohou posouvat, proto kov vede proud a teplo.", - "Elektronegativita je schopnost atomu přitahovat elektrony vazby.", - "Velký rozdíl elektronegativit vede spíš k iontové vazbě.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[1], "chem_unit2", "chem_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaká vazba drží krystal chloridu sodného?", - {"Kovalentní nepolární", "Iontová", "Kovová", "Vodíkový můstek jako jediná"}, - 4, 1}, - {"Co je kovalentní vazba?", - {"Přenos elektronu z kovu na nekov", - "Sdílení elektronového páru", - "Pohyb volných elektronů mezi kationty kovu", - "Přitažlivost jen mezi molekulami vody"}, - 4, 1}, - {"Proč kovy vedou elektrický proud?", - {"Mají pevné jádro bez elektronů", - "Obsahují pohyblivé elektrony kovové vazby", - "Jsou vždy kapalné", - "Nemají protony"}, - 4, 1}, - {"Co je elektronegativita?", - {"Počet neutronů v jádře", - "Schopnost atomu přitahovat elektrony vazby", - "Hmotnost jednoho molu", - "Teplota varu kovu"}, - 4, 1}, - }; - static const char *hints[] = { - "Sodík předá elektron chloru. Vznikne Na+ a Cl−.", - "Kovalentní vazba je společný elektronový pár, ne trvalý přenos.", - "Kovová vazba má volné elektrony, které přenášejí náboj.", - "Čím větší rozdíl elektronegativit, tím polárnější nebo iontovější vazba.", - }; - - return sci_mcq_page(0, 1, "chemunit2", "chem_ex2_title", "chem_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_chem_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Rovnice", "Co se při reakci zachová", - "Tip: vyčíslit znamená srovnat počty atomů, ne měnit vzorce.", - { - "Při chemické reakci se atomy přeskupují, ale neztrácejí.", - "Zákon zachování hmotnosti: hmotnost reaktantů se rovná hmotnosti produktů.", - "V rovnici musí být na obou stranách stejný počet atomů každého prvku.", - "Koeficient před vzorcem násobí celou částici.", - NULL, - }, - }, - { - "2 / 3 • Mol", "Kolik je částic", - "Tip: molární hmotnost vody je přibližně 18 g/mol.", - { - "Mol je jednotka látkového množství.", - "Jeden mol obsahuje 6,022 × 10^23 částic, to je Avogadrova konstanta.", - "Molární hmotnost M je hmotnost jednoho molu v g/mol.", - "Látkové množství se počítá jako n = m / M.", - NULL, - }, - }, - { - "3 / 3 • Výpočet", "Od hmotnosti k molům", - "Tip: nejdřív sečti relativní atomové hmotnosti ve vzorci.", - { - "Relativní atomová hmotnost vodíku je 1, kyslíku 16, uhlíku 12.", - "Voda H2O má molární hmotnost 18 g/mol, oxid uhličitý CO2 má 44 g/mol.", - "18 g vody je 1 mol, tedy 6,022 × 10^23 molekul.", - "Stechiometrie porovnává moly podle koeficientů v rovnici.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[2], "chem_unit3", "chem_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co říká zákon zachování hmotnosti?", - {"Hmotnost produktů je vždy menší", - "Hmotnost reaktantů se rovná hmotnosti produktů", - "Atomy se při reakci ničí", - "Molární hmotnost se během reakce mění"}, - 4, 1}, - {"Kolik částic je v jednom molu?", - {"18", "44", "6,022 × 10^23", "1000"}, - 4, 2}, - {"Jak se spočítá látkové množství?", - {"n = m × M", "n = m / M", "n = M / m", "n = Z + A"}, - 4, 1}, - {"Jaká je přibližně molární hmotnost vody?", - {"2 g/mol", "16 g/mol", "18 g/mol", "44 g/mol"}, - 4, 2}, - }; - static const char *hints[] = { - "Atomy se přeskupují. Jejich celková hmotnost zůstává.", - "Avogadrova konstanta je počet částic v jednom molu.", - "Hmotnost dělíme molární hmotností. Výsledek je v molech.", - "H2O: 1 + 1 + 16 = 18. CO2 je 12 + 16 + 16 = 44.", - }; - - return sci_mcq_page(0, 2, "chemunit3", "chem_ex3_title", "chem_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_chem_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Směsi", "Čistá látka a směs", - "Tip: roztok je homogenní směs, suspenze heterogenní.", - { - "Čistá látka má stálé složení a stálé vlastnosti.", - "Směs obsahuje dvě nebo více látek, které nejsou chemicky vázané.", - "Homogenní směs, třeba roztok, vypadá v celém objemu stejně.", - "Heterogenní směs má rozlišitelné složky, třeba suspenze nebo emulze.", - NULL, - }, - }, - { - "2 / 3 • Roztok", "Složení roztoku", - "Tip: hmotnostní zlomek je podíl hmotnosti složky a hmotnosti směsi.", - { - "Rozpouštědlo je látka, v níž se rozpouští rozpuštěná látka.", - "Hmotnostní zlomek w = hmotnost složky / hmotnost celé směsi.", - "Nasycený roztok už při dané teplotě další látku nerozpustí.", - "Rozpustnost většiny pevných látek s teplotou roste.", - NULL, - }, - }, - { - "3 / 3 • pH", "Kyseliny a zásady", - "Tip: neutralizace kyseliny hydroxidem dává sůl a vodu.", - { - "Kyselina ve vodě zvyšuje množství H+, zásada množství OH−.", - "pH menší než 7 je kyselé, 7 neutrální, větší než 7 zásadité.", - "Silné kyseliny jsou třeba HCl a H2SO4, silná zásada je NaOH.", - "Neutralizace: kyselina + hydroxid → sůl + voda.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[3], "chem_unit4", "chem_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je roztok?", - {"Heterogenní směs dvou kovů", "Homogenní směs", - "Čistý prvek", "Jen sraženina na dně"}, - 4, 1}, - {"Jaké pH má kyselý roztok?", - {"Přesně 7", "Menší než 7", "Větší než 7", "Vždy 14"}, - 4, 1}, - {"Co vzniká neutralizací kyseliny hydroxidem?", - {"Jen vodík a kyslík jako prvky", "Sůl a voda", - "Uhlovodík", "Vzácný plyn"}, - 4, 1}, - {"Co je hmotnostní zlomek?", - {"Podíl hmotnosti složky a hmotnosti směsi", - "Počet molů v litru", - "Rozdíl pH a 7", - "Hmotnost jednoho protonu"}, - 4, 0}, - }; - static const char *hints[] = { - "Roztok je stejnorodý. Suspenze a emulze jsou různorodé.", - "Neutrální pH je 7. Pod ním je kyselina, nad ním zásada.", - "H+ z kyseliny a OH− ze zásady dají vodu, zbytek iontů sůl.", - "w = m(složky) / m(směsi). Nemá jednotku, nebo se uvádí v procentech.", - }; - - return sci_mcq_page(0, 3, "chemunit4", "chem_ex4_title", "chem_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_chem_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Názvy", "Čtyři skupiny sloučenin", - "Tip: oxid uhličitý je CO2, oxid uhelnatý je CO.", - { - "Oxidy jsou sloučeniny prvku s kyslíkem.", - "Kyseliny ve vzorci obsahují vodík, který mohou odštěpit jako H+.", - "Hydroxidy obsahují skupinu OH, soli vznikají z kyseliny náhradou vodíku.", - "NaCl je chlorid sodný, NaOH hydroxid sodný, HCl kyselina chlorovodíková.", - NULL, - }, - }, - { - "2 / 3 • Nekovy", "Halogeny, kyslík, dusík", - "Tip: halogeny jsou ve 17. skupině a jsou velmi reaktivní.", - { - "Kyslík O2 tvoří asi pětinu vzduchu a je nutný k dýchání i hoření.", - "Halogeny fluor, chlor, brom a jod tvoří soli, halogenidy.", - "Dusík N2 tvoří většinu vzduchu a je v bílkovinách i v hnojivech.", - "Síra je v kyselině sírové H2SO4, důležité průmyslové kyselině.", - NULL, - }, - }, - { - "3 / 3 • Kovy", "Sodík, vápník, železo", - "Tip: alkalické kovy reagují s vodou a musí se uchovávat pod petrolejem.", - { - "Alkalické kovy lithium, sodík a draslík jsou měkké a velmi reaktivní.", - "Vápník a hořčík patří ke kovům alkalických zemin a jsou v kostech i chlorofylu.", - "Železo je přechodný kov, základ oceli, a v těle je v hemoglobinu.", - "Ušlechtilé kovy, třeba zlato, vzdorují korozi víc než železo.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[4], "chem_unit5", "chem_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Který vzorec patří oxidu uhličitému?", - {"CO", "CO2", "H2CO3", "CaCO3"}, - 4, 1}, - {"Co je hydroxid sodný?", - {"NaCl", "NaOH", "HCl", "H2SO4"}, - 4, 1}, - {"Které prvky jsou halogeny?", - {"Li, Na, K", "F, Cl, Br, I", "Fe, Cu, Zn", "He, Ne, Ar"}, - 4, 1}, - {"Kam patří sodík a draslík?", - {"Mezi vzácné plyny", "Mezi alkalické kovy", - "Mezi halogeny", "Mezi polokovy"}, - 4, 1}, - }; - static const char *hints[] = { - "CO je oxid uhelnatý, CO2 oxid uhličitý. H2CO3 je kyselina uhličitá.", - "Hydroxidy končí na OH. NaOH je silná zásada.", - "Halogeny jsou 17. skupina. Alkalické kovy jsou 1. skupina.", - "Li, Na a K jsou alkalické kovy. S vodou reagují bouřlivě.", - }; - - return sci_mcq_page(0, 4, "chemunit5", "chem_ex5_title", "chem_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_chem_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Uhlík", "Proč existuje organická chemie", - "Tip: organické sloučeniny staví řetězce a kruhy z uhlíku.", - { - "Organická chemie zkoumá sloučeniny uhlíku, kromě oxidů a uhličitanů.", - "Uhlík tvoří čtyři vazby a může se řetězit.", - "Uhlovodíky obsahují jen uhlík a vodík.", - "Nasycené mají jen jednoduché vazby, nenasycené i dvojné nebo trojné.", - NULL, - }, - }, - { - "2 / 3 • Řady", "Alkany, alkeny a alkyny", - "Tip: obecný vzorec alkanů je CnH2n+2.", - { - "Alkany jsou nasycené. Methan CH4 je nejjednodušší.", - "Alkeny mají dvojnou vazbu. Ethen C2H4 je surovina pro plasty.", - "Alkyny mají trojnou vazbu. Ethyn, acetylen, se používá ke svařování.", - "Hořením uhlovodíků vzniká oxid uhličitý a voda.", - NULL, - }, - }, - { - "3 / 3 • Areny", "Benzen", - "Tip: benzen není alken se třemi obyčejnými dvojnými vazbami.", - { - "Areny jsou aromatické uhlovodíky s zvláštně stálým kruhem.", - "Benzen má vzorec C6H6.", - "Aromatický kruh je stálejší než obyčejné střídání dvojných vazeb.", - "Z arenů se vyrábějí plasty, léčiva i barviva.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[5], "chem_unit6", "chem_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Který uhlovodík je alkan?", - {"Ethen", "Ethyn", "Methan", "Benzen"}, - 4, 2}, - {"Jaký je obecný vzorec alkanů?", - {"CnH2n", "CnH2n+2", "CnH2n−2", "CnH2n−6"}, - 4, 1}, - {"Čím se ethen liší od ethanu?", - {"Nemá uhlík", "Má dvojnou vazbu", - "Je to kov", "Má trojnou vazbu"}, - 4, 1}, - {"Jaký vzorec má benzen?", - {"CH4", "C2H4", "C2H2", "C6H6"}, - 4, 3}, - }; - static const char *hints[] = { - "Methan a ethan jsou alkany. Ethen je alken, ethyn alkyn, benzen aren.", - "Alkany CnH2n+2, alkeny CnH2n, alkyny CnH2n−2.", - "Ethan je nasycený. Ethen má jednu dvojnou vazbu.", - "Benzen C6H6 je základní aren. Methan je CH4.", - }; - - return sci_mcq_page(0, 5, "chemunit6", "chem_ex6_title", "chem_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_chem_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Skupiny", "Deriváty uhlovodíků", - "Tip: funkční skupina rozhoduje o vlastnostech víc než délka řetězce.", - { - "Derivát vzniká náhradou vodíku jinou skupinou atomů.", - "Alkoholy mají hydroxyl −OH. Ethanol je v alkoholických nápojích.", - "Karboxylové kyseliny mají −COOH. Kyselina octová je v octu.", - "Aldehydy a ketony obsahují karbonylovou skupinu C=O.", - NULL, - }, - }, - { - "2 / 3 • Cukry", "Sacharidy", - "Tip: glukóza je monosacharid, škrob a celulóza jsou její polymery.", - { - "Sacharidy jsou přírodní látky z uhlíku, vodíku a kyslíku.", - "Glukóza C6H12O6 je základní cukr a palivo buněk.", - "Sacharosa je řepný a třtinový cukr, škrob je zásoba rostlin.", - "Celulóza tvoří buněčné stěny rostlin a člověk ji netráví.", - NULL, - }, - }, - { - "3 / 3 • Tuky a bílkoviny", "Z čeho je tělo", - "Tip: bílkovina je řetězec aminokyselin, tuk je ester glycerolu.", - { - "Lipidy jsou tuky a oleje, estery glycerolu a mastných kyselin.", - "Tuky jsou zásoba energie a součást membrán.", - "Bílkoviny vznikají spojením aminokyselin peptidovou vazbou.", - "Pořadí aminokyselin určuje tvar a funkci bílkoviny.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[6], "chem_unit7", "chem_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kterou skupinu mají alkoholy?", - {"−COOH", "−OH", "−NH2 jako jedinou v alkanech", "Jen dvojnou vazbu uhlík–uhlík"}, - 4, 1}, - {"Co je kyselina octová?", - {"Alkan", "Karboxylová kyselina", "Halogen", "Hydroxid"}, - 4, 1}, - {"Která látka je sacharid?", - {"Škrob", "Chlorid sodný", "Ethyn", "Oxid vápenatý"}, - 4, 0}, - {"Z čeho jsou bílkoviny?", - {"Z glycerolu a nic jiného", "Z aminokyselin", - "Jen z glukózy", "Z vzácných plynů"}, - 4, 1}, - }; - static const char *hints[] = { - "Hydroxyl −OH je alkohol. Karboxyl −COOH je kyselina.", - "Octová kyselina CH3COOH má karboxyl. V octu je její zředěný roztok.", - "Glukóza, sacharosa, škrob a celulóza jsou sacharidy.", - "Aminokyseliny se pojí peptidovou vazbou do bílkoviny.", - }; - - return sci_mcq_page(0, 6, "chemunit7", "chem_ex7_title", "chem_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_chem_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Enzymy", "Biokatalyzátory", - "Tip: enzym je bílkovina a urychluje jednu určitou reakci.", - { - "Biochemie zkoumá chemické děje v živých organismech.", - "Enzym je bílkovinný katalyzátor. Snižuje aktivační energii.", - "Každý enzym působí na určitý substrát, jako klíč do zámku.", - "Teplo a nevhodné pH enzym denaturují a reakce se zpomalí.", - NULL, - }, - }, - { - "2 / 3 • Energie", "Fotosyntéza a dýchání", - "Tip: fotosyntéza váže energii, buněčné dýchání ji uvolňuje.", - { - "Fotosyntéza: 6 CO2 + 6 H2O → C6H12O6 + 6 O2, potřebuje světlo.", - "Probíhá v chloroplastech a je zdrojem kyslíku i organických látek.", - "Buněčné dýchání glukózu oxiduje a uvolňuje energii pro buňku.", - "Zjednodušeně je dýchání opačný směr než fotosyntéza.", - NULL, - }, - }, - { - "3 / 3 • DNA", "Chemický zápis dědičnosti", - "Tip: v RNA je uracil tam, kde má DNA thymin.", - { - "Nukleové kyseliny jsou DNA a RNA.", - "DNA nese genetickou informaci. Báze jsou adenin, thymin, guanin a cytosin.", - "Adenin se páruje s thyminem, guanin s cytosinem.", - "RNA má místo thyminu uracil a v buňce pomáhá číst geny.", - NULL, - }, - }, - }; - - return sci_unit_page(0, &chem_lessons[7], "chem_unit8", "chem_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_chem_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je enzym?", - {"Anorganická sůl", "Bílkovinný biokatalyzátor", - "Vzácný plyn", "Nasycený uhlovodík"}, - 4, 1}, - {"Co při fotosyntéze vzniká spolu s glukózou?", - {"Dusík", "Kyslík", "Chlorid sodný", "Železo"}, - 4, 1}, - {"Která báze je v RNA místo thyminu?", - {"Adenin", "Uracil", "Guanin navíc bez cytosinu", "Sodík"}, - 4, 1}, - {"Co dělá buněčné dýchání s glukózou?", - {"Ukládá ji beze změny do jádra", - "Oxiduje ji a uvolňuje energii", - "Mění ji na vzácný plyn", - "Zastavuje všechny enzymy"}, - 4, 1}, - }; - static const char *hints[] = { - "Enzym je bílkovina. Katalyzátor reakci urychlí a sám se nespotřebuje.", - "Zjednodušená rovnice končí glukózou a kyslíkem.", - "DNA: A, T, G, C. RNA má U místo T.", - "Dýchání je opak fotosyntézy v tom smyslu, že energii z glukózy uvolní.", - }; - - return sci_mcq_page(0, 7, "chemunit8", "chem_ex8_title", "chem_quiz8_head", - qs, hints, 4); -} - -void add_chem_pages(GtkStack *stack) { - typedef GtkWidget *(*SciBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - SciBuilder build_unit; - SciBuilder build_ex; - } pages[] = { - {"chemunit1", "chemex1", build_chem_unit1_page, build_chem_unit1_exercise_page}, - {"chemunit2", "chemex2", build_chem_unit2_page, build_chem_unit2_exercise_page}, - {"chemunit3", "chemex3", build_chem_unit3_page, build_chem_unit3_exercise_page}, - {"chemunit4", "chemex4", build_chem_unit4_page, build_chem_unit4_exercise_page}, - {"chemunit5", "chemex5", build_chem_unit5_page, build_chem_unit5_exercise_page}, - {"chemunit6", "chemex6", build_chem_unit6_page, build_chem_unit6_exercise_page}, - {"chemunit7", "chemex7", build_chem_unit7_page, build_chem_unit7_exercise_page}, - {"chemunit8", "chemex8", build_chem_unit8_page, build_chem_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/czech.c b/src/czech.c deleted file mode 100644 index 49991f8..0000000 --- a/src/czech.c +++ /dev/null @@ -1,167 +0,0 @@ -#include "graduately.h" - -/* ---- Czech language and literature (Český jazyk a literatura) ----- */ - -#define CZ_NODES 3 -#define CZ_BUBBLE SUB_BUBBLE -#define CZ_LABEL_W 200.0 -#define CZ_CW 600 -#define CZ_CH 470 - -static const char *cz_keys[CZ_NODES] = { - "Literatura", "Mluvnice", "Maturitní četba", -}; -static const char *cz_initials[CZ_NODES] = { - "L", "M", "Č", -}; - -static GtkWidget *cz_rail; -static double cz_cx[CZ_NODES]; -static double cz_cy[CZ_NODES]; - -static void cz_geometry(void) { - cz_cx[0] = 300.0; cz_cy[0] = 120.0; /* Literatura (top) */ - cz_cx[1] = 140.0; cz_cy[1] = 350.0; /* Mluvnice (bottom-left) */ - cz_cx[2] = 460.0; cz_cy[2] = 350.0; /* Maturitní četba (bottom-right) */ -} - -/* Three bubbles joined into a triangle by thick rails. */ -static void draw_cz_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb slate = color_from_hex(app_theme.surface1); - - (void)area; - (void)width; - (void)height; - (void)data; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - cairo_move_to(cr, cz_cx[0], cz_cy[0]); - cairo_line_to(cr, cz_cx[1], cz_cy[1]); - cairo_line_to(cr, cz_cx[2], cz_cy[2]); - cairo_close_path(cr); - - cairo_set_line_width(cr, 14); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke_preserve(cr); - - cairo_set_line_width(cr, 9); - cairo_set_source_rgb(cr, slate.r, slate.g, slate.b); - cairo_stroke(cr); -} - -void czech_rail_theme_reset(void) { - if (cz_rail) - gtk_widget_queue_draw(cz_rail); -} - -static GtkWidget *cz_make_node(int index, gboolean locked) { - GtkWidget *btn; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_size_request(btn, (int)CZ_BUBBLE, (int)CZ_BUBBLE); - - if (locked) { - gtk_widget_add_css_class(btn, "locked"); - gtk_widget_set_sensitive(btn, FALSE); - gtk_button_set_child(GTK_BUTTON(btn), - icon_area_new(draw_lock_icon, - 0.3451, 0.3569, 0.4392, 26)); - } else { - GtkWidget *label = gtk_label_new(cz_initials[index]); - - gtk_widget_add_css_class(btn, "current"); - gtk_widget_add_css_class(label, "unit-number"); - gtk_button_set_child(GTK_BUTTON(btn), label); - } - - return btn; -} - -GtkWidget *build_czechmap_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - - cz_geometry(); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "Český jazyk a literatura", - "czech_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, CZ_CW, CZ_CH); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, CZ_CW, CZ_CH); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), draw_cz_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - cz_rail = rail; - - for (int i = 0; i < CZ_NODES; i++) { - GtkWidget *btn = cz_make_node(i, FALSE); - GtkWidget *name = gtk_label_new(NULL); - const char *target = (i == 0) ? "lityears" - : (i == 1) ? "mluvnice" - : "readinglist"; - - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - - i18n_bind(name, cz_keys[i], 0); - gtk_widget_set_size_request(name, (int)CZ_LABEL_W, -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - gtk_widget_add_css_class(name, "cz-label"); - - gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0); - gtk_fixed_put(GTK_FIXED(fixed), name, 0, 0); - - gtk_fixed_move(GTK_FIXED(fixed), btn, - (int)(cz_cx[i] - CZ_BUBBLE / 2.0), - (int)(cz_cy[i] - CZ_BUBBLE / 2.0)); - gtk_fixed_move(GTK_FIXED(fixed), name, - (int)(cz_cx[i] - CZ_LABEL_W / 2.0), - (int)(cz_cy[i] + CZ_BUBBLE / 2.0 + 10.0)); - } - - return page; -} diff --git a/src/english.c b/src/english.c deleted file mode 100644 index 1c9ef8a..0000000 --- a/src/english.c +++ /dev/null @@ -1,1647 +0,0 @@ -#include "graduately.h" - -#include - -#ifdef __APPLE__ -#include -#include -#endif -#ifdef G_OS_UNIX -#include -#include -#endif - -/* English across four gymnasium years (RVP G, foreign language, maturita - * skills). Lesson text lives in english_lessons.inc. */ - -#define EN_YEARS 4 -#define EN_N 8 - -#include "english_lessons.inc" - -typedef struct { - const ChoiceQ *q; - GtkToggleButton *tb[4]; - GtkWidget *hint; -} EnPick; - -typedef struct { - int year; - int index; - const EnLesson *lesson; - void (*on_done)(int year, int index); - GtkWidget *feedback; - GtkWidget *model; - GArray *picks; - GArray *entries; - GArray *gap_hints; - GtkWidget *essay; - GtkWidget *play_note; - GtkWidget *play_btn; - gboolean played; - gboolean busy; - gboolean paused; - gboolean fallback; - gboolean restarting; - gboolean voice_dirty; - gboolean heard; - double speed; - double gain; - const char *voice; - GPid pid; - guint apply_src; - guint poll; -#ifdef __APPLE__ - id synth; -#endif -} EnEx; - -typedef struct { - int year; - GtkWidget *scroll; - GtkWidget *fixed; - GtkWidget *rail; - GtkWidget *nodes[EN_N]; - GtkWidget *labels[EN_N]; - double cx[EN_N]; - double cy[EN_N]; - int cols, rows, cw, ch; - guint idle; - double last_avail; - int last_cols, last_rows, last_cw, last_ch; - cairo_surface_t *cache; - int cache_w, cache_h; -} EngMap; - -static NetLesson en_rt[EN_YEARS][EN_N]; -static EngMap en_maps[EN_YEARS]; -static char en_map_page[EN_YEARS][16]; -static char en_unit_page[EN_YEARS][EN_N][16]; -static char en_ex_page[EN_YEARS][EN_N][16]; -static char en_title_key[EN_YEARS][EN_N][16]; -static char en_sub_key[EN_YEARS][EN_N][20]; -static gboolean en_ready; - -static void en_prepare(void) { - if (en_ready) - return; - en_ready = TRUE; - for (int y = 0; y < EN_YEARS; y++) { - g_snprintf(en_map_page[y], sizeof en_map_page[y], "en%dmap", y + 1); - for (int i = 0; i < EN_N; i++) { - g_snprintf(en_unit_page[y][i], sizeof en_unit_page[y][i], - "en%dunit%d", y + 1, i + 1); - g_snprintf(en_ex_page[y][i], sizeof en_ex_page[y][i], - "en%dex%d", y + 1, i + 1); - g_snprintf(en_title_key[y][i], sizeof en_title_key[y][i], - "en_y%d_u%d", y + 1, i + 1); - g_snprintf(en_sub_key[y][i], sizeof en_sub_key[y][i], - "en_y%d_u%d_sub", y + 1, i + 1); - en_rt[y][i].unit_page = en_unit_page[y][i]; - en_rt[y][i].ex_page = en_ex_page[y][i]; - en_rt[y][i].n_slides = (guint)en_lessons[y][i].n_slides; - } - } -} - -static void en_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - gchar *data; - GError *err = NULL; - - for (int y = 0; y < EN_YEARS; y++) { - for (int i = 0; i < EN_N; i++) { - char key[8]; - - g_snprintf(key, sizeof key, "%d-%d", y + 1, i + 1); - g_key_file_set_boolean(kf, "done", key, en_rt[y][i].done); - } - } - data = g_key_file_to_data(kf, NULL, NULL); - if (!g_file_set_contents(PROGRESS_EN, data, -1, &err)) { - g_warning("english progress: %s", err->message); - g_error_free(err); - } - g_free(data); - g_key_file_free(kf); -} - -void en_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - en_prepare(); - if (!g_key_file_load_from_file(kf, PROGRESS_EN, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - for (int y = 0; y < EN_YEARS; y++) { - for (int i = 0; i < EN_N; i++) { - char key[8]; - - g_snprintf(key, sizeof key, "%d-%d", y + 1, i + 1); - en_rt[y][i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - } - g_key_file_free(kf); -} - -static void en_refresh(void) { - for (int y = 0; y < EN_YEARS; y++) { - for (int i = 0; i < EN_N; i++) { - GtkWidget *node = en_maps[y].nodes[i]; - GtkWidget *icon = en_rt[y][i].done_icon; - - if (!node) - continue; - if (en_rt[y][i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } - } -} - -static void mark_en_done(int year, int index) { - if (year < 0 || year >= EN_YEARS || index < 0 || index >= EN_N) - return; - if (en_rt[year][index].done) - return; - en_rt[year][index].done = TRUE; - en_save_progress(); - en_refresh(); - refresh_stats_ui(); -} - -void progress_for_en(ProgressSum *out) { - out->total_ex += EN_YEARS * EN_N; - out->open_units += EN_YEARS * EN_N; - for (int y = 0; y < EN_YEARS; y++) { - for (int i = 0; i < EN_N; i++) { - if (en_rt[y][i].done) { - out->done_ex++; - out->done_units++; - } - } - } -} - -/* ------------------------------------------------------------------ */ -/* Path */ -/* ------------------------------------------------------------------ */ - -static void en_point(EngMap *m, double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= EN_N - 1) { k = EN_N - 2; u = 1.0; } - - p1x = m->cx[k]; p1y = m->cy[k]; - p2x = m->cx[k + 1]; p2y = m->cy[k + 1]; - if (k - 1 >= 0) { p0x = m->cx[k - 1]; p0y = m->cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < EN_N) { p3x = m->cx[k + 2]; p3y = m->cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -static void en_path(EngMap *m, cairo_t *cr, double t0, double t1) { - int n = (int)((t1 - t0) * 24.0); - double x, y; - - if (n < 1) - n = 1; - en_point(m, t0, &x, &y); - cairo_move_to(cr, x, y); - for (int s = 1; s <= n; s++) { - en_point(m, t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -static void en_geometry(EngMap *m, double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(EN_N - 1); - int rows; - - for (rows = 1; rows <= EN_N; rows++) { - int cols = (EN_N + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > EN_N) - rows = EN_N; - m->rows = rows; - m->cols = (EN_N + rows - 1) / rows; - if (m->cols < 1) - m->cols = 1; - m->cw = (int)(2.0 * ROAD_MX + (m->cols - 1) * PATH_SPAC); - m->ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (int r = 0; r < rows; r++) { - int base = r * m->cols; - int len = MIN(m->cols, EN_N - base); - int fwd = (r % 2) == 0; - - for (int c = 0; c < len; c++) { - int i = base + c; - int cc = fwd ? c : (m->cols - 1 - c); - - m->cx[i] = ROAD_MX + cc * PATH_SPAC; - m->cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -static void en_apply_layout(EngMap *m) { - if (!m->fixed) - return; - if (m->cols == m->last_cols && m->rows == m->last_rows && - m->cw == m->last_cw && m->ch == m->last_ch) - return; - m->last_cols = m->cols; - m->last_rows = m->rows; - m->last_cw = m->cw; - m->last_ch = m->ch; - if (m->cache) { - cairo_surface_destroy(m->cache); - m->cache = NULL; - } - for (int i = 0; i < EN_N; i++) { - if (!m->nodes[i] || !m->labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(m->fixed), m->nodes[i], - (int)(m->cx[i] - NODE_SIZE / 2.0), - (int)(m->cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(m->fixed), m->labels[i], - (int)(m->cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(m->cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - gtk_widget_set_size_request(m->fixed, m->cw, m->ch); - gtk_widget_set_size_request(m->rail, m->cw, m->ch); - gtk_fixed_move(GTK_FIXED(m->fixed), m->rail, 0, 0); - gtk_widget_queue_draw(m->rail); -} - -static void en_relayout(EngMap *m) { - GtkAdjustment *hadj; - double avail; - - if (!m->scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(m->scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - m->last_avail) < 1.0) - return; - m->last_avail = avail; - en_geometry(m, avail); - en_apply_layout(m); -} - -static gboolean en_relayout_idle(gpointer data) { - EngMap *m = data; - - m->idle = 0; - en_relayout(m); - return G_SOURCE_REMOVE; -} - -static void en_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, gpointer data) { - EngMap *m = data; - - (void)adj; - (void)ps; - if (m->idle == 0) - m->idle = g_idle_add(en_relayout_idle, m); -} - -static void en_render_rail(EngMap *m, cairo_t *cr) { - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - cairo_new_path(cr); - en_path(m, cr, 0.0, (double)(EN_N - 1)); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - en_path(m, cr, 0.0, (double)(EN_N - 1)); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -static void en_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - EngMap *m = data; - - (void)area; - (void)width; - (void)height; - if (!m->cache || m->cache_w != m->cw || m->cache_h != m->ch) { - cairo_t *rcr; - - if (m->cache) - cairo_surface_destroy(m->cache); - m->cache_w = m->cw > 0 ? m->cw : 1; - m->cache_h = m->ch > 0 ? m->ch : 1; - m->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - m->cache_w, m->cache_h); - rcr = cairo_create(m->cache); - en_render_rail(m, rcr); - cairo_destroy(rcr); - } - cairo_set_source_surface(cr, m->cache, 0, 0); - cairo_paint(cr); -} - -void en_rail_theme_reset(void) { - for (int y = 0; y < EN_YEARS; y++) { - if (en_maps[y].cache) { - cairo_surface_destroy(en_maps[y].cache); - en_maps[y].cache = NULL; - } - if (en_maps[y].rail) - gtk_widget_queue_draw(en_maps[y].rail); - } -} - -static void en_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof name, "slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static void en_add_node(EngMap *m, GtkFixed *fixed, int index) { - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_add_css_class(card, "current"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", index + 1); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - en_rt[m->year][index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(en_open_unit), - &en_rt[m->year][index]); - - m->nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - i18n_bind(name, en_title_key[m->year][index], 0); - m->labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} - -static GtkWidget *en_year_button(int year) { - static const char *keys[] = {"en_year1", "en_year2", "en_year3", "en_year4"}; - static const char *subs[] = {"en_y1_sub", "en_y2_sub", "en_y3_sub", "en_y4_sub"}; - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - GtkWidget *sub; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 112); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_widget_set_margin_top(row, 8); - gtk_widget_set_margin_bottom(row, 8); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", year); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, keys[year - 1], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - sub = gtk_label_new(NULL); - i18n_bind(sub, subs[year - 1], 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0); - gtk_widget_add_css_class(sub, "meaning"); - gtk_widget_set_visible(sub, TRUE); - gtk_box_append(GTK_BOX(texts), sub); - - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(en_map_page[year - 1]), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - return btn; -} - -GtkWidget *build_enyears_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - - en_prepare(); - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "English", "en_years_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 460, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - for (int y = 1; y <= EN_YEARS; y++) - gtk_box_append(GTK_BOX(list), en_year_button(y)); - return page; -} - -GtkWidget *build_enmap_page(int year) { - EngMap *m; - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - static const char *year_keys[] = { - "en_year1", "en_year2", "en_year3", "en_year4", - }; - static const char *sub_keys[] = { - "en_y1_sub", "en_y2_sub", "en_y3_sub", "en_y4_sub", - }; - - en_prepare(); - m = &en_maps[year]; - m->year = year; - en_geometry(m, 1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), - top_bar("enyears", year_keys[year], sub_keys[year])); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - m->scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, m->cw, m->ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - m->fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, m->cw, m->ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), en_draw_rail, m, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - m->rail = rail; - - for (int i = 0; i < EN_N; i++) - en_add_node(m, GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", G_CALLBACK(en_adjust_notify), m); - g_signal_connect(va, "notify::page-size", G_CALLBACK(en_adjust_notify), m); - en_refresh(); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Slides */ -/* ------------------------------------------------------------------ */ - -void skill_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof name, "slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - } - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); -} - -static int en_note_w = -1; -static gboolean en_note_ready; - -static void en_rescale_notes(int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) - body = 14; - if (body > 26) - body = 26; - head = body + 14; - if (head > 46) - head = 46; - kick = body - 3; - if (kick < 11) - kick = 11; - for (int y = 0; y < EN_YEARS; y++) - for (int i = 0; i < EN_N; i++) - net_rescale_lesson_notes(&en_rt[y][i], body, head, kick); -} - -static gboolean en_note_tick(GtkWidget *w, GdkFrameClock *clock, gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width != en_note_w) { - en_note_w = width; - en_rescale_notes(width); - } - return G_SOURCE_CONTINUE; -} - -static void en_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (L && L->idx > 0) { - L->idx--; - skill_slide_apply(L); - } -} - -static void en_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - skill_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -void en_lessons_apply_lang(void) { - for (int y = 0; y < EN_YEARS; y++) - for (int i = 0; i < EN_N; i++) - skill_slide_apply(&en_rt[y][i]); -} - -GtkWidget *skill_unit_page(NetLesson *L, const EnLesson *lesson, - const char *back, const char *title_key, - const char *sub_key) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = (guint)lesson->n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - gtk_box_append(GTK_BOX(page), - top_bar(back, title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < L->n_slides; s++) { - GtkWidget *card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - char name[16]; - - g_snprintf(name, sizeof name, "slide%u", s); - gtk_widget_set_margin_top(card, 8); - gtk_widget_set_margin_bottom(card, 8); - net_note_kicker(card, lesson->slides[s].kicker); - net_note_title(card, lesson->slides[s].title); - for (int i = 0; i < 8 && lesson->slides[s].line[i]; i++) - net_note_line(card, lesson->slides[s].line[i], FALSE); - if (lesson->slides[s].tip) - net_note_line(card, lesson->slides[s].tip, TRUE); - gtk_stack_add_named(GTK_STACK(L->stack), card, name); - } - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(en_slide_prev), L); - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - gtk_box_append(GTK_BOX(nav), L->next_btn); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(en_slide_next), L); - if (!en_note_ready) { - gtk_widget_add_tick_callback(L->stack, en_note_tick, NULL, NULL); - en_note_ready = TRUE; - } - en_rescale_notes(0); - net_notes_target = NULL; - skill_slide_apply(L); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise */ -/* ------------------------------------------------------------------ */ - -static GtkWidget *en_heading(GtkWidget *body, const char *key) { - GtkWidget *label = gtk_label_new(NULL); - - i18n_bind(label, key, 0); - gtk_widget_set_halign(label, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(label), TRUE); - gtk_widget_add_css_class(label, "quiz-heading"); - gtk_widget_set_margin_top(label, 8); - gtk_box_append(GTK_BOX(body), label); - return label; -} - -static GtkWidget *en_passage(GtkWidget *body, const char *text, gboolean hide) { - GtkWidget *label = gtk_label_new(text); - - gtk_label_set_wrap(GTK_LABEL(label), TRUE); - gtk_label_set_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); - gtk_label_set_selectable(GTK_LABEL(label), TRUE); - gtk_label_set_xalign(GTK_LABEL(label), 0); - gtk_widget_set_halign(label, GTK_ALIGN_START); - gtk_widget_add_css_class(label, "quiz-intro"); - gtk_widget_set_visible(label, !hide); - gtk_box_append(GTK_BOX(body), label); - return label; -} - -static void en_add_mcq(EnEx *ctx, GtkWidget *body, const ChoiceQ *qs, - const char **hints, int n) { - for (int i = 0; i < n; i++) { - EnPick pick; - GtkWidget *card; - - memset(&pick, 0, sizeof pick); - pick.q = &qs[i]; - card = mcq_append_question(body, i + 1, &qs[i], pick.tb); - if (hints && hints[i]) - pick.hint = meaning_add(card, hints[i]); - g_array_append_val(ctx->picks, pick); - } -} - -static int en_word_count(const char *norm) { - int n = 0; - const char *p = norm ? norm : ""; - - while (*p) { - while (*p == ' ') - p++; - if (!*p) - break; - n++; - while (*p && *p != ' ') - p++; - } - return n; -} - -static gboolean en_has_word(const char *norm, const char *word) { - char *key = normalize_answer(word); - size_t n; - const char *p; - gboolean ok = FALSE; - - if (!key || !key[0]) { - g_free(key); - return TRUE; - } - n = strlen(key); - for (p = norm; p && (p = strstr(p, key)); p += n) { - gboolean left = p == norm || p[-1] == ' '; - gboolean right = p[n] == '\0' || p[n] == ' '; - - if (left && right) { - ok = TRUE; - break; - } - } - g_free(key); - return ok; -} - -static void en_sync_play(EnEx *ctx) { - const char *key = "en_play"; - - if (!ctx->play_btn) - return; - if (ctx->paused) - key = "en_resume"; - else if (ctx->busy) - key = "en_pause"; - gtk_button_set_label(GTK_BUTTON(ctx->play_btn), tr(key)); -} - -static void en_start_fallback(EnEx *ctx) { - ctx->fallback = TRUE; - ctx->played = TRUE; - ctx->busy = FALSE; - ctx->paused = FALSE; - if (ctx->play_note) { - gtk_label_set_text(GTK_LABEL(ctx->play_note), tr("en_listen_fallback")); - gtk_widget_set_visible(ctx->play_note, TRUE); - } - en_sync_play(ctx); -} - -static gboolean en_launch(EnEx *ctx); - -static void en_voice_done(GPid pid, gint status, gpointer data) { - EnEx *ctx = data; - gboolean ok = FALSE; - gboolean restart = ctx->restarting; - - g_spawn_close_pid(pid); - if (ctx->pid == pid) - ctx->pid = 0; - if (restart) { - ctx->restarting = FALSE; - en_launch(ctx); - return; - } -#ifdef G_OS_UNIX - ok = WIFEXITED(status) && WEXITSTATUS(status) == 0; -#else - ok = status == 0; -#endif - ctx->busy = FALSE; - ctx->paused = FALSE; - en_sync_play(ctx); - if (!ok) - en_start_fallback(ctx); -} - -static gboolean en_spawn(char **argv, GPid *pid) { - GError *err = NULL; - - if (!argv[0] || !g_find_program_in_path(argv[0])) - return FALSE; - if (!g_spawn_async(NULL, argv, NULL, - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, - NULL, NULL, pid, &err)) { - g_clear_error(&err); - return FALSE; - } - return TRUE; -} - -#ifdef __APPLE__ -static id en_ns(const char *s) { - return ((id (*)(Class, SEL, const char *))objc_msgSend)( - objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), s); -} - -static void en_mac_levels(EnEx *ctx) { - float rate = (float)(180.0 * (ctx->speed > 0.2 ? ctx->speed : 0.9)); - float vol = (float)(ctx->gain < 0 ? 0 : (ctx->gain > 1 ? 1 : ctx->gain)); - - ((void (*)(id, SEL, float))objc_msgSend)( - ctx->synth, sel_registerName("setRate:"), rate); - ((void (*)(id, SEL, float))objc_msgSend)( - ctx->synth, sel_registerName("setVolume:"), vol); -} - -static gboolean en_mac_try_voice(id synth, const char *name) { - return ((BOOL (*)(id, SEL, id))objc_msgSend)( - synth, sel_registerName("setVoice:"), en_ns(name)); -} - -static void en_mac_choose(id synth, const char *lang) { - static const char *en_voices[] = { - "com.apple.voice.compact.en-GB.Daniel", - "com.apple.speech.synthesis.voice.daniel", - "com.apple.voice.compact.en-US.Samantha", - "com.apple.speech.synthesis.voice.samantha", - NULL - }; - static const char *de_voices[] = { - "com.apple.voice.compact.de-DE.Anna", - "com.apple.speech.synthesis.voice.anna", - "com.apple.voice.compact.de-DE.Helena", - "com.apple.speech.synthesis.voice.petra", - NULL - }; - gboolean german = lang && g_str_has_prefix(lang, "de"); - const char **list = german ? de_voices : en_voices; - const char *needle = german ? "de-DE" : "en-GB"; - Class cls; - id voices; - unsigned long n; - - for (int i = 0; list[i]; i++) { - if (en_mac_try_voice(synth, list[i])) - return; - } - cls = objc_getClass("NSSpeechSynthesizer"); - if (!cls) - return; - voices = ((id (*)(Class, SEL))objc_msgSend)( - cls, sel_registerName("availableVoices")); - if (!voices) - return; - n = ((unsigned long (*)(id, SEL))objc_msgSend)( - voices, sel_registerName("count")); - for (unsigned long i = 0; i < n; i++) { - id name = ((id (*)(id, SEL, unsigned long))objc_msgSend)( - voices, sel_registerName("objectAtIndex:"), i); - const char *utf = ((const char *(*)(id, SEL))objc_msgSend)( - name, sel_registerName("UTF8String")); - - if (utf && strstr(utf, needle) && en_mac_try_voice(synth, utf)) - return; - } -} - -static gboolean en_mac_ensure(EnEx *ctx) { - Class cls; - id obj; - - if (ctx->synth) - return TRUE; - cls = objc_getClass("NSSpeechSynthesizer"); - if (!cls) - return FALSE; - obj = ((id (*)(Class, SEL))objc_msgSend)(cls, sel_registerName("alloc")); - obj = ((id (*)(id, SEL))objc_msgSend)(obj, sel_registerName("init")); - if (!obj) - return FALSE; - ctx->synth = obj; - en_mac_choose(obj, ctx->voice); - return TRUE; -} - -static gboolean en_mac_speaking(EnEx *ctx) { - if (!ctx->synth) - return FALSE; - return ((BOOL (*)(id, SEL))objc_msgSend)( - ctx->synth, sel_registerName("isSpeaking")); -} - -static void en_mac_stop(EnEx *ctx) { - if (ctx->synth) - ((void (*)(id, SEL))objc_msgSend)( - ctx->synth, sel_registerName("stopSpeaking")); -} - -static gboolean en_mac_start(EnEx *ctx) { - if (!en_mac_ensure(ctx)) - return FALSE; - en_mac_levels(ctx); - ctx->heard = FALSE; - return ((BOOL (*)(id, SEL, id))objc_msgSend)( - ctx->synth, sel_registerName("startSpeakingString:"), - en_ns(ctx->lesson->listening)); -} - -static void en_mac_pause(EnEx *ctx) { - ((BOOL (*)(id, SEL, long))objc_msgSend)( - ctx->synth, sel_registerName("pauseSpeakingAtBoundary:"), 1L); -} - -static void en_mac_resume(EnEx *ctx) { - if (ctx->voice_dirty) { - ctx->voice_dirty = FALSE; - en_mac_stop(ctx); - en_mac_start(ctx); - return; - } - ((BOOL (*)(id, SEL))objc_msgSend)( - ctx->synth, sel_registerName("continueSpeaking")); -} - -static gboolean en_poll_speech(gpointer data) { - EnEx *ctx = data; - - if (ctx->paused || ctx->restarting) - return G_SOURCE_CONTINUE; - if (en_mac_speaking(ctx)) { - ctx->heard = TRUE; - return G_SOURCE_CONTINUE; - } - if (!ctx->heard) - return G_SOURCE_CONTINUE; - ctx->poll = 0; - ctx->busy = FALSE; - ctx->paused = FALSE; - en_sync_play(ctx); - return G_SOURCE_REMOVE; -} -#endif - -static gboolean en_launch(EnEx *ctx) { - char *text = (char *)ctx->lesson->listening; - double speed = ctx->speed > 0.2 ? ctx->speed : 0.9; - char rate[16]; - char amp[16]; - - ctx->played = TRUE; - ctx->busy = TRUE; - ctx->paused = FALSE; - ctx->voice_dirty = FALSE; -#ifdef __APPLE__ - if (en_mac_start(ctx)) { - if (!ctx->poll) - ctx->poll = g_timeout_add(200, en_poll_speech, ctx); - en_sync_play(ctx); - return TRUE; - } -#endif - g_snprintf(rate, sizeof rate, "%d", (int)(160.0 * speed)); - g_snprintf(amp, sizeof amp, "%d", (int)(ctx->gain * 200.0)); - { - const char *voice = ctx->voice && ctx->voice[0] ? ctx->voice : "en"; - char *a[] = {"espeak-ng", "-v", (char *)voice, "-s", rate, "-a", amp, text, NULL}; - char *b[] = {"espeak", "-v", (char *)voice, "-s", rate, "-a", amp, text, NULL}; -#ifdef __APPLE__ - char *c_en[] = {"say", "-r", rate, text, NULL}; - char *c_de[] = {"say", "-v", "Anna", "-r", rate, text, NULL}; - char **tries[] = {g_str_has_prefix(voice, "de") ? c_de : c_en}; - int n = 1; -#else - char *c[] = {"spd-say", "-l", (char *)voice, "-r", rate, text, NULL}; - char **tries[] = {a, b, c}; - int n = 3; -#endif - (void)a; - (void)b; - for (int i = 0; i < n; i++) { - if (en_spawn(tries[i], &ctx->pid)) { - g_child_watch_add(ctx->pid, en_voice_done, ctx); - en_sync_play(ctx); - return TRUE; - } - } - } - ctx->busy = FALSE; - en_start_fallback(ctx); - return FALSE; -} - -static void en_pause_voice(EnEx *ctx) { - ctx->paused = TRUE; -#ifdef __APPLE__ - if (ctx->synth && en_mac_speaking(ctx)) { - en_mac_pause(ctx); - en_sync_play(ctx); - return; - } -#endif -#ifdef G_OS_UNIX - if (ctx->pid) { - kill((pid_t)ctx->pid, SIGSTOP); - en_sync_play(ctx); - return; - } -#endif - en_sync_play(ctx); -} - -static void en_resume_voice(EnEx *ctx) { - ctx->paused = FALSE; -#ifdef __APPLE__ - if (ctx->synth) { - en_mac_resume(ctx); - if (!ctx->poll) - ctx->poll = g_timeout_add(200, en_poll_speech, ctx); - en_sync_play(ctx); - return; - } -#endif - if (ctx->voice_dirty) { - ctx->voice_dirty = FALSE; - if (ctx->pid) { - ctx->restarting = TRUE; -#ifdef G_OS_UNIX - kill((pid_t)ctx->pid, SIGKILL); -#endif - } - en_sync_play(ctx); - return; - } -#ifdef G_OS_UNIX - if (ctx->pid) { - kill((pid_t)ctx->pid, SIGCONT); - en_sync_play(ctx); - return; - } -#endif - en_sync_play(ctx); -} - -static void en_restart_voice(EnEx *ctx) { - ctx->voice_dirty = FALSE; - ctx->paused = FALSE; -#ifdef __APPLE__ - if (ctx->synth) { - ctx->restarting = TRUE; - en_mac_stop(ctx); - ctx->restarting = FALSE; - en_mac_start(ctx); - if (!ctx->poll) - ctx->poll = g_timeout_add(200, en_poll_speech, ctx); - en_sync_play(ctx); - return; - } -#endif - if (ctx->fallback) - return; - if (ctx->pid) { - ctx->restarting = TRUE; -#ifdef G_OS_UNIX - kill((pid_t)ctx->pid, SIGKILL); -#endif - } -} - -static gboolean en_apply_voice(gpointer data) { - EnEx *ctx = data; - - ctx->apply_src = 0; - if (ctx->busy && !ctx->paused) - en_restart_voice(ctx); - return G_SOURCE_REMOVE; -} - -static void en_level_changed(GtkRange *range, gpointer data) { - EnEx *ctx = data; - const char *which = g_object_get_data(G_OBJECT(range), "en-level"); - - if (g_strcmp0(which, "speed") == 0) - ctx->speed = gtk_range_get_value(range); - else - ctx->gain = gtk_range_get_value(range) / 100.0; - ctx->voice_dirty = TRUE; - if (ctx->apply_src) - g_source_remove(ctx->apply_src); - ctx->apply_src = g_timeout_add(180, en_apply_voice, ctx); -} - -static void en_play_clicked(GtkButton *button, gpointer data) { - EnEx *ctx = data; - - (void)button; - if (!ctx->lesson->listening) - return; - ctx->played = TRUE; - if (!ctx->busy) { - en_launch(ctx); - return; - } - if (ctx->paused) - en_resume_voice(ctx); - else - en_pause_voice(ctx); -} - -static char *en_format_level(GtkScale *scale, double value, gpointer data) { - const char *which = g_object_get_data(G_OBJECT(scale), "en-level"); - - (void)data; - if (g_strcmp0(which, "speed") == 0) - return g_strdup_printf("%.1f×", value); - return g_strdup_printf("%.0f %%", value); -} - -static GtkWidget *en_level_control(EnEx *ctx, const char *key, const char *which, - double min, double max, double value) { - GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - GtkWidget *lab = gtk_label_new(NULL); - GtkWidget *scale = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, - min, max, max > 10 ? 1 : 0.1); - - i18n_bind(lab, key, 0); - gtk_widget_add_css_class(lab, "listen-caption"); - gtk_label_set_xalign(GTK_LABEL(lab), 0); - gtk_widget_set_halign(lab, GTK_ALIGN_START); - g_object_set_data(G_OBJECT(scale), "en-level", (gpointer)which); - gtk_scale_set_format_value_func(GTK_SCALE(scale), en_format_level, NULL, NULL); - gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE); - gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT); - gtk_range_set_value(GTK_RANGE(scale), value); - gtk_widget_add_css_class(scale, "listen-scale"); - gtk_widget_set_size_request(scale, 156, -1); - gtk_widget_set_hexpand(scale, FALSE); - gtk_widget_set_halign(scale, GTK_ALIGN_FILL); - g_signal_connect(scale, "value-changed", G_CALLBACK(en_level_changed), ctx); - gtk_box_append(GTK_BOX(box), lab); - gtk_box_append(GTK_BOX(box), scale); - gtk_widget_set_hexpand(box, FALSE); - gtk_widget_set_halign(box, GTK_ALIGN_FILL); - return box; -} - -/* Transcript stays on screen. Speed and volume sit in a short column - * beside it, so the sliders do not run the width of the page. */ -static void en_add_listen(EnEx *ctx, GtkWidget *parent) { - GtkWidget *card; - GtkWidget *text_col; - GtkWidget *script; - GtkWidget *controls; - GtkWidget *play; - GtkWidget *note; - - en_heading(parent, "en_sec_listen"); - - note = gtk_label_new(NULL); - i18n_bind(note, "en_listen_note", 0); - gtk_label_set_wrap(GTK_LABEL(note), TRUE); - gtk_label_set_xalign(GTK_LABEL(note), 0); - gtk_widget_set_halign(note, GTK_ALIGN_START); - gtk_widget_add_css_class(note, "quiz-intro"); - gtk_box_append(GTK_BOX(parent), note); - - card = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 22); - gtk_widget_add_css_class(card, "quiz-card"); - gtk_widget_add_css_class(card, "listen-card"); - - controls = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_widget_set_hexpand(controls, FALSE); - gtk_widget_set_halign(controls, GTK_ALIGN_START); - gtk_widget_set_valign(controls, GTK_ALIGN_START); - gtk_widget_set_size_request(controls, 168, -1); - - ctx->speed = 0.9; - ctx->gain = 1.0; - play = gtk_button_new_with_label(tr("en_play")); - gtk_widget_add_css_class(play, "btn-primary"); - gtk_widget_set_hexpand(play, TRUE); - gtk_widget_set_halign(play, GTK_ALIGN_FILL); - ctx->play_btn = play; - g_signal_connect(play, "clicked", G_CALLBACK(en_play_clicked), ctx); - gtk_box_append(GTK_BOX(controls), play); - gtk_box_append(GTK_BOX(controls), - en_level_control(ctx, "en_speed", "speed", - 0.6, 1.5, ctx->speed)); - gtk_box_append(GTK_BOX(controls), - en_level_control(ctx, "en_volume", "volume", - 0, 100, ctx->gain * 100.0)); - - text_col = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - gtk_widget_set_hexpand(text_col, TRUE); - gtk_widget_set_valign(text_col, GTK_ALIGN_CENTER); - - script = gtk_label_new(ctx->lesson->listening); - gtk_label_set_wrap(GTK_LABEL(script), TRUE); - gtk_label_set_wrap_mode(GTK_LABEL(script), PANGO_WRAP_WORD_CHAR); - gtk_label_set_width_chars(GTK_LABEL(script), 36); - gtk_label_set_max_width_chars(GTK_LABEL(script), 72); - gtk_label_set_selectable(GTK_LABEL(script), TRUE); - gtk_label_set_xalign(GTK_LABEL(script), 0); - gtk_widget_set_halign(script, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(script, TRUE); - gtk_widget_add_css_class(script, "listen-script"); - gtk_box_append(GTK_BOX(text_col), script); - - ctx->play_note = gtk_label_new(""); - gtk_label_set_wrap(GTK_LABEL(ctx->play_note), TRUE); - gtk_label_set_xalign(GTK_LABEL(ctx->play_note), 0); - gtk_widget_set_halign(ctx->play_note, GTK_ALIGN_START); - gtk_widget_add_css_class(ctx->play_note, "meaning"); - gtk_widget_set_visible(ctx->play_note, FALSE); - gtk_box_append(GTK_BOX(text_col), ctx->play_note); - - gtk_box_append(GTK_BOX(card), controls); - gtk_box_append(GTK_BOX(card), text_col); - gtk_box_append(GTK_BOX(parent), card); -} - -static void en_check(GtkButton *button, gpointer data) { - EnEx *ctx = data; - int mcq_ok = 0; - int gap_ok = 0; - gboolean write_ok = TRUE; - gboolean all; - - (void)button; - if (ctx->lesson->listening && !ctx->played) { - set_feedback(ctx->feedback, FALSE, tr("en_listen_first")); - return; - } - - for (guint i = 0; i < ctx->picks->len; i++) { - EnPick *p = &g_array_index(ctx->picks, EnPick, i); - int active = -1; - - for (int o = 0; o < p->q->n_options; o++) { - gtk_widget_remove_css_class(GTK_WIDGET(p->tb[o]), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(p->tb[o]), "wrong"); - if (gtk_toggle_button_get_active(p->tb[o])) - active = o; - } - if (active == p->q->correct) { - mcq_ok++; - if (active >= 0) - gtk_widget_add_css_class(GTK_WIDGET(p->tb[active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class(GTK_WIDGET(p->tb[active]), "wrong"); - } - if (p->hint) - gtk_widget_set_visible(p->hint, TRUE); - } - - for (guint i = 0; i < ctx->entries->len; i++) { - GtkWidget *entry = g_array_index(ctx->entries, GtkWidget *, i); - const char *txt = gtk_editable_get_text(GTK_EDITABLE(entry)); - char *norm = normalize_answer(txt); - gboolean ok = answer_accepts(norm, ctx->lesson->gaps[i].answers); - - gtk_widget_remove_css_class(entry, "answer-ok"); - gtk_widget_remove_css_class(entry, "answer-wrong"); - gtk_widget_add_css_class(entry, ok ? "answer-ok" : "answer-wrong"); - if (ok) - gap_ok++; - g_free(norm); - if (i < ctx->gap_hints->len) { - GtkWidget *hint = g_array_index(ctx->gap_hints, GtkWidget *, i); - - if (hint) - gtk_widget_set_visible(hint, TRUE); - } - } - - if (ctx->essay && ctx->lesson->write_prompt) { - GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ctx->essay)); - GtkTextIter a, b; - char *raw; - char *norm; - gboolean keys = TRUE; - - gtk_text_buffer_get_bounds(buf, &a, &b); - raw = gtk_text_buffer_get_text(buf, &a, &b, FALSE); - norm = normalize_answer(raw); - if (ctx->lesson->write_keys) { - gchar **parts = g_strsplit(ctx->lesson->write_keys, "|", -1); - - for (int i = 0; parts[i]; i++) { - if (parts[i][0] && !en_has_word(norm, parts[i])) - keys = FALSE; - } - g_strfreev(parts); - } - write_ok = keys && en_word_count(norm) >= ctx->lesson->write_min; - g_free(norm); - g_free(raw); - } - - all = mcq_ok == (int)ctx->picks->len - && gap_ok == ctx->lesson->n_gaps - && write_ok; - if (all) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - if (ctx->model) - gtk_widget_set_visible(ctx->model, TRUE); - if (ctx->on_done) - ctx->on_done(ctx->year, ctx->index); - } else if (ctx->essay && !write_ok && - mcq_ok == (int)ctx->picks->len && - gap_ok == ctx->lesson->n_gaps) { - set_feedback(ctx->feedback, FALSE, tr("en_write_short")); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -GtkWidget *skill_ex_page(const EnLesson *lesson, int year, int index, - void (*on_done)(int, int), - const char *back, const char *title_key, - const char *voice) { - EnEx *ctx = g_new0(EnEx, 1); - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - - ctx->year = year; - ctx->index = index; - ctx->lesson = lesson; - ctx->on_done = on_done; - ctx->voice = voice && voice[0] ? voice : "en"; - ctx->picks = g_array_new(FALSE, FALSE, sizeof(EnPick)); - ctx->entries = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - ctx->gap_hints = g_array_new(FALSE, TRUE, sizeof(GtkWidget *)); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), top_bar(back, title_key, NULL)); - - /* Keep the recording in view while the questions scroll. Lessons that - * also have a reading passage leave it in the scroll, above the player. */ - if (lesson->listening && !lesson->reading) - en_add_listen(ctx, page); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_bottom(body, 12); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - if (lesson->reading) { - en_heading(body, lesson->n_read ? "en_sec_read" : "en_sec_read"); - en_passage(body, lesson->reading, FALSE); - if (lesson->n_read) - en_add_mcq(ctx, body, lesson->readq, lesson->read_hints, lesson->n_read); - } - - if (lesson->listening && lesson->reading) - en_add_listen(ctx, body); - if (lesson->n_listen) - en_add_mcq(ctx, body, lesson->listenq, lesson->listen_hints, - lesson->n_listen); - - if (lesson->n_gaps) { - en_heading(body, "en_sec_gap"); - for (int i = 0; i < lesson->n_gaps; i++) { - GtkWidget *card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - GtkWidget *prompt = gtk_label_new(NULL); - GtkWidget *entry = gtk_entry_new(); - GtkWidget *hint = NULL; - char *text = g_strdup_printf("%d.) %s", i + 1, lesson->gaps[i].prompt); - - gtk_widget_add_css_class(card, "quiz-card"); - gtk_label_set_text(GTK_LABEL(prompt), text); - g_free(text); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_label_set_xalign(GTK_LABEL(prompt), 0); - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(card), prompt); - gtk_editable_set_width_chars(GTK_EDITABLE(entry), 24); - gtk_widget_set_halign(entry, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(card), entry); - if (lesson->gaps[i].meaning) - hint = meaning_add(card, lesson->gaps[i].meaning); - gtk_box_append(GTK_BOX(body), card); - g_array_append_val(ctx->entries, entry); - g_array_append_val(ctx->gap_hints, hint); - } - } - - if (lesson->write_prompt) { - GtkWidget *prompt; - GtkWidget *view; - - en_heading(body, "en_sec_write"); - prompt = gtk_label_new(lesson->write_prompt); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_label_set_xalign(GTK_LABEL(prompt), 0); - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_widget_add_css_class(prompt, "quiz-q"); - gtk_box_append(GTK_BOX(body), prompt); - - view = gtk_text_view_new(); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR); - gtk_widget_set_size_request(view, -1, 140); - gtk_widget_add_css_class(view, "quiz-card"); - gtk_box_append(GTK_BOX(body), view); - ctx->essay = view; - - ctx->model = gtk_label_new(lesson->write_model); - gtk_label_set_wrap(GTK_LABEL(ctx->model), TRUE); - gtk_label_set_selectable(GTK_LABEL(ctx->model), TRUE); - gtk_label_set_xalign(GTK_LABEL(ctx->model), 0); - gtk_widget_set_halign(ctx->model, GTK_ALIGN_START); - gtk_widget_add_css_class(ctx->model, "meaning"); - gtk_widget_set_visible(ctx->model, FALSE); - gtk_box_append(GTK_BOX(body), ctx->model); - } - - if (lesson->n_quiz) { - en_heading(body, "en_sec_quiz"); - en_add_mcq(ctx, body, lesson->quiz, lesson->quiz_hints, lesson->n_quiz); - } - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_widget_set_margin_top(check, 8); - gtk_box_append(GTK_BOX(body), check); - g_signal_connect(check, "clicked", G_CALLBACK(en_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(ctx->feedback), TRUE); - gtk_box_append(GTK_BOX(body), ctx->feedback); - return page; -} - -static GtkWidget *build_en_unit_page(int year, int index) { - return skill_unit_page(&en_rt[year][index], &en_lessons[year][index], - en_map_page[year], en_title_key[year][index], - en_sub_key[year][index]); -} - -static GtkWidget *build_en_ex_page(int year, int index) { - return skill_ex_page(&en_lessons[year][index], year, index, mark_en_done, - en_unit_page[year][index], en_title_key[year][index], - "en"); -} - -void add_en_pages(GtkStack *stack) { - en_prepare(); - for (int y = 0; y < EN_YEARS; y++) { - gtk_stack_add_named(stack, build_enmap_page(y), en_map_page[y]); - for (int i = 0; i < EN_N; i++) { - gtk_stack_add_named(stack, build_en_unit_page(y, i), - en_unit_page[y][i]); - gtk_stack_add_named(stack, build_en_ex_page(y, i), - en_ex_page[y][i]); - } - } -} - -void draw_uk_flag(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - double cx = width / 2.0; - double cy = height / 2.0; - double r = MIN(width, height) / 2.0 - 2.0; - double w = (double)width; - double h = (double)height; - - (void)area; - (void)data; - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_save(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_clip(cr); - - cairo_set_source_rgb(cr, 0.01, 0.14, 0.40); - cairo_paint(cr); - - cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_set_line_width(cr, w * 0.16); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, w, h); - cairo_move_to(cr, w, 0); - cairo_line_to(cr, 0, h); - cairo_stroke(cr); - - cairo_set_source_rgb(cr, 0.80, 0.05, 0.15); - cairo_set_line_width(cr, w * 0.055); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, w, h); - cairo_move_to(cr, w, 0); - cairo_line_to(cr, 0, h); - cairo_stroke(cr); - - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_rectangle(cr, 0, h * 0.38, w, h * 0.24); - cairo_rectangle(cr, w * 0.38, 0, w * 0.24, h); - cairo_fill(cr); - - cairo_set_source_rgb(cr, 0.80, 0.05, 0.15); - cairo_rectangle(cr, 0, h * 0.43, w, h * 0.14); - cairo_rectangle(cr, w * 0.43, 0, w * 0.14, h); - cairo_fill(cr); - - cairo_restore(cr); -} diff --git a/src/english_i18n.inc b/src/english_i18n.inc deleted file mode 100644 index 8fdb949..0000000 --- a/src/english_i18n.inc +++ /dev/null @@ -1,90 +0,0 @@ - {"en_years_sub", "Čtyři ročníky podle osnov gymnázia, od A2 k maturitě.", "Four years of the gymnasium syllabus, from A2 to the exam."}, - {"en_year1", "1. ročník", "Year 1"}, - {"en_year2", "2. ročník", "Year 2"}, - {"en_year3", "3. ročník", "Year 3"}, - {"en_year4", "4. ročník", "Year 4"}, - {"en_sec_read", "Čtení", "Reading"}, - {"en_sec_listen", "Poslech", "Listening"}, - {"en_sec_write", "Psaní", "Writing"}, - {"en_sec_gap", "Doplňte", "Complete"}, - {"en_sec_quiz", "Kvíz", "Quiz"}, - {"en_sec_test", "Jazyková část", "Language"}, - {"en_play", "Přehrát", "Play"}, - {"en_pause", "Pauza", "Pause"}, - {"en_resume", "Pokračovat", "Resume"}, - {"en_speed", "Rychlost", "Speed"}, - {"en_volume", "Hlasitost", "Volume"}, - {"en_listen_note", "Text nahrávky zůstává vidět. Přehrání obstará hlas zařízení.", "The recording text stays visible. The device voice plays it."}, - {"en_listen_first", "Nejdřív poslech přehrajte.", "Play the recording first."}, - {"en_listen_fallback", "Hlas není dostupný. Text si můžete přečíst.", "No voice is available. You can read the text."}, - {"en_write_short", "Text je krátký nebo v něm chybí požadovaná slova.", "The text is short or it misses the required words."}, - {"en_model", "Vzor", "Model"}, - {"en_write_ph", "Pište anglicky…", "Write in English…"}, - {"en_y1_sub", "Osobní život, škola, domov a minulost. Úroveň A2.", "Personal life, school, home and the past. Level A2."}, - {"en_y1_u1", "Já a moje rodina", "Me and my family"}, - {"en_y1_u1_sub", "Sloveso be, have got a přivlastňovací zájmena. Doplňování a kvíz.", "The verb be, have got and possessives. Gaps and a quiz."}, - {"en_y1_u2", "Školní den", "A school day"}, - {"en_y1_u2_sub", "Přítomný čas prostý. Čtení a doplňování.", "The present simple. Reading and gaps."}, - {"en_y1_u3", "Víkend ve městě", "A weekend in town"}, - {"en_y1_u3_sub", "Přítomný čas průběhový pro domluvené plány. Poslech.", "The present continuous for arrangements. Listening."}, - {"en_y1_u4", "Můj pokoj", "My room"}, - {"en_y1_u4_sub", "There is / there are a předložky místa. Krátký popis a kvíz.", "There is / there are and prepositions. A short description and a quiz."}, - {"en_y1_u5", "Na trhu", "At the market"}, - {"en_y1_u5_sub", "Počitatelnost, some a any, how much a how many. Čtení a doplňování.", "Countability, some and any, how much and how many. Reading and gaps."}, - {"en_y1_u6", "Minulé léto", "Last summer"}, - {"en_y1_u6_sub", "Minulý čas prostý, pravidelná i nepravidelná slovesa. Poslech a kvíz.", "The past simple, regular and irregular verbs. Listening and a quiz."}, - {"en_y1_u7", "Zpráva kamarádovi", "A message to a friend"}, - {"en_y1_u7_sub", "Will a going to. Krátká neformální zpráva a doplňování.", "Will and going to. A short informal message and gaps."}, - {"en_y1_u8", "Test 1. ročníku", "Year 1 test"}, - {"en_y1_u8_sub", "Čtení, poslech, gramatika a krátké psaní. Úroveň A2.", "Reading, listening, grammar and a short piece of writing. Level A2."}, - {"en_y2_sub", "Cestování, zdraví, práce, média a příroda. Úroveň B1.", "Travel, health, work, the media and nature. Level B1."}, - {"en_y2_u1", "Na cestách", "On the road"}, - {"en_y2_u1_sub", "Stupňování a minulý čas průběhový. Doplňování a kvíz.", "Comparison and the past continuous. Gaps and a quiz."}, - {"en_y2_u2", "U lékaře", "At the clinic"}, - {"en_y2_u2_sub", "Should, must a have to. Čtení letáku a kvíz.", "Should, must and have to. A leaflet and a quiz."}, - {"en_y2_u3", "První brigáda", "A first job"}, - {"en_y2_u3_sub", "Předpřítomný čas, for a since. Poslech pohovoru a doplňování.", "The present perfect, for and since. A job interview and gaps."}, - {"en_y2_u4", "Recenze filmu", "A film review"}, - {"en_y2_u4_sub", "Vztažné věty who, which a that. Krátká recenze a kvíz.", "Relative clauses with who, which and that. A short review and a quiz."}, - {"en_y2_u5", "Počasí a výlet", "Weather and a trip"}, - {"en_y2_u5_sub", "Too a enough, will a going to v předpovědi. Čtení a doplňování.", "Too and enough, will and going to in a forecast. Reading and gaps."}, - {"en_y2_u6", "Festival", "A festival"}, - {"en_y2_u6_sub", "Předpřítomný čas proti minulému. Poslech a kvíz.", "Present perfect versus past simple. Listening and a quiz."}, - {"en_y2_u7", "Kdyby", "If I could"}, - {"en_y2_u7_sub", "První a druhá podmínková věta. Psaní a doplňování.", "First and second conditionals. Writing and gaps."}, - {"en_y2_u8", "Test 2. ročníku", "Year 2 test"}, - {"en_y2_u8_sub", "Čtení, poslech, gramatika B1 a krátké psaní.", "Reading, listening, B1 grammar and a short piece of writing."}, - {"en_y3_sub", "Společnost, prostředí, média a složitější gramatika. Úroveň B1 až B2.", "Society, the environment, the media and harder grammar. Level B1 to B2."}, - {"en_y3_u1", "Jak se to vyrábí", "How things are made"}, - {"en_y3_u1_sub", "Trpný rod v přítomnosti a minulosti. Doplňování a kvíz.", "The present and past passive. Gaps and a quiz."}, - {"en_y3_u2", "Škola, o které se mluví", "A school people talk about"}, - {"en_y3_u2_sub", "Nepřímá řeč oznamovací. Čtení a kvíz.", "Reported statements. Reading and a quiz."}, - {"en_y3_u3", "Poslední buk", "The last beech"}, - {"en_y3_u3_sub", "Podmínky a slovník prostředí. Poslech podcastu a doplňování.", "Conditionals and environment vocabulary. A podcast and gaps."}, - {"en_y3_u4", "Pro a proti", "For and against"}, - {"en_y3_u4_sub", "Stavba úvahy a spojovací výrazy. Esej a kvíz.", "Essay structure and linking words. An essay and a quiz."}, - {"en_y3_u5", "Kdo to musel být", "It must have been"}, - {"en_y3_u5_sub", "Modální slovesa dedukce. Čtení záhady a kvíz.", "Modals of deduction. A short mystery and a quiz."}, - {"en_y3_u6", "Zprávy dne", "The news desk"}, - {"en_y3_u6_sub", "Nepřímé otázky. Poslech rozhovoru a kvíz.", "Reported questions. An interview and a quiz."}, - {"en_y3_u7", "Frázová slovesa v příběhu", "Phrasal verbs in a story"}, - {"en_y3_u7_sub", "Běžná frázová slovesa. Doplňování a kvíz.", "Common phrasal verbs. Gaps and a quiz."}, - {"en_y3_u8", "Test 3. ročníku", "Year 3 test"}, - {"en_y3_u8_sub", "Čtení, poslech, gramatika B1+ a krátká úvaha.", "Reading, listening, B1+ grammar and a short argument."}, - {"en_y4_sub", "Maturitní dovednosti: mluvení, formální psaní, čtení, poslech a gramatika. Úroveň B2.", "Exam skills: speaking, formal writing, reading, listening and grammar. Level B2."}, - {"en_y4_u1", "Maturitní kartička", "The speaking card"}, - {"en_y4_u1_sub", "Strategie ústní zkoušky a kolokace osobních témat. Kvíz a doplňování.", "Speaking-exam strategy and personal-topic collocations. A quiz and gaps."}, - {"en_y4_u2", "Formální e-mail", "A formal email"}, - {"en_y4_u2_sub", "Žádost a stížnost. Psaní a kvíz rejstříku.", "A request and a complaint. Writing and a register quiz."}, - {"en_y4_u3", "Noční vlak", "The night train"}, - {"en_y4_u3_sub", "Delší čtení ve stylu didaktického testu. Čtyři otázky k článku.", "A longer reading in the style of the written paper. Four questions."}, - {"en_y4_u4", "Tábor ve Walesu", "A camp in Wales"}, - {"en_y4_u4_sub", "Delší poslech: pohovor. Pět otázek.", "A longer listening: an interview. Five questions."}, - {"en_y4_u5", "Názorová esej", "An opinion essay"}, - {"en_y4_u5_sub", "Struktura názoru. Esej a kvíz o odstavcích.", "Opinion-essay structure. An essay and a quiz about paragraphs."}, - {"en_y4_u6", "Slovní zásoba okruhů", "Topic vocabulary"}, - {"en_y4_u6_sub", "Kolokace k maturitním tématům. Doplňování a kvíz.", "Collocations for the exam topics. Gaps and a quiz."}, - {"en_y4_u7", "Gramatická ambulance", "Grammar clinic"}, - {"en_y4_u7_sub", "Smíšené jevy k didaktickému testu. Kvíz a doplňování.", "Mixed points for the language paper. A quiz and gaps."}, - {"en_y4_u8", "Cvičná maturita", "A practice paper"}, - {"en_y4_u8_sub", "Čtení, poslech, jazyková kompetence a krátká písemná práce.", "Reading, listening, language in use and a short piece of writing."}, diff --git a/src/english_lessons.inc b/src/english_lessons.inc deleted file mode 100644 index e6d502c..0000000 --- a/src/english_lessons.inc +++ /dev/null @@ -1,1907 +0,0 @@ -/* Generated by scripts/gen-english.py. Do not edit by hand. */ - -static const NetSlide en_y1_l1_slides[] = { - { - "1 / 2 • Be", "Kdo jsem", "Tip: věk se říká slovesem be. „She has 16 years“ je čechismus.", - { - "I am, you are, he/she/it is, we/you/they are.", - "Zápor a otázka: She isn't tall. Are you from Prague?", - "Věk, povolání i nálada: I am 16. My mum is a nurse. I am fine.", - "Přivlastňovací zájmena: my, your, his, her, its, our, their.", - NULL, - }, - }, - { - "2 / 2 • Have got", "Co mám", "Tip: have got je britská hovorová vazba pro vlastnictví, ne pro věk.", - { - "I've got a younger brother. She hasn't got a pet.", - "Have you got any cousins? — Yes, I have. / No, I haven't.", - "V americké angličtině stačí have: I have a brother.", - "Rodina: parents, siblings, only child, get on well, look like.", - NULL, - }, - }, -}; - -static const TypedQ en_y1_l1_gaps[] = { - {"My sister ___ sixteen.", "is", "Věk: be, ne have."}, - {"___ you got a bike?", "Have", "Otázka s have got."}, - {"This is ___ grandmother. She lives with us.", "our", "Přivlastňovací zájmeno."}, - {"They ___ not from Brno. They are from Olomouc.", "are", "They + are."}, - {"He ___ got a dog, but he has got two cats.", "hasn't|has not", "Zápor have got."}, -}; - -static const ChoiceQ en_y1_l1_quiz[] = { - {"Which sentence is correct?", {"She has 16 years.", "She is 16 years old.", "She is 16 years.", "She has 16 years old."}, 4, 1}, - {"I ___ two cousins and one aunt.", {"am", "have got", "has got", "is"}, 4, 1}, - {"Eva is my sister. ___ room is next to mine.", {"She", "Her", "His", "Hers"}, 4, 1}, - {"___ your parents at home?", {"Is", "Are", "Have", "Do"}, 4, 1}, -}; -static const char *en_y1_l1_quiz_hints[] = { - "Věk: be + years old.", - "Vlastnictví v 1. osobě: have got.", - "Před podstatným jménem je her, ne she.", - "Parents je množné číslo: Are.", -}; - -static const NetSlide en_y1_l2_slides[] = { - { - "1 / 2 • Present simple", "Co dělám pravidelně", "Tip: ve 3. osobě jednotného čísla přibývá -s/-es: she watches.", - { - "I get up at seven. He gets up at six.", - "Zápor: I don't like maths. She doesn't eat meat.", - "Otázka: Do you walk to school? Does she play the piano?", - "Příslovce četnosti stojí před slovesem: I usually walk. She is always late.", - NULL, - }, - }, - { - "2 / 2 • Škola", "Rozvrh a přestávky", "Tip: předmět ve škole je bez členu, když mluvíme obecně: I like biology.", - { - "lessons, break, canteen, homework, timetable, subject.", - "Čas: at eight, at half past twelve, in the morning, on Monday.", - "because vysvětluje důvod: I like biology because we do experiments.", - "never / sometimes / often / usually / always.", - NULL, - }, - }, -}; - -static const char *en_y1_l2_read = "My school day starts early. I get up at half past six, have breakfast and catch the tram. Lessons begin at eight. On Monday we have maths, English and biology. I like biology because we do experiments, but I don't like maths. We have lunch at half past twelve in the canteen. After school I do my homework or meet friends. I never go to bed after ten on a school night."; - -static const ChoiceQ en_y1_l2_readq[] = { - {"What time do lessons begin?", {"At half past six", "At eight", "At half past twelve", "At ten"}, 4, 1}, - {"Why does the writer like biology?", {"Because it is easy", "Because they do experiments", "Because the teacher is funny", "Because there is no homework"}, 4, 1}, - {"Where do they have lunch?", {"At home", "On the tram", "In the canteen", "In the park"}, 4, 2}, - {"On a school night the writer goes to bed…", {"after eleven", "at midnight", "never after ten", "before six"}, 4, 2}, -}; -static const char *en_y1_l2_readq_hints[] = { - "Lessons begin at eight.", - "because we do experiments.", - "in the canteen.", - "never go to bed after ten.", -}; - -static const TypedQ en_y1_l2_gaps[] = { - {"She ___ (watch) a series every evening.", "watches", "3. osoba: watches."}, - {"We ___ (not go) to school on Sunday.", "don't go|do not go", "Zápor v 1. osobě množného čísla."}, - {"___ he play football on Fridays?", "Does", "Otázka ve 3. osobě."}, - {"I usually ___ (get) up at seven.", "get", "Usually nemění tvar slovesa."}, -}; - -static const NetSlide en_y1_l3_slides[] = { - { - "1 / 2 • Continuous", "Co právě probíhá a co je domluvené", "Tip: I'm meeting Eva at ten je plán, ne jen „potkávám“.", - { - "Tvar: am/is/are + -ing. I'm waiting. She isn't coming.", - "Teď: Look, it is raining. Please be quiet, the baby is sleeping.", - "Blízký plán: We're having lunch on Saturday. I'm playing volleyball.", - "Stavová slovesa obvykle průběhový čas nemají: I know, I like, I want.", - NULL, - }, - }, - { - "2 / 2 • Poslech", "Jak poslouchat vzkaz", "Tip: nejdřív si přečtěte otázky, pak teprve pusťte nahrávku.", - { - "Chyťte jména, časy a místa. Ta se v otázkách opakují.", - "Nenechte se zastavit jedním slovem. Poslouchejte dál.", - "I'm meeting, we're going, I'm playing jsou v tomhle vzkazu klíčové.", - "Na konci bývá prosba: Call me back.", - NULL, - }, - }, -}; - -static const char *en_y1_l3_listen = "Hi Tom, it's Anna. Are you free on Saturday? I'm meeting Eva at the station at ten. We're going to the market first, and then we're having lunch in that new café by the river. In the afternoon I'm playing volleyball with my class in the park. Do you want to come to the café? Call me back tonight."; - -static const ChoiceQ en_y1_l3_listenq[] = { - {"Who is Anna meeting?", {"Tom", "Eva", "Her class", "Her mum"}, 4, 1}, - {"Where are they meeting?", {"At school", "At the station", "In the park", "By the river only"}, 4, 1}, - {"What is Anna doing in the afternoon?", {"Going to the market", "Having lunch", "Playing volleyball", "Sleeping"}, 4, 2}, - {"What should Tom do?", {"Buy tickets", "Call her back", "Come to school", "Bring a map"}, 4, 1}, -}; -static const char *en_y1_l3_listenq_hints[] = { - "I'm meeting Eva.", - "at the station at ten.", - "I'm playing volleyball.", - "Call me back tonight.", -}; - -static const TypedQ en_y1_l3_gaps[] = { - {"Listen, the phone ___.", "is ringing", "Děje se to teď."}, - {"We ___ lunch with Eva on Saturday.", "are having|'re having", "Domluvený plán."}, - {"I ___ not coming to the match.", "am|'m", "Zápor: am not."}, - {"She ___ volleyball this afternoon.", "is playing|'s playing", "Domluvená aktivita."}, -}; - -static const NetSlide en_y1_l4_slides[] = { - { - "1 / 2 • There is", "Co v pokoji je", "Tip: there is pro jedno, there are pro více. There je formální podmět.", - { - "There is a desk under the window. There are two chairs.", - "Zápor: There isn't a TV. There aren't any posters.", - "Otázka: Is there a lamp? Are there any books?", - "Předložky: in, on, under, next to, between, behind, in front of.", - NULL, - }, - }, - { - "2 / 2 • Psaní", "Popis místa", "Tip: jděte od velkého k malému, od dveří k oknu.", - { - "Začněte velikostí a světlem: small but bright.", - "Každá věta ať má věc a místo: The bag is under the chair.", - "Střídejte there is a there are, ať text není seznam.", - "Na konci jedna osobní věta: I like it because it is quiet.", - NULL, - }, - }, -}; - -static const char *en_y1_l4_write[] = { - "Describe your room in at least 30 words. Say what is in it and where things are. Use on and a piece of furniture such as a bed, and mention a window.", - "My room is small but bright. There is a bed next to the window and a wooden desk under a shelf. My books are on the desk and my school bag is under the chair. There are two posters on the wall. I like the room because it is quiet in the evening.", - "bed|window|on", - "30", -}; - -static const ChoiceQ en_y1_l4_quiz[] = { - {"The lamp is ___ the desk.", {"under", "on", "between", "at"}, 4, 1}, - {"There ___ a big window.", {"are", "is", "be", "have"}, 4, 1}, - {"There ___ two posters on the wall.", {"is", "are", "has", "been"}, 4, 1}, - {"The cat is sleeping ___ the bed.", {"under", "next", "between to", "at to"}, 4, 0}, -}; -static const char *en_y1_l4_quiz_hints[] = { - "Lampa stojí na desce: on.", - "Jedno okno: there is.", - "Dva plakáty: there are.", - "Pod postelí: under the bed.", -}; - -static const NetSlide en_y1_l5_slides[] = { - { - "1 / 2 • Množství", "Počitatelné a nepočitatelné", "Tip: some v kladné větě, any v otázce a záporu. Nabídka je výjimka: Would you like some tea?", - { - "Počitatelné: an apple, some apples. Nepočitatelné: some bread, some milk.", - "How many apples? How much milk?", - "a little milk, a few rolls, a lot of cheese.", - "V obchodě: How much is it? It's four euros a kilo.", - NULL, - }, - }, - { - "2 / 2 • Dialog", "Zdvořilá žádost", "Tip: Can I have… a I'd like… zní v obchodě přirozeně.", - { - "Have you got any bread? — Sorry, we haven't got any today.", - "We've got some rolls instead.", - "How many would you like? — Six, please.", - "Anything else? — No, that's all. Thank you.", - NULL, - }, - }, -}; - -static const char *en_y1_l5_read = "On Saturday morning the market by the river is busy. A woman asks, \"How much is this cheese?\" The seller says, \"It's four euros a kilo.\" Then she asks, \"Have you got any bread?\" He answers, \"Sorry, we haven't got any bread today, but we've got some fresh rolls.\" \"How many rolls do you want?\" \"Six, please, and a little milk.\" She also buys a few apples. \"Anything else?\" \"No, that's all.\""; - -static const ChoiceQ en_y1_l5_readq[] = { - {"How much is the cheese?", {"Four euros a piece", "Four euros a kilo", "Six euros", "A little"}, 4, 1}, - {"What hasn't the seller got?", {"Rolls", "Milk", "Bread", "Apples"}, 4, 2}, - {"How many rolls does the woman want?", {"Four", "A few", "Six", "A kilo"}, 4, 2}, - {"Which phrase is an offer of more shopping?", {"That's all.", "Anything else?", "How much is it?", "A little milk."}, 4, 1}, -}; -static const char *en_y1_l5_readq_hints[] = { - "four euros a kilo.", - "haven't got any bread today.", - "Six, please.", - "Anything else? nabízí další nákup.", -}; - -static const TypedQ en_y1_l5_gaps[] = { - {"We haven't got ___ bread today.", "any", "Zápor: any."}, - {"There are ___ rolls in the bag.", "some", "Kladná věta: some."}, - {"How ___ apples do you want?", "many", "Apples se dají počítat."}, - {"How ___ milk is in the bottle?", "much", "Milk je nepočitatelné."}, -}; - -static const NetSlide en_y1_l6_slides[] = { - { - "1 / 2 • Past simple", "Co se stalo a je dokončené", "Tip: zápor a otázka používají did, sloveso zůstává v základním tvaru.", - { - "Pravidelná: play → played, visit → visited, try → tried, stop → stopped.", - "Nepravidelná: go → went, take → took, swim → swam, buy → bought.", - "I didn't stay in a hotel. Did you visit the island?", - "Signály: yesterday, last July, ago, in 2019, when I was ten.", - NULL, - }, - }, - { - "2 / 2 • Vyprávění", "Jedna událost za druhou", "Tip: then, after that a one day drží příběh pohromadě.", - { - "Začněte kdy a kam: Last July we went to Croatia.", - "Pak doprava, počasí a jedna konkrétní příhoda.", - "Nepravidelná slovesa se neučí po jednom u testu, ale ve větě.", - "Na konci dojem: It was the best week of the year.", - NULL, - }, - }, -}; - -static const char *en_y1_l6_listen = "Last July we went to Croatia. We travelled by train and then by bus because the flight was too expensive. The weather was hot every day. I swam in the morning and my brother tried surfing. He fell off the board a lot, but he loved it. One day we visited a small island. We didn't stay in a hotel. We stayed with our uncle near the beach. I took hundreds of photos."; - -static const ChoiceQ en_y1_l6_listenq[] = { - {"Where did they go?", {"Italy", "Croatia", "Greece", "Spain"}, 4, 1}, - {"How did they travel?", {"By plane", "By train and bus", "By car", "By ferry only"}, 4, 1}, - {"What did the brother try?", {"Swimming", "Surfing", "Cooking", "Driving"}, 4, 1}, - {"Where did they stay?", {"In a hotel", "On the island", "With their uncle", "On the train"}, 4, 2}, -}; -static const char *en_y1_l6_listenq_hints[] = { - "went to Croatia.", - "by train and then by bus.", - "tried surfing.", - "stayed with our uncle.", -}; - -static const ChoiceQ en_y1_l6_quiz[] = { - {"go → ___", {"goed", "went", "gone", "going"}, 4, 1}, - {"I ___ a lot of photos.", {"taked", "took", "taken", "token"}, 4, 1}, - {"She ___ in the sea every morning.", {"swimmed", "swam", "swum", "swims"}, 4, 1}, - {"We ___ stay in a hotel.", {"don't", "didn't", "wasn't", "haven't"}, 4, 1}, -}; -static const char *en_y1_l6_quiz_hints[] = { - "go, went, gone.", - "take, took, taken.", - "Minulý tvar swim je swam.", - "Zápor minulého času: didn't + sloveso.", -}; - -static const NetSlide en_y1_l7_slides[] = { - { - "1 / 2 • Budoucnost", "Plán, nebo rozhodnutí teď", "Tip: going to má důkaz nebo plán. Will je rozhodnutí v tu chvíli nebo odhad.", - { - "We've got tickets. We're going to leave at six. To je plán.", - "Look at those clouds. It's going to rain. To je důkaz.", - "The phone is ringing. I'll answer it. Rozhodnutí teď.", - "I think I'll stay at home. Will jako názor, ne jistý plán.", - NULL, - }, - }, - { - "2 / 2 • Zpráva", "Neformální styl", "Tip: Hi, kontraktované tvary a na konci otázka kamarádovi.", - { - "Začněte Hi a jménem, ne Dear Sir.", - "Napište kdy, co a proč. Jedna věta s because stačí.", - "I'm going to… je v takové zprávě přirozené.", - "Konec: Want to come? Write back.", - NULL, - }, - }, -}; - -static const TypedQ en_y1_l7_gaps[] = { - {"Look at those clouds. It ___ rain.", "is going to|'s going to", "Je vidět důkaz: going to."}, - {"I think I ___ stay at home tonight.", "will|'ll", "Názor v tu chvíli: will."}, - {"The tickets are in my bag. We ___ leave at six.", "are going to|'re going to", "Už je to domluvené."}, - {"Don't worry. I ___ help you with the bags.", "will|'ll", "Rozhodnutí teď: will."}, -}; - -static const char *en_y1_l7_write[] = { - "Write a short message to a friend about next weekend. Use at least 25 words. Say what you are going to do, mention the weekend, and give a reason with because.", - "Hi Lena, next weekend I am going to visit my cousins in Pilsen. We are going to the cinema on Saturday because a new film is on. On Sunday we are going to cook lunch together. Do you want to come with me? Write back soon.", - "going|weekend|because", - "25", -}; - -static const NetSlide en_y1_l8_slides[] = { - { - "1 / 2 • Co test bere", "A2 v jedné sadě", "Tip: nejdřív otázky, pak text nebo nahrávku. U psaní počítejte slova.", - { - "Čtení: najděte v textu čas, místo a důvod, nehádejte z jednoho slova.", - "Poslech: jména a čísla si poznamenejte hned.", - "Gramatika: be, přítomné časy, some/any, minulý čas, will a going to.", - "Psaní: krátký souvislý text, ne jen odrážky.", - NULL, - }, - }, - { - "2 / 2 • Jak opravovat", "Nejčastější čechismy", "Tip: po kontrole si přečtěte nápovědy, i když je věta správně.", - { - "I am 16, ne I have 16 years.", - "She likes, ne she like.", - "Did you went je špatně. Did you go.", - "There is a book, ne It is a book on the table, když věc uvádíte.", - NULL, - }, - }, -}; - -static const char *en_y1_l8_read = "Klara lives in a flat with her parents and a small dog. On weekdays she walks to school because it is only ten minutes away. She loves art. Last Friday her class visited a gallery and she bought a poster. This Saturday she is meeting her cousin at the station. They are going to a concert in the evening."; - -static const ChoiceQ en_y1_l8_readq[] = { - {"How does Klara get to school?", {"By tram", "She walks", "Her dad drives", "By train"}, 4, 1}, - {"What did she buy at the gallery?", {"A dog", "A ticket", "A poster", "A flat"}, 4, 2}, - {"Who is she meeting on Saturday?", {"Her parents", "Her art teacher", "Her cousin", "The singer"}, 4, 2}, -}; -static const char *en_y1_l8_readq_hints[] = { - "she walks to school.", - "she bought a poster.", - "meeting her cousin.", -}; - -static const char *en_y1_l8_listen = "Hi, it's Marek. I missed you after school. I'm at the sports centre. The match starts at four, not at three, so don't hurry. Can you bring my blue jacket? It's on the chair in the kitchen. See you there."; - -static const ChoiceQ en_y1_l8_listenq[] = { - {"Where is Marek?", {"At school", "At the sports centre", "In the kitchen", "On the tram"}, 4, 1}, - {"What time does the match start?", {"At three", "At four", "At five", "At ten"}, 4, 1}, - {"What should his friend bring?", {"A ticket", "A blue jacket", "Lunch", "A poster"}, 4, 1}, -}; -static const char *en_y1_l8_listenq_hints[] = { - "at the sports centre.", - "starts at four, not at three.", - "bring my blue jacket.", -}; - -static const char *en_y1_l8_write[] = { - "Write at least 30 words about your family. Use is or are, and the words family and because.", - "My family is not very big. I live with my parents and my younger sister. She is twelve and she is funny. We get on well because we both like films. My dad is a driver and my mum is a nurse. I am happy at home.", - "family|because", - "30", -}; - -static const ChoiceQ en_y1_l8_quiz[] = { - {"She ___ coffee.", {"don't like", "doesn't like", "not like", "isn't like"}, 4, 1}, - {"There ___ any milk.", {"isn't", "aren't", "hasn't", "don't"}, 4, 0}, - {"Yesterday we ___ to the lake.", {"go", "went", "gone", "going"}, 4, 1}, - {"I've got the tickets. We ___ leave at noon.", {"will", "are going to", "did", "are"}, 4, 1}, -}; -static const char *en_y1_l8_quiz_hints[] = { - "3. osoba: doesn't like.", - "Milk je jednotné: there isn't.", - "Minulý tvar go je went.", - "Plán s důkazem: going to.", -}; - -static const NetSlide en_y2_l1_slides[] = { - { - "1 / 2 • Stupňování", "Porovnat dvě věci i celou skupinu", "Tip: kratší přídavná jména berou -er/-est, delší more/most.", - { - "cheap → cheaper → the cheapest. Expensive → more expensive → the most expensive.", - "Nepravidelné: good → better → the best, bad → worse → the worst, far → further → the furthest.", - "as … as: The bus is as fast as the train today.", - "than stojí po komparativu: This hostel is cheaper than the hotel.", - NULL, - }, - }, - { - "2 / 2 • Past continuous", "Děje, který probíhal, když se stalo něco jiného", "Tip: průběhový čas je pozadí, prostý je krátká událost.", - { - "I was reading when the train stopped.", - "While we were waiting, it started to rain.", - "Zápor: We weren't sleeping. Otázka: Were you driving?", - "Nepleťte si ho s minulým prostým: I walked home popisuje celou cestu.", - NULL, - }, - }, -}; - -static const TypedQ en_y2_l1_gaps[] = { - {"This ticket is ___ (cheap) than the night train.", "cheaper", "Krátké přídavné jméno: -er."}, - {"It was the ___ (bad) hotel in the town.", "worst", "bad, worse, the worst."}, - {"Prague is not as ___ as London.", "big", "as + základní tvar + as."}, - {"I ___ (read) when the bus suddenly stopped.", "was reading", "Pozadí: past continuous."}, - {"While we ___ (wait), a street musician started to play.", "were waiting", "While + průběhový děj."}, -}; - -static const ChoiceQ en_y2_l1_quiz[] = { - {"far → ___ → the furthest", {"farer", "further", "more far", "farthest only"}, 4, 1}, - {"Which sentence is correct?", {"This café is more cheap than that one.", "This café is cheaper than that one.", "This café is the cheaper than that one.", "This café is cheap than that one."}, 4, 1}, - {"She ___ a map when she missed the stop.", {"looked", "was looking", "looks", "is looking"}, 4, 1}, - {"good → better → ___", {"the goodest", "the better", "the best", "the most good"}, 4, 2}, -}; -static const char *en_y2_l1_quiz_hints[] = { - "far, further, the furthest. Farthest je taky možné, ale further je v učebnici první.", - "cheap → cheaper than.", - "Dělo se to v okamžiku, kdy zmeškala zastávku.", - "the best.", -}; - -static const NetSlide en_y2_l2_slides[] = { - { - "1 / 2 • Modální slovesa", "Rada, povinnost, zákaz", "Tip: must je silný pocit mluvčího, have to je pravidlo zvenku.", - { - "You should rest. You shouldn't go to school tomorrow. To je rada.", - "I must call the doctor. Mluvčí cítí, že to je nutné.", - "You have to show your insurance card. To chce ordinace.", - "Mustn't je zákaz. Don't have to znamená, že to není nutné.", - NULL, - }, - }, - { - "2 / 2 • Tělo a příznaky", "Jak to říct u přepážky", "Tip: I've got a sore throat zní přirozeněji než I have pain in throat.", - { - "a headache, a sore throat, a cough, a temperature, a rash.", - "It hurts when I swallow. I feel dizzy.", - "How long have you had it? — Since Monday. / For three days.", - "Take these tablets twice a day. Drink plenty of water.", - NULL, - }, - }, -}; - -static const char *en_y2_l2_read = "The school clinic is open from seven to three. If you feel ill, you should tell your teacher first. You have to bring your insurance card. You must not come to school with a high temperature. Students with a cough should wear a mask in the waiting room. You don't have to make an appointment for a small cut, but you should come before noon. The nurse can give you a painkiller. She can't give you antibiotics."; - -static const ChoiceQ en_y2_l2_readq[] = { - {"What do you have to bring?", {"A mask", "An insurance card", "Antibiotics", "An appointment"}, 4, 1}, - {"What is forbidden?", {"Coming with a high temperature", "Telling the teacher", "Wearing a mask", "Coming before noon"}, 4, 0}, - {"You don't have to make an appointment if…", {"you need antibiotics", "you have a small cut", "you have a temperature", "you arrive at four"}, 4, 1}, - {"What can't the nurse give you?", {"Water", "A painkiller", "Antibiotics", "A mask"}, 4, 2}, -}; -static const char *en_y2_l2_readq_hints[] = { - "have to bring your insurance card.", - "must not come with a high temperature.", - "for a small cut.", - "She can't give you antibiotics.", -}; - -static const ChoiceQ en_y2_l2_quiz[] = { - {"You ___ shout in the waiting room. It's a rule.", {"don't have to", "mustn't", "shouldn't to", "haven't"}, 4, 1}, - {"You ___ wear a tie. Nobody minds.", {"mustn't", "don't have to", "must", "should to"}, 4, 1}, - {"I've got a headache. You ___ drink some water and rest.", {"should", "must to", "have", "are"}, 4, 0}, - {"Visitors ___ show a card. The clinic asks for it.", {"have to", "should to", "don't must", "are have"}, 4, 0}, -}; -static const char *en_y2_l2_quiz_hints[] = { - "Zákaz: mustn't.", - "Není to nutné: don't have to.", - "Rada: should.", - "Pravidlo zvenku: have to.", -}; - -static const NetSlide en_y2_l3_slides[] = { - { - "1 / 2 • Present perfect", "Zkušenost a děj až do teď", "Tip: have/has + příčestí. Otázka na zkušenost začíná Have you ever…?", - { - "I have worked in a café. She has never had a paid job.", - "Ever v otázce, never v záporném významu: Have you ever used a till?", - "For three months = jak dlouho. Since May = od kdy.", - "Just, already, yet: I've just finished. I haven't finished yet.", - NULL, - }, - }, - { - "2 / 2 • Pohovor", "Krátké odpovědi", "Tip: odpovězte a přidejte jednu konkrétní větu, ať to není jen yes.", - { - "I'm reliable and I get on well with people.", - "I have looked after my neighbours' children.", - "I can work on Saturdays, but I can't work on Sunday mornings.", - "Could you tell me what the shift is?", - NULL, - }, - }, -}; - -static const char *en_y2_l3_listen = "Manager: Have you ever worked in a shop? Tereza: Not in a shop, but I have helped in my uncle's bakery since May. Manager: What do you do there? Tereza: I have served customers and I have learned to use the till. I haven't baked bread yet. Manager: Can you start next Saturday? Tereza: Yes. I have already asked my uncle, and he says it's fine. I can't work on Sunday mornings because I have a match."; - -static const ChoiceQ en_y2_l3_listenq[] = { - {"Where has Tereza helped?", {"In a supermarket", "In her uncle's bakery", "In a hotel", "At school"}, 4, 1}, - {"Since when?", {"Since March", "Since May", "Since Saturday", "For a year"}, 4, 1}, - {"What hasn't she done yet?", {"Served customers", "Used the till", "Baked bread", "Asked her uncle"}, 4, 2}, - {"Why can't she work on Sunday mornings?", {"The bakery is closed", "She has a match", "She is ill", "She has no till"}, 4, 1}, -}; -static const char *en_y2_l3_listenq_hints[] = { - "in my uncle's bakery.", - "since May.", - "I haven't baked bread yet.", - "because I have a match.", -}; - -static const TypedQ en_y2_l3_gaps[] = { - {"She ___ (live) here since 2019.", "has lived|'s lived", "Since + předpřítomný čas."}, - {"I have known him ___ three years.", "for", "For + délka."}, - {"Have you ___ (be) to London?", "been", "Been to = mít zkušenost."}, - {"We haven't finished ___.", "yet", "Yet v záporu na konci."}, - {"He has ___ eaten, so he isn't hungry.", "already|just", "Already nebo just."}, -}; - -static const NetSlide en_y2_l4_slides[] = { - { - "1 / 2 • Vztažné věty", "Která osoba, která věc", "Tip: who pro lidi, which pro věci. That jde často pro obojí v definující větě.", - { - "The actor who plays the captain is brilliant.", - "A lighthouse which stands on a black rock.", - "V definující větě se čárka nepíše: The boy who lives next door.", - "Nedefinující věta čárku má a that se v ní nepoužívá: Prague, which I love, …", - NULL, - }, - }, - { - "2 / 2 • Recenze", "Názor, ne jen děj", "Tip: neprozrazujte konec. Napište, pro koho film je.", - { - "Jedna věta o ději, jedna o postavě, jedna o tom, co se povedlo.", - "I would recommend it to anyone who likes quiet films.", - "The ending, which I will not describe, stays with you.", - "Hodnocení ať je konkrétní: the music is too loud, the script is sharp.", - NULL, - }, - }, -}; - -static const char *en_y2_l4_write[] = { - "Write a short review of a film or a book in at least 40 words. Use who once and which once, and say who you would recommend it to.", - "The Lighthouse Keeper is a quiet film which follows a woman on a small island. The actor who plays her hardly speaks, but her face tells the story. The sea, which is almost a character, is beautiful and dangerous. I would recommend it to anyone who likes slow films. The ending is sad but honest.", - "who|which|recommend", - "40", -}; - -static const ChoiceQ en_y2_l4_quiz[] = { - {"The nurse ___ helped me was very calm.", {"which", "who", "where", "whose it"}, 4, 1}, - {"The app ___ crashed is useless.", {"who", "which", "where", "whom"}, 4, 1}, - {"Prague, ___ is my home city, is full of tourists in July.", {"that", "which", "who", "what"}, 4, 1}, - {"That's the boy ___ dog ran into the road.", {"who", "which", "whose", "that his"}, 4, 2}, -}; -static const char *en_y2_l4_quiz_hints[] = { - "Člověk: who.", - "Věc: which.", - "S čárkou that nepatří. Which.", - "Čí: whose.", -}; - -static const NetSlide en_y2_l5_slides[] = { - { - "1 / 2 • Too / enough", "Příliš a dost", "Tip: too stojí před přídavným jménem, enough za ním.", - { - "It's too cold to swim. The water isn't warm enough.", - "Too many people, too much rain.", - "Enough + podstatné jméno: enough water. Nebo za přídavným jménem: old enough.", - "Not enough time je častější než too little time.", - NULL, - }, - }, - { - "2 / 2 • Předpověď", "Co říct, když se díváte z okna", "Tip: mraky, které vidíte, vedou k going to. Odhad bez důkazu k will.", - { - "Those clouds are black. It's going to storm.", - "I think it will be sunny on Sunday. To je jen odhad.", - "If it rains, we'll stay in the cabin.", - "Slovník: foggy, chilly, pouring, a heatwave, a breeze.", - NULL, - }, - }, -}; - -static const char *en_y2_l5_read = "We wanted to cycle to the lake, but the morning was too foggy to start. By ten the sun was out and the path was dry enough. There were too many cyclists near the dam, so we took a quieter road. We didn't have enough water, which was a mistake. At the lake a guard said, \"Look at that cloud. It's going to pour. I think the storm will last an hour.\" We were not fast enough. We got soaked."; - -static const ChoiceQ en_y2_l5_readq[] = { - {"Why didn't they start early?", {"The bikes were broken", "It was too foggy", "The lake was closed", "They had no map"}, 4, 1}, - {"Why did they change the road?", {"There were too many cyclists", "They were lost", "It was pouring", "The guard sent them back"}, 4, 0}, - {"What mistake did they make?", {"They forgot the bikes", "They didn't have enough water", "They started at night", "They swam"}, 4, 1}, - {"What did the guard predict from the cloud?", {"Fog", "A heatwave", "Rain", "Snow"}, 4, 2}, -}; -static const char *en_y2_l5_readq_hints[] = { - "too foggy to start.", - "too many cyclists near the dam.", - "didn't have enough water.", - "It's going to pour.", -}; - -static const TypedQ en_y2_l5_gaps[] = { - {"The rucksack is ___ heavy to carry.", "too", "Too + přídavné jméno."}, - {"She isn't tall ___ to reach the shelf.", "enough", "Enough za přídavným jménem."}, - {"There is too ___ sugar in this tea.", "much", "Nepočitatelné: too much."}, - {"Look at the sky. It ___ snow.", "is going to|'s going to", "Viditelný důkaz."}, -}; - -static const NetSlide en_y2_l6_slides[] = { - { - "1 / 2 • Dva časy", "Kdy je děj uzavřený", "Tip: jakmile zazní yesterday, last year nebo in 2019, patří minulý čas.", - { - "I have been to the festival three times. Neříkám kdy.", - "I went in 2023. Tehdy pršelo. To už je uzavřené.", - "Have you ever slept in a tent? — Yes. I slept in one last June.", - "Been to znamená, že už je člověk zpátky. Gone to znamená, že je pořád pryč.", - NULL, - }, - }, - { - "2 / 2 • Reportáž", "Co se děje na místě", "Tip: reportér míchá „už se stalo“ a „bylo to včera večer“.", - { - "The gates have just opened.", - "Last night the main band played for two hours.", - "Have you seen the lanterns yet?", - "A local baker has made a cake in the shape of a violin.", - NULL, - }, - }, -}; - -static const char *en_y2_l6_listen = "This is Nora at the river festival. The gates have just opened and hundreds of people have already come in. I have never seen so many lanterns. Last night the main band played for two hours, but tonight's singer hasn't arrived yet. A local baker has made a cake in the shape of a violin. I tried a piece yesterday. It was delicious. Have you ever been here? I came for the first time in 2022, and I have come back every summer since then."; - -static const ChoiceQ en_y2_l6_listenq[] = { - {"What has just happened?", {"The band has left", "The gates have opened", "It has started to snow", "The baker has closed"}, 4, 1}, - {"When did the main band play?", {"Just now", "Last night", "In 2022", "Every summer"}, 4, 1}, - {"What hasn't happened yet?", {"People have come in", "Tonight's singer has arrived", "Nora tried the cake", "The gates opened"}, 4, 1}, - {"When did Nora come for the first time?", {"Yesterday", "Last night", "In 2022", "This morning"}, 4, 2}, -}; -static const char *en_y2_l6_listenq_hints[] = { - "The gates have just opened.", - "Last night the main band played.", - "hasn't arrived yet.", - "for the first time in 2022.", -}; - -static const ChoiceQ en_y2_l6_quiz[] = { - {"I ___ this play in 2019.", {"have seen", "saw", "seen", "have saw"}, 4, 1}, - {"She has ___ to Paris. She is still there.", {"been", "gone", "went", "going"}, 4, 1}, - {"___ you ever slept in a tent?", {"Did", "Have", "Do", "Were"}, 4, 1}, - {"We ___ the lanterns yesterday.", {"have seen", "saw", "seen", "have watch"}, 4, 1}, -}; -static const char *en_y2_l6_quiz_hints[] = { - "Rok uzavírá děj: saw.", - "Pořád je pryč: gone.", - "Ever + present perfect: Have you ever…?", - "Yesterday → past simple.", -}; - -static const NetSlide en_y2_l7_slides[] = { - { - "1 / 2 • Podmínky", "Reálná a hypotetická", "Tip: v if větě není will. If it rains, we will stay in.", - { - "1. kondicionál: If I finish early, I will call you. Je to možné.", - "2. kondicionál: If I had a car, I would drive. Teď auto nemám.", - "V formální druhé podmínce je were: If I were you, I would apologise.", - "Unless = if not: We'll miss the bus unless we leave now.", - NULL, - }, - }, - { - "2 / 2 • Vlastní věta", "Jedna reálná, jedna vysněná", "Tip: would se v if větě druhé podmínky neopakuje na obou stranách špatně. If I would have je chyba.", - { - "Napište situaci, která se může stát tento týden.", - "Pak situaci, která teď pravda není.", - "Would like není druhá podmínka. To je jen přání: I'd like a tea.", - "Krátký text ať má oba typy, ať je rozdíl vidět.", - NULL, - }, - }, -}; - -static const TypedQ en_y2_l7_gaps[] = { - {"If it ___ (rain), we will stay in the tent.", "rains", "1. podmínka: přítomný čas v if."}, - {"If I ___ (be) you, I would tell the truth.", "were|was", "Were je přesnější, was se taky slyší."}, - {"She would travel more if she ___ (have) time.", "had", "2. podmínka: minulý tvar."}, - {"We'll be late ___ we hurry.", "unless", "Unless = if not."}, -}; - -static const char *en_y2_l7_write[] = { - "Write at least 35 words. Include one real plan with if and will, and one unreal dream with would. Use the word if twice.", - "If I finish my project tonight, I will go climbing with Eva on Saturday. We will take the early bus if the weather is fine. If I had more free time, I would learn the guitar. I would also travel by night train if tickets were cheaper. If is a small word with two very different lives.", - "if|will|would", - "35", -}; - -static const NetSlide en_y2_l8_slides[] = { - { - "1 / 2 • B1", "Co už má držet pohromadě", "Tip: u předpřítomného času hledejte ever, yet, since. U minulého yesterday a rok.", - { - "Stupňování, past continuous, modální slovesa rady a povinnosti.", - "Present perfect proti past simple.", - "Who a which, too a enough, první a druhá podmínka.", - "Psaní: krátký souvislý názor, ne odrážkový seznam.", - NULL, - }, - }, - { - "2 / 2 • Strategie", "Jedna věta navíc", "Tip: v psaní ať je důvod. Because nebo so text zvedne.", - { - "U čtení škrtněte odpověď, která v textu vůbec není.", - "U poslechu si čísla zapište číslicí.", - "Mustn't není don't have to.", - "If I would have time je chyba. If I had time, I would…", - NULL, - }, - }, -}; - -static const char *en_y2_l8_read = "The night bus to Brno is cheaper than the train, but it is also slower. Last Friday I was sleeping when the driver stopped at a dark petrol station. A woman who had missed her connection asked if she could sit next to me. She has travelled this route since March because her new job starts at six. If the bus is late, she has to run. She says she would move closer if flats were cheaper."; - -static const ChoiceQ en_y2_l8_readq[] = { - {"The bus is ___ than the train.", {"faster and cheaper", "cheaper and slower", "the best", "as fast"}, 4, 1}, - {"What was the writer doing when the bus stopped?", {"Reading", "Sleeping", "Running", "Driving"}, 4, 1}, - {"Why has the woman travelled this route since March?", {"She likes petrol stations", "Her job starts early", "Flats are cheap", "She missed a concert"}, 4, 1}, -}; -static const char *en_y2_l8_readq_hints[] = { - "cheaper, but slower.", - "I was sleeping when the driver stopped.", - "her new job starts at six.", -}; - -static const char *en_y2_l8_listen = "Doctor: How long have you had this cough? Adam: Since Sunday. I have also had a sore throat for two days. Doctor: You should rest and drink water. You don't have to stay in bed all day, but you mustn't play football this week. If you still feel ill on Friday, come back."; - -static const ChoiceQ en_y2_l8_listenq[] = { - {"Since when has Adam had the cough?", {"Since Friday", "Since Sunday", "For a month", "Since March"}, 4, 1}, - {"What mustn't he do?", {"Drink water", "Rest", "Play football", "Come back"}, 4, 2}, - {"When should he come back?", {"If he is still ill on Friday", "Every day", "Never", "On Sunday morning"}, 4, 0}, -}; -static const char *en_y2_l8_listenq_hints[] = { - "Since Sunday.", - "mustn't play football.", - "If you still feel ill on Friday.", -}; - -static const char *en_y2_l8_write[] = { - "Write at least 35 words about a trip or a job you would like. Use would and because.", - "I would like to work in a small bookshop by the station because I love quiet mornings. I would talk to customers and I would also read in the breaks. If I had the job, I would cycle there. I have never worked in a shop, but I have helped at school events.", - "would|because", - "35", -}; - -static const ChoiceQ en_y2_l8_quiz[] = { - {"This hostel is ___ than the hotel.", {"cheaper", "more cheap", "the cheapest", "cheap"}, 4, 0}, - {"I have lived here ___ 2020.", {"for", "since", "ago", "during"}, 4, 1}, - {"You ___ wear a helmet. It's the law.", {"must to", "have to", "don't have", "should to"}, 4, 1}, - {"If I ___ richer, I would take the train.", {"am", "will be", "were", "would be"}, 4, 2}, -}; -static const char *en_y2_l8_quiz_hints[] = { - "cheap → cheaper.", - "Since + bod v čase.", - "Pravidlo: have to.", - "2. podmínka: were.", -}; - -static const NetSlide en_y3_l1_slides[] = { - { - "1 / 2 • Passive", "Když je důležitější děj než původce", "Tip: be + příčestí. Čas nese sloveso be, ne příčestí.", - { - "English is spoken here. The window was broken last night.", - "Původce s by, jen když na něm záleží: The book was written by a nurse.", - "Modální trpný rod: The form must be signed. It can be recycled.", - "Nelze trpně vyjádřit každé sloveso. Happen trpný rod nemá.", - NULL, - }, - }, - { - "2 / 2 • Popis procesu", "Od suroviny k věci", "Tip: first, then, after that, finally. Původce často chybí, protože je obecný.", - { - "The beans are picked by hand. They are dried in the sun.", - "The jars were labelled yesterday.", - "Waste paper is collected every Thursday.", - "A new bridge is being built. To už je průběhový trpný rod, zatím stačí ho poznat.", - NULL, - }, - }, -}; - -static const TypedQ en_y3_l1_gaps[] = { - {"This bread ___ (bake) every morning.", "is baked", "Přítomný trpný rod."}, - {"The letters ___ (send) yesterday.", "were sent", "Minulý trpný rod, množné číslo."}, - {"The poem ___ (write) by a student.", "was written", "Write → written."}, - {"These bottles can ___ (recycle).", "be recycled", "Modální sloveso + be + příčestí."}, - {"The window ___ (not break) by the wind. Someone hit it.", "wasn't broken|was not broken", "Zápor minulého trpného rodu."}, -}; - -static const ChoiceQ en_y3_l1_quiz[] = { - {"Which sentence is passive?", {"Someone stole my bike.", "My bike was stolen.", "My bike stole.", "Someone was steal my bike."}, 4, 1}, - {"The news ___ at ten.", {"is reading", "are read", "is read", "read"}, 4, 2}, - {"You ___ wear a badge. The factory requires it, in the passive of must.", {"must be worn a badge", "A badge must be worn", "A badge must worn", "A badge is must wear"}, 4, 1}, - {"They built the school in 1998. → The school ___ in 1998.", {"built", "was built", "was build", "has built"}, 4, 1}, -}; -static const char *en_y3_l1_quiz_hints[] = { - "was + stolen.", - "News je jednotné: is read.", - "A badge must be worn.", - "was built.", -}; - -static const NetSlide en_y3_l2_slides[] = { - { - "1 / 2 • Reported speech", "Posun času", "Tip: said that, told me that. Tell potřebuje osobu, say ne.", - { - "„I am tired.“ → She said she was tired.", - "„I will help.“ → He said he would help.", - "„I have finished.“ → She told me she had finished.", - "„I can't come.“ → He said he couldn't come.", - NULL, - }, - }, - { - "2 / 2 • Kdy čas neposouvat", "Pořád to platí", "Tip: obecné pravdy a situace, které trvají, často zůstávají v přítomném čase.", - { - "The teacher said that water boils at 100 degrees.", - "She said she lives in Kolín, a pořád tam bydlí.", - "Zájmena se mění podle smyslu: „my book“ → he said his book.", - "Today → that day, tomorrow → the next day, yesterday → the day before. V testu to bude jen u jasných vět.", - NULL, - }, - }, -}; - -static const char *en_y3_l2_read = "Our head teacher told the local paper that the school was changing. She said that students would start an hour later next term. One pupil told the reporter that he was pleased because he hated early buses. A parent said that she was worried. She said her daughter had joined three clubs and had very little time. The cook said that lunch would still be at noon. He added that the menu was going to include more vegetables."; - -static const ChoiceQ en_y3_l2_readq[] = { - {"What did the head teacher say about the start of school?", {"It would start an hour later", "It would start at night", "It had already closed", "Clubs would end"}, 4, 0}, - {"Why was the pupil pleased?", {"He liked buses", "He hated early buses", "He wanted less lunch", "He had three clubs"}, 4, 1}, - {"What had the daughter done?", {"She had left school", "She had joined three clubs", "She had become a cook", "She had bought a bus"}, 4, 1}, - {"Lunch, according to the cook, …", {"would move to the evening", "would still be at noon", "had been cancelled", "was only vegetables"}, 4, 1}, -}; -static const char *en_y3_l2_readq_hints[] = { - "students would start an hour later.", - "because he hated early buses.", - "had joined three clubs.", - "would still be at noon.", -}; - -static const ChoiceQ en_y3_l2_quiz[] = { - {"„I am hungry.“ → She said she ___ hungry.", {"is", "was", "has", "were be"}, 4, 1}, - {"„I will call.“ → He said he ___ call.", {"will", "would", "called", "has"}, 4, 1}, - {"Which verb needs a person?", {"say", "tell", "speak that", "talk that"}, 4, 1}, - {"She said, „I can't swim.“ → She said she ___.", {"can't swim", "couldn't swim", "doesn't swim", "hasn't swum"}, 4, 1}, -}; -static const char *en_y3_l2_quiz_hints[] = { - "am → was.", - "will → would.", - "tell somebody.", - "can → could. V nepřímé řeči o minulém rozhovoru.", -}; - -static const NetSlide en_y3_l3_slides[] = { - { - "1 / 2 • Prostředí", "Konkrétní slova, ne jen nature", "Tip: drought, soil, volunteer, ban, shortcut. U maturitního tématu zabírají víc než slovo pollution samo.", - { - "A drought is a long time without rain. Soil is the earth plants grow in.", - "Unless it rains, the young trees will die.", - "If the town banned cars, the air would be cleaner. Teď je nezakázalo, proto would.", - "If people keep using the road, the soil will wash away. To se může stát.", - NULL, - }, - }, - { - "2 / 2 • Podcast", "Kdo co řekl", "Tip: u nepřímé řeči v poslechu si pamatujte sloveso řekl/řekla a pak obsah.", - { - "Ranger = strážce lesa.", - "Young trees were planted, but many may still die.", - "A shortcut šetří čas a někdy ničí místo.", - "Čísla si zapište: two thousand.", - NULL, - }, - }, -}; - -static const char *en_y3_l3_listen = "Last month our class recorded a podcast called The Last Beech. A ranger said that the trees were thirsty because the summers had become hotter. She told us that volunteers had planted two thousand young trees, but she added that many would die unless it rained. If the town banned cars from the forest road, the air would be cleaner. If people keep using it as a shortcut, the soil will wash away."; - -static const ChoiceQ en_y3_l3_listenq[] = { - {"What did the ranger say about the trees?", {"They were thirsty", "They had been cut down", "They were a shortcut", "They banned cars"}, 4, 0}, - {"How many young trees had volunteers planted?", {"Two hundred", "Two thousand", "Twenty", "None"}, 4, 1}, - {"The young trees will die unless…", {"people drive there", "it rains", "the podcast ends", "the soil is sold"}, 4, 1}, - {"What would make the air cleaner?", {"Banning cars from the forest road", "Using the road as a shortcut", "Cutting the beeches", "Washing the soil"}, 4, 0}, -}; -static const char *en_y3_l3_listenq_hints[] = { - "the trees were thirsty.", - "two thousand.", - "unless it rained / unless it rains. V textu: unless it rained v nepřímé řeči.", - "If the town banned cars.", -}; - -static const TypedQ en_y3_l3_gaps[] = { - {"If we ___ (ban) cars here, the air would be cleaner.", "banned", "2. podmínka."}, - {"The soil will wash away ___ people stop using the shortcut.", "unless", "Unless = if not. Pozor: věta chce if not ve významu dokud nepřestanou. Unless people stop = if they don't stop."}, - {"Many young trees ___ (plant) last month.", "were planted", "Minulý trpný rod."}, - {"She said the summers ___ (become) hotter.", "had become", "Posun předpřítomného času."}, -}; - -static const NetSlide en_y3_l4_slides[] = { - { - "1 / 2 • Čtyři kroky", "Úvod, dvě strany, závěr", "Tip: v úvodu otázku neopakujte doslova. Převeďte ji vlastními slovy.", - { - "Úvod: o čem text je a že existují dva pohledy.", - "Jeden odstavec pro výhody, jeden pro nevýhody.", - "On the one hand … On the other hand …", - "Závěr: váš názor. In my opinion, I believe. Nepřidávejte úplně nový argument.", - NULL, - }, - }, - { - "2 / 2 • Spojky", "However není because", "Tip: however stojí mezi větami a odděluje se čárkou. Although spojuje věty v jednu.", - { - "School uniforms are cheaper. However, they limit personality.", - "Although uniforms save time, many students hate them.", - "Because dává důvod. So dává výsledek.", - "In conclusion shrnuje. Nepíše se In the conclusion.", - NULL, - }, - }, -}; - -static const char *en_y3_l4_write[] = { - "Write a for-and-against paragraph of at least 50 words about school uniforms. Use however and because, and finish with your opinion using believe.", - "School uniforms are a common argument. They are practical because students do not have to decide what to wear, and families spend less money. However, a uniform hides personality and can feel childish at eighteen. Although it makes mornings faster, it does not make lessons better. I believe schools should keep a simple dress code, but they should not force one jacket on everyone.", - "however|because|believe", - "50", -}; - -static const ChoiceQ en_y3_l4_quiz[] = { - {"Which linker shows contrast?", {"because", "however", "so", "for example"}, 4, 1}, - {"___ uniforms save time, students still complain.", {"However", "Although", "So", "Believe"}, 4, 1}, - {"Choose the best ending of an essay.", {"In conclusion, I have no idea.", "In conclusion, I believe a simple rule is enough.", "Because however so.", "To begin with, the essay starts now."}, 4, 1}, - {"Because introduces…", {"a result only", "a reason", "a list of names", "a question"}, 4, 1}, -}; -static const char *en_y3_l4_quiz_hints[] = { - "However staví protiklad.", - "Although spojuje dvě části jedné věty.", - "Závěr má názor, ne nový zmatek.", - "Because = důvod.", -}; - -static const NetSlide en_y3_l5_slides[] = { - { - "1 / 2 • Dedukce", "Jisté, možné, vyloučené", "Tip: must je skoro jistota, might je možnost, can't je „to přece nejde“.", - { - "The lights are on. She must be at home.", - "He might be in the lab. I'm not sure.", - "That can't be Eva. Eva is in Vienna this week.", - "O minulosti: must have left, might have forgotten, can't have seen it.", - NULL, - }, - }, - { - "2 / 2 • Vynález", "Čtěte důkazy, ne nadpis", "Tip: u must have hledejte důkaz, který už nejde rozumně popřít.", - { - "A notebook with today's date is stronger than a guess.", - "Can't have znamená, že to odporuje faktu.", - "Might have nechává dvě možnosti otevřené.", - "Nepoužívejte can pro dedukci v kladné větě. Can umí, must musí být.", - NULL, - }, - }, -}; - -static const char *en_y3_l5_read = "Someone left a strange machine in the physics lab. It was warm, so it must have been switched on recently. The only key can't have been used by the caretaker, because he is in hospital. Two students, Nora and Adam, know the code. Nora might have come back after the club, but her train ticket shows she was in Pardubice. Adam's notebook is on the bench and the handwriting matches the label. He must have built it."; - -static const ChoiceQ en_y3_l5_readq[] = { - {"Why must the machine have been on recently?", {"It was noisy", "It was warm", "It was new", "It was labelled"}, 4, 1}, - {"Why can't the caretaker have used the key?", {"He lost it", "He is in hospital", "He hates physics", "He was in Pardubice"}, 4, 1}, - {"Where was Nora?", {"In the lab", "In Pardubice", "In hospital", "On the bench"}, 4, 1}, - {"Who must have built the machine?", {"The caretaker", "Nora", "Adam", "Nobody"}, 4, 2}, -}; -static const char *en_y3_l5_readq_hints[] = { - "It was warm.", - "he is in hospital.", - "her ticket shows Pardubice.", - "The notebook and the handwriting point to Adam.", -}; - -static const ChoiceQ en_y3_l5_quiz[] = { - {"The window is broken and his bag is gone. He ___ left in a hurry.", {"must have", "must", "can have", "should"}, 4, 0}, - {"That ___ be Lea. Lea is abroad.", {"must", "can't", "should", "is"}, 4, 1}, - {"I'm not sure. They ___ have missed the bus.", {"must", "can't", "might", "are"}, 4, 2}, - {"Which sentence is a deduction, not a duty?", {"You must wear gloves.", "She must be tired.", "You must sign this.", "Visitors must wait."}, 4, 1}, -}; -static const char *en_y3_l5_quiz_hints[] = { - "Minulá skoro jistota: must have left.", - "Odporuje faktu: can't.", - "Možnost: might have.", - "She must be tired je úsudek.", -}; - -static const NetSlide en_y3_l6_slides[] = { - { - "1 / 2 • Reported questions", "Otázka se v nepřímé řeči narovná", "Tip: žádný otazník a pořadí podmětu a slovesa jako v oznamovací větě.", - { - "„Where do you live?“ → She asked me where I lived.", - "„Did you see it?“ → He asked if I had seen it.", - "Whether a if jsou u zjišťovacích otázek obě možné.", - "Tázací výraz zůstává: what, where, why, how long.", - NULL, - }, - }, - { - "2 / 2 • Redakce", "Novinář se ptá starosty", "Tip: v poslechu odlište otázku reportéra od odpovědi starosty.", - { - "Asked if the bridge was safe.", - "Wondered how long the repairs would take.", - "The mayor said he didn't know yet.", - "Slovesa ask, wonder, want to know.", - NULL, - }, - }, -}; - -static const char *en_y3_l6_listen = "Reporter: Mayor, is the old bridge safe? Mayor: I can't promise that. An engineer told me that two cables were weak. Reporter: How long will the repairs take? Mayor: She asked the firm the same question yesterday. They said they didn't know yet. Reporter: Did anyone complain? Mayor: A shopkeeper asked me why the bus stop had moved. I asked her if she could wait until Friday. Reporter: Will you close the bridge? Mayor: We might. I have asked the police whether they can send officers tonight."; - -static const ChoiceQ en_y3_l6_listenq[] = { - {"What did the engineer tell the mayor?", {"The bridge was new", "Two cables were weak", "The shop was closed", "Friday was impossible"}, 4, 1}, - {"What didn't the firm know?", {"The mayor's name", "How long the repairs would take", "Where the bus stop was", "Who the police were"}, 4, 1}, - {"What did the shopkeeper ask?", {"Why the bus stop had moved", "If the mayor could swim", "Where the cables were made", "Whether Friday was a holiday"}, 4, 0}, - {"Who might come tonight?", {"The firm", "The shopkeeper", "Police officers", "The engineer only"}, 4, 2}, -}; -static const char *en_y3_l6_listenq_hints[] = { - "two cables were weak.", - "They said they didn't know yet. Šlo o délku oprav.", - "why the bus stop had moved.", - "whether they can send officers tonight.", -}; - -static const ChoiceQ en_y3_l6_quiz[] = { - {"„Where do you live?“ → He asked me where I ___.", {"did live", "lived", "do live", "living"}, 4, 1}, - {"„Are you ready?“ → She asked if I ___.", {"was ready", "am I ready", "ready was", "did ready"}, 4, 0}, - {"Which sentence is wrong?", {"He asked where she was.", "He asked where was she.", "He asked if she was tired.", "He wanted to know why she had left."}, 4, 1}, - {"Whether means about the same as…", {"because", "if", "however", "whose"}, 4, 1}, -}; -static const char *en_y3_l6_quiz_hints[] = { - "Pořadí oznamovací věty: where I lived.", - "if I was ready.", - "V nepřímé otázce není inverze.", - "Whether ≈ if v nepřímé zjišťovací otázce.", -}; - -static const NetSlide en_y3_l7_slides[] = { - { - "1 / 2 • Částice mění význam", "Look není look after", "Tip: frázové sloveso se učte jako jednu jednotku, s českým protějškem ve větě.", - { - "look after = starat se, look for = hledat, look forward to = těšit se.", - "give up = vzdát se, find out = zjistit, run out of = dojít zásoba.", - "turn off = vypnout, take off = sundat nebo vzlétnout, get on = nastoupit i vycházet.", - "Look forward to je následované -ing: I look forward to seeing you.", - NULL, - }, - }, - { - "2 / 2 • Příběh", "Jedno sloveso, jedna situace", "Tip: když částici neznáte, představte si gesto. Off je pryč, up je do konce.", - { - "The bus took off není o oblečení. U letadla ano, u autobusu spíš pulled away.", - "Take off a coat = sundat. Take off = vzlétnout. Kontext rozhoduje.", - "Get on with somebody = vycházet s někým.", - "Run out of time je u testu častější než run out time.", - NULL, - }, - }, -}; - -static const TypedQ en_y3_l7_gaps[] = { - {"Can you look ___ my dog this weekend?", "after", "Look after = postarat se."}, - {"We are looking ___ to the trip.", "forward", "Look forward to."}, - {"Don't give ___. The last chapter is the best.", "up", "Give up = vzdát to."}, - {"I need to find ___ who left the note.", "out", "Find out = zjistit."}, - {"We've run ___ of milk.", "out", "Run out of."}, -}; - -static const ChoiceQ en_y3_l7_quiz[] = { - {"Please turn ___ the lights.", {"off", "after", "forward", "out of"}, 4, 0}, - {"She gets ___ well with her neighbours.", {"on", "off", "up", "after"}, 4, 0}, - {"He took ___ his wet coat.", {"off", "up to", "after", "forward"}, 4, 0}, - {"I look forward to ___ you.", {"see", "seeing", "saw", "seen"}, 4, 1}, -}; -static const char *en_y3_l7_quiz_hints[] = { - "Turn off = vypnout.", - "Get on with = vycházet.", - "Sundat: take off.", - "To je předložka, následuje -ing.", -}; - -static const NetSlide en_y3_l8_slides[] = { - { - "1 / 2 • B1+", "Trpný rod, řeč, podmínky, dedukce", "Tip: u trpného rodu hledejte be. U nepřímé otázky žádnou inverzi.", - { - "was written, must be signed, is spoken.", - "said she would, asked where I lived.", - "If they banned cars, the air would be cleaner.", - "must have, might have, can't have.", - NULL, - }, - }, - { - "2 / 2 • Úvaha ve zkratce", "However a because v jednom textu", "Tip: jedna výhoda, jeden háček, jedna věta s názorem.", - { - "Neopakujte zadání první větou.", - "Phrasal verbs nechte ve správné částici. Look after není look for.", - "Told me, ne said me.", - "In conclusion je až na konci, ne v úvodu.", - NULL, - }, - }, -}; - -static const char *en_y3_l8_read = "A repair café opened in a former bakery. Broken radios are mended there on Saturdays. The founder said that people would rather repair than buy if they were shown how. She told a reporter that twenty kettles had been saved in March. Visitors have to bring the broken object, but they don't have to pay. If the café closed, a lot of working parts would be thrown away."; - -static const ChoiceQ en_y3_l8_readq[] = { - {"What happens to radios there?", {"They are sold", "They are mended", "They are banned", "They are thrown away at once"}, 4, 1}, - {"How many kettles had been saved in March?", {"Twelve", "Twenty", "Two thousand", "None"}, 4, 1}, - {"What would happen if the café closed?", {"Parts would be thrown away", "Radios would be cheaper", "People would pay more", "The bakery would reopen as a shop"}, 4, 0}, -}; -static const char *en_y3_l8_readq_hints[] = { - "are mended.", - "twenty kettles.", - "working parts would be thrown away.", -}; - -static const char *en_y3_l8_listen = "Editor: Did the mayor answer you? Journalist: I asked him whether the bridge was safe. He said he didn't know. I also asked how long the repairs would take. He told me that the firm hadn't decided. A resident asked me why the paper hadn't printed a map. I said we would print one tomorrow."; - -static const ChoiceQ en_y3_l8_listenq[] = { - {"What did the journalist ask about safety?", {"Whether the bridge was safe", "If the paper was closed", "Where the mayor lived", "Why kettles break"}, 4, 0}, - {"What hadn't the firm done?", {"Decided", "Printed a map", "Closed the paper", "Asked the resident"}, 4, 0}, - {"What did the journalist promise?", {"To close the bridge", "To print a map tomorrow", "To repair the cables", "To interview a baker"}, 4, 1}, -}; -static const char *en_y3_l8_listenq_hints[] = { - "whether the bridge was safe.", - "hadn't decided.", - "we would print one tomorrow.", -}; - -static const char *en_y3_l8_write[] = { - "In at least 40 words, give one reason for repairing things and one objection. Use because and however.", - "Repairing things matters because a kettle can work for years after a small fix. However, some people do not have the tools or the time, so a café where volunteers help is a fair idea. I believe every town should have one quiet room for broken objects. It is slower than shopping, but it is kinder.", - "because|however", - "40", -}; - -static const ChoiceQ en_y3_l8_quiz[] = { - {"The cake ___ by a student.", {"baked", "was baked", "was bake", "has bake"}, 4, 1}, - {"She asked me where I ___.", {"did live", "lived", "do live", "living"}, 4, 1}, - {"He ___ be at school. I just saw him there.", {"can't", "must", "mustn't", "should to"}, 4, 1}, - {"Please look ___ the tickets. I can't find them.", {"for", "forward", "after", "up of"}, 4, 0}, -}; -static const char *en_y3_l8_quiz_hints[] = { - "was baked.", - "where I lived.", - "Skoro jistota: must.", - "Look for = hledat. Look after by bylo hlídat.", -}; - -static const NetSlide en_y4_l1_slides[] = { - { - "1 / 2 • Ústní zkouška", "Čtyři minuty nejsou román", "Tip: katalog CERMAT chce souvislý projev, popis obrázku, porovnání a reakci na otázky. Ne seznam slov.", - { - "Úvod jednou větou: I'd like to talk about my town, which is smaller than it looks.", - "Obecné plus osobní: Many people commute. I cycle, because the centre is close.", - "Když slovo chybí, opis: the thing you use to open a tin.", - "Na obrázku: In the foreground, in the background, it looks as if.", - NULL, - }, - }, - { - "2 / 2 • Kolokace", "Make, do, have, take", "Tip: české „dělat“ se rozpadá. Do homework, make a mistake, take a photo, have a rest.", - { - "Make a decision, make friends, make the bed.", - "Do the washing-up, do a course, do someone a favour.", - "Take part in, take care of, take an exam.", - "Have a look, have a word with, have trouble with.", - NULL, - }, - }, -}; - -static const TypedQ en_y4_l1_gaps[] = { - {"I need to ___ a decision before Friday.", "make", "Make a decision."}, - {"She ___ her homework on the train.", "does|did", "Do homework."}, - {"Can I ___ a photo of the bridge?", "take", "Take a photo."}, - {"Let's ___ a rest. We've walked for hours.", "have", "Have a rest."}, - {"He ___ part in the school play every year.", "takes|took", "Take part in."}, -}; - -static const ChoiceQ en_y4_l1_quiz[] = { - {"You don't know the word kettle. What helps?", {"Stop the exam", "Paraphrase it", "Switch to Czech for the rest", "Invent a Latin word and insist"}, 4, 1}, - {"In the foreground means…", {"at the back", "at the front of the picture", "outside the frame", "in the past"}, 4, 1}, - {"Which collocation is right?", {"do a mistake", "make a mistake", "take a mistake", "have a mistake"}, 4, 1}, - {"A strong speaking answer…", {"is a list of single words", "adds a personal example", "translates the question", "avoids all verbs"}, 4, 1}, -}; -static const char *en_y4_l1_quiz_hints[] = { - "Opis je lepší než ticho.", - "Foreground = popředí.", - "Make a mistake.", - "Obecné plus vlastní příklad.", -}; - -static const NetSlide en_y4_l2_slides[] = { - { - "1 / 2 • Kostra", "Komu, proč, co chcete, jak se loučíte", "Tip: neznámé jméno → Dear Sir or Madam a Yours faithfully. Známé jméno → Dear Ms Novák a Yours sincerely.", - { - "I am writing to apply for… / to complain about…", - "I would be grateful if you could…", - "Kontrakce v čistě formálním textu omezte: I am, not I'm.", - "Na konci celé jméno. Žádné Cheers ani xoxo.", - NULL, - }, - }, - { - "2 / 2 • Stížnost", "Fakta, dopad, žádost", "Tip: zlost text oslabuje. Datum, číslo spoje a klidná žádost ho posílí.", - { - "The train on 3 May, which I had booked, arrived 90 minutes late.", - "As a result I missed the interview.", - "I would like a refund or an explanation.", - "I look forward to your reply.", - NULL, - }, - }, -}; - -static const char *en_y4_l2_write[] = { - "Write a formal email of at least 55 words to a railway company. Complain about a delay. Start with Dear, use would, and end with sincerely or faithfully.", - "Dear Sir or Madam, I am writing to complain about the night train to Berlin on 3 May. It arrived ninety minutes late, so I missed a morning interview. I would be grateful if you could explain the delay and offer a refund. I have attached my ticket. Please reply to this address. Yours faithfully, Tereza Malá.", - "dear|would|faithfully", - "55", -}; - -static const ChoiceQ en_y4_l2_quiz[] = { - {"You do not know the person's name. You end with…", {"Yours faithfully", "Yours sincerely", "Cheers", "Love"}, 4, 0}, - {"Dear Ms Novák, … ___", {"Yours faithfully", "Yours sincerely", "Hi again", "Bye"}, 4, 1}, - {"Which opening is formal?", {"Hey!!!", "I am writing to apply for the post.", "I wanna the job.", "What's up"}, 4, 1}, - {"A formal request sounds like…", {"Give me a refund now.", "I would be grateful if you could look into this.", "You guys messed up.", "Send money pls."}, 4, 1}, -}; -static const char *en_y4_l2_quiz_hints[] = { - "Neznámé jméno: faithfully. Po Dear Sir or Madam.", - "Jméno znáte: sincerely.", - "I am writing to…", - "I would be grateful if you could…", -}; - -static const NetSlide en_y4_l3_slides[] = { - { - "1 / 2 • Čtení u maturity", "Nečtěte každé slovo stejně pomalu", "Tip: u výběru ze čtyř možností nejdřív zjistěte, na co se otázka ptá, a teprve pak hledejte odstavec.", - { - "Hlavní myšlenka bývá v úvodu nebo v závěru, ne v jednom příkladu.", - "Distraktor často opakuje slovo z textu, ale v jiném vztahu.", - "Which surprises… uvádí postoj, ne jen fakt o ceně.", - "Not given v tomhle cvičení není. Jedna možnost je opřená o text.", - NULL, - }, - }, - { - "2 / 2 • Slovník z kontextu", "Boarding gate a carriage", "Tip: neznámé slovo ohraničte větou před ním a za ním.", - { - "A boarding gate je letištní východ k letadlu. Text ho staví proti posteli ve vlaku.", - "A carriage je vůz vlaku.", - "Demand = poptávka. If demand stays high, přidají vozy.", - "Deleted journey by byl let, který člověk chce mít co nejkratší.", - NULL, - }, - }, -}; - -static const char *en_y4_l3_read = "When the night train from Prague to Berlin returned last spring, stations filled with people who prefer a bed to a boarding gate. A single ticket is often more expensive than a flight, which surprises anyone who thinks trains are always the cheap choice. Still, passengers say they arrive calmer. They can read, talk and avoid the bright shops of an airport. Critics point out that a delay of two hours is common and that the cabins are small. The railway has promised that new carriages will be added if demand stays high. A student I spoke to had taken the train three times. She said she would fly only if she missed the evening departure. For her, the journey is part of the trip, not a problem to be deleted."; - -static const ChoiceQ en_y4_l3_readq[] = { - {"What is the main point?", {"Flights have been cancelled", "Some people choose the night train even when it costs more", "Berlin has closed its station", "Students may not travel"}, 4, 1}, - {"What surprises some readers?", {"That a train ticket can cost more than a flight", "That stations are empty", "That nobody reads", "That the train is free"}, 4, 0}, - {"What do critics mention?", {"Free meals", "Delays and small cabins", "Too many books", "A lack of stations"}, 4, 1}, - {"The student would fly only if…", {"the ticket was cheap", "she missed the evening departure", "the cabins were small", "she hated reading"}, 4, 1}, - {"New carriages will be added if…", {"critics agree", "demand stays high", "flights are banned", "students complain"}, 4, 1}, -}; -static const char *en_y4_l3_readq_hints[] = { - "Lístek bývá dražší než let, a přesto lidé vlak volí.", - "more expensive than a flight, which surprises…", - "a delay of two hours, cabins are small.", - "only if she missed the evening departure.", - "if demand stays high.", -}; - -static const NetSlide en_y4_l4_slides[] = { - { - "1 / 2 • Poslech u maturity", "Dvě přehrání stačí, když víte co", "Tip: při prvním poslechu chyťte kostru, při druhém doplňte past, podmínku a zápor.", - { - "Otázky si přečtěte dřív. Podtrhněte tázací slovo.", - "Čísla a never/already mění význam celé věty.", - "Wouldn't force není couldn't.", - "I didn't give him any medicine je důležité právě proto, že je zápor.", - NULL, - }, - }, - { - "2 / 2 • Práce s dětmi", "Slovník pohovoru", "Tip: deal with an emergency, refuse, offer, look forward to.", - { - "For two years je délka, ne bod v čase.", - "A quieter task je alternativa, ne trest.", - "Although přiznává nevýhodu a názor nemění.", - "Boots jsou důkaz, že s deštěm počítá. Proto going to / already.", - NULL, - }, - }, -}; - -static const char *en_y4_l4_listen = "Interviewer: Why did you apply to the summer camp in Wales? Hana: I have worked with children for two years, and I wanted a job where English is the only language. Interviewer: What would you do if a child refused to join an activity? Hana: I wouldn't force them. I would ask why, and I might offer a quieter task. Interviewer: Have you ever dealt with an emergency? Hana: Yes. Last August a boy cut his foot. I cleaned the cut and called the nurse. I didn't give him any medicine. Interviewer: The camp is rainy. Is that a problem? Hana: Not really. I have already bought boots. I look forward to the hills, although I know the work will be tiring."; - -static const ChoiceQ en_y4_l4_listenq[] = { - {"Why does Hana want the job?", {"She has never met children", "She wants a job where only English is spoken", "She hates hills", "She wants to sell boots"}, 4, 1}, - {"How long has she worked with children?", {"For two weeks", "For two years", "Since last August only", "She hasn't"}, 4, 1}, - {"What would she do if a child refused an activity?", {"Force them", "Send them home", "Ask why and maybe offer a quieter task", "Give them medicine"}, 4, 2}, - {"What didn't she do in the emergency?", {"Clean the cut", "Call the nurse", "Give medicine", "Help the boy"}, 4, 2}, - {"How does she feel about the rain?", {"She has already bought boots and still looks forward to the hills", "She will refuse the job", "She has never seen rain", "She hates children"}, 4, 0}, -}; -static const char *en_y4_l4_listenq_hints[] = { - "where English is the only language.", - "for two years.", - "I wouldn't force them. I might offer a quieter task.", - "I didn't give him any medicine.", - "already bought boots, look forward to the hills.", -}; - -static const NetSlide en_y4_l5_slides[] = { - { - "1 / 2 • Názor", "Nejdřív stanovisko, pak důvody", "Tip: u názorové eseje čtenář nemá hádat, na čí straně jste. Řekněte to v úvodu.", - { - "I believe that… / In my opinion…", - "First reason, second reason, a short answer to the other side.", - "Although some people argue that…, I still think…", - "Závěr ať zní jako závěr, ne jako třetí nový důvod.", - NULL, - }, - }, - { - "2 / 2 • Rozsah", "Radši čtyři hutné věty než deset prázdných", "Tip: u písemné práce se počítají slova. Opakování zadání se nepočítá jako myšlenka.", - { - "Každý důvod ať má příklad z běžného života.", - "Nepoužívejte etc. Místo toho jedno konkrétní slovo.", - "Spojky: firstly, in addition, on the other hand, in conclusion.", - "Kontraktované tvary jsou v názorové eseji v pořádku, když text není stížnost úřadu.", - NULL, - }, - }, -}; - -static const char *en_y4_l5_write[] = { - "Write an opinion of at least 60 words: should students have a gap year before university? Use believe, although and in conclusion.", - "I believe a gap year can help, but only when it has a plan. Although some students waste the time, others work, travel or look after a relative and return calmer. A year in a job also shows whether a degree is really necessary. On the other hand, a long break can make it harder to study again. In conclusion, a gap year is useful if the person can explain what they will do with it.", - "believe|although|conclusion", - "60", -}; - -static const ChoiceQ en_y4_l5_quiz[] = { - {"Where should your opinion appear in this kind of essay?", {"Only in a footnote", "In the introduction and again at the end", "Never", "Only in the title"}, 4, 1}, - {"Although introduces…", {"a concession", "a list of books", "a greeting", "a date"}, 4, 0}, - {"In conclusion should…", {"start a brand-new topic", "sum up", "replace the introduction", "ask the examiner a question"}, 4, 1}, - {"Which is the best topic sentence?", {"Gap year gap year gap year.", "A gap year is worth it when it has a clear plan.", "Hello my name is and I will write.", "Etc. etc. etc."}, 4, 1}, -}; -static const char *en_y4_l5_quiz_hints[] = { - "Úvod i závěr.", - "Ústupka: something true that does not win.", - "Shrnutí.", - "Věta, která už nese názor.", -}; - -static const NetSlide en_y4_l6_slides[] = { - { - "1 / 2 • Okruhy", "Ne izolovaná slovíčka", "Tip: ústní zkouška sahá na osobu, rodinu, domov, školu, volný čas, kulturu, sport, cestování, zdraví, jídlo, služby, práci, společnost a přírodu.", - { - "Heavy rain, strong coffee, fast food, junk food. Ne strong rain.", - "A balanced diet, processed food, a food allergy.", - "Public transport, rush hour, a traffic jam, a return ticket.", - "Renewable energy, a carbon footprint, a heatwave, a drought.", - NULL, - }, - }, - { - "2 / 2 • Společnost a práce", "Fráze, které unesou odstavec", "Tip: apply for a job, hand in a notice, earn a living, from home.", - { - "A gap year, an apprenticeship, a degree, tuition fees.", - "Freedom of speech, a stereotype, volunteer work.", - "Break the law, pay a fine, a witness.", - "Mental health, a check-up, be in pain. Ne have pain in the leg jako jediná možnost: My leg hurts.", - NULL, - }, - }, -}; - -static const TypedQ en_y4_l6_gaps[] = { - {"There was heavy ___ all night.", "rain", "Heavy rain, ne strong rain."}, - {"I'd like a ___ ticket to Brno.", "return", "Return ticket = zpáteční."}, - {"She applied ___ the post of guide.", "for", "Apply for."}, - {"Solar power is ___ energy.", "renewable", "Renewable energy."}, - {"He has a nut ___, so he can't eat the cake.", "allergy", "A food allergy."}, -}; - -static const ChoiceQ en_y4_l6_quiz[] = { - {"Which pair is right?", {"strong rain / heavy coffee", "heavy rain / strong coffee", "fast coffee / junk rain", "a traffic diet"}, 4, 1}, - {"Rush hour is…", {"a quiet morning", "the busiest time to travel", "a kind of ticket", "a school subject"}, 4, 1}, - {"An apprenticeship is…", {"a fine", "training for a job", "a heatwave", "a stereotype"}, 4, 1}, - {"My leg ___.", {"hurts", "is pain", "has hurted", "does hurtness"}, 4, 0}, -}; -static const char *en_y4_l6_quiz_hints[] = { - "Heavy rain, strong coffee.", - "Špička.", - "Praktická příprava na řemeslo nebo práci.", - "My leg hurts.", -}; - -static const NetSlide en_y4_l7_slides[] = { - { - "1 / 2 • Články a časy", "To, co se v testu sype", "Tip: the night train, a night train, night trains. Člen podle toho, jestli čtenář ví který.", - { - "I have lived here since May. I lived there in 2018.", - "If I were you, I would wait. If it rains, we will wait.", - "The book was written in 1962. People speak English here → English is spoken here.", - "Used to: I used to walk. Zvyk, který už neplatí. Didn't use to.", - NULL, - }, - }, - { - "2 / 2 • Věta", "Slovosled a shoda", "Tip: never dávejte před sloveso, ale za am/is/are: She is never late. She never arrives late.", - { - "A little time, a few minutes. Much v záporu a otázce, a lot of v kladné větě je bezpečné.", - "Suggest + -ing nebo suggest that. Suggest me to go je chyba.", - "Enjoy, avoid, mind, can't help + -ing.", - "Want, decide, promise, hope + to.", - NULL, - }, - }, -}; - -static const TypedQ en_y4_l7_gaps[] = { - {"I ___ (live) in this flat since May.", "have lived|'ve lived", "Since → present perfect."}, - {"She suggested ___ (take) the night train.", "taking", "Suggest + -ing."}, - {"If I ___ you, I would book earlier.", "were|was", "If I were you."}, - {"These letters must ___ (sign) today.", "be signed", "Must be + příčestí."}, - {"I ___ to get up at five. I don't anymore.", "used", "Used to."}, -}; - -static const ChoiceQ en_y4_l7_quiz[] = { - {"She enjoys ___.", {"to swim", "swimming", "swim", "swam"}, 4, 1}, - {"I have ___ finished.", {"yet", "just", "since", "ago"}, 4, 1}, - {"English ___ all over the building.", {"speaks", "is spoken", "is spoke", "speak"}, 4, 1}, - {"There isn't ___ time.", {"many", "much", "a few", "several"}, 4, 1}, - {"He asked me where ___.", {"did I live", "I lived", "do I lived", "lived I"}, 4, 1}, - {"You ___ shout. The baby is asleep. It is forbidden.", {"don't have to", "mustn't", "might", "used to"}, 4, 1}, -}; -static const char *en_y4_l7_quiz_hints[] = { - "Enjoy + -ing.", - "Just before the participle. Yet belongs at the end in negatives.", - "Trpný rod.", - "Time je nepočitatelné: much.", - "Bez inverze.", - "Zákaz: mustn't.", -}; - -static const NetSlide en_y4_l8_slides[] = { - { - "1 / 2 • Celá zkouška", "Tři části, jeden mozek", "Tip: didaktický test míchá poslech, čtení a jazykovou kompetenci. Písemná práce je zvlášť. Tady je zmenšený model.", - { - "Nejdřív přečtěte zadání psaní, ať víte, kolik času si necháte.", - "U čtení nehledejte stejná slova. Hledejte stejný význam.", - "U poslechu zápor bývá ta správná odpověď.", - "Když váháte mezi dvěma, vyhoďte tu, která přidává informaci v textu neslyšenou.", - NULL, - }, - }, - { - "2 / 2 • Písemná práce", "Účel, čtenář, rozsah", "Tip: e-mail kamarádovi a stížnost úřadu se nepíšou stejným jazykem. Tady jde o kamaráda.", - { - "Řekněte proč píšete hned v první větě.", - "Dejte tam čas a místo, ať text není mlha.", - "Jedna věta s because a jedna s if textu pomůžou.", - "Na konci otázka, která zní jako opravdový zájem.", - NULL, - }, - }, -}; - -static const char *en_y4_l8_read = "The town library now lends tools as well as books. Hammers, sewing machines and a cake tin can be borrowed for a week. The idea came from a librarian who was tired of people buying things they would use once. She said the workshop had been visited by more teenagers than the reading room. Critics argue that a library should stay quiet. She replies that a library should be useful. If the experiment works, other branches will copy it. Users have to return each object clean, and they must not lend it to anyone else."; - -static const ChoiceQ en_y4_l8_readq[] = { - {"What can people borrow besides books?", {"Cars", "Tools", "Flats", "Tickets to Berlin"}, 4, 1}, - {"Why did the idea start?", {"People were buying things they would use once", "The reading room was too popular", "Teenagers hated books", "The tools were illegal"}, 4, 0}, - {"Who has visited the workshop more, according to her?", {"Critics", "Teenagers, more than the reading room", "Other branches", "Nobody"}, 4, 1}, - {"What must users not do?", {"Return the object", "Clean it", "Lend it to someone else", "Visit the library"}, 4, 2}, -}; -static const char *en_y4_l8_readq_hints[] = { - "Hammers, sewing machines, a cake tin.", - "buying things they would use once.", - "more teenagers than the reading room.", - "must not lend it to anyone else.", -}; - -static const char *en_y4_l8_listen = "Welcome to the night-train podcast. The 22:40 to Berlin has been delayed by forty minutes because a tree is on the line near Ústí. Passengers who already have a seat can wait in carriage four, where tea is being served. If you have not checked in, please do it on your phone. We would be grateful if you kept the corridor clear. The delay might be shorter. We will know more at ten."; - -static const ChoiceQ en_y4_l8_listenq[] = { - {"How long is the delay?", {"14 minutes", "40 minutes", "4 hours", "22 minutes"}, 4, 1}, - {"Why?", {"Snow", "A tree on the line", "A missing driver", "A festival"}, 4, 1}, - {"Where can passengers with a seat wait?", {"Carriage four", "The airport", "Ústí station only", "The corridor"}, 4, 0}, - {"What should people without a check-in do?", {"Buy tea", "Check in on their phone", "Leave the train", "Call the mayor"}, 4, 1}, -}; -static const char *en_y4_l8_listenq_hints[] = { - "forty minutes.", - "a tree is on the line.", - "carriage four.", - "do it on your phone.", -}; - -static const char *en_y4_l8_write[] = { - "Write at least 45 words to a friend. Invite them to borrow something from a library of things. Use because and if.", - "Hi Adam, the library now lends tools, and I think you would like it because you always need a drill for one afternoon. If you come on Saturday, I will show you how it works. You have to bring your card and return everything clean. We could borrow a cake tin and bake something after. Let me know if you are free.", - "because|if", - "45", -}; - -static const ChoiceQ en_y4_l8_quiz[] = { - {"Tea ___ in carriage four.", {"serves", "is being served", "is serving", "has serve"}, 4, 1}, - {"We would be grateful if you ___ the corridor clear.", {"keep", "kept", "keeping", "to keep"}, 4, 1}, - {"She said the workshop ___ by more teenagers.", {"visited", "had been visited", "has visit", "is visiting"}, 4, 1}, - {"Users ___ return the tools clean.", {"have to", "must to", "don't must", "are have"}, 4, 0}, -}; -static const char *en_y4_l8_quiz_hints[] = { - "Průběhový trpný rod.", - "Would be grateful if + minulý tvar.", - "Had been visited.", - "Have to.", -}; - -static const EnLesson en_lessons[EN_YEARS][EN_N] = { - { - { - .slides = en_y1_l1_slides, - .n_slides = (int)(sizeof en_y1_l1_slides / sizeof en_y1_l1_slides[0]), - .gaps = en_y1_l1_gaps, - .n_gaps = (int)(sizeof en_y1_l1_gaps / sizeof en_y1_l1_gaps[0]), - .quiz = en_y1_l1_quiz, - .quiz_hints = en_y1_l1_quiz_hints, - .n_quiz = (int)(sizeof en_y1_l1_quiz / sizeof en_y1_l1_quiz[0]), - }, - { - .slides = en_y1_l2_slides, - .n_slides = (int)(sizeof en_y1_l2_slides / sizeof en_y1_l2_slides[0]), - .reading = "My school day starts early. I get up at half past six, have breakfast and catch the tram. Lessons begin at eight. On Monday we have maths, English and biology. I like biology because we do experiments, but I don't like maths. We have lunch at half past twelve in the canteen. After school I do my homework or meet friends. I never go to bed after ten on a school night.", - .readq = en_y1_l2_readq, - .read_hints = en_y1_l2_readq_hints, - .n_read = (int)(sizeof en_y1_l2_readq / sizeof en_y1_l2_readq[0]), - .gaps = en_y1_l2_gaps, - .n_gaps = (int)(sizeof en_y1_l2_gaps / sizeof en_y1_l2_gaps[0]), - }, - { - .slides = en_y1_l3_slides, - .n_slides = (int)(sizeof en_y1_l3_slides / sizeof en_y1_l3_slides[0]), - .listening = "Hi Tom, it's Anna. Are you free on Saturday? I'm meeting Eva at the station at ten. We're going to the market first, and then we're having lunch in that new café by the river. In the afternoon I'm playing volleyball with my class in the park. Do you want to come to the café? Call me back tonight.", - .listenq = en_y1_l3_listenq, - .listen_hints = en_y1_l3_listenq_hints, - .n_listen = (int)(sizeof en_y1_l3_listenq / sizeof en_y1_l3_listenq[0]), - .gaps = en_y1_l3_gaps, - .n_gaps = (int)(sizeof en_y1_l3_gaps / sizeof en_y1_l3_gaps[0]), - }, - { - .slides = en_y1_l4_slides, - .n_slides = (int)(sizeof en_y1_l4_slides / sizeof en_y1_l4_slides[0]), - .write_prompt = "Describe your room in at least 30 words. Say what is in it and where things are. Use on and a piece of furniture such as a bed, and mention a window.", - .write_model = "My room is small but bright. There is a bed next to the window and a wooden desk under a shelf. My books are on the desk and my school bag is under the chair. There are two posters on the wall. I like the room because it is quiet in the evening.", - .write_keys = "bed|window|on", - .write_min = 30, - .quiz = en_y1_l4_quiz, - .quiz_hints = en_y1_l4_quiz_hints, - .n_quiz = (int)(sizeof en_y1_l4_quiz / sizeof en_y1_l4_quiz[0]), - }, - { - .slides = en_y1_l5_slides, - .n_slides = (int)(sizeof en_y1_l5_slides / sizeof en_y1_l5_slides[0]), - .reading = "On Saturday morning the market by the river is busy. A woman asks, \"How much is this cheese?\" The seller says, \"It's four euros a kilo.\" Then she asks, \"Have you got any bread?\" He answers, \"Sorry, we haven't got any bread today, but we've got some fresh rolls.\" \"How many rolls do you want?\" \"Six, please, and a little milk.\" She also buys a few apples. \"Anything else?\" \"No, that's all.\"", - .readq = en_y1_l5_readq, - .read_hints = en_y1_l5_readq_hints, - .n_read = (int)(sizeof en_y1_l5_readq / sizeof en_y1_l5_readq[0]), - .gaps = en_y1_l5_gaps, - .n_gaps = (int)(sizeof en_y1_l5_gaps / sizeof en_y1_l5_gaps[0]), - }, - { - .slides = en_y1_l6_slides, - .n_slides = (int)(sizeof en_y1_l6_slides / sizeof en_y1_l6_slides[0]), - .listening = "Last July we went to Croatia. We travelled by train and then by bus because the flight was too expensive. The weather was hot every day. I swam in the morning and my brother tried surfing. He fell off the board a lot, but he loved it. One day we visited a small island. We didn't stay in a hotel. We stayed with our uncle near the beach. I took hundreds of photos.", - .listenq = en_y1_l6_listenq, - .listen_hints = en_y1_l6_listenq_hints, - .n_listen = (int)(sizeof en_y1_l6_listenq / sizeof en_y1_l6_listenq[0]), - .quiz = en_y1_l6_quiz, - .quiz_hints = en_y1_l6_quiz_hints, - .n_quiz = (int)(sizeof en_y1_l6_quiz / sizeof en_y1_l6_quiz[0]), - }, - { - .slides = en_y1_l7_slides, - .n_slides = (int)(sizeof en_y1_l7_slides / sizeof en_y1_l7_slides[0]), - .gaps = en_y1_l7_gaps, - .n_gaps = (int)(sizeof en_y1_l7_gaps / sizeof en_y1_l7_gaps[0]), - .write_prompt = "Write a short message to a friend about next weekend. Use at least 25 words. Say what you are going to do, mention the weekend, and give a reason with because.", - .write_model = "Hi Lena, next weekend I am going to visit my cousins in Pilsen. We are going to the cinema on Saturday because a new film is on. On Sunday we are going to cook lunch together. Do you want to come with me? Write back soon.", - .write_keys = "going|weekend|because", - .write_min = 25, - }, - { - .slides = en_y1_l8_slides, - .n_slides = (int)(sizeof en_y1_l8_slides / sizeof en_y1_l8_slides[0]), - .reading = "Klara lives in a flat with her parents and a small dog. On weekdays she walks to school because it is only ten minutes away. She loves art. Last Friday her class visited a gallery and she bought a poster. This Saturday she is meeting her cousin at the station. They are going to a concert in the evening.", - .readq = en_y1_l8_readq, - .read_hints = en_y1_l8_readq_hints, - .n_read = (int)(sizeof en_y1_l8_readq / sizeof en_y1_l8_readq[0]), - .listening = "Hi, it's Marek. I missed you after school. I'm at the sports centre. The match starts at four, not at three, so don't hurry. Can you bring my blue jacket? It's on the chair in the kitchen. See you there.", - .listenq = en_y1_l8_listenq, - .listen_hints = en_y1_l8_listenq_hints, - .n_listen = (int)(sizeof en_y1_l8_listenq / sizeof en_y1_l8_listenq[0]), - .write_prompt = "Write at least 30 words about your family. Use is or are, and the words family and because.", - .write_model = "My family is not very big. I live with my parents and my younger sister. She is twelve and she is funny. We get on well because we both like films. My dad is a driver and my mum is a nurse. I am happy at home.", - .write_keys = "family|because", - .write_min = 30, - .quiz = en_y1_l8_quiz, - .quiz_hints = en_y1_l8_quiz_hints, - .n_quiz = (int)(sizeof en_y1_l8_quiz / sizeof en_y1_l8_quiz[0]), - } - }, - { - { - .slides = en_y2_l1_slides, - .n_slides = (int)(sizeof en_y2_l1_slides / sizeof en_y2_l1_slides[0]), - .gaps = en_y2_l1_gaps, - .n_gaps = (int)(sizeof en_y2_l1_gaps / sizeof en_y2_l1_gaps[0]), - .quiz = en_y2_l1_quiz, - .quiz_hints = en_y2_l1_quiz_hints, - .n_quiz = (int)(sizeof en_y2_l1_quiz / sizeof en_y2_l1_quiz[0]), - }, - { - .slides = en_y2_l2_slides, - .n_slides = (int)(sizeof en_y2_l2_slides / sizeof en_y2_l2_slides[0]), - .reading = "The school clinic is open from seven to three. If you feel ill, you should tell your teacher first. You have to bring your insurance card. You must not come to school with a high temperature. Students with a cough should wear a mask in the waiting room. You don't have to make an appointment for a small cut, but you should come before noon. The nurse can give you a painkiller. She can't give you antibiotics.", - .readq = en_y2_l2_readq, - .read_hints = en_y2_l2_readq_hints, - .n_read = (int)(sizeof en_y2_l2_readq / sizeof en_y2_l2_readq[0]), - .quiz = en_y2_l2_quiz, - .quiz_hints = en_y2_l2_quiz_hints, - .n_quiz = (int)(sizeof en_y2_l2_quiz / sizeof en_y2_l2_quiz[0]), - }, - { - .slides = en_y2_l3_slides, - .n_slides = (int)(sizeof en_y2_l3_slides / sizeof en_y2_l3_slides[0]), - .listening = "Manager: Have you ever worked in a shop? Tereza: Not in a shop, but I have helped in my uncle's bakery since May. Manager: What do you do there? Tereza: I have served customers and I have learned to use the till. I haven't baked bread yet. Manager: Can you start next Saturday? Tereza: Yes. I have already asked my uncle, and he says it's fine. I can't work on Sunday mornings because I have a match.", - .listenq = en_y2_l3_listenq, - .listen_hints = en_y2_l3_listenq_hints, - .n_listen = (int)(sizeof en_y2_l3_listenq / sizeof en_y2_l3_listenq[0]), - .gaps = en_y2_l3_gaps, - .n_gaps = (int)(sizeof en_y2_l3_gaps / sizeof en_y2_l3_gaps[0]), - }, - { - .slides = en_y2_l4_slides, - .n_slides = (int)(sizeof en_y2_l4_slides / sizeof en_y2_l4_slides[0]), - .write_prompt = "Write a short review of a film or a book in at least 40 words. Use who once and which once, and say who you would recommend it to.", - .write_model = "The Lighthouse Keeper is a quiet film which follows a woman on a small island. The actor who plays her hardly speaks, but her face tells the story. The sea, which is almost a character, is beautiful and dangerous. I would recommend it to anyone who likes slow films. The ending is sad but honest.", - .write_keys = "who|which|recommend", - .write_min = 40, - .quiz = en_y2_l4_quiz, - .quiz_hints = en_y2_l4_quiz_hints, - .n_quiz = (int)(sizeof en_y2_l4_quiz / sizeof en_y2_l4_quiz[0]), - }, - { - .slides = en_y2_l5_slides, - .n_slides = (int)(sizeof en_y2_l5_slides / sizeof en_y2_l5_slides[0]), - .reading = "We wanted to cycle to the lake, but the morning was too foggy to start. By ten the sun was out and the path was dry enough. There were too many cyclists near the dam, so we took a quieter road. We didn't have enough water, which was a mistake. At the lake a guard said, \"Look at that cloud. It's going to pour. I think the storm will last an hour.\" We were not fast enough. We got soaked.", - .readq = en_y2_l5_readq, - .read_hints = en_y2_l5_readq_hints, - .n_read = (int)(sizeof en_y2_l5_readq / sizeof en_y2_l5_readq[0]), - .gaps = en_y2_l5_gaps, - .n_gaps = (int)(sizeof en_y2_l5_gaps / sizeof en_y2_l5_gaps[0]), - }, - { - .slides = en_y2_l6_slides, - .n_slides = (int)(sizeof en_y2_l6_slides / sizeof en_y2_l6_slides[0]), - .listening = "This is Nora at the river festival. The gates have just opened and hundreds of people have already come in. I have never seen so many lanterns. Last night the main band played for two hours, but tonight's singer hasn't arrived yet. A local baker has made a cake in the shape of a violin. I tried a piece yesterday. It was delicious. Have you ever been here? I came for the first time in 2022, and I have come back every summer since then.", - .listenq = en_y2_l6_listenq, - .listen_hints = en_y2_l6_listenq_hints, - .n_listen = (int)(sizeof en_y2_l6_listenq / sizeof en_y2_l6_listenq[0]), - .quiz = en_y2_l6_quiz, - .quiz_hints = en_y2_l6_quiz_hints, - .n_quiz = (int)(sizeof en_y2_l6_quiz / sizeof en_y2_l6_quiz[0]), - }, - { - .slides = en_y2_l7_slides, - .n_slides = (int)(sizeof en_y2_l7_slides / sizeof en_y2_l7_slides[0]), - .gaps = en_y2_l7_gaps, - .n_gaps = (int)(sizeof en_y2_l7_gaps / sizeof en_y2_l7_gaps[0]), - .write_prompt = "Write at least 35 words. Include one real plan with if and will, and one unreal dream with would. Use the word if twice.", - .write_model = "If I finish my project tonight, I will go climbing with Eva on Saturday. We will take the early bus if the weather is fine. If I had more free time, I would learn the guitar. I would also travel by night train if tickets were cheaper. If is a small word with two very different lives.", - .write_keys = "if|will|would", - .write_min = 35, - }, - { - .slides = en_y2_l8_slides, - .n_slides = (int)(sizeof en_y2_l8_slides / sizeof en_y2_l8_slides[0]), - .reading = "The night bus to Brno is cheaper than the train, but it is also slower. Last Friday I was sleeping when the driver stopped at a dark petrol station. A woman who had missed her connection asked if she could sit next to me. She has travelled this route since March because her new job starts at six. If the bus is late, she has to run. She says she would move closer if flats were cheaper.", - .readq = en_y2_l8_readq, - .read_hints = en_y2_l8_readq_hints, - .n_read = (int)(sizeof en_y2_l8_readq / sizeof en_y2_l8_readq[0]), - .listening = "Doctor: How long have you had this cough? Adam: Since Sunday. I have also had a sore throat for two days. Doctor: You should rest and drink water. You don't have to stay in bed all day, but you mustn't play football this week. If you still feel ill on Friday, come back.", - .listenq = en_y2_l8_listenq, - .listen_hints = en_y2_l8_listenq_hints, - .n_listen = (int)(sizeof en_y2_l8_listenq / sizeof en_y2_l8_listenq[0]), - .write_prompt = "Write at least 35 words about a trip or a job you would like. Use would and because.", - .write_model = "I would like to work in a small bookshop by the station because I love quiet mornings. I would talk to customers and I would also read in the breaks. If I had the job, I would cycle there. I have never worked in a shop, but I have helped at school events.", - .write_keys = "would|because", - .write_min = 35, - .quiz = en_y2_l8_quiz, - .quiz_hints = en_y2_l8_quiz_hints, - .n_quiz = (int)(sizeof en_y2_l8_quiz / sizeof en_y2_l8_quiz[0]), - } - }, - { - { - .slides = en_y3_l1_slides, - .n_slides = (int)(sizeof en_y3_l1_slides / sizeof en_y3_l1_slides[0]), - .gaps = en_y3_l1_gaps, - .n_gaps = (int)(sizeof en_y3_l1_gaps / sizeof en_y3_l1_gaps[0]), - .quiz = en_y3_l1_quiz, - .quiz_hints = en_y3_l1_quiz_hints, - .n_quiz = (int)(sizeof en_y3_l1_quiz / sizeof en_y3_l1_quiz[0]), - }, - { - .slides = en_y3_l2_slides, - .n_slides = (int)(sizeof en_y3_l2_slides / sizeof en_y3_l2_slides[0]), - .reading = "Our head teacher told the local paper that the school was changing. She said that students would start an hour later next term. One pupil told the reporter that he was pleased because he hated early buses. A parent said that she was worried. She said her daughter had joined three clubs and had very little time. The cook said that lunch would still be at noon. He added that the menu was going to include more vegetables.", - .readq = en_y3_l2_readq, - .read_hints = en_y3_l2_readq_hints, - .n_read = (int)(sizeof en_y3_l2_readq / sizeof en_y3_l2_readq[0]), - .quiz = en_y3_l2_quiz, - .quiz_hints = en_y3_l2_quiz_hints, - .n_quiz = (int)(sizeof en_y3_l2_quiz / sizeof en_y3_l2_quiz[0]), - }, - { - .slides = en_y3_l3_slides, - .n_slides = (int)(sizeof en_y3_l3_slides / sizeof en_y3_l3_slides[0]), - .listening = "Last month our class recorded a podcast called The Last Beech. A ranger said that the trees were thirsty because the summers had become hotter. She told us that volunteers had planted two thousand young trees, but she added that many would die unless it rained. If the town banned cars from the forest road, the air would be cleaner. If people keep using it as a shortcut, the soil will wash away.", - .listenq = en_y3_l3_listenq, - .listen_hints = en_y3_l3_listenq_hints, - .n_listen = (int)(sizeof en_y3_l3_listenq / sizeof en_y3_l3_listenq[0]), - .gaps = en_y3_l3_gaps, - .n_gaps = (int)(sizeof en_y3_l3_gaps / sizeof en_y3_l3_gaps[0]), - }, - { - .slides = en_y3_l4_slides, - .n_slides = (int)(sizeof en_y3_l4_slides / sizeof en_y3_l4_slides[0]), - .write_prompt = "Write a for-and-against paragraph of at least 50 words about school uniforms. Use however and because, and finish with your opinion using believe.", - .write_model = "School uniforms are a common argument. They are practical because students do not have to decide what to wear, and families spend less money. However, a uniform hides personality and can feel childish at eighteen. Although it makes mornings faster, it does not make lessons better. I believe schools should keep a simple dress code, but they should not force one jacket on everyone.", - .write_keys = "however|because|believe", - .write_min = 50, - .quiz = en_y3_l4_quiz, - .quiz_hints = en_y3_l4_quiz_hints, - .n_quiz = (int)(sizeof en_y3_l4_quiz / sizeof en_y3_l4_quiz[0]), - }, - { - .slides = en_y3_l5_slides, - .n_slides = (int)(sizeof en_y3_l5_slides / sizeof en_y3_l5_slides[0]), - .reading = "Someone left a strange machine in the physics lab. It was warm, so it must have been switched on recently. The only key can't have been used by the caretaker, because he is in hospital. Two students, Nora and Adam, know the code. Nora might have come back after the club, but her train ticket shows she was in Pardubice. Adam's notebook is on the bench and the handwriting matches the label. He must have built it.", - .readq = en_y3_l5_readq, - .read_hints = en_y3_l5_readq_hints, - .n_read = (int)(sizeof en_y3_l5_readq / sizeof en_y3_l5_readq[0]), - .quiz = en_y3_l5_quiz, - .quiz_hints = en_y3_l5_quiz_hints, - .n_quiz = (int)(sizeof en_y3_l5_quiz / sizeof en_y3_l5_quiz[0]), - }, - { - .slides = en_y3_l6_slides, - .n_slides = (int)(sizeof en_y3_l6_slides / sizeof en_y3_l6_slides[0]), - .listening = "Reporter: Mayor, is the old bridge safe? Mayor: I can't promise that. An engineer told me that two cables were weak. Reporter: How long will the repairs take? Mayor: She asked the firm the same question yesterday. They said they didn't know yet. Reporter: Did anyone complain? Mayor: A shopkeeper asked me why the bus stop had moved. I asked her if she could wait until Friday. Reporter: Will you close the bridge? Mayor: We might. I have asked the police whether they can send officers tonight.", - .listenq = en_y3_l6_listenq, - .listen_hints = en_y3_l6_listenq_hints, - .n_listen = (int)(sizeof en_y3_l6_listenq / sizeof en_y3_l6_listenq[0]), - .quiz = en_y3_l6_quiz, - .quiz_hints = en_y3_l6_quiz_hints, - .n_quiz = (int)(sizeof en_y3_l6_quiz / sizeof en_y3_l6_quiz[0]), - }, - { - .slides = en_y3_l7_slides, - .n_slides = (int)(sizeof en_y3_l7_slides / sizeof en_y3_l7_slides[0]), - .gaps = en_y3_l7_gaps, - .n_gaps = (int)(sizeof en_y3_l7_gaps / sizeof en_y3_l7_gaps[0]), - .quiz = en_y3_l7_quiz, - .quiz_hints = en_y3_l7_quiz_hints, - .n_quiz = (int)(sizeof en_y3_l7_quiz / sizeof en_y3_l7_quiz[0]), - }, - { - .slides = en_y3_l8_slides, - .n_slides = (int)(sizeof en_y3_l8_slides / sizeof en_y3_l8_slides[0]), - .reading = "A repair café opened in a former bakery. Broken radios are mended there on Saturdays. The founder said that people would rather repair than buy if they were shown how. She told a reporter that twenty kettles had been saved in March. Visitors have to bring the broken object, but they don't have to pay. If the café closed, a lot of working parts would be thrown away.", - .readq = en_y3_l8_readq, - .read_hints = en_y3_l8_readq_hints, - .n_read = (int)(sizeof en_y3_l8_readq / sizeof en_y3_l8_readq[0]), - .listening = "Editor: Did the mayor answer you? Journalist: I asked him whether the bridge was safe. He said he didn't know. I also asked how long the repairs would take. He told me that the firm hadn't decided. A resident asked me why the paper hadn't printed a map. I said we would print one tomorrow.", - .listenq = en_y3_l8_listenq, - .listen_hints = en_y3_l8_listenq_hints, - .n_listen = (int)(sizeof en_y3_l8_listenq / sizeof en_y3_l8_listenq[0]), - .write_prompt = "In at least 40 words, give one reason for repairing things and one objection. Use because and however.", - .write_model = "Repairing things matters because a kettle can work for years after a small fix. However, some people do not have the tools or the time, so a café where volunteers help is a fair idea. I believe every town should have one quiet room for broken objects. It is slower than shopping, but it is kinder.", - .write_keys = "because|however", - .write_min = 40, - .quiz = en_y3_l8_quiz, - .quiz_hints = en_y3_l8_quiz_hints, - .n_quiz = (int)(sizeof en_y3_l8_quiz / sizeof en_y3_l8_quiz[0]), - } - }, - { - { - .slides = en_y4_l1_slides, - .n_slides = (int)(sizeof en_y4_l1_slides / sizeof en_y4_l1_slides[0]), - .gaps = en_y4_l1_gaps, - .n_gaps = (int)(sizeof en_y4_l1_gaps / sizeof en_y4_l1_gaps[0]), - .quiz = en_y4_l1_quiz, - .quiz_hints = en_y4_l1_quiz_hints, - .n_quiz = (int)(sizeof en_y4_l1_quiz / sizeof en_y4_l1_quiz[0]), - }, - { - .slides = en_y4_l2_slides, - .n_slides = (int)(sizeof en_y4_l2_slides / sizeof en_y4_l2_slides[0]), - .write_prompt = "Write a formal email of at least 55 words to a railway company. Complain about a delay. Start with Dear, use would, and end with sincerely or faithfully.", - .write_model = "Dear Sir or Madam, I am writing to complain about the night train to Berlin on 3 May. It arrived ninety minutes late, so I missed a morning interview. I would be grateful if you could explain the delay and offer a refund. I have attached my ticket. Please reply to this address. Yours faithfully, Tereza Malá.", - .write_keys = "dear|would|faithfully", - .write_min = 55, - .quiz = en_y4_l2_quiz, - .quiz_hints = en_y4_l2_quiz_hints, - .n_quiz = (int)(sizeof en_y4_l2_quiz / sizeof en_y4_l2_quiz[0]), - }, - { - .slides = en_y4_l3_slides, - .n_slides = (int)(sizeof en_y4_l3_slides / sizeof en_y4_l3_slides[0]), - .reading = "When the night train from Prague to Berlin returned last spring, stations filled with people who prefer a bed to a boarding gate. A single ticket is often more expensive than a flight, which surprises anyone who thinks trains are always the cheap choice. Still, passengers say they arrive calmer. They can read, talk and avoid the bright shops of an airport. Critics point out that a delay of two hours is common and that the cabins are small. The railway has promised that new carriages will be added if demand stays high. A student I spoke to had taken the train three times. She said she would fly only if she missed the evening departure. For her, the journey is part of the trip, not a problem to be deleted.", - .readq = en_y4_l3_readq, - .read_hints = en_y4_l3_readq_hints, - .n_read = (int)(sizeof en_y4_l3_readq / sizeof en_y4_l3_readq[0]), - }, - { - .slides = en_y4_l4_slides, - .n_slides = (int)(sizeof en_y4_l4_slides / sizeof en_y4_l4_slides[0]), - .listening = "Interviewer: Why did you apply to the summer camp in Wales? Hana: I have worked with children for two years, and I wanted a job where English is the only language. Interviewer: What would you do if a child refused to join an activity? Hana: I wouldn't force them. I would ask why, and I might offer a quieter task. Interviewer: Have you ever dealt with an emergency? Hana: Yes. Last August a boy cut his foot. I cleaned the cut and called the nurse. I didn't give him any medicine. Interviewer: The camp is rainy. Is that a problem? Hana: Not really. I have already bought boots. I look forward to the hills, although I know the work will be tiring.", - .listenq = en_y4_l4_listenq, - .listen_hints = en_y4_l4_listenq_hints, - .n_listen = (int)(sizeof en_y4_l4_listenq / sizeof en_y4_l4_listenq[0]), - }, - { - .slides = en_y4_l5_slides, - .n_slides = (int)(sizeof en_y4_l5_slides / sizeof en_y4_l5_slides[0]), - .write_prompt = "Write an opinion of at least 60 words: should students have a gap year before university? Use believe, although and in conclusion.", - .write_model = "I believe a gap year can help, but only when it has a plan. Although some students waste the time, others work, travel or look after a relative and return calmer. A year in a job also shows whether a degree is really necessary. On the other hand, a long break can make it harder to study again. In conclusion, a gap year is useful if the person can explain what they will do with it.", - .write_keys = "believe|although|conclusion", - .write_min = 60, - .quiz = en_y4_l5_quiz, - .quiz_hints = en_y4_l5_quiz_hints, - .n_quiz = (int)(sizeof en_y4_l5_quiz / sizeof en_y4_l5_quiz[0]), - }, - { - .slides = en_y4_l6_slides, - .n_slides = (int)(sizeof en_y4_l6_slides / sizeof en_y4_l6_slides[0]), - .gaps = en_y4_l6_gaps, - .n_gaps = (int)(sizeof en_y4_l6_gaps / sizeof en_y4_l6_gaps[0]), - .quiz = en_y4_l6_quiz, - .quiz_hints = en_y4_l6_quiz_hints, - .n_quiz = (int)(sizeof en_y4_l6_quiz / sizeof en_y4_l6_quiz[0]), - }, - { - .slides = en_y4_l7_slides, - .n_slides = (int)(sizeof en_y4_l7_slides / sizeof en_y4_l7_slides[0]), - .gaps = en_y4_l7_gaps, - .n_gaps = (int)(sizeof en_y4_l7_gaps / sizeof en_y4_l7_gaps[0]), - .quiz = en_y4_l7_quiz, - .quiz_hints = en_y4_l7_quiz_hints, - .n_quiz = (int)(sizeof en_y4_l7_quiz / sizeof en_y4_l7_quiz[0]), - }, - { - .slides = en_y4_l8_slides, - .n_slides = (int)(sizeof en_y4_l8_slides / sizeof en_y4_l8_slides[0]), - .reading = "The town library now lends tools as well as books. Hammers, sewing machines and a cake tin can be borrowed for a week. The idea came from a librarian who was tired of people buying things they would use once. She said the workshop had been visited by more teenagers than the reading room. Critics argue that a library should stay quiet. She replies that a library should be useful. If the experiment works, other branches will copy it. Users have to return each object clean, and they must not lend it to anyone else.", - .readq = en_y4_l8_readq, - .read_hints = en_y4_l8_readq_hints, - .n_read = (int)(sizeof en_y4_l8_readq / sizeof en_y4_l8_readq[0]), - .listening = "Welcome to the night-train podcast. The 22:40 to Berlin has been delayed by forty minutes because a tree is on the line near Ústí. Passengers who already have a seat can wait in carriage four, where tea is being served. If you have not checked in, please do it on your phone. We would be grateful if you kept the corridor clear. The delay might be shorter. We will know more at ten.", - .listenq = en_y4_l8_listenq, - .listen_hints = en_y4_l8_listenq_hints, - .n_listen = (int)(sizeof en_y4_l8_listenq / sizeof en_y4_l8_listenq[0]), - .write_prompt = "Write at least 45 words to a friend. Invite them to borrow something from a library of things. Use because and if.", - .write_model = "Hi Adam, the library now lends tools, and I think you would like it because you always need a drill for one afternoon. If you come on Saturday, I will show you how it works. You have to bring your card and return everything clean. We could borrow a cake tin and bake something after. Let me know if you are free.", - .write_keys = "because|if", - .write_min = 45, - .quiz = en_y4_l8_quiz, - .quiz_hints = en_y4_l8_quiz_hints, - .n_quiz = (int)(sizeof en_y4_l8_quiz / sizeof en_y4_l8_quiz[0]), - } - }, -}; - diff --git a/src/exercise_common.c b/src/exercise_common.c deleted file mode 100644 index 1e59e3e..0000000 --- a/src/exercise_common.c +++ /dev/null @@ -1,857 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Exercise page shell */ -/* ------------------------------------------------------------------ */ - -/* Exercise text would otherwise run the full width of a maximised window, - * which is tiring to read. Keep the body at a comfortable measure and centre - * it once there is room to spare; below that it still fills the page. */ -#define EX_BODY_MAX_WIDTH 880 - -static void ex_body_clamp(GtkAdjustment *adj, GParamSpec *ps, gpointer data) { - GtkWidget *body = data; - double avail = gtk_adjustment_get_page_size(adj); - - (void)ps; - if (avail < 1.0) - return; - if (avail < (double)EX_BODY_MAX_WIDTH) { - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_size_request(body, -1, -1); - } else { - gtk_widget_set_halign(body, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(body, EX_BODY_MAX_WIDTH, -1); - } -} - -GtkWidget *ex_page_shell(const char *back_target, const char *title, - const char *subtitle, const char *btn_label, - GtkWidget **body_out, GtkWidget **feedback_out, - GtkWidget **btn_out) { - GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *bottom; - GtkWidget *feedback; - GtkWidget *btn; - - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_target, title, subtitle)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_widget_set_margin_bottom(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_vexpand(body, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - g_signal_connect(gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(scroll)), - "notify::page-size", G_CALLBACK(ex_body_clamp), body); - *body_out = body; - - bottom = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); - gtk_widget_set_margin_top(bottom, 4); - gtk_box_append(GTK_BOX(page), bottom); - - feedback = gtk_label_new(""); - gtk_widget_set_halign(feedback, GTK_ALIGN_START); - gtk_widget_set_valign(feedback, GTK_ALIGN_CENTER); - gtk_widget_set_hexpand(feedback, TRUE); - gtk_box_append(GTK_BOX(bottom), feedback); - *feedback_out = feedback; - - btn = gtk_button_new(); - i18n_bind(btn, btn_label, 1); - gtk_widget_add_css_class(btn, "btn-primary"); - gtk_widget_set_valign(btn, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(bottom), btn); - *btn_out = btn; - - return page; -} - -/* ------------------------------------------------------------------ */ -/* Word-selection (combo box) exercise */ -/* ------------------------------------------------------------------ */ - - -/* Build a hidden translation label ("meaning") appended under an item. */ -GtkWidget *meaning_add(GtkWidget *body, const char *text) { - GtkWidget *lbl = gtk_label_new(NULL); - - i18n_bind(lbl, text, 0); - gtk_label_set_xalign(GTK_LABEL(lbl), 0.0); - gtk_widget_set_halign(lbl, GTK_ALIGN_START); - gtk_widget_add_css_class(lbl, "meaning"); - gtk_label_set_wrap(GTK_LABEL(lbl), TRUE); - gtk_widget_set_visible(lbl, FALSE); - gtk_widget_set_margin_top(lbl, 2); - gtk_widget_set_margin_bottom(lbl, 2); - gtk_widget_set_margin_start(lbl, 8); - gtk_box_append(GTK_BOX(body), lbl); - return lbl; -} - -GtkWidget *mcq_option_toggle(const char *text, int index, - GtkToggleButton **group_first) { - GtkWidget *tb; - GtkWidget *lab; - char *labeled; - - labeled = g_strdup_printf("%c %s", 'A' + index, text); - tb = gtk_toggle_button_new(); - lab = gtk_label_new(labeled); - g_free(labeled); - - gtk_label_set_wrap(GTK_LABEL(lab), TRUE); - gtk_label_set_wrap_mode(GTK_LABEL(lab), PANGO_WRAP_WORD_CHAR); - gtk_label_set_xalign(GTK_LABEL(lab), 0.0); - gtk_widget_set_halign(lab, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(lab, TRUE); - gtk_button_set_child(GTK_BUTTON(tb), lab); - - gtk_widget_add_css_class(tb, "pill"); - gtk_widget_add_css_class(tb, "quiz-pill"); - gtk_widget_set_hexpand(tb, TRUE); - gtk_widget_set_halign(tb, GTK_ALIGN_FILL); - - gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(tb), *group_first); - if (!*group_first) - *group_first = GTK_TOGGLE_BUTTON(tb); - - return tb; -} - -GtkWidget *mcq_append_question(GtkWidget *parent, int num, const ChoiceQ *q, - GtkToggleButton **out_toggles) { - GtkWidget *card; - GtkWidget *prompt; - GtkWidget *opts; - GtkToggleButton *first = NULL; - char *qtext; - int o; - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_widget_add_css_class(card, "quiz-card"); - gtk_widget_set_hexpand(card, TRUE); - gtk_box_append(GTK_BOX(parent), card); - - qtext = g_strdup_printf("%d.) %s", num, q->prompt); - prompt = gtk_label_new(qtext); - g_free(qtext); - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_label_set_xalign(GTK_LABEL(prompt), 0.0); - gtk_widget_add_css_class(prompt, "quiz-q"); - gtk_box_append(GTK_BOX(card), prompt); - - opts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - gtk_widget_add_css_class(opts, "quiz-options"); - gtk_box_append(GTK_BOX(card), opts); - - for (o = 0; o < q->n_options; o++) { - GtkWidget *tb = mcq_option_toggle(q->options[o], o, &first); - - gtk_box_append(GTK_BOX(opts), tb); - out_toggles[o] = GTK_TOGGLE_BUTTON(tb); - } - - return card; -} - -/* A hidden green label that shows the model German sentence after Check. */ -GtkWidget *model_answer_add(GtkWidget *body, const char *german) { - GtkWidget *lbl = gtk_label_new(german); - - gtk_widget_set_halign(lbl, GTK_ALIGN_START); - gtk_label_set_xalign(GTK_LABEL(lbl), 0.0); - gtk_label_set_wrap(GTK_LABEL(lbl), TRUE); - gtk_widget_set_margin_top(lbl, 2); - gtk_widget_set_margin_bottom(lbl, 2); - gtk_widget_set_margin_start(lbl, 8); - gtk_widget_add_css_class(lbl, "u3-answer"); - gtk_widget_set_visible(lbl, FALSE); - gtk_box_append(GTK_BOX(body), lbl); - return lbl; -} - -void meaning_reveal_all(GtkWidget **labels, int n) { - for (int i = 0; i < n; i++) - if (labels[i]) - gtk_widget_set_visible(labels[i], TRUE); -} - -ComboListCtx *combo_list_ctx_new(UnitCtx *unit, int ex_num, - GtkWidget *feedback) { - ComboListCtx *ctx = g_new0(ComboListCtx, 1); - ctx->combos = g_array_new(FALSE, FALSE, sizeof(GtkComboBox *)); - ctx->answers = g_array_new(FALSE, FALSE, sizeof(const char *)); - ctx->trans = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - ctx->models = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - return ctx; -} - -void combo_list_add(ComboListCtx *ctx, GtkWidget *combo, const char *ans) { - g_array_append_val(ctx->combos, combo); - g_array_append_val(ctx->answers, ans); -} - -void combo_list_add_trans(ComboListCtx *ctx, GtkWidget *label) { - g_array_append_val(ctx->trans, label); -} - -GtkWidget *make_word_combo(const char **words, int n) { - GtkWidget *combo = gtk_combo_box_text_new(); - int *order = g_new0(int, n); - - for (int i = 0; i < n; i++) - order[i] = i; - shuffle_indices(order, n); - for (int i = 0; i < n; i++) - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(combo), NULL, - words[order[i]]); - gtk_combo_box_set_active(GTK_COMBO_BOX(combo), -1); - g_free(order); - return combo; -} - -gboolean answer_accepts(const char *sel_norm, const char *ans) { - gchar **parts = g_strsplit(ans, "|", -1); - gboolean ok = FALSE; - - for (int i = 0; parts[i] != NULL; i++) { - gchar *a = normalize_answer(parts[i]); - if (g_strcmp0(sel_norm, a) == 0) { - ok = TRUE; - g_free(a); - break; - } - g_free(a); - } - - g_strfreev(parts); - return ok; -} - -/* True when the typed answer matches the beginning of an accepted answer but - * is missing one or more trailing words (e.g. "jmenovat" for "jmenovat se"). - * Used to warn about an incomplete answer before counting it wrong. */ -gboolean answer_is_incomplete(const char *sel_norm, const char *ans) { - gchar **parts = g_strsplit(ans, "|", -1); - gboolean incomplete = FALSE; - - for (int i = 0; parts[i] != NULL && !incomplete; i++) { - gchar *a = normalize_answer(parts[i]); - gchar **sel_w = g_strsplit(sel_norm, " ", -1); - gchar **ans_w = g_strsplit(a, " ", -1); - int nsel = g_strv_length(sel_w); - int nans = g_strv_length(ans_w); - int k; - - if (sel_norm[0] && nsel > 0 && nsel < nans) { - incomplete = TRUE; - for (k = 0; k < nsel; k++) { - if (g_strcmp0(sel_w[k], ans_w[k]) != 0) { - incomplete = FALSE; - break; - } - } - } - g_strfreev(sel_w); - g_strfreev(ans_w); - g_free(a); - } - - g_strfreev(parts); - return incomplete; -} - -void combo_list_check(GtkButton *button, gpointer data) { - ComboListCtx *ctx = data; - guint total = ctx->combos->len; - guint ok = 0; - - (void)button; - - for (guint i = 0; i < total; i++) { - GtkComboBox *combo = g_array_index(ctx->combos, GtkComboBox *, i); - const char *ans = g_array_index(ctx->answers, const char *, i); - gchar *sel = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo)); - gboolean good = FALSE; - - if (sel) { - gchar *t = normalize_answer(sel); - good = answer_accepts(t, ans); - g_free(t); - g_free(sel); - } - answer_mark(GTK_WIDGET(combo), good); - if (good) - ok++; - } - - if (ctx->trans->len > 0) { - for (guint i = 0; i < ctx->trans->len; i++) { - GtkWidget *lbl = g_array_index(ctx->trans, GtkWidget *, i); - if (lbl) - gtk_widget_set_visible(lbl, TRUE); - } - } - - if (ctx->models->len > 0) { - for (guint i = 0; i < ctx->models->len; i++) { - GtkWidget *lbl = g_array_index(ctx->models, GtkWidget *, i); - if (lbl) - gtk_widget_set_visible(lbl, TRUE); - } - } - - if (ok == total) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - -/* ------------------------------------------------------------------ */ -/* Word-arrangement (chips) exercise */ -/* ------------------------------------------------------------------ */ - - - -void sent_rebuild(SentBuilder *sb) { - for (int i = 0; i < sb->n_words; i++) { - GtkWidget *parent = gtk_widget_get_parent(sb->chips[i]); - if (parent != NULL && GTK_IS_FLOW_BOX_CHILD(parent)) - gtk_flow_box_child_set_child(GTK_FLOW_BOX_CHILD(parent), NULL); - } - - flow_clear(GTK_FLOW_BOX(sb->pool)); - flow_clear(GTK_FLOW_BOX(sb->target)); - - for (int i = 0; i < sb->placed_count; i++) - gtk_flow_box_insert(GTK_FLOW_BOX(sb->target), - sb->chips[sb->placed[i]], -1); - - for (int i = 0; i < sb->n_words; i++) { - int w = sb->pool_order[i]; - gboolean in_target = FALSE; - for (int j = 0; j < sb->placed_count; j++) { - if (sb->placed[j] == w) { - in_target = TRUE; - break; - } - } - if (!in_target) - gtk_flow_box_insert(GTK_FLOW_BOX(sb->pool), sb->chips[w], -1); - } -} - - -GdkContentProvider *asm_drag_prepare(GtkDragSource *source, - double x, double y, - gpointer data) { - ChipRef *ref = data; - (void)source; - (void)x; - (void)y; - return gdk_content_provider_new_typed(G_TYPE_INT, ref->idx); -} - -gboolean asm_rebuild_idle(gpointer data) { - sent_rebuild(data); - return G_SOURCE_REMOVE; -} - -void asm_drag_end(GtkDragSource *source, GdkDrag *drag, - gboolean delete_data, gpointer data) { - ChipRef *ref = data; - (void)source; - (void)drag; - (void)delete_data; - g_idle_add(asm_rebuild_idle, ref->sb); -} - -gboolean asm_drop_to_sentence(GtkDropTarget *target, const GValue *value, - double x, double y, gpointer data) { - SentBuilder *sb = data; - int idx; - int pos = -1; - - (void)target; - (void)x; - (void)y; - - if (!G_VALUE_HOLDS_INT(value)) - return FALSE; - - idx = g_value_get_int(value); - for (int i = 0; i < sb->placed_count; i++) { - if (sb->placed[i] == idx) { - pos = i; - break; - } - } - if (pos >= 0) { - for (int i = pos; i < sb->placed_count - 1; i++) - sb->placed[i] = sb->placed[i + 1]; - sb->placed_count--; - } - sb->placed[sb->placed_count++] = idx; - return TRUE; -} - -gboolean asm_drop_to_pool(GtkDropTarget *target, const GValue *value, - double x, double y, gpointer data) { - SentBuilder *sb = data; - int idx; - int pos = -1; - - (void)target; - (void)x; - (void)y; - - if (!G_VALUE_HOLDS_INT(value)) - return FALSE; - - idx = g_value_get_int(value); - for (int i = 0; i < sb->placed_count; i++) { - if (sb->placed[i] == idx) { - pos = i; - break; - } - } - if (pos < 0) - return FALSE; - - for (int i = pos; i < sb->placed_count - 1; i++) - sb->placed[i] = sb->placed[i + 1]; - sb->placed_count--; - return TRUE; -} - -/* ------------------------------------------------------------------ */ -/* Click-to-move with a fly ("glide") animation */ -/* ------------------------------------------------------------------ */ - - -void asm_finish_fly(FlyCtx *fc) { - gtk_widget_remove_css_class(fc->chip, "ghost-host"); - gtk_fixed_remove(GTK_FIXED(fc->stage), fc->ghost); - if (fc->flying) - *fc->flying = FALSE; - g_free(fc); -} - -gboolean asm_fly_tick(gpointer data) { - FlyCtx *fc = data; - gint64 now = g_get_monotonic_time() / 1000; - - if (fc->t0 < 0) { - double nx = 0.0, ny = 0.0; - gboolean ok; - - fc->wait++; - ok = gtk_widget_translate_coordinates(fc->chip, fc->stage, - 0, 0, &nx, &ny); - if (fc->wait < 2) - return G_SOURCE_CONTINUE; - - if (ok && fc->wait < 14 && - fabs(nx - fc->sx) + fabs(ny - fc->sy) < 0.5) - return G_SOURCE_CONTINUE; /* still waiting for relayout */ - - if (ok) { - fc->tx = nx; - fc->ty = ny; - } else { - fc->tx = fc->sx; - fc->ty = fc->sy; - } - fc->t0 = now; - return G_SOURCE_CONTINUE; - } - - { - double t = (double)(now - fc->t0) / 240.0; - double e, x, y; - - if (t > 1.0) - t = 1.0; - e = 1.0 - pow(1.0 - t, 3.0); /* ease-out cubic */ - x = fc->sx + (fc->tx - fc->sx) * e; - y = fc->sy + (fc->ty - fc->sy) * e; - gtk_fixed_move(GTK_FIXED(fc->stage), fc->ghost, (int)x, (int)y); - - if (t >= 1.0) { - asm_finish_fly(fc); - return G_SOURCE_REMOVE; - } - } - return G_SOURCE_CONTINUE; -} - -/* Start a fly animation: hide `chip` in place and animate a ghost from - * (sx, sy) to the chip's new location. */ -void asm_begin_fly(GtkWidget *chip, GtkWidget *stage, - gboolean *flying, double sx, double sy) { - GtkWidget *child = gtk_button_get_child(GTK_BUTTON(chip)); - const char *txt = (child && GTK_IS_LABEL(child)) - ? gtk_label_get_text(GTK_LABEL(child)) : NULL; - GtkWidget *ghost = gtk_button_new_with_label(txt ? txt : ""); - FlyCtx *fc; - - gtk_widget_add_css_class(ghost, "chip"); - gtk_widget_set_sensitive(ghost, FALSE); - gtk_widget_set_can_focus(ghost, FALSE); - gtk_fixed_put(GTK_FIXED(stage), ghost, (int)sx, (int)sy); - - fc = g_new0(FlyCtx, 1); - fc->chip = chip; - fc->ghost = ghost; - fc->stage = stage; - fc->flying = flying; - fc->sx = sx; - fc->sy = sy; - fc->t0 = -1; - - if (flying) - *flying = TRUE; - gtk_widget_add_css_class(chip, "ghost-host"); - - g_timeout_add(16, asm_fly_tick, fc); -} - -void asm_move_by_click(GtkButton *button, gpointer data) { - ChipRef *ref = data; - SentBuilder *sb = ref->sb; - int idx = ref->idx; - int pos = -1; - double sx = 0.0, sy = 0.0; - GtkWidget *chip = GTK_WIDGET(button); - - (void)button; - - if (sb->flying) - return; - - for (int i = 0; i < sb->placed_count; i++) { - if (sb->placed[i] == idx) { - pos = i; - break; - } - } - - if (sb->stage && - gtk_widget_translate_coordinates(chip, sb->stage, 0, 0, &sx, &sy)) { - if (pos >= 0) { - for (int i = pos; i < sb->placed_count - 1; i++) - sb->placed[i] = sb->placed[i + 1]; - sb->placed_count--; - } else { - sb->placed[sb->placed_count++] = idx; - } - - sent_rebuild(sb); - asm_begin_fly(chip, sb->stage, &sb->flying, sx, sy); - } else { - /* No usable animation layer yet – just move instantly. */ - if (pos >= 0) { - for (int i = pos; i < sb->placed_count - 1; i++) - sb->placed[i] = sb->placed[i + 1]; - sb->placed_count--; - } else { - sb->placed[sb->placed_count++] = idx; - } - sent_rebuild(sb); - } -} - - -void assembly_check(GtkButton *button, gpointer data) { - AsmCtx *ctx = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - SentBuilder *sb = ctx->sbs[i]; - gboolean good = (sb->placed_count == sb->n_words); - if (good) { - for (int j = 0; j < sb->placed_count; j++) { - if (sb->placed[j] != j) { - good = FALSE; - break; - } - } - } - if (good) { - ok++; - gtk_widget_remove_css_class(sb->group, "wrong"); - gtk_widget_add_css_class(sb->group, "ok"); - } else { - gtk_widget_remove_css_class(sb->group, "ok"); - gtk_widget_add_css_class(sb->group, "wrong"); - } - } - - for (int i = 0; i < ctx->n; i++) { - if (ctx->sbs[i]->trans) - gtk_widget_set_visible(ctx->sbs[i]->trans, TRUE); - } - - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_sentences")); - } -} - -GtkWidget *build_assembly(UnitCtx *unit, const char *title, - const char *subtitle, int ex_num, - const AssemblyItem *items, - const char **meanings, int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, subtitle, "check", - &body, &feedback, &check); - AsmCtx *ctx = g_new0(AsmCtx, 1); - - ctx->sbs = g_new0(SentBuilder *, n); - ctx->n = n; - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - - for (int s = 0; s < n; s++) { - const AssemblyItem *item = &items[s]; - SentBuilder *sb = g_new0(SentBuilder, 1); - GtkWidget *holder; - GtkWidget *group; - GtkWidget *target; - GtkWidget *pool; - GtkWidget *stage; - - sb->n_words = item->n; - ctx->sbs[s] = sb; - - if (item->prompt) { - GtkWidget *prompt = gtk_label_new(item->prompt); - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_widget_add_css_class(prompt, "chain"); - gtk_box_append(GTK_BOX(body), prompt); - } - - holder = gtk_overlay_new(); - gtk_widget_set_hexpand(holder, TRUE); - - group = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - gtk_widget_add_css_class(group, "sent-group"); - sb->group = group; - gtk_overlay_set_child(GTK_OVERLAY(holder), group); - - target = gtk_flow_box_new(); - gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(target), GTK_SELECTION_NONE); - gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(target), 2); - gtk_widget_set_size_request(target, -1, 44); - sb->target = target; - gtk_box_append(GTK_BOX(group), target); - - pool = gtk_flow_box_new(); - gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(pool), GTK_SELECTION_NONE); - gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(pool), 2); - gtk_widget_set_size_request(pool, -1, 44); - sb->pool = pool; - gtk_box_append(GTK_BOX(group), pool); - - stage = gtk_fixed_new(); - gtk_widget_set_halign(stage, GTK_ALIGN_FILL); - gtk_widget_set_valign(stage, GTK_ALIGN_FILL); - gtk_widget_set_can_target(stage, FALSE); - gtk_overlay_add_overlay(GTK_OVERLAY(holder), stage); - sb->stage = stage; - - { - GtkDropTarget *dt = gtk_drop_target_new(G_TYPE_INT, GDK_ACTION_COPY); - GtkDropTarget *dp = gtk_drop_target_new(G_TYPE_INT, GDK_ACTION_COPY); - g_signal_connect(dt, "drop", G_CALLBACK(asm_drop_to_sentence), sb); - gtk_widget_add_controller(target, GTK_EVENT_CONTROLLER(dt)); - g_signal_connect(dp, "drop", G_CALLBACK(asm_drop_to_pool), sb); - gtk_widget_add_controller(pool, GTK_EVENT_CONTROLLER(dp)); - } - - for (int w = 0; w < item->n; w++) { - GtkWidget *chip = gtk_button_new_with_label(item->words[w]); - GtkDragSource *src = gtk_drag_source_new(); - ChipRef *ref = g_new(ChipRef, 1); - gtk_widget_add_css_class(chip, "chip"); - g_object_ref(chip); - sb->chips[w] = chip; - ref->sb = sb; - ref->idx = w; - gtk_drag_source_set_actions(src, GDK_ACTION_COPY); - g_signal_connect(src, "prepare", G_CALLBACK(asm_drag_prepare), ref); - g_signal_connect(src, "drag-end", G_CALLBACK(asm_drag_end), ref); - g_signal_connect(chip, "clicked", G_CALLBACK(asm_move_by_click), ref); - gtk_widget_add_controller(chip, GTK_EVENT_CONTROLLER(src)); - } - - { - for (int w = 0; w < item->n; w++) - sb->pool_order[w] = w; - shuffle_indices(sb->pool_order, item->n); - for (int w = 0; w < item->n; w++) - gtk_flow_box_insert(GTK_FLOW_BOX(pool), - sb->chips[sb->pool_order[w]], -1); - } - - gtk_box_append(GTK_BOX(body), holder); - - if (meanings[s]) - sb->trans = meaning_add(body, meanings[s]); - } - - g_signal_connect(check, "clicked", G_CALLBACK(assembly_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 1: Dialog (word selection) */ -/* ------------------------------------------------------------------ */ - - - -const DialogRow ex1_d1[] = { - {"A:", "Hallo! Ich ", "bin|heiße", " Anna."}, - {"B:", "Hallo! Ich ", "bin|heiße", " Peter."}, - {"A:", "Woher ", "kommst", " du?"}, - {"B:", "Ich komme ", "aus", " Tschechien."}, -}; - -const DialogRow ex1_d2[] = { - {"A:", "Guten ", "Morgen", "!"}, - {"B:", "Wie ", "geht", " es dir?"}, - {"A:", "Mir geht es gut, ", "danke", "."}, -}; - -const DialogRow ex1_d3[] = { - {"A:", "Ich muss gehen. Auf ", "Wiedersehen", "!"}, - {"B:", "", "Bis", " bald!"}, - {"A:", "", "Tschüss", "!"}, -}; - -const Dialogue ex1_dialogues[] = { - {"Sich vorstellen", ex1_d1, G_N_ELEMENTS(ex1_d1)}, - {"Begrüßung", ex1_d2, G_N_ELEMENTS(ex1_d2)}, - {"Verabschiedung", ex1_d3, G_N_ELEMENTS(ex1_d3)}, -}; - -const char *ex1_pool[] = { - "bin", "heiße", "kommst", "aus", "Morgen", - "geht", "danke", "Wiedersehen", "Bis", "Tschüss", -}; - -/* One Czech meaning per dialog line, in the same order as the rows. */ -const char *ex1_meaning[] = { - "Ahoj! Jmenuji se Anna.", - "Ahoj! Jmenuji se Petr.", - "Odkud jsi?", - "Pocházím z Česka.", - "Dobré ráno!", - "Jak se máš?", - "Mám se dobře, děkuji.", - "Musím jít. Na shledanou!", - "Brzy na viděnou!", - "Čau!", -}; - -GtkWidget *build_ex1(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Dialog", - "sub_dialog", - "check", &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 1, feedback); - int ri = 0; - - for (guint d = 0; d < G_N_ELEMENTS(ex1_dialogues); d++) { - const Dialogue *diag = &ex1_dialogues[d]; - GtkWidget *name = gtk_label_new(diag->name); - gtk_widget_set_halign(name, GTK_ALIGN_START); - gtk_widget_add_css_class(name, "ex-sub"); - gtk_widget_set_margin_top(name, d > 0 ? 10 : 0); - gtk_box_append(GTK_BOX(body), name); - - for (int r = 0; r < diag->n; r++) { - const DialogRow *row = &diag->rows[r]; - GtkWidget *line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *combo; - gtk_widget_set_halign(line, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), line); - - if (row->speaker && row->speaker[0]) { - GtkWidget *spk = gtk_label_new(row->speaker); - gtk_widget_add_css_class(spk, "dlg-speaker"); - gtk_widget_set_valign(spk, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(line), spk); - } - if (row->before && row->before[0]) { - GtkWidget *lb = gtk_label_new(row->before); - gtk_widget_set_valign(lb, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(lb, "ex-prompt"); - gtk_box_append(GTK_BOX(line), lb); - } - - combo = make_word_combo(ex1_pool, G_N_ELEMENTS(ex1_pool)); - gtk_widget_set_size_request(combo, 130, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(line), combo); - combo_list_add(ctx, combo, row->answer); - - if (row->after && row->after[0]) { - GtkWidget *la = gtk_label_new(row->after); - gtk_widget_set_valign(la, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(la, "ex-prompt"); - gtk_box_append(GTK_BOX(line), la); - } - - if (ri < (int)G_N_ELEMENTS(ex1_meaning)) - combo_list_add_trans(ctx, meaning_add(body, ex1_meaning[ri])); - ri++; - } - } - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 2: Sätze bilden (word arrangement) */ -/* ------------------------------------------------------------------ */ - -const AssemblyItem ex2_items[] = { - {NULL, {"Ich", "heiße", "Anna", "."}, 4}, - {NULL, {"Woher", "kommst", "du", "?"}, 4}, - {NULL, {"Ich", "komme", "aus", "Tschechien", "."}, 5}, - {NULL, {"Wie", "geht", "es", "dir", "?"}, 5}, -}; - -const char *ex2_meaning[] = { - "Jmenuji se Anna.", - "Odkud jsi?", - "Pocházím z Česka.", - "Jak se máš?", -}; diff --git a/src/exercise_u1.c b/src/exercise_u1.c deleted file mode 100644 index 6155710..0000000 --- a/src/exercise_u1.c +++ /dev/null @@ -1,1360 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Choice exercises (3 + 9) */ -/* ------------------------------------------------------------------ */ - - -const ChoiceQ ex3_questions[] = { - {"Welche Zahl ist „vierzehn“?", {"4", "14", "40"}, 3, 1}, - {"Welche Zahl ist „siebzehn“?", {"7", "17", "70"}, 3, 1}, - {"Welche Zahl ist „zwanzig“?", {"2", "12", "20"}, 3, 2}, - {"Welche Zahl ist „sechs“?", {"6", "16", "60"}, 3, 0}, -}; - -const char *ex3_meaning[] = { - "„vierzehn“ = čtrnáct (14)", - "„siebzehn“ = sedmnáct (17)", - "„zwanzig“ = dvacet (20)", - "„sechs“ = šest (6)", -}; - -const ChoiceQ ex9_questions[] = { - {"___ heißt du?", {"Wer", "Wie", "Wo"}, 3, 1}, - {"___ kommst du?", {"Woher", "Wie", "Wer"}, 3, 0}, - {"___ wohnst du?", {"Wo", "Wer", "Was"}, 3, 0}, - {"___ ist das?", {"Wer", "Wo", "Wie"}, 3, 0}, - {"___ alt bist du?", {"Wie", "Woher", "Was"}, 3, 0}, -}; - -const char *ex9_meaning[] = { - "Jak se jmenuješ?", - "Odkud jsi?", - "Kde bydlíš?", - "Kdo to je?", - "Kolik je ti let?", -}; - - -void choice_check(GtkButton *button, gpointer data) { - ChoiceCtx *ctx = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - int active = -1; - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class(GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class(GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - } - - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } - - meaning_reveal_all(ctx->trans, ctx->n); -} - -GtkWidget *build_choice(UnitCtx *unit, const char *title, - const char *subtitle, int ex_num, - const ChoiceQ *qs, const char **meanings, int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, subtitle, "check", - &body, &feedback, &check); - ChoiceCtx *ctx = g_new0(ChoiceCtx, 1); - int n_opts = qs[0].n_options; - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->trans = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - if (meanings[i]) - ctx->trans[i] = meaning_add(card, meanings[i]); - } - - g_signal_connect(check, "clicked", G_CALLBACK(choice_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 4: Freie Antwort */ -/* ------------------------------------------------------------------ */ - - -const FreeQ ex4_questions[] = { - {"Wie heißt du?", "Jak se jmenuješ?", - "Ich heiße Anna.", "Jmenuji se Anna."}, - {"Woher kommst du?", "Odkud pocházíš?", - "Ich komme aus Tschechien.", "Pocházím z Česka."}, - {"Wie alt bist du?", "Kolik je ti let?", - "Ich bin sechzehn Jahre alt.", "Je mi šestnáct let."}, - {"Wie geht es dir?", "Jak se máš?", - "Mir geht es gut, danke.", "Mám se dobře, děkuji."}, -}; - -void ex4_fill_sample(GtkWidget *label) { - const FreeQ *q = g_object_get_data(G_OBJECT(label), "fq"); - char *txt; - - if (!q) - return; - txt = g_strdup_printf(tr("sample_fmt"), tr(q->q_cs), q->sample, - tr(q->a_cs)); - gtk_label_set_text(GTK_LABEL(label), txt); - g_free(txt); -} - -void ex4_reveal(GtkButton *button, gpointer data) { - GtkWidget *sample = data; - (void)button; - ex4_fill_sample(sample); - gtk_widget_set_visible(sample, !gtk_widget_get_visible(sample)); -} - - -void ex4_finish(GtkButton *button, gpointer data) { - Ex4Ctx *ctx = data; - (void)button; - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - for (int i = 0; i < ctx->n; i++) { - ex4_fill_sample(ctx->samples[i]); - gtk_widget_set_visible(ctx->samples[i], TRUE); - } - mark_done(ctx->unit, ctx->ex_num); -} - -GtkWidget *build_free_answer(UnitCtx *unit, int ex_num, const char *title, - const char *subtitle, const char *tip_key, - const FreeQ *qs, int n) { - GtkWidget *body, *feedback, *check; - Ex4Ctx *ctx; - GtkWidget *page = ex_page_shell(unit->page, title, subtitle, "finish", - &body, &feedback, &check); - - ctx = g_new0(Ex4Ctx, 1); - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->n = n; - ctx->samples = g_new0(GtkWidget *, n); - - if (tip_key) { - GtkWidget *tip = gtk_label_new(NULL); - i18n_bind(tip, tip_key, 0); - gtk_widget_set_halign(tip, GTK_ALIGN_START); - gtk_widget_add_css_class(tip, "hint"); - gtk_box_append(GTK_BOX(body), tip); - } - - for (int i = 0; i < n; i++) { - const FreeQ *q = &qs[i]; - GtkWidget *ql = gtk_label_new(q->question); - GtkWidget *entry; - GtkWidget *reveal; - GtkWidget *sample; - - gtk_widget_set_halign(ql, GTK_ALIGN_START); - gtk_widget_add_css_class(ql, "ex-prompt"); - gtk_box_append(GTK_BOX(body), ql); - - entry = gtk_entry_new(); - i18n_bind(entry, "your_answer", 3); - gtk_box_append(GTK_BOX(body), entry); - - reveal = gtk_button_new(); - i18n_bind(reveal, "show_sample", 1); - gtk_widget_add_css_class(reveal, "pill"); - gtk_widget_set_halign(reveal, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), reveal); - - sample = gtk_label_new(NULL); - g_object_set_data(G_OBJECT(sample), "fq", (gpointer)q); - gtk_widget_set_halign(sample, GTK_ALIGN_START); - gtk_widget_add_css_class(sample, "hint"); - gtk_label_set_wrap(GTK_LABEL(sample), TRUE); - gtk_widget_set_visible(sample, FALSE); - gtk_box_append(GTK_BOX(body), sample); - ctx->samples[i] = sample; - - g_signal_connect(reveal, "clicked", G_CALLBACK(ex4_reveal), sample); - } - - g_signal_connect(check, "clicked", G_CALLBACK(ex4_finish), ctx); - return page; -} - -GtkWidget *build_ex4(UnitCtx *unit) { - return build_free_answer(unit, 4, "Freie Antwort", "sub_free", "tip_ss", - ex4_questions, - (int)G_N_ELEMENTS(ex4_questions)); -} - -/* ------------------------------------------------------------------ */ -/* Exercise 5: Zahlen (digits -> word) */ -/* ------------------------------------------------------------------ */ - - -const NumberQ ex5_data[] = { - {"14", "vierzehn"}, - {"17", "siebzehn"}, - {"20", "zwanzig"}, - {"6", "sechs"}, - {"13", "dreizehn"}, -}; - -const char *ex5_pool[] = { - "vierzehn", "siebzehn", "zwanzig", "sechs", "dreizehn", -}; - -const char *ex5_meaning[] = { - "čtrnáct", - "sedmnáct", - "dvacet", - "šest", - "třináct", -}; - -GtkWidget *build_ex5(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Zahlen", - "sub_zahlen", - "check", &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 5, feedback); - - for (guint i = 0; i < G_N_ELEMENTS(ex5_data); i++) { - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - GtkWidget *digits = gtk_label_new(ex5_data[i].digits); - GtkWidget *eq = gtk_label_new("="); - GtkWidget *combo; - - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_add_css_class(digits, "number-big"); - gtk_widget_set_valign(digits, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), digits); - - gtk_widget_set_valign(eq, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(eq, "ex-prompt"); - gtk_box_append(GTK_BOX(row), eq); - - combo = make_word_combo(ex5_pool, G_N_ELEMENTS(ex5_pool)); - gtk_widget_set_size_request(combo, 140, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), combo); - combo_list_add(ctx, combo, ex5_data[i].answer); - - gtk_box_append(GTK_BOX(body), row); - combo_list_add_trans(ctx, meaning_add(body, ex5_meaning[i])); - } - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 6: Wie viel? */ -/* ------------------------------------------------------------------ */ - - -const CountQ ex6_data[] = { - {"🍎", 2, "Äpfel", "zwei"}, - {"⭐", 5, "Sterne", "fünf"}, - {"🐱", 7, "Katzen", "sieben"}, - {"🌸", 9, "Blumen", "neun"}, - {"🚗", 3, "Autos", "drei"}, - {"📚", 11, "Bücher", "elf"}, - {"🕯️", 4, "Kerzen", "vier"}, - {"⚽", 8, "Bälle", "acht"}, - {"🐦", 6, "Vögel", "sechs"}, -}; - -const char *ex6_pool[] = { - "zwei", "fünf", "sieben", "neun", "drei", "elf", "vier", "acht", "sechs", -}; - -const char *ex6_meaning[] = { - "dvě jablka", - "pět hvězd", - "sedm koček", - "devět květin", - "tři auta", - "jedenáct knih", - "čtyři svíčky", - "osm míčů", - "šest ptáků", -}; - -GtkWidget *build_ex6(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Wie viel?", - "sub_wieviel", - "check", &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 6, feedback); - - for (guint i = 0; i < G_N_ELEMENTS(ex6_data); i++) { - const CountQ *q = &ex6_data[i]; - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - GString *em = g_string_new(NULL); - GtkWidget *icons; - GtkWidget *noun; - GtkWidget *combo; - - for (int c = 0; c < q->count; c++) { - if (c) - g_string_append_c(em, ' '); - g_string_append(em, q->emoji); - } - icons = gtk_label_new(em->str); - g_string_free(em, TRUE); - gtk_widget_set_valign(icons, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), icons); - - noun = gtk_label_new(q->noun); - gtk_widget_set_valign(noun, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(noun, "ex-prompt"); - gtk_box_append(GTK_BOX(row), noun); - - combo = make_word_combo(ex6_pool, G_N_ELEMENTS(ex6_pool)); - gtk_widget_set_size_request(combo, 130, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), combo); - combo_list_add(ctx, combo, q->answer); - - gtk_box_append(GTK_BOX(body), row); - combo_list_add_trans(ctx, meaning_add(body, ex6_meaning[i])); - } - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 7: Zahlenreihe */ -/* ------------------------------------------------------------------ */ - - -const SeqQ ex7_data[] = { - {"sechs, sieben, ", ", neun", "acht"}, - {"zwölf, dreizehn, ", ", fünfzehn", "vierzehn"}, - {"achtzehn, neunzehn, ", ", einundzwanzig", "zwanzig"}, - {"vier, fünf, ", ", sieben", "sechs"}, - {"zehn, elf, ", ", dreizehn", "zwölf"}, -}; - -const char *ex7_pool[] = { - "acht", "vierzehn", "zwanzig", "sechs", "zwölf", -}; - -const char *ex7_meaning[] = { - "šest, sedm, osm, devět", - "dvanáct, třináct, čtrnáct, patnáct", - "osmnáct, devatenáct, dvacet, dvacet jedna", - "čtyři, pět, šest, sedm", - "deset, jedenáct, dvanáct, třináct", -}; - -GtkWidget *build_ex7(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Zahlenreihe", - "sub_reihe", - "check", &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 7, feedback); - - for (guint i = 0; i < G_N_ELEMENTS(ex7_data); i++) { - const SeqQ *q = &ex7_data[i]; - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *before = gtk_label_new(q->before); - GtkWidget *after = gtk_label_new(q->after); - GtkWidget *combo; - - gtk_widget_set_halign(row, GTK_ALIGN_START); - - gtk_widget_set_valign(before, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(before, "ex-prompt"); - gtk_box_append(GTK_BOX(row), before); - - combo = make_word_combo(ex7_pool, G_N_ELEMENTS(ex7_pool)); - gtk_widget_set_size_request(combo, 140, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), combo); - combo_list_add(ctx, combo, q->answer); - - gtk_widget_set_valign(after, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(after, "ex-prompt"); - gtk_box_append(GTK_BOX(row), after); - - gtk_box_append(GTK_BOX(body), row); - - combo_list_add_trans(ctx, meaning_add(body, ex7_meaning[i])); - } - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 8: Verb einsetzen (word selection) */ -/* ------------------------------------------------------------------ */ - - -/* Complete German sentence for a before/after gap row (with any trailing - * "(…)" hint such as "(kommen)" removed) – shown after Check. */ -char *verbq_german(const char *before, const char *answer, - const char *after) { - GString *s; - const char *p; - gboolean inside = FALSE; - char *out; - - s = g_string_new(NULL); - if (before && before[0]) - g_string_append(s, before); - if (answer && answer[0]) - g_string_append(s, answer); - if (after && after[0]) - g_string_append(s, after); - - out = s->str; - s->str = NULL; - g_string_free(s, TRUE); - s = g_string_new(NULL); - for (p = out; *p; p++) { - if (*p == '(') { - inside = TRUE; - continue; - } - if (*p == ')') { - inside = FALSE; - continue; - } - if (!inside) - g_string_append_c(s, *p); - } - g_free(out); - - while (s->len > 0 && g_ascii_isspace(s->str[s->len - 1])) - g_string_truncate(s, s->len - 1); - if (s->len == 0) { - g_string_free(s, TRUE); - return NULL; - } - return g_string_free(s, FALSE); -} - -const VerbQ ex8_data[] = { - {"Ich ", " Peter.", "heiße"}, - {"Woher ", " du?", "kommst"}, - {"Ich ", " in Prag.", "wohne"}, - {"Wie alt ", " du?", "bist"}, - {"Ich ", " Fußball.", "spiele"}, - {"Was ", " du gern?", "machst"}, -}; - -const char *ex8_pool[] = { - "heißen", "kommen", "wohnen", "sein", "spielen", "machen", - "heiße", "kommst", "wohne", "bist", "spiele", "machst", -}; - -const char *ex8_meaning[] = { - "Jmenuji se Petr.", - "Odkud jsi?", - "Bydlím v Praze.", - "Kolik je ti let?", - "Hraji fotbal.", - "Co rád/a děláš?", -}; - -GtkWidget *build_ex8(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Verb einsetzen", - "sub_verb", - "check", &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 8, feedback); - - ctx->trans_upfront = TRUE; - ctx->reveal_german = TRUE; - - for (guint i = 0; i < G_N_ELEMENTS(ex8_data); i++) { - const VerbQ *q = &ex8_data[i]; - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *before = gtk_label_new(q->before); - GtkWidget *after = gtk_label_new(q->after); - GtkWidget *combo; - - gtk_widget_set_halign(row, GTK_ALIGN_START); - - gtk_widget_set_valign(before, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(before, "ex-prompt"); - gtk_box_append(GTK_BOX(row), before); - - combo = make_word_combo(ex8_pool, G_N_ELEMENTS(ex8_pool)); - gtk_widget_set_size_request(combo, 120, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), combo); - combo_list_add(ctx, combo, q->answer); - - gtk_widget_set_valign(after, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(after, "ex-prompt"); - gtk_box_append(GTK_BOX(row), after); - - gtk_box_append(GTK_BOX(body), row); - - { - GtkWidget *mean = meaning_add(body, ex8_meaning[i]); - GtkWidget *w; - char *sentence; - - gtk_widget_set_visible(mean, TRUE); - combo_list_add_trans(ctx, mean); - - sentence = verbq_german(q->before, q->answer, q->after); - if (sentence && sentence[0]) { - w = model_answer_add(body, sentence); - g_array_append_val(ctx->models, w); - } - g_free(sentence); - } - } - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 10: Wörter trennen (word arrangement) */ -/* ------------------------------------------------------------------ */ - -const AssemblyItem ex10_items[] = { - {"wiespätistes", {"wie", "spät", "ist", "es"}, 4}, - {"ichheißeanna", {"ich", "heiße", "anna"}, 3}, - {"woherkommstdu", {"woher", "kommst", "du"}, 3}, - {"aufwiedersehen", {"auf", "wiedersehen"}, 2}, - {"dankeschön", {"danke", "schön"}, 2}, -}; - -const char *ex10_meaning[] = { - "Kolik je hodin?", - "Jmenuji se Anna.", - "Odkud jsi?", - "Na shledanou.", - "Moc děkuji.", -}; - -/* ------------------------------------------------------------------ */ -/* Exercise 12: Was macht er/sie? */ -/* ------------------------------------------------------------------ */ - - -const VerbClueQ ex12_data[] = { - {"🏊", "Er ", " im See.", "schwimmt"}, - {"🎤", "Sie ", " ein Lied.", "singt"}, - {"🍳", "Er ", " Suppe.", "kocht"}, - {"📖", "Sie ", " ein Buch.", "liest"}, - {"🚗", "Er ", " Auto.", "fährt"}, - {"🎨", "Sie ", " ein Bild.", "malt"}, - {"⚽", "Er ", " Fußball.", "spielt"}, - {"🛏️", "Sie ", " .", "schläft"}, -}; - -const char *ex12_pool[] = { - "schwimmt", "singt", "kocht", "liest", "fährt", "malt", "spielt", "schläft", -}; - -const char *ex12_meaning[] = { - "Plave v jezeře.", - "Zpívá píseň.", - "Vaří polévku.", - "Čte knihu.", - "Řídí auto.", - "Maluje obraz.", - "Hraje fotbal.", - "Spí.", -}; - -GtkWidget *build_ex12(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Was macht er/sie?", - "sub_bild", - "check", &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 12, feedback); - - ctx->trans_upfront = TRUE; - ctx->reveal_german = TRUE; - - for (guint i = 0; i < G_N_ELEMENTS(ex12_data); i++) { - const VerbClueQ *q = &ex12_data[i]; - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *emoji = gtk_label_new(q->emoji); - GtkWidget *before = gtk_label_new(q->before); - GtkWidget *after = gtk_label_new(q->after); - GtkWidget *combo; - - gtk_widget_set_halign(row, GTK_ALIGN_START); - - gtk_widget_set_valign(emoji, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), emoji); - - gtk_widget_set_valign(before, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(before, "ex-prompt"); - gtk_box_append(GTK_BOX(row), before); - - combo = make_word_combo(ex12_pool, G_N_ELEMENTS(ex12_pool)); - gtk_widget_set_size_request(combo, 120, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), combo); - combo_list_add(ctx, combo, q->answer); - - gtk_widget_set_valign(after, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(after, "ex-prompt"); - gtk_box_append(GTK_BOX(row), after); - - gtk_box_append(GTK_BOX(body), row); - - { - GtkWidget *mean = meaning_add(body, ex12_meaning[i]); - GtkWidget *w; - char *sentence; - - gtk_widget_set_visible(mean, TRUE); - combo_list_add_trans(ctx, mean); - - sentence = verbq_german(q->before, q->answer, q->after); - if (sentence && sentence[0]) { - w = model_answer_add(body, sentence); - g_array_append_val(ctx->models, w); - } - g_free(sentence); - } - } - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Assign exercises (11 + 13) */ -/* ------------------------------------------------------------------ */ - - -const AssignItem ex11_items[] = { - {NULL, "Hallo", 0}, - {NULL, "Guten Morgen", 0}, - {NULL, "Guten Tag", 0}, - {NULL, "Guten Abend", 0}, - {NULL, "Grüß Gott", 0}, - {NULL, "Servus", 0}, - {NULL, "Tschüss", 1}, - {NULL, "Auf Wiedersehen", 1}, - {NULL, "Bis bald", 1}, - {NULL, "Bis morgen", 1}, - {NULL, "Gute Nacht", 1}, - {NULL, "Bis später", 1}, -}; - -const AssignItem ex13_items[] = { - {"🥨", "Brezel", 0}, - {"🌭", "Bratwurst", 0}, - {"🏰", "Brandenburger Tor", 0}, - {"🚗", "Volkswagen", 0}, - {"🎻", "Mozart", 1}, - {"🍰", "Sachertorte", 1}, - {"🥩", "Wiener Schnitzel", 1}, - {"🧀", "Käse", 2}, - {"⛰️", "Matterhorn", 2}, - {"🍫", "Schokolade", 2}, -}; - -const char *ex11_groups[] = {"Begrüßung", "Verabschiedung"}; -const char *ex13_groups[] = {"Deutschland (D)", "Österreich (A)", "Schweiz (CH)"}; - -const char *ex11_meaning[] = { - "Ahoj", - "Dobré ráno", - "Dobrý den", - "Dobrý večer", - "Dobrý den (Bavorsko, Rakousko)", - "Ahoj / Čau", - "Čau", - "Na shledanou", - "Brzy na viděnou", - "Do zítřka", - "Dobrou noc", - "Zatím / Na viděnou", -}; - -const char *ex13_meaning[] = { - "Preclík", - "Klobása", - "Braniborská brána", - "Značka aut", - "Rakouský skladatel", - "Čokoládový dort (Vídeň)", - "Vídeňský řízek", - "Sýr", - "Švýcarská hora", - "Čokoláda", -}; - - - -void assign_rebuild(AssignCtx *ac) { - for (int i = 0; i < ac->n_items; i++) { - GtkWidget *parent = gtk_widget_get_parent(ac->items[i]); - if (parent != NULL && GTK_IS_FLOW_BOX_CHILD(parent)) - gtk_flow_box_child_set_child(GTK_FLOW_BOX_CHILD(parent), NULL); - } - - flow_clear(GTK_FLOW_BOX(ac->pool)); - for (int g = 0; g < ac->n_groups; g++) - flow_clear(GTK_FLOW_BOX(ac->group_flow[g])); - - for (int i = 0; i < ac->n_items; i++) { - if (ac->current_group[i] < 0) - gtk_flow_box_insert(GTK_FLOW_BOX(ac->pool), ac->items[i], -1); - else - gtk_flow_box_insert(GTK_FLOW_BOX(ac->group_flow[ac->current_group[i]]), - ac->items[i], -1); - } -} - -void assign_chip_clicked(GtkButton *button, gpointer data) { - AssignChipRef *ref = data; - AssignCtx *ac = ref->ac; - int idx = ref->idx; - double sx = 0.0, sy = 0.0; - GtkWidget *chip = GTK_WIDGET(button); - - (void)button; - - if (ac->flying) - return; - - if (ac->stage && - gtk_widget_translate_coordinates(chip, ac->stage, 0, 0, &sx, &sy)) { - if (ac->current_group[idx] < 0) - ac->current_group[idx] = ac->active_group; - else - ac->current_group[idx] = -1; - - assign_rebuild(ac); - asm_begin_fly(chip, ac->stage, &ac->flying, sx, sy); - } else { - /* No usable animation layer yet – just move instantly. */ - if (ac->current_group[idx] < 0) - ac->current_group[idx] = ac->active_group; - else - ac->current_group[idx] = -1; - - assign_rebuild(ac); - } -} - -void assign_group_toggled(GtkToggleButton *button, gpointer data) { - AssignCtx *ac = data; - - if (!gtk_toggle_button_get_active(button)) - return; - - for (int g = 0; g < ac->n_groups; g++) { - if (GTK_TOGGLE_BUTTON(ac->group_btn[g]) == button) { - ac->active_group = g; - break; - } - } -} - -void assign_check(GtkButton *button, gpointer data) { - AssignCtx *ac = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ac->n_items; i++) - if (ac->current_group[i] == ac->items_data[i].correct_group) - ok++; - - if (ok == ac->n_items) { - set_feedback(ac->feedback, TRUE, tr("feedback_ok")); - mark_done(ac->unit, ac->ex_num); - } else { - set_feedback(ac->feedback, FALSE, tr("feedback_retry")); - } - - for (int i = 0; i < ac->n_items; i++) - if (ac->trans[i]) - gtk_widget_set_visible(ac->trans[i], TRUE); -} - -GtkWidget *build_assign(UnitCtx *unit, const char *title, - const char *subtitle, int ex_num, - const AssignItem *items, int n_items, - const char **group_labels, int n_groups, - const char **meanings) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, subtitle, "check", - &body, &feedback, &check); - AssignCtx *ac = g_new0(AssignCtx, 1); - GtkWidget *hint; - GtkWidget *row; - GtkWidget *holder; - GtkWidget *content; - GtkWidget *stage; - GtkToggleButton *first = NULL; - int *order; - - ac->n_items = n_items; - ac->n_groups = n_groups; - ac->active_group = 0; - ac->unit = unit; - ac->ex_num = ex_num; - ac->feedback = feedback; - ac->items_data = items; - ac->items = g_new0(GtkWidget *, n_items); - ac->trans = g_new0(GtkWidget *, n_items); - ac->current_group = g_new0(int, n_items); - for (int i = 0; i < n_items; i++) - ac->current_group[i] = -1; - - holder = gtk_overlay_new(); - gtk_widget_set_hexpand(holder, TRUE); - gtk_box_append(GTK_BOX(body), holder); - - content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(content, GTK_ALIGN_FILL); - gtk_overlay_set_child(GTK_OVERLAY(holder), content); - - stage = gtk_fixed_new(); - gtk_widget_set_halign(stage, GTK_ALIGN_FILL); - gtk_widget_set_valign(stage, GTK_ALIGN_FILL); - gtk_widget_set_can_target(stage, FALSE); - gtk_overlay_add_overlay(GTK_OVERLAY(holder), stage); - ac->stage = stage; - - hint = gtk_label_new(NULL); - i18n_bind(hint, "assign_hint", 0); - gtk_label_set_wrap(GTK_LABEL(hint), TRUE); - gtk_widget_set_halign(hint, GTK_ALIGN_START); - gtk_widget_add_css_class(hint, "ex-sub"); - gtk_box_append(GTK_BOX(content), hint); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(content), row); - for (int g = 0; g < n_groups; g++) { - GtkWidget *gb = gtk_toggle_button_new_with_label(group_labels[g]); - gtk_widget_add_css_class(gb, "group-btn"); - gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(gb), first); - if (!first) - first = GTK_TOGGLE_BUTTON(gb); - gtk_box_append(GTK_BOX(row), gb); - ac->group_btn[g] = gb; - g_signal_connect(gb, "toggled", G_CALLBACK(assign_group_toggled), ac); - } - gtk_toggle_button_set_active(first, TRUE); - - ac->pool = gtk_flow_box_new(); - gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(ac->pool), GTK_SELECTION_NONE); - gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(ac->pool), 2); - gtk_widget_set_size_request(ac->pool, -1, 48); - gtk_box_append(GTK_BOX(content), ac->pool); - - for (int g = 0; g < n_groups; g++) { - GtkWidget *panel = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - GtkWidget *gl = gtk_label_new(group_labels[g]); - GtkWidget *gf = gtk_flow_box_new(); - - gtk_widget_add_css_class(panel, "group-panel"); - - gtk_widget_set_halign(gl, GTK_ALIGN_START); - gtk_widget_add_css_class(gl, "group-panel-label"); - gtk_box_append(GTK_BOX(panel), gl); - - gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(gf), GTK_SELECTION_NONE); - gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(gf), 2); - gtk_widget_set_size_request(gf, -1, 48); - ac->group_flow[g] = gf; - gtk_box_append(GTK_BOX(panel), gf); - - gtk_box_append(GTK_BOX(content), panel); - } - - order = g_new0(int, n_items); - for (int i = 0; i < n_items; i++) - order[i] = i; - shuffle_indices(order, n_items); - - for (int k = 0; k < n_items; k++) { - int i = order[k]; - GString *lab = g_string_new(NULL); - GtkWidget *box; - GtkWidget *chip; - GtkWidget *m = NULL; - AssignChipRef *ref = g_new(AssignChipRef, 1); - - if (items[i].emoji) { - g_string_append(lab, items[i].emoji); - g_string_append(lab, " "); - } - g_string_append(lab, items[i].label); - - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(box, GTK_ALIGN_CENTER); - - chip = gtk_button_new_with_label(lab->str); - g_string_free(lab, TRUE); - gtk_widget_add_css_class(chip, "chip"); - gtk_widget_set_halign(chip, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(box), chip); - - if (meanings[i]) { - m = gtk_label_new(NULL); - i18n_bind(m, meanings[i], 0); - gtk_label_set_xalign(GTK_LABEL(m), 0.5); - gtk_widget_set_halign(m, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(m, "meaning"); - gtk_label_set_wrap(GTK_LABEL(m), TRUE); - gtk_label_set_max_width_chars(GTK_LABEL(m), 16); - gtk_widget_set_visible(m, FALSE); - gtk_box_append(GTK_BOX(box), m); - ac->trans[i] = m; - } - - g_object_ref(box); - ac->items[i] = box; - - ref->ac = ac; - ref->idx = i; - g_signal_connect(chip, "clicked", G_CALLBACK(assign_chip_clicked), ref); - - gtk_flow_box_insert(GTK_FLOW_BOX(ac->pool), box, -1); - } - g_free(order); - - g_signal_connect(check, "clicked", G_CALLBACK(assign_check), ac); - return page; -} - -/* ------------------------------------------------------------------ */ -/* Exercise 14: Wörter übersetzen */ -/* ------------------------------------------------------------------ */ - -const TypedQ trans_p10[] = { - {"der Abend, -e", "večer|evening", "večer"}, - {"Guten Abend!", "dobrý večer|good evening", "Dobrý večer!"}, - {"du", "ty|you", "ty"}, - {"(Es) freut mich.", "těší mě|nice to meet you|pleased to meet you", - "Těší mě."}, - {"gut", "dobrý|dobře|good", "dobrý"}, - {"Hallo!", "ahoj|hello", "Ahoj!"}, - {"heißen (Infinitiv)", - "jmenovat se|jmenuje se|to be called|to be named", "jmenovat se"}, - {"Ich heiße Jens.", - "jmenuji se jens|jmenuju se jens|my name is jens", "Jmenuji se Jens."}, - {"Hi!", "ahoj|čau|hi", "Ahoj! (neformálně)"}, - {"ich", "já|i", "já"}, - {"ihr", "vy|you", "vy"}, - {"ja", "ano|jo|yes", "ano"}, - {"der Morgen", "ráno|morning", "ráno"}, - {"Guten Morgen!", "dobré ráno|good morning", "Dobré ráno!"}, - {"der Name, -n", "jméno|name", "jméno"}, - {"nein", "ne|no", "ne"}, - {"(er/sie/es) ist", "je|is", "je"}, - {"der Tag, -e", "den|day", "den"}, - {"Guten Tag!", "dobrý den|good day", "Dobrý den!"}, - {"und", "a|and", "a"}, - {"wer", "kdo|who", "kdo"}, - {"Wer bist du?", "kdo jsi|kdo jste|who are you", "Kdo jsi?"}, - {"wie", "jak|how", "jak"}, - {"Wie heißt du?", - "jak se jmenuješ|jak se jmenujete|what is your name|what's your name", - "Jak se jmenuješ?"}, - {"wir", "my|we", "my"}, -}; - -const TypedQ trans_p11[] = { - {"in", "v|ve|in", "v"}, - {"in der Nähe (von)", - "poblíž|v blízkosti|nedaleko|blízko|near|nearby|close to", - "poblíž, v blízkosti"}, - {"das Spiel, -e", "hra|game", "hra"}, - {"wo", "kde|where", "kde"}, - {"wohnen (Infinitiv)", "bydlet|bydlí|to live", "bydlet"}, - {"Wo wohnst du?", - "kde bydlíš|kde bydlíte|where do you live", "Kde bydlíš?"}, - {"Ich wohne in Prag.", "bydlím v praze|i live in prague", "Bydlím v Praze."}, - {"null", "nula|zero", "nula"}, - {"eins", "jedna|jeden|one", "jedna"}, - {"zwei", "dvě|dva|two", "dvě"}, - {"drei", "tři|three", "tři"}, - {"vier", "čtyři|four", "čtyři"}, - {"fünf", "pět|five", "pět"}, - {"sechs", "šest|six", "šest"}, - {"sieben", "sedm|seven", "sedm"}, - {"acht", "osm|eight", "osm"}, - {"neun", "devět|nine", "devět"}, - {"zehn", "deset|ten", "deset"}, - {"elf", "jedenáct|eleven", "jedenáct"}, - {"zwölf", "dvanáct|twelve", "dvanáct"}, - {"dreizehn", "třináct|thirteen", "třináct"}, - {"vierzehn", "čtrnáct|fourteen", "čtrnáct"}, - {"fünfzehn", "patnáct|fifteen", "patnáct"}, - {"sechzehn", "šestnáct|sixteen", "šestnáct"}, - {"siebzehn", "sedmnáct|seventeen", "sedmnáct"}, - {"achtzehn", "osmnáct|eighteen", "osmnáct"}, - {"neunzehn", "devatenáct|nineteen", "devatenáct"}, - {"zwanzig", "dvacet|twenty", "dvacet"}, -}; - -const TypedQ trans_p12[] = { - {"alt", "starý|old", "starý"}, - {"er", "on|he", "on"}, - {"der Monat, -e", "měsíc|month", "měsíc"}, - {"sie (Singular)", "ona|she", "ona"}, - {"sie (Plural)", "oni|they", "oni"}, -}; - -const TypedQ trans_p13[] = { - {"aber", "ale|but", "ale"}, - {"das Alter", "věk|age", "věk"}, - {"auch", "také|taky|also|too", "také"}, - {"aus", "z|ze|from", "z"}, - {"die Band, -s", "skupina|hudební skupina|kapela|hudební kapela|band", "(hudební) skupina"}, - {"chatten (Infinitiv)", "chatovat|chatuje|to chat", "chatovat"}, - {"das Computerspiel, -e", "počítačová hra|computer game", "počítačová hra"}, - {"die/das E-Mail, -s", "e-mail|email", "e-mail"}, - {"das Englisch", "angličtina|anglicky|english", "angličtina, anglicky"}, - {"der Fan, -s", "fanoušek|fanda|fan", "fanoušek"}, - {"das Französisch", "francouzština|francouzsky|french", - "francouzština, francouzsky"}, - {"der Freund, -e", "kamarád|přítel|friend", "kamarád"}, - {"die Freundin, -nen", "kamarádka|přítelkyně|friend", "kamarádka"}, - {"beste Freundin", "nejlepší kamarádka|nejlepší přítelkyně|best friend", - "nejlepší kamarádka"}, - {"der Fußball", "fotbal|football|soccer", "fotbal"}, - {"Er ist Fußballfanatiker.", "je fotbalový fanatik|he is a football fanatic", - "Je fotbalový fanatik."}, - {"gehen (Infinitiv)", "jít|jde|chodit|to go", "jít"}, - {"Ich gehe gern auf Konzerte.", - "rád chodím na koncerty|ráda chodím na koncerty|chodím rád na koncerty|chodím ráda na koncerty|i like going to concerts", - "Rád(a) chodím na koncerty."}, - {"gern", "rád|ráda|gladly", "rád/a"}, - {"die Gitarre, -n", "kytara|guitar", "kytara"}, - {"das Handy, -s", "mobil|mobilní telefon|mobile phone", "mobil"}, - {"das Hobby, -s", "koníček|hobby", "koníček"}, - {"hören (Infinitiv)", "poslouchat|poslouchá|slyšet|to listen|to hear", - "poslouchat"}, - {"Er hört gern Musik.", "rád poslouchá hudbu|he likes listening to music", - "Rád poslouchá hudbu."}, - {"im Internet surfen (Infinitiv)", - "surfovat na internetu|to surf the internet", "surfovat na internetu"}, - {"immer", "pořád|neustále|vždy|vždycky|always", "pořád, neustále"}, - {"das Jahr, -e", "rok|year", "rok"}, - {"kein/keine/kein", "žádný|žádná|žádné|no|none", "žádný/žádná/žádné"}, - {"das Klavier, -e", "klavír|piano", "klavír"}, - {"kommen (Infinitiv, aus)", - "přicházet|přijít|přichází|pocházet|pochází|to come|to come from", - "přicházet, pocházet (z)"}, - {"Er kommt aus Wien.", - "pochází z vídně|he comes from vienna|he is from vienna", - "Pochází z Vídně."}, - {"das Konzert, -e", "koncert|concert", "koncert"}, - {"lernen (Infinitiv)", "učit se|učí se|to learn", "učit se"}, - {"liegen (Infinitiv)", "ležet|leží|to lie|to be located", "ležet"}, - {"der Nachname, -n", "příjmení|surname|last name", "příjmení"}, - {"nicht weit von", "nedaleko od|not far from", "nedaleko od"}, - {"reisen (Infinitiv)", "cestovat|cestuje|to travel", "cestovat"}, - {"schreiben (Infinitiv)", "psát|píše|to write", "psát"}, - {"die Schule, -n", "škola|school", "škola"}, - {"spielen (Infinitiv)", "hrát|hraje|to play", "hrát"}, - {"Sie spielt Gitarre.", "hraje na kytaru|she plays the guitar", - "Hraje na kytaru."}, - {"tanzen (Infinitiv)", "tancovat|tančí|tancuje|to dance", "tancovat"}, - {"der Vorname, -n", "křestní jméno|first name", "křestní jméno"}, - {"der Wohnort, -e", "bydliště|místo bydliště|place of residence", - "bydliště"}, -}; - -const TypedQ trans_p14[] = { - {"falsch", "nesprávně|chybně|špatně|nepravda|wrong|incorrect", "nesprávně, chybně"}, - {"die Flöte, -n", "flétna|flute", "flétna"}, - {"haben (Infinitiv)", "mít|má|to have", "mít"}, - {"das Instrument, -e", "nástroj|hudební nástroj|instrument", "(hudební) nástroj"}, - {"jetzt", "teď|nyní|now", "teď"}, - {"machen (Infinitiv)", "dělat|dělá|to do|to make", "dělat"}, - {"richtig", "správně|správný|correct|right", "správně"}, - {"der Sport", "sport", "sport"}, - {"Sport treiben (Infinitiv)", - "sportovat|sportuje|provozovat sport|dělat sport|to do sport", "sportovat"}, - {"das Squash", "squash", "squash"}, - {"das/der Yoga", "jóga|yoga", "jóga"}, -}; - -const TypedQ trans_p15[] = { - {"bald", "brzy|brzo|soon", "brzy"}, - {"Bis bald!", "brzy na shledanou|brzo na shledanou|brzy se uvidíme|brzo se uvidíme|see you soon", - "Brzy na shledanou!"}, - {"bis", "do|až|until", "do"}, - {"Bis zum nächsten Mal!", "do příštího setkání|do příště|until next time", - "Do příštího setkání!"}, - {"die Frau, -en", "paní|žena|manželka|woman|mrs|wife", "paní"}, - {"der Herr, -en", "pan|muž|man|mr", "pan"}, - {"Mach's gut!", "měj se hezky|měj se|mějte se hezky|mějte se|take care", "Měj se hezky!"}, - {"das Museum, Museen", "muzeum|museum", "muzeum"}, - {"Sie gehen ins Museum.", - "jdou do muzea|they are going to the museum|they go to the museum", - "Jdou do muzea."}, - {"schön", "hezký|krásný|pěkný|beautiful|nice", "hezký"}, - {"Einen schönen Tag noch!", - "hezký zbytek dne|měj hezký den|have a nice day", "Hezký zbytek dne!"}, - {"Servus!", "ahoj|servus|hi", "Ahoj! (servus)"}, - {"Tschüs!", "ahoj|čau|bye", "Ahoj! (při loučení)"}, - {"das Wiedersehen", "shledání|reunion", "shledání"}, - {"Auf Wiedersehen!", "na shledanou|na viděnou|goodbye", "Na shledanou!"}, -}; - -const TransSection u1_trans_sections[] = { - {"Strana 10", trans_p10, (int)G_N_ELEMENTS(trans_p10)}, - {"Strana 11", trans_p11, (int)G_N_ELEMENTS(trans_p11)}, - {"Strana 12", trans_p12, (int)G_N_ELEMENTS(trans_p12)}, - {"Strana 13", trans_p13, (int)G_N_ELEMENTS(trans_p13)}, - {"Strana 14", trans_p14, (int)G_N_ELEMENTS(trans_p14)}, - {"Strana 15", trans_p15, (int)G_N_ELEMENTS(trans_p15)}, -}; -const int u1_trans_sections_n = (int)G_N_ELEMENTS(u1_trans_sections); - -typedef struct { - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget *header; - GtkWidget *progress; - GtkWidget *prompt; - GtkWidget *entry; - GtkWidget *check; - TypedQ *qs; /* flattened words, in page order */ - const char **headers; /* section header i18n key per word */ - int total; - int done; - int *order; /* queue of word indices, order[0] = current */ - int qn; /* words still in the queue */ - gboolean warned; /* current word already got an "incomplete" warning */ -} TransCtx; - -/* Canonical translation of a word, in the current UI language. */ -static const char *trans_answer(const TypedQ *q) { - if (q->meaning) - return tr(q->meaning); - return q->answers ? q->answers : ""; -} - -static void trans_update_progress(TransCtx *ctx) { - gchar *txt = g_strdup_printf(tr("trans_progress"), ctx->done, ctx->total); - - gtk_label_set_text(GTK_LABEL(ctx->progress), txt); - g_free(txt); -} - -static void trans_show(TransCtx *ctx) { - ctx->warned = FALSE; - - if (ctx->qn <= 0) { - gtk_label_set_text(GTK_LABEL(ctx->header), ""); - gtk_label_set_text(GTK_LABEL(ctx->prompt), tr("trans_done")); - gtk_widget_set_visible(ctx->entry, FALSE); - gtk_widget_set_visible(ctx->check, FALSE); - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - trans_update_progress(ctx); - mark_done(ctx->unit, ctx->ex_num); - return; - } - - { - int idx = ctx->order[0]; - const TypedQ *q = &ctx->qs[idx]; - - gtk_label_set_text(GTK_LABEL(ctx->header), tr(ctx->headers[idx])); - gtk_label_set_text(GTK_LABEL(ctx->prompt), q->prompt); - } - - gtk_editable_set_text(GTK_EDITABLE(ctx->entry), ""); - gtk_widget_set_visible(ctx->entry, TRUE); - trans_update_progress(ctx); - if (gtk_widget_get_mapped(ctx->entry)) - gtk_widget_grab_focus(ctx->entry); -} - -static void trans_on_map(GtkWidget *widget, gpointer data) { - TransCtx *ctx = data; - - (void)widget; - if (ctx->qn > 0 && gtk_widget_get_visible(ctx->entry)) - gtk_widget_grab_focus(ctx->entry); -} - -static void translate_check(GtkButton *button, gpointer data) { - TransCtx *ctx = data; - int idx; - const TypedQ *q; - const gchar *txt; - gchar *norm; - gboolean good; - - (void)button; - - if (ctx->qn <= 0) - return; - - idx = ctx->order[0]; - q = &ctx->qs[idx]; - txt = gtk_editable_get_text(GTK_EDITABLE(ctx->entry)); - norm = normalize_answer(txt ? txt : ""); - good = txt && txt[0] && answer_accepts(norm, q->answers); - - /* Nearly there (e.g. "jmenovat" for "jmenovat se"): warn in yellow and let - * the student finish the answer. A second Check on the same word counts. */ - if (!good && !ctx->warned && txt && txt[0] && - answer_is_incomplete(norm, q->answers)) { - g_free(norm); - ctx->warned = TRUE; - set_feedback_warn(ctx->feedback, tr("trans_incomplete")); - return; - } - g_free(norm); - - /* Pop the current word off the front of the queue. */ - for (int i = 0; i < ctx->qn - 1; i++) - ctx->order[i] = ctx->order[i + 1]; - ctx->qn--; - - if (good) { - ctx->done++; - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - } else { - gchar *msg = g_strdup_printf(tr("trans_wrong"), trans_answer(q)); - - set_feedback(ctx->feedback, FALSE, msg); - g_free(msg); - ctx->order[ctx->qn++] = idx; /* failed words retry at the end */ - } - - trans_show(ctx); -} - -GtkWidget *build_translate(UnitCtx *unit) { - GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *wrap, *card, *bottom, *feedback, *check; - TransCtx *ctx = g_new0(TransCtx, 1); - int total = 0; - int k = 0; - - for (int s = 0; s < unit->n_trans_sections; s++) - total += unit->trans_sections[s].n; - - ctx->unit = unit; - ctx->ex_num = unit->branch_ex; - ctx->total = total; - ctx->qn = total; - ctx->qs = g_new0(TypedQ, total); - ctx->headers = g_new0(const char *, total); - ctx->order = g_new0(int, total); - - for (int s = 0; s < unit->n_trans_sections; s++) { - const TransSection *sec = &unit->trans_sections[s]; - - for (int i = 0; i < sec->n; i++, k++) { - ctx->qs[k] = sec->rows[i]; - ctx->headers[k] = sec->header; - ctx->order[k] = k; - } - } - - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), - top_bar(unit->page, "Vokabeltraining", "sub_translate")); - - wrap = gtk_center_box_new(); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_box_append(GTK_BOX(page), wrap); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - gtk_widget_set_size_request(card, 380, -1); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), card); - - ctx->header = gtk_label_new(NULL); - gtk_widget_set_halign(ctx->header, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(ctx->header, "ex-sub"); - gtk_box_append(GTK_BOX(card), ctx->header); - - ctx->progress = gtk_label_new(NULL); - gtk_widget_set_halign(ctx->progress, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(ctx->progress, "hint"); - gtk_box_append(GTK_BOX(card), ctx->progress); - - ctx->prompt = gtk_label_new(NULL); - gtk_widget_set_halign(ctx->prompt, GTK_ALIGN_CENTER); - gtk_label_set_wrap(GTK_LABEL(ctx->prompt), TRUE); - gtk_label_set_justify(GTK_LABEL(ctx->prompt), GTK_JUSTIFY_CENTER); - gtk_widget_add_css_class(ctx->prompt, "trans-word"); - gtk_widget_set_margin_top(ctx->prompt, 10); - gtk_widget_set_margin_bottom(ctx->prompt, 10); - gtk_box_append(GTK_BOX(card), ctx->prompt); - - ctx->entry = gtk_entry_new(); - gtk_entry_set_placeholder_text(GTK_ENTRY(ctx->entry), tr("your_answer")); - gtk_widget_set_halign(ctx->entry, GTK_ALIGN_FILL); - gtk_box_append(GTK_BOX(card), ctx->entry); - - bottom = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12); - gtk_widget_set_margin_top(bottom, 4); - gtk_box_append(GTK_BOX(page), bottom); - - feedback = gtk_label_new(""); - gtk_widget_set_halign(feedback, GTK_ALIGN_START); - gtk_widget_set_valign(feedback, GTK_ALIGN_CENTER); - gtk_widget_set_hexpand(feedback, TRUE); - gtk_box_append(GTK_BOX(bottom), feedback); - ctx->feedback = feedback; - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_valign(check, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(bottom), check); - ctx->check = check; - - g_signal_connect(check, "clicked", G_CALLBACK(translate_check), ctx); - g_signal_connect(ctx->entry, "activate", G_CALLBACK(translate_check), ctx); - g_signal_connect(page, "map", G_CALLBACK(trans_on_map), ctx); - - trans_show(ctx); - return page; -} diff --git a/src/exercise_u2.c b/src/exercise_u2.c deleted file mode 100644 index 0c6d2a2..0000000 --- a/src/exercise_u2.c +++ /dev/null @@ -1,1540 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Unit 2 exercises ("Aus aller Welt") */ -/* ------------------------------------------------------------------ */ - -/* ---- generic word-row helper (single blank, shared word bank) ----- */ - -void verb_rows_add(ComboListCtx *ctx, GtkWidget *body, int *counter, - const VerbQ *qs, int n, - const char **pool, int pool_n, - const char **meanings, gboolean pre_meaning) { - for (int i = 0; i < n; i++) { - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *before = gtk_label_new(qs[i].before); - GtkWidget *after = gtk_label_new(qs[i].after); - GtkWidget *combo; - char *numtxt; - - (*counter)++; - numtxt = g_strdup_printf("%d. ", *counter); - GtkWidget *num = gtk_label_new(numtxt); - g_free(numtxt); - - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(num, "ex-prompt"); - gtk_box_append(GTK_BOX(row), num); - - gtk_widget_set_valign(before, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(before, "ex-prompt"); - gtk_box_append(GTK_BOX(row), before); - - combo = make_word_combo(pool, pool_n); - gtk_widget_set_size_request(combo, 150, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), combo); - combo_list_add(ctx, combo, qs[i].answer); - - if (qs[i].after && qs[i].after[0]) { - gtk_widget_set_valign(after, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(after, "ex-prompt"); - gtk_box_append(GTK_BOX(row), after); - } - - gtk_box_append(GTK_BOX(body), row); - - if (meanings && meanings[i]) { - GtkWidget *mean = meaning_add(body, meanings[i]); - if (pre_meaning || ctx->trans_upfront) - gtk_widget_set_visible(mean, TRUE); - combo_list_add_trans(ctx, mean); - } - - if (ctx->reveal_german) { - char *sentence = verbq_german(qs[i].before, qs[i].answer, - qs[i].after); - - if (sentence && sentence[0]) { - GtkWidget *w = model_answer_add(body, sentence); - - g_array_append_val(ctx->models, w); - } - g_free(sentence); - } - } -} - - -void verb_note_reveal(VerbNoteCtx *nc) { - GString *s; - int i; - - if (!nc->note || !nc->gloss) - return; - - s = g_string_new(NULL); - for (i = 0; i < nc->n; i++) { - if (i > 0) - g_string_append_c(s, '\n'); - g_string_append_printf(s, "%s – %s", nc->qs[i].answer, - tr(nc->gloss[i])); - } - gtk_label_set_text(GTK_LABEL(nc->note), s->str); - g_string_free(s, TRUE); - gtk_widget_set_visible(nc->note, TRUE); -} - -void verb_ex_check(GtkButton *button, gpointer data) { - VerbNoteCtx *nc = data; - - combo_list_check(button, nc->ctx); - verb_note_reveal(nc); -} - -GtkWidget *build_verb_ex(UnitCtx *unit, int ex_num, - const char *title, const char *sub, - const VerbQ *qs, int n, - const char **pool, int pool_n, - const char **meanings, gboolean pre_meaning, - const char **gloss) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, sub, "check", - &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, ex_num, feedback); - VerbNoteCtx *nc = NULL; - int counter = 0; - - ctx->trans_upfront = TRUE; - ctx->reveal_german = TRUE; - - verb_rows_add(ctx, body, &counter, qs, n, pool, pool_n, meanings, - pre_meaning); - - if (gloss) { - GtkWidget *note = gtk_label_new(NULL); - gtk_widget_set_halign(note, GTK_ALIGN_START); - gtk_widget_set_margin_top(note, 6); - gtk_widget_add_css_class(note, "meaning"); - gtk_label_set_wrap(GTK_LABEL(note), TRUE); - gtk_widget_set_visible(note, FALSE); - gtk_box_append(GTK_BOX(body), note); - - nc = g_new0(VerbNoteCtx, 1); - nc->ctx = ctx; - nc->note = note; - nc->qs = qs; - nc->n = n; - nc->gloss = gloss; - g_signal_connect(check, "clicked", G_CALLBACK(verb_ex_check), nc); - } else { - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - } - - return page; -} - -/* ---- typed-entry builder with auto-check --------------------------- */ - - - -void typed_check(GtkButton *button, gpointer data) { - TypedCtx *ctx = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(ctx->entries[i])); - gchar *norm = normalize_answer(txt); - gboolean good = txt && txt[0] && answer_accepts(norm, ctx->qs[i].answers); - g_free(norm); - answer_mark(ctx->entries[i], good); - if (good) - ok++; - } - - if (ctx->trans) { - for (int i = 0; i < ctx->n; i++) - if (ctx->trans[i]) - gtk_widget_set_visible(ctx->trans[i], TRUE); - } - - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - - -/* Capitalise the first (canonical) answer alternative for display. */ -char *typed_answer_display(const char *answers) { - const char *pipe = strchr(answers, '|'); - char *base = pipe ? g_strndup(answers, (gsize)(pipe - answers)) - : g_strdup(answers); - - if (base[0]) { - gunichar ch = g_utf8_get_char(base); - gunichar up = g_unichar_toupper(ch); - if (up != ch) { - char *first = g_ucs4_to_utf8(&up, 1, NULL, NULL, NULL); - char *res = g_strconcat(first, g_utf8_next_char(base), NULL); - g_free(first); - g_free(base); - return res; - } - } - return base; -} - -void typed_note_reveal(TypedNoteCtx *nc) { - GString *s; - int i; - - if (!nc->note) - return; - - s = g_string_new(NULL); - for (i = 0; i < nc->n; i++) { - char *word = typed_answer_display(nc->qs[i].answers); - if (i > 0) - g_string_append_c(s, '\n'); - if (nc->qs[i].meaning) - g_string_append_printf(s, "%s – %s", word, tr(nc->qs[i].meaning)); - else - g_string_append(s, word); - g_free(word); - } - gtk_label_set_text(GTK_LABEL(nc->note), s->str); - g_string_free(s, TRUE); - gtk_widget_set_visible(nc->note, TRUE); -} - -void typed_ex_check(GtkButton *button, gpointer data) { - TypedNoteCtx *nc = data; - - typed_check(button, nc->ctx); - typed_note_reveal(nc); -} - -GtkWidget *build_typed(UnitCtx *unit, int ex_num, - const char *title, const char *sub, - const TypedQ *qs, int n, - const char *word_bank, gboolean answers_note) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, sub, "check", - &body, &feedback, &check); - TypedCtx *ctx = g_new0(TypedCtx, 1); - TypedNoteCtx *nc = NULL; - - ctx->qs = qs; - ctx->n = n; - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->entries = g_new0(GtkWidget *, n); - ctx->trans = g_new0(GtkWidget *, n); - - { - gboolean need = FALSE; - - for (int i = 0; i < n; i++) { - if (text_has_german_umlaut(qs[i].prompt) || - text_has_german_umlaut(qs[i].answers)) { - need = TRUE; - break; - } - } - if (need) - add_umlaut_note(body); - } - - if (word_bank) { - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *hdr = gtk_label_new(NULL); - GtkWidget *words = gtk_label_new(word_bank); - - gtk_widget_set_halign(row, GTK_ALIGN_START); - i18n_bind(hdr, "wordbank", 0); - gtk_widget_add_css_class(hdr, "hint"); - gtk_widget_add_css_class(words, "hint"); - gtk_box_append(GTK_BOX(row), hdr); - gtk_box_append(GTK_BOX(row), words); - gtk_box_append(GTK_BOX(body), row); - } - - for (int i = 0; i < n; i++) { - GtkWidget *prompt = gtk_label_new(qs[i].prompt); - GtkWidget *entry; - - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_widget_add_css_class(prompt, "ex-prompt"); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_box_append(GTK_BOX(body), prompt); - - entry = gtk_entry_new(); - gtk_widget_set_hexpand(entry, FALSE); - gtk_widget_set_halign(entry, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), entry); - ctx->entries[i] = entry; - - if (qs[i].meaning) - ctx->trans[i] = meaning_add(body, qs[i].meaning); - } - - if (answers_note) { - GtkWidget *note = gtk_label_new(NULL); - gtk_widget_set_halign(note, GTK_ALIGN_START); - gtk_widget_set_margin_top(note, 6); - gtk_widget_add_css_class(note, "meaning"); - gtk_label_set_wrap(GTK_LABEL(note), TRUE); - gtk_widget_set_visible(note, FALSE); - gtk_box_append(GTK_BOX(body), note); - - nc = g_new0(TypedNoteCtx, 1); - nc->ctx = ctx; - nc->note = note; - nc->qs = qs; - nc->n = n; - g_signal_connect(check, "clicked", G_CALLBACK(typed_ex_check), nc); - } else { - g_signal_connect(check, "clicked", G_CALLBACK(typed_check), ctx); - } - - return page; -} - -/* ---- G05/G06/G07/G11/S03 typed content ----------------------------- */ - -const char *g05_bank = - "Tscheche, Tschechin, Spanier, Spanierin, Türke, Türkin, Kroate, " - "Kroatin, Deutscher, Deutsche, Österreicher, Österreicherin, " - "Slowake, Slowakin"; - -const TypedQ g05_rows[] = { - {"Er kommt aus Tschechien. Er ist _________.", "tscheche", "Čech"}, - {"Sie kommt aus Spanien. Sie ist _________.", "spanierin", "Španělka"}, - {"Er kommt aus der Türkei. Er ist _________.", "türke|turke", "Turek"}, - {"Sie kommt aus Kroatien. Sie ist _________.", "kroatin", "Chorvatka"}, - {"Sie kommt aus Deutschland. Sie ist _________.", "deutsche", "Němka"}, - {"Sie kommt aus Österreich. Sie ist _________.", "österreicherin|osterreicherin", - "Rakušanka"}, - {"Er kommt aus der Slowakei. Er ist _________.", "slowake", "Slovák"}, -}; - -const TypedQ g06_rows[] = { - {"Ich heiße Thomas. Ich spreche Deutsch. Ich komme aus D________.", - "deutschland|eutschland", "Deutschland – Německo"}, - {"Ich heiße Martina. Ich spreche Slowakisch. Ich komme aus der S________.", - "slowakei|lowakei", "Slowakei – Slovensko"}, - {"Ich heiße Petra. Ich spreche Deutsch. Ich komme aus Ö________.", - "österreich|osterreich|sterreich", "Österreich – Rakousko"}, - {"Ich heiße Miguel. Ich spreche Spanisch. Ich komme aus S________.", - "spanien|panien", "Spanien – Španělsko"}, - {"Ich heiße George. Ich spreche Englisch. Ich komme aus E________.", - "england|ngland", "England – Anglie"}, - {"Ich heiße Maria. Ich spreche Polnisch. Ich komme aus P________.", - "polen|olen", "Polen – Polsko"}, -}; - -const TypedQ g07_rows[] = { - {"1. Ru__land", "russland|ss", "Russland – Rusko"}, - {"2. T_rkei", "türkei|turkei|ü|u", "Türkei – Turecko"}, - {"3. Slo__kei", "slowakei|wa", "Slowakei – Slovensko"}, - {"4. Kro__ien", "kroatien|at", "Kroatien – Chorvatsko"}, - {"5. Deut___land", "deutschland|sch", "Deutschland – Německo"}, - {"6. Öst__reich", "österreich|osterreich|er", "Österreich – Rakousko"}, - {"7. Gr__chenland", "griechenland|ie", "Griechenland – Řecko"}, - {"8. Ita__en", "italien|li", "Italien – Itálie"}, -}; - -const TypedQ g11_rows[] = { - {"tergehvatereikauwauzeh", "vater", "otec"}, - {"berelternnemrerhobschaz", "eltern", "rodiče"}, - {"nefrastschechinreiabtab", "tschechin", "Češka"}, - {"hejkosstudentaldwsahujoi", "student", "student"}, -}; - -const TypedQ s03_rows[] = { - {"1. 🇨🇿 Bist du Russe? – Nein, ich bin _________.", "tscheche", - "Čech"}, - {"2. 🇦🇹 Bist du Tschechin? – Nein, ich bin _________.", "österreicherin|osterreicherin", - "Rakušanka"}, - {"3. 🇨🇭 Bist du Deutsche? – Nein, ich bin _________.", "schweizerin", - "Švýcarka"}, - {"4. 🇩🇪 Bist du Engländer? – Nein, ich bin _________.", "deutscher", - "Němec"}, - {"5. 🇨🇭 Bist du Amerikanerin? – Nein, ich bin _________.", "schweizerin", - "Švýcarka"}, -}; - -/* ---- G01 content ---------------------------------------------------- */ - -const VerbQ g01_peter[] = { - {"Er ", " aus Österreich. (kommen)", "kommt"}, - {"Er ", " in Graz. (wohnen)", "wohnt"}, - {"Er ", " gern Golf. (spielen)", "spielt"}, - {"Er ", " Deutsch, Englisch und Italienisch. (sprechen)", "spricht"}, -}; - -const VerbQ g01_jana[] = { - {"Sie ", " aus der Slowakei. (kommen)", "kommen"}, - {"Sie ", " in Bratislava. (wohnen)", "wohnen"}, - {"Sie ", " gern. (tanzen)", "tanzt"}, - {"Er ", " gern. (reisen)", "reist"}, - {"Sie ", " gute Freunde. (sein)", "sind"}, -}; - -const char *g01_pool[] = { - "kommt", "kommst", "komme", "kommen", - "wohnt", "wohnst", "wohne", "wohnen", - "spielt", "spielst", "spiele", "spielen", - "spricht", "sprichst", "spreche", "sprechen", - "tanzt", "tanze", "tanzen", - "reist", "reise", "reisen", - "ist", "bist", "bin", "sind", "seid", -}; - -const char *g01_peter_mean[] = { - "Pochází z Rakouska.", - "Bydlí ve Štýrském Hradci (Graz).", - "Rád hraje golf.", - "Mluví německy, anglicky a italsky.", -}; - -const char *g01_jana_mean[] = { - "Pocházejí ze Slovenska.", - "Bydlí v Bratislavě (ona).", - "Ona ráda tancuje.", - "On rád cestuje.", - "Jsou dobří přátelé.", -}; - -/* ---- G04 sprechen --------------------------------------------------- */ - -const VerbQ g04_rows[] = { - {"• Ich ", " Deutsch und du?", "spreche"}, - {"• Welche Sprachen ", " Sie?", "sprechen"}, - {"• ", " du Französisch?", "sprichst"}, - {"• Wir ", " Polnisch und ihr?", "sprechen"}, - {"• ", " ihr Englisch?", "sprecht"}, - {"• Er ", " kein Wort Türkisch.", "spricht"}, -}; - -const char *g04_pool[] = { - "spreche", "sprichst", "spricht", "sprechen", "sprecht", -}; - -const char *g04_mean[] = { - "Mluvím německy. A ty?", - "Kterými jazyky mluvíte?", - "Mluvíš francouzsky? – Ano, trochu.", - "My mluvíme polsky a vy?", - "Mluvíte anglicky? – Ano, velmi dobře.", - "Nemluví ani slovo turecky.", -}; - -/* ---- G08 Verben einsetzen ------------------------------------------- */ - -const VerbQ g08_rows[] = { - {"Was ", " er? → Ein Buch. (lesen)", "liest"}, - {"Was ", " sie? → Medizin. (studieren)", "studiert"}, - {"Was ", " Jan gern? → Auto. (fahren)", "fährt"}, - {"Wo ", " ihr? → In Wien. (leben)", "lebt"}, - {"Wer ", " bei Siemens? → Meine Freundin Vera. (arbeiten)", - "arbeitet"}, -}; - -const char *g08_pool[] = { - "liest", "lese", "lest", "lesen", - "studiert", "studiere", "studiert", "studieren", - "fährt", "fahre", "fahrt", "fahren", - "lebt", "lebe", "lebt", "leben", - "arbeitet", "arbeite", "arbeitet", "arbeiten", -}; - -const char *g08_mean[] = { - "Co čte? – Knihu.", - "Co studuje? – Medicínu.", - "Čím Jan rád jezdí? – Autem.", - "Kde bydlíte? – Ve Vídni.", - "Kdo pracuje u Siemensu? – Moje kamarádka Věra.", -}; - -/* ---- G10 Euro -------------------------------------------------------- */ - -const VerbQ g10_rows[] = { - {"Julia hat ", " Euro.", "dreiundsechzig"}, - {"Tina hat ", " Euro.", "achtunddreißig"}, - {"Peter hat ", " Euro.", "fünfundvierzig"}, - {"Hans hat ", " Euro.", "siebenundfünfzig"}, - {"Barbara hat ", " Euro.", "neunundneunzig"}, -}; - -const char *g10_pool[] = { - "dreiundsechzig", "achtunddreißig", "fünfundvierzig", - "siebenundfünfzig", "neunundneunzig", -}; - -const char *g10_mean[] = { - "šedesát tři eur", - "třicet osm eur", - "čtyřicet pět eur", - "padesát sedm eur", - "devadesát devět eur", -}; - -/* ---- G14 Lückentext -------------------------------------------------- */ - -const VerbQ g14_rows[] = { - {"Agnieszka Kowalski kommt ", " Polen, aus Kraków.", "aus"}, - {"Sie ist 18 Jahre alt und ", " dieses Jahr Abitur.", "macht"}, - {"Sie chattet gerne mit ihrem deutschen ", ".", "Freund"}, - {"Er heißt Stefan Böhmermann und ", " in Dresden.", "lebt"}, - {"Agnieszka findet die ", " cool.", "Sprache"}, - {"Sie spricht schon sehr ", " Deutsch.", "gut"}, -}; - -const char *g14_pool[] = { - "aus", "macht", "Freund", "lebt", "Sprache", "gut", -}; - -const char *g14_mean[] = { - "Agnieszka Kowalski pochází z Polska, z Krakova.", - "Je jí 18 let a letos dělá maturitu.", - "Ráda chatuje se svým německým přítelem.", - "Jmenuje se Stefan Böhmermann a bydlí v Drážďanech.", - "Agnieszce přijde ten jazyk super.", - "Už mluví velmi dobře německy.", -}; - -const char *g14_gloss[] = { - "z", "dělá", "kamarád", "žije", "jazyk", "dobře", -}; - -/* ---- G15 Verbinde ---------------------------------------------------- */ - -const VerbQ g15_rows[] = { - {"ein Handy ", "", "brauchen"}, - {"bei BMW ", "", "arbeiten"}, - {"Auto ", "", "fahren"}, - {"das Gymnasium ", "", "besuchen"}, - {"Spanisch ", "", "sprechen"}, - {"Krimis ", "", "lesen"}, -}; - -const char *g15_pool[] = { - "brauchen", "arbeiten", "fahren", "besuchen", "sprechen", "lesen", -}; - -const char *g15_mean[] = { - "potřebovat mobil", - "pracovat ve BMW", - "řídit auto", - "navštěvovat gymnázium", - "mluvit španělsky", - "číst detektivky", -}; - -const char *g15_gloss[] = { - "potřebovat", "pracovat", "řídit", - "navštěvovat", "mluvit", "číst", -}; - -/* ---- G16 Zahlenpaare -------------------------------------------------- */ - -const VerbQ g16_rows[] = { - {"54 = ", "", "vierundfünfzig"}, - {"45 = ", "", "fünfundvierzig"}, - {"369 = ", "", "dreihundertneunundsechzig"}, - {"112 = ", "", "hundertzwölf"}, - {"122 = ", "", "hundertzweiundzwanzig"}, - {"68 = ", "", "achtundsechzig"}, -}; - -const char *g16_pool[] = { - "vierundfünfzig", "fünfundvierzig", "dreihundertneunundsechzig", - "hundertzwölf", "hundertzweiundzwanzig", "achtundsechzig", -}; - -const char *g16_mean[] = { - "padesát čtyři", - "čtyřicet pět", - "tři sta šedesát devět", - "sto dvanáct", - "sto dvacet dva", - "šedesát osm", -}; - -/* ---- G02 choice ------------------------------------------------------ */ - -const ChoiceQ g02_rows[] = { - {"1. Ich komme ___ Athen.", {"aus", "in"}, 2, 0}, - {"2. Peter wohnt ___ Salzburg.", {"aus", "in"}, 2, 1}, - {"3. Berlin liegt ___ Deutschland.", {"aus", "in"}, 2, 1}, - {"4. Wir wohnen ___ Paris.", {"aus", "in"}, 2, 1}, - {"5. Sie kommen ___ Griechenland.", {"aus", "in"}, 2, 0}, -}; - -const char *g02_mean[] = { - "Pocházím z Atén.", - "Petr bydlí v Salcburku.", - "Berlín leží v Německu.", - "Bydlíme v Paříži.", - "Pocházejí z Řecka.", -}; - -/* ---- G03 Fragewörter -------------------------------------------------- */ - -const ChoiceQ g03_rows[] = { - {"1. ___ kommt er? → Aus London.", {"Wer", "Wie", "Wo", "Woher", "Was"}, - 5, 3}, - {"2. ___ heißt sie? → Andrea.", {"Wer", "Wie", "Wo", "Woher", "Was"}, - 5, 1}, - {"3. ___ kommt aus Russland? → Alexander.", - {"Wer", "Wie", "Wo", "Woher", "Was"}, 5, 0}, - {"4. ___ liegt Prag? → In Tschechien.", {"Wer", "Wie", "Wo", "Woher", "Was"}, - 5, 2}, - {"5. ___ wohnen sie? → In Bratislava.", - {"Wer", "Wie", "Wo", "Woher", "Was"}, 5, 2}, - {"6. ___ macht ihr? → Wir studieren Germanistik.", - {"Wer", "Wie", "Wo", "Woher", "Was"}, 5, 4}, -}; - -const char *g03_mean[] = { - "Odkud je? – Z Londýna.", - "Jak se jmenuje? – Andrea.", - "Kdo pochází z Ruska? – Alexandr.", - "Kde leží Praha? – V Česku.", - "Kde bydlí? – V Bratislavě.", - "Co děláte? – Studujeme germanistiku.", -}; - -/* ---- G12 Unterstreiche ------------------------------------------------ */ - -const ChoiceQ g12_rows[] = { - {"1. Peter ___ gern Bücher.", {"liest", "lest", "lesen"}, 3, 0}, - {"2. Filip ___ in Salzburg.", {"arbeit", "arbeitet", "arbeite"}, 3, 1}, - {"3. Magda ___ gut Englisch.", {"spricht", "sprecht", "sprechen"}, 3, 0}, - {"4. Marek ___ das Gymnasium.", {"besuchst", "besucht", "besuchen"}, 3, 1}, - {"5. Dominika ___ 15 Jahre alt.", {"ist", "seid", "bin"}, 3, 0}, - {"6. Meine Schwester ___ Marta.", {"heiße", "heißt", "heißen"}, 3, 1}, -}; - -const char *g12_mean[] = { - "Petr rád čte knihy.", - "Filip pracuje v Salcburku.", - "Magda dobře mluví anglicky.", - "Marek navštěvuje gymnázium.", - "Dominice je 15 let.", - "Moje sestra se jmenuje Marta.", -}; - -/* ---- G13 Ordne zu ----------------------------------------------------- */ - - -const OrdneRow g13_rows[] = { - {"heißen sie?", "Wie", "Jana und Michael."}, - {"spricht Polnisch?", "Wer", "Jacek."}, - {"wohnt Eva?", "Wo", "In Plzeň."}, - {"kommt Markus?", "Woher", "Aus Deutschland."}, - {"macht ihr?", "Was", "Wir studieren Germanistik."}, - {"spricht Jana?", "Was", "Slowakisch."}, -}; - -const char *g13_fw_pool[] = {"Was", "Wer", "Wie", "Wo", "Woher"}; - -const char *g13_ans_pool[] = { - "Jana und Michael.", "Jacek.", "In Plzeň.", "Aus Deutschland.", - "Wir studieren Germanistik.", "Slowakisch.", -}; - -const char *g13_mean[] = { - "Jak se jmenují? – Jana a Michael.", - "Kdo mluví polsky? – Jacek.", - "Kde bydlí Eva? – V Plzni.", - "Odkud pochází Markus? – Z Německa.", - "Co děláte? – Studujeme germanistiku.", - "Jakým jazykem mluví Jana? – Slovensky.", -}; - -/* ---- G09 content (Freie Antwort) ------------------------------------- */ - -const FreeQ ex9_free_qs[] = { - {"Wie heißt du?", "Jak se jmenuješ?", - "Ich heiße Lukas.", "Jmenuji se Lukáš."}, - {"Wo wohnst du?", "Kde bydlíš?", - "Ich wohne in Prag.", "Bydlím v Praze."}, - {"Wohin fährst du?", "Kam jedeš?", - "Ich fahre nach Deutschland.", "Jedu do Německa."}, - {"Was liest du gern?", "Co rád/a čteš?", - "Ich lese gern Krimis.", "Rád/a čtu detektivky."}, - {"Was spielst du gern?", "Co rád/a hraješ?", - "Ich spiele gern Golf.", "Rád/a hraju golf."}, -}; - -/* ---- S01 Steckbrief --------------------------------------------------- */ - - -const ProfileQ s01_rows[] = { - {"Ich heiße …", "Ich heiße Petra."}, - {"Ich komme …", "Ich komme aus Tschechien."}, - {"Ich lebe …", "Ich lebe in Prag."}, - {"Ich bin …", "Ich bin fünfzehn Jahre alt."}, - {"Ich spreche …", "Ich spreche Tschechisch und Deutsch."}, - {"Ich besuche …", "Ich besuche das Gymnasium."}, - {"Ich finde …", "Ich finde Deutsch toll."}, - {"Ich arbeite …", "Ich arbeite noch nicht."}, -}; - -void s01_fill_sample(GtkWidget *label) { - const ProfileQ *q = g_object_get_data(G_OBJECT(label), "pq"); - char *txt; - - if (!q) - return; - txt = g_strdup_printf(tr("sample_line"), q->sample); - gtk_label_set_text(GTK_LABEL(label), txt); - g_free(txt); -} - - -void s01_reveal(GtkButton *button, gpointer data) { - GtkWidget *sample = data; - (void)button; - s01_fill_sample(sample); - gtk_widget_set_visible(sample, !gtk_widget_get_visible(sample)); -} - -void s01_finish(GtkButton *button, gpointer data) { - ProfileCtx *ctx = data; - (void)button; - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - for (int i = 0; i < ctx->n; i++) { - s01_fill_sample(ctx->samples[i]); - gtk_widget_set_visible(ctx->samples[i], TRUE); - } - mark_done(ctx->unit, ctx->ex_num); -} - -GtkWidget *build_profile(UnitCtx *unit, int ex_num, const char *title, - const char *sub, const ProfileQ *qs, int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, sub, "finish", - &body, &feedback, &check); - ProfileCtx *ctx = g_new0(ProfileCtx, 1); - - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->n = n; - ctx->samples = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *prompt = gtk_label_new(qs[i].stem); - GtkWidget *entry; - GtkWidget *reveal; - GtkWidget *sample; - - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_widget_add_css_class(prompt, "ex-prompt"); - gtk_box_append(GTK_BOX(body), prompt); - - entry = gtk_entry_new(); - i18n_bind(entry, "your_answer", 3); - gtk_box_append(GTK_BOX(body), entry); - - reveal = gtk_button_new(); - i18n_bind(reveal, "show_sample", 1); - gtk_widget_add_css_class(reveal, "pill"); - gtk_widget_set_halign(reveal, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), reveal); - - sample = gtk_label_new(NULL); - g_object_set_data(G_OBJECT(sample), "pq", (gpointer)&qs[i]); - gtk_widget_set_halign(sample, GTK_ALIGN_START); - gtk_widget_add_css_class(sample, "hint"); - gtk_label_set_wrap(GTK_LABEL(sample), TRUE); - gtk_widget_set_visible(sample, FALSE); - gtk_box_append(GTK_BOX(body), sample); - ctx->samples[i] = sample; - - g_signal_connect(reveal, "clicked", G_CALLBACK(s01_reveal), sample); - } - - g_signal_connect(check, "clicked", G_CALLBACK(s01_finish), ctx); - return page; -} - -/* ---- S02 Hangman (Berufe) --------------------------------------------- */ - - -const char *hm_words[HM_WORDS] = { - "KOCH", "ARZT", "LEHRER", "POLIZIST", "VERKÄUFER", -}; - -const char *hm_tips[HM_WORDS] = { - "vaří v restauraci", - "léčí nemocné lidi", - "učí ve škole", - "pracuje u policie", - "prodává v obchodě", -}; - -/* QWERTY order, Ä/Ö/Ü in their own bottom row. */ -const char *hm_letters[] = { - "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", - "A", "S", "D", "F", "G", "H", "J", "K", "L", - "Z", "X", "C", "V", "B", "N", "M", - "Ä", "Ö", "Ü", -}; - -const gunichar hm_letters_u[] = { - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', - 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', - 'Z', 'X', 'C', 'V', 'B', 'N', 'M', - 0x00c4, 0x00d6, 0x00dc, -}; - - -int hm_char_index(gunichar ch) { - for (int i = 0; i < HM_N_LETTERS; i++) - if (hm_letters_u[i] == ch) - return i; - return -1; -} - -void hm_update_slots(HangmanCtx *hm) { - const char *w = hm_words[hm->word_index]; - const char *p = w; - GString *out = g_string_new(NULL); - - while (*p) { - gunichar ch = g_utf8_get_char(p); - p = g_utf8_next_char(p); - if (out->len > 0) - g_string_append_c(out, ' '); - int idx = hm_char_index(ch); - if (idx >= 0 && hm->guessed[idx]) - g_string_append_unichar(out, ch); - else - g_string_append_c(out, '_'); - } - gtk_label_set_text(GTK_LABEL(hm->slots), out->str); - g_string_free(out, TRUE); -} - -gboolean hm_word_solved(HangmanCtx *hm) { - const char *w = hm_words[hm->word_index]; - const char *p = w; - - while (*p) { - gunichar ch = g_utf8_get_char(p); - p = g_utf8_next_char(p); - int idx = hm_char_index(ch); - if (idx < 0 || !hm->guessed[idx]) - return FALSE; - } - return TRUE; -} - -void hm_set_letters_enabled(HangmanCtx *hm, gboolean enabled) { - for (int i = 0; i < HM_N_LETTERS; i++) { - if (hm->letter_btns[i]) - gtk_widget_set_sensitive(hm->letter_btns[i], enabled); - } -} - -void hm_redraw(HangmanCtx *hm) { - if (hm->draw) - gtk_widget_queue_draw(hm->draw); -} - -void hm_clear_feedback(HangmanCtx *hm) { - gtk_widget_remove_css_class(hm->feedback, "feedback-ok"); - gtk_widget_remove_css_class(hm->feedback, "feedback-err"); - gtk_label_set_text(GTK_LABEL(hm->feedback), ""); -} - -gboolean hm_advance(gpointer data) { - HangmanCtx *hm = data; - - hm->locked = FALSE; - if (hm->word_index + 1 >= HM_WORDS) { - hm->finished = TRUE; - set_feedback(hm->feedback, TRUE, tr("hm_done")); - mark_done(hm->unit, hm->ex_num); - return G_SOURCE_REMOVE; - } - hm->word_index++; - hm->misses = 0; - for (int i = 0; i < HM_N_LETTERS; i++) - hm->guessed[i] = FALSE; - hm_set_letters_enabled(hm, TRUE); - hm_update_slots(hm); - gtk_label_set_text(GTK_LABEL(hm->hint_lbl), tr(hm_tips[hm->word_index])); - { - char *t = g_strdup_printf(tr("hm_progress"), hm->word_index + 1, - HM_WORDS); - gtk_label_set_text(GTK_LABEL(hm->counter_lbl), t); - g_free(t); - } - hm_clear_feedback(hm); - hm_redraw(hm); - return G_SOURCE_REMOVE; -} - -void hm_reset_word(gpointer data) { - HangmanCtx *hm = data; - hm->misses = 0; - for (int i = 0; i < HM_N_LETTERS; i++) - hm->guessed[i] = FALSE; - hm->locked = FALSE; - hm_set_letters_enabled(hm, TRUE); - hm_update_slots(hm); - hm_clear_feedback(hm); - hm_redraw(hm); -} - -gboolean hm_retry_word(gpointer data) { - hm_reset_word(data); - return G_SOURCE_REMOVE; -} - -void hm_guess_letter(GtkButton *button, gpointer data) { - HangmanCtx *hm = data; - int idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "li")); - const char *w = hm_words[hm->word_index]; - const char *p = w; - gboolean correct = FALSE; - - (void)button; - if (hm->finished || hm->locked) - return; - gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE); - hm->guessed[idx] = TRUE; - - while (*p) { - gunichar ch = g_utf8_get_char(p); - p = g_utf8_next_char(p); - if (hm_char_index(ch) == idx) { - correct = TRUE; - break; - } - } - - if (correct) { - hm_update_slots(hm); - if (hm_word_solved(hm)) { - hm->locked = TRUE; - hm_set_letters_enabled(hm, FALSE); - set_feedback(hm->feedback, TRUE, tr("hm_wrong")); - g_timeout_add(1100, hm_advance, hm); - } - } else { - hm->misses++; - hm_redraw(hm); - if (hm->misses >= HM_MAX_MISSES) { - char *msg = g_strdup_printf(tr("hm_fail"), w); - hm->locked = TRUE; - hm_set_letters_enabled(hm, FALSE); - set_feedback(hm->feedback, FALSE, msg); - g_free(msg); - /* reveal the word, then restart it with empty letters */ - for (int i = 0; i < HM_N_LETTERS; i++) - hm->guessed[i] = TRUE; - hm_update_slots(hm); - hm_redraw(hm); - g_timeout_add(1600, hm_retry_word, hm); - } - } -} - -void draw_hangman(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - HangmanCtx *hm = data; - Rgb c = color_from_hex(app_theme.subtext); - double cx = width / 2.0 - 30.0; - double ground = height - 10.0; - int parts = hm->misses; - - (void)area; - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_width(cr, 3.0); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - - /* scaffold */ - cairo_new_path(cr); - cairo_move_to(cr, width * 0.15, ground); - cairo_line_to(cr, width * 0.85, ground); - cairo_move_to(cr, cx, ground); - cairo_line_to(cr, cx, 20.0); - cairo_line_to(cr, cx + 70.0, 20.0); - cairo_move_to(cr, cx + 70.0, 20.0); - cairo_line_to(cr, cx + 70.0, 42.0); - cairo_stroke(cr); - - if (parts >= 1) { /* head */ - cairo_new_path(cr); - cairo_arc(cr, cx + 70.0, 54.0, 12.0, 0.0, 2.0 * G_PI); - cairo_stroke(cr); - } - if (parts >= 2) { /* body */ - cairo_new_path(cr); - cairo_move_to(cr, cx + 70.0, 66.0); - cairo_line_to(cr, cx + 70.0, 108.0); - cairo_stroke(cr); - } - if (parts >= 3) { /* left arm */ - cairo_new_path(cr); - cairo_move_to(cr, cx + 70.0, 76.0); - cairo_line_to(cr, cx + 50.0, 96.0); - cairo_stroke(cr); - } - if (parts >= 4) { /* right arm */ - cairo_new_path(cr); - cairo_move_to(cr, cx + 70.0, 76.0); - cairo_line_to(cr, cx + 90.0, 96.0); - cairo_stroke(cr); - } - if (parts >= 5) { /* left leg */ - cairo_new_path(cr); - cairo_move_to(cr, cx + 70.0, 108.0); - cairo_line_to(cr, cx + 50.0, 132.0); - cairo_stroke(cr); - } - if (parts >= 6) { /* right leg */ - cairo_new_path(cr); - cairo_move_to(cr, cx + 70.0, 108.0); - cairo_line_to(cr, cx + 90.0, 132.0); - cairo_stroke(cr); - } -} - -GtkWidget *build_hangman(UnitCtx *unit, int ex_num, const char *title, - const char *sub) { - GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *wrap = gtk_center_box_new(); - GtkWidget *content; - HangmanCtx *hm = g_new0(HangmanCtx, 1); - GtkWidget *hint_row; - GtkWidget *counter; - GtkWidget *slots; - GtkWidget *tip_hdr; - GtkWidget *hint_lbl; - GtkWidget *letters; - GtkWidget *head; - GtkWidget *guess_lbl; - char *tmp; - - hm->unit = unit; - hm->ex_num = ex_num; - - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), top_bar(unit->page, title, sub)); - - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_box_append(GTK_BOX(page), wrap); - - content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(content, GTK_ALIGN_CENTER); - gtk_widget_set_valign(content, GTK_ALIGN_CENTER); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), content); - - counter = gtk_label_new(NULL); - hm->counter_lbl = counter; - gtk_widget_add_css_class(counter, "ex-sub"); - gtk_box_append(GTK_BOX(content), counter); - - head = gtk_drawing_area_new(); - gtk_widget_set_size_request(head, 220, 170); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(head), draw_hangman, - hm, NULL); - hm->draw = head; - gtk_box_append(GTK_BOX(content), head); - - slots = gtk_label_new(NULL); - gtk_widget_add_css_class(slots, "hm-word"); - hm->slots = slots; - gtk_box_append(GTK_BOX(content), slots); - - hint_row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_widget_set_halign(hint_row, GTK_ALIGN_CENTER); - tip_hdr = gtk_label_new(NULL); - i18n_bind(tip_hdr, "hm_hint", 0); - gtk_widget_add_css_class(tip_hdr, "hint"); - hint_lbl = gtk_label_new(NULL); - gtk_widget_add_css_class(hint_lbl, "hint"); - hm->hint_lbl = hint_lbl; - gtk_box_append(GTK_BOX(hint_row), tip_hdr); - gtk_box_append(GTK_BOX(hint_row), hint_lbl); - gtk_box_append(GTK_BOX(content), hint_row); - - guess_lbl = gtk_label_new(NULL); - i18n_bind(guess_lbl, "hm_guess", 0); - gtk_widget_add_css_class(guess_lbl, "ex-sub"); - gtk_box_append(GTK_BOX(content), guess_lbl); - - letters = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); - gtk_box_append(GTK_BOX(content), letters); - - hm->letter_btns = g_new0(GtkWidget *, HM_N_LETTERS); - { - static const int kb_start[4] = { 0, HM_ROW2, HM_ROW3, HM_ROW4 }; - static const int kb_end[4] = { HM_ROW2, HM_ROW3, HM_ROW4, - HM_N_LETTERS }; - for (int r = 0; r < 4; r++) { - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); - gtk_widget_set_halign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_top(row, r == 3 ? 4 : 0); - for (int i = kb_start[r]; i < kb_end[r]; i++) { - GtkWidget *b = gtk_button_new_with_label(hm_letters[i]); - gtk_widget_add_css_class(b, "pill"); - gtk_widget_add_css_class(b, "hm-key"); - g_object_set_data(G_OBJECT(b), "li", GINT_TO_POINTER(i)); - g_signal_connect(b, "clicked", G_CALLBACK(hm_guess_letter), hm); - gtk_box_append(GTK_BOX(row), b); - hm->letter_btns[i] = b; - } - gtk_box_append(GTK_BOX(letters), row); - } - } - - hm->feedback = gtk_label_new(NULL); - gtk_widget_set_halign(hm->feedback, GTK_ALIGN_CENTER); - gtk_widget_set_margin_top(hm->feedback, 6); - gtk_box_append(GTK_BOX(content), hm->feedback); - - gtk_label_set_text(GTK_LABEL(hint_lbl), tr(hm_tips[0])); - tmp = g_strdup_printf(tr("hm_progress"), 1, HM_WORDS); - gtk_label_set_text(GTK_LABEL(counter), tmp); - g_free(tmp); - hm_update_slots(hm); - - return page; -} - -/* ---- per-exercise builders for unit 2 ------------------------------- */ - -GtkWidget *u2ex1(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Verben konjugieren", - "sub_verben", "check", - &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 1, feedback); - int counter = 0; - - ctx->trans_upfront = TRUE; - ctx->reveal_german = TRUE; - - GtkWidget *h1 = gtk_label_new("Peter Fritsch:"); - gtk_widget_set_halign(h1, GTK_ALIGN_START); - gtk_widget_add_css_class(h1, "ex-sub"); - gtk_box_append(GTK_BOX(body), h1); - verb_rows_add(ctx, body, &counter, g01_peter, G_N_ELEMENTS(g01_peter), - g01_pool, G_N_ELEMENTS(g01_pool), g01_peter_mean, FALSE); - - GtkWidget *h2 = gtk_label_new("Jana Nová und Pavol Korčák:"); - gtk_widget_set_halign(h2, GTK_ALIGN_START); - gtk_widget_add_css_class(h2, "ex-sub"); - gtk_widget_set_margin_top(h2, 10); - gtk_box_append(GTK_BOX(body), h2); - verb_rows_add(ctx, body, &counter, g01_jana, G_N_ELEMENTS(g01_jana), - g01_pool, G_N_ELEMENTS(g01_pool), g01_jana_mean, FALSE); - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -GtkWidget *u2ex2(UnitCtx *unit) { - return build_choice(unit, "aus oder in", "sub_ausin", 2, - g02_rows, g02_mean, G_N_ELEMENTS(g02_rows)); -} - -GtkWidget *u2ex3(UnitCtx *unit) { - return build_choice(unit, "Fragewörter", "sub_wer", 3, - g03_rows, g03_mean, G_N_ELEMENTS(g03_rows)); -} - -GtkWidget *u2ex4(UnitCtx *unit) { - return build_verb_ex(unit, 4, "sprechen", "sub_sprich", - g04_rows, G_N_ELEMENTS(g04_rows), - g04_pool, G_N_ELEMENTS(g04_pool), g04_mean, FALSE, - NULL); -} - -GtkWidget *u2ex5(UnitCtx *unit) { - return build_typed(unit, 5, "Nationalitäten", "sub_nation", - g05_rows, G_N_ELEMENTS(g05_rows), g05_bank, FALSE); -} - -GtkWidget *u2ex6(UnitCtx *unit) { - return build_typed(unit, 6, "Woher?", "sub_woher", - g06_rows, G_N_ELEMENTS(g06_rows), NULL, FALSE); -} - -GtkWidget *u2ex7(UnitCtx *unit) { - return build_typed(unit, 7, "Länder schreiben", "sub_laender", - g07_rows, G_N_ELEMENTS(g07_rows), NULL, FALSE); -} - -GtkWidget *u2ex8(UnitCtx *unit) { - return build_verb_ex(unit, 8, "Verben einsetzen", "sub_verb2", - g08_rows, G_N_ELEMENTS(g08_rows), - g08_pool, G_N_ELEMENTS(g08_pool), g08_mean, FALSE, - NULL); -} - -GtkWidget *u2ex9(UnitCtx *unit) { - return build_free_answer(unit, 9, "Freie Antwort", "sub_free", "tip_ss", - ex9_free_qs, (int)G_N_ELEMENTS(ex9_free_qs)); -} - -GtkWidget *u2ex10(UnitCtx *unit) { - return build_verb_ex(unit, 10, "Euro", "sub_euro", - g10_rows, G_N_ELEMENTS(g10_rows), - g10_pool, G_N_ELEMENTS(g10_pool), g10_mean, TRUE, - NULL); -} - -GtkWidget *u2ex11(UnitCtx *unit) { - return build_typed(unit, 11, "Wörter suchen", "sub_wortsuchen", - g11_rows, G_N_ELEMENTS(g11_rows), NULL, FALSE); -} - -GtkWidget *u2ex12(UnitCtx *unit) { - return build_choice(unit, "Was ist richtig?", "sub_verb2", 12, - g12_rows, g12_mean, G_N_ELEMENTS(g12_rows)); -} - -GtkWidget *u2ex13(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Ordne zu", "sub_ordne", - "check", &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, 13, feedback); - - for (guint i = 0; i < G_N_ELEMENTS(g13_rows); i++) { - const OrdneRow *r = &g13_rows[i]; - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *num = gtk_label_new(NULL); - GtkWidget *mid = gtk_label_new(r->mid); - GtkWidget *arrow = gtk_label_new("→"); - GtkWidget *fw = make_word_combo(g13_fw_pool, - G_N_ELEMENTS(g13_fw_pool)); - GtkWidget *ans = make_word_combo(g13_ans_pool, - G_N_ELEMENTS(g13_ans_pool)); - char *numtxt = g_strdup_printf("%d.", (int)(i + 1)); - - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_label_set_text(GTK_LABEL(num), numtxt); - g_free(numtxt); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(num, "ex-prompt"); - gtk_box_append(GTK_BOX(row), num); - - gtk_widget_set_valign(fw, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fw, 110, -1); - gtk_box_append(GTK_BOX(row), fw); - combo_list_add(ctx, fw, r->fw); - - gtk_widget_set_valign(mid, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(mid, "ex-prompt"); - gtk_box_append(GTK_BOX(row), mid); - - gtk_widget_set_valign(arrow, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(arrow, "ex-prompt"); - gtk_box_append(GTK_BOX(row), arrow); - - gtk_widget_set_valign(ans, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(ans, 190, -1); - gtk_box_append(GTK_BOX(row), ans); - combo_list_add(ctx, ans, r->ans); - - gtk_box_append(GTK_BOX(body), row); - combo_list_add_trans(ctx, meaning_add(body, g13_mean[i])); - } - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -GtkWidget *u2ex14(UnitCtx *unit) { - return build_verb_ex(unit, 14, "Lückentext", "sub_luecke", - g14_rows, G_N_ELEMENTS(g14_rows), - g14_pool, G_N_ELEMENTS(g14_pool), g14_mean, TRUE, - g14_gloss); -} - -GtkWidget *u2ex15(UnitCtx *unit) { - return build_verb_ex(unit, 15, "Verbinde", "sub_verbinde", - g15_rows, G_N_ELEMENTS(g15_rows), - g15_pool, G_N_ELEMENTS(g15_pool), g15_mean, TRUE, - g15_gloss); -} - -GtkWidget *u2ex16(UnitCtx *unit) { - return build_verb_ex(unit, 16, "Zahlen", "sub_zahlpaar", - g16_rows, G_N_ELEMENTS(g16_rows), - g16_pool, G_N_ELEMENTS(g16_pool), g16_mean, FALSE, - NULL); -} - -GtkWidget *u2ex17(UnitCtx *unit) { - return build_profile(unit, 17, "Steckbrief", "sub_steckbrief", - s01_rows, G_N_ELEMENTS(s01_rows)); -} - -GtkWidget *u2ex18(UnitCtx *unit) { - return build_hangman(unit, 18, "Berufe", "sub_berufe"); -} - -GtkWidget *u2ex19(UnitCtx *unit) { - return build_typed(unit, 19, "Nationalität", "sub_bistdu", - s03_rows, G_N_ELEMENTS(s03_rows), NULL, TRUE); -} - -/* ------------------------------------------------------------------ */ -/* Unit 2 vocabulary (off-path Vokabeltraining branch) */ -/* ------------------------------------------------------------------ */ - -const TypedQ u2_trans_p22[] = { - {"arbeiten (Infinitiv)", "pracovat|pracuje|to work", "pracovat"}, - {"das Auto, -s", "auto|car", "auto"}, - {"brauchen (Infinitiv)", "potřebovat|potřebuje|to need", "potřebovat"}, - {"die Britin, -nen", "britka|british woman", "Britka"}, - {"britisch", "britský|british", "britský"}, - {"deutsch", "německý|german", "německý"}, - {"das Deutsch", - "němčina|německy|němčina, německy|german", "němčina, německy"}, - {"die Eisschnelläuferin, -nen", - "rychlobruslařka|speed skater", "rychlobruslařka"}, - {"fahren (Infinitiv)", "jezdit|jet|řídit|to drive|to go", "jezdit"}, - {"Er fährt gern Auto.", - "rád řídí auto|rád jezdí autem|he likes driving a car", - "Rád řídí auto."}, - {"Frankreich", "francie|france", "Francie"}, - {"für", "pro|za|for", "pro, za"}, - {"der Fußballspieler", "fotbalista|footballer|football player", - "fotbalista"}, - {"das Jahrhunderttalent, -e", - "talent století|talent of the century", "talent století"}, - {"das Kind, -er", "dítě|child", "dítě"}, - {"lesen (Infinitiv)", "číst|to read", "číst"}, - {"das Model, -s", "model|modelka|model, modelka", "model, modelka"}, - {"die Nummer, -n", "číslo|number", "číslo"}, - {"die Schauspielerin, -nen", "herečka|actress", "herečka"}, - {"der Schüler, -", "žák|pupil|schoolboy", "žák"}, - {"die Sportinitiative, -n", - "sportovní iniciativa|sports initiative", "sportovní iniciativa"}, - {"sprechen (Infinitiv)", "mluvit|to speak", "mluvit"}, - {"Sie spricht Englisch.", - "mluví anglicky|ona mluví anglicky|she speaks english", - "Mluví anglicky."}, - {"der Trainer, -", "trenér|coach|trainer", "trenér"}, -}; - -const TypedQ u2_trans_p23[] = { - {"besuchen (Infinitiv)", "navštěvovat|navštívit|to visit", - "navštěvovat, navštívit"}, - {"Er besucht das Gymnasium.", - "chodí na gymnázium|navštěvuje gymnázium|he attends grammar school", - "Chodí na gymnázium."}, - {"dort", "tam|there", "tam"}, - {"dreifach", "trojnásobný|threefold|triple", "trojnásobný"}, - {"gewinnen (Infinitiv)", "vyhrát|vyhrávat|to win", "vyhrát, vyhrávat"}, - {"die Goldmedaille, -n", "zlatá medaile|gold medal", "zlatá medaile"}, - {"das Gymnasium, Gymnasien", "gymnázium|grammar school", "gymnázium"}, - {"heute", "dnes|dneska|today", "dnes"}, - {"das Kroatisch", - "chorvatština|chorvatsky|chorvatština, chorvatsky|croatian", - "chorvatština, chorvatsky"}, - {"leben (Infinitiv)", "žít|to live", "žít"}, - {"Sie lebt in Österreich.", "žije v rakousku|she lives in austria", - "Žije v Rakousku."}, - {"die Muttersprache, -n", "mateřský jazyk|mother tongue", - "mateřský jazyk"}, - {"oft", "často|often", "často"}, - {"Österreich", "rakousko|austria", "Rakousko"}, - {"die Rad(renn)fahrerin, -nen", "cyklistka|cyclist", "cyklistka"}, - {"das Spanisch", - "španělština|španělsky|španělština, španělsky|spanish", - "španělština, španělsky"}, - {"die Sportlerin, -nen", "sportovkyně|sportswoman|athlete", - "sportovkyně"}, - {"sportlich", "sportovní|sporty", "sportovní"}, - {"tschechisch", "český|czech", "český"}, - {"das Tschechisch", - "čeština|česky|čeština, česky|czech", "čeština, česky"}, -}; - -const TypedQ u2_trans_p24[] = { - {"das Amerika", "amerika|america", "Amerika"}, - {"die Assistentin, -nen", "asistentka|assistant", "asistentka"}, - {"der Beruf, -e", "povolání|profese|job|profession", "povolání"}, - {"Was ist er von Beruf?", - "jaké má povolání|čím je|what is his job", "Jaké má povolání?"}, - {"Deutschland", "německo|germany", "Německo"}, - {"England", "anglie|england", "Anglie"}, - {"die Flagge, -n", "vlajka|flag", "vlajka"}, - {"Griechenland", "řecko|greece", "Řecko"}, - {"das Griechisch", - "řečtina|řecky|řečtina, řecky|greek", "řečtina, řecky"}, - {"Großbritannien", "velká británie|great britain", "Velká Británie"}, - {"die Herkunft", "původ|origin", "původ"}, - {"Italien", "itálie|italy", "Itálie"}, - {"das Italienisch", - "italština|italsky|italština, italsky|italian", "italština, italsky"}, - {"Kroatien", "chorvatsko|croatia", "Chorvatsko"}, - {"das Land, Länder", "země|stát|country", "země, stát"}, - {"der Lehrer, -", "učitel|teacher", "učitel"}, - {"die Lehrerin, -nen", "učitelka|teacher", "učitelka"}, - {"der Manager, -", "manažer|manager", "manažer"}, - {"Polen", "polsko|poland", "Polsko"}, - {"das Polnisch", - "polština|polsky|polština, polsky|polish", "polština, polsky"}, - {"das Russisch", - "ruština|rusky|ruština, rusky|russian", "ruština, rusky"}, - {"Russland", "rusko|russia", "Rusko"}, - {"die Schweiz", "švýcarsko|switzerland", "Švýcarsko"}, - {"die Slowakei", "slovensko|slovakia", "Slovensko"}, - {"das Slowakisch", - "slovenština|slovensky|slovenština, slovensky|slovak", - "slovenština, slovensky"}, - {"Spanien", "španělsko|spain", "Španělsko"}, - {"die Sprache, -n", "jazyk|řeč|language", "jazyk, řeč"}, - {"der Student, -en", "student|student", "student"}, - {"die Studentin, -nen", "studentka|student", "studentka"}, - {"Tschechien", "česko|czechia", "Česko"}, - {"die Türkei", "turecko|turkey", "Turecko"}, - {"das Türkisch", - "turečtina|turecky|turečtina, turecky|turkish", "turečtina, turecky"}, - {"das Ungarisch", - "maďarština|maďarsky|maďarština, maďarsky|hungarian", - "maďarština, maďarsky"}, - {"Ungarn", "maďarsko|hungary", "Maďarsko"}, - {"die Verkäuferin, -nen", "prodavačka|shop assistant|saleswoman", - "prodavačka"}, - {"welcher/welche/welches", "jaký|jaká|jaké|which", "jaký/jaká/jaké"}, - {"Welche Sprachen spricht sie?", - "jakými jazyky mluví|které jazyky mluví|which languages does she speak", - "Jakými jazyky mluví?"}, - {"super", "super|skvělý|great|super, skvělý", "super, skvělý"}, - {"wenig", "málo|little|few", "málo"}, - {"ein wenig", "trochu|a little|a bit", "trochu"}, - {"das Wort, Wörter", "slovo|word", "slovo"}, -}; - -const TypedQ u2_trans_p25[] = { - {"das Abitur, -e", "maturita|a-levels", "maturita"}, - {"der Austausch, -e", "výměna|exchange", "výměna"}, - {"ein bisschen", "trochu|a bit|a little", "trochu"}, - {"finden (Infinitiv)", - "najít|považovat|shledávat|myslet si|to find", - "najít, považovat"}, - {"Sie findet den Kurs...", - "kurz se jí líbí|kurz shledává skvělým|she likes the course", - "Kurz se jí líbí. (Kurz shledává skvělým.)"}, - {"interessant", "zajímavý|interesting", "zajímavý"}, - {"der Kurs, -e", "kurz|course", "kurz"}, - {"leider", "bohužel|unfortunately", "bohužel"}, - {"mein/meine/mein", "můj|moje|my", "můj/moje/moje"}, - {"der Mensch, -en", "člověk|human|person", "člověk"}, - {"die Mutter, Mütter", "matka|mother", "matka"}, - {"noch", "ještě|still", "ještě"}, - {"Portugal", "portugalsko|portugal", "Portugalsko"}, - {"das Portugiesisch", - "portugalština|portugalsky|portugalština, portugalsky|portuguese", - "portugalština, portugalsky"}, - {"Schweden", "švédsko|sweden", "Švédsko"}, - {"das Schwedisch", - "švédština|švédsky|švédština, švédsky|swedish", "švédština, švédsky"}, - {"sehr", "velmi|very", "velmi"}, - {"nicht sehr gut", "ne moc dobře|not very well", "ne moc dobře"}, - {"studieren (Infinitiv)", "studovat|to study", "studovat"}, - {"das Südamerika", "jižní amerika|south america", "Jižní Amerika"}, - {"die USA (mn. č.)", "usa|united states|spojené státy", "USA"}, - {"viel", "hodně|much|a lot", "hodně"}, - {"wie viel", "kolik|how much|how many", "kolik"}, -}; - -const TypedQ u2_trans_p26a[] = { - {"Deutscher/Deutsche", "němec|němka|němec/němka", "Němec/Němka"}, - {"Engländer/Engländerin", - "angličan|angličanka|angličan/angličanka", "Angličan/Angličanka"}, - {"Franzose/Französin", - "francouz|francouzka|francouz/francouzka", "Francouz/Francouzka"}, - {"Italiener/Italienerin", "ital|italka|ital/italka", "Ital/Italka"}, - {"die Nationalität, -en", "národnost|nationality", "národnost"}, - {"Österreicher/Österreicherin", - "rakušan|rakušanka|rakušan/rakušanka", "Rakušan/Rakušanka"}, - {"Russe/Russin", "rus|ruska|rus/ruska", "Rus/Ruska"}, - {"Schweizer/Schweizerin", - "švýcar|švýcarka|švýcar/švýcarka", "Švýcar/Švýcarka"}, - {"Slowake/Slowakin", "slovák|slovenka|slovák/slovenka", - "Slovák/Slovenka"}, - {"Spanier/Spanierin", "španěl|španělka|španěl/španělka", - "Španěl/Španělka"}, - {"Tscheche/Tschechin", "čech|češka|čech/češka", "Čech/Češka"}, -}; - -const TypedQ u2_trans_p26b[] = { - {"dreißig", "30|třicet", "třicet (30)"}, - {"vierzig", "40|čtyřicet", "čtyřicet (40)"}, - {"fünfzig", "50|padesát", "padesát (50)"}, - {"sechzig", "60|šedesát", "šedesát (60)"}, - {"siebzig", "70|sedmdesát", "sedmdesát (70)"}, - {"achtzig", "80|osmdesát", "osmdesát (80)"}, - {"neunzig", "90|devadesát", "devadesát (90)"}, - {"(ein)hundert", "100|sto", "sto (100)"}, - {"(ein)tausend", "1000|tisíc", "tisíc (1000)"}, -}; - -const TypedQ u2_trans_p27[] = { - {"das Afrika", "afrika|africa", "Afrika"}, - {"die Arbeit, -en", "práce|work|job", "práce"}, - {"Asien", "asie|asia", "Asie"}, - {"das Australien", "austrálie|australia", "Austrálie"}, - {"beginnen (Infinitiv)", "začít|začínat|to begin|to start", - "začít, začínat"}, - {"danke", "děkuji|díky|thanks|thank you", "děkuji, díky"}, - {"das Europa", "evropa|europe", "Evropa"}, - {"ganz", "celý|whole", "celý"}, - {"gehen (Infinitiv)", "jít|chodit|to go", "jít"}, - {"Wie geht es Ihnen?", "jak se máte|how are you", "Jak se máte?"}, - {"Wie geht es dir?", "jak se máš|how are you", "Jak se máš?"}, - {"genau", "přesně|exactly", "přesně"}, - {"morgen", "zítra|tomorrow", "zítra"}, - {"nur", "jen|only", "jen"}, - {"der Rekord, -e", "rekord|record", "rekord"}, - {"schon", "již|už|already", "již, už"}, - {"das Semester, -", "semestr|semester", "semestr"}, - {"viel", "hodně|much|a lot", "hodně"}, - {"wie viel", "kolik|how much|how many", "kolik"}, - {"die Welt", "svět|world", "svět"}, - {"aus der ganzen Welt", "z celého světa|from all over the world", - "z celého světa"}, -}; - -const TransSection u2_trans_sections[] = { - {"Strana 22", u2_trans_p22, (int)G_N_ELEMENTS(u2_trans_p22)}, - {"Strana 23", u2_trans_p23, (int)G_N_ELEMENTS(u2_trans_p23)}, - {"Strana 24", u2_trans_p24, (int)G_N_ELEMENTS(u2_trans_p24)}, - {"Strana 25", u2_trans_p25, (int)G_N_ELEMENTS(u2_trans_p25)}, - {"Strana 26", u2_trans_p26a, (int)G_N_ELEMENTS(u2_trans_p26a)}, - {"Strana 26", u2_trans_p26b, (int)G_N_ELEMENTS(u2_trans_p26b)}, - {"Strana 27", u2_trans_p27, (int)G_N_ELEMENTS(u2_trans_p27)}, -}; -const int u2_trans_sections_n = (int)G_N_ELEMENTS(u2_trans_sections); - diff --git a/src/exercise_u3.c b/src/exercise_u3.c deleted file mode 100644 index ea09fed..0000000 --- a/src/exercise_u3.c +++ /dev/null @@ -1,1547 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Unit 3 exercises ("Bei uns zu Hause") */ -/* ------------------------------------------------------------------ */ - -/* Sentence fill-ins: a row is made of literal text segments that - * alternate with one or more blank widgets (dropdowns). `num` is the - * optional item number shown at the start of the line. */ - -/* Build the complete German sentence of a fill row (segments spliced - * with the correct answers) – used as the model shown after Check. */ -char *u3_fill_sentence(const U3Fill *f) { - const char *segs[4]; - const char *ans[3]; - GString *s; - int i, g; - - segs[0] = f->s0; - segs[1] = f->s1; - segs[2] = f->s2; - segs[3] = f->s3; - ans[0] = f->a0; - ans[1] = f->a1; - ans[2] = f->a2; - g = 0; - while (g < 3 && ans[g]) - g++; - - s = g_string_new(NULL); - for (i = 0; i <= g; i++) { - if (segs[i] && segs[i][0]) - g_string_append(s, segs[i]); - if (i < g && ans[i]) - g_string_append(s, ans[i]); - } - if (s->len == 0) { - g_string_free(s, TRUE); - return NULL; - } - return g_string_free(s, FALSE); -} - -/* Append one horizontal fill row to `body`. The answer of blank i sits - * between text segments s[i] and s[i+1]; empty segments are skipped. - * `gloss` (may be NULL) is an i18n key for a small grey note shown at - * the end of the line, e.g. the meaning of the expected possessive. */ -void u3_fill_row(ComboListCtx *ctx, GtkWidget *body, const U3Fill *f, - const char **pool, int pool_n, const char *gloss) { - const char *segs[4]; - const char *ans[3]; - int i, g; - GtkWidget *line; - - segs[0] = f->s0; - segs[1] = f->s1; - segs[2] = f->s2; - segs[3] = f->s3; - ans[0] = f->a0; - ans[1] = f->a1; - ans[2] = f->a2; - g = 0; - while (g < 3 && ans[g]) - g++; - - line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_widget_set_halign(line, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), line); - - if (f->num && f->num[0]) { - GtkWidget *nl = gtk_label_new(f->num); - gtk_widget_set_valign(nl, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(nl, "ex-prompt"); - gtk_box_append(GTK_BOX(line), nl); - } - for (i = 0; i <= g; i++) { - if (segs[i] && segs[i][0]) { - GtkWidget *lb = gtk_label_new(segs[i]); - gtk_widget_set_valign(lb, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(lb, "ex-prompt"); - gtk_box_append(GTK_BOX(line), lb); - } - if (i < g) { - GtkWidget *combo = make_word_combo(pool, pool_n); - gtk_widget_set_size_request(combo, 96, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(line), combo); - combo_list_add(ctx, combo, ans[i]); - } - } - - if (gloss && gloss[0]) { - GtkWidget *gl = gtk_label_new(NULL); - i18n_bind(gl, gloss, 0); - gtk_widget_set_valign(gl, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(gl, 8); - gtk_widget_add_css_class(gl, "meaning"); - gtk_box_append(GTK_BOX(line), gl); - } - - if (f->mean && f->mean[0]) { - GtkWidget *m = meaning_add(body, f->mean); - combo_list_add_trans(ctx, m); - if (ctx->trans_upfront) - gtk_widget_set_visible(m, TRUE); - } - - if (ctx->reveal_german) { - char *sentence = u3_fill_sentence(f); - - if (sentence && sentence[0]) { - GtkWidget *w = model_answer_add(body, sentence); - - g_array_append_val(ctx->models, w); - } - g_free(sentence); - } -} - -void u3_sample_line(GtkWidget *body, const char *text) { - GtkWidget *sl = gtk_label_new(text); - - gtk_widget_set_halign(sl, GTK_ALIGN_START); - gtk_widget_set_margin_top(sl, 2); - gtk_widget_set_margin_bottom(sl, 4); - gtk_widget_add_css_class(sl, "hint"); - gtk_label_set_wrap(GTK_LABEL(sl), TRUE); - gtk_box_append(GTK_BOX(body), sl); -} - -GtkWidget *u3_build_drop(UnitCtx *unit, int ex_num, const char *title, - const char *sub, const char *sample, - const U3Fill *rows, int n, - const char **pool, int pool_n, - const char **glosses, gboolean show_german) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, sub, "check", - &body, &feedback, &check); - ComboListCtx *ctx = combo_list_ctx_new(unit, ex_num, feedback); - - ctx->trans_upfront = show_german; - ctx->reveal_german = show_german; - - if (sample && sample[0]) - u3_sample_line(body, sample); - - for (int i = 0; i < n; i++) - u3_fill_row(ctx, body, &rows[i], pool, pool_n, - glosses ? glosses[i] : NULL); - - g_signal_connect(check, "clicked", G_CALLBACK(combo_list_check), ctx); - return page; -} - -/* ---- ex1: Familienpaare (match the pair) ---------------------------- */ - -const char *ex1_u3_pool[] = { - "die Cousine", "die Tante", "die Oma", "der Bruder", - "die Freundin", "der Sohn", -}; - -const U3Fill ex1_u3_rows[] = { - {"1.", "der Cousin", "die Cousine", NULL, NULL, NULL, NULL, NULL, - "bratranec / sestřenice"}, - {"2.", "der Onkel", "die Tante", NULL, NULL, NULL, NULL, NULL, - "strýc / teta"}, - {"3.", "der Opa", "die Oma", NULL, NULL, NULL, NULL, NULL, - "dědeček / babička"}, - {"4.", "die Schwester", "der Bruder", NULL, NULL, NULL, NULL, NULL, - "sestra / bratr"}, - {"5.", "der Freund", "die Freundin", NULL, NULL, NULL, NULL, NULL, - "kamarád / kamarádka"}, - {"6.", "die Tochter", "der Sohn", NULL, NULL, NULL, NULL, NULL, - "dcera / syn"}, -}; - -GtkWidget *u3ex1(UnitCtx *unit) { - return u3_build_drop(unit, 1, "Familienpaare", "sub3_pair", - "Beispiel: der Vater ↔ die Mutter", - ex1_u3_rows, G_N_ELEMENTS(ex1_u3_rows), - ex1_u3_pool, G_N_ELEMENTS(ex1_u3_pool), NULL, FALSE); -} - -/* ---- ex2: Possessivpronomen im Nominativ ----------------------------- */ - -const char *ex2_u3_pool[] = { - "dein", "deine", "mein", "meine", "sein", "seine", -}; - -/* The Czech sentence is shown straight away, and pressing "Check" only - * adds the translations of the words the student picked in the blanks. */ - - -const Ex2Row ex2_u3_rows2[] = { - {"2.", {"Ist das ", " Mutter? – Nein, das ist nicht ", " Mutter.", NULL}, - {"deine", "meine", NULL}, 2}, - {NULL, {"Das ist ", " Tante.", NULL, NULL}, {"seine", NULL, NULL}, 1}, -}; - -const Ex2Row ex2_u3_rows3[] = { - {"3.", {"Ist das ", " Bruder? – Nein, das ist nicht ", " Bruder.", NULL}, - {"dein", "mein", NULL}, 2}, - {NULL, {"Das ist ", " Cousin.", NULL, NULL}, {"sein", NULL, NULL}, 1}, -}; - -const Ex2Row ex2_u3_rows4[] = { - {"4.", - {"Sind das ", " Eltern? – Nein, das sind nicht ", - " Eltern. Das sind die Eltern von Markus.", NULL}, - {"deine", "meine", NULL}, 2}, -}; - -const Ex2Item ex2_u3_items[] = { - {"Je to tvoje matka? – Ne, to není moje matka. To je jeho teta.", - ex2_u3_rows2, G_N_ELEMENTS(ex2_u3_rows2)}, - {"Je to tvůj bratr? – Ne, to není můj bratr. To je jeho bratranec.", - ex2_u3_rows3, G_N_ELEMENTS(ex2_u3_rows3)}, - {"Jsou to tvoji rodiče? – Ne, to nejsou moji rodiče. To jsou rodiče " - "Markuse.", - ex2_u3_rows4, G_N_ELEMENTS(ex2_u3_rows4)}, -}; - - -const char *ex2_word_cs(const char *w) { - if (!w) - return NULL; - if (g_strcmp0(w, "dein") == 0) return "tvůj"; - if (g_strcmp0(w, "deine") == 0) return "tvoje"; - if (g_strcmp0(w, "mein") == 0) return "můj"; - if (g_strcmp0(w, "meine") == 0) return "moje"; - if (g_strcmp0(w, "sein") == 0) return "jeho"; - if (g_strcmp0(w, "seine") == 0) return "jeho"; - return NULL; -} - -void ex2_check(GtkButton *button, gpointer data) { - Ex2Ctx *ctx = data; - guint total = ctx->combos->len; - guint ok = 0; - - (void)button; - - for (guint i = 0; i < total; i++) { - GtkComboBox *combo = g_array_index(ctx->combos, GtkComboBox *, i); - const char *ans = g_array_index(ctx->answers, const char *, i); - gchar *sel = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(combo)); - gboolean good = FALSE; - if (sel) { - gchar *t = normalize_answer(sel); - good = answer_accepts(t, ans); - g_free(t); - g_free(sel); - } - answer_mark(GTK_WIDGET(combo), good); - if (good) - ok++; - } - - for (int it = 0; it < ctx->n_items; it++) { - GArray *item = ctx->item_combos[it]; - GtkWidget *note = ctx->notes[it]; - GString *s = g_string_new(NULL); - for (guint k = 0; k < item->len; k++) { - GtkComboBox *combo = g_array_index(item, GtkComboBox *, k); - gchar *sel = gtk_combo_box_text_get_active_text( - GTK_COMBO_BOX_TEXT(combo)); - const char *cs; - if (sel) { - cs = ex2_word_cs(sel); - if (cs) { - if (s->len > 0) - g_string_append(s, " · "); - g_string_append_printf(s, "%s = %s", sel, tr(cs)); - } - g_free(sel); - } - } - gtk_label_set_text(GTK_LABEL(note), s->str); - g_string_free(s, TRUE); - gtk_widget_set_visible(note, TRUE); - } - - if (ok == total) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - -GtkWidget *u3ex2(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "mein oder dein", "sub3_poss", - "check", &body, &feedback, &check); - Ex2Ctx *ctx = g_new0(Ex2Ctx, 1); - - ctx->combos = g_array_new(FALSE, FALSE, sizeof(GtkComboBox *)); - ctx->answers = g_array_new(FALSE, FALSE, sizeof(const char *)); - ctx->n_items = G_N_ELEMENTS(ex2_u3_items); - ctx->notes = g_new0(GtkWidget *, ctx->n_items); - ctx->item_combos = g_new0(GArray *, ctx->n_items); - ctx->unit = unit; - ctx->ex_num = 2; - ctx->feedback = feedback; - - u3_sample_line(body, "Beispiel: Ist das dein Vater? – Nein, das ist " - "nicht mein Vater. Das ist sein Onkel."); - - for (int it = 0; it < ctx->n_items; it++) { - const Ex2Item *item = &ex2_u3_items[it]; - GtkWidget *mean; - GtkWidget *note; - GArray *item_combos = g_array_new(FALSE, FALSE, - sizeof(GtkComboBox *)); - ctx->item_combos[it] = item_combos; - - for (int r = 0; r < item->nrows; r++) { - const Ex2Row *row = &item->rows[r]; - GtkWidget *line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - - gtk_widget_set_halign(line, GTK_ALIGN_START); - if (row->num && row->num[0]) { - GtkWidget *nl = gtk_label_new(row->num); - gtk_widget_set_valign(nl, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(nl, "ex-prompt"); - gtk_box_append(GTK_BOX(line), nl); - } - for (int i = 0; i <= row->gaps; i++) { - if (row->seg[i] && row->seg[i][0]) { - GtkWidget *lb = gtk_label_new(row->seg[i]); - gtk_widget_set_valign(lb, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(lb, "ex-prompt"); - gtk_box_append(GTK_BOX(line), lb); - } - if (i < row->gaps) { - GtkWidget *combo = make_word_combo(ex2_u3_pool, - G_N_ELEMENTS(ex2_u3_pool)); - gtk_widget_set_size_request(combo, 96, -1); - gtk_widget_set_valign(combo, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(line), combo); - g_array_append_val(ctx->combos, combo); - g_array_append_val(item_combos, combo); - g_array_append_val(ctx->answers, row->ans[i]); - } - } - gtk_box_append(GTK_BOX(body), line); - } - - /* Czech sentence is available before checking. */ - mean = meaning_add(body, item->czech); - gtk_widget_set_visible(mean, TRUE); - - /* word translations appear only after pressing "Check". */ - note = gtk_label_new(NULL); - gtk_widget_set_halign(note, GTK_ALIGN_START); - gtk_widget_set_margin_bottom(note, 2); - gtk_widget_add_css_class(note, "meaning"); - gtk_label_set_wrap(GTK_LABEL(note), TRUE); - gtk_widget_set_visible(note, FALSE); - gtk_box_append(GTK_BOX(body), note); - ctx->notes[it] = note; - } - - g_signal_connect(check, "clicked", G_CALLBACK(ex2_check), ctx); - return page; -} - -/* ---- ex3: Haustiere – ein/kein --------------------------------------- */ - -const char *ex3_u3_pool[] = { - "ein", "eine", "einen", "kein", "keine", "keinen", -}; - -const U3Fill ex3_u3_rows[] = { - {"2.", "Hast du ", "einen", - " Hamster? – Nein, ich habe ", "keinen", " Hamster.", NULL, NULL, - NULL}, - {NULL, "Ich habe ", "eine", " Schildkröte.", NULL, NULL, NULL, NULL, - "Máš křečka? – Ne, nemám křečka. Mám želvu."}, - {"3.", "Hast du ", "ein", - " Pferd? – Nein, ich habe ", "kein", " Pferd.", NULL, NULL, NULL}, - {NULL, "Ich habe ", "ein", " Kaninchen.", NULL, NULL, NULL, NULL, - "Máš koně? – Ne, nemám koně. Mám králíka."}, - {"4.", "Hast du ", "einen", - " Fisch? – Nein, ich habe ", "keinen", " Fisch.", NULL, NULL, NULL}, - {NULL, "Ich habe ", "einen", " Vogel.", NULL, NULL, NULL, NULL, - "Máš rybu? – Ne, nemám rybu. Mám ptáka."}, - {"5.", "Hast du ", "ein", - " Meerschweinchen? – Nein, ich habe ", "kein", - " Meerschweinchen.", NULL, NULL, NULL}, - {NULL, "Ich habe ", "einen", " Wellensittich.", NULL, NULL, NULL, NULL, - "Máš morče? – Ne, nemám morče. Mám andulku."}, -}; - -GtkWidget *u3ex3(UnitCtx *unit) { - return u3_build_drop(unit, 3, "ein / kein", "sub3_haustier", - "Beispiel: Hast du eine Katze? – Nein, ich habe " - "keine Katze. Ich habe einen Hund.", - ex3_u3_rows, G_N_ELEMENTS(ex3_u3_rows), - ex3_u3_pool, G_N_ELEMENTS(ex3_u3_pool), NULL, TRUE); -} - -/* ---- inline letter-gap rows (ex15) ----------------------------------- */ - -/* One sentence row whose text is split into segments with up to four - * small text entries (one per missing-letter group) inserted. */ - - -U3LetCtx *u3_let_ctx_new(UnitCtx *unit, int ex_num, - GtkWidget *feedback) { - U3LetCtx *ctx = g_new0(U3LetCtx, 1); - ctx->entries = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - ctx->answers = g_array_new(FALSE, FALSE, sizeof(const char *)); - ctx->trans = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - ctx->models = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - return ctx; -} - -/* Rebuild the full German sentence (letter gaps filled in). */ -char *u3_let_sentence(const U3Let *row) { - const char *segs[5]; - const char *ans[4]; - GString *s; - int i, g; - - segs[0] = row->s0; - segs[1] = row->s1; - segs[2] = row->s2; - segs[3] = row->s3; - segs[4] = row->s4; - ans[0] = row->a0; - ans[1] = row->a1; - ans[2] = row->a2; - ans[3] = row->a3; - g = 0; - while (g < 4 && ans[g]) - g++; - - s = g_string_new(NULL); - for (i = 0; i <= g; i++) { - if (segs[i] && segs[i][0]) - g_string_append(s, segs[i]); - if (i < g && ans[i]) - g_string_append(s, ans[i]); - } - if (s->len == 0) { - g_string_free(s, TRUE); - return NULL; - } - return g_string_free(s, FALSE); -} - -void u3_let_check(GtkButton *button, gpointer data) { - U3LetCtx *ctx = data; - guint total = ctx->entries->len; - guint ok = 0; - - (void)button; - - for (guint i = 0; i < total; i++) { - GtkWidget *e = g_array_index(ctx->entries, GtkWidget *, i); - const char *ans = g_array_index(ctx->answers, const char *, i); - const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(e)); - gchar *norm = normalize_answer(txt); - gboolean good = txt && txt[0] && answer_accepts(norm, ans); - g_free(norm); - answer_mark(e, good); - if (good) - ok++; - } - - for (guint i = 0; i < ctx->trans->len; i++) { - GtkWidget *lbl = g_array_index(ctx->trans, GtkWidget *, i); - if (lbl) - gtk_widget_set_visible(lbl, TRUE); - } - - for (guint i = 0; i < ctx->models->len; i++) { - GtkWidget *lbl = g_array_index(ctx->models, GtkWidget *, i); - if (lbl) - gtk_widget_set_visible(lbl, TRUE); - } - - if (ok == total) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - -void u3_let_row(U3LetCtx *ctx, GtkWidget *body, const U3Let *row) { - const char *segs[5]; - const char *ans[4]; - int i, g; - GtkWidget *line; - - segs[0] = row->s0; - segs[1] = row->s1; - segs[2] = row->s2; - segs[3] = row->s3; - segs[4] = row->s4; - ans[0] = row->a0; - ans[1] = row->a1; - ans[2] = row->a2; - ans[3] = row->a3; - g = 0; - while (g < 4 && ans[g]) - g++; - - line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - gtk_widget_set_halign(line, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), line); - - if (row->num && row->num[0]) { - GtkWidget *nl = gtk_label_new(row->num); - gtk_widget_set_valign(nl, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(nl, "ex-prompt"); - gtk_box_append(GTK_BOX(line), nl); - } - for (i = 0; i <= g; i++) { - if (segs[i] && segs[i][0]) { - GtkWidget *lb = gtk_label_new(segs[i]); - gtk_widget_set_valign(lb, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(lb, "ex-prompt"); - gtk_box_append(GTK_BOX(line), lb); - } - if (i < g) { - GtkWidget *e = gtk_entry_new(); - gtk_editable_set_width_chars(GTK_EDITABLE(e), 4); - gtk_widget_set_valign(e, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(line), e); - g_array_append_val(ctx->entries, e); - g_array_append_val(ctx->answers, ans[i]); - } - } - - if (row->mean && row->mean[0]) { - GtkWidget *m = meaning_add(body, row->mean); - gtk_widget_set_visible(m, TRUE); - g_array_append_val(ctx->trans, m); - } - - { - char *sentence = u3_let_sentence(row); - - if (sentence && sentence[0]) { - GtkWidget *w = model_answer_add(body, sentence); - - g_array_append_val(ctx->models, w); - } - g_free(sentence); - } -} - -GtkWidget *u3_build_letters(UnitCtx *unit, int ex_num, - const char *title, const char *sub, - const U3Let *rows, int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, sub, "check", - &body, &feedback, &check); - U3LetCtx *ctx = u3_let_ctx_new(unit, ex_num, feedback); - - { - gboolean need = FALSE; - - for (int i = 0; i < n && !need; i++) { - const U3Let *r = &rows[i]; - - need = text_has_german_umlaut(r->s0) || - text_has_german_umlaut(r->s1) || - text_has_german_umlaut(r->s2) || - text_has_german_umlaut(r->s3) || - text_has_german_umlaut(r->s4) || - text_has_german_umlaut(r->a0) || - text_has_german_umlaut(r->a1) || - text_has_german_umlaut(r->a2) || - text_has_german_umlaut(r->a3); - } - if (need) - add_umlaut_note(body); - } - - for (int i = 0; i < n; i++) - u3_let_row(ctx, body, &rows[i]); - - g_signal_connect(check, "clicked", G_CALLBACK(u3_let_check), ctx); - return page; -} - -/* ---- ex4: missing letters in a paragraph ----------------------------- */ - -/* The Czech sentence is shown straight away; pressing "Check" only adds - * the translations of the words the student had to complete. */ - -const Ex4Row ex4_u3_rows[] = { - {{"Wir hab", "n Fre", "nde in Öster", "ich. Sie wo", "nen in Wien."}, - {"e", "u", "re", "h"}, - "Máme přátele v Rakousku. Bydlí ve Vídni.", - {"haben", "Freunde", "Österreich", "wohnen"}, - {"mít", "přátelé", "Rakousko", "bydlet"}, 4}, - {{"Sie hei", "en Elfriede und Jiri. Sie haben auch ", "inder.", NULL, - NULL}, - {"ß", "K", NULL, NULL}, - "Jmenují se Elfriede a Jiří. Mají také děti.", - {"heißen", "Kinder", NULL, NULL}, - {"jmenovat se", "děti", NULL, NULL}, 2}, - {{"Ihr S", "hn heißt Philipp und ihr", " Tochter heißt Sabine.", NULL, - NULL}, - {"o", "e", NULL, NULL}, - "Jejich syn se jmenuje Philipp a jejich dcera Sabine.", - {"Sohn", "ihre", NULL, NULL}, - {"syn", "jejich", NULL, NULL}, 2}, - {{"Die Famili", " re", "st gern.", NULL, NULL}, - {"e", "i", NULL, NULL}, - "Rodina ráda cestuje.", - {"Familie", "reist", NULL, NULL}, - {"rodina", "cestuje", NULL, NULL}, 2}, - {{"Sie ist o", "t bei uns zu Bes", "ch in Tsche", "ien.", NULL}, - {"f", "u", "ch", NULL}, - "Často je u nás na návštěvě v Česku.", - {"oft", "Besuch", "Tschechien", NULL}, - {"často", "návštěva", "Česko", NULL}, 3}, - {{"Die Kinder ler", "en auch Tsche", "isch.", NULL, NULL}, - {"n", "ch", NULL, NULL}, - "Děti se učí také česky.", - {"lernen", "Tschechisch", NULL, NULL}, - {"učit se", "čeština", NULL, NULL}, 2}, -}; - - -void ex4_check(GtkButton *button, gpointer data) { - Ex4LetterCtx *ctx = data; - guint total = ctx->entries->len; - guint ok = 0; - - (void)button; - - for (guint i = 0; i < total; i++) { - GtkWidget *e = g_array_index(ctx->entries, GtkWidget *, i); - const char *ans = g_array_index(ctx->answers, const char *, i); - const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(e)); - gchar *norm = normalize_answer(txt); - gboolean good = txt && txt[0] && answer_accepts(norm, ans); - g_free(norm); - answer_mark(e, good); - if (good) - ok++; - } - - for (int r = 0; r < ctx->n_rows; r++) { - const Ex4Row *row = &ctx->rows[r]; - GtkWidget *note = ctx->notes[r]; - GString *s = g_string_new(NULL); - for (int k = 0; k < row->gaps; k++) { - if (k > 0) - g_string_append(s, " · "); - if (row->word[k]) - g_string_append_printf(s, "%s = %s", row->word[k], - tr(row->gmean[k])); - } - gtk_label_set_text(GTK_LABEL(note), s->str); - g_string_free(s, TRUE); - gtk_widget_set_visible(note, TRUE); - } - - if (ok == total) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - -GtkWidget *u3ex4(UnitCtx *unit) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Lückentext", "sub3_buchst", - "check", &body, &feedback, &check); - Ex4LetterCtx *ctx = g_new0(Ex4LetterCtx, 1); - - ctx->entries = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - ctx->answers = g_array_new(FALSE, FALSE, sizeof(const char *)); - ctx->rows = ex4_u3_rows; - ctx->n_rows = G_N_ELEMENTS(ex4_u3_rows); - ctx->notes = g_new0(GtkWidget *, ctx->n_rows); - ctx->unit = unit; - ctx->ex_num = 4; - ctx->feedback = feedback; - - { - gboolean need = FALSE; - - for (int r = 0; r < ctx->n_rows && !need; r++) { - for (int i = 0; i < ctx->rows[r].gaps; i++) { - if (text_has_german_umlaut(ctx->rows[r].ans[i]) || - text_has_german_umlaut(ctx->rows[r].word[i])) { - need = TRUE; - break; - } - } - } - if (need) - add_umlaut_note(body); - } - - for (int r = 0; r < ctx->n_rows; r++) { - const Ex4Row *row = &ctx->rows[r]; - GtkWidget *line = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - GtkWidget *mean; - GtkWidget *note; - - gtk_widget_set_halign(line, GTK_ALIGN_START); - for (int i = 0; i <= row->gaps; i++) { - if (row->seg[i] && row->seg[i][0]) { - GtkWidget *lb = gtk_label_new(row->seg[i]); - gtk_widget_set_valign(lb, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(lb, "ex-prompt"); - gtk_box_append(GTK_BOX(line), lb); - } - if (i < row->gaps) { - GtkWidget *e = gtk_entry_new(); - gtk_editable_set_width_chars(GTK_EDITABLE(e), 4); - gtk_widget_set_valign(e, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(line), e); - g_array_append_val(ctx->entries, e); - g_array_append_val(ctx->answers, row->ans[i]); - } - } - gtk_box_append(GTK_BOX(body), line); - - /* the Czech sentence is available before checking */ - mean = meaning_add(body, row->czech); - gtk_widget_set_visible(mean, TRUE); - - /* gapped-word translations appear only after "Check" */ - note = gtk_label_new(NULL); - gtk_widget_set_halign(note, GTK_ALIGN_START); - gtk_widget_set_margin_bottom(note, 2); - gtk_widget_add_css_class(note, "meaning"); - gtk_label_set_wrap(GTK_LABEL(note), TRUE); - gtk_widget_set_visible(note, FALSE); - gtk_box_append(GTK_BOX(body), note); - ctx->notes[r] = note; - } - - g_signal_connect(check, "clicked", G_CALLBACK(ex4_check), ctx); - return page; -} - -/* ---- ex5: Marcos Familie (word-bank typing) -------------------------- */ - -const char *ex5_u3_bank = - "Tanten | Job | Vater | Ferien | Zwillinge | Eltern | Kroatien"; - -const TypedQ ex5_u3_rows[] = { - {"Wir haben eine Männer-Wohngemeinschaft: Mein ________ Johann (50), " - "Ivo (16) und ich.", - "vater", "Máme mužskou domácnost: Můj otec Johann (50), Ivo (16) a já."}, - {"Ivo und ich sind gleich alt – wir sind nämlich ________.", - "zwillinge", "Ivo a já jsme stejně staří – jsme totiž dvojčata."}, - {"Jetzt wohnen wir in Hannover, unser Vater hat hier einen neuen " - "________.", - "job", "Náš otec tu má novou práci."}, - {"Unsere ________ sind geschieden.", - "eltern", "Naši rodiče jsou rozvedení."}, - {"Unsere Mutter Maja (50) lebt in Wien, aber sie kommt aus ________.", - "kroatien", "Naše matka Maja (50) žije ve Vídni, ale pochází z " - "Chorvatska."}, - {"Wir haben viele Onkel, ________, Cousinen und Cousins in Kroatien.", - "tanten", "Máme v Chorvatsku hodně strýců, tet, sestřenic a bratranců."}, - {"Wir sehen sie manchmal in den ________.", - "ferien", "Vídáme je někdy o prázdninách."}, -}; - -GtkWidget *u3ex5(UnitCtx *unit) { - return build_typed(unit, 5, "Marcos Familie", "sub3_marco", - ex5_u3_rows, G_N_ELEMENTS(ex5_u3_rows), - ex5_u3_bank, FALSE); -} - -/* ---- ex6: Wortschatz sortieren --------------------------------------- */ - -const AssignItem ex6_u3_items[] = { - {NULL, "die Oma", 0}, - {NULL, "der Bruder", 0}, - {NULL, "der Opa", 0}, - {NULL, "die Tochter", 0}, - {NULL, "die Tante", 0}, - {NULL, "der Hamster", 1}, - {NULL, "das Pferd", 1}, - {NULL, "die Katze", 1}, - {NULL, "der Hund", 1}, - {NULL, "der Wellensittich", 1}, -}; - -const char *ex6_u3_groups[] = {"Familienmitglieder", "Haustiere"}; - -const char *ex6_u3_meaning[] = { - "babička", "bratr", "dědeček", "dcera", "teta", - "křeček", "kůň", "kočka", "pes", "andulka", -}; - -GtkWidget *u3ex6(UnitCtx *unit) { - return build_assign(unit, "Sortieren", "sub3_sort", 6, - ex6_u3_items, G_N_ELEMENTS(ex6_u3_items), - ex6_u3_groups, G_N_ELEMENTS(ex6_u3_groups), - ex6_u3_meaning); -} - -/* ---- ex7: Possessivpronomen-Tabelle ---------------------------------- */ - - -void u3_table_check(GtkButton *button, gpointer data) { - U3TableCtx *ctx = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - const gchar *txt = gtk_editable_get_text( - GTK_EDITABLE(ctx->entries[i])); - gchar *norm = normalize_answer(txt); - gboolean good = txt && txt[0] && - g_strcmp0(norm, ctx->answers[i]) == 0; - g_free(norm); - answer_mark(ctx->entries[i], good); - if (good) - ok++; - } - - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - -GtkWidget *u3ex7(UnitCtx *unit) { - static const char *persons[] = { - "ich", "du", "er", "sie", "es", "wir", "ihr", "sie / Sie", - }; - static const char *nouns[] = { - "der Garten", "die Idee", "das Fest", "die Geschwister", - }; - static const char *ans[4][8] = { - {"mein", "dein", "sein", "ihr", "sein", "unser", "euer", - "ihr"}, - {"meine", "deine", "seine", "ihre", "seine", "unsere", "eure", - "ihre"}, - {"mein", "dein", "sein", "ihr", "sein", "unser", "euer", - "ihr"}, - {"meine", "deine", "seine", "ihre", "seine", "unsere", "eure", - "ihre"}, - }; - const int np = G_N_ELEMENTS(persons); - const int nn = G_N_ELEMENTS(nouns); - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, "Possessivtabelle", - "sub3_tabelle", "check", - &body, &feedback, &check); - GtkWidget *grid; - GtkWidget *sample_note; - GtkWidget *bank_row; - GtkWidget *bank_hdr; - GtkWidget *bank1; - GtkWidget *bank2; - U3TableCtx *ctx = g_new0(U3TableCtx, 1); - - ctx->n = nn * np; - ctx->entries = g_new0(GtkWidget *, ctx->n); - ctx->answers = g_new0(const char *, ctx->n); - ctx->unit = unit; - ctx->ex_num = 7; - ctx->feedback = feedback; - - sample_note = gtk_label_new("Beispiel: mein (ich × der Garten)"); - gtk_widget_set_halign(sample_note, GTK_ALIGN_START); - gtk_widget_set_margin_top(sample_note, 2); - gtk_widget_set_margin_bottom(sample_note, 4); - gtk_widget_add_css_class(sample_note, "hint"); - gtk_box_append(GTK_BOX(body), sample_note); - - bank_row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_widget_set_halign(bank_row, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), bank_row); - bank_hdr = gtk_label_new(NULL); - i18n_bind(bank_hdr, "wordbank", 0); - gtk_widget_add_css_class(bank_hdr, "hint"); - gtk_box_append(GTK_BOX(bank_row), bank_hdr); - bank1 = gtk_label_new("(der Garten / das Fest) " - "mein · dein · sein · ihr · unser · euer"); - gtk_widget_add_css_class(bank1, "hint"); - gtk_box_append(GTK_BOX(bank_row), bank1); - - bank_row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_widget_set_halign(bank_row, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), bank_row); - bank2 = gtk_label_new("(die Idee / die Geschwister) " - "meine · deine · seine · ihre · unsere · eure"); - gtk_widget_add_css_class(bank2, "hint"); - gtk_box_append(GTK_BOX(bank_row), bank2); - - grid = gtk_grid_new(); - gtk_grid_set_column_spacing(GTK_GRID(grid), 8); - gtk_grid_set_row_spacing(GTK_GRID(grid), 8); - gtk_widget_set_halign(grid, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), grid); - - for (int c = 0; c < np; c++) { - GtkWidget *h = gtk_label_new(persons[c]); - gtk_widget_set_halign(h, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(h, "ex-sub"); - gtk_grid_attach(GTK_GRID(grid), h, c + 1, 0, 1, 1); - } - for (int r = 0; r < nn; r++) { - GtkWidget *h = gtk_label_new(nouns[r]); - gtk_widget_set_halign(h, GTK_ALIGN_START); - gtk_widget_add_css_class(h, "ex-sub"); - gtk_grid_attach(GTK_GRID(grid), h, 0, r + 1, 1, 1); - } - for (int r = 0; r < nn; r++) { - for (int c = 0; c < np; c++) { - GtkWidget *e = gtk_entry_new(); - gtk_editable_set_width_chars(GTK_EDITABLE(e), 6); - gtk_widget_set_halign(e, GTK_ALIGN_CENTER); - gtk_grid_attach(GTK_GRID(grid), e, c + 1, r + 1, 1, 1); - ctx->entries[r * np + c] = e; - ctx->answers[r * np + c] = ans[r][c]; - } - } - /* pre-filled sample cell (ich × der Garten) */ - gtk_editable_set_text(GTK_EDITABLE(ctx->entries[0]), "mein"); - gtk_widget_set_sensitive(ctx->entries[0], FALSE); - - g_signal_connect(check, "clicked", G_CALLBACK(u3_table_check), ctx); - return page; -} - -/* ---- ex8: Possessivpronomen im Akkusativ ------------------------------ */ - -const char *ex8_u3_pool[] = { - "mein", "meine", "meinen", "dein", "deine", "deinen", - "sein", "seine", "seinen", "ihr", "ihre", "ihren", - "unser", "unsere", "unseren", "euer", "eure", "euren", -}; - -const U3Fill ex8_u3_rows[] = { - {"2.", "das Handy → Du brauchst ", "dein", " Handy.", NULL, NULL, NULL, - NULL, "Potřebuješ svůj mobil."}, - {"3.", "das Pferd → Er hat ", "sein", " Pferd.", NULL, NULL, NULL, NULL, - "Má svého koně."}, - {"4.", "die Party → Sie macht ", "ihre", " Party.", NULL, NULL, NULL, - NULL, "Dělá svou párty."}, - {"5.", "der Lehrer → Es fragt ", "seinen", " Lehrer.", NULL, NULL, NULL, - NULL, "Ptá se svého učitele."}, - {"6.", "das Wochenendhaus → Wir besuchen ", "unser", " Wochenendhaus.", - NULL, NULL, NULL, NULL, "Navštěvujeme náš víkendový dům."}, - {"7.", "der Hund → Ihr seht ", "euren", " Hund.", NULL, NULL, NULL, NULL, - "Vy vidíte svého psa."}, - {"8.", "die Instrumente → Sie haben ", "ihre", " Instrumente.", NULL, - NULL, NULL, NULL, "Mají své nástroje."}, -}; - -const char *ex8_u3_gloss[] = { - "u3g_dein", "u3g_sein", "u3g_ihr_sie", "u3g_sein_es", - "u3g_unser", "u3g_euer", "u3g_ihr_sie_pl", -}; - -GtkWidget *u3ex8(UnitCtx *unit) { - return u3_build_drop(unit, 8, "Akkusativ", "sub3_akk", - "Beispiel: die Inliner (ich) → Ich brauche meine " - "Inliner.", - ex8_u3_rows, G_N_ELEMENTS(ex8_u3_rows), - ex8_u3_pool, G_N_ELEMENTS(ex8_u3_pool), - ex8_u3_gloss, TRUE); -} - -/* ---- ex9: kein / keine / keinen / nicht ------------------------------ */ - -const char *ex9_u3_pool[] = { - "kein", "keine", "keinen", "nicht", -}; - -const U3Fill ex9_u3_rows[] = { - {"1.", "● Sprichst du Spanisch? ○ Nein, ich spreche ", "kein", - " Spanisch.", NULL, NULL, NULL, NULL, - "Mluvíš španělsky? – Ne, nemluvím španělsky."}, - {"2.", "● Hast du einen Bruder? ○ Nein, ich habe ", "keinen", - " Bruder.", NULL, NULL, NULL, NULL, "Máš bratra? – Ne, nemám bratra."}, - {"3.", "● Gibt es in Opava einen Zoo? ○ Nein, in Opava gibt es ", - "keinen", " Zoo.", NULL, NULL, NULL, NULL, - "Je v Opavě zoo? – Ne, v Opavě žádná zoo není."}, - {"4.", "● Gehst du ins Schwimmbad? ○ Nein, ich gehe ", "nicht", - " ins Schwimmbad.", NULL, NULL, NULL, NULL, - "Jdeš do bazénu? – Ne, do bazénu nejdu."}, - {"5.", "● Wandert er gern? ○ Nein, er wandert ", "nicht", " gern.", - NULL, NULL, NULL, NULL, "Rád chodí na túry? – Ne, nerad chodí na túry."}, - {"6.", "● Besuchst du heute ein Schloss? ○ Nein, heute besuche ich ", - "kein", " Schloss.", NULL, NULL, NULL, NULL, - "Navštívíš dnes zámek? – Ne, dnes nenavštívím žádný zámek."}, -}; - -GtkWidget *u3ex9(UnitCtx *unit) { - return u3_build_drop(unit, 9, "kein / nicht", "sub3_nicht", NULL, - ex9_u3_rows, G_N_ELEMENTS(ex9_u3_rows), - ex9_u3_pool, G_N_ELEMENTS(ex9_u3_pool), NULL, TRUE); -} - -/* ---- ex10: Sätze bauen ------------------------------------------------ */ - -const AssemblyItem ex10_u3_items[] = { - {NULL, {"Sie", "haben", "eine", "Schildkröte", "."}, 5}, - {NULL, {"Was", "macht", "deine", "Freundin", "am", "Wochenende?"}, 6}, - {NULL, {"Mein", "Vater", "ist", "Lehrer", "von", "Beruf."}, 6}, - {NULL, {"Seid", "ihr", "viele", "zu", "Hause?"}, 5}, - {NULL, {"Julia", "stellt", "ihren", "Hund", "Trixi", "vor."}, 6}, -}; - -const char *ex10_u3_meaning[] = { - "Mají želvu.", - "Co dělá tvoje kamarádka o víkendu?", - "Můj otec je povoláním učitel.", - "Je vás doma hodně?", - "Julie představuje svého psa Trixiho.", -}; - -GtkWidget *u3ex10(UnitCtx *unit) { - return build_assembly(unit, "Sätze bauen", "sub3_satz", 10, - ex10_u3_items, ex10_u3_meaning, - G_N_ELEMENTS(ex10_u3_items)); -} - -/* ---- keyword-typed builder (ex11 + ex14) ----------------------------- */ - - - -void u3_kw_check(GtkButton *button, gpointer data) { - U3KwCtx *ctx = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(ctx->entries[i])); - gchar *norm = normalize_answer(txt); - gboolean good = txt && txt[0]; - if (good) { - gchar **parts = g_strsplit(ctx->qs[i].answers, "|", -1); - good = FALSE; - for (int j = 0; parts[j]; j++) { - gchar *a = normalize_answer(parts[j]); - if (a[0] && g_strrstr(norm, a)) { - good = TRUE; - g_free(a); - break; - } - g_free(a); - } - g_strfreev(parts); - } - g_free(norm); - answer_mark(ctx->entries[i], good); - if (good) - ok++; - } - - for (int i = 0; i < ctx->n; i++) - if (ctx->models[i]) - gtk_widget_set_visible(ctx->models[i], TRUE); - - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - -GtkWidget *u3_build_kw(UnitCtx *unit, int ex_num, const char *title, - const char *sub, const char *sample, - const U3Kw *qs, int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell(unit->page, title, sub, "check", - &body, &feedback, &check); - U3KwCtx *ctx = g_new0(U3KwCtx, 1); - - ctx->qs = qs; - ctx->n = n; - ctx->unit = unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->entries = g_new0(GtkWidget *, n); - ctx->trans = g_new0(GtkWidget *, n); - ctx->models = g_new0(GtkWidget *, n); - - { - gboolean need = FALSE; - - for (int i = 0; i < n && !need; i++) { - need = text_has_german_umlaut(qs[i].prompt) || - text_has_german_umlaut(qs[i].answers) || - text_has_german_umlaut(qs[i].german); - } - if (need) - add_umlaut_note(body); - } - - if (sample && sample[0]) - u3_sample_line(body, sample); - - for (int i = 0; i < n; i++) { - GtkWidget *prompt = gtk_label_new(qs[i].prompt); - GtkWidget *entry; - - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_widget_add_css_class(prompt, "ex-prompt"); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_box_append(GTK_BOX(body), prompt); - - entry = gtk_entry_new(); - gtk_widget_set_hexpand(entry, FALSE); - gtk_widget_set_halign(entry, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), entry); - ctx->entries[i] = entry; - - if (qs[i].mean) - ctx->trans[i] = meaning_add(body, qs[i].mean); - - /* Czech meaning acts as a hint and stays visible. */ - if (ctx->trans[i]) - gtk_widget_set_visible(ctx->trans[i], TRUE); - - /* The model German sentence is only shown after clicking Check. */ - if (qs[i].german && qs[i].german[0]) { - GtkWidget *model = gtk_label_new(qs[i].german); - - gtk_widget_set_halign(model, GTK_ALIGN_START); - gtk_label_set_xalign(GTK_LABEL(model), 0.0); - gtk_label_set_wrap(GTK_LABEL(model), TRUE); - gtk_widget_set_margin_top(model, 2); - gtk_widget_set_margin_bottom(model, 2); - gtk_widget_set_margin_start(model, 8); - gtk_widget_add_css_class(model, "u3-answer"); - gtk_widget_set_visible(model, FALSE); - gtk_box_append(GTK_BOX(body), model); - ctx->models[i] = model; - } - } - - g_signal_connect(check, "clicked", G_CALLBACK(u3_kw_check), ctx); - return page; -} - -/* ---- ex11: Was siehst du? -------------------------------------------- */ - -const U3Kw ex11_u3_qs[] = { - {"Ein altes Gebäude aus dem Mittelalter. Es steht auf einem Berg.", - "burg|schloss", "Vidím hrad / zámek.", - "Ich sehe eine Burg. / Ich sehe ein Schloss."}, - {"Wasser, Bäume und Berge. Es ist sehr ruhig.", - "see", "Vidím jezero.", "Ich sehe einen See."}, - {"Eine Frau, ein Mann und zwei Kinder essen zusammen.", - "familie", "Vidím rodinu.", "Ich sehe eine Familie."}, -}; - -GtkWidget *u3ex11(UnitCtx *unit) { - return u3_build_kw(unit, 11, "Was siehst du?", "sub3_sehen", - "Beispiel: Ich sehe eine Burg. / Ich sehe ein Schloss.", - ex11_u3_qs, G_N_ELEMENTS(ex11_u3_qs)); -} - -/* ---- ex12: Wem gehört das? ------------------------------------------- */ - -const char *ex12_u3_pool[] = { - "mein", "meine", "dein", "deine", "sein", "seine", - "ihr", "ihre", "unser", "unsere", "euer", "eure", -}; - -const U3Fill ex12_u3_rows[] = { - {"1.", "Das ist Tom. → Das ist ", "sein", " Handy.", NULL, NULL, NULL, - NULL, "To je jeho mobil."}, - {"2.", "Das ist Maria. → Das ist ", "ihr", " Kaninchen.", NULL, NULL, - NULL, NULL, "To je její králík."}, - {"3.", "Das sind Max und Lisa. → Das sind ", "ihre", " Inliner.", NULL, - NULL, NULL, NULL, "To jsou jejich brusle."}, - {"4.", "Das ist Frau Berger. → Das ist ", "ihr", " Kuchen.", NULL, NULL, - NULL, NULL, "To je její dort."}, - {"5.", "Das ist Herr Müller. → Das ist ", "sein", " Haus.", NULL, NULL, - NULL, NULL, "To je jeho dům."}, - {"6.", "Das sind die Schmidts. → Das sind ", "ihre", " Kinder.", NULL, - NULL, NULL, NULL, "To jsou jejich děti."}, -}; - -GtkWidget *u3ex12(UnitCtx *unit) { - return u3_build_drop(unit, 12, "Wem gehört das?", "sub3_wem", NULL, - ex12_u3_rows, G_N_ELEMENTS(ex12_u3_rows), - ex12_u3_pool, G_N_ELEMENTS(ex12_u3_pool), NULL, TRUE); -} - -/* ---- ex13: Es gibt + unbestimmter Artikel ---------------------------- */ - -const char *ex13_u3_pool[] = {"ein", "eine", "einen"}; - -const U3Fill ex13_u3_rows[] = { - {"1.", "(das Konzert) → Es gibt ", "ein", " Konzert.", NULL, NULL, NULL, - NULL, "Je tu koncert."}, - {"2.", "(die Ausstellung) → Es gibt ", "eine", " Ausstellung.", NULL, - NULL, NULL, NULL, "Je tu výstava."}, - {"3.", "(das Sportfest) → Es gibt ", "ein", " Sportfest.", NULL, NULL, - NULL, NULL, "Je tu sportovní slavnost."}, - {"4.", "(das Familientreffen) → Es gibt ", "ein", " Familientreffen.", - NULL, NULL, NULL, NULL, "Je tu rodinné setkání."}, - {"5.", "(die Theatervorstellung) → Es gibt ", "eine", - " Theatervorstellung.", NULL, NULL, NULL, NULL, - "Je tu divadelní představení."}, - {"6.", "(der Flohmarkt) → Es gibt ", "einen", " Flohmarkt.", NULL, NULL, - NULL, NULL, "Je tu bleší trh."}, -}; - -GtkWidget *u3ex13(UnitCtx *unit) { - return u3_build_drop(unit, 13, "Es gibt …", "sub3_gibt", NULL, - ex13_u3_rows, G_N_ELEMENTS(ex13_u3_rows), - ex13_u3_pool, G_N_ELEMENTS(ex13_u3_pool), NULL, TRUE); -} - -/* ---- ex14: Beschreiben (sentence pairs) ------------------------------ */ - -const U3Kw ex14_u3_qs[] = { - {"Eine Frau fährt Fahrrad. → Ich sehe ________.", - "eine frau|frau", "Vidím ženu.", "Ich sehe eine Frau."}, - {"→ Sie ________.", - "sie fährt fahrrad|sie fährt|fährt fahrrad|fährt", "Jezdí na kole.", - "Sie fährt Fahrrad."}, - {"Ein Mann wandert im Wald. → Ich sehe ________.", - "einen mann|mann", "Vidím muže.", "Ich sehe einen Mann."}, - {"→ Er ________.", - "er wandert im wald|er wandert|wandert im wald|wandert", - "Chodí po lese.", "Er wandert im Wald."}, - {"Zwei Kinder spielen Fußball. → Ich sehe ________.", - "zwei kinder|kinder", "Vidím dvě děti.", "Ich sehe zwei Kinder."}, - {"→ Sie ________.", - "sie spielen fußball|sie spielen fussball|spielen fußball|spielen " - "fussball|spielen", "Hrají fotbal.", "Sie spielen Fußball."}, -}; - -GtkWidget *u3ex14(UnitCtx *unit) { - return u3_build_kw(unit, 14, "Beschreiben", "sub3_saetze", - "Beispiel: Ich sehe einen Jungen. Er liest ein Buch.", - ex14_u3_qs, G_N_ELEMENTS(ex14_u3_qs)); -} - -/* ---- ex15: missing letters (Wochenende) ------------------------------ */ - -const U3Let ex15_u3_rows[] = { - {"1.", "Meine Gr", "oß", "eltern fahr", "en", " ins Wochen", "end", - "haus.", NULL, NULL, - "Moji prarodiče jedou o víkendu do víkendového domu."}, - {"2.", "Mein ", "Va", "ter und mein", "e", " Mutter besuch", "en", - " ein Konz", "er", "t.", - "Můj otec a moje matka navštíví koncert."}, - {"3.", "Mein", "e", " Sch", "w", "ester geh", "t", " ins K", "in", "o.", - "Moje sestra jde do kina."}, - {"4.", "Mein Bru", "d", "er f", "äh", "rt an ", "ei", "nen S", "ee", - ".", - "Můj bratr jede k jezeru."}, - {"5.", "Und ich? Ich besuch", "e", " ein Einka", "ufs", "zentrum.", - NULL, NULL, NULL, NULL, - "A já? Navštívím obchodní centrum."}, -}; - -GtkWidget *u3ex15(UnitCtx *unit) { - return u3_build_letters(unit, 15, "Wochenende", "sub3_wochen", - ex15_u3_rows, G_N_ELEMENTS(ex15_u3_rows)); -} - -/* ------------------------------------------------------------------ */ -/* Unit 3 vocabulary (off-path Vokabeltraining branch) */ -/* ------------------------------------------------------------------ */ - -const TypedQ u3_trans_p32[] = { - {"die Geburtstagsparty, -s", - "narozeninová slavnost|narozeninová oslava|birthday party", - "narozeninová slavnost"}, - {"das Haustier, -e", "domácí zvíře|domácí mazlíček|pet", "domácí zvíře"}, -}; - -const TypedQ u3_trans_p33[] = { - {"die Aktivität, -en", "aktivita|činnost|activity", "aktivita"}, - {"der Stammbaum, Stammbäume", "rodokmen|family tree", "rodokmen"}, -}; - -const TypedQ u3_trans_p34[] = { - {"der Bruder, Brüder", "bratr|brother", "bratr"}, - {"der Cousin, -s", "bratranec|cousin", "bratranec"}, - {"die Cousine, -n", "sestřenice|cousin", "sestřenice"}, - {"die Ehefrau, -en", "manželka|žena|wife", "manželka"}, - {"der Ehemann, Ehemänner", "manžel|muž|husband", "manžel"}, - {"das Einzelkind, -er", "jedináček|only child", "jedináček"}, - {"die Eltern (mn. č.)", "rodiče|parents", "rodiče"}, - {"die Familie, -n", "rodina|family", "rodina"}, - {"feiern (Infinitiv)", "slavit|oslavovat|to celebrate", - "slavit, oslavovat"}, - {"das Fest, -e", "oslava|slavnost|svátek|celebration|festival", - "oslava, slavnost"}, - {"der Garten, Gärten", "zahrada|garden", "zahrada"}, - {"gehören (Infinitiv)", "patřit|to belong", "patřit"}, - {"Er gehört zur Familie.", "patří k rodině|he belongs to the family", - "Patří k rodině."}, - {"geschieden", "rozvedený|rozvedená|divorced", "rozvedený"}, - {"Meine Eltern sind geschieden.", - "moji rodiče jsou rozvedení|my parents are divorced", - "Moji rodiče jsou rozvedení."}, - {"die Geschwister (mn. č.)", "sourozenci|siblings", "sourozenci"}, - {"gleich", "stejný|rovný|same|equal", "stejný"}, - {"groß", "velký|big|large|tall", "velký"}, - {"haben (Infinitiv)", "mít|to have", "mít"}, - {"Unser Haus hat einen großen Garten.", - "náš dům má velkou zahradu|our house has a big garden", - "Náš dům má velkou zahradu."}, - {"das Haus, Häuser", "dům|house", "dům"}, - {"hier", "zde|tady|tu|here", "zde, tady"}, - {"der Hund, -e", "pes|dog", "pes"}, - {"ihr, ihre, ihr", "její|jejich|její, jejich|her|their", "její"}, - {"der Iran", "írán|iran", "Írán"}, - {"der Job, -s", "pracovní místo|zaměstnání|práce|job", - "(pracovní) místo, zaměstnání"}, - {"der Kater, -", "kocour|tomcat", "kocour"}, - {"lange", "dlouho|long", "dlouho"}, - {"manchmal", "někdy|občas|sometimes", "někdy, občas"}, - {"mehr", "více|víc|již|more", "více, již"}, - {"Ich bin kein Einzelkind mehr.", - "již nejsem jedináček|už nejsem jedináček|i am no longer an only child", - "Již nejsem jedináček."}, - {"nämlich", "totiž|namely", "totiž"}, - {"natürlich", "samozřejmě|přirozeně|of course|naturally", - "samozřejmě"}, - {"neu", "nový|new", "nový"}, - {"die Oma, -s", "babička|babi|grandma|grandmother", "babička"}, - {"der Onkel, -", "strýc|uncle", "strýc"}, - {"der Opa, -s", "dědeček|děda|grandpa|grandfather", "dědeček"}, - {"die Patchworkfamilie, -n", - "patchworková rodina|patchwork family|blended family", - "patchworková rodina"}, - {"Persisch", "perština|persky|persian", "perština, persky"}, - {"die Person, -en", "osoba|person", "osoba"}, - {"die Schwester, -n", "sestra|sister", "sestra"}, - {"sehen (Infinitiv)", "vidět|to see", "vidět"}, - {"Wir sehen sie manchmal in den Ferien.", - "vídáme je občas o prázdninách|vidíme je někdy o prázdninách|" - "we see them sometimes during the holidays", - "Vídáme je občas o prázdninách."}, - {"die Stiefmutter, Stiefmütter", - "nevlastní matka|macecha|stepmother", "nevlastní matka"}, - {"die Stiefschwester, -n", "nevlastní sestra|stepsister", - "nevlastní sestra"}, - {"die Tante, -n", "teta|téta|aunt", "teta"}, - {"die Tochter, Töchter", "dcera|daughter", "dcera"}, - {"tot", "mrtvý|dead", "mrtvý"}, - {"Er ist leider schon tot.", - "on je již bohužel mrtvý|je bohužel už mrtvý|" - "he is unfortunately already dead", "(On) Je již bohužel mrtvý."}, - {"typisch", "typický|klasický|typical", "typický, klasický"}, - {"unser, unsere, unser", "náš|naše|our", "náš, naše, naše"}, - {"der Vater, Väter", "otec|táta|father|dad", "otec"}, - {"verstehen sich", - "rozumět si|rozumí si|to get along|to understand each other", - "rozumět si"}, - {"Wir verstehen uns alle sehr gut.", - "všichni si moc dobře rozumíme|všichni si velmi dobře rozumíme|" - "we all get along very well", "Všichni si moc dobře rozumíme."}, - {"der/die Verwandte, -n", "příbuzný|příbuzná|relative", - "příbuzný/příbuzná"}, - {"die Wohngemeinschaft, -en", - "společné bydlení|spolubydlení|flat share|shared apartment", - "společné bydlení (studentů)"}, - {"die Männer-Wohngemeinschaft", - "mužská domácnost|mužské spolubydlení|men's shared flat", - "mužská domácnost"}, - {"zusammen", "spolu|dohromady|together", "spolu, dohromady"}, - {"der Zwilling, -e", "dvojče|dvojčata|twin|twins", "dvojče"}, -}; - -const TypedQ u3_trans_p35[] = { - {"dein, deine, dein", "tvůj|tvoje|your", "tvůj, tvoje, tvoje"}, - {"euer, eure, euer", "váš|vaše|your", "váš, vaše, vaše"}, - {"ihr, ihre, ihr", "jejich|její|their|her", "jejich"}, - {"sein, seine, sein", "jeho|his", "jeho"}, -}; - -const TypedQ u3_trans_p36[] = { - {"bitte", "prosím|please", "prosím"}, - {"dann", "tak|pak|then", "tak, pak"}, - {"dauern (Infinitiv)", "trvat|to last|to take", "trvat"}, - {"Die Vorbereitung dauert nicht so lange.", - "příprava netrvá moc dlouho|příprava netrvá tak dlouho|" - "the preparation doesn't take that long", - "Příprava netrvá moc dlouho."}, - {"doch", "přece|přeci|ale ano|yet|but", "přece"}, - {"einladen (Infinitiv)", "pozvat|zvát|to invite", "pozvat"}, - {"Wir laden Oma und Opa ein.", - "pozveme babičku a dědečka|zveme babičku a dědečka|" - "we invite grandma and grandpa", "Pozveme babičku a dědečka."}, - {"die Feier, -n", "oslava|slavnost|celebration|party", - "oslava, slavnost"}, - {"fragen (Infinitiv)", "ptát se|zeptat se|to ask", - "ptát se, zeptat se"}, - {"Ich frage meine Schwester.", - "zeptám se své sestry|ptám se své sestry|i ask my sister", - "Zeptám se své sestry."}, - {"der Geburtstag, -e", "narozeniny|birthday", "narozeniny"}, - {"grillen (Infinitiv)", "grilovat|to grill|to barbecue", "grilovat"}, - {"die Idee, -n", "nápad|myšlenka|idea", "nápad, myšlenka"}, - {"die Köchin, -nen", "kuchařka|cook|chef", "kuchařka"}, - {"der Kuchen, -", "koláč|moučník|dort|cake", "koláč, moučník"}, - {"das Menü, -s", "menu|jídelní lístek", "menu"}, - {"5-Gänge-Menü", "pětichodové menu|pětchodové menu|five-course menu", - "pětichodové menu"}, - {"ob", "zda|jestli|whether|if", "zda, jestli"}, - {"der Papa, -s", "tatínek|táta|dad|daddy", "tatínek"}, - {"die Party, -s", "party|večírek|oslava", "party, večírek"}, - {"das Restaurant", "restaurace|restaurant", "restaurace"}, - {"schrecklich", "strašný|hrozný|terrible|awful", "strašný, hrozný"}, - {"die Schwarzwälder Kirschtorte", - "schwarzwaldský dort|black forest cake", "Schwarzwaldský dort"}, - {"singen (Infinitiv)", "zpívat|to sing", "zpívat"}, - {"Wir singen Happy Birthday.", - "zpíváme happy birthday|we sing happy birthday", - "Zpíváme Happy Birthday."}, - {"stimmen (Infinitiv)", "souhlasit|to be right|to be correct", - "souhlasit"}, - {"Ja, stimmt.", - "ano, správně|ano, souhlasí|yes, that's right|yes, right", - "Ano, správně."}, - {"die Vorbereitung, -en", "příprava|preparation", "příprava"}, - {"wieder", "opět|zase|again", "opět, zase"}, - {"zu Hause", "doma|at home", "doma"}, -}; - -const TypedQ u3_trans_p37[] = { - {"das Chamäleon, -s", "chameleon|chameleón", "chameleon"}, - {"der Goldfisch, -e", "zlatá rybka|karas|goldfish", - "zlatá rybka (karas)"}, - {"der Hamster, -", "křeček|hamster", "křeček"}, - {"der Kanarienvogel, Kanarienvögel", "kanárek|kanár|canary", - "kanárek"}, - {"das Kaninchen, -", "králík|rabbit", "králík"}, - {"die Katze, -n", "kočka|cat", "kočka"}, - {"das Meerschweinchen, -", "morče|guinea pig", "morče"}, - {"das Pferd, -e", "kůň|horse", "kůň"}, - {"die Schildkröte, -n", "želva|turtle|tortoise", "želva"}, - {"das Tier, -e", "zvíře|animal", "zvíře"}, -}; - -const TypedQ u3_trans_p38[] = { - {"der Ausflug, Ausflüge", "výlet|trip|excursion", "výlet"}, - {"die Ausstellung, -en", "výstava|exhibition", "výstava"}, - {"die Burg, -en", "hrad|castle", "hrad"}, - {"cool", "cool|skvělý|super", "cool, skvělý"}, - {"es gibt", "je|existuje|there is|there are", "je, existuje"}, - {"das Hochzeitsfest, -e", - "svatební party|svatební oslava|wedding party", "svatební party"}, - {"die Hochzeitstorte, -n", "svatební dort|wedding cake", - "svatební dort"}, - {"nach", "do|to", "do"}, - {"Ich fahre nach Wien.", - "jedu do vídně|i go to vienna|i'm going to vienna", - "Jedu do Vídně."}, - {"nächster, nächste, nächstes", "příští|next", "příští"}, - {"nächsten Monat / nächste Woche / nächstes Jahr", - "příští měsíc / příští týden / příští rok|" - "příští měsíc, příští týden, příští rok|" - "next month / next week / next year|next month, next week, next year", - "příští měsíc / příští týden / příští rok"}, - {"das Schloss, Schlösser", "zámek|castle|palace", "zámek"}, - {"das Schwimmbad, Schwimmbäder", - "koupaliště|plavecký bazén|swimming pool", - "koupaliště, plavecký bazén"}, - {"der Schwimmbadbesuch, -e", - "návštěva koupaliště|návštěva plaveckého bazénu|" - "visit to the swimming pool", - "návštěva koupaliště, plaveckého bazénu"}, - {"schwimmen (Infinitiv)", "plavat|to swim", "plavat"}, - {"Meine Mutter schwimmt gern.", - "moje matka ráda plave|my mother likes swimming", - "Moje matka ráda plave."}, - {"shoppen (Infinitiv)", "nakupovat|to shop", "nakupovat"}, - {"Wir gehen shoppen.", "jdeme nakupovat|jdem nakupovat|we go shopping", - "Jdeme nakupovat."}, - {"das Sportevent, -s", - "sportovní akce|sportovní událost|sports event", - "sportovní akce (zápas, závody)"}, - {"der Vergnügungspark, -s", - "zábavní park|amusement park|theme park", "zábavní park"}, - {"Wir gehen in den Vergnügungspark.", - "jdeme do zábavního parku|we go to the amusement park", - "Jdeme do zábavního parku."}, - {"wandern (Infinitiv)", "putovat|cestovat|to hike|to wander", - "putovat, cestovat"}, - {"Ich wandere gern.", - "rád(a) putuji|rád putuji|ráda putuji|i like hiking", - "Rád(a) putuji."}, - {"die Woche, -n", "týden|week", "týden"}, - {"diese Woche", "tento týden|this week", "tento týden"}, - {"der Zoo, -s", "zoo|zoologická zahrada", "zoo"}, - {"der Zoobesuch, -e", "návštěva zoo|visit to the zoo", "návštěva zoo"}, -}; - -const TypedQ u3_trans_p39[] = { - {"das Einkaufszentrum", - "nákupní centrum|shopping centre|shopping mall|shopping center", - "nákupní centrum"}, - {"die Inliner (mn. č.)", - "inline brusle|inline bruslení|inliners", "inline brusle"}, - {"Sie fährt Inliner.", - "(ona) jezdí na inline bruslích|jezdí na inline bruslích|" - "she goes inline skating", "(Ona) Jezdí na inline bruslích."}, - {"der See, -n", "jezero|lake", "jezero"}, - {"Am Wochenende fahren wir an einen See.", - "o víkendu pojedeme k jezeru|o víkendu jedeme k jezeru|" - "at the weekend we drive to a lake", - "O víkendu pojedeme k (nějakému) jezeru."}, - {"das Wochenende, -n", "víkend|weekend", "víkend"}, - {"am Wochenende", "o víkendu|on the weekend", "o víkendu"}, - {"dieses Wochenende", "tento víkend|this weekend", "tento víkend"}, - {"das Wochenendhaus, Wochenendhäuser", - "chata|chalupa|víkendový dům|weekend house", "chata, chalupa"}, - {"Wir fahren dieses Wochenende ins Wochenendhaus.", - "tento víkend jedeme na chatu|tento víkend jedeme na chalupu|" - "this weekend we go to the cottage", "Tento víkend jedeme na chatu."}, -}; - -const TransSection u3_trans_sections[] = { - {"Strana 32", u3_trans_p32, (int)G_N_ELEMENTS(u3_trans_p32)}, - {"Strana 33", u3_trans_p33, (int)G_N_ELEMENTS(u3_trans_p33)}, - {"Strana 34", u3_trans_p34, (int)G_N_ELEMENTS(u3_trans_p34)}, - {"Strana 35", u3_trans_p35, (int)G_N_ELEMENTS(u3_trans_p35)}, - {"Strana 36", u3_trans_p36, (int)G_N_ELEMENTS(u3_trans_p36)}, - {"Strana 37", u3_trans_p37, (int)G_N_ELEMENTS(u3_trans_p37)}, - {"Strana 38", u3_trans_p38, (int)G_N_ELEMENTS(u3_trans_p38)}, - {"Strana 39", u3_trans_p39, (int)G_N_ELEMENTS(u3_trans_p39)}, -}; -const int u3_trans_sections_n = (int)G_N_ELEMENTS(u3_trans_sections); diff --git a/src/fyz_year1.c b/src/fyz_year1.c deleted file mode 100644 index e673180..0000000 --- a/src/fyz_year1.c +++ /dev/null @@ -1,615 +0,0 @@ -#include "graduately.h" - -/* Year 1: mechanics. Quantities, kinematics, dynamics, energy, - * gravitation, rigid bodies, fluids. */ - -NetLesson fyz_lessons[FYZ_N] = { - { .n_slides = 3, .unit_page = "fyzunit1", .ex_page = "fyzex1" }, - { .n_slides = 3, .unit_page = "fyzunit2", .ex_page = "fyzex2" }, - { .n_slides = 3, .unit_page = "fyzunit3", .ex_page = "fyzex3" }, - { .n_slides = 3, .unit_page = "fyzunit4", .ex_page = "fyzex4" }, - { .n_slides = 3, .unit_page = "fyzunit5", .ex_page = "fyzex5" }, - { .n_slides = 3, .unit_page = "fyzunit6", .ex_page = "fyzex6" }, - { .n_slides = 3, .unit_page = "fyzunit7", .ex_page = "fyzex7" }, - { .n_slides = 3, .unit_page = "fyzunit8", .ex_page = "fyzex8" }, -}; - -static GtkWidget *build_fyz_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Měření", "Veličina a jednotka", - "Tip: základní jednotka hmotnosti je kilogram, ne gram.", - { - "Fyzikální veličina má číselnou hodnotu a jednotku.", - "Soustava SI má sedm základních jednotek: m, kg, s, A, K, mol a cd.", - "Odvozené jednotky vznikají ze základních, třeba newton nebo joule.", - "Předpona kilo znamená tisíc, mili znamená tisícinu.", - NULL, - }, - }, - { - "2 / 3 • Druhy", "Skalár a vektor", - "Tip: rychlost jako vektor má velikost i směr.", - { - "Skalár má jen velikost. Patří sem hmotnost, čas nebo teplota.", - "Vektor má velikost i směr. Patří sem síla, rychlost a zrychlení.", - "Vektory se skládají podle rovnoběžníku.", - "Opačný vektor má stejnou velikost a opačný směr.", - NULL, - }, - }, - { - "3 / 3 • Přesnost", "Chyba měření", - "Tip: relativní chyba se často udává v procentech.", - { - "Každé měření má chybu. Opakování měření ji zmenšuje.", - "Absolutní chyba je rozdíl naměřené a správné hodnoty.", - "Relativní chyba je podíl absolutní chyby a správné hodnoty.", - "Výsledek se zaokrouhluje podle přesnosti měřidla.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[0], "fyz_unit1", "fyz_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Která jednotka je základní jednotka SI pro hmotnost?", - {"Gram", "Kilogram", "Newton", "Tuna"}, - 4, 1}, - {"Co má vektor navíc proti skaláru?", - {"Jen jednotku", "Směr", "Jen číselnou hodnotu", "Předponu kilo"}, - 4, 1}, - {"Co znamená předpona mili?", - {"Tisíc", "Milion", "Tisícinu", "Setinu"}, - 4, 2}, - {"Co je relativní chyba?", - {"Rozdíl naměřené a správné hodnoty", - "Podíl absolutní chyby a správné hodnoty", - "Součet všech měření", - "Nejmenší dílek měřidla"}, - 4, 1}, - }; - static const char *hints[] = { - "Gram je tisícina kilogramu. Newton je jednotka síly.", - "Hmotnost je skalár. Rychlost a síla jsou vektory.", - "Kilo je 1000, centi je 0,01, mili je 0,001.", - "Absolutní chyba je rozdíl. Relativní je tento rozdíl dělený správnou hodnotou.", - }; - - return fyz_mcq_page(0, 0, "fyzunit1", "fyz_ex1_title", "fyz_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Pohyb", "Dráha a rychlost", - "Tip: při rovnoměrném pohybu je rychlost stálá.", - { - "Trajektorie je čára, po které se bod pohybuje. Dráha je její délka.", - "Průměrná rychlost je dráha dělená časem.", - "Rovnoměrný přímočarý pohyb má stálou rychlost a přímou trajektorii.", - "Dráha rovnoměrného pohybu je s = v·t.", - NULL, - }, - }, - { - "2 / 3 • Změna rychlosti", "Zrychlení", - "Tip: jednotka zrychlení je metr za sekundu na druhou.", - { - "Zrychlení popisuje, jak rychle se mění rychlost.", - "Rovnoměrně zrychlený pohyb má stálé zrychlení.", - "Rychlost je v = v₀ + a·t.", - "Dráha z klidu je s = ½·a·t².", - NULL, - }, - }, - { - "3 / 3 • Pád", "Volný pád", - "Tip: tíhové zrychlení u Země je přibližně 9,81 m/s².", - { - "Volný pád je pohyb jen pod vlivem tíhového zrychlení.", - "Tíhové zrychlení g je u povrchu Země asi 9,81 m/s².", - "Odpor vzduchu volný pád zpomaluje. Ve vakuu padají tělesa stejně.", - "Graf rychlosti na čase je u rovnoměrně zrychleného pohybu přímka.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[1], "fyz_unit2", "fyz_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se počítá dráha rovnoměrného pohybu?", - {"s = v / t", "s = v·t", "s = a·t", "s = v·a"}, - 4, 1}, - {"Jaká je jednotka zrychlení?", - {"m/s", "m/s²", "N", "J"}, - 4, 1}, - {"Čemu se rovná rychlost rovnoměrně zrychleného pohybu?", - {"v = v₀ + a·t", "v = s·t", "v = a / t", "v = g·m"}, - 4, 0}, - {"Jak velké je tíhové zrychlení u povrchu Země?", - {"Asi 1 m/s²", "Asi 9,81 m/s²", "Asi 100 m/s²", "Přesně rychlost světla"}, - 4, 1}, - }; - static const char *hints[] = { - "Rychlost je dráha za čas, proto dráha je rychlost krát čas.", - "Zrychlení je změna rychlosti za čas, tedy metr za sekundu za sekundu.", - "Počáteční rychlost se k přírůstku a·t přičítá.", - "Škola používá g ≈ 9,81 m/s², často i přibližně 10 m/s².", - }; - - return fyz_mcq_page(0, 1, "fyzunit2", "fyz_ex2_title", "fyz_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • První zákon", "Setrvačnost", - "Tip: zákon platí v inerciální soustavě.", - { - "Těleso zůstává v klidu nebo v rovnoměrném přímočarém pohybu, dokud na ně nepůsobí výsledná síla.", - "Setrvačnost je snaha tělesa udržet svůj pohybový stav.", - "Hmotnost je míra setrvačnosti.", - "Inerciální soustava se vůči jiné inerciální nepohybuje se zrychlením.", - NULL, - }, - }, - { - "2 / 3 • Druhý zákon", "Síla a zrychlení", - "Tip: newton je síla, která hmotnosti 1 kg udělí zrychlení 1 m/s².", - { - "Výsledná síla je F = m·a.", - "Větší síla při stejné hmotnosti znamená větší zrychlení.", - "Větší hmotnost při stejné síle znamená menší zrychlení.", - "Jednotka síly je newton, N.", - NULL, - }, - }, - { - "3 / 3 • Třetí zákon", "Akce a reakce", - "Tip: obě síly působí na dvě různá tělesa.", - { - "Síly, kterými na sebe dvě tělesa působí, jsou stejně velké a opačně orientované.", - "Akce a reakce vznikají i zanikají současně.", - "Navzájem se neruší, protože každá působí na jiné těleso.", - "Hybnost je p = m·v. V izolované soustavě se hybnost zachovává.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[2], "fyz_unit3", "fyz_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co říká první Newtonův zákon?", - {"F = m·a", - "Těleso nemění pohybový stav, dokud na ně nepůsobí výsledná síla", - "Akce a reakce se sčítají na jednom tělese", - "Hybnost se vždy ztrácí"}, - 4, 1}, - {"Jak zní druhý Newtonův zákon?", - {"F = m / a", "F = m·a", "F = m·v", "F = a / m"}, - 4, 1}, - {"Na co působí akce a reakce?", - {"Na jedno a totéž těleso a ruší se", - "Na dvě různá tělesa", - "Jen na těleso v klidu", - "Jen ve směru tíhy"}, - 4, 1}, - {"Co je hybnost?", - {"m·a", "m·v", "F·t jen jako jednotka", "m·g·h"}, - 4, 1}, - }; - static const char *hints[] = { - "První zákon je zákon setrvačnosti. Druhý je F = m·a.", - "Newton je kg·m/s². Síla a zrychlení mají stejný směr.", - "Reakce není síla, která by na stejném tělese rušila akci.", - "Hybnost je vektor. Izolovaná soustava ji zachovává.", - }; - - return fyz_mcq_page(0, 2, "fyzunit3", "fyz_ex3_title", "fyz_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tíha", "Tíhová a třecí síla", - "Tip: tíhová síla je G = m·g.", - { - "Tíhová síla působí svisle dolů a je G = m·g.", - "Třecí síla působí proti pohybu nebo proti snaze o pohyb.", - "Smykové tření závisí na normálové síle a na součiniteli tření.", - "Valivé tření je obvykle menší než smykové.", - NULL, - }, - }, - { - "2 / 3 • Tlak", "Síla na plochu", - "Tip: pascal je newton na metr čtvereční.", - { - "Tlak je p = F / S, kde S je obsah plochy.", - "Stejná síla na menší plochu znamená větší tlak.", - "Jednotka tlaku je pascal, Pa.", - "Ostrý hrot má malou plochu, proto velký tlak.", - NULL, - }, - }, - { - "3 / 3 • Skládání", "Výslednice sil", - "Tip: dvě stejně velké opačné síly dají nulu.", - { - "Síly stejného směru se sčítají.", - "Síly opačného směru se odečítají.", - "Kolmé síly se skládají podle Pythagorovy věty.", - "Rovnováha nastane, když je výslednice nulová.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[3], "fyz_unit4", "fyz_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se počítá tíhová síla?", - {"G = m / g", "G = m·g", "G = m·v", "G = F / S"}, - 4, 1}, - {"Na čem závisí smykové tření?", - {"Jen na barvě tělesa", - "Na normálové síle a součiniteli tření", - "Jen na objemu", - "Na rychlosti světla"}, - 4, 1}, - {"Jak se počítá tlak?", - {"p = F·S", "p = F / S", "p = m·a", "p = S / F"}, - 4, 1}, - {"Jaká je jednotka tlaku?", - {"Newton", "Pascal", "Joule", "Watt"}, - 4, 1}, - }; - static const char *hints[] = { - "g je tíhové zrychlení. Tíha má směr svisle dolů.", - "Ft = f·Fn. Drsnější styk má větší součinitel tření.", - "Menší plocha při stejné síle zvětší tlak.", - "1 Pa = 1 N/m². Atmosférický tlak je asi 101 kPa.", - }; - - return fyz_mcq_page(0, 3, "fyzunit4", "fyz_ex4_title", "fyz_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Práce", "Síla po dráze", - "Tip: síla kolmá k posunutí práci nekoná.", - { - "Mechanická práce je W = F·s·cos α.", - "α je úhel mezi silou a posunutím.", - "Když je síla kolmá k posunutí, práce je nulová.", - "Jednotka práce je joule, J.", - NULL, - }, - }, - { - "2 / 3 • Energie", "Pohybová a polohová", - "Tip: polohová energie roste s výškou.", - { - "Kinetická energie je Ek = ½·m·v².", - "Polohová energie v tíhovém poli je Ep = m·g·h.", - "Výšku h počítáme od zvolené hladiny.", - "Bez tření se součet kinetické a polohové energie zachovává.", - NULL, - }, - }, - { - "3 / 3 • Výkon", "Práce za čas", - "Tip: watt je joule za sekundu.", - { - "Výkon je P = W / t.", - "Jednotka výkonu je watt, W.", - "Účinnost je podíl užitečné a dodané energie.", - "Účinnost je vždy menší než 1, protože část energie se ztrácí.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[4], "fyz_unit5", "fyz_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy je mechanická práce nulová?", - {"Když je síla rovnoběžná s posunutím", - "Když je síla kolmá k posunutí", - "Když je hmotnost velká", - "Když je výkon 1 W"}, - 4, 1}, - {"Jak se počítá kinetická energie?", - {"Ek = m·g·h", "Ek = ½·m·v²", "Ek = F / s", "Ek = m·v"}, - 4, 1}, - {"Jak se počítá polohová energie v tíhovém poli?", - {"Ep = ½·m·v²", "Ep = m·g·h", "Ep = F·a", "Ep = p·V"}, - 4, 1}, - {"Co je výkon?", - {"Práce dělená časem", "Síla dělená plochou", - "Hmotnost krát zrychlení", "Hybnost za dráhu"}, - 4, 0}, - }; - static const char *hints[] = { - "cos 90° je 0, proto kolmá síla práci nekoná.", - "Dvojnásobná rychlost znamená čtyřnásobnou kinetickou energii.", - "Hladinu nulové polohové energie si volíme.", - "Watt je J/s. Účinnost je podíl energií, ne jejich součet.", - }; - - return fyz_mcq_page(0, 4, "fyzunit5", "fyz_ex5_title", "fyz_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Zákon", "Newtonova gravitace", - "Tip: gravitační síla klesá s druhou mocninou vzdálenosti.", - { - "Dvě tělesa se přitahují silou Fg = κ·m₁·m₂ / r².", - "κ je gravitační konstanta, asi 6,67·10⁻¹¹ N·m²/kg².", - "r je vzdálenost středů těles.", - "Gravitace působí na dálku a je vždy přitažlivá.", - NULL, - }, - }, - { - "2 / 3 • U Země", "Tíhové zrychlení", - "Tip: první kosmická rychlost je asi 7,9 km/s.", - { - "U povrchu Země je tíhové zrychlení přibližně 9,81 m/s².", - "Tíhová síla je výslednice gravitační síly a setrvačné síly od otáčení Země.", - "První kosmická rychlost je rychlost kruhové dráhy těsně u povrchu, asi 7,9 km/s.", - "Druhá kosmická rychlost, asi 11,2 km/s, stačí k opuštění Země.", - NULL, - }, - }, - { - "3 / 3 • Pohyby", "Keplerovy zákony", - "Tip: planety obíhají po elipsách, Slunce je v ohnisku.", - { - "Planety se pohybují po elipsách a Slunce je v jednom ohnisku.", - "Průvodič planety opíše za stejný čas stejnou plochu.", - "Poměr krychle velké poloosy a čtverce oběžné doby je pro planety stejný.", - "Družice padá kolem Země, proto zůstává na oběžné dráze.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[5], "fyz_unit6", "fyz_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak závisí gravitační síla na vzdálenosti?", - {"Je přímo úměrná vzdálenosti", - "Je nepřímo úměrná druhé mocnině vzdálenosti", - "Na vzdálenosti nezávisí", - "Je úměrná třetí mocnině vzdálenosti"}, - 4, 1}, - {"Jaká je přibližně gravitační konstanta κ?", - {"9,81", "6,67·10⁻¹¹ N·m²/kg²", "3·10⁸ m/s", "101 kPa"}, - 4, 1}, - {"Co je první kosmická rychlost?", - {"Rychlost světla", - "Rychlost kruhové dráhy těsně u Země, asi 7,9 km/s", - "Rychlost zvuku", - "Rychlost volného pádu z 1 m"}, - 4, 1}, - {"Jaký tvar mají dráhy planet podle Keplera?", - {"Kružnice se Sluncem ve středu vždy", - "Elipsy a Slunce je v ohnisku", - "Přímky", - "Paraboly se Zemí v ohnisku"}, - 4, 1}, - }; - static const char *hints[] = { - "Dvojnásobná vzdálenost znamená čtvrtinovou sílu.", - "κ je velmi malé číslo. g = 9,81 m/s² je zrychlení, ne konstanta κ.", - "Druhá kosmická rychlost je asi 11,2 km/s.", - "První Keplerův zákon mluví o elipse a ohnisku.", - }; - - return fyz_mcq_page(0, 5, "fyzunit6", "fyz_ex6_title", "fyz_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Otáčení", "Moment síly", - "Tip: moment je větší, když síla zabírá dál od osy.", - { - "Tuhé těleso nemění působením sil svůj tvar.", - "Moment síly je M = F·d, kde d je rameno síly.", - "Rameno je kolmá vzdálenost osy od přímky síly.", - "Jednotka momentu je newton metr, N·m.", - NULL, - }, - }, - { - "2 / 3 • Páka", "Rovnováha", - "Tip: na páce v rovnováze jsou momenty na obou stranách stejné.", - { - "Těleso je v rovnováze, když je výslednice sil i výsledný moment nulový.", - "Na dvojzvratné páce platí F₁·d₁ = F₂·d₂.", - "Páka, kladka a nakloněná rovina jsou jednoduché stroje.", - "Jednoduchý stroj práci neušetří, jen změní velikost síly nebo dráhu.", - NULL, - }, - }, - { - "3 / 3 • Těžiště", "Stabilita", - "Tip: těleso je stabilní, když se po malém vychýlení vrací.", - { - "Těžiště je působiště tíhové síly.", - "U stejnorodého pravidelného tělesa je těžiště ve středu.", - "Stabilní poloha se po vychýlení vrací, labilní se převrací.", - "Nízké těžiště a široká základna zvětšují stabilitu.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[6], "fyz_unit7", "fyz_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se počítá moment síly?", - {"M = F / d", "M = F·d", "M = m·g·h", "M = p·V"}, - 4, 1}, - {"Kdy je páka v rovnováze?", - {"Když jsou síly vždy stejně velké bez ohledu na rameno", - "Když se momenty na obou stranách rovnají", - "Když je jedno rameno nulové", - "Když páka koná práci zdarma"}, - 4, 1}, - {"Co je těžiště?", - {"Místo největšího tlaku kapaliny", - "Působiště tíhové síly", - "Ohnisko elipsy", - "Střed elektrického náboje"}, - 4, 1}, - {"Která poloha je stabilní?", - {"Po malém vychýlení se těleso vrací", - "Po malém vychýlení se těleso převrátí", - "Těleso zůstane v nové poloze vždy", - "Těžiště je nad bodem dotyku co nejvýš a základna je bod"}, - 4, 0}, - }; - static const char *hints[] = { - "Delší rameno znamená větší moment při stejné síle.", - "F₁·d₁ = F₂·d₂. Menší silou na delším rameni zvedneme větší náklad.", - "Těleso se chová, jako by v těžišti působila celá tíha.", - "Labilní poloha se po vychýlení vzdaluje. Volná zůstane, kde je.", - }; - - return fyz_mcq_page(0, 6, "fyzunit7", "fyz_ex7_title", "fyz_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tlak", "Hydrostatický tlak", - "Tip: tlak v kapalině roste s hloubkou.", - { - "Tlak v kapalině způsobený tíhou je p = h·ρ·g.", - "h je hloubka, ρ je hustota kapaliny.", - "V téže hloubce je tlak ve všech směrech stejný.", - "Pascalův zákon: tlak v uzavřené kapalině se šíří všemi směry stejně.", - NULL, - }, - }, - { - "2 / 3 • Vztlak", "Archimédův zákon", - "Tip: těleso plave, když se jeho průměrná hustota rovná hustotě kapaliny nebo je menší.", - { - "Na těleso v tekutině působí vztlaková síla svisle vzhůru.", - "Vztlak se rovná tíze tekutiny tělesem vytlačené.", - "Těleso se potápí, když je jeho hustota větší než hustota tekutiny.", - "Těleso se vznáší, když jsou hustoty stejné.", - NULL, - }, - }, - { - "3 / 3 • Plyny", "Atmosféra a proudění", - "Tip: normální atmosférický tlak je asi 101,3 kPa.", - { - "Atmosférický tlak u hladiny moře je přibližně 101,3 kPa.", - "S výškou atmosférický tlak klesá.", - "V užší části trubice proudí kapalina rychleji a tlak tam klesá.", - "Na tom stojí vztlak křídla i rozprašovač.", - NULL, - }, - }, - }; - - return fyz_unit_page(0, &fyz_lessons[7], "fyz_unit8", "fyz_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se počítá hydrostatický tlak?", - {"p = h / ρ", "p = h·ρ·g", "p = F·S", "p = m·v"}, - 4, 1}, - {"Co říká Archimédův zákon?", - {"Vztlak se rovná tíze vytlačené tekutiny", - "Tlak nezávisí na hloubce", - "Kapaliny se nedají stlačit vůbec a nemají vztlak", - "Vztlak působí dolů"}, - 4, 0}, - {"Kdy se těleso v kapalině potápí?", - {"Když má menší hustotu než kapalina", - "Když má větší hustotu než kapalina", - "Když má stejnou hustotu", - "Když je hladina v klidu"}, - 4, 1}, - {"Jak velký je přibližně normální atmosférický tlak?", - {"1 Pa", "101 kPa", "9,81 Pa", "6,67·10⁻¹¹ Pa"}, - 4, 1}, - }; - static const char *hints[] = { - "Hustší kapalina a větší hloubka znamenají větší tlak.", - "Vytlačená tekutina má objem ponořené části tělesa.", - "Vznášení je při stejné hustotě. Plování je při menší průměrné hustotě.", - "1013 hPa je totéž co asi 101,3 kPa.", - }; - - return fyz_mcq_page(0, 7, "fyzunit8", "fyz_ex8_title", "fyz_quiz8_head", - qs, hints, 4); -} - -void add_fyz_pages(GtkStack *stack) { - typedef GtkWidget *(*FyzBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - FyzBuilder build_unit; - FyzBuilder build_ex; - } pages[] = { - {"fyzunit1", "fyzex1", build_fyz_unit1_page, build_fyz_unit1_exercise_page}, - {"fyzunit2", "fyzex2", build_fyz_unit2_page, build_fyz_unit2_exercise_page}, - {"fyzunit3", "fyzex3", build_fyz_unit3_page, build_fyz_unit3_exercise_page}, - {"fyzunit4", "fyzex4", build_fyz_unit4_page, build_fyz_unit4_exercise_page}, - {"fyzunit5", "fyzex5", build_fyz_unit5_page, build_fyz_unit5_exercise_page}, - {"fyzunit6", "fyzex6", build_fyz_unit6_page, build_fyz_unit6_exercise_page}, - {"fyzunit7", "fyzex7", build_fyz_unit7_page, build_fyz_unit7_exercise_page}, - {"fyzunit8", "fyzex8", build_fyz_unit8_page, build_fyz_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/fyz_year2.c b/src/fyz_year2.c deleted file mode 100644 index 9110f4f..0000000 --- a/src/fyz_year2.c +++ /dev/null @@ -1,621 +0,0 @@ -#include "graduately.h" - -/* Year 2: kinetic theory, heat, the structure of matter, changes of - * state, mechanical oscillation and waves, sound. */ - -NetLesson fyz2_lessons[FYZ_N] = { - { .n_slides = 3, .unit_page = "fyz2unit1", .ex_page = "fyz2ex1" }, - { .n_slides = 3, .unit_page = "fyz2unit2", .ex_page = "fyz2ex2" }, - { .n_slides = 3, .unit_page = "fyz2unit3", .ex_page = "fyz2ex3" }, - { .n_slides = 3, .unit_page = "fyz2unit4", .ex_page = "fyz2ex4" }, - { .n_slides = 3, .unit_page = "fyz2unit5", .ex_page = "fyz2ex5" }, - { .n_slides = 3, .unit_page = "fyz2unit6", .ex_page = "fyz2ex6" }, - { .n_slides = 3, .unit_page = "fyz2unit7", .ex_page = "fyz2ex7" }, - { .n_slides = 3, .unit_page = "fyz2unit8", .ex_page = "fyz2ex8" }, -}; - -static GtkWidget *build_fyz2_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Částice", "Z čeho je látka", - "Tip: částice se neustále neuspořádaně pohybují.", - { - "Látky se skládají z atomů, molekul nebo iontů.", - "Částice se neuspořádaně pohybují. Tomu říkáme tepelný pohyb.", - "Mezi částicemi působí přitažlivé i odpudivé síly.", - "Brownův pohyb a difuze jsou důkazy pohybu částic.", - NULL, - }, - }, - { - "2 / 3 • Skupenství", "Pevné, kapalné, plynné", - "Tip: v plynu jsou částice daleko od sebe a nevyplňují stálý tvar.", - { - "V pevné látce částice kmitají kolem rovnovážných poloh.", - "V kapalině jsou částice blízko, ale mohou se přesouvat.", - "V plynu se částice pohybují volně a narážejí do stěn.", - "Plazma je ionizovaný plyn a bývá čtvrté skupenství.", - NULL, - }, - }, - { - "3 / 3 • Energie", "Vnitřní energie", - "Tip: vnitřní energie roste s teplotou.", - { - "Vnitřní energie je součet kinetické a potenciální energie částic.", - "Teplo je energie předaná díky rozdílu teplot.", - "Práce i teplo mohou vnitřní energii změnit.", - "Teplota popisuje stav, teplo popisuje děj.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[0], "fyz2_unit1", "fyz2_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co dokazuje Brownův pohyb?", - {"Že částice stojí", "Že se částice neustále pohybují", - "Že světlo je vlna", "Že tlak nezávisí na teplotě"}, - 4, 1}, - {"Jak se částice chovají v pevné látce?", - {"Volně létají nádobou", - "Kmitají kolem rovnovážných poloh", - "Nemají žádnou energii", - "Jsou od sebe jako v řídkém plynu"}, - 4, 1}, - {"Co je teplo?", - {"Stavová veličina stejná jako teplota", - "Energie předaná díky rozdílu teplot", - "Hmotnost částic", - "Tlak nasycené páry"}, - 4, 1}, - {"Co je vnitřní energie?", - {"Jen polohová energie celého tělesa m·g·h", - "Součet kinetické a potenciální energie částic", - "Práce tíhové síly", - "Výkon ohřívače"}, - 4, 1}, - }; - static const char *hints[] = { - "Pylová zrnka ve vodě poskakují, protože do nich narážejí molekuly.", - "Kapalina teče, plyn vyplní nádobu. Pevná látka drží tvar.", - "Teplota je stav. Teplo je přenos energie.", - "Zahřátí zvýší kinetickou energii částic, a tím vnitřní energii.", - }; - - return fyz_mcq_page(1, 0, "fyz2unit1", "fyz2_ex1_title", "fyz2_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz2_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Stupnice", "Celsiova a termodynamická", - "Tip: 0 °C je 273,15 K. Velikost jednoho stupně je stejná.", - { - "Celsiova teplota má nulu při tání ledu a 100 °C při varu vody za normálního tlaku.", - "Termodynamická teplota T se měří v kelvinech.", - "T = t + 273,15. Absolutní nula je 0 K, tedy −273,15 °C.", - "Částice se při absolutní nule nezastaví úplně, ale klasická teorie tam končí.", - NULL, - }, - }, - { - "2 / 3 • Teplo", "Kalorimetrická rovnice", - "Tip: měrná tepelná kapacita vody je asi 4180 J/(kg·K).", - { - "Teplo přijaté tělesem je Q = m·c·Δt.", - "c je měrná tepelná kapacita, u vody přibližně 4180 J/(kg·K).", - "Tepelná kapacita C = m·c říká, kolik tepla ohřeje těleso o 1 K.", - "V izolované soustavě je teplo odevzdané rovno teplu přijatému.", - NULL, - }, - }, - { - "3 / 3 • Přenos", "Vedení, proudění, záření", - "Tip: vakuum nevede teplo částicemi, záření jím projde.", - { - "Vedení přenáší energii srážkami částic, hlavně v pevných látkách.", - "Proudění přenáší teplo pohybem kapaliny nebo plynu.", - "Záření přenáší energii elektromagnetickými vlnami i ve vakuu.", - "Kovy vedou teplo dobře, vzduch a pěnové izolace špatně.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[1], "fyz2_unit2", "fyz2_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kolik kelvinů je 0 °C?", - {"0 K", "100 K", "273,15 K", "373,15 K"}, - 4, 2}, - {"Jak se počítá přijaté teplo?", - {"Q = m·c·Δt", "Q = m·g·h", "Q = ½·m·v²", "Q = p·V"}, - 4, 0}, - {"Jaká je přibližně měrná tepelná kapacita vody?", - {"4180 J/(kg·K)", "9,81 J/(kg·K)", "101 J/(kg·K)", "3·10⁸ J/(kg·K)"}, - 4, 0}, - {"Který přenos tepla funguje i ve vakuu?", - {"Vedení", "Proudění", "Záření", "Difuzi částic"}, - 4, 2}, - }; - static const char *hints[] = { - "100 °C je 373,15 K. Rozdíl 1 °C je stejný jako rozdíl 1 K.", - "Δt je změna teploty. Větší hmotnost i větší c znamenají více tepla.", - "Voda má velkou měrnou tepelnou kapacitu, proto se ohřívá pomalu.", - "Vedení a proudění potřebují látku. Záření ne.", - }; - - return fyz_mcq_page(1, 1, "fyz2unit2", "fyz2_ex2_title", "fyz2_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz2_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Kalorimetr", "Směšovací rovnice", - "Tip: teplejší těleso teplo odevzdá, chladnější přijme.", - { - "V izolované soustavě platí Q odevzdané = Q přijaté.", - "Při smíchání dvou dávek téže kapaliny je m₁·c·(t₁ − t) = m₂·c·(t − t₂).", - "c se u stejné látky zkrátí.", - "Kalorimetr sám také přijme část tepla. Přesný výpočet s ním počítá.", - NULL, - }, - }, - { - "2 / 3 • Skupenství", "Teplo bez změny teploty", - "Tip: při tání a varu se teplota čisté látky nemění.", - { - "Skupenské teplo tání je Lt = m·lt.", - "Skupenské teplo varu je Lv = m·lv.", - "Měrné skupenské teplo tání ledu je asi 334 kJ/kg.", - "Měrné skupenské teplo varu vody je asi 2,26 MJ/kg.", - NULL, - }, - }, - { - "3 / 3 • 1. věta", "Zákon zachování", - "Tip: perpetuum mobile prvního druhu odporuje první větě.", - { - "První termodynamická věta: ΔU = W + Q.", - "Znaménka závisí na dohodě, škola často bere teplo přijaté a práci vykonanou na soustavě.", - "Energie nevzniká ani nezaniká, jen se přeměňuje.", - "Stroj nemůže trvale konat práci bez přísunu energie.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[2], "fyz2_unit3", "fyz2_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co platí v izolované soustavě při výměně tepla?", - {"Teplo odevzdané je větší než přijaté", - "Teplo odevzdané se rovná teplu přijatému", - "Teplota obou těles zůstane původní", - "Hmotnost se zdvojnásobí"}, - 4, 1}, - {"Co se děje s teplotou čisté látky při tání?", - {"Stoupá rovnoměrně", "Nemění se, dokud látka taje", - "Klesá k absolutní nule", "Skáče o 100 K"}, - 4, 1}, - {"Jak se počítá skupenské teplo tání?", - {"Lt = m·c·Δt", "Lt = m·lt", "Lt = p·V", "Lt = ½·m·v²"}, - 4, 1}, - {"Co říká první termodynamická věta?", - {"Teplo se nedá nikam předat", - "Změna vnitřní energie souvisí s teplem a prací", - "Teplota je vždy 273 K", - "Účinnost tepelného stroje je 100 %"}, - 4, 1}, - }; - static const char *hints[] = { - "Kalorimetrická rovnice z toho přímo vychází.", - "Dodávané teplo při tání rozrušuje vazby, nezvedá teplotu.", - "lt je měrné skupenské teplo tání. U ledu asi 334 kJ/kg.", - "Druhá věta omezuje, kolik tepla lze proměnit v práci.", - }; - - return fyz_mcq_page(1, 2, "fyz2unit3", "fyz2_ex3_title", "fyz2_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz2_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Model", "Ideální plyn", - "Tip: stavová rovnice je p·V = n·R·T.", - { - "Ideální plyn má zanedbatelný vlastní objem částic a srážky bez ztráty kinetické energie.", - "Stavová rovnice je p·V = n·R·T.", - "R je molární plynová konstanta, asi 8,31 J/(mol·K).", - "T v této rovnici musí být v kelvinech.", - NULL, - }, - }, - { - "2 / 3 • Děje", "Izochorický, izobarický, izotermický", - "Tip: izotermický děj má stálou teplotu, proto p·V je konstantní.", - { - "Izochorický děj má stálý objem. Platí p / T = konst.", - "Izobarický děj má stálý tlak. Platí V / T = konst.", - "Izotermický děj má stálou teplotu. Platí p·V = konst.", - "Adiabatický děj nevyměňuje teplo s okolím.", - NULL, - }, - }, - { - "3 / 3 • Tlak plynu", "Odkud se bere", - "Tip: vyšší teplota znamená rychlejší částice a větší tlak.", - { - "Tlak plynu vzniká nárazy částic na stěnu.", - "Střední kinetická energie částice je úměrná termodynamické teplotě.", - "Normální podmínky jsou 0 °C a normální atmosférický tlak.", - "Reálný plyn se ideálnímu blíží při nízkém tlaku a vyšší teplotě.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[3], "fyz2_unit4", "fyz2_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak zní stavová rovnice ideálního plynu?", - {"p·V = n·R·T", "p / V = T", "Q = m·c·Δt", "F = m·a"}, - 4, 0}, - {"Co je stálé při izotermickém ději?", - {"Objem", "Tlak", "Teplota", "Hmotnost částice"}, - 4, 2}, - {"Co platí při izochorickém ději?", - {"V / T = konst.", "p / T = konst.", "p·V = konst.", "p·T = V"}, - 4, 1}, - {"V jakých jednotkách musí být T ve stavové rovnici?", - {"Ve stupních Celsia", "V kelvinech", "Ve wattech", "V pascalech"}, - 4, 1}, - }; - static const char *hints[] = { - "n je látkové množství, R ≈ 8,31 J/(mol·K).", - "Boylův-Mariottův zákon: p·V = konst. při stálé teplotě.", - "Izochorický znamená stálý objem. Zahřátí zvedne tlak.", - "Dosazení Celsiovy teploty do p·V = n·R·T je chyba.", - }; - - return fyz_mcq_page(1, 3, "fyz2unit4", "fyz2_ex4_title", "fyz2_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz2_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Deformace", "Hookův zákon", - "Tip: v pružné oblasti je prodloužení úměrné síle.", - { - "Deformace je změna tvaru nebo objemu.", - "Pružná deformace zmizí, až síla přestane působit.", - "Tvárná deformace zůstane.", - "Hookův zákon: F = k·Δl. k je tuhost.", - NULL, - }, - }, - { - "2 / 3 • Krystal", "Pevné látky", - "Tip: amorfní látka nemá pravidelnou mřížku v celém objemu.", - { - "Krystal má částice v pravidelné mřížce.", - "Amorfní látka, třeba sklo, pravidelnou mřížku na velkou vzdálenost nemá.", - "Teplotní roztažnost zvětšuje rozměry při zahřátí.", - "Dilatace mostů a kolejí počítá s mezerami.", - NULL, - }, - }, - { - "3 / 3 • Povrch", "Kapaliny", - "Tip: kapka je kulatá, protože povrchová vrstva se stahuje.", - { - "Povrchová vrstva kapaliny se chová jako tenká blána.", - "Povrchové napětí stahuje povrch na co nejmenší obsah.", - "Kapilární elevace zvedá smáčivou kapalinu v úzké trubici.", - "Kapilární deprese stahuje nesmáčivou kapalinu, třeba rtuť ve skle.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[4], "fyz2_unit5", "fyz2_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co říká Hookův zákon v pružné oblasti?", - {"Síla je úměrná prodloužení", - "Síla je úměrná druhé mocnině prodloužení vždy", - "Deformace je vždy trvalá", - "Tlak nezávisí na síle"}, - 4, 0}, - {"Čím se krystal liší od amorfní látky?", - {"Nemá částice", - "Má pravidelnou mřížku", - "Nemá teplotní roztažnost", - "Je vždy plyn"}, - 4, 1}, - {"Proč má kapka kulový tvar?", - {"Protože povrchová vrstva stahuje povrch", - "Protože v kapalině není tlak", - "Protože kapka je krystal", - "Protože Hookův zákon platí jen pro koule"}, - 4, 0}, - {"Co je kapilární elevace?", - {"Pokles nesmáčivé kapaliny", - "Vzestup smáčivé kapaliny v úzké trubici", - "Var při nízkém tlaku", - "Trvalá deformace"}, - 4, 1}, - }; - static const char *hints[] = { - "Za mezí pružnosti už závislost není přímá a těleso se nevrátí.", - "Sklo je typická amorfní látka. Sůl je krystal.", - "Koule má při daném objemu nejmenší povrch.", - "Deprese je pokles, třeba rtuti. Elevace je vzestup, třeba vody.", - }; - - return fyz_mcq_page(1, 4, "fyz2unit5", "fyz2_ex5_title", "fyz2_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz2_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tání a tuhnutí", "Pevná látka a kapalina", - "Tip: teplota tání a teplota tuhnutí téže látky jsou stejné.", - { - "Tání mění pevnou látku na kapalinu při teplotě tání.", - "Tuhnutí je opačný děj a u čisté látky probíhá při stejné teplotě.", - "Příměsi teplotu tání obvykle snižují.", - "Led potřebuje skupenské teplo tání, proto směs ledu a vody drží 0 °C.", - NULL, - }, - }, - { - "2 / 3 • Vypařování", "Var a pára", - "Tip: var nastane, když se tlak syté páry rovná vnějšímu tlaku.", - { - "Vypařování probíhá z povrchu při každé teplotě.", - "Var probíhá v celém objemu při teplotě varu.", - "Sytá pára je v rovnováze se svou kapalinou.", - "Nižší vnější tlak znamená nižší teplotu varu.", - NULL, - }, - }, - { - "3 / 3 • Vlhkost", "Pára ve vzduchu", - "Tip: relativní vlhkost 100 % znamená, že pára je sytá.", - { - "Absolutní vlhkost udává hmotnost vodní páry v objemu vzduchu.", - "Relativní vlhkost je podíl tlaku páry a tlaku syté páry při dané teplotě.", - "Rosný bod je teplota, při které se pára ve vzduchu stane sytou.", - "Kondenzace je vznik kapaliny z páry.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[5], "fyz2_unit6", "fyz2_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Při jaké teplotě tuhne čistá voda za normálního tlaku?", - {"Při 100 °C", "Při 0 °C", "Při −273,15 °C", "Při teplotě varu rtuti"}, - 4, 1}, - {"Čím se var liší od vypařování?", - {"Var probíhá jen na povrchu a při každé teplotě", - "Var probíhá v celém objemu při teplotě varu", - "Var nepotřebuje skupenské teplo", - "Vypařování nastane jen při 100 °C"}, - 4, 1}, - {"Kdy nastane var?", - {"Když je tlak syté páry roven vnějšímu tlaku", - "Když je relativní vlhkost nulová", - "Když klesne teplota k rosnému bodu", - "Když je látka amorfní"}, - 4, 0}, - {"Co je relativní vlhkost 100 %?", - {"Ve vzduchu není žádná pára", - "Pára ve vzduchu je sytá", - "Teplota je 100 °C", - "Tlak je 100 Pa"}, - 4, 1}, - }; - static const char *hints[] = { - "Tání a tuhnutí čisté vody jsou při 0 °C. Var je při 100 °C.", - "Vypařování je povrchové a děje se i pod teplotou varu.", - "Na horách je nižší tlak, proto voda vře při nižší teplotě.", - "Rosný bod je teplota, při níž relativní vlhkost dosáhne 100 %.", - }; - - return fyz_mcq_page(1, 5, "fyz2unit6", "fyz2_ex6_title", "fyz2_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz2_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Oscilátor", "Perioda a frekvence", - "Tip: frekvence je převrácená hodnota periody.", - { - "Kmitání je pohyb, který se po periodě opakuje.", - "Perioda T je doba jednoho kmitu. Frekvence f = 1 / T.", - "Jednotka frekvence je hertz, Hz.", - "Harmonické kmitání popisuje sinus nebo kosinus.", - NULL, - }, - }, - { - "2 / 3 • Dva oscilátory", "Pružina a kyvadlo", - "Tip: perioda kyvadla nezávisí na hmotnosti závaží.", - { - "Pružinový oscilátor má T = 2π·√(m / k).", - "Matematické kyvadlo má pro malé výchylky T = 2π·√(l / g).", - "Delší kyvadlo kmitá pomaleji.", - "Větší g znamená kratší periodu kyvadla.", - NULL, - }, - }, - { - "3 / 3 • Rezonance", "Vlastní a nucené kmitání", - "Tip: rezonance nastane, když budicí frekvence souhlasí s vlastní.", - { - "Vlastní frekvence patří volnému oscilátoru.", - "Nucené kmitání udržuje vnější síla.", - "Při rezonanci amplituda silně vzroste.", - "Tlumení energii kmitů odebírá a amplitudu zmenšuje.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[6], "fyz2_unit7", "fyz2_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak spolu souvisí frekvence a perioda?", - {"f = T", "f = 1 / T", "f = T²", "f = 2π·T"}, - 4, 1}, - {"Na čem závisí perioda matematického kyvadla?", - {"Na hmotnosti závaží a na barvě", - "Na délce a na tíhovém zrychlení", - "Jen na amplitudě při velkých úhlech jako jediném údaji", - "Na tlaku vzduchu jako na hlavní veličině"}, - 4, 1}, - {"Jak se změní perioda, když kyvadlo prodloužíme?", - {"Zkrátí se", "Prodlouží se", "Nezmění se", "Stane se nulovou"}, - 4, 1}, - {"Kdy nastane rezonance?", - {"Když je budicí frekvence rovna vlastní frekvenci", - "Když je tlumení nekonečné", - "Když oscilátor stojí", - "Když je perioda rovna vlnové délce"}, - 4, 0}, - }; - static const char *hints[] = { - "10 Hz znamená 10 kmitů za sekundu, perioda je 0,1 s.", - "Vzorec T = 2π·√(l / g) hmotnost neobsahuje.", - "Pod odmocninou je délka. Delší l znamená větší T.", - "Rezonance může stavbu nebo most rozkmitat nebezpečně.", - }; - - return fyz_mcq_page(1, 6, "fyz2unit7", "fyz2_ex7_title", "fyz2_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz2_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Vlna", "Vlnová délka", - "Tip: v = λ·f platí pro každou vlnu.", - { - "Vlnění přenáší energii, ne látku jako celek.", - "Vlnová délka λ je vzdálenost dvou sousedních bodů ve stejné fázi.", - "Rychlost vlny je v = λ·f.", - "Postupné vlnění se šíří prostředím. Stojaté vzniká skládáním.", - NULL, - }, - }, - { - "2 / 3 • Druhy", "Příčné a podélné", - "Tip: zvuk ve vzduchu je podélné vlnění.", - { - "U příčného vlnění kmitají částice kolmo ke směru šíření.", - "U podélného vlnění kmitají ve směru šíření.", - "Na hladině vody je vlnění příčné, zvuk v plynu podélný.", - "Odraz, lom a ohyb patří k vlnění obecně.", - NULL, - }, - }, - { - "3 / 3 • Zvuk", "Výška, hlasitost, barva", - "Tip: zdravé ucho slyší zhruba od 20 Hz do 20 kHz.", - { - "Zvuk je mechanické vlnění, které vnímáme sluchem.", - "Výška tónu odpovídá frekvenci. Hlasitost souvisí s amplitudou.", - "Infrazvuk je pod 20 Hz, ultrazvuk nad 20 kHz.", - "Ve vzduchu při pokojové teplotě je rychlost zvuku asi 340 m/s.", - NULL, - }, - }, - }; - - return fyz_unit_page(1, &fyz2_lessons[7], "fyz2_unit8", "fyz2_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz2_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se počítá rychlost vlny?", - {"v = λ / f", "v = λ·f", "v = f / λ", "v = T·λ²"}, - 4, 1}, - {"Jaké vlnění je zvuk ve vzduchu?", - {"Příčné elektromagnetické", "Podélné mechanické", - "Stojaté jen na hladině", "Příčné jako světlo"}, - 4, 1}, - {"Které frekvence člověk obvykle slyší?", - {"Od 20 Hz do 20 kHz", "Jen nad 20 kHz", - "Jen pod 20 Hz", "Od 340 Hz do 340 kHz"}, - 4, 0}, - {"Jak rychle se šíří zvuk ve vzduchu při pokojové teplotě?", - {"Asi 340 m/s", "Asi 3·10⁸ m/s", "Asi 9,81 m/s", "Asi 1500 km/s"}, - 4, 0}, - }; - static const char *hints[] = { - "Vyšší frekvence při stejné rychlosti znamená kratší vlnovou délku.", - "Světlo je příčné elektromagnetické. Zvuk potřebuje látkové prostředí.", - "Pod 20 Hz je infrazvuk, nad 20 kHz ultrazvuk.", - "Ve vodě je zvuk rychlejší, zhruba 1500 m/s. Světlo má 3·10⁸ m/s.", - }; - - return fyz_mcq_page(1, 7, "fyz2unit8", "fyz2_ex8_title", "fyz2_quiz8_head", - qs, hints, 4); -} - -void add_fyz2_pages(GtkStack *stack) { - typedef GtkWidget *(*FyzBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - FyzBuilder build_unit; - FyzBuilder build_ex; - } pages[] = { - {"fyz2unit1", "fyz2ex1", build_fyz2_unit1_page, build_fyz2_unit1_exercise_page}, - {"fyz2unit2", "fyz2ex2", build_fyz2_unit2_page, build_fyz2_unit2_exercise_page}, - {"fyz2unit3", "fyz2ex3", build_fyz2_unit3_page, build_fyz2_unit3_exercise_page}, - {"fyz2unit4", "fyz2ex4", build_fyz2_unit4_page, build_fyz2_unit4_exercise_page}, - {"fyz2unit5", "fyz2ex5", build_fyz2_unit5_page, build_fyz2_unit5_exercise_page}, - {"fyz2unit6", "fyz2ex6", build_fyz2_unit6_page, build_fyz2_unit6_exercise_page}, - {"fyz2unit7", "fyz2ex7", build_fyz2_unit7_page, build_fyz2_unit7_exercise_page}, - {"fyz2unit8", "fyz2ex8", build_fyz2_unit8_page, build_fyz2_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/fyz_year3.c b/src/fyz_year3.c deleted file mode 100644 index cb3b45e..0000000 --- a/src/fyz_year3.c +++ /dev/null @@ -1,618 +0,0 @@ -#include "graduately.h" - -/* Year 3: electricity and magnetism. Charge, current, circuits, - * matter in electric field, magnetic field, induction, alternating - * current and electromagnetic waves. */ - -NetLesson fyz3_lessons[FYZ_N] = { - { .n_slides = 3, .unit_page = "fyz3unit1", .ex_page = "fyz3ex1" }, - { .n_slides = 3, .unit_page = "fyz3unit2", .ex_page = "fyz3ex2" }, - { .n_slides = 3, .unit_page = "fyz3unit3", .ex_page = "fyz3ex3" }, - { .n_slides = 3, .unit_page = "fyz3unit4", .ex_page = "fyz3ex4" }, - { .n_slides = 3, .unit_page = "fyz3unit5", .ex_page = "fyz3ex5" }, - { .n_slides = 3, .unit_page = "fyz3unit6", .ex_page = "fyz3ex6" }, - { .n_slides = 3, .unit_page = "fyz3unit7", .ex_page = "fyz3ex7" }, - { .n_slides = 3, .unit_page = "fyz3unit8", .ex_page = "fyz3ex8" }, -}; - -static GtkWidget *build_fyz3_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Náboj", "Dva druhy", - "Tip: souhlasné náboje se odpuzují, nesouhlasné přitahují.", - { - "Elektrický náboj je kladný nebo záporný.", - "Elementární náboj je e ≈ 1,6·10⁻¹⁹ C.", - "Náboj se zachovává a je celistvým násobkem e.", - "Třením se náboje rozdělují, nevznikají z ničeho.", - NULL, - }, - }, - { - "2 / 3 • Coulomb", "Síla mezi náboji", - "Tip: síla klesá s druhou mocninou vzdálenosti.", - { - "Coulombův zákon: Fe = k·|Q₁·Q₂| / r².", - "k je asi 9·10⁹ N·m²/C².", - "Vodič má volné náboje, izolant je nemá.", - "Elektrické pole je kolem každého náboje.", - NULL, - }, - }, - { - "3 / 3 • Pole", "Intenzita a napětí", - "Tip: napětí je práce na jednotkový náboj.", - { - "Intenzita E = F / q ukazuje sílu na kladný jednotkový náboj.", - "Homogenní pole má všude stejnou intenzitu, třeba mezi deskami.", - "Napětí U = W / Q. Jednotka je volt.", - "Ekvipotenciální hladina je množina bodů se stejným potenciálem.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[0], "fyz3_unit1", "fyz3_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak na sebe působí souhlasné náboje?", - {"Přitahují se", "Odpuzují se", "Nepůsobí", "Jen při stejné hmotnosti"}, - 4, 1}, - {"Jak velký je elementární náboj?", - {"Asi 1,6·10⁻¹⁹ C", "Asi 9·10⁹ C", "1 C přesně jako proton", "Asi 6,67·10⁻¹¹ C"}, - 4, 0}, - {"Jak závisí Coulombova síla na vzdálenosti?", - {"Přímo úměrně", "Nepřímo úměrně druhé mocnině vzdálenosti", - "Nezávisí na ní", "Přímo úměrně druhé mocnině"}, - 4, 1}, - {"Co je elektrické napětí?", - {"Síla na jednotkovou hmotnost", - "Práce na jednotkový náboj", - "Náboj za čas", - "Odpor krát plocha"}, - 4, 1}, - }; - static const char *hints[] = { - "Nesouhlasné náboje se přitahují. Neutrální těleso má vyrovnané náboje.", - "Proton má +e, elektron −e. Coulomb je velmi velký náboj.", - "Stejný tvar má i gravitační zákon, jen konstanta je jiná.", - "1 V = 1 J/C. Intenzita se měří v N/C nebo V/m.", - }; - - return fyz_mcq_page(2, 0, "fyz3unit1", "fyz3_ex1_title", "fyz3_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz3_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Proud", "Náboj v pohybu", - "Tip: dohodnutý směr proudu je směr pohybu kladného náboje.", - { - "Elektrický proud je usměrněný pohyb nabitých částic.", - "Proud I = Q / t. Jednotka je ampér.", - "V kovech proud nesou volné elektrony.", - "Dohodnutý směr proudu je opačný než směr pohybu elektronů.", - NULL, - }, - }, - { - "2 / 3 • Ohm", "Odpor", - "Tip: větší délka vodiče znamená větší odpor, větší průřez menší.", - { - "Ohmův zákon pro část obvodu: U = R·I.", - "Odpor R závisí na materiálu, délce a průřezu.", - "R = ρ·l / S. ρ je měrný elektrický odpor.", - "S rostoucí teplotou odpor kovů obvykle roste.", - NULL, - }, - }, - { - "3 / 3 • Zdroj", "Svorkové napětí", - "Tip: vnitřní odpor zdroje snižuje napětí při odběru proudu.", - { - "Zdroj má elektromotorické napětí a vnitřní odpor.", - "Svorkové napětí je menší než elektromotorické, když obvodem teče proud.", - "Zkrat je spojení s velmi malým odporem. Proud je nebezpečně velký.", - "Ampérmetr se řadí sériově, voltmetr paralelně.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[1], "fyz3_unit2", "fyz3_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se počítá proud?", - {"I = Q·t", "I = Q / t", "I = U·R", "I = R / U"}, - 4, 1}, - {"Jak zní Ohmův zákon pro část obvodu?", - {"U = R / I", "U = R·I", "U = I / R", "R = U·I"}, - 4, 1}, - {"Kdy má kovový vodič větší odpor?", - {"Když je kratší a tlustší", - "Když je delší a tenčí", - "Když má větší průřez při stejné délce", - "Když je z látky s nulovým měrným odporem"}, - 4, 1}, - {"Jak se zapojuje ampérmetr?", - {"Paralelně ke spotřebiči", "Sériově do obvodu", - "Jen místo voltmetru paralelně", "Mimo obvod"}, - 4, 1}, - }; - static const char *hints[] = { - "Ampér je coulomb za sekundu.", - "Odpor je U/I. Větší odpor při stejném napětí znamená menší proud.", - "R = ρ·l / S. Měrný odpor ρ je vlastnost látky.", - "Voltmetr má mít velký odpor a měří napětí vedle spotřebiče.", - }; - - return fyz_mcq_page(2, 1, "fyz3unit2", "fyz3_ex2_title", "fyz3_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz3_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Spojení", "Sériově a paralelně", - "Tip: sériově se odpory sčítají, proud je všude stejný.", - { - "Při sériovém spojení je proud stejný a napětí se sčítají.", - "Výsledný odpor sériově je R = R₁ + R₂ + …", - "Při paralelním spojení je napětí stejné a proudy se sčítají.", - "Pro dva paralelní odpory je 1/R = 1/R₁ + 1/R₂.", - NULL, - }, - }, - { - "2 / 3 • Kirchhoff", "Uzly a smyčky", - "Tip: v uzlu je součet přitékajících proudů roven součtu odtékajících.", - { - "První Kirchhoffův zákon je o proudu v uzlu.", - "Druhý Kirchhoffův zákon: součet napětí ve smyčce je nulový.", - "Zdroj ve smyčce dodává napětí, spotřebiče ho ubírají.", - "Zákony stačí na jednoduché obvody se dvěma smyčkami.", - NULL, - }, - }, - { - "3 / 3 • Výkon", "Práce proudu", - "Tip: příkon je P = U·I.", - { - "Práce elektrického proudu je W = U·I·t.", - "Příkon je P = U·I = R·I² = U² / R.", - "Kilowatthodina je jednotka energie, ne výkonu.", - "Jouleovo teplo ve vodiči je Q = R·I²·t.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[2], "fyz3_unit3", "fyz3_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaký je výsledný odpor dvou sériově spojených rezistorů?", - {"R = R₁ + R₂", "1/R = 1/R₁ + 1/R₂", "R = R₁·R₂", "R = R₁ / R₂"}, - 4, 0}, - {"Co je stejné na paralelně spojených spotřebičích?", - {"Proud každým z nich", "Napětí", - "Odpor každého z nich", "Jouleovo teplo bez ohledu na odpor"}, - 4, 1}, - {"Co říká první Kirchhoffův zákon?", - {"Součet napětí ve smyčce je nula", - "Součet proudů v uzlu je nula", - "Odpor roste s teplotou", - "Výkon je U děleno I"}, - 4, 1}, - {"Jak se počítá elektrická práce?", - {"W = F·s", "W = U·I·t", "W = R / I", "W = Q·c·Δt"}, - 4, 1}, - }; - static const char *hints[] = { - "Paralelní spojení výsledný odpor zmenší. Dva stejné paralelně dají polovinu.", - "Větší odpor při stejném napětí bere menší proud.", - "Druhý zákon se týká napětí ve smyčce.", - "1 kWh = 3,6·10⁶ J. Příkon ve wattech je U·I.", - }; - - return fyz_mcq_page(2, 2, "fyz3unit3", "fyz3_ex3_title", "fyz3_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz3_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Polovodič", "Vlastní a příměsová vodivost", - "Tip: dioda vede proud hlavně v propustném směru.", - { - "Polovodič má vodivost mezi vodičem a izolantem.", - "S teplotou jeho odpor obvykle klesá, na rozdíl od kovu.", - "Typ N má příměs s volnými elektrony, typ P s dírami.", - "Přechod PN je základ diody. V závěrném směru téměř nevede.", - NULL, - }, - }, - { - "2 / 3 • Kapaliny", "Elektrolyt", - "Tip: v elektrolytu nesou proud ionty, ne volné elektrony jako v kovu.", - { - "Elektrolyt je roztok nebo tavenina, která vede proud ionty.", - "Kationty putují ke katodě, anionty k anodě.", - "Elektrolýza vylučuje látku na elektrodách.", - "Hmotnost vyloučené látky je úměrná náboji, který prošel.", - NULL, - }, - }, - { - "3 / 3 • Plyny", "Výboj", - "Tip: plyn za běžných podmínek nevede, dokud se neionizuje.", - { - "Samostatný výboj udržuje ionizaci sám, nesamostatný potřebuje vnější ionizátor.", - "Jiskra, oblouk a doutnavý výboj jsou druhy výboje.", - "Blesk je jiskrový výboj v atmosféře.", - "Výbojka a zářivka využívají záření výboje v plynu.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[3], "fyz3_unit4", "fyz3_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se s teplotou obvykle mění odpor polovodiče?", - {"Roste jako u kovu", "Klesá", "Nemění se", "Skokem se stane nulovým vždy"}, - 4, 1}, - {"Co je polovodič typu N?", - {"Má převahu děr", "Má převahu volných elektronů z příměsi", - "Je izolant bez náboje", "Vede jen ionty"}, - 4, 1}, - {"Čím je nesen proud v elektrolytu?", - {"Jen volnými elektrony jako v mědi", "Ionty", - "Fotony", "Neutrony"}, - 4, 1}, - {"Kdy plyn začne výrazně vést proud?", - {"Až když je ionizovaný", "Vždy stejně jako kov", - "Jen pod absolutní nulou", "Jen když je to vakuum bez částic"}, - 4, 0}, - }; - static const char *hints[] = { - "Termistor s klesajícím odporem při zahřátí je typické užití.", - "Typ P má díry. Dioda je jeden přechod PN.", - "Katoda přitahuje kationty. Faradayův zákon váže hmotnost a náboj.", - "Nesamostatný výboj zanikne, když zmizí vnější ionizátor.", - }; - - return fyz_mcq_page(2, 3, "fyz3unit4", "fyz3_ex4_title", "fyz3_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz3_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Magnet", "Pole magnetu", - "Tip: souhlasné póly se odpuzují.", - { - "Souhlasné magnetické póly se odpuzují, nesouhlasné přitahují.", - "Severní pól střelky ukazuje k jižnímu magnetickému pólu Země.", - "Magnetické indukční čáry jsou uzavřené.", - "Zemské pole odklání část nabitých částic z vesmíru.", - NULL, - }, - }, - { - "2 / 3 • Proud", "Magnetické pole vodiče", - "Tip: cívka s proudem se chová jako magnet.", - { - "Kolem přímého vodiče s proudem jsou indukční čáry kružnice.", - "Cívka, solenoid, má uvnitř téměř homogenní pole.", - "Na vodič s proudem v magnetickém poli působí síla F = B·I·l·sin α.", - "B je magnetická indukce. Jednotka je tesla, T.", - NULL, - }, - }, - { - "3 / 3 • Užití", "Motor a měřidlo", - "Tip: elektromotor mění elektrickou energii na pohybovou.", - { - "Stejnosměrný motor využívá sílu na závit s proudem v magnetickém poli.", - "Komutátor mění směr proudu v závitu, aby se točil dál.", - "Částice s nábojem v magnetickém poli zatáčí, pokud má složku rychlosti kolmou k poli.", - "Magnetický záznam a elektromagnet jsou běžné užití pole.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[4], "fyz3_unit5", "fyz3_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaký tvar mají magnetické indukční čáry?", - {"Začínají na severním pólu a končí v nekonečnu jako přímky", - "Jsou uzavřené", - "Jsou vždy rovnoběžné s vodičem", - "Existují jen ve vakuu"}, - 4, 1}, - {"Jak se počítá síla na přímý vodič s proudem v magnetickém poli?", - {"F = B·I·l·sin α", "F = k·Q₁·Q₂ / r²", "F = m·g", "F = U / R"}, - 4, 0}, - {"Jaká je jednotka magnetické indukce?", - {"Volt", "Tesla", "Henry jen jako indukce B", "Ampér"}, - 4, 1}, - {"K čemu je v stejnosměrném motoru komutátor?", - {"Aby zvýšil odpor na nekonečno", - "Aby měnil směr proudu v závitu a motor se točil dál", - "Aby zrušil magnetické pole", - "Aby měřil napětí"}, - 4, 1}, - }; - static const char *hints[] = { - "Elektrické siločáry začínají a končí na nábojích. Magnetické jsou uzavřené.", - "Když je vodič rovnoběžný s polem, sin α je 0 a síla je nulová.", - "Tesla je N/(A·m). Henry je jednotka indukčnosti.", - "Bez komutátoru by se závit po půl otáčce zastavil.", - }; - - return fyz_mcq_page(2, 4, "fyz3unit5", "fyz3_ex5_title", "fyz3_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz3_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Faraday", "Indukované napětí", - "Tip: napětí vzniká, jen když se magnetický tok mění.", - { - "Elektromagnetická indukce vzniká při změně magnetického toku plochou smyčky.", - "Magnetický tok je Φ = B·S·cos α.", - "Indukované napětí je tím větší, čím rychleji se tok mění.", - "Stálé pole a klidná smyčka napětí neindukují.", - NULL, - }, - }, - { - "2 / 3 • Lenz", "Směr proudu", - "Tip: indukovaný proud působí proti změně, která ho vyvolala.", - { - "Lenzův zákon určuje směr indukovaného proudu.", - "Proud vytváří pole, které brání změně toku.", - "Proto se magnet padající měděnou trubkou brzdí.", - "Vlastní indukce brání změně proudu v cívce.", - NULL, - }, - }, - { - "3 / 3 • Transformátor", "Změna napětí", - "Tip: poměr napětí je poměr počtů závitů.", - { - "Transformátor má dvě cívky na společném jádře.", - "U₁ / U₂ = N₁ / N₂.", - "Zvyšovací transformátor má na sekundáru víc závitů.", - "U ideálního transformátoru je příkon roven výkonu, proud se mění opačně než napětí.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[5], "fyz3_unit6", "fyz3_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy se ve smyčce indukuje napětí?", - {"Když je magnetický tok stálý", - "Když se magnetický tok plochou smyčky mění", - "Když smyčkou neteče žádný náboj a tok je nulový trvale", - "Jen při stejnosměrném proudu v klidném poli"}, - 4, 1}, - {"Co říká Lenzův zákon?", - {"Indukovaný proud podporuje změnu toku", - "Indukovaný proud působí proti změně, která ho vyvolala", - "Napětí je vždy rovno proudu", - "Tok je B děleno S"}, - 4, 1}, - {"Jaký je poměr napětí na ideálním transformátoru?", - {"U₁ / U₂ = N₂ / N₁", "U₁ / U₂ = N₁ / N₂", - "U₁ / U₂ = I₁ / I₂ vždy při stejném počtu závitů jen", - "Napětí nezávisí na závitech"}, - 4, 1}, - {"Co platí pro ideální transformátor?", - {"Příkon je roven výkonu", - "Sekundární proud je vždy nulový", - "Funguje i se stejnosměrným stálým proudem", - "Napětí na obou cívkách je stejné bez ohledu na závity"}, - 4, 0}, - }; - static const char *hints[] = { - "Pohyb magnetu u cívky, nebo změna proudu v primáru, tok mění.", - "Zákon zachování energie: indukce nemůže změnu sama zesilovat donekonečna.", - "Více závitů na sekundáru znamená vyšší sekundární napětí.", - "Stejnosměrný stálý proud tok nemění, proto se netransformuje.", - }; - - return fyz_mcq_page(2, 5, "fyz3unit6", "fyz3_ex6_title", "fyz3_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz3_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Střídání", "Perioda a frekvence", - "Tip: síť v Česku má frekvenci 50 Hz.", - { - "Střídavý proud periodicky mění velikost i směr.", - "Harmonické napětí popisuje sinus.", - "Frekvence sítě je 50 Hz, perioda je 0,02 s.", - "Okamžitá hodnota se stále mění. Měří se efektivní hodnota.", - NULL, - }, - }, - { - "2 / 3 • Efektivní", "Co ukáže voltmetr", - "Tip: efektivní hodnota je maximální dělená odmocninou ze dvou.", - { - "Efektivní proud vydá na rezistoru stejný výkon jako stejný stejnosměrný proud.", - "Pro sinusový průběh je Uef = Umax / √2.", - "Síťové napětí 230 V je efektivní hodnota.", - "Amplituda je tedy asi 325 V.", - NULL, - }, - }, - { - "3 / 3 • Obvod", "Odpor, cívka, kondenzátor", - "Tip: na rezistoru jsou napětí a proud ve fázi.", - { - "Rezistor proud a napětí neposouvá.", - "Cívka zpožďuje proud za napětím, kondenzátor ho předbíhá.", - "Indukčnost a kapacita závisejí na frekvenci.", - "Výkon na rezistoru je P = Uef·Ief.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[6], "fyz3_unit7", "fyz3_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaká je frekvence elektrické sítě v Česku?", - {"50 Hz", "230 Hz", "1 Hz", "60 kHz"}, - 4, 0}, - {"Co znamená síťové napětí 230 V?", - {"Maximální hodnotu", "Efektivní hodnotu", - "Napětí za jednu periodu jako součet", "Vnitřní odpor"}, - 4, 1}, - {"Jak spolu souvisí efektivní a maximální hodnota u sinusového napětí?", - {"Uef = Umax·√2", "Uef = Umax / √2", "Uef = Umax", "Uef = Umax / 2"}, - 4, 1}, - {"Jak je to s fází na rezistoru?", - {"Proud se zpožďuje o čtvrt periodu", - "Napětí a proud jsou ve fázi", - "Proud předbíhá o půl periodu", - "Fáze závisí jen na barvě rezistoru"}, - 4, 1}, - }; - static const char *hints[] = { - "Perioda 50 Hz je 20 ms. V USA je síť 60 Hz.", - "Maximální napětí sítě je 230·√2, zhruba 325 V.", - "√2 je asi 1,414. Efektivní hodnota je menší než amplituda.", - "Fázový posun dělá cívka a kondenzátor, ne samotný rezistor.", - }; - - return fyz_mcq_page(2, 6, "fyz3unit7", "fyz3_ex7_title", "fyz3_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz3_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Vznik", "Elektromagnetická vlna", - "Tip: ve vakuu se vlna šíří rychlostí světla.", - { - "Kmitající náboj vyzařuje elektromagnetickou vlnu.", - "Elektrická a magnetická složka jsou navzájem kolmé a kolmé ke směru šíření.", - "Ve vakuu je rychlost c = 3·10⁸ m/s.", - "Vlna přenáší energii a nepotřebuje látkové prostředí.", - NULL, - }, - }, - { - "2 / 3 • Spektrum", "Od rádia po záření gama", - "Tip: viditelné světlo je jen úzká část spektra.", - { - "Spektrum tvoří rádiové vlny, mikrovlny, infračervené záření, světlo, ultrafialové, rentgenové a gama.", - "Větší frekvence znamená kratší vlnovou délku, protože c = λ·f.", - "Viditelné světlo je zhruba 400 až 750 nm.", - "Za fialovou je ultrafialové záření, před červenou infračervené.", - NULL, - }, - }, - { - "3 / 3 • Užití", "Spoje a ohřev", - "Tip: mikrovlny rozkmitávají molekuly vody.", - { - "Rádiové vlny přenášejí rozhlas, televizi i mobilní signál.", - "Mikrovlny se používají v radarové technice a v troubě.", - "Rentgenové záření prochází měkkými tkáněmi víc než kostmi.", - "Všechny tyto vlny jsou totéž elektromagnetické vlnění, liší se frekvencí.", - NULL, - }, - }, - }; - - return fyz_unit_page(2, &fyz3_lessons[7], "fyz3_unit8", "fyz3_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz3_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak rychle se šíří elektromagnetická vlna ve vakuu?", - {"Asi 340 m/s", "Asi 3·10⁸ m/s", "Asi 9,81 m/s", "Závisí na hlasitosti"}, - 4, 1}, - {"Co platí pro vlnovou délku a frekvenci ve vakuu?", - {"c = λ / f", "c = λ·f", "c = f / λ", "λ nezávisí na f"}, - 4, 1}, - {"Kde ve spektru leží viditelné světlo?", - {"Mezi rádiovými vlnami a mikrovlnami", - "Mezi infračerveným a ultrafialovým zářením", - "Za zářením gama", - "Jen jako zvuk"}, - 4, 1}, - {"Čím se od sebe liší rádiová vlna a rentgenové záření?", - {"Rentgen není elektromagnetická vlna", - "Mají jinou frekvenci", - "Rentgen potřebuje vzduch, rádio vakuum", - "Rádiová vlna má vždy vyšší frekvenci"}, - 4, 1}, - }; - static const char *hints[] = { - "340 m/s je zvuk. Světlo je skoro milionkrát rychlejší.", - "Stejný vztah jako u mechanické vlny, rychlost je c.", - "Fialová má kratší vlnovou délku než červená.", - "Gama a rentgen mají vysokou frekvenci a krátkou vlnovou délku.", - }; - - return fyz_mcq_page(2, 7, "fyz3unit8", "fyz3_ex8_title", "fyz3_quiz8_head", - qs, hints, 4); -} - -void add_fyz3_pages(GtkStack *stack) { - typedef GtkWidget *(*FyzBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - FyzBuilder build_unit; - FyzBuilder build_ex; - } pages[] = { - {"fyz3unit1", "fyz3ex1", build_fyz3_unit1_page, build_fyz3_unit1_exercise_page}, - {"fyz3unit2", "fyz3ex2", build_fyz3_unit2_page, build_fyz3_unit2_exercise_page}, - {"fyz3unit3", "fyz3ex3", build_fyz3_unit3_page, build_fyz3_unit3_exercise_page}, - {"fyz3unit4", "fyz3ex4", build_fyz3_unit4_page, build_fyz3_unit4_exercise_page}, - {"fyz3unit5", "fyz3ex5", build_fyz3_unit5_page, build_fyz3_unit5_exercise_page}, - {"fyz3unit6", "fyz3ex6", build_fyz3_unit6_page, build_fyz3_unit6_exercise_page}, - {"fyz3unit7", "fyz3ex7", build_fyz3_unit7_page, build_fyz3_unit7_exercise_page}, - {"fyz3unit8", "fyz3ex8", build_fyz3_unit8_page, build_fyz3_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/fyz_year4.c b/src/fyz_year4.c deleted file mode 100644 index 8965050..0000000 --- a/src/fyz_year4.c +++ /dev/null @@ -1,635 +0,0 @@ -#include "graduately.h" - -/* Year 4: wave and geometric optics, special relativity, quantum - * physics, the atom, the nucleus, nuclear reactions and astrophysics. */ - -NetLesson fyz4_lessons[FYZ_N] = { - { .n_slides = 3, .unit_page = "fyz4unit1", .ex_page = "fyz4ex1" }, - { .n_slides = 3, .unit_page = "fyz4unit2", .ex_page = "fyz4ex2" }, - { .n_slides = 3, .unit_page = "fyz4unit3", .ex_page = "fyz4ex3" }, - { .n_slides = 3, .unit_page = "fyz4unit4", .ex_page = "fyz4ex4" }, - { .n_slides = 3, .unit_page = "fyz4unit5", .ex_page = "fyz4ex5" }, - { .n_slides = 3, .unit_page = "fyz4unit6", .ex_page = "fyz4ex6" }, - { .n_slides = 3, .unit_page = "fyz4unit7", .ex_page = "fyz4ex7" }, - { .n_slides = 3, .unit_page = "fyz4unit8", .ex_page = "fyz4ex8" }, -}; - -static GtkWidget *build_fyz4_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Paprsek", "Odraz a lom", - "Tip: úhel odrazu se rovná úhlu dopadu.", - { - "Světlo se v homogenním prostředí šíří přímočaře.", - "Úhel odrazu se rovná úhlu dopadu. Oba se měří od kolmice.", - "Index lomu je n = c / v. Ve skle je větší než 1.", - "Snellův zákon: n₁·sin α = n₂·sin β.", - NULL, - }, - }, - { - "2 / 3 • Mez", "Úplný odraz", - "Tip: úplný odraz nastane při přechodu do opticky řidšího prostředí.", - { - "Opticky hustší prostředí má větší index lomu.", - "Při přechodu do řidšího prostředí se paprsek láme od kolmice.", - "Od mezního úhlu se už neláme a nastane úplný odraz.", - "Optická vlákna vedou světlo opakovaným úplným odrazem.", - NULL, - }, - }, - { - "3 / 3 • Vlna", "Interference a ohyb", - "Tip: světlo je příčné elektromagnetické vlnění.", - { - "Interference je skládání vln. Světlý pruh vzniká při dráhovém rozdílu k·λ.", - "Tmavý pruh vzniká při rozdílu liché poloviny vlnové délky.", - "Ohyb je patrný, když je překážka srovnatelná s vlnovou délkou.", - "Polarizace dokazuje, že světlo je příčné vlnění.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[0], "fyz4_unit1", "fyz4_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak zní zákon odrazu?", - {"Úhel odrazu je dvojnásobek úhlu dopadu", - "Úhel odrazu se rovná úhlu dopadu", - "Úhel odrazu je vždy 90°", - "Odraz nezávisí na kolmici"}, - 4, 1}, - {"Co je index lomu?", - {"n = v / c", "n = c / v", "n = λ·f v látce dělené c²", "n = sin α"}, - 4, 1}, - {"Kdy nastane úplný odraz?", - {"Při přechodu do opticky řidšího prostředí nad mezním úhlem", - "Při každém dopadu na zrcadlo", - "Jen ve vakuu", - "Při přechodu do hustšího prostředí"}, - 4, 0}, - {"Kdy vznikne interferencí světlý pruh?", - {"Při dráhovém rozdílu k·λ", - "Při dráhovém rozdílu vždy λ/2", - "Když se vlny nepotkají", - "Jen u podélného zvuku"}, - 4, 0}, - }; - static const char *hints[] = { - "Úhly se měří od kolmice dopadu, ne od plochy.", - "V látce je světlo pomalejší než ve vakuu, proto n > 1.", - "Mezní úhel splňuje sin αm = n₂ / n₁ pro n₁ > n₂.", - "Podmínka pro minimum je (2k+1)·λ/2.", - }; - - return fyz_mcq_page(3, 0, "fyz4unit1", "fyz4_ex1_title", "fyz4_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz4_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Zrcadla", "Dutá a vypuklá", - "Tip: zobrazovací rovnice je 1/a + 1/a' = 1/f.", - { - "Rovinné zrcadlo dává vzpřímený obraz stejné velikosti, zdánlivě za zrcadlem.", - "Duté zrcadlo může dát skutečný převrácený obraz.", - "Vypuklé zrcadlo dává zmenšený vzpřímený zdánlivý obraz.", - "Ohnisková vzdálenost kulového zrcadla je f = r / 2.", - NULL, - }, - }, - { - "2 / 3 • Čočky", "Spojka a rozptylka", - "Tip: spojka soustředí rovnoběžné paprsky do ohniska.", - { - "Spojka je uprostřed tlustší a má kladnou ohniskovou vzdálenost.", - "Rozptylka je uprostřed tenčí a paprsky rozbíhá.", - "Zobrazovací rovnice je 1/a + 1/a' = 1/f.", - "a je vzdálenost předmětu, a' vzdálenost obrazu.", - NULL, - }, - }, - { - "3 / 3 • Oko", "Vady a přístroje", - "Tip: krátkozrakost se koriguje rozptylkou.", - { - "Oko zobrazuje spojnou soustavou na sítnici.", - "Krátkozraké oko zobrazuje před sítnici. Pomůže rozptylka.", - "Dalekozraké oko zobrazuje za sítnici. Pomůže spojka.", - "Lupa je spojka a předmět je mezi čočkou a ohniskem.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[1], "fyz4_unit2", "fyz4_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaká je ohnisková vzdálenost kulového zrcadla?", - {"f = r", "f = r / 2", "f = 2·r", "f = 1 / r²"}, - 4, 1}, - {"Jak zní zobrazovací rovnice čočky?", - {"a + a' = f", "1/a + 1/a' = 1/f", "a·a' = f", "1/a − 1/f = a'"}, - 4, 1}, - {"Čím se koriguje krátkozrakost?", - {"Spojkou", "Rozptylkou", "Dutým zrcadlem v oku", "Clonou bez čočky"}, - 4, 1}, - {"Jaký obraz dává lupa?", - {"Skutečný převrácený, předmět je za ohniskem", - "Zvětšený vzpřímený zdánlivý, předmět je mezi čočkou a ohniskem", - "Zmenšený obraz v nekonečnu vždy", - "Obraz stejný jako rovinné zrcadlo"}, - 4, 1}, - }; - static const char *hints[] = { - "Poloměr křivosti je dvojnásobek ohniskové vzdálenosti.", - "Když je a = 2f, je i a' = 2f a obraz je stejně velký.", - "Dalekozrakost koriguje spojka. Obraz pak padne na sítnici.", - "Zdánlivý obraz spojky vzniká, když je předmět uvnitř ohniska.", - }; - - return fyz_mcq_page(3, 1, "fyz4unit2", "fyz4_ex2_title", "fyz4_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz4_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Postuláty", "Dva principy", - "Tip: rychlost světla ve vakuu je ve všech inerciálních soustavách stejná.", - { - "Fyzikální zákony mají ve všech inerciálních soustavách stejný tvar.", - "Rychlost světla ve vakuu je ve všech inerciálních soustavách c.", - "c je mezní rychlost pro přenos informace a pro částice s hmotností.", - "Klasické skládání rychlostí u rychlostí blízkých c selhává.", - NULL, - }, - }, - { - "2 / 3 • Čas a délka", "Dilatace a kontrakce", - "Tip: pohybující se hodiny jdou z hlediska klidné soustavy pomaleji.", - { - "Dilatace času: pohyblivé hodiny jdou pomaleji.", - "Kontrakce délky zkracuje rozměr ve směru pohybu.", - "Rozměry kolmé ke směru pohybu se nemění.", - "Efekty jsou patrné až při rychlostech srovnatelných s c.", - NULL, - }, - }, - { - "3 / 3 • Energie", "E = m·c²", - "Tip: klidová energie je energie tělesa v soustavě, kde je v klidu.", - { - "Klidová energie je E₀ = m·c².", - "Celková energie roste s rychlostí.", - "Hmotnost a energie jsou dvě stránky téže veličiny.", - "Částice s nenulovou klidovou hmotností nikdy nedosáhne rychlosti c.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[2], "fyz4_unit3", "fyz4_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co platí o rychlosti světla ve vakuu?", - {"Závisí na rychlosti zdroje klasickým součtem", - "Je ve všech inerciálních soustavách stejná", - "Je 340 m/s", - "Je různá podle barvy jako hlavní postulát"}, - 4, 1}, - {"Co je dilatace času?", - {"Pohyblivé hodiny jdou z hlediska klidného pozorovatele pomaleji", - "Pohyblivé hodiny jdou rychleji", - "Čas se zastaví při každé rychlosti", - "Délka se prodlužuje"}, - 4, 0}, - {"Který rozměr se při kontrakci zkracuje?", - {"Rozměr kolmý ke směru pohybu", - "Rozměr ve směru pohybu", - "Všechny rozměry stejně", - "Žádný, zkracuje se jen hmotnost"}, - 4, 1}, - {"Jak se značí klidová energie?", - {"E₀ = m·v² / 2", "E₀ = m·c²", "E₀ = m·g·h", "E₀ = h·f"}, - 4, 1}, - }; - static const char *hints[] = { - "Druhý postulát nahrazuje klasické skládání rychlostí světla.", - "Vzorec obsahuje √(1 − v²/c²) ve jmenovateli vlastního času.", - "Tyč kolmá k pohybu má stejnou délku v obou soustavách.", - "c² je obrovské číslo, proto i malá hmotnost znamená velkou energii.", - }; - - return fyz_mcq_page(3, 2, "fyz4unit3", "fyz4_ex3_title", "fyz4_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz4_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Foton", "Energie kvanta", - "Tip: E = h·f. h je Planckova konstanta.", - { - "Záření si vyměňuje energii po kvantech, fotonech.", - "Energie fotonu je E = h·f.", - "h je asi 6,63·10⁻³⁴ J·s.", - "Větší frekvence znamená energičtější foton.", - NULL, - }, - }, - { - "2 / 3 • Fotoefekt", "Světlo vyráží elektrony", - "Tip: pod mezní frekvencí elektrony nevyletí, i když je světlo silné.", - { - "Fotoelektrický jev: foton předá energii elektronu v kovu.", - "Výstupní práce Wv je energie potřebná k opuštění kovu.", - "Einsteinova rovnice: h·f = Wv + Ek.", - "Počet elektronů roste s intenzitou, jejich maximální energie s frekvencí.", - NULL, - }, - }, - { - "3 / 3 • Dualita", "Vlna i částice", - "Tip: de Broglieho vlnová délka je λ = h / p.", - { - "Světlo se v interferenci chová jako vlna a ve fotoefektu jako částice.", - "I elektrony mají vlnové vlastnosti.", - "De Broglie: λ = h / p, kde p je hybnost.", - "Čím větší hybnost, tím kratší vlnová délka.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[3], "fyz4_unit4", "fyz4_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se počítá energie fotonu?", - {"E = m·c² jen pro foton v klidu", "E = h·f", "E = h / f", "E = f / h"}, - 4, 1}, - {"Co rozhoduje o tom, zda fotoefekt nastane?", - {"Jen intenzita světla", - "Frekvence musí být aspoň mezní", - "Jen barva kovu bez frekvence", - "Teplota laboratoře jako jediná podmínka"}, - 4, 1}, - {"Jak zní Einsteinova rovnice fotoefektu?", - {"h·f = Wv + Ek", "h·f = Wv − Ek vždy záporně", - "E = m·g·h", "h·f = R·I"}, - 4, 0}, - {"Co říká de Broglieho vztah?", - {"λ = h·p", "λ = h / p", "λ = p / h", "λ = c·p"}, - 4, 1}, - }; - static const char *hints[] = { - "Foton nemá klidovou hmotnost. Jeho energie je h·f, hybnost h/λ.", - "Silnější světlo stejné nízké frekvence elektrony neuvolní.", - "Zbytek energie fotonu po výstupní práci je kinetická energie elektronu.", - "Makroskopická tělesa mají obrovskou hybnost, proto nepatrnou vlnovou délku.", - }; - - return fyz_mcq_page(3, 3, "fyz4unit4", "fyz4_ex4_title", "fyz4_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz4_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Modely", "Od Rutherforda k Bohrovi", - "Tip: Rutherfordův pokus ukázal malé kladné jádro.", - { - "Thomsonův model měl náboj rozptýlený v celém atomu.", - "Rutherford: atom má malé kladné jádro a obal z elektronů.", - "Většina objemu atomu je prázdná.", - "Bohr doplnil, že elektron je jen na určitých drahách bez vyzařování.", - NULL, - }, - }, - { - "2 / 3 • Hladiny", "Emise a absorpce", - "Tip: atom vyzáří foton, když elektron klesne na nižší hladinu.", - { - "Energie elektronu v atomu je kvantovaná.", - "Při přeskoku dolů atom vyzáří foton, při přeskoku nahoru ho pohltí.", - "Rozdíl hladin je E = h·f.", - "Spektrum plynu je čárové, spektrum pevné látky je spojité.", - NULL, - }, - }, - { - "3 / 3 • Obal", "Slupky", - "Tip: slupky se značí K, L, M a odpovídají hlavnímu kvantovému číslu.", - { - "Hlavní kvantové číslo n určuje slupku a energii ve vodíku.", - "Slupka K je n = 1, L je n = 2, M je n = 3.", - "Pauliho princip: v atomu nejsou dva elektrony se všemi kvantovými čísly stejnými.", - "Chemická vazba vzniká hlavně elektrony ve vnější slupce.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[4], "fyz4_unit5", "fyz4_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co ukázal Rutherfordův pokus?", - {"Že atom nemá jádro", - "Že kladný náboj je soustředěn v malém jádře", - "Že elektron má vlnovou délku nula", - "Že spektrum pevné látky je čárové"}, - 4, 1}, - {"Kdy atom vyzáří foton?", - {"Když elektron přejde na nižší hladinu", - "Když elektron přejde na vyšší hladinu", - "Když se jádro nepohne a elektron stojí", - "Při každém oběhu podle klasické fyziky trvale"}, - 4, 0}, - {"Jaká je energie fotonu při přeskoku?", - {"Součet obou hladin", "Rozdíl hladin", - "Vždy h·c bez rozdílu", "Klidová energie elektronu"}, - 4, 1}, - {"Která slupka je nejblíž jádru?", - {"M", "L", "K", "Libovolná se stejným n"}, - 4, 2}, - }; - static const char *hints[] = { - "Odraz mála částic alfa o velký úhel nešel vysvětlit rozptýleným nábojem.", - "Přeskok nahoru je absorpce. Elektron energii fotonu přijme.", - "E₂ − E₁ = h·f. Větší skok znamená větší frekvenci.", - "n = 1 je K. Vyšší n je dál od jádra a má vyšší energii.", - }; - - return fyz_mcq_page(3, 4, "fyz4unit5", "fyz4_ex5_title", "fyz4_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz4_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Jádro", "Protonové a nukleonové číslo", - "Tip: nukleonové číslo A je počet protonů a neutronů.", - { - "Jádro tvoří protony a neutrony, souhrnně nukleony.", - "Protonové číslo Z je počet protonů a určuje prvek.", - "Nukleonové číslo A je počet nukleonů. Neutronů je A − Z.", - "Izotopy mají stejné Z a různé A.", - NULL, - }, - }, - { - "2 / 3 • Vazba", "Vazebná energie", - "Tip: jádro je lehčí než součet volných nukleonů.", - { - "Jaderné síly drží nukleony pohromadě a působí na krátkou vzdálenost.", - "Vazebná energie je energie, kterou je třeba dodat na rozbití jádra na nukleony.", - "Hmotnostní úbytek odpovídá vazebné energii podle E = m·c².", - "Nejstabilnější jsou jádra kolem železa.", - NULL, - }, - }, - { - "3 / 3 • Rozpad", "Alfa, beta, gama", - "Tip: poločas je doba, za kterou se rozpadne polovina jader.", - { - "Záření alfa je jádro helia, má malý dolet a silné ionizační účinky.", - "Záření beta jsou elektrony nebo pozitrony z jádra.", - "Záření gama je elektromagnetické a proniká nejvíc.", - "Poločas rozpadu je pro daný nuklid stálý a nezávisí na okolí.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[5], "fyz4_unit6", "fyz4_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je nukleonové číslo A?", - {"Počet protonů", "Počet protonů a neutronů", - "Počet elektronů v obalu", "Počet slupek"}, - 4, 1}, - {"Co jsou izotopy?", - {"Jádra se stejným Z a různým A", - "Jádra se stejným A a různým Z", - "Jádra bez neutronů", - "Atomy bez elektronů"}, - 4, 0}, - {"Co je záření alfa?", - {"Elektromagnetická vlna", "Jádro helia", - "Volný neutron", "Foton z obalu"}, - 4, 1}, - {"Co je poločas rozpadu?", - {"Doba, za kterou se rozpadne polovina jader", - "Doba jednoho oběhu elektronu", - "Doba, za kterou vznikne jádro železa", - "Doba života jednoho neutronu mimo každou látku jako jediný údaj"}, - 4, 0}, - }; - static const char *hints[] = { - "Zapiš uhlík 14 jako A = 14, Z = 6, neutronů 8.", - "Stejné protonové číslo znamená stejný prvek.", - "Beta je elektron nebo pozitron. Gama je foton.", - "Po dvou poločasech zbývá čtvrtina původních jader.", - }; - - return fyz_mcq_page(3, 5, "fyz4unit6", "fyz4_ex6_title", "fyz4_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz4_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Štěpení", "Těžká jádra", - "Tip: štěpení uranu uvolní neutrony, které mohou štěpit dál.", - { - "Štěpení rozdělí těžké jádro na dvě středně těžká.", - "Uvolní se energie, protože produkty mají větší vazebnou energii na nukleon.", - "Při štěpení uranu 235 vznikají i neutrony.", - "Řetězová reakce pokračuje, když každý krok uvolní aspoň jeden další neutron.", - NULL, - }, - }, - { - "2 / 3 • Reaktor", "Řízená reakce", - "Tip: moderátor neutrony zpomaluje, regulační tyče je pohlcují.", - { - "V reaktoru je řetězová reakce řízená.", - "Moderátor, třeba voda, zpomaluje neutrony.", - "Regulační tyče neutrony zachycují a výkon tím klesá.", - "Teplo z reaktoru ohřívá vodu a pohání turbínu.", - NULL, - }, - }, - { - "3 / 3 • Syntéza", "Slučování lehkých jader", - "Tip: fúze pohání Slunce. Potřebuje vysokou teplotu.", - { - "Jaderná syntéza slučuje lehká jádra, třeba vodík na helium.", - "Uvolní víc energie na nukleon než štěpení.", - "K překonání odpudivé síly je potřeba velmi vysoká teplota.", - "Ochrana před zářením stojí na čase, vzdálenosti a stínění.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[6], "fyz4_unit7", "fyz4_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je řetězová reakce?", - {"Jedno štěpení, které se dál nešíří", - "Štěpení udržované neutrony z předchozích štěpení", - "Slučování elektronů", - "Rozpad alfa bez neutronů"}, - 4, 1}, - {"K čemu je v reaktoru moderátor?", - {"Aby neutrony zpomalil", - "Aby všechna jádra okamžitě rozbil", - "Aby pohltil všechno teplo bez užitku", - "Aby zvýšil protonové číslo paliva"}, - 4, 0}, - {"Co dělají regulační tyče?", - {"Neutrony zachycují a reakci brzdí", - "Neutrony jen vyrábějí", - "Slouží jako palivo místo uranu", - "Zvyšují teplotu fúze"}, - 4, 0}, - {"Proč fúze potřebuje vysokou teplotu?", - {"Aby jádra překonala elektrické odpuzování", - "Aby se jádra ochladila", - "Aby vznikl moderátor", - "Aby poločas klesl k nule"}, - 4, 0}, - }; - static const char *hints[] = { - "Kritické množství znamená, že neutrony nestačí utéct a reakce běží.", - "Pomalý neutron štěpí uran 235 ochotněji než rychlý.", - "Zasunutí tyčí výkon sníží. Vysunutí ho zvýší.", - "Ve Slunci fúzi pomáhá i obrovský tlak. Záření se stíní olovem a betonem.", - }; - - return fyz_mcq_page(3, 6, "fyz4unit7", "fyz4_ex7_title", "fyz4_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_fyz4_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Slunce", "Hvězda", - "Tip: Slunce získává energii fúzí vodíku na helium.", - { - "Slunce je hvězda. Svítí díky jaderné syntéze v jádře.", - "Světlo ze Slunce letí na Zemi asi 8 minut.", - "Svítivost a teplota povrchu řadí hvězdy do Hertzsprungova–Russellova diagramu.", - "Většina hvězd leží na hlavní posloupnosti.", - NULL, - }, - }, - { - "2 / 3 • Vývoj", "Od oblaku k závěru", - "Tip: hmotnější hvězda žije kratší dobu.", - { - "Hvězda vzniká smršťováním oblaku plynu a prachu.", - "Po vyčerpání vodíku se mění stavba hvězdy.", - "Hvězda podobná Slunci skončí jako bílý trpaslík.", - "Velmi hmotná hvězda může skončit výbuchem supernovy a zbyde neutronová hvězda nebo černá díra.", - NULL, - }, - }, - { - "3 / 3 • Vesmír", "Galaxie a rozpínání", - "Tip: světelný rok je vzdálenost, ne čas.", - { - "Galaxie je soustava hvězd, plynu a prachu. Slunce je v Mléčné dráze.", - "Světelný rok je dráha, kterou světlo urazí za rok.", - "Vzdálené galaxie mají spektrum posunuté k červené. To znamená, že se vzdalují.", - "Rudý posuv podporuje obraz rozpínajícího se vesmíru.", - NULL, - }, - }, - }; - - return fyz_unit_page(3, &fyz4_lessons[7], "fyz4_unit8", "fyz4_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_fyz4_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Odkud bere Slunce energii?", - {"Z hoření uhlí", "Z fúze vodíku na helium", - "Z štěpení uranu v kůře", "Z odrazu světla planet"}, - 4, 1}, - {"Co je hlavní posloupnost?", - {"Pás, na kterém leží většina hvězd v HR diagramu", - "Dráha Země kolem Slunce", - "Řada planet podle velikosti", - "Spektrum jen bílých trpaslíků"}, - 4, 0}, - {"Co je světelný rok?", - {"Doba oběhu Země", "Vzdálenost, kterou světlo urazí za rok", - "Rychlost světla", "Stáří Slunce"}, - 4, 1}, - {"Co znamená rudý posuv vzdálených galaxií?", - {"Galaxie se přibližují", - "Galaxie se vzdalují", - "Galaxie přestaly svítit", - "Světlo změnilo rychlost ve vakuu"}, - 4, 1}, - }; - static const char *hints[] = { - "Fúze v jádře Slunce mění hmotnost na energii podle E = m·c².", - "Obři a bílí trpaslíci leží mimo hlavní posloupnost.", - "Rok je tu doba letu světla, výsledek je délka.", - "Posuv k delší vlnové délce je Dopplerův jev rozpínání.", - }; - - return fyz_mcq_page(3, 7, "fyz4unit8", "fyz4_ex8_title", "fyz4_quiz8_head", - qs, hints, 4); -} - -void add_fyz4_pages(GtkStack *stack) { - typedef GtkWidget *(*FyzBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - FyzBuilder build_unit; - FyzBuilder build_ex; - } pages[] = { - {"fyz4unit1", "fyz4ex1", build_fyz4_unit1_page, build_fyz4_unit1_exercise_page}, - {"fyz4unit2", "fyz4ex2", build_fyz4_unit2_page, build_fyz4_unit2_exercise_page}, - {"fyz4unit3", "fyz4ex3", build_fyz4_unit3_page, build_fyz4_unit3_exercise_page}, - {"fyz4unit4", "fyz4ex4", build_fyz4_unit4_page, build_fyz4_unit4_exercise_page}, - {"fyz4unit5", "fyz4ex5", build_fyz4_unit5_page, build_fyz4_unit5_exercise_page}, - {"fyz4unit6", "fyz4ex6", build_fyz4_unit6_page, build_fyz4_unit6_exercise_page}, - {"fyz4unit7", "fyz4ex7", build_fyz4_unit7_page, build_fyz4_unit7_exercise_page}, - {"fyz4unit8", "fyz4ex8", build_fyz4_unit8_page, build_fyz4_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/fyzika.c b/src/fyzika.c deleted file mode 100644 index 76aa339..0000000 --- a/src/fyzika.c +++ /dev/null @@ -1,720 +0,0 @@ -#include "graduately.h" - -/* Physics across four secondary-school years. Each year is a list of - * lessons, then slides and a quiz. The syllabus follows the gymnasium - * outline: mechanics, thermal physics and waves, electromagnetism, - * then optics, relativity, the micro-world and astrophysics. */ - -typedef struct { - const char *map_page; - const char *back_page; - const char *title_key; - const char *sub_key; - char **progress_path; - NetLesson *lessons; - const char *unit_keys[FYZ_N]; - const char *sub_keys[FYZ_N]; - GtkWidget *nodes[FYZ_N]; - int note_last_w; -} FyzTrack; - -static FyzTrack fyz_tracks[4]; -static gboolean fyz_ready; - -static void fyz_ensure(void) { - static const char *keys0[] = { - "fyz_unit1", "fyz_unit2", "fyz_unit3", "fyz_unit4", - "fyz_unit5", "fyz_unit6", "fyz_unit7", "fyz_unit8", - }; - static const char *subs0[] = { - "fyz_unit1_sub", "fyz_unit2_sub", "fyz_unit3_sub", "fyz_unit4_sub", - "fyz_unit5_sub", "fyz_unit6_sub", "fyz_unit7_sub", "fyz_unit8_sub", - }; - static const char *keys1[] = { - "fyz2_unit1", "fyz2_unit2", "fyz2_unit3", "fyz2_unit4", - "fyz2_unit5", "fyz2_unit6", "fyz2_unit7", "fyz2_unit8", - }; - static const char *subs1[] = { - "fyz2_unit1_sub", "fyz2_unit2_sub", "fyz2_unit3_sub", "fyz2_unit4_sub", - "fyz2_unit5_sub", "fyz2_unit6_sub", "fyz2_unit7_sub", "fyz2_unit8_sub", - }; - static const char *keys2[] = { - "fyz3_unit1", "fyz3_unit2", "fyz3_unit3", "fyz3_unit4", - "fyz3_unit5", "fyz3_unit6", "fyz3_unit7", "fyz3_unit8", - }; - static const char *subs2[] = { - "fyz3_unit1_sub", "fyz3_unit2_sub", "fyz3_unit3_sub", "fyz3_unit4_sub", - "fyz3_unit5_sub", "fyz3_unit6_sub", "fyz3_unit7_sub", "fyz3_unit8_sub", - }; - static const char *keys3[] = { - "fyz4_unit1", "fyz4_unit2", "fyz4_unit3", "fyz4_unit4", - "fyz4_unit5", "fyz4_unit6", "fyz4_unit7", "fyz4_unit8", - }; - static const char *subs3[] = { - "fyz4_unit1_sub", "fyz4_unit2_sub", "fyz4_unit3_sub", "fyz4_unit4_sub", - "fyz4_unit5_sub", "fyz4_unit6_sub", "fyz4_unit7_sub", "fyz4_unit8_sub", - }; - static const char *const *all_keys[4] = {keys0, keys1, keys2, keys3}; - static const char *const *all_subs[4] = {subs0, subs1, subs2, subs3}; - static const char *maps[] = {"fyzmap", "fyz2map", "fyz3map", "fyz4map"}; - static const char *titles[] = { - "fyz_year1", "fyz_year2", "fyz_year3", "fyz_year4", - }; - static const char *subs[] = {"fyz_sub", "fyz2_sub", "fyz3_sub", "fyz4_sub"}; - NetLesson *lessons[4] = { - fyz_lessons, fyz2_lessons, fyz3_lessons, fyz4_lessons, - }; - char **paths[4] = { - &app_progress_fyz, &app_progress_fyz2, - &app_progress_fyz3, &app_progress_fyz4, - }; - - if (fyz_ready) - return; - for (int y = 0; y < 4; y++) { - FyzTrack *T = &fyz_tracks[y]; - - T->map_page = maps[y]; - T->back_page = "fyzyears"; - T->title_key = titles[y]; - T->sub_key = subs[y]; - T->progress_path = paths[y]; - T->lessons = lessons[y]; - T->note_last_w = -1; - for (int i = 0; i < FYZ_N; i++) { - T->unit_keys[i] = all_keys[y][i]; - T->sub_keys[i] = all_subs[y][i]; - } - } - fyz_ready = TRUE; -} - -static void fyz_save(FyzTrack *T) { - GKeyFile *kf; - char *path; - gchar *data; - - if (!T->progress_path || !*T->progress_path) - return; - path = *T->progress_path; - kf = g_key_file_new(); - for (int i = 0; i < FYZ_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, T->lessons[i].done); - } - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - if (data) { - GError *err = NULL; - - g_file_set_contents(path, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -static void fyz_load_one(FyzTrack *T) { - GKeyFile *kf; - GError *err = NULL; - const char *path; - - if (!T->progress_path || !*T->progress_path) - return; - path = *T->progress_path; - kf = g_key_file_new(); - if (!g_key_file_load_from_file(kf, path, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - for (int i = 0; i < FYZ_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - T->lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - g_key_file_free(kf); -} - -void fyz_load_progress(void) { - fyz_ensure(); - for (int y = 0; y < 4; y++) - fyz_load_one(&fyz_tracks[y]); -} - -void fyz_rail_theme_reset(void) { -} - -static void fyz_refresh(FyzTrack *T) { - for (int i = 0; i < FYZ_N; i++) { - GtkWidget *node = T->nodes[i]; - GtkWidget *icon = T->lessons[i].done_icon; - - if (!node) - continue; - if (T->lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -static void fyz_mark_done(FyzTrack *T, int lesson_id) { - if (lesson_id < 0 || lesson_id >= FYZ_N) - return; - if (T->lessons[lesson_id].done) - return; - T->lessons[lesson_id].done = TRUE; - fyz_save(T); - fyz_refresh(T); - refresh_stats_ui(); -} - -void progress_for_fyz(ProgressSum *out) { - if (!out) - return; - fyz_ensure(); - for (int y = 0; y < 4; y++) { - FyzTrack *T = &fyz_tracks[y]; - - out->total_ex += FYZ_N; - out->open_units += FYZ_N; - for (int i = 0; i < FYZ_N; i++) { - if (T->lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - } -} - -static void fyz_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof(name), "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static GtkWidget *fyz_lesson_button(FyzTrack *T, int index) { - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - GtkWidget *sub; - GtkWidget *icon; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 84); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", index + 1); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, T->unit_keys[index], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - sub = gtk_label_new(NULL); - i18n_bind(sub, T->sub_keys[index], 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0.0); - gtk_widget_add_css_class(sub, "hint"); - gtk_box_append(GTK_BOX(texts), sub); - - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_widget_set_valign(icon, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), icon); - T->lessons[index].done_icon = icon; - T->nodes[index] = btn; - g_signal_connect(btn, "clicked", G_CALLBACK(fyz_open_unit), - &T->lessons[index]); - return btn; -} - -static GtkWidget *fyz_build_list(FyzTrack *T) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - - fyz_ensure(); - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar(T->back_page, T->title_key, T->sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_START); - gtk_widget_set_size_request(list, 520, -1); - gtk_widget_set_margin_bottom(list, 12); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (int i = 0; i < FYZ_N; i++) - gtk_box_append(GTK_BOX(list), fyz_lesson_button(T, i)); - fyz_refresh(T); - return page; -} - -GtkWidget *build_fyzmap_page(void) { return fyz_build_list(&fyz_tracks[0]); } -GtkWidget *build_fyz2map_page(void) { return fyz_build_list(&fyz_tracks[1]); } -GtkWidget *build_fyz3map_page(void) { return fyz_build_list(&fyz_tracks[2]); } -GtkWidget *build_fyz4map_page(void) { return fyz_build_list(&fyz_tracks[3]); } - -static GtkWidget *fyz_year_button(int year, const char *target, - const char *title_key, const char *sub_key) { - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - GtkWidget *sub; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 84); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", year); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, title_key, 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - sub = gtk_label_new(NULL); - i18n_bind(sub, sub_key, 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0.0); - gtk_widget_add_css_class(sub, "hint"); - gtk_box_append(GTK_BOX(texts), sub); - - g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - return btn; -} - -GtkWidget *build_fyzyears_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - static const char *targets[] = {"fyzmap", "fyz2map", "fyz3map", "fyz4map"}; - static const char *titles[] = { - "fyz_year1", "fyz_year2", "fyz_year3", "fyz_year4", - }; - static const char *subs[] = {"fyz_sub", "fyz2_sub", "fyz3_sub", "fyz4_sub"}; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "Fyzika", "fyz_years_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 480, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (int y = 0; y < 4; y++) - gtk_box_append(GTK_BOX(list), - fyz_year_button(y + 1, targets[y], titles[y], subs[y])); - return page; -} - -static void fyz_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void fyz_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L || L->idx == 0) - return; - L->idx--; - fyz_slide_apply(L); -} - -static void fyz_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - fyz_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -static void fyz_rescale(FyzTrack *T, int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < FYZ_N; i++) - net_rescale_lesson_notes(&T->lessons[i], body, head, kick); -} - -static gboolean fyz_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - FyzTrack *T = data; - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - if (width != T->note_last_w) { - T->note_last_w = width; - fyz_rescale(T, width); - } - return G_SOURCE_CONTINUE; -} - -GtkWidget *fyz_unit_page(int year, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides) { - FyzTrack *T; - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - fyz_ensure(); - if (year < 0 || year > 3) - year = 0; - T = &fyz_tracks[year]; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar(T->map_page, title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "s%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, fyz_note_tick, T, NULL); - T->note_last_w = -1; - fyz_rescale(T, 0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(fyz_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(fyz_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - fyz_slide_apply(L); - return page; -} - -void fyz_lessons_apply_lang(void) { - fyz_ensure(); - for (int y = 0; y < 4; y++) { - for (int i = 0; i < FYZ_N; i++) - fyz_slide_apply(&fyz_tracks[y].lessons[i]); - } -} - -typedef struct { - const ChoiceQ *qs; - int n; - int n_opts; - FyzTrack *track; - int lesson_id; - GtkWidget *feedback; - GtkToggleButton **toggles; - GtkWidget **hints; -} FyzMcqCtx; - -static void fyz_mcq_check(GtkButton *button, gpointer data) { - FyzMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - fyz_mark_done(ctx->track, ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -GtkWidget *fyz_mcq_page(int year, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - FyzMcqCtx *ctx = g_new0(FyzMcqCtx, 1); - int n_opts = qs[0].n_options; - - fyz_ensure(); - if (year < 0 || year > 3) - year = 0; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->track = &fyz_tracks[year]; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(fyz_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - return page; -} diff --git a/src/german_course.c b/src/german_course.c deleted file mode 100644 index 9714719..0000000 --- a/src/german_course.c +++ /dev/null @@ -1,234 +0,0 @@ -#include "graduately.h" - -/* Skill course next to the three textbook units. Four years, same - * listening / reading / writing player as English. */ - -#define DE_YEARS 4 -#define DE_N 6 - -#include "german_lessons.inc" - -static NetLesson de_rt[DE_YEARS][DE_N]; -static char de_map_page[DE_YEARS][16]; -static char de_unit_page[DE_YEARS][DE_N][16]; -static char de_ex_page[DE_YEARS][DE_N][16]; -static char de_title_key[DE_YEARS][DE_N][16]; -static char de_sub_key[DE_YEARS][DE_N][20]; -static gboolean de_ready; - -static void de_prepare(void) { - if (de_ready) - return; - de_ready = TRUE; - for (int y = 0; y < DE_YEARS; y++) { - g_snprintf(de_map_page[y], sizeof de_map_page[y], "de%dmap", y + 1); - for (int i = 0; i < DE_N; i++) { - g_snprintf(de_unit_page[y][i], sizeof de_unit_page[y][i], - "de%dunit%d", y + 1, i + 1); - g_snprintf(de_ex_page[y][i], sizeof de_ex_page[y][i], - "de%dex%d", y + 1, i + 1); - g_snprintf(de_title_key[y][i], sizeof de_title_key[y][i], - "de_y%d_u%d", y + 1, i + 1); - g_snprintf(de_sub_key[y][i], sizeof de_sub_key[y][i], - "de_y%d_u%d_sub", y + 1, i + 1); - de_rt[y][i].unit_page = de_unit_page[y][i]; - de_rt[y][i].ex_page = de_ex_page[y][i]; - de_rt[y][i].n_slides = (guint)de_lessons[y][i].n_slides; - } - } -} - -static void de_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - gchar *data; - GError *err = NULL; - - for (int y = 0; y < DE_YEARS; y++) { - for (int i = 0; i < DE_N; i++) { - char key[8]; - - g_snprintf(key, sizeof key, "%d-%d", y + 1, i + 1); - g_key_file_set_boolean(kf, "done", key, de_rt[y][i].done); - } - } - data = g_key_file_to_data(kf, NULL, NULL); - if (!g_file_set_contents(PROGRESS_DE, data, -1, &err)) { - g_warning("german course: %s", err->message); - g_error_free(err); - } - g_free(data); - g_key_file_free(kf); -} - -void de_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - de_prepare(); - if (!g_key_file_load_from_file(kf, PROGRESS_DE, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - for (int y = 0; y < DE_YEARS; y++) { - for (int i = 0; i < DE_N; i++) { - char key[8]; - - g_snprintf(key, sizeof key, "%d-%d", y + 1, i + 1); - de_rt[y][i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - } - g_key_file_free(kf); -} - -static void mark_de_done(int year, int index) { - if (year < 0 || year >= DE_YEARS || index < 0 || index >= DE_N) - return; - if (de_rt[year][index].done) - return; - de_rt[year][index].done = TRUE; - de_save_progress(); - refresh_stats_ui(); -} - -void progress_for_de(ProgressSum *out) { - out->total_ex += DE_YEARS * DE_N; - out->open_units += DE_YEARS * DE_N; - for (int y = 0; y < DE_YEARS; y++) { - for (int i = 0; i < DE_N; i++) { - if (de_rt[y][i].done) { - out->done_ex++; - out->done_units++; - } - } - } -} - -void de_lessons_apply_lang(void) { - for (int y = 0; y < DE_YEARS; y++) - for (int i = 0; i < DE_N; i++) - skill_slide_apply(&de_rt[y][i]); -} - -static GtkWidget *de_nav_button(const char *title_key, const char *sub_key, - const char *target, const char *badge) { - GtkWidget *btn = gtk_button_new(); - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - GtkWidget *num = gtk_label_new(badge); - GtkWidget *texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - GtkWidget *title = gtk_label_new(NULL); - GtkWidget *sub = gtk_label_new(NULL); - - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_widget_set_margin_top(row, 10); - gtk_widget_set_margin_bottom(row, 10); - gtk_button_set_child(GTK_BUTTON(btn), row); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - i18n_bind(title, title_key, 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - i18n_bind(sub, sub_key, 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0); - gtk_widget_add_css_class(sub, "quiz-intro"); - gtk_box_append(GTK_BOX(texts), sub); - g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - return btn; -} - -static GtkWidget *de_list_page(const char *back, const char *title, - const char *sub, GtkWidget *list) { - GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *scroll = gtk_scrolled_window_new(); - - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), top_bar(back, title, sub)); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 520, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - return page; -} - -GtkWidget *build_dehome_page(void) { - GtkWidget *list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - static const char *years[] = { - "de_year1", "de_year2", "de_year3", "de_year4", - }; - static const char *subs[] = { - "de_y1_sub", "de_y2_sub", "de_y3_sub", "de_y4_sub", - }; - - de_prepare(); - gtk_box_append(GTK_BOX(list), - de_nav_button("de_book_title", "de_book_sub", "roadmap", "U")); - for (int y = 0; y < DE_YEARS; y++) { - char badge[8]; - - g_snprintf(badge, sizeof badge, "%d", y + 1); - gtk_box_append(GTK_BOX(list), - de_nav_button(years[y], subs[y], de_map_page[y], badge)); - } - return de_list_page("subjects", "Deutsch", "de_home_sub", list); -} - -static GtkWidget *build_de_map(int year) { - GtkWidget *list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - static const char *year_keys[] = { - "de_year1", "de_year2", "de_year3", "de_year4", - }; - static const char *sub_keys[] = { - "de_y1_sub", "de_y2_sub", "de_y3_sub", "de_y4_sub", - }; - - de_prepare(); - for (int i = 0; i < DE_N; i++) { - char badge[8]; - - g_snprintf(badge, sizeof badge, "%d", i + 1); - gtk_box_append(GTK_BOX(list), - de_nav_button(de_title_key[year][i], - de_sub_key[year][i], - de_unit_page[year][i], badge)); - } - return de_list_page("dehome", year_keys[year], sub_keys[year], list); -} - -void add_de_pages(GtkStack *stack) { - de_prepare(); - for (int y = 0; y < DE_YEARS; y++) { - gtk_stack_add_named(stack, build_de_map(y), de_map_page[y]); - for (int i = 0; i < DE_N; i++) { - gtk_stack_add_named(stack, - skill_unit_page(&de_rt[y][i], &de_lessons[y][i], - de_map_page[y], de_title_key[y][i], - de_sub_key[y][i]), - de_unit_page[y][i]); - gtk_stack_add_named(stack, - skill_ex_page(&de_lessons[y][i], y, i, mark_de_done, - de_unit_page[y][i], de_title_key[y][i], "de"), - de_ex_page[y][i]); - } - } -} diff --git a/src/german_i18n.inc b/src/german_i18n.inc deleted file mode 100644 index ec099ec..0000000 --- a/src/german_i18n.inc +++ /dev/null @@ -1,60 +0,0 @@ - {"de_home_sub", "Učebnice a čtyři ročníky s poslechem, čtením a psaním.", "The textbook plus four years of listening, reading and writing."}, - {"de_book_title", "Učebnice", "Textbook"}, - {"de_book_sub", "Neue Freunde, Aus aller Welt a Bei uns zu Hause.", "Neue Freunde, Aus aller Welt and Bei uns zu Hause."}, - {"de_years_title", "Ročníky", "School years"}, - {"de_y1_sub", "Pozdravy, rodina, škola, jídlo a den. Úroveň A1.", "Greetings, family, school, food and the day. Level A1."}, - {"de_year1", "1. ročník", "Year 1"}, - {"de_y1_u1", "Pozdravy a představení", "Greetings and introductions"}, - {"de_y1_u1_sub", "Sein, heißen a woher. Doplňování a kvíz.", "Sein, heißen and woher. Gaps and a quiz."}, - {"de_y1_u2", "Rodina", "Family"}, - {"de_y1_u2_sub", "Haben a přivlastňovací zájmena. Čtení a doplňování.", "Haben and possessives. Reading and gaps."}, - {"de_y1_u3", "Ve škole", "At school"}, - {"de_y1_u3_sub", "Přítomný čas. Poslech a doplňování.", "The present tense. Listening and gaps."}, - {"de_y1_u4", "Jídlo", "Food"}, - {"de_y1_u4_sub", "Möchten a 4. pád. Krátký dialog a kvíz.", "Möchten and the accusative. A short dialogue and a quiz."}, - {"de_y1_u5", "Můj den", "My day"}, - {"de_y1_u5_sub", "Čas a odlučitelné předpony. Čtení a doplňování.", "Time and separable verbs. Reading and gaps."}, - {"de_y1_u6", "Test 1. ročníku", "Year 1 test"}, - {"de_y1_u6_sub", "Čtení, poslech, gramatika A1 a krátké psaní.", "Reading, listening, A1 grammar and a short text."}, - {"de_y2_sub", "Město, nákupy, volný čas, bydlení a perfektum. Úroveň A2.", "Town, shopping, free time, home and the perfect. Level A2."}, - {"de_year2", "2. ročník", "Year 2"}, - {"de_y2_u1", "Ve městě", "In town"}, - {"de_y2_u1_sub", "Wo a wohin, předložky. Doplňování a kvíz.", "Wo and wohin, prepositions. Gaps and a quiz."}, - {"de_y2_u2", "Nákupy", "Shopping"}, - {"de_y2_u2_sub", "Ceny a 4. pád v obchodě. Čtení a kvíz.", "Prices and the accusative in a shop. Reading and a quiz."}, - {"de_y2_u3", "Volný čas", "Free time"}, - {"de_y2_u3_sub", "Modální slovesa. Poslech a doplňování.", "Modal verbs. Listening and gaps."}, - {"de_y2_u4", "Bydlení", "Home"}, - {"de_y2_u4_sub", "Místnosti a předložky. Popis bytu.", "Rooms and prepositions. A description of a flat."}, - {"de_y2_u5", "Perfektum", "The perfect tense"}, - {"de_y2_u5_sub", "Haben nebo sein a příčestí. Doplňování a kvíz.", "Haben or sein plus the participle. Gaps and a quiz."}, - {"de_y2_u6", "Test 2. ročníku", "Year 2 test"}, - {"de_y2_u6_sub", "Čtení, poslech, A2 a krátké psaní.", "Reading, listening, A2 and a short text."}, - {"de_y3_sub", "Zdraví, cestování, věty s weil, práce a srovnání. Úroveň A2+.", "Health, travel, weil-clauses, work and comparison. Level A2+."}, - {"de_year3", "3. ročník", "Year 3"}, - {"de_y3_u1", "U lékaře", "At the doctor's"}, - {"de_y3_u1_sub", "Tělo, tut a rozkaz. Čtení a kvíz.", "The body, tut and the imperative. Reading and a quiz."}, - {"de_y3_u2", "Cesta", "A trip"}, - {"de_y3_u2_sub", "Perfektum v vyprávění. Poslech a doplňování.", "The perfect in a story. Listening and gaps."}, - {"de_y3_u3", "Weil, dass, wenn", "Weil, dass, wenn"}, - {"de_y3_u3_sub", "Vedlejší věta a sloveso na konci. Doplňování a kvíz.", "Subordinate clauses and the verb at the end. Gaps and a quiz."}, - {"de_y3_u4", "Práce a vykání", "Work and Sie"}, - {"de_y3_u4_sub", "Formální věta. E-mail a kvíz.", "A formal sentence. An email and a quiz."}, - {"de_y3_u5", "Srovnání a příroda", "Comparison and nature"}, - {"de_y3_u5_sub", "Komparativ a superlativ. Čtení a doplňování.", "Comparative and superlative. Reading and gaps."}, - {"de_y3_u6", "Test 3. ročníku", "Year 3 test"}, - {"de_y3_u6_sub", "Čtení, poslech, weil a krátký názor.", "Reading, listening, weil and a short opinion."}, - {"de_y4_sub", "Média, formální dopis, čtení, konjunktiv a maturitní témata. Úroveň B1.", "Media, a formal letter, reading, the subjunctive and exam topics. Level B1."}, - {"de_year4", "4. ročník", "Year 4"}, - {"de_y4_u1", "Média", "The media"}, - {"de_y4_u1_sub", "Poslech rozhovoru a kvíz k slovům.", "An interview and a vocabulary quiz."}, - {"de_y4_u2", "Formální e-mail", "A formal email"}, - {"de_y4_u2_sub", "Stížnost nebo žádost. Psaní a kvíz.", "A complaint or a request. Writing and a quiz."}, - {"de_y4_u3", "Čtení: noční vlak", "Reading: the night train"}, - {"de_y4_u3_sub", "Delší text a otázky jako u maturity.", "A longer text and exam-style questions."}, - {"de_y4_u4", "Kdyby", "If I were"}, - {"de_y4_u4_sub", "Konjunktiv II. Doplňování a kvíz.", "Konjunktiv II. Gaps and a quiz."}, - {"de_y4_u5", "Témata k maturitě", "Exam topics"}, - {"de_y4_u5_sub", "Kolokace k běžným okruhům. Doplňování a kvíz.", "Collocations for common topics. Gaps and a quiz."}, - {"de_y4_u6", "Cvičná zkouška", "A practice paper"}, - {"de_y4_u6_sub", "Čtení, poslech, gramatika a krátký text.", "Reading, listening, grammar and a short text."}, diff --git a/src/german_lessons.inc b/src/german_lessons.inc deleted file mode 100644 index 73c3655..0000000 --- a/src/german_lessons.inc +++ /dev/null @@ -1,1453 +0,0 @@ -/* Generated by scripts/gen-german.py. Do not edit by hand. */ - -static const NetSlide de_y1_l1_slides[] = { - { - "1 / 2 • Sein", "Kdo jsem", "Tip: věk je Ich bin 16, ne Ich habe 16 Jahre.", - { - "ich bin, du bist, er/sie/es ist, wir/ihr/sie sind.", - "Ich heiße Anna. Wie heißt du?", - "Woher kommst du? — Ich komme aus Prag.", - "Guten Tag, Hallo, Tschüss, Danke, Bitte.", - NULL, - }, - }, - { - "2 / 2 • Otázka", "Sloveso na druhém místě", "Tip: v otázce je sloveso hned za tázacím slovem.", - { - "Wie heißt du? Wo wohnst du? Was machst du?", - "Zápor: Ich heiße nicht Peter. Er ist nicht hier.", - "Sie s velkým S je vykání. sie s malým je ona nebo oni.", - "Zdvořilost: Guten Morgen, Frau Novak.", - NULL, - }, - }, -}; - -static const TypedQ de_y1_l1_gaps[] = { - {"Ich ___ Anna.", "heiße|heisse", "heißen ve 1. osobě."}, - {"___ kommst du?", "Woher", "Odkud."}, - {"Wir ___ Schüler.", "sind", "wir + sein."}, - {"Er ___ mein Bruder.", "ist", "er + sein."}, - {"Wie ___ du?", "heißt|heisst", "du + heißen."}, -}; - -static const ChoiceQ de_y1_l1_quiz[] = { - {"Jak se německy řekne věk?", {"Ich habe 16 Jahre.", "Ich bin 16 Jahre alt.", "Ich ist 16.", "Ich bin 16 Jahre."}, 4, 1}, - {"Woher kommst du?", {"Ich bin gut.", "Ich komme aus Brno.", "Ich heiße aus Brno.", "Ich wohne kommst."}, 4, 1}, - {"du + sein", {"du ist", "du bist", "du sind", "du bin"}, 4, 1}, - {"Který pozdrav je odpoledne neutrální?", {"Gute Nacht", "Guten Tag", "Tschüss gleich", "Bitte sehr Tag"}, 4, 1}, -}; -static const char *de_y1_l1_quiz_hints[] = { - "bin + Jahre alt.", - "kommen aus + město.", - "du bist.", - "Guten Tag.", -}; - -static const NetSlide de_y1_l2_slides[] = { - { - "1 / 2 • Haben", "Co mám", "Tip: haben není věk. Ich habe einen Bruder.", - { - "ich habe, du hast, er hat, wir haben.", - "Přivlastňovací: mein, dein, sein, ihr, unser, euer.", - "Člen der/die/das se v 1. pádu u jmen učí s podstatným jménem.", - "die Mutter, der Vater, die Schwester, der Bruder, die Eltern.", - NULL, - }, - }, - { - "2 / 2 • Text", "Krátký medailon", "Tip: v textu hledejte čísla a kdo s kým bydlí.", - { - "und spojuje, aber staví proti.", - "nicht stojí před tím, co popíráme.", - "auch = taky.", - "zu Hause = doma.", - NULL, - }, - }, -}; - -static const char *de_y1_l2_read = "Ich heiße Lukas und ich bin fünfzehn. Ich wohne mit meinen Eltern in Pilsen. Ich habe eine Schwester. Sie heißt Eva und sie ist zwölf. Mein Vater ist Lehrer und meine Mutter arbeitet im Krankenhaus. Wir haben auch einen Hund. Er heißt Max. Am Wochenende besuchen wir meine Oma. Sie wohnt nicht bei uns, aber sie wohnt in derselben Stadt."; - -static const ChoiceQ de_y1_l2_readq[] = { - {"Wie alt ist Lukas?", {"Zwölf", "Fünfzehn", "Sechzehn", "Der Text sagt es nicht"}, 4, 1}, - {"Was ist der Vater von Beruf?", {"Arzt", "Lehrer", "Koch", "Schüler"}, 4, 1}, - {"Wo wohnt die Oma?", {"Bei der Familie", "In einer anderen Stadt", "In derselben Stadt", "Im Krankenhaus"}, 4, 2}, - {"Wie heißt der Hund?", {"Lukas", "Eva", "Max", "Der Text nennt keinen Namen"}, 4, 2}, -}; -static const char *de_y1_l2_readq_hints[] = { - "ich bin fünfzehn.", - "Mein Vater ist Lehrer.", - "in derselben Stadt.", - "Er heißt Max.", -}; - -static const TypedQ de_y1_l2_gaps[] = { - {"Ich ___ eine Schwester.", "habe", "haben, 1. osoba."}, - {"___ Vater ist Lehrer.", "Mein", "Přivlastňovací u maskulina."}, - {"Sie ___ zwölf.", "ist", "Věk: sein."}, - {"Wir ___ einen Hund.", "haben", "wir haben."}, -}; - -static const NetSlide de_y1_l3_slides[] = { - { - "1 / 2 • Präsens", "Pravidelné sloveso", "Tip: kmen + koncovka. spielen: ich spiele, du spielst, er spielt.", - { - "ich -e, du -st, er/sie/es -t, wir -en, ihr -t, sie -en.", - "Otázka bez tázacího slova: Spielst du Fußball?", - "Zápor: Ich spiele nicht Klavier.", - "Sloveso je ve větě na druhém místě: Heute spiele ich Tennis.", - NULL, - }, - }, - { - "2 / 2 • Poslech", "Rozvrh", "Tip: nejdřív otázky, pak nahrávka. Chyťte předměty a dny.", - { - "am Montag, am Dienstag, in der Pause.", - "das Fach, die Stunde, die Hausaufgabe.", - "gern = rád. Ich lerne gern Deutsch.", - "lieber = radši.", - NULL, - }, - }, -}; - -static const char *de_y1_l3_listen = "Hallo, ich bin Mia. Am Montag haben wir Deutsch, Mathe und Biologie. Deutsch mag ich gern, weil die Lehrerin nett ist. Mathe mag ich nicht. In der Pause esse ich ein Brötchen und spreche mit Eva. Nach der Schule mache ich Hausaufgaben oder ich spiele Volleyball. Am Abend lese ich oder ich höre Musik. Um zehn gehe ich ins Bett."; - -static const ChoiceQ de_y1_l3_listenq[] = { - {"Welches Fach mag Mia gern?", {"Mathe", "Deutsch", "Volleyball", "Musik nur"}, 4, 1}, - {"Warum?", {"Weil es leicht ist", "Weil die Lehrerin nett ist", "Weil sie keine Hausaufgaben hat", "Weil es am Abend ist"}, 4, 1}, - {"Was macht sie in der Pause?", {"Sie schläft", "Sie isst ein Brötchen und spricht mit Eva", "Sie spielt Volleyball", "Sie lernt Mathe"}, 4, 1}, - {"Wann geht sie ins Bett?", {"Um acht", "Um neun", "Um zehn", "Um elf"}, 4, 2}, -}; -static const char *de_y1_l3_listenq_hints[] = { - "Deutsch mag ich gern.", - "weil die Lehrerin nett ist.", - "esse ich ein Brötchen und spreche mit Eva.", - "Um zehn.", -}; - -static const TypedQ de_y1_l3_gaps[] = { - {"Ich ___ (spielen) gern Tennis.", "spiele", "ich + -e."}, - {"___ du heute Deutsch?", "Lernst", "Otázka: Lernst du heute Deutsch?"}, - {"Er ___ (wohnen) in Prag.", "wohnt", "er + -t."}, - {"Wir ___ (machen) Hausaufgaben.", "machen", "wir + -en."}, -}; - -static const NetSlide de_y1_l4_slides[] = { - { - "1 / 2 • Möchten", "Chtěl bych", "Tip: ich möchte, du möchtest, er möchte. Je to zdvořilé chtít.", - { - "Ich möchte einen Apfel. die → eine, der → einen v akuzativu.", - "Maskulinum: der Salat → einen Salat. Neutrum: das Brot → ein Brot.", - "Femininum se v akuzativu nemění: die Suppe → eine Suppe.", - "Was möchten Sie? je vykání v restauraci.", - NULL, - }, - }, - { - "2 / 2 • Psaní", "Objednávka", "Tip: začněte Guten Tag a skončete Danke.", - { - "Ich möchte … und …", - "Für mich bitte einen Tee.", - "Die Rechnung, bitte.", - "Es schmeckt gut.", - NULL, - }, - }, -}; - -static const char *de_y1_l4_write[] = { - "Schreib mindestens 25 Wörter. Bestell im Café etwas zu essen und zu trinken. Benutze möchte und bitte.", - "Guten Tag, ich möchte eine Suppe und ein Brot, bitte. Für mich bitte auch einen Tee. Meine Schwester möchte einen Apfelsaft. Die Suppe schmeckt gut. Die Rechnung, bitte. Danke, das ist alles.", - "möchte|bitte", - "25", -}; - -static const ChoiceQ de_y1_l4_quiz[] = { - {"der Salat im Akkusativ", {"eine Salat", "einen Salat", "einem Salat", "der Salat bleibt immer"}, 4, 1}, - {"Was ist höflich?", {"Ich will sofort Pizza.", "Ich möchte eine Suppe, bitte.", "Gib mir Essen.", "Du bist Hunger."}, 4, 1}, - {"die Suppe im Akkusativ", {"einen Suppe", "einem Suppe", "eine Suppe", "ein Suppe"}, 4, 2}, - {"Ich ___ einen Tee.", {"möchte", "möchtest", "möchten du", "bist möchte"}, 4, 0}, -}; -static const char *de_y1_l4_quiz_hints[] = { - "Maskulinum: einen.", - "möchte + bitte.", - "Femininum se nemění: eine Suppe.", - "ich möchte.", -}; - -static const NetSlide de_y1_l5_slides[] = { - { - "1 / 2 • Čas", "Um, am, im", "Tip: um + hodina, am + den, im + měsíc nebo roční období.", - { - "Um sieben stehe ich auf. Am Montag habe ich Deutsch.", - "Im Sommer fahre ich ans Meer.", - "Odlučitelné: aufstehen → Ich stehe um sieben auf.", - "Předpona jde na konec věty.", - NULL, - }, - }, - { - "2 / 2 • Pořadí", "Nejdřív, potom, nakonec", "Tip: zuerst, dann, danach, zum Schluss.", - { - "Zuerst stehe ich auf. Dann frühstücke ich.", - "Danach gehe ich zur Schule.", - "Am Abend sehe ich fern.", - "fernsehen → Ich sehe abends fern.", - NULL, - }, - }, -}; - -static const char *de_y1_l5_read = "An einem Schultag stehe ich um halb sieben auf. Zuerst dusche ich, dann frühstücke ich Brot und Tee. Um sieben fahre ich mit der Straßenbahn zur Schule. Der Unterricht beginnt um acht. Nach der Schule mache ich Hausaufgaben. Am Abend sehe ich manchmal fern oder ich rufe eine Freundin an. Um zehn gehe ich ins Bett."; - -static const ChoiceQ de_y1_l5_readq[] = { - {"Wann steht sie auf?", {"Um zehn", "Um halb sieben", "Um acht", "Am Abend"}, 4, 1}, - {"Womit fährt sie zur Schule?", {"Mit dem Auto", "Mit der Straßenbahn", "Zu Fuß nur", "Mit dem Zug"}, 4, 1}, - {"Was macht sie nach der Schule?", {"Sie schläft sofort", "Sie macht Hausaufgaben", "Sie fährt ans Meer", "Sie hat frei"}, 4, 1}, - {"anrufen v větě Ich ___ eine Freundin ___.", {"rufe … an", "anrufe …", "rufe … auf", "stehe … an"}, 4, 0}, -}; -static const char *de_y1_l5_readq_hints[] = { - "um halb sieben.", - "mit der Straßenbahn.", - "mache ich Hausaufgaben.", - "Předpona an jde na konec.", -}; - -static const TypedQ de_y1_l5_gaps[] = { - {"Ich stehe um sieben ___.", "auf", "aufstehen."}, - {"___ Montag habe ich Deutsch.", "Am", "am + den."}, - {"Der Unterricht beginnt ___ acht.", "um", "um + hodina."}, - {"Ich sehe abends ___.", "fern", "fernsehen."}, -}; - -static const NetSlide de_y1_l6_slides[] = { - { - "1 / 2 • A1", "Co už má sedět", "Tip: bin pro věk, habe pro vlastnictví, sloveso na druhém místě.", - { - "sein, haben, heißen, wohnen, möchten.", - "mein/dein, ein/einen.", - "um, am, odlučitelná předpona na konci.", - "Psaní: Guten Tag a bitte.", - NULL, - }, - }, - { - "2 / 2 • Kontrola", "Nejčastější chyby", "Tip: po kontrole si přečtěte nápovědy.", - { - "Ich bin 15, ne Ich habe 15 Jahre.", - "Ich komme aus Prag, ne Ich bin aus Prag kommen.", - "einen Apfel, ne ein Apfel jako předmět.", - "Ich stehe auf, ne Ich aufstehe.", - NULL, - }, - }, -}; - -static const char *de_y1_l6_read = "Nina ist sechzehn und wohnt in Olomouc. Sie hat einen Bruder. Er heißt Tom und er ist zehn. Am Morgen isst Nina Brot. In der Schule lernt sie gern Deutsch, aber sie mag Mathe nicht. Nach der Schule ruft sie ihre Freundin an."; - -static const ChoiceQ de_y1_l6_readq[] = { - {"Wo wohnt Nina?", {"In Prag", "In Olomouc", "In Brno", "Der Text sagt es nicht"}, 4, 1}, - {"Wie alt ist Tom?", {"Sechzehn", "Zehn", "Zwölf", "Fünfzehn"}, 4, 1}, - {"Was macht Nina nach der Schule?", {"Sie schläft", "Sie ruft ihre Freundin an", "Sie kocht für Tom", "Sie fährt nach Wien"}, 4, 1}, -}; -static const char *de_y1_l6_readq_hints[] = { - "wohnt in Olomouc.", - "er ist zehn.", - "ruft sie ihre Freundin an.", -}; - -static const char *de_y1_l6_listen = "Guten Tag, ich möchte einen Salat und ein Wasser, bitte. Haben Sie auch Brot? Ja, natürlich. Dann bitte noch ein Brot. Möchten Sie Kaffee? Nein, danke, nur Wasser. Die Rechnung mache ich später."; - -static const ChoiceQ de_y1_l6_listenq[] = { - {"Was bestellt die Person zuerst?", {"Kaffee und Kuchen", "Einen Salat und ein Wasser", "Nur Brot", "Eine Suppe"}, 4, 1}, - {"Möchte sie Kaffee?", {"Ja", "Nein", "Nur am Abend", "Der Text sagt es nicht"}, 4, 1}, - {"Was kommt noch dazu?", {"Ein Brot", "Ein Tee", "Ein Hund", "Die Oma"}, 4, 0}, -}; -static const char *de_y1_l6_listenq_hints[] = { - "einen Salat und ein Wasser.", - "Nein, danke.", - "noch ein Brot.", -}; - -static const char *de_y1_l6_write[] = { - "Schreib mindestens 30 Wörter über deine Familie. Benutze bin und habe.", - "Ich bin sechzehn und ich wohne in Prag. Ich habe eine Schwester und meine Eltern. Mein Vater ist nett und meine Mutter arbeitet viel. Wir haben keine Katze, aber ich habe einen Freund in der Schule. Am Sonntag besuchen wir oft meine Oma.", - "bin|habe", - "30", -}; - -static const ChoiceQ de_y1_l6_quiz[] = { - {"Ich ___ fünfzehn Jahre alt.", {"habe", "bin", "ist", "hat"}, 4, 1}, - {"Sie hat ___ Bruder.", {"eine", "einen", "einem", "der"}, 4, 1}, - {"Ich stehe um sieben ___.", {"auf", "an", "ein", "um"}, 4, 0}, - {"___ du aus Prag?", {"Kommst", "Wohnst", "Bist", "Hast"}, 4, 0}, -}; -static const char *de_y1_l6_quiz_hints[] = { - "Alter mit sein.", - "der Bruder → einen Bruder.", - "aufstehen.", - "kommen aus: Kommst du aus Prag?", -}; - -static const NetSlide de_y2_l1_slides[] = { - { - "1 / 2 • Místo", "Kde a kam", "Tip: wo ptá kde to je, wohin ptá kam někdo jde.", - { - "Wo ist der Bahnhof? — Er ist neben der Post.", - "Wohin gehst du? — Ich gehe zum Bahnhof.", - "in, an, auf, neben, zwischen, gegenüber.", - "zu + der = zur, zu + dem = zum.", - NULL, - }, - }, - { - "2 / 2 • Popis cesty", "Krátké věty", "Tip: zuerst, dann, dann links, dann rechts.", - { - "Gehen Sie geradeaus.", - "Nehmen Sie die erste Straße links.", - "Die Apotheke ist gegenüber vom Park.", - "Es ist nicht weit.", - NULL, - }, - }, -}; - -static const TypedQ de_y2_l1_gaps[] = { - {"Wo ___ der Bahnhof?", "ist", "Wo + sein."}, - {"Ich gehe ___ Bahnhof.", "zum", "zu + dem = zum."}, - {"Die Post ist ___ der Schule.", "neben", "vedle."}, - {"___ gehst du?", "Wohin", "Kam."}, - {"Gehen Sie ___.", "geradeaus", "rovně."}, -}; - -static const ChoiceQ de_y2_l1_quiz[] = { - {"Wohin bedeutet…", {"wo", "woher", "kam", "wann"}, 4, 2}, - {"zu + dem", {"zur", "zum", "zu dem bleibt immer zwei Wörter", "beim"}, 4, 1}, - {"zu + der", {"zum", "zur", "zu die", "am"}, 4, 1}, - {"Die Apotheke ist ___ vom Park.", {"gegenüber", "weil", "um", "aufstehe"}, 4, 0}, -}; -static const char *de_y2_l1_quiz_hints[] = { - "wohine = kam.", - "zum.", - "zur.", - "gegenüber.", -}; - -static const NetSlide de_y2_l2_slides[] = { - { - "1 / 2 • Obchod", "Kolik to stojí", "Tip: Wie viel kostet das? Es kostet fünf Euro.", - { - "Ich suche einen Pullover.", - "Haben Sie das auch in Blau?", - "Das ist mir zu teuer. Haben Sie etwas Billigeres?", - "Ich nehme den Pullover.", - NULL, - }, - }, - { - "2 / 2 • Barvy a velikost", "Velikost", "Tip: die Größe M, zu klein, zu groß.", - { - "groß, klein, billig, teuer, bequem.", - "die Jacke, der Schuh, das Hemd.", - "Zahlen: zweiundzwanzig Euro.", - "Bar oder mit Karte?", - NULL, - }, - }, -}; - -static const char *de_y2_l2_read = "Anna sucht eine Jacke. Die rote Jacke kostet neunzig Euro. Das ist ihr zu teuer. Eine blaue Jacke kostet fünfundvierzig Euro und sie ist bequem. Anna nimmt die blaue Jacke. Dazu kauft sie noch ein Hemd für ihren Bruder. Das Hemd kostet zwanzig Euro. Sie zahlt mit Karte."; - -static const ChoiceQ de_y2_l2_readq[] = { - {"Warum nimmt Anna die rote Jacke nicht?", {"Sie ist zu klein", "Sie ist zu teuer", "Es gibt sie nicht", "Sie ist nicht rot"}, 4, 1}, - {"Was kostet die blaue Jacke?", {"90 Euro", "45 Euro", "20 Euro", "22 Euro"}, 4, 1}, - {"Für wen ist das Hemd?", {"Für Anna", "Für den Bruder", "Für die Lehrerin", "Für niemanden"}, 4, 1}, - {"Wie zahlt sie?", {"Bar", "Mit Karte", "Sie zahlt nicht", "Mit dem Hemd"}, 4, 1}, -}; -static const char *de_y2_l2_readq_hints[] = { - "zu teuer.", - "fünfundvierzig Euro.", - "für ihren Bruder.", - "mit Karte.", -}; - -static const ChoiceQ de_y2_l2_quiz[] = { - {"Ich suche ___ Pullover.", {"eine", "einen", "einem", "der"}, 4, 1}, - {"Das ist mir zu ___. Ich habe nur zwanzig Euro.", {"billig", "teuer", "bequem", "blau"}, 4, 1}, - {"Wie viel ___ das?", {"kostet", "kosten du", "bist", "heißt"}, 4, 0}, - {"Sie zahlt ___ Karte.", {"mit", "zu", "am", "auf"}, 4, 0}, -}; -static const char *de_y2_l2_quiz_hints[] = { - "der Pullover → einen.", - "zu teuer.", - "kostet.", - "mit Karte.", -}; - -static const NetSlide de_y2_l3_slides[] = { - { - "1 / 2 • Modály", "können, müssen, wollen", "Tip: modální sloveso je na druhém místě, významové na konci.", - { - "Ich kann schwimmen. Du musst lernen. Wir wollen ins Kino.", - "können: ich kann, du kannst, er kann, wir können.", - "müssen: ich muss, du musst, er muss.", - "Zápor: Ich kann heute nicht kommen.", - NULL, - }, - }, - { - "2 / 2 • Koníčky", "gern a lieber", "Tip: Ich schwimme gern. Ich spiele lieber Fußball als Tennis.", - { - "das Hobby, die Mannschaft, das Training.", - "am Wochenende, in der Freizeit.", - "zu laut, zu spät.", - "Darf ich mitkommen?", - NULL, - }, - }, -}; - -static const char *de_y2_l3_listen = "Am Samstag muss ich vormittags lernen, weil wir am Montag einen Test haben. Nachmittags kann ich aber Fußball spielen. Mein Freund Paul will auch kommen. Er kann nicht so gut spielen, aber er ist nett. Abends wollen wir einen Film sehen. Ich darf nicht zu spät nach Hause kommen. Um elf muss ich zu Hause sein."; - -static const ChoiceQ de_y2_l3_listenq[] = { - {"Warum muss er vormittags lernen?", {"Weil er krank ist", "Weil am Montag ein Test ist", "Weil Paul nicht kann", "Weil der Film lang ist"}, 4, 1}, - {"Was kann er nachmittags machen?", {"Schlafen", "Fußball spielen", "Nach Wien fahren", "Kochen"}, 4, 1}, - {"Wann muss er zu Hause sein?", {"Um neun", "Um zehn", "Um elf", "Um zwölf"}, 4, 2}, - {"Was wollen sie abends machen?", {"Einen Film sehen", "Lernen", "Fußball spielen", "Einkaufen"}, 4, 0}, -}; -static const char *de_y2_l3_listenq_hints[] = { - "am Montag einen Test.", - "Fußball spielen.", - "Um elf.", - "einen Film sehen.", -}; - -static const TypedQ de_y2_l3_gaps[] = { - {"Ich ___ heute nicht kommen.", "kann", "können, ich kann."}, - {"Du ___ lernen.", "musst", "müssen, du musst."}, - {"Wir ___ ins Kino.", "wollen", "wollen, wir wollen."}, - {"Das Modalverb steht, das andere Verb steht am ___.", "Ende|Satzende", "Významové sloveso na konci."}, -}; - -static const NetSlide de_y2_l4_slides[] = { - { - "1 / 2 • Byt", "Wo steht was", "Tip: Es gibt + akuzativ. Es gibt einen Balkon.", - { - "die Küche, das Wohnzimmer, das Bad, das Schlafzimmer.", - "Das Sofa steht vor dem Fenster.", - "an der Wand, auf dem Tisch, unter dem Bett.", - "hell, dunkel, ruhig, laut, gemütlich.", - NULL, - }, - }, - { - "2 / 2 • Psaní", "Můj pokoj", "Tip: nejdřív velikost, pak nábytek a místo.", - { - "Mein Zimmer ist klein, aber hell.", - "Es gibt ein Bett und einen Schreibtisch.", - "Das Buch liegt auf dem Tisch.", - "Ich mag mein Zimmer, weil es ruhig ist.", - NULL, - }, - }, -}; - -static const char *de_y2_l4_write[] = { - "Beschreib dein Zimmer in mindestens 35 Wörtern. Benutze es gibt und weil.", - "Mein Zimmer ist klein, aber hell. Es gibt ein Bett, einen Schreibtisch und ein Fenster. Das Bett steht an der Wand und der Schreibtisch steht vor dem Fenster. Meine Bücher liegen auf dem Tisch. Ich mag das Zimmer, weil es ruhig ist und ich dort gut lernen kann.", - "weil|gibt", - "35", -}; - -static const ChoiceQ de_y2_l4_quiz[] = { - {"Es gibt ___ Balkon.", {"ein", "einen", "einem", "der"}, 4, 1}, - {"Das Buch liegt ___ dem Tisch.", {"auf", "weil", "um", "zum"}, 4, 0}, - {"gemütlich bedeutet…", {"teuer", "příjemný, útulný", "hlasitý", "prázdný"}, 4, 1}, - {"Das Bad ist…", {"die Küche", "koupelna", "ložnice", "balkon"}, 4, 1}, -}; -static const char *de_y2_l4_quiz_hints[] = { - "der Balkon → einen.", - "auf dem Tisch.", - "útulný.", - "das Bad = koupelna.", -}; - -static const NetSlide de_y2_l5_slides[] = { - { - "1 / 2 • Perfekt", "Minulost v hovoru", "Tip: haben/sein je na druhém místě, příčestí na konci.", - { - "Ich habe gestern Fußball gespielt.", - "Ich bin nach Wien gefahren. Pohyb a změna stavu berou sein.", - "ge- + kmen + t u pravidelných: gemacht, gespielt.", - "Nepravidelné: gesehen, gegessen, getrunken, genommen.", - NULL, - }, - }, - { - "2 / 2 • Signály", "Kdy", "Tip: gestern, letzte Woche, vor zwei Tagen, im Urlaub.", - { - "gehen → ist gegangen. kommen → ist gekommen.", - "bleiben → ist geblieben.", - "kaufen → hat gekauft. Lernen bere sein, protože to není pohyb.", - "Otázka: Hast du das gesehen? Bist du gekommen?", - NULL, - }, - }, -}; - -static const TypedQ de_y2_l5_gaps[] = { - {"Ich ___ gestern Tennis gespielt.", "habe", "spielen bere haben."}, - {"Wir ___ nach Berlin gefahren.", "sind", "fahren bere sein."}, - {"Er hat einen Film ___.", "gesehen", "sehen → gesehen."}, - {"___ du gut geschlafen?", "Hast", "schlafen s haben v této učebnicové řadě často haben; otázka Hast du."}, - {"Sie ist um acht ___ Hause gekommen.", "nach", "nach Hause."}, -}; - -static const ChoiceQ de_y2_l5_quiz[] = { - {"gehen im Perfekt", {"hat gegangen", "ist gegangen", "ist gehen", "hat gegehen"}, 4, 1}, - {"kaufen im Perfekt", {"ist gekauft", "hat gekauft", "hat kaufen", "ist gekaufen"}, 4, 1}, - {"Wo steht das Partizip?", {"Am Anfang", "Am Ende", "Vor dem Subjekt", "Es verschwindet"}, 4, 1}, - {"gestern bedeutet…", {"zítra", "včera", "vždycky", "nikdy"}, 4, 1}, -}; -static const char *de_y2_l5_quiz_hints[] = { - "ist gegangen.", - "hat gekauft.", - "Na konci.", - "včera.", -}; - -static const NetSlide de_y2_l6_slides[] = { - { - "1 / 2 • A2", "Nové jevy", "Tip: wohin, modální sloveso, perfektum, es gibt.", - { - "zum a zur.", - "Ich kann / muss / will + infinitiv na konci.", - "habe gemacht, bin gegangen.", - "weil přijde ve 3. ročníku pořádně, tady stačí protože v jednoduché větě.", - NULL, - }, - }, - { - "2 / 2 • Strategie", "Jedna věta", "Tip: v psaní ať je sloveso na druhém místě.", - { - "Nejdřív podmět, pak sloveso.", - "Čísla si zapište.", - "einen u maskulina ve 4. pádu.", - "Partizip na konec.", - NULL, - }, - }, -}; - -static const char *de_y2_l6_read = "Letztes Wochenende bin ich mit Paul in die Stadt gefahren. Zuerst haben wir einen Pullover gesucht. Er war zu teuer. Dann sind wir ins Café gegangen. Ich habe einen Kuchen gegessen und Paul hat einen Tee getrunken. Danach sind wir nach Hause gefahren, weil Paul lernen musste."; - -static const ChoiceQ de_y2_l6_readq[] = { - {"Wohin sind sie zuerst gefahren?", {"Nach Hause", "In die Stadt", "Ins Krankenhaus", "Nach Wien"}, 4, 1}, - {"Warum haben sie den Pullover nicht genommen?", {"Er war zu teuer", "Er war blau", "Paul war krank", "Das Café war zu"}, 4, 0}, - {"Warum sind sie nach Hause gefahren?", {"Weil der Tee kalt war", "Weil Paul lernen musste", "Weil es geregnet hat", "Weil der Zug weg war"}, 4, 1}, -}; -static const char *de_y2_l6_readq_hints[] = { - "in die Stadt.", - "zu teuer.", - "weil Paul lernen musste.", -}; - -static const char *de_y2_l6_listen = "Entschuldigung, wo ist die Apotheke? Gehen Sie geradeaus und dann links. Sie ist neben der Post. Ist es weit? Nein, nur fünf Minuten. Danke! Kann ich dort auch Tee kaufen? Nein, Tee gibt es im Supermarkt gegenüber."; - -static const ChoiceQ de_y2_l6_listenq[] = { - {"Wo ist die Apotheke?", {"Im Bahnhof", "Neben der Post", "Im Café", "Weit vom Zentrum"}, 4, 1}, - {"Wie weit ist es?", {"Fünf Minuten", "Eine Stunde", "Zu weit", "Neben dem Tee"}, 4, 0}, - {"Wo gibt es Tee?", {"In der Apotheke", "Im Supermarkt gegenüber", "Im Zug", "Nirgends"}, 4, 1}, -}; -static const char *de_y2_l6_listenq_hints[] = { - "neben der Post.", - "fünf Minuten.", - "im Supermarkt gegenüber.", -}; - -static const char *de_y2_l6_write[] = { - "Schreib mindestens 30 Wörter. Was hast du gestern gemacht? Benutze habe und bin.", - "Gestern bin ich in die Schule gegangen und ich habe einen Test geschrieben. Danach habe ich mit Eva gesprochen. Am Abend bin ich nach Hause gekommen und ich habe Musik gehört. Ich bin um elf ins Bett gegangen.", - "habe|bin", - "30", -}; - -static const ChoiceQ de_y2_l6_quiz[] = { - {"Ich ___ schwimmen.", {"kann", "kannst", "bin kann", "können"}, 4, 0}, - {"Wir sind nach Prag ___.", {"gefahren", "gefahrt", "fahren", "gegeht"}, 4, 0}, - {"Es gibt ___ Balkon.", {"ein", "einen", "einem", "eine"}, 4, 1}, - {"Wohin ___ du?", {"gehst", "kommst aus", "bist wo", "hast wohin"}, 4, 0}, -}; -static const char *de_y2_l6_quiz_hints[] = { - "ich kann.", - "gefahren.", - "einen Balkon.", - "Wohin gehst du?", -}; - -static const NetSlide de_y3_l1_slides[] = { - { - "1 / 2 • Körper", "Co mě bolí", "Tip: Mir tut der Kopf weh. Ich habe Fieber.", - { - "der Kopf, der Hals, der Bauch, der Rücken.", - "Ich fühle mich nicht gut.", - "Du sollst viel trinken. Sie müssen im Bett bleiben.", - "Rozkaz: Trink Wasser! Bleiben Sie zu Hause!", - NULL, - }, - }, - { - "2 / 2 • Rada", "sollen", "Tip: sollen je rada. müssen je nutné.", - { - "Du sollst heute nicht trainieren.", - "Sie müssen die Tabletten zweimal am Tag nehmen.", - "Gute Besserung!", - "die Apotheke, das Rezept, die Tablette.", - NULL, - }, - }, -}; - -static const char *de_y3_l1_read = "Tom hat Halsschmerzen und ein bisschen Fieber. Die Ärztin sagt: Sie sollen viel trinken und heute zu Hause bleiben. Sie müssen nicht im Bett liegen, aber Sie sollen nicht Fußball spielen. Hier ist ein Rezept. Die Tabletten nehmen Sie zweimal am Tag. Wenn es am Freitag nicht besser ist, kommen Sie wieder."; - -static const ChoiceQ de_y3_l1_readq[] = { - {"Was hat Tom?", {"Nur Kopfschmerzen", "Halsschmerzen und Fieber", "Ein gebrochenes Bein", "Keine Symptome"}, 4, 1}, - {"Was soll er heute nicht machen?", {"Trinken", "Fußball spielen", "Zum Arzt gehen", "Schlafen"}, 4, 1}, - {"Wie oft nimmt er die Tabletten?", {"Einmal", "Zweimal am Tag", "Nur am Freitag", "Gar nicht"}, 4, 1}, - {"Wann kommt er wieder?", {"Wenn es am Freitag nicht besser ist", "Jeden Morgen", "Nie", "Nur mit dem Rezept"}, 4, 0}, -}; -static const char *de_y3_l1_readq_hints[] = { - "Halsschmerzen und Fieber.", - "nicht Fußball spielen.", - "zweimal am Tag.", - "am Freitag.", -}; - -static const ChoiceQ de_y3_l1_quiz[] = { - {"Mir tut der Kopf ___.", {"weh", "gut", "auf", "zum"}, 4, 0}, - {"Du ___ viel trinken. Das ist ein Rat.", {"sollst", "bist", "heißt", "wohinst"}, 4, 0}, - {"Gute Besserung znamená…", {"dobrou chuť", "brzké uzdravení", "na shledanou navždy", "účet prosím"}, 4, 1}, - {"Rozkaz pro du od trinken", {"Trinkst!", "Trink!", "Trinken du!", "Du trink bitte nicht Form"}, 4, 1}, -}; -static const char *de_y3_l1_quiz_hints[] = { - "weh tun.", - "sollen.", - "uzdravení.", - "Trink!", -}; - -static const NetSlide de_y3_l2_slides[] = { - { - "1 / 2 • Vyprávění", "Jedna věc po druhé", "Tip: dann, danach, später, am Ende.", - { - "Zuerst sind wir zum Bahnhof gegangen.", - "Der Zug hatte Verspätung, ale v A2 stačí: Der Zug war zu spät.", - "Wir haben Tickets gekauft.", - "angekommen, eingestiegen, ausgestiegen.", - NULL, - }, - }, - { - "2 / 2 • Vlak", "Slovník", "Tip: der Bahnsteig, die Fahrkarte, umsteigen.", - { - "eine einfache Fahrt, hin und zurück.", - "der Sitzplatz, das Abteil.", - "Entschuldigung, ist dieser Platz frei?", - "in Wien umsteigen.", - NULL, - }, - }, -}; - -static const char *de_y3_l2_listen = "Letzten Samstag sind wir nach Wien gefahren. Zuerst haben wir am Automaten zwei Fahrkarten gekauft, hin und zurück. Der Zug war zwanzig Minuten zu spät. Im Zug habe ich ein Buch gelesen und meine Schwester hat geschlafen. In Wien sind wir am Hauptbahnhof ausgestiegen. Danach haben wir die Innenstadt gesehen. Am Abend sind wir wieder nach Hause gefahren."; - -static const ChoiceQ de_y3_l2_listenq[] = { - {"Wohin sind sie gefahren?", {"Nach Berlin", "Nach Wien", "Nach Prag", "Ans Meer"}, 4, 1}, - {"Wie viel Verspätung hatte der Zug?", {"Keine", "Zehn Minuten", "Zwanzig Minuten", "Zwei Stunden"}, 4, 2}, - {"Was hat die Schwester gemacht?", {"Sie hat gelesen", "Sie hat geschlafen", "Sie hat gekocht", "Sie ist zu Hause geblieben"}, 4, 1}, - {"Wo sind sie ausgestiegen?", {"Am Hauptbahnhof", "Am Flughafen", "In der Schule", "Im Café"}, 4, 0}, -}; -static const char *de_y3_l2_listenq_hints[] = { - "nach Wien.", - "zwanzig Minuten.", - "hat geschlafen.", - "am Hauptbahnhof.", -}; - -static const TypedQ de_y3_l2_gaps[] = { - {"Wir haben zwei Fahrkarten ___.", "gekauft", "kaufen → gekauft."}, - {"Der Zug war zwanzig Minuten zu ___.", "spät", "zu spät."}, - {"Wir sind in Wien ___.", "ausgestiegen", "aussteigen."}, - {"Am Abend sind wir nach Hause ___.", "gefahren", "fahren → gefahren."}, -}; - -static const NetSlide de_y3_l3_slides[] = { - { - "1 / 2 • Sloveso na konci", "weil", "Tip: po weil, dass a wenn jde sloveso na konec.", - { - "Ich bleibe zu Hause, weil ich krank bin.", - "Sie sagt, dass sie morgen kommt.", - "Wenn es regnet, bleiben wir hier. V wenn-větě je sloveso na konci, v hlavní na druhém místě.", - "Čárka mezi větami.", - NULL, - }, - }, - { - "2 / 2 • denn a weil", "Dvě možnosti", "Tip: denn nemění pořádek. weil ano.", - { - "Ich lerne, denn ich habe einen Test. Sloveso habe je druhé.", - "Ich lerne, weil ich einen Test habe.", - "dass není das. das je člen nebo vztažné.", - "ob = jestli v otázce: Ich weiß nicht, ob er kommt.", - NULL, - }, - }, -}; - -static const TypedQ de_y3_l3_gaps[] = { - {"Ich bleibe hier, weil ich krank ___.", "bin", "Sloveso na konci."}, - {"Sie sagt, dass sie morgen ___.", "kommt", "dass + sloveso na konci."}, - {"___ es regnet, bleiben wir zu Hause.", "Wenn", "když."}, - {"Ich lerne, ___ ich einen Test habe.", "weil", "důvod se slovesem na konci."}, - {"Ich weiß nicht, ___ er kommt.", "ob", "jestli."}, -}; - -static const ChoiceQ de_y3_l3_quiz[] = { - {"Welche Variante ist richtig?", {"weil ich bin krank", "weil ich krank bin", "weil bin ich krank", "weil ich krank ist"}, 4, 1}, - {"denn…", {"schickt das Verb ans Ende", "ändert die Wortstellung nicht", "bedeutet wenn", "ist ein Artikel"}, 4, 1}, - {"dass oder das? Sie sagt, ___ sie kommt.", {"das", "dass", "weil", "den"}, 4, 1}, - {"Wenn es regnet, ___ wir zu Hause.", {"bleiben", "bleiben wir", "wir bleiben am Ende nur", "bleibt du"}, 4, 1}, -}; -static const char *de_y3_l3_quiz_hints[] = { - "bin na konci.", - "Po denn zůstává běžný pořádek.", - "spojka dass.", - "V hlavní větě po wenn je sloveso první: bleiben wir.", -}; - -static const NetSlide de_y3_l4_slides[] = { - { - "1 / 2 • Sie", "Vykání", "Tip: Sie, Ihr, Ihnen se píšou velké.", - { - "Wie heißen Sie? Was machen Sie beruflich?", - "Ich möchte mich bewerben.", - "der Lebenslauf, die Stelle, das Vorstellungsgespräch.", - "Mit freundlichen Grüßen.", - NULL, - }, - }, - { - "2 / 2 • E-mail", "Krátká žádost", "Tip: Sehr geehrte Frau …, na konci jméno.", - { - "Ich schreibe Ihnen, weil ich die Stelle interessant finde.", - "Im Anhang ist mein Lebenslauf.", - "Ich freue mich auf Ihre Antwort.", - "Ne Piš Hi a Tschüss ve formálním mailu.", - NULL, - }, - }, -}; - -static const char *de_y3_l4_write[] = { - "Schreib eine kurze formale E-Mail, mindestens 40 Wörter. Benutze Sie a Grüßen.", - "Sehr geehrte Frau Berger, ich schreibe Ihnen, weil ich die Stelle im Café interessant finde. Ich bin siebzehn und ich habe schon im Sommer in einem Geschäft gearbeitet. Ich kann am Samstag arbeiten. Können Sie mich anrufen? Im Anhang ist mein Lebenslauf. Mit freundlichen Grüßen, Eva Malá.", - "Sie|Grüßen", - "40", -}; - -static const ChoiceQ de_y3_l4_quiz[] = { - {"Vykání od heißen", {"Wie heißt du?", "Wie heißen Sie?", "Wie heißt Sie?", "Wie heißen du?"}, 4, 1}, - {"Formální konec", {"Tschüss, dein Freund", "Mit freundlichen Grüßen", "Hi und Kuss", "Bye weil"}, 4, 1}, - {"der Lebenslauf je…", {"účtenka", "životopis", "nádraží", "recept"}, 4, 1}, - {"Ihr v Ich freue mich auf ___ Antwort.", {"deine", "Ihre", "sein", "mein Sie"}, 4, 1}, -}; -static const char *de_y3_l4_quiz_hints[] = { - "Wie heißen Sie?", - "Mit freundlichen Grüßen.", - "životopis.", - "Ihre s velkým I.", -}; - -static const NetSlide de_y3_l5_slides[] = { - { - "1 / 2 • Stupňování", "-er a am -sten", "Tip: billig → billiger → am billigsten. gern → lieber → am liebsten.", - { - "klein, kleiner, am kleinsten.", - "gut, besser, am besten. viel, mehr, am meisten.", - "als po komparativu: Prag ist größer als Pilsen.", - "so … wie: nicht so teuer wie.", - NULL, - }, - }, - { - "2 / 2 • Prostředí", "Jednoduchá slova", "Tip: der Müll, trennen, sparen, die Natur, das Klima.", - { - "zu Fuß gehen statt mit dem Auto fahren.", - "weniger Plastik, mehr Gemüse.", - "Ich finde die Bahn besser als das Flugzeug.", - "weil es die Umwelt schont.", - NULL, - }, - }, -}; - -static const char *de_y3_l5_read = "Die Bahn ist oft besser für die Umwelt als das Flugzeug, aber nicht immer billiger. Ein Ticket nach Berlin kann teurer sein als ein Flug. Trotzdem fahren viele Jugendliche lieber mit dem Zug, weil sie unterwegs lesen können. Am liebsten fahre ich nachts, weil der Sitz dann so ruhig ist wie zu Hause."; - -static const ChoiceQ de_y3_l5_readq[] = { - {"Was ist oft besser für die Umwelt?", {"Das Flugzeug", "Die Bahn", "Das Auto immer", "Nichts"}, 4, 1}, - {"Ist die Bahn immer billiger?", {"Ja", "Nein", "Nur nachts", "Nur für Jugendliche"}, 4, 1}, - {"Warum fahren viele lieber mit dem Zug?", {"Weil sie unterwegs lesen können", "Weil es immer gratis ist", "Weil es kein Flugzeug gibt", "Weil Berlin klein ist"}, 4, 0}, - {"am liebsten bedeutet…", {"nejradši", "málo", "včera", "naproti"}, 4, 0}, -}; -static const char *de_y3_l5_readq_hints[] = { - "Die Bahn.", - "nicht immer billiger.", - "lesen können.", - "nejradši.", -}; - -static const TypedQ de_y3_l5_gaps[] = { - {"Prag ist ___ (groß) als Pilsen.", "größer", "Komparativ + als."}, - {"Das ist am ___.", "besten", "gut → am besten."}, - {"Ich fahre ___ mit dem Zug als mit dem Flugzeug.", "lieber", "gern → lieber."}, - {"Nicht so teuer ___ ein Flug.", "wie", "so … wie."}, -}; - -static const NetSlide de_y3_l6_slides[] = { - { - "1 / 2 • A2+", "Věta", "Tip: po weil je sloveso na konci. V perfektu je příčestí taky na konci.", - { - "sollen a müssen.", - "weil, dass, wenn, ob.", - "Sie s velkým S.", - "größer als, am liebsten.", - NULL, - }, - }, - { - "2 / 2 • Psaní", "Jeden důvod", "Tip: jedna věta s weil stačí, když je sloveso správně.", - { - "Ich finde …, weil …", - "Neweil ich bin.", - "Konkrétní příklad.", - "Na konec Mit freundlichen Grüßen jen ve formálním textu.", - NULL, - }, - }, -}; - -static const char *de_y3_l6_read = "Mia bleibt heute zu Hause, weil sie Fieber hat. Die Ärztin hat gesagt, dass sie viel trinken soll. Wenn es morgen besser ist, geht Mia wieder in die Schule. Sie findet die Bahn besser als das Auto, aber heute kann sie nicht fahren."; - -static const ChoiceQ de_y3_l6_readq[] = { - {"Warum bleibt Mia zu Hause?", {"Weil sie Fieber hat", "Weil die Bahn teuer ist", "Weil morgen Samstag ist", "Weil sie Fußball spielt"}, 4, 0}, - {"Was soll sie machen?", {"Viel trinken", "Fußball spielen", "Nach Wien fahren", "Nichts sagen"}, 4, 0}, - {"Was findet sie besser als das Auto?", {"Das Flugzeug", "Die Bahn", "Das Fieber", "Die Schule"}, 4, 1}, -}; -static const char *de_y3_l6_readq_hints[] = { - "weil sie Fieber hat.", - "viel trinken.", - "die Bahn.", -}; - -static const char *de_y3_l6_listen = "Ich habe mich für die Stelle beworben, weil ich gern mit Menschen arbeite. Die Chefin hat gesagt, dass ich am Samstag kommen soll. Wenn das Gespräch gut ist, kann ich im Juli anfangen. Ich bin nervös, aber ich freue mich."; - -static const ChoiceQ de_y3_l6_listenq[] = { - {"Warum hat sie sich beworben?", {"Weil sie gern mit Menschen arbeitet", "Weil sie Fieber hat", "Weil der Zug zu spät war", "Weil sie nicht arbeiten will"}, 4, 0}, - {"Wann soll sie kommen?", {"Am Montag", "Am Samstag", "Im Zug", "Nie"}, 4, 1}, - {"Wann kann sie anfangen?", {"Im Juli, wenn das Gespräch gut ist", "Gestern", "Nur im Winter", "Sie weiß es nicht"}, 4, 0}, -}; -static const char *de_y3_l6_listenq_hints[] = { - "gern mit Menschen.", - "am Samstag.", - "im Juli.", -}; - -static const char *de_y3_l6_write[] = { - "Schreib mindestens 35 Wörter. Was findest du besser, Bahn oder Auto, und warum? Benutze weil.", - "Ich finde die Bahn besser als das Auto, weil ich unterwegs lesen kann und nicht selbst fahren muss. Das Auto ist manchmal schneller, aber die Bahn ist ruhiger. Am liebsten fahre ich mit dem Zug, weil ich dabei Musik hören kann.", - "weil|besser", - "35", -}; - -static const ChoiceQ de_y3_l6_quiz[] = { - {"weil ich krank ___", {"bin", "bin ich", "ist", "habe bin"}, 4, 0}, - {"Mir tut der Hals ___.", {"weh", "weil", "auf", "gern"}, 4, 0}, - {"größer ___ Berlin? Nein, Prag ist kleiner.", {"wie", "als", "dass", "ob"}, 4, 1}, - {"Wie heißen ___?", {"Sie", "du Sie", "dein", "dir"}, 4, 0}, -}; -static const char *de_y3_l6_quiz_hints[] = { - "bin na konci.", - "weh.", - "Komparativ + als. Otázka je schválně o vztahu als.", - "Sie.", -}; - -static const NetSlide de_y4_l1_slides[] = { - { - "1 / 2 • Medien", "Co sleduju", "Tip: die Nachrichten, die Serie, das Handy, der Account.", - { - "Ich schaue selten fern, aber ich bin oft online.", - "eine Nachricht teilen, einen Kommentar schreiben.", - "Das stimmt nicht. Das ist ein Gerücht.", - "die Quelle, seriös, falsch.", - NULL, - }, - }, - { - "2 / 2 • Poslech", "Dvě otázky předem", "Tip: čísla a zápor si zapište hned.", - { - "seit zwei Jahren, jeden Abend, fast nie.", - "nicht mehr = už ne.", - "zu viel Zeit.", - "Ich habe gemerkt, dass …", - NULL, - }, - }, -}; - -static const char *de_y4_l1_listen = "Früher habe ich jeden Abend ferngesehen. Seit zwei Jahren mache ich das nicht mehr. Ich höre einen Podcast auf dem Weg zur Schule und ich lese die Nachrichten auf dem Handy. Manche Videos sind lustig, aber nicht jede Quelle ist seriös. Letzte Woche habe ich ein Gerücht geteilt und später gemerkt, dass es falsch war. Seitdem prüfe ich den Text, bevor ich ihn schicke."; - -static const ChoiceQ de_y4_l1_listenq[] = { - {"Seit wann sieht er nicht mehr jeden Abend fern?", {"Seit zwei Wochen", "Seit zwei Jahren", "Seit gestern", "Er sieht immer noch fern"}, 4, 1}, - {"Was hört er auf dem Weg zur Schule?", {"Einen Podcast", "Nur Musik aus dem Fernseher", "Nichts", "Die Lehrerin"}, 4, 0}, - {"Was ist letzte Woche passiert?", {"Er hat ein Gerücht geteilt", "Er hat den Fernseher gekauft", "Er hat die Prüfung bestanden", "Er ist nach Wien gefahren"}, 4, 0}, - {"Was macht er seitdem?", {"Er teilt alles sofort", "Er prüft den Text, bevor er ihn schickt", "Er sieht wieder jeden Abend fern", "Er schreibt keine Nachrichten"}, 4, 1}, - {"seriös bedeutet…", {"vtipný", "důvěryhodný", "zdarma", "hlasitý"}, 4, 1}, -}; -static const char *de_y4_l1_listenq_hints[] = { - "Seit zwei Jahren.", - "einen Podcast.", - "ein Gerücht geteilt.", - "prüft den Text.", - "seriózní, důvěryhodný.", -}; - -static const NetSlide de_y4_l2_slides[] = { - { - "1 / 2 • Kostra", "Čtyři části", "Tip: oslovení, důvod, prosba, rozloučení.", - { - "Sehr geehrte Damen und Herren,", - "Ich schreibe Ihnen, weil …", - "Ich bitte Sie um eine Antwort.", - "Mit freundlichen Grüßen und jméno.", - NULL, - }, - }, - { - "2 / 2 • Tón", "Klidně a konkrétně", "Tip: datum, spoj, co chcete. Bez nadávek.", - { - "Der Zug am 3. Mai hatte Verspätung.", - "Deshalb habe ich den Termin verpasst.", - "Ich bitte um eine Erklärung oder um Geld zurück.", - "Im Anhang finden Sie das Ticket.", - NULL, - }, - }, -}; - -static const char *de_y4_l2_write[] = { - "Schreib eine formelle E-Mail, mindestens 45 Wörter. Der Zug hatte Verspätung. Benutze Ihnen a Grüßen.", - "Sehr geehrte Damen und Herren, ich schreibe Ihnen, weil der Zug am 3. Mai nach Berlin zwanzig Minuten zu spät war. Deshalb habe ich meinen Termin verpasst. Ich bitte Sie um eine Erklärung oder um das Geld zurück. Im Anhang ist mein Ticket. Mit freundlichen Grüßen, Tereza Malá.", - "Ihnen|Grüßen", - "45", -}; - -static const ChoiceQ de_y4_l2_quiz[] = { - {"Neznámé jméno", {"Hi Leute", "Sehr geehrte Damen und Herren", "Tschüss Chef", "Liebe du"}, 4, 1}, - {"Ich schreibe ___, weil …", {"dir du", "Ihnen", "dein", "euch Sie"}, 4, 1}, - {"im Anhang znamená…", {"v příloze", "na nástupišti", "včera", "zdarma"}, 4, 0}, - {"Který konec sedí?", {"Bye!", "Mit freundlichen Grüßen", "Dein Kumpel", "Kuss"}, 4, 1}, -}; -static const char *de_y4_l2_quiz_hints[] = { - "Damen und Herren.", - "Ihnen.", - "v příloze.", - "Mit freundlichen Grüßen.", -}; - -static const NetSlide de_y4_l3_slides[] = { - { - "1 / 2 • Čtení", "Nejdřív otázka", "Tip: nehledejte stejné slovo, hledejte stejný význam.", - { - "Hlavní myšlenka bývá na začátku nebo na konci.", - "obwohl = ačkoli. Sloveso po obwohl je na konci.", - "trotzdem = přesto. Po trotzdem je běžný pořádek.", - "die Verspätung, das Abteil, der Schaffner.", - NULL, - }, - }, - { - "2 / 2 • Slovo z kontextu", "Neznámé slovo", "Tip: věta před ním a za ním ho ohraničí.", - { - "umsteigen = přestupovat.", - "pünktlich = včas.", - "sich lohnen = vyplatit se.", - "lieber = radši.", - NULL, - }, - }, -}; - -static const char *de_y4_l3_read = "Der Nachtzug von Prag nach Berlin ist für viele Jugendliche interessanter als ein billiger Flug, obwohl das Ticket oft mehr kostet. Man kann lesen, schlafen und muss nicht um fünf Uhr am Flughafen sein. Kritiker sagen, dass die Verspätung ein Problem ist und dass die Abteile klein sind. Trotzdem lohnt sich die Fahrt für Lea. Sie ist schon dreimal gefahren. Sie sagt, dass sie nur fliegt, wenn sie den Abendzug verpasst. Für sie ist die Reise ein Teil des Urlaubs und nicht nur eine Strecke."; - -static const ChoiceQ de_y4_l3_readq[] = { - {"Was ist die Hauptidee?", {"Flüge sind verboten", "Manche Leute nehmen den Nachtzug, obwohl er mehr kosten kann", "Berlin hat keinen Bahnhof", "Lea fliegt jeden Tag"}, 4, 1}, - {"Was kann man im Zug machen?", {"Nur stehen", "Lesen und schlafen", "Das Flugzeug steuern", "Nichts"}, 4, 1}, - {"Was sagen die Kritiker?", {"Der Zug ist immer gratis", "Verspätung und kleine Abteile sind ein Problem", "Es gibt keine Tickets", "Lea ist der Schaffner"}, 4, 1}, - {"Wann fliegt Lea?", {"Immer", "Nur wenn sie den Abendzug verpasst", "Nie, das steht nicht so", "Jeden Morgen um fünf"}, 4, 1}, - {"obwohl bedeutet…", {"protože", "ačkoli", "potom", "bez"}, 4, 1}, -}; -static const char *de_y4_l3_readq_hints[] = { - "obwohl das Ticket oft mehr kostet, přesto vlak volí.", - "lesen, schlafen.", - "Verspätung, Abteile klein.", - "wenn sie den Abendzug verpasst.", - "ačkoli.", -}; - -static const NetSlide de_y4_l4_slides[] = { - { - "1 / 2 • wäre a hätte", "Neskutečná podmínka", "Tip: Wenn ich Zeit hätte, würde ich mehr lesen.", - { - "haben → hätte, sein → wäre.", - "würde + infinitiv pro ostatní slovesa.", - "Wenn ich reich wäre, würde ich reisen.", - "Sloveso po wenn je na konci: Wenn ich Zeit hätte.", - NULL, - }, - }, - { - "2 / 2 • Zdvořilost", "würde a könnte", "Tip: Könnten Sie mir helfen? je měkčí než Können Sie.", - { - "Ich hätte gern einen Kaffee.", - "Würden Sie das bitte wiederholen?", - "An deiner Stelle würde ich warten.", - "Není to minulost, i když tvar vypadá jako minulý.", - NULL, - }, - }, -}; - -static const TypedQ de_y4_l4_gaps[] = { - {"Wenn ich Zeit ___, würde ich mehr lesen.", "hätte", "haben → hätte."}, - {"Wenn ich reich ___, würde ich reisen.", "wäre", "sein → wäre."}, - {"Ich ___ gern einen Kaffee.", "hätte", "Ich hätte gern."}, - {"An deiner Stelle ___ ich warten.", "würde", "würde + infinitiv."}, - {"___ Sie das bitte wiederholen?", "Würden|Könnten", "Zdvořilá prosba."}, -}; - -static const ChoiceQ de_y4_l4_quiz[] = { - {"Wenn ich du wäre, ___ ich das nicht machen.", {"werde", "würde", "bin", "hast"}, 4, 1}, - {"hätte je od slovesa…", {"sein", "haben", "werden", "gehen"}, 4, 1}, - {"Könnten Sie… je…", {"rozkaz", "zdvořilejší otázka", "minulý čas perfekta", "člen"}, 4, 1}, - {"Welche Satz ist richtig?", {"Wenn ich hätte Zeit", "Wenn ich Zeit hätte", "Wenn hätte ich Zeit", "Wenn ich Zeit habe würde nur so"}, 4, 1}, -}; -static const char *de_y4_l4_quiz_hints[] = { - "würde.", - "haben.", - "zdvořilost.", - "hätte na konci.", -}; - -static const NetSlide de_y4_l5_slides[] = { - { - "1 / 2 • Okruhy", "Ne izolovaná slovíčka", "Tip: ústní zkouška z němčiny bere osobu, rodinu, školu, volný čas, město, zdraví, práci a média.", - { - "eine Meinung haben, ein Beispiel nennen.", - "zu Fuß gehen, mit der Bahn fahren, im Stau stehen.", - "sich gesund ernähren, Sport treiben.", - "einen Nebenjob haben, Geld verdienen.", - NULL, - }, - }, - { - "2 / 2 • Věta navíc", "Obecné a osobní", "Tip: Viele Jugendliche … Ich persönlich …", - { - "Einerseits … andererseits …", - "Das finde ich gut, weil …", - "Zum Beispiel …", - "Zusammenfassend …", - NULL, - }, - }, -}; - -static const TypedQ de_y4_l5_gaps[] = { - {"Ich treibe dreimal pro Woche ___.", "Sport", "Sport treiben."}, - {"Viele Leute stehen morgens im ___.", "Stau", "im Stau stehen."}, - {"Sie hat einen ___ im Café.", "Nebenjob|Job", "brigáda, práce."}, - {"Ich persönlich ___ die Bahn besser.", "finde", "finden."}, - {"___ Beispiel lese ich im Zug.", "Zum", "Zum Beispiel."}, -}; - -static const ChoiceQ de_y4_l5_quiz[] = { - {"einerseits … andererseits", {"nejdřív a nakonec bez kontrastu", "na jedné straně … na druhé straně", "protože … když", "včera … zítra"}, 4, 1}, - {"sich gesund ernähren", {"zdravě jíst", "být v zácpě", "psát e-mail", "zmeškat vlak"}, 4, 0}, - {"Was passt zu einer mündlichen Prüfung?", {"Nur einzelne Wörter", "Eine allgemeine Aussage und ein persönliches Beispiel", "Ein Formular ohne Verben", "Nur Ja"}, 4, 1}, - {"im Stau stehen", {"stát ve frontě v bance jen", "být v dopravní zácpě", "stát na balkóně", "stát v čele třídy"}, 4, 1}, -}; -static const char *de_y4_l5_quiz_hints[] = { - "kontrast.", - "stravovat se.", - "obecné plus příklad.", - "zácpa.", -}; - -static const NetSlide de_y4_l6_slides[] = { - { - "1 / 2 • Celek", "Tři dovednosti", "Tip: nejdřív si přečtěte otázky. U weil a wenn kontrolujte konec věty.", - { - "Čtení: význam, ne stejné slovo.", - "Poslech: čísla a nein.", - "Konjunktiv: hätte, wäre, würde.", - "Psaní: sloveso na druhém místě v hlavní větě.", - NULL, - }, - }, - { - "2 / 2 • Text", "Kamarádovi", "Tip: tady není formální mail. Hallo stačí, ale věty ať jsou celé.", - { - "Napište proč píšete.", - "Jedna věta s weil.", - "Jedna věta s wenn nebo würde.", - "Otázka na konci.", - NULL, - }, - }, -}; - -static const char *de_y4_l6_read = "In unserer Bibliothek kann man jetzt nicht nur Bücher, sondern auch Werkzeug ausleihen. Die Idee kommt von einer Bibliothekarin, die sagte, dass viele Leute Dinge kaufen, die sie nur einmal brauchen. Im März haben Jugendliche zwanzig Wasserkocher repariert. Wenn das Projekt weitergeht, machen andere Bibliotheken mit. Man muss die Sachen sauber zurückgeben."; - -static const ChoiceQ de_y4_l6_readq[] = { - {"Was kann man außer Büchern ausleihen?", {"Autos", "Werkzeug", "Wohnungen", "Flugtickets"}, 4, 1}, - {"Warum entstand die Idee?", {"Weil Leute Dinge nur einmal brauchen und trotzdem kaufen", "Weil es keine Bücher gibt", "Weil der Zug zu spät war", "Weil niemand liest"}, 4, 0}, - {"Wie viele Wasserkocher haben sie im März repariert?", {"Zwei", "Zwölf", "Zwanzig", "Zweihundert"}, 4, 2}, - {"Was muss man machen?", {"Die Sachen sauber zurückgeben", "Einen neuen Kocher kaufen", "Nach Berlin fahren", "Nichts"}, 4, 0}, -}; -static const char *de_y4_l6_readq_hints[] = { - "Werkzeug.", - "nur einmal brauchen.", - "zwanzig.", - "sauber zurückgeben.", -}; - -static const char *de_y4_l6_listen = "Der Nachtzug nach Berlin hat vierzig Minuten Verspätung, weil ein Baum auf den Gleisen liegt. Fahrgäste mit einem Platz können in Wagen vier warten. Wenn Sie noch nicht eingecheckt haben, machen Sie das bitte am Handy. Wir wären froh, wenn der Gang frei bliebe. Um zehn wissen wir mehr."; - -static const ChoiceQ de_y4_l6_listenq[] = { - {"Wie lang ist die Verspätung?", {"Vier Minuten", "Vierzig Minuten", "Vier Stunden", "Der Zug ist pünktlich"}, 4, 1}, - {"Warum?", {"Schnee", "Ein Baum auf den Gleisen", "Kein Personal", "Ein Fest"}, 4, 1}, - {"Wo können Fahrgäste mit Platz warten?", {"In Wagen vier", "Am Flughafen", "Zu Hause", "Im Gang"}, 4, 0}, - {"Was sollen Leute ohne Check-in machen?", {"Den Baum wegtragen", "Am Handy einchecken", "Nach Prag laufen", "Nichts sagen"}, 4, 1}, -}; -static const char *de_y4_l6_listenq_hints[] = { - "vierzig Minuten.", - "ein Baum.", - "Wagen vier.", - "am Handy.", -}; - -static const char *de_y4_l6_write[] = { - "Schreib mindestens 40 Wörter an einen Freund. Lad ihn ein, Werkzeug in der Bibliothek auszuleihen. Benutze weil.", - "Hallo Adam, in der Bibliothek kann man jetzt Werkzeug ausleihen, und ich glaube, das ist etwas für dich, weil du oft nur eine Bohrmaschine für einen Nachmittag brauchst. Wenn du am Samstag Zeit hast, komme ich mit. Wir müssen die Sachen danach sauber zurückgeben. Hast du Lust?", - "weil|wenn", - "40", -}; - -static const ChoiceQ de_y4_l6_quiz[] = { - {"Wenn ich Zeit ___, würde ich kommen.", {"hätte", "habe würde", "bin", "hatte nur Perfekt"}, 4, 0}, - {"Sie sagt, dass der Zug Verspätung ___.", {"hat", "hat er", "ist hat", "haben"}, 4, 0}, - {"Man muss die Sachen sauber ___.", {"zurückgeben", "zurückgibt", "geben zurück sofort als einziges", "zu zurück"}, 4, 0}, - {"Ich wäre froh, wenn du ___.", {"kommst sofort nur so", "kommen würdest", "bist kommen", "kommst du"}, 4, 1}, -}; -static const char *de_y4_l6_quiz_hints[] = { - "hätte.", - "hat na konci.", - "zurückgeben na konci po muss.", - "würdest na konci je v pořádku. Alternativa wenn du kämst je těžší.", -}; - -static const EnLesson de_lessons[DE_YEARS][DE_N] = { - { - { - .slides = de_y1_l1_slides, - .n_slides = (int)(sizeof de_y1_l1_slides / sizeof de_y1_l1_slides[0]), - .gaps = de_y1_l1_gaps, - .n_gaps = (int)(sizeof de_y1_l1_gaps / sizeof de_y1_l1_gaps[0]), - .quiz = de_y1_l1_quiz, - .quiz_hints = de_y1_l1_quiz_hints, - .n_quiz = (int)(sizeof de_y1_l1_quiz / sizeof de_y1_l1_quiz[0]), - }, - { - .slides = de_y1_l2_slides, - .n_slides = (int)(sizeof de_y1_l2_slides / sizeof de_y1_l2_slides[0]), - .reading = "Ich heiße Lukas und ich bin fünfzehn. Ich wohne mit meinen Eltern in Pilsen. Ich habe eine Schwester. Sie heißt Eva und sie ist zwölf. Mein Vater ist Lehrer und meine Mutter arbeitet im Krankenhaus. Wir haben auch einen Hund. Er heißt Max. Am Wochenende besuchen wir meine Oma. Sie wohnt nicht bei uns, aber sie wohnt in derselben Stadt.", - .readq = de_y1_l2_readq, - .read_hints = de_y1_l2_readq_hints, - .n_read = (int)(sizeof de_y1_l2_readq / sizeof de_y1_l2_readq[0]), - .gaps = de_y1_l2_gaps, - .n_gaps = (int)(sizeof de_y1_l2_gaps / sizeof de_y1_l2_gaps[0]), - }, - { - .slides = de_y1_l3_slides, - .n_slides = (int)(sizeof de_y1_l3_slides / sizeof de_y1_l3_slides[0]), - .listening = "Hallo, ich bin Mia. Am Montag haben wir Deutsch, Mathe und Biologie. Deutsch mag ich gern, weil die Lehrerin nett ist. Mathe mag ich nicht. In der Pause esse ich ein Brötchen und spreche mit Eva. Nach der Schule mache ich Hausaufgaben oder ich spiele Volleyball. Am Abend lese ich oder ich höre Musik. Um zehn gehe ich ins Bett.", - .listenq = de_y1_l3_listenq, - .listen_hints = de_y1_l3_listenq_hints, - .n_listen = (int)(sizeof de_y1_l3_listenq / sizeof de_y1_l3_listenq[0]), - .gaps = de_y1_l3_gaps, - .n_gaps = (int)(sizeof de_y1_l3_gaps / sizeof de_y1_l3_gaps[0]), - }, - { - .slides = de_y1_l4_slides, - .n_slides = (int)(sizeof de_y1_l4_slides / sizeof de_y1_l4_slides[0]), - .write_prompt = "Schreib mindestens 25 Wörter. Bestell im Café etwas zu essen und zu trinken. Benutze möchte und bitte.", - .write_model = "Guten Tag, ich möchte eine Suppe und ein Brot, bitte. Für mich bitte auch einen Tee. Meine Schwester möchte einen Apfelsaft. Die Suppe schmeckt gut. Die Rechnung, bitte. Danke, das ist alles.", - .write_keys = "möchte|bitte", - .write_min = 25, - .quiz = de_y1_l4_quiz, - .quiz_hints = de_y1_l4_quiz_hints, - .n_quiz = (int)(sizeof de_y1_l4_quiz / sizeof de_y1_l4_quiz[0]), - }, - { - .slides = de_y1_l5_slides, - .n_slides = (int)(sizeof de_y1_l5_slides / sizeof de_y1_l5_slides[0]), - .reading = "An einem Schultag stehe ich um halb sieben auf. Zuerst dusche ich, dann frühstücke ich Brot und Tee. Um sieben fahre ich mit der Straßenbahn zur Schule. Der Unterricht beginnt um acht. Nach der Schule mache ich Hausaufgaben. Am Abend sehe ich manchmal fern oder ich rufe eine Freundin an. Um zehn gehe ich ins Bett.", - .readq = de_y1_l5_readq, - .read_hints = de_y1_l5_readq_hints, - .n_read = (int)(sizeof de_y1_l5_readq / sizeof de_y1_l5_readq[0]), - .gaps = de_y1_l5_gaps, - .n_gaps = (int)(sizeof de_y1_l5_gaps / sizeof de_y1_l5_gaps[0]), - }, - { - .slides = de_y1_l6_slides, - .n_slides = (int)(sizeof de_y1_l6_slides / sizeof de_y1_l6_slides[0]), - .reading = "Nina ist sechzehn und wohnt in Olomouc. Sie hat einen Bruder. Er heißt Tom und er ist zehn. Am Morgen isst Nina Brot. In der Schule lernt sie gern Deutsch, aber sie mag Mathe nicht. Nach der Schule ruft sie ihre Freundin an.", - .readq = de_y1_l6_readq, - .read_hints = de_y1_l6_readq_hints, - .n_read = (int)(sizeof de_y1_l6_readq / sizeof de_y1_l6_readq[0]), - .listening = "Guten Tag, ich möchte einen Salat und ein Wasser, bitte. Haben Sie auch Brot? Ja, natürlich. Dann bitte noch ein Brot. Möchten Sie Kaffee? Nein, danke, nur Wasser. Die Rechnung mache ich später.", - .listenq = de_y1_l6_listenq, - .listen_hints = de_y1_l6_listenq_hints, - .n_listen = (int)(sizeof de_y1_l6_listenq / sizeof de_y1_l6_listenq[0]), - .write_prompt = "Schreib mindestens 30 Wörter über deine Familie. Benutze bin und habe.", - .write_model = "Ich bin sechzehn und ich wohne in Prag. Ich habe eine Schwester und meine Eltern. Mein Vater ist nett und meine Mutter arbeitet viel. Wir haben keine Katze, aber ich habe einen Freund in der Schule. Am Sonntag besuchen wir oft meine Oma.", - .write_keys = "bin|habe", - .write_min = 30, - .quiz = de_y1_l6_quiz, - .quiz_hints = de_y1_l6_quiz_hints, - .n_quiz = (int)(sizeof de_y1_l6_quiz / sizeof de_y1_l6_quiz[0]), - } - }, - { - { - .slides = de_y2_l1_slides, - .n_slides = (int)(sizeof de_y2_l1_slides / sizeof de_y2_l1_slides[0]), - .gaps = de_y2_l1_gaps, - .n_gaps = (int)(sizeof de_y2_l1_gaps / sizeof de_y2_l1_gaps[0]), - .quiz = de_y2_l1_quiz, - .quiz_hints = de_y2_l1_quiz_hints, - .n_quiz = (int)(sizeof de_y2_l1_quiz / sizeof de_y2_l1_quiz[0]), - }, - { - .slides = de_y2_l2_slides, - .n_slides = (int)(sizeof de_y2_l2_slides / sizeof de_y2_l2_slides[0]), - .reading = "Anna sucht eine Jacke. Die rote Jacke kostet neunzig Euro. Das ist ihr zu teuer. Eine blaue Jacke kostet fünfundvierzig Euro und sie ist bequem. Anna nimmt die blaue Jacke. Dazu kauft sie noch ein Hemd für ihren Bruder. Das Hemd kostet zwanzig Euro. Sie zahlt mit Karte.", - .readq = de_y2_l2_readq, - .read_hints = de_y2_l2_readq_hints, - .n_read = (int)(sizeof de_y2_l2_readq / sizeof de_y2_l2_readq[0]), - .quiz = de_y2_l2_quiz, - .quiz_hints = de_y2_l2_quiz_hints, - .n_quiz = (int)(sizeof de_y2_l2_quiz / sizeof de_y2_l2_quiz[0]), - }, - { - .slides = de_y2_l3_slides, - .n_slides = (int)(sizeof de_y2_l3_slides / sizeof de_y2_l3_slides[0]), - .listening = "Am Samstag muss ich vormittags lernen, weil wir am Montag einen Test haben. Nachmittags kann ich aber Fußball spielen. Mein Freund Paul will auch kommen. Er kann nicht so gut spielen, aber er ist nett. Abends wollen wir einen Film sehen. Ich darf nicht zu spät nach Hause kommen. Um elf muss ich zu Hause sein.", - .listenq = de_y2_l3_listenq, - .listen_hints = de_y2_l3_listenq_hints, - .n_listen = (int)(sizeof de_y2_l3_listenq / sizeof de_y2_l3_listenq[0]), - .gaps = de_y2_l3_gaps, - .n_gaps = (int)(sizeof de_y2_l3_gaps / sizeof de_y2_l3_gaps[0]), - }, - { - .slides = de_y2_l4_slides, - .n_slides = (int)(sizeof de_y2_l4_slides / sizeof de_y2_l4_slides[0]), - .write_prompt = "Beschreib dein Zimmer in mindestens 35 Wörtern. Benutze es gibt und weil.", - .write_model = "Mein Zimmer ist klein, aber hell. Es gibt ein Bett, einen Schreibtisch und ein Fenster. Das Bett steht an der Wand und der Schreibtisch steht vor dem Fenster. Meine Bücher liegen auf dem Tisch. Ich mag das Zimmer, weil es ruhig ist und ich dort gut lernen kann.", - .write_keys = "weil|gibt", - .write_min = 35, - .quiz = de_y2_l4_quiz, - .quiz_hints = de_y2_l4_quiz_hints, - .n_quiz = (int)(sizeof de_y2_l4_quiz / sizeof de_y2_l4_quiz[0]), - }, - { - .slides = de_y2_l5_slides, - .n_slides = (int)(sizeof de_y2_l5_slides / sizeof de_y2_l5_slides[0]), - .gaps = de_y2_l5_gaps, - .n_gaps = (int)(sizeof de_y2_l5_gaps / sizeof de_y2_l5_gaps[0]), - .quiz = de_y2_l5_quiz, - .quiz_hints = de_y2_l5_quiz_hints, - .n_quiz = (int)(sizeof de_y2_l5_quiz / sizeof de_y2_l5_quiz[0]), - }, - { - .slides = de_y2_l6_slides, - .n_slides = (int)(sizeof de_y2_l6_slides / sizeof de_y2_l6_slides[0]), - .reading = "Letztes Wochenende bin ich mit Paul in die Stadt gefahren. Zuerst haben wir einen Pullover gesucht. Er war zu teuer. Dann sind wir ins Café gegangen. Ich habe einen Kuchen gegessen und Paul hat einen Tee getrunken. Danach sind wir nach Hause gefahren, weil Paul lernen musste.", - .readq = de_y2_l6_readq, - .read_hints = de_y2_l6_readq_hints, - .n_read = (int)(sizeof de_y2_l6_readq / sizeof de_y2_l6_readq[0]), - .listening = "Entschuldigung, wo ist die Apotheke? Gehen Sie geradeaus und dann links. Sie ist neben der Post. Ist es weit? Nein, nur fünf Minuten. Danke! Kann ich dort auch Tee kaufen? Nein, Tee gibt es im Supermarkt gegenüber.", - .listenq = de_y2_l6_listenq, - .listen_hints = de_y2_l6_listenq_hints, - .n_listen = (int)(sizeof de_y2_l6_listenq / sizeof de_y2_l6_listenq[0]), - .write_prompt = "Schreib mindestens 30 Wörter. Was hast du gestern gemacht? Benutze habe und bin.", - .write_model = "Gestern bin ich in die Schule gegangen und ich habe einen Test geschrieben. Danach habe ich mit Eva gesprochen. Am Abend bin ich nach Hause gekommen und ich habe Musik gehört. Ich bin um elf ins Bett gegangen.", - .write_keys = "habe|bin", - .write_min = 30, - .quiz = de_y2_l6_quiz, - .quiz_hints = de_y2_l6_quiz_hints, - .n_quiz = (int)(sizeof de_y2_l6_quiz / sizeof de_y2_l6_quiz[0]), - } - }, - { - { - .slides = de_y3_l1_slides, - .n_slides = (int)(sizeof de_y3_l1_slides / sizeof de_y3_l1_slides[0]), - .reading = "Tom hat Halsschmerzen und ein bisschen Fieber. Die Ärztin sagt: Sie sollen viel trinken und heute zu Hause bleiben. Sie müssen nicht im Bett liegen, aber Sie sollen nicht Fußball spielen. Hier ist ein Rezept. Die Tabletten nehmen Sie zweimal am Tag. Wenn es am Freitag nicht besser ist, kommen Sie wieder.", - .readq = de_y3_l1_readq, - .read_hints = de_y3_l1_readq_hints, - .n_read = (int)(sizeof de_y3_l1_readq / sizeof de_y3_l1_readq[0]), - .quiz = de_y3_l1_quiz, - .quiz_hints = de_y3_l1_quiz_hints, - .n_quiz = (int)(sizeof de_y3_l1_quiz / sizeof de_y3_l1_quiz[0]), - }, - { - .slides = de_y3_l2_slides, - .n_slides = (int)(sizeof de_y3_l2_slides / sizeof de_y3_l2_slides[0]), - .listening = "Letzten Samstag sind wir nach Wien gefahren. Zuerst haben wir am Automaten zwei Fahrkarten gekauft, hin und zurück. Der Zug war zwanzig Minuten zu spät. Im Zug habe ich ein Buch gelesen und meine Schwester hat geschlafen. In Wien sind wir am Hauptbahnhof ausgestiegen. Danach haben wir die Innenstadt gesehen. Am Abend sind wir wieder nach Hause gefahren.", - .listenq = de_y3_l2_listenq, - .listen_hints = de_y3_l2_listenq_hints, - .n_listen = (int)(sizeof de_y3_l2_listenq / sizeof de_y3_l2_listenq[0]), - .gaps = de_y3_l2_gaps, - .n_gaps = (int)(sizeof de_y3_l2_gaps / sizeof de_y3_l2_gaps[0]), - }, - { - .slides = de_y3_l3_slides, - .n_slides = (int)(sizeof de_y3_l3_slides / sizeof de_y3_l3_slides[0]), - .gaps = de_y3_l3_gaps, - .n_gaps = (int)(sizeof de_y3_l3_gaps / sizeof de_y3_l3_gaps[0]), - .quiz = de_y3_l3_quiz, - .quiz_hints = de_y3_l3_quiz_hints, - .n_quiz = (int)(sizeof de_y3_l3_quiz / sizeof de_y3_l3_quiz[0]), - }, - { - .slides = de_y3_l4_slides, - .n_slides = (int)(sizeof de_y3_l4_slides / sizeof de_y3_l4_slides[0]), - .write_prompt = "Schreib eine kurze formale E-Mail, mindestens 40 Wörter. Benutze Sie a Grüßen.", - .write_model = "Sehr geehrte Frau Berger, ich schreibe Ihnen, weil ich die Stelle im Café interessant finde. Ich bin siebzehn und ich habe schon im Sommer in einem Geschäft gearbeitet. Ich kann am Samstag arbeiten. Können Sie mich anrufen? Im Anhang ist mein Lebenslauf. Mit freundlichen Grüßen, Eva Malá.", - .write_keys = "Sie|Grüßen", - .write_min = 40, - .quiz = de_y3_l4_quiz, - .quiz_hints = de_y3_l4_quiz_hints, - .n_quiz = (int)(sizeof de_y3_l4_quiz / sizeof de_y3_l4_quiz[0]), - }, - { - .slides = de_y3_l5_slides, - .n_slides = (int)(sizeof de_y3_l5_slides / sizeof de_y3_l5_slides[0]), - .reading = "Die Bahn ist oft besser für die Umwelt als das Flugzeug, aber nicht immer billiger. Ein Ticket nach Berlin kann teurer sein als ein Flug. Trotzdem fahren viele Jugendliche lieber mit dem Zug, weil sie unterwegs lesen können. Am liebsten fahre ich nachts, weil der Sitz dann so ruhig ist wie zu Hause.", - .readq = de_y3_l5_readq, - .read_hints = de_y3_l5_readq_hints, - .n_read = (int)(sizeof de_y3_l5_readq / sizeof de_y3_l5_readq[0]), - .gaps = de_y3_l5_gaps, - .n_gaps = (int)(sizeof de_y3_l5_gaps / sizeof de_y3_l5_gaps[0]), - }, - { - .slides = de_y3_l6_slides, - .n_slides = (int)(sizeof de_y3_l6_slides / sizeof de_y3_l6_slides[0]), - .reading = "Mia bleibt heute zu Hause, weil sie Fieber hat. Die Ärztin hat gesagt, dass sie viel trinken soll. Wenn es morgen besser ist, geht Mia wieder in die Schule. Sie findet die Bahn besser als das Auto, aber heute kann sie nicht fahren.", - .readq = de_y3_l6_readq, - .read_hints = de_y3_l6_readq_hints, - .n_read = (int)(sizeof de_y3_l6_readq / sizeof de_y3_l6_readq[0]), - .listening = "Ich habe mich für die Stelle beworben, weil ich gern mit Menschen arbeite. Die Chefin hat gesagt, dass ich am Samstag kommen soll. Wenn das Gespräch gut ist, kann ich im Juli anfangen. Ich bin nervös, aber ich freue mich.", - .listenq = de_y3_l6_listenq, - .listen_hints = de_y3_l6_listenq_hints, - .n_listen = (int)(sizeof de_y3_l6_listenq / sizeof de_y3_l6_listenq[0]), - .write_prompt = "Schreib mindestens 35 Wörter. Was findest du besser, Bahn oder Auto, und warum? Benutze weil.", - .write_model = "Ich finde die Bahn besser als das Auto, weil ich unterwegs lesen kann und nicht selbst fahren muss. Das Auto ist manchmal schneller, aber die Bahn ist ruhiger. Am liebsten fahre ich mit dem Zug, weil ich dabei Musik hören kann.", - .write_keys = "weil|besser", - .write_min = 35, - .quiz = de_y3_l6_quiz, - .quiz_hints = de_y3_l6_quiz_hints, - .n_quiz = (int)(sizeof de_y3_l6_quiz / sizeof de_y3_l6_quiz[0]), - } - }, - { - { - .slides = de_y4_l1_slides, - .n_slides = (int)(sizeof de_y4_l1_slides / sizeof de_y4_l1_slides[0]), - .listening = "Früher habe ich jeden Abend ferngesehen. Seit zwei Jahren mache ich das nicht mehr. Ich höre einen Podcast auf dem Weg zur Schule und ich lese die Nachrichten auf dem Handy. Manche Videos sind lustig, aber nicht jede Quelle ist seriös. Letzte Woche habe ich ein Gerücht geteilt und später gemerkt, dass es falsch war. Seitdem prüfe ich den Text, bevor ich ihn schicke.", - .listenq = de_y4_l1_listenq, - .listen_hints = de_y4_l1_listenq_hints, - .n_listen = (int)(sizeof de_y4_l1_listenq / sizeof de_y4_l1_listenq[0]), - }, - { - .slides = de_y4_l2_slides, - .n_slides = (int)(sizeof de_y4_l2_slides / sizeof de_y4_l2_slides[0]), - .write_prompt = "Schreib eine formelle E-Mail, mindestens 45 Wörter. Der Zug hatte Verspätung. Benutze Ihnen a Grüßen.", - .write_model = "Sehr geehrte Damen und Herren, ich schreibe Ihnen, weil der Zug am 3. Mai nach Berlin zwanzig Minuten zu spät war. Deshalb habe ich meinen Termin verpasst. Ich bitte Sie um eine Erklärung oder um das Geld zurück. Im Anhang ist mein Ticket. Mit freundlichen Grüßen, Tereza Malá.", - .write_keys = "Ihnen|Grüßen", - .write_min = 45, - .quiz = de_y4_l2_quiz, - .quiz_hints = de_y4_l2_quiz_hints, - .n_quiz = (int)(sizeof de_y4_l2_quiz / sizeof de_y4_l2_quiz[0]), - }, - { - .slides = de_y4_l3_slides, - .n_slides = (int)(sizeof de_y4_l3_slides / sizeof de_y4_l3_slides[0]), - .reading = "Der Nachtzug von Prag nach Berlin ist für viele Jugendliche interessanter als ein billiger Flug, obwohl das Ticket oft mehr kostet. Man kann lesen, schlafen und muss nicht um fünf Uhr am Flughafen sein. Kritiker sagen, dass die Verspätung ein Problem ist und dass die Abteile klein sind. Trotzdem lohnt sich die Fahrt für Lea. Sie ist schon dreimal gefahren. Sie sagt, dass sie nur fliegt, wenn sie den Abendzug verpasst. Für sie ist die Reise ein Teil des Urlaubs und nicht nur eine Strecke.", - .readq = de_y4_l3_readq, - .read_hints = de_y4_l3_readq_hints, - .n_read = (int)(sizeof de_y4_l3_readq / sizeof de_y4_l3_readq[0]), - }, - { - .slides = de_y4_l4_slides, - .n_slides = (int)(sizeof de_y4_l4_slides / sizeof de_y4_l4_slides[0]), - .gaps = de_y4_l4_gaps, - .n_gaps = (int)(sizeof de_y4_l4_gaps / sizeof de_y4_l4_gaps[0]), - .quiz = de_y4_l4_quiz, - .quiz_hints = de_y4_l4_quiz_hints, - .n_quiz = (int)(sizeof de_y4_l4_quiz / sizeof de_y4_l4_quiz[0]), - }, - { - .slides = de_y4_l5_slides, - .n_slides = (int)(sizeof de_y4_l5_slides / sizeof de_y4_l5_slides[0]), - .gaps = de_y4_l5_gaps, - .n_gaps = (int)(sizeof de_y4_l5_gaps / sizeof de_y4_l5_gaps[0]), - .quiz = de_y4_l5_quiz, - .quiz_hints = de_y4_l5_quiz_hints, - .n_quiz = (int)(sizeof de_y4_l5_quiz / sizeof de_y4_l5_quiz[0]), - }, - { - .slides = de_y4_l6_slides, - .n_slides = (int)(sizeof de_y4_l6_slides / sizeof de_y4_l6_slides[0]), - .reading = "In unserer Bibliothek kann man jetzt nicht nur Bücher, sondern auch Werkzeug ausleihen. Die Idee kommt von einer Bibliothekarin, die sagte, dass viele Leute Dinge kaufen, die sie nur einmal brauchen. Im März haben Jugendliche zwanzig Wasserkocher repariert. Wenn das Projekt weitergeht, machen andere Bibliotheken mit. Man muss die Sachen sauber zurückgeben.", - .readq = de_y4_l6_readq, - .read_hints = de_y4_l6_readq_hints, - .n_read = (int)(sizeof de_y4_l6_readq / sizeof de_y4_l6_readq[0]), - .listening = "Der Nachtzug nach Berlin hat vierzig Minuten Verspätung, weil ein Baum auf den Gleisen liegt. Fahrgäste mit einem Platz können in Wagen vier warten. Wenn Sie noch nicht eingecheckt haben, machen Sie das bitte am Handy. Wir wären froh, wenn der Gang frei bliebe. Um zehn wissen wir mehr.", - .listenq = de_y4_l6_listenq, - .listen_hints = de_y4_l6_listenq_hints, - .n_listen = (int)(sizeof de_y4_l6_listenq / sizeof de_y4_l6_listenq[0]), - .write_prompt = "Schreib mindestens 40 Wörter an einen Freund. Lad ihn ein, Werkzeug in der Bibliothek auszuleihen. Benutze weil.", - .write_model = "Hallo Adam, in der Bibliothek kann man jetzt Werkzeug ausleihen, und ich glaube, das ist etwas für dich, weil du oft nur eine Bohrmaschine für einen Nachmittag brauchst. Wenn du am Samstag Zeit hast, komme ich mit. Wir müssen die Sachen danach sauber zurückgeben. Hast du Lust?", - .write_keys = "weil|wenn", - .write_min = 40, - .quiz = de_y4_l6_quiz, - .quiz_hints = de_y4_l6_quiz_hints, - .n_quiz = (int)(sizeof de_y4_l6_quiz / sizeof de_y4_l6_quiz[0]), - } - }, -}; - diff --git a/src/globals.c b/src/globals.c deleted file mode 100644 index 59db94d..0000000 --- a/src/globals.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "graduately.h" - -GtkStack *main_stack; - -GtkWindow *main_window; - -GtkWidget *welcome_heading; - -GtkCssProvider *theme_provider; - -ThemeId app_theme_id = THEME_CATPPUCCIN; - -ColorMode app_color_mode = MODE_LIGHT; - -UiLang app_lang = LANG_CS; - -ThemePalette app_theme; - -double app_ui_scale = 1.0; - -const char *theme_names[THEME_COUNT] = { - "Catppuccin", - "Nord", - "Dracula", - "Rose Pine", - "Ocean", - "Gruvbox", - "Solarized", - "Everforest", - "Monokai", - "One Dark", -}; - -GtkWidget *theme_swatch_areas[THEME_COUNT]; - -UnitCtx units[NUM_UNITS] = {0}; - -const char *const u1_ex_names[MAX_UNIT_EX + 1] = { - NULL, - "Dialog", "Sätze bilden", "Was ist richtig?", "Freie Antwort", - "Zahlen", "Wie viel?", "Zahlenreihe", "Verb einsetzen", - "Wer? Wie? Wo?", "Wörter trennen", "Grußformen", - "Was macht er/sie?", "Länder", -}; - -const char *const u2_ex_names[MAX_UNIT_EX + 1] = { - NULL, - "Verben konjugieren", "aus oder in", "Fragewörter", "sprechen", - "Nationalitäten", "Woher?", "Länder schreiben", "Verben einsetzen", - "Freie Antwort", "Euro", "Wörter suchen", "Was ist richtig?", - "Ordne zu", "Lückentext", "Verbinde", "Zahlen", - "Steckbrief", "Berufe", "Nationalität", -}; - -const char *const u3_ex_names[MAX_UNIT_EX + 1] = { - NULL, - "Familienpaare", "mein oder dein", "ein / kein", "Lückentext", - "Marcos Familie", "Sortieren", "Possessivtabelle", "Akkusativ", - "kein / nicht", "Sätze bauen", "Was siehst du?", "Wem gehört das?", - "Es gibt …", "Beschreiben", "Wochenende", -}; - -GtkWidget *road_scroll; - -GtkWidget *road_fixed; - -GtkWidget *road_rail; - -GtkWidget *road_nodes[NUM_UNITS]; - -GtkWidget *road_labels[NUM_UNITS]; - -double road_cx[NUM_UNITS]; - -double road_cy[NUM_UNITS]; - -int road_cols = NUM_UNITS; - -int road_rows = 1; - -int road_cw = (int)(2.0 * ROAD_MX + (NUM_UNITS - 1) * PATH_SPAC); - -int road_ch = (int)(2.0 * ROAD_MY); diff --git a/src/graduately.h b/src/graduately.h deleted file mode 100644 index 8bb95fe..0000000 --- a/src/graduately.h +++ /dev/null @@ -1,1571 +0,0 @@ -#ifndef GRADUATELY_H -#define GRADUATELY_H - -#include -#include -#include -#include -#include - -/* GLib on Ubuntu 22.04 predates G_APPLICATION_DEFAULT_FLAGS. */ -#ifndef G_APPLICATION_DEFAULT_FLAGS -#define G_APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE -#endif - -#define NUM_UNITS 10 -#define NUM_UNLOCKED 3 /* first NUM_UNLOCKED units (index 0..2) are open */ -#define MAX_UNIT_EX 20 /* largest exercise count any unit may have */ -#define NUM_SUBJECTS 13 -#define NET_SUBJ 1 /* index of "Správa počítačových sítí" */ -#define HW_SUBJ 2 /* index of "Technické vybavení" */ -#define CZ_SUBJ 3 /* index of "Český jazyk a literatura" */ -#define ON_SUBJ 4 /* index of "Občanská nauka" */ -#define EN_SUBJ 5 /* index of "English" */ -#define MATH_SUBJ 6 /* index of "Matematika" */ -#define PHY_SUBJ 7 /* index of "Fyzika" */ -#define SCI_SUBJ 8 /* index of "Základy Přírodopisných věd" */ -#define CSS_FILE "style.css" -#define CHANGELOG_FILE "changelog.txt" -#define APP_ID "org.maturita.Maturita" -/* Published builds bake in the commit they were made from (see COMMIT in the - * Makefile), which is what the updater compares against the build published - * in the repository. Plain source builds stay at "dev" and never offer an - * update; the macOS bundler supplies the checkout commit for local packages. */ -#ifndef APP_COMMIT -#define APP_COMMIT "dev" -#endif -#define UPDATE_REPO "pepaskopec-blip/Graduately" -/* Packages live on their own branch rather than in releases, so the update - * always matches whatever is on main. */ -#define UPDATE_BRANCH "builds" -#define ICON_NAME "maturita" -#define ICON_FILE "assets/app-icon.png" -#define ICON_THEME_DIR "assets/icons" /* cwd when run from source tree */ -#define ICON_THEME_DIR_ALT "icons" /* next to the binary after install */ -#define ICON_FILE_ALT "icons/hicolor/512x512/apps/maturita.png" -#define SHARE_DIR "share" /* portable Freedesktop data root */ -/* Relative leaf names; absolute paths are filled by setup_portable_paths(). */ -#define PROGRESS_DIR_NAME "progress" -extern char *app_progress_dir; -extern char *app_progress_u1; -extern char *app_progress_u2; -extern char *app_progress_u3; -extern char *app_settings_file; -extern char *app_progress_net; -extern char *app_progress_hw; -extern char *app_progress_on; -extern char *app_progress_on2; -extern char *app_progress_on3; -extern char *app_progress_on4; -extern char *app_progress_en; -extern char *app_progress_de; -extern char *app_progress_mluvnice; -extern char *app_progress_cetba; -extern char *app_progress_lit; -extern char *app_progress_lit2; -extern char *app_progress_lit3; -extern char *app_progress_lit4; -extern char *app_progress_chem; -extern char *app_progress_bio; -extern char *app_progress_fyz; -extern char *app_progress_fyz2; -extern char *app_progress_fyz3; -extern char *app_progress_fyz4; -extern char *app_progress_mat0; -extern char *app_progress_mat; -extern char *app_progress_mat2; -extern char *app_progress_mat3; -extern char *app_progress_mat4; -#define PROGRESS_DIR app_progress_dir -#define PROGRESS_U1 app_progress_u1 -#define PROGRESS_U2 app_progress_u2 -#define PROGRESS_U3 app_progress_u3 -#define SETTINGS_FILE app_settings_file -#define PROGRESS_NET app_progress_net -#define PROGRESS_HW app_progress_hw -#define PROGRESS_ON app_progress_on -#define PROGRESS_ON2 app_progress_on2 -#define PROGRESS_ON3 app_progress_on3 -#define PROGRESS_ON4 app_progress_on4 -#define PROGRESS_EN app_progress_en -#define PROGRESS_DE app_progress_de -#define NODE_SIZE 88.0 -#define PATH_SPAC 240.0 -#define ROAD_MX 150.0 /* horizontal canvas margin */ -#define ROAD_MY 150.0 /* vertical canvas margin */ -#define ROAD_GAP 240.0 /* vertical space between folded rows */ -#define ROAD_WAVE 44.0 /* wavy vertical offset of the nodes */ -#define SUB_BUBBLE NODE_SIZE /* round node, matches .unit-node */ -#define SUB_MX 110.0 -#define SUB_MY 150.0 -#define SUB_SPAC 220.0 -#define SUB_GAP 210.0 -#define SUB_WAVE 34.0 -#define EX_BUBBLE 64.0 /* exercise bubble size (matches .ex-bubble) */ -#define EX_MX 80.0 /* horizontal canvas margin */ -#define EX_MY 120.0 /* vertical canvas margin */ -#define EX_SPAC 150.0 /* horizontal distance between bubbles */ -#define EX_GAP 200.0 /* vertical space between folded rows */ -#define EX_WAVE 26.0 /* wavy vertical offset of the bubbles */ -#define EX_BRANCH_LIFT 150.0 /* extra top space for an off-path branch */ -#define EX_BRANCH_DX 64.0 /* sideways offset so the branch link slants */ -#define HM_WORDS 5 -#define HM_MAX_MISSES 6 -#define HM_N_LETTERS 29 /* QWERTY rows + Ä/Ö/Ü (see hm_letters[]) */ -#define HM_ROW2 10 /* start of the ASDF row */ -#define HM_ROW3 19 /* start of the ZXCV row */ -#define HM_ROW4 26 /* start of the umlaut row */ -#define NET_UNITS 27 -#define NET_SLIDES 4 -#define NET2_SLIDES 5 -#define NET3_SLIDES 4 -#define NET4_SLIDES 4 -#define NET5_SLIDES 4 -#define NET6_SLIDES 4 -#define NET7_SLIDES 4 -#define NET8_SLIDES 4 -#define NET9_SLIDES 4 -#define NET10_SLIDES 3 -#define NET11_SLIDES 8 -#define NET12_SLIDES 6 -#define NET13_SLIDES 4 -#define NET14_SLIDES 5 -#define NET15_SLIDES 3 -#define NET16_SLIDES 4 -#define NET17_SLIDES 7 -#define NET18_SLIDES 5 -#define NET19_SLIDES 7 -#define NET20_SLIDES 7 -#define NET21_SLIDES 8 -#define NET22_SLIDES 8 -#define NET23_SLIDES 5 -#define NET24_SLIDES 5 -#define NET25_SLIDES 6 -#define NET26_SLIDES 7 -#define NET27_SLIDES 8 -#define NET_LESSONS 27 -#define HW_UNITS 29 -#define HW_LESSONS 29 -#define ON_UNITS 17 -#define ON_LESSONS 17 -#define ON2_UNITS 16 -#define ON2_LESSONS 16 -#define ON3_UNITS 16 -#define ON3_LESSONS 16 -#define ON4_UNITS 16 -#define ON4_LESSONS 16 -#define LIT_N 8 -#define SCI_N 8 -#define FYZ_N 8 -#define MATH_N 8 -#define HW_SLIDES 3 -#define HW2_SLIDES 6 -#define HW3_SLIDES 2 -#define HW4_SLIDES 2 -#define HW5_SLIDES 2 -#define HW6_SLIDES 2 -#define HW7_SLIDES 2 -#define HW8_SLIDES 2 -#define HW9_SLIDES 2 - -typedef enum { - THEME_CATPPUCCIN = 0, - THEME_NORD, - THEME_DRACULA, - THEME_ROSE_PINE, - THEME_OCEAN, - THEME_GRUVBOX, - THEME_SOLARIZED, - THEME_EVERFOREST, - THEME_MONOKAI, - THEME_ONE_DARK, - THEME_COUNT -} ThemeId; -typedef enum { - MODE_DARK = 0, - MODE_LIGHT -} ColorMode; -typedef enum { - LANG_CS = 0, - LANG_EN -} UiLang; -typedef struct TransSection TransSection; /* vocabulary word list for a branch */ -typedef struct { - unsigned crust; - unsigned base; - unsigned mantle; - unsigned surface0; - unsigned surface1; - unsigned surface2; - unsigned overlay; - unsigned text; - unsigned subtext; - unsigned accent; - unsigned accent2; - unsigned accent3; - unsigned success; - unsigned success2; - unsigned warning; - unsigned error; - unsigned on_accent; - unsigned node; - unsigned locked_bg; - unsigned locked_border; - unsigned rail; - unsigned finish_dark; - unsigned finish_light; - unsigned finish_stroke; -} ThemePalette; -typedef struct { - const char *title; /* German unit title */ - const char *page; /* roadmap-stack child name, e.g. "unit1" */ - const char *ex_tag; /* exercise page prefix, e.g. "u1" */ - const char *sub_key; /* i18n key for the exercise-map subtitle */ - const char *back_target; /* page the exercise map returns to */ - const char *progress_file; - gboolean unlocked; - gboolean done[MAX_UNIT_EX + 1]; /* exercise state, 1..n_ex */ - const char *ex_names[MAX_UNIT_EX + 1]; /* bubble labels, 1..n_ex */ - int n_ex; - GtkWidget *node; /* roadmap node button */ - GtkWidget *node_done_icon; - /* exercise-map page widgets + serpentine geometry */ - GtkWidget *ex_scroll; - GtkWidget *ex_fixed; - GtkWidget *ex_rail; - GtkWidget *ex_cells[MAX_UNIT_EX]; /* 0..n_ex-1 */ - GtkWidget *ex_labels[MAX_UNIT_EX]; /* 0..n_ex-1 */ - GtkWidget *ex_icons[MAX_UNIT_EX + 1]; /* per-bubble check icon 1..n */ - double ex_cx[MAX_UNIT_EX]; - double ex_cy[MAX_UNIT_EX]; - int ex_rows, ex_cols, ex_cw, ex_ch; - guint ex_idle; - /* optional off-path branch exercise (e.g. vocabulary training) */ - gboolean has_branch; - const char *branch_name; /* label under the branch bubble */ - const char *branch_target; /* stack page name */ - int branch_ex; /* done[] slot used by the branch */ - GtkWidget *branch_cell; - GtkWidget *branch_label; - GtkWidget *branch_icon; - double branch_cx; - double branch_cy; - const struct TransSection *trans_sections; /* branch vocabulary content */ - int n_trans_sections; -} UnitCtx; -typedef struct { double r, g, b; } Rgb; -typedef struct { - GtkWidget *widget; - const char *key; - int kind; /* 0 label, 1 button, 2 tooltip, 3 placeholder, 4 ex4 sample */ -} I18nBind; -typedef struct { - const char *key; - const char *cs; - const char *en; -} TrEntry; -typedef struct { - GtkWidget *ex_value; - GtkWidget *pct_value; - GtkWidget *units_value; - GtkWidget *overall_bar; - - /* one progress block per subject (index matches sub_keys[]) */ - struct { - GtkWidget *name; /* subject heading label */ - GtkWidget *count; /* "13 / 47" or the locked text */ - GtkWidget *bar; /* per-subject overall progress bar */ - GtkWidget *units_box; /* holds the unit rows, NULL if no units */ - } subj[NUM_SUBJECTS]; - - /* per-unit rows, indexed by the global units[] index */ - GtkWidget *unit_count[NUM_UNITS]; - GtkWidget *unit_badge[NUM_UNITS]; - GtkWidget *unit_bar[NUM_UNITS]; - GtkWidget *unit_row[NUM_UNITS]; -} StatsUi; -typedef struct { - int done_ex; - int total_ex; - int done_units; - int open_units; -} ProgressSum; -typedef struct { - GArray *combos; /* GtkComboBox* */ - GArray *answers; /* const char* */ - GArray *trans; /* GtkWidget* hidden meaning labels */ - GArray *models; /* GtkWidget* hidden German answer labels */ - gboolean trans_upfront; /* meanings shown before Check */ - gboolean reveal_german; /* German answer shown on Check */ - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; -} ComboListCtx; -typedef struct { - const char *prompt; /* optional label shown above the sentence */ - const char *words[6]; - int n; -} AssemblyItem; -typedef struct { - GtkWidget *pool; - GtkWidget *target; - GtkWidget *group; - GtkWidget *stage; /* transparent overlay layer for the fly sprite */ - GtkWidget *trans; /* hidden meaning label under the group */ - GtkWidget *chips[6]; - int pool_order[6]; /* fixed shuffled order of the word pool */ - int placed[6]; - int placed_count; - int n_words; - gboolean flying; /* a click-move animation is in progress */ -} SentBuilder; -typedef struct { - SentBuilder *sb; - int idx; -} ChipRef; -typedef struct { - GtkWidget *chip; /* real chip, kept invisible in its final slot */ - GtkWidget *ghost; /* sprite flying from start to finish */ - GtkWidget *stage; - gboolean *flying; /* pointer to the owner's "animating" flag */ - double sx, sy; /* start position (stage coords) */ - double tx, ty; /* target position (stage coords) */ - guint wait; /* ticks waited for relayout */ - gint64 t0; /* < 0 while still measuring the target */ -} FlyCtx; -typedef struct { - SentBuilder **sbs; - int n; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; -} AsmCtx; -typedef struct { - const char *speaker; - const char *before; - const char *answer; - const char *after; -} DialogRow; -typedef struct { - const char *name; - const DialogRow *rows; - int n; -} Dialogue; -typedef struct { - const char *prompt; - const char *options[5]; - int n_options; - int correct; -} ChoiceQ; -typedef struct { - const char *prompt; - const char *answer; - const char *hint; -} MathItem; -typedef struct { - const ChoiceQ *qs; - int n; - int n_opts; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkToggleButton **toggles; - GtkWidget **trans; /* hidden meaning labels, one per question */ -} ChoiceCtx; -typedef struct { - const char *question; - const char *q_cs; /* Czech translation of the question */ - const char *sample; - const char *a_cs; /* Czech translation of the sample answer */ -} FreeQ; -typedef struct { - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget **samples; - int n; -} Ex4Ctx; -typedef struct { - const char *digits; - const char *answer; -} NumberQ; -typedef struct { - const char *emoji; - int count; - const char *noun; - const char *answer; -} CountQ; -typedef struct { - const char *before; - const char *after; - const char *answer; -} SeqQ; -typedef struct { - const char *before; - const char *after; - const char *answer; -} VerbQ; -typedef struct { - const char *emoji; - const char *before; - const char *after; - const char *answer; -} VerbClueQ; -typedef struct { - const char *emoji; - const char *label; - int correct_group; -} AssignItem; -typedef struct { - GtkWidget *pool; - GtkWidget *group_flow[3]; - GtkWidget *group_btn[3]; - int n_groups; - int active_group; - GtkWidget **items; /* per-item boxes (chip + hidden meaning) */ - GtkWidget **trans; /* hidden meaning labels */ - GtkWidget *stage; /* transparent overlay layer for the fly */ - gboolean flying; /* a click-move animation is in progress */ - int n_items; - int *current_group; - const AssignItem *items_data; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; -} AssignCtx; -typedef struct { - AssignCtx *ac; - int idx; -} AssignChipRef; -typedef struct { - ComboListCtx *ctx; - GtkWidget *note; - const VerbQ *qs; - int n; - const char **gloss; /* per-row word-level meaning keys (current lang) */ -} VerbNoteCtx; -typedef struct { - const char *prompt; /* German prompt text */ - const char *answers; /* accepted answers separated by '|' */ - const char *meaning; /* i18n key of the revealed meaning or NULL */ -} TypedQ; -struct TransSection { - const char *header; /* page label shown above the word, e.g. "Strana 22" */ - const TypedQ *rows; - int n; -}; -typedef struct { - const TypedQ *qs; - int n; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget **entries; - GtkWidget **trans; -} TypedCtx; -typedef struct { - TypedCtx *ctx; - GtkWidget *note; - const TypedQ *qs; - int n; -} TypedNoteCtx; -typedef struct { - const char *mid; /* middle part of the question, without the FW */ - const char *fw; /* correct Fragewort */ - const char *ans; /* correct answer */ -} OrdneRow; -typedef struct { - const char *stem; /* German sentence beginning with an ellipsis */ - const char *sample; /* finished German sample line */ -} ProfileQ; -typedef struct { - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget **samples; - int n; -} ProfileCtx; -typedef struct { - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget *draw; - GtkWidget *slots; - GtkWidget *hint_lbl; - GtkWidget *counter_lbl; - GtkWidget **letter_btns; - gboolean guessed[HM_N_LETTERS]; - gboolean locked; /* true during the "word solved" pause */ - gboolean finished; - int misses; - int word_index; -} HangmanCtx; -typedef struct { - const char *num; - const char *s0, *a0, *s1, *a1, *s2, *a2, *s3; /* up to 3 blanks */ - const char *mean; /* Czech meaning */ -} U3Fill; -typedef struct { - const char *num; /* item number on the first line of the item */ - const char *seg[4]; /* literal text segments, gaps+1 of them */ - const char *ans[3]; /* correct word per blank */ - int gaps; -} Ex2Row; -typedef struct { - const char *czech; /* whole-sentence translation, always shown */ - const Ex2Row *rows; - int nrows; -} Ex2Item; -typedef struct { - GArray *combos; /* every blank combo (checking order) */ - GArray *answers; - GtkWidget **notes; /* one hidden word-translation note per item */ - GArray **item_combos; /* blank combos of each item */ - int n_items; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; -} Ex2Ctx; -typedef struct { - const char *num; - const char *s0, *a0, *s1, *a1, *s2, *a2, *s3, *a3, *s4; - const char *mean; -} U3Let; -typedef struct { - GArray *entries; - GArray *answers; - GArray *trans; - GArray *models; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; -} U3LetCtx; -typedef struct { - const char *seg[5]; /* literal text segments (gaps + 1) */ - const char *ans[4]; /* missing letters per gap */ - const char *czech; /* whole-sentence translation, always shown */ - const char *word[4]; /* completed German word per gap */ - const char *gmean[4]; /* Czech meaning of that word */ - int gaps; -} Ex4Row; -typedef struct { - GArray *entries; /* every small letter entry (checking order) */ - GArray *answers; - const Ex4Row *rows; - int n_rows; - GtkWidget **notes; /* hidden word-translation note per row */ - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; -} Ex4LetterCtx; -typedef struct { - GtkWidget **entries; - const char **answers; - int n; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; -} U3TableCtx; -typedef struct { - const char *prompt; - const char *answers; /* accepted substrings separated by '|' */ - const char *mean; /* Czech meaning shown under the entry */ - const char *german; /* German sentence(s) revealed after Check */ -} U3Kw; -typedef struct { - const U3Kw *qs; - int n; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget **entries; - GtkWidget **trans; - GtkWidget **models; -} U3KwCtx; -typedef struct { - const char *prompt; - const char *solution; -} NetTask; -typedef struct { - int pfx; - const char *net; - const char *bcast; - const char *lo; - const char *hi; -} NetAns; -typedef struct { - GtkWidget *combo[4]; - GtkWidget *net[4]; - GtkWidget *bcast[4]; - GtkWidget *lo[4]; - GtkWidget *hi[4]; - GtkWidget *feed; - GtkWidget *note; - int id; - gboolean infeasible; -} NetQz; -typedef struct { - GtkWidget *stack; - GtkWidget *prev_btn; - GtkWidget *next_btn; - guint idx; - guint n_slides; - const char *unit_page; - const char *ex_page; - GArray *note_kicks; - GArray *note_titles; - GArray *note_bodies; - GtkWidget *done_icon; - gboolean done; -} NetLesson; -typedef struct { - const char *kicker; - const char *title; - const char *tip; - const char *line[8]; -} NetSlide; -typedef struct { - const NetSlide *slides; - int n_slides; - const char *reading; - const ChoiceQ *readq; - const char **read_hints; - int n_read; - const char *listening; - const ChoiceQ *listenq; - const char **listen_hints; - int n_listen; - const TypedQ *gaps; - int n_gaps; - const char *write_prompt; - const char *write_model; - const char *write_keys; - int write_min; - const ChoiceQ *quiz; - const char **quiz_hints; - int n_quiz; -} EnLesson; -typedef struct { - const ChoiceQ *qs; - int n; - int n_opts; - int lesson_id; - GtkWidget *feedback; - GtkToggleButton **toggles; - GtkWidget **hints; -} NetMcqCtx; - -extern GtkStack *main_stack; -extern GtkWindow *main_window; -extern GtkWidget *welcome_heading; -extern GtkCssProvider *theme_provider; -extern ThemeId app_theme_id; -extern ColorMode app_color_mode; -extern UiLang app_lang; -extern ThemePalette app_theme; -extern double app_ui_scale; -extern const char *theme_names[THEME_COUNT]; -extern GtkWidget *theme_swatch_areas[THEME_COUNT]; -extern UnitCtx units[NUM_UNITS]; -extern const char *sub_keys[NUM_SUBJECTS]; -extern const int sub_unit_start[NUM_SUBJECTS]; -extern const int sub_unit_count[NUM_SUBJECTS]; -extern const char *const u1_ex_names[MAX_UNIT_EX + 1]; -extern const char *const u2_ex_names[MAX_UNIT_EX + 1]; -extern const char *const u3_ex_names[MAX_UNIT_EX + 1]; -extern GtkWidget *road_scroll; -extern GtkWidget *road_fixed; -extern GtkWidget *road_rail; -extern GtkWidget *road_nodes[NUM_UNITS]; -extern GtkWidget *road_labels[NUM_UNITS]; -extern double road_cx[NUM_UNITS]; -extern double road_cy[NUM_UNITS]; -extern int road_cols; -extern int road_rows; -extern int road_cw; -extern int road_ch; -extern GArray *i18n_binds; -extern const TrEntry tr_ui[]; -extern const TrEntry tr_content[]; -extern StatsUi stats_ui; -extern char *stats_return_page; -extern guint road_idle; -extern GtkWidget *sub_scroll; -extern GtkWidget *sub_fixed; -extern GtkWidget *sub_rail; -extern GtkWidget *sub_cells[NUM_SUBJECTS]; -extern GtkWidget *sub_labels[NUM_SUBJECTS]; -extern double sub_cx[NUM_SUBJECTS]; -extern double sub_cy[NUM_SUBJECTS]; -extern int sub_rows; -extern int sub_cols; -extern int sub_cw; -extern int sub_ch; -extern guint sub_idle; -extern const DialogRow ex1_d1[]; -extern const DialogRow ex1_d2[]; -extern const DialogRow ex1_d3[]; -extern const Dialogue ex1_dialogues[]; -extern const char *ex1_pool[]; -extern const char *ex1_meaning[]; -extern const AssemblyItem ex2_items[]; -extern const char *ex2_meaning[]; -extern const ChoiceQ ex3_questions[]; -extern const char *ex3_meaning[]; -extern const ChoiceQ ex9_questions[]; -extern const char *ex9_meaning[]; -extern const FreeQ ex4_questions[]; -extern const NumberQ ex5_data[]; -extern const char *ex5_pool[]; -extern const char *ex5_meaning[]; -extern const CountQ ex6_data[]; -extern const char *ex6_pool[]; -extern const char *ex6_meaning[]; -extern const SeqQ ex7_data[]; -extern const char *ex7_pool[]; -extern const char *ex7_meaning[]; -extern const VerbQ ex8_data[]; -extern const char *ex8_pool[]; -extern const char *ex8_meaning[]; -extern const AssemblyItem ex10_items[]; -extern const char *ex10_meaning[]; -extern const VerbClueQ ex12_data[]; -extern const char *ex12_pool[]; -extern const char *ex12_meaning[]; -extern const AssignItem ex11_items[]; -extern const AssignItem ex13_items[]; -extern const char *ex11_groups[]; -extern const char *ex13_groups[]; -extern const char *ex11_meaning[]; -extern const char *ex13_meaning[]; -extern const char *g05_bank; -extern const TypedQ g05_rows[]; -extern const TypedQ g06_rows[]; -extern const TypedQ g07_rows[]; -extern const TypedQ g11_rows[]; -extern const TypedQ s03_rows[]; -extern const TransSection u1_trans_sections[]; -extern const int u1_trans_sections_n; -extern const TransSection u2_trans_sections[]; -extern const int u2_trans_sections_n; -extern const TransSection u3_trans_sections[]; -extern const int u3_trans_sections_n; -extern const VerbQ g01_peter[]; -extern const VerbQ g01_jana[]; -extern const char *g01_pool[]; -extern const char *g01_peter_mean[]; -extern const char *g01_jana_mean[]; -extern const VerbQ g04_rows[]; -extern const char *g04_pool[]; -extern const char *g04_mean[]; -extern const VerbQ g08_rows[]; -extern const char *g08_pool[]; -extern const char *g08_mean[]; -extern const VerbQ g10_rows[]; -extern const char *g10_pool[]; -extern const char *g10_mean[]; -extern const VerbQ g14_rows[]; -extern const char *g14_pool[]; -extern const char *g14_mean[]; -extern const char *g14_gloss[]; -extern const VerbQ g15_rows[]; -extern const char *g15_pool[]; -extern const char *g15_mean[]; -extern const char *g15_gloss[]; -extern const VerbQ g16_rows[]; -extern const char *g16_pool[]; -extern const char *g16_mean[]; -extern const ChoiceQ g02_rows[]; -extern const char *g02_mean[]; -extern const ChoiceQ g03_rows[]; -extern const char *g03_mean[]; -extern const ChoiceQ g12_rows[]; -extern const char *g12_mean[]; -extern const OrdneRow g13_rows[]; -extern const char *g13_fw_pool[]; -extern const char *g13_ans_pool[]; -extern const char *g13_mean[]; -extern const FreeQ ex9_free_qs[]; -extern const ProfileQ s01_rows[]; -extern const char *hm_words[HM_WORDS]; -extern const char *hm_tips[HM_WORDS]; -extern const char *hm_letters[]; -extern const gunichar hm_letters_u[]; -extern const char *ex1_u3_pool[]; -extern const U3Fill ex1_u3_rows[]; -extern const char *ex2_u3_pool[]; -extern const Ex2Row ex2_u3_rows2[]; -extern const Ex2Row ex2_u3_rows3[]; -extern const Ex2Row ex2_u3_rows4[]; -extern const Ex2Item ex2_u3_items[]; -extern const char *ex3_u3_pool[]; -extern const U3Fill ex3_u3_rows[]; -extern const Ex4Row ex4_u3_rows[]; -extern const char *ex5_u3_bank; -extern const TypedQ ex5_u3_rows[]; -extern const AssignItem ex6_u3_items[]; -extern const char *ex6_u3_groups[]; -extern const char *ex6_u3_meaning[]; -extern const char *ex8_u3_pool[]; -extern const U3Fill ex8_u3_rows[]; -extern const char *ex8_u3_gloss[]; -extern const char *ex9_u3_pool[]; -extern const U3Fill ex9_u3_rows[]; -extern const AssemblyItem ex10_u3_items[]; -extern const char *ex10_u3_meaning[]; -extern const U3Kw ex11_u3_qs[]; -extern const char *ex12_u3_pool[]; -extern const U3Fill ex12_u3_rows[]; -extern const char *ex13_u3_pool[]; -extern const U3Fill ex13_u3_rows[]; -extern const U3Kw ex14_u3_qs[]; -extern const U3Let ex15_u3_rows[]; -extern NetLesson net_lessons[NET_LESSONS]; -extern NetLesson *net_notes_target; -extern NetLesson hw_lessons[HW_LESSONS]; -extern GtkWidget *hw_nodes[HW_UNITS]; -extern NetLesson on_lessons[ON_LESSONS]; -extern GtkWidget *on_nodes[ON_UNITS]; -extern NetLesson on2_lessons[ON2_LESSONS]; -extern GtkWidget *on2_nodes[ON2_UNITS]; -extern NetLesson on3_lessons[ON3_LESSONS]; -extern GtkWidget *on3_nodes[ON3_UNITS]; -extern NetLesson on4_lessons[ON4_LESSONS]; -extern GtkWidget *on4_nodes[ON4_UNITS]; -extern GtkWidget *net_note_host; -extern int net_note_last_w; -extern GtkWidget *net_scroll; -extern GtkWidget *net_fixed; -extern GtkWidget *net_rail; -extern GtkWidget *net_nodes[NET_UNITS]; -extern GtkWidget *net_labels[NET_UNITS]; -extern double net_cx[NET_UNITS]; -extern double net_cy[NET_UNITS]; -extern int net_cols; -extern int net_rows; -extern int net_cw; -extern int net_ch; -extern guint net_idle; -extern double net_last_avail; -extern int net_last_cols; -extern int net_last_rows; -extern int net_last_cw; -extern int net_last_ch; -extern cairo_surface_t *net_rail_cache; -extern int net_cache_w; -extern int net_cache_h; -extern const NetTask net_tasks[]; -extern const NetAns net_ans[4][4]; - -Rgb color_from_hex(unsigned int hex); -Rgb mix_rgb(Rgb a, Rgb b, double t); -ThemePalette theme_palette(ThemeId id, ColorMode mode); -void ex4_fill_sample(GtkWidget *label); -const char *tr(const char *key); -void i18n_ensure(void); -void i18n_apply_one(const I18nBind *b); -void i18n_bind(GtkWidget *widget, const char *key, int kind); -void refresh_welcome_heading(void); -void refresh_stats_ui(void); -void net_rail_theme_reset(void); -void apply_language(void); -char *read_css_file(void); -char *build_theme_css(const ThemePalette *p); -void save_settings(void); -void load_settings(void); -void force_restyle_tree(GtkWidget *w); -void apply_theme(void); -void draw_check_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void lock_paint(cairo_t *cr, double x0, double y0, double size, - const Rgb *c); -void draw_lock_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_wifi_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_back_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_settings_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_stats_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_search_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -GtkWidget *icon_area_new(GtkDrawingAreaDrawFunc fn, - double r, double g, double b, int px); -void setup_portable_paths(void); -char *normalize_answer(const char *input); -void shuffle_indices(int *arr, int n); -void flow_clear(GtkFlowBox *fb); -void answer_mark(GtkWidget *widget, gboolean ok); -void set_feedback(GtkWidget *label, gboolean ok, const char *text); -void set_feedback_warn(GtkWidget *label, const char *text); -gboolean text_has_german_umlaut(const char *s); -void add_umlaut_note(GtkWidget *body); -void unit_save_progress(UnitCtx *u); -void unit_load_progress(UnitCtx *u); -void load_progress(void); -void all_rails_redraw(void); -void refresh_completion_ui(void); -void mark_done(UnitCtx *u, int n); -void net_load_progress(void); -void net_save_progress(void); -void mark_net_done(int lesson_id); -void refresh_net_completion_ui(void); -void progress_for_net(ProgressSum *out); -void hw_load_progress(void); -void hw_save_progress(void); -void mark_hw_done(int lesson_id); -void refresh_hw_completion_ui(void); -void progress_for_hw(ProgressSum *out); -void hw_rail_theme_reset(void); -void on_load_progress(void); -void on_save_progress(void); -void mark_on_done(int lesson_id); -void refresh_on_completion_ui(void); -void progress_for_on(ProgressSum *out); -void on_rail_theme_reset(void); -void on_lessons_apply_lang(void); -GtkWidget *build_onyears_page(void); -GtkWidget *build_onmap_page(void); -void add_on_pages(GtkStack *stack); -void en_load_progress(void); -void progress_for_en(ProgressSum *out); -void en_rail_theme_reset(void); -GtkWidget *build_enyears_page(void); -void add_en_pages(GtkStack *stack); -GtkWidget *skill_unit_page(NetLesson *L, const EnLesson *lesson, - const char *back, const char *title_key, - const char *sub_key); -GtkWidget *skill_ex_page(const EnLesson *lesson, int year, int index, - void (*on_done)(int, int), - const char *back, const char *title_key, - const char *voice); -void skill_slide_apply(NetLesson *L); -GtkWidget *build_dehome_page(void); -void add_de_pages(GtkStack *stack); -void de_load_progress(void); -void progress_for_de(ProgressSum *out); -typedef struct QuizYear QuizYear; -extern QuizYear *qy_net2; -extern QuizYear *qy_net3; -extern QuizYear *qy_net4; -extern QuizYear *qy_hw2; -extern QuizYear *qy_hw3; -extern QuizYear *qy_hw4; -void quizyear_boot(void); -void quizyear_load_all(void); -void quizyear_apply_lang(void); -void progress_for_net_years(ProgressSum *out); -void progress_for_hw_years(ProgressSum *out); -GtkWidget *quizyear_map(QuizYear *Y); -GtkWidget *quizyear_unit(QuizYear *Y, int index, const char *title_key, - const char *sub_key, const NetSlide *slides, - int n_slides); -GtkWidget *quizyear_quiz(QuizYear *Y, int index, const char *title_key, - const char *head_key, const ChoiceQ *qs, - const char **hints, int n); -void add_it_year_pages(GtkStack *stack); -void on2_load_progress(void); -void on2_save_progress(void); -void mark_on2_done(int lesson_id); -void refresh_on2_completion_ui(void); -void on2_rail_theme_reset(void); -void on2_lessons_apply_lang(void); -GtkWidget *build_on2map_page(void); -void add_on2_pages(GtkStack *stack); -void on3_load_progress(void); -void on3_save_progress(void); -void mark_on3_done(int lesson_id); -void refresh_on3_completion_ui(void); -void on3_rail_theme_reset(void); -void on3_lessons_apply_lang(void); -GtkWidget *build_on3map_page(void); -void add_on3_pages(GtkStack *stack); -void on4_load_progress(void); -void on4_save_progress(void); -void mark_on4_done(int lesson_id); -void refresh_on4_completion_ui(void); -void on4_rail_theme_reset(void); -void on4_lessons_apply_lang(void); -GtkWidget *build_on4map_page(void); -void add_on4_pages(GtkStack *stack); -void czech_rail_theme_reset(void); -void lit_load_progress(void); -void lit_rail_theme_reset(void); -void lit_lessons_apply_lang(void); -void progress_for_lit(ProgressSum *out); -GtkWidget *lit_unit_page(int year, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides); -GtkWidget *lit_mcq_page(int year, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n); -GtkWidget *build_lityears_page(void); -GtkWidget *build_litmap_page(void); -GtkWidget *build_lit2map_page(void); -GtkWidget *build_lit3map_page(void); -GtkWidget *build_lit4map_page(void); -void add_lit_pages(GtkStack *stack); -void add_lit2_pages(GtkStack *stack); -void add_lit3_pages(GtkStack *stack); -void add_lit4_pages(GtkStack *stack); -extern NetLesson lit_lessons[LIT_N]; -extern NetLesson lit2_lessons[LIT_N]; -extern NetLesson lit3_lessons[LIT_N]; -extern NetLesson lit4_lessons[LIT_N]; -void sci_load_progress(void); -void sci_rail_theme_reset(void); -void sci_lessons_apply_lang(void); -void progress_for_sci(ProgressSum *out); -GtkWidget *sci_unit_page(int area, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides); -GtkWidget *sci_mcq_page(int area, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n); -GtkWidget *build_scimap_page(void); -GtkWidget *build_chemmap_page(void); -GtkWidget *build_biomap_page(void); -void add_chem_pages(GtkStack *stack); -void add_bio_pages(GtkStack *stack); -extern NetLesson chem_lessons[SCI_N]; -extern NetLesson bio_lessons[SCI_N]; -void fyz_load_progress(void); -void fyz_rail_theme_reset(void); -void fyz_lessons_apply_lang(void); -void progress_for_fyz(ProgressSum *out); -GtkWidget *fyz_unit_page(int year, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides); -GtkWidget *fyz_mcq_page(int year, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n); -GtkWidget *build_fyzyears_page(void); -GtkWidget *build_fyzmap_page(void); -GtkWidget *build_fyz2map_page(void); -GtkWidget *build_fyz3map_page(void); -GtkWidget *build_fyz4map_page(void); -void add_fyz_pages(GtkStack *stack); -void add_fyz2_pages(GtkStack *stack); -void add_fyz3_pages(GtkStack *stack); -void add_fyz4_pages(GtkStack *stack); -extern NetLesson fyz_lessons[FYZ_N]; -extern NetLesson fyz2_lessons[FYZ_N]; -extern NetLesson fyz3_lessons[FYZ_N]; -extern NetLesson fyz4_lessons[FYZ_N]; -gboolean math_answer_ok(const char *spec, const char *user); -gboolean math_is_draw(const char *spec); -int math_draw_need(const char *spec); -int math_draw_fixed(const char *spec, int *xs, int *ys, int cap); -gboolean math_draw_ok(const char *spec, const int *xs, const int *ys, int n); -void math_load_progress(void); -void math_rail_theme_reset(void); -void math_lessons_apply_lang(void); -void progress_for_math(ProgressSum *out); -GtkWidget *math_unit_page(int year, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides); -GtkWidget *math_practice_page(int year, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const MathItem *items, int n); -GtkWidget *build_matyears_page(void); -GtkWidget *build_mat0map_page(void); -GtkWidget *build_matmap_page(void); -GtkWidget *build_mat2map_page(void); -GtkWidget *build_mat3map_page(void); -GtkWidget *build_mat4map_page(void); -void add_mat0_pages(GtkStack *stack); -void add_mat_pages(GtkStack *stack); -void add_mat2_pages(GtkStack *stack); -void add_mat3_pages(GtkStack *stack); -void add_mat4_pages(GtkStack *stack); -extern NetLesson mat0_lessons[MATH_N]; -extern NetLesson mat_lessons[MATH_N]; -extern NetLesson mat2_lessons[MATH_N]; -extern NetLesson mat3_lessons[MATH_N]; -extern NetLesson mat4_lessons[MATH_N]; -void hw_lessons_apply_lang(void); -GtkWidget *build_hwyears_page(void); -GtkWidget *build_hwmap_page(void); -GtkWidget *build_czechmap_page(void); -void mluvnice_init(void); -GtkWidget *build_mluvnice_page(void); -GtkWidget *build_mluvnice_exercise_page(int n); -void mluvnice_refresh_ui(void); -void progress_for_mluvnice(ProgressSum *out); -GtkWidget *build_readinglist_page(void); -GtkWidget *build_cetba1984_page(void); -GtkWidget *build_cetba1984_quiz_page(void); -GtkWidget *build_cetba1984_plot_page(void); -GtkWidget *build_cetba_fuks_page(void); -GtkWidget *build_cetba_fuks_quiz_page(void); -GtkWidget *build_cetba_fuks_plot_page(void); -GtkWidget *build_cetba_stub_page(void); -GtkWidget *build_cetba_stub_quiz_page(void); -GtkWidget *build_cetba_stub_plot_page(void); -void cetba_register_search(void); -void cetba_open_stub(int idx); -void search_catalog_add(const char *title, const char *subtitle, - const char *target, gboolean locked, int rank, - const char *extra); -void book_rail_theme_reset(void); -GtkWidget *build_hw_unit1_page(void); -GtkWidget *build_hw_unit1_exercise_page(void); -GtkWidget *build_hw_unit2_page(void); -GtkWidget *build_hw_unit2_exercise_page(void); -GtkWidget *build_hw_unit3_page(void); -GtkWidget *build_hw_unit3_exercise_page(void); -GtkWidget *build_hw_unit4_page(void); -GtkWidget *build_hw_unit4_exercise_page(void); -GtkWidget *build_hw_unit5_page(void); -GtkWidget *build_hw_unit5_exercise_page(void); -GtkWidget *build_hw_unit6_page(void); -GtkWidget *build_hw_unit6_exercise_page(void); -GtkWidget *build_hw_unit7_page(void); -GtkWidget *build_hw_unit7_exercise_page(void); -GtkWidget *build_hw_unit8_page(void); -GtkWidget *build_hw_unit8_exercise_page(void); -GtkWidget *build_hw_unit9_page(void); -GtkWidget *build_hw_unit9_exercise_page(void); -GtkWidget *build_hw_unit10_page(void); -GtkWidget *build_hw_unit10_exercise_page(void); -GtkWidget *build_hw_unit11_page(void); -GtkWidget *build_hw_unit11_exercise_page(void); -GtkWidget *build_hw_unit12_page(void); -GtkWidget *build_hw_unit12_exercise_page(void); -GtkWidget *build_hw_unit13_page(void); -GtkWidget *build_hw_unit13_exercise_page(void); -GtkWidget *build_hw_unit14_page(void); -GtkWidget *build_hw_unit14_exercise_page(void); -GtkWidget *build_hw_unit15_page(void); -GtkWidget *build_hw_unit15_exercise_page(void); -GtkWidget *build_hw_unit16_page(void); -GtkWidget *build_hw_unit16_exercise_page(void); -GtkWidget *build_hw_unit17_page(void); -GtkWidget *build_hw_unit17_exercise_page(void); -GtkWidget *build_hw_unit18_page(void); -GtkWidget *build_hw_unit18_exercise_page(void); -GtkWidget *build_hw_unit19_page(void); -GtkWidget *build_hw_unit19_exercise_page(void); -GtkWidget *build_hw_unit20_page(void); -GtkWidget *build_hw_unit20_exercise_page(void); -GtkWidget *build_hw_unit21_page(void); -GtkWidget *build_hw_unit21_exercise_page(void); -GtkWidget *build_hw_unit22_page(void); -GtkWidget *build_hw_unit22_exercise_page(void); -GtkWidget *build_hw_unit23_page(void); -GtkWidget *build_hw_unit23_exercise_page(void); -GtkWidget *build_hw_unit24_page(void); -GtkWidget *build_hw_unit24_exercise_page(void); -GtkWidget *build_hw_unit25_page(void); -GtkWidget *build_hw_unit25_exercise_page(void); -GtkWidget *build_hw_unit26_page(void); -GtkWidget *build_hw_unit26_exercise_page(void); -GtkWidget *build_hw_unit27_page(void); -GtkWidget *build_hw_unit27_exercise_page(void); -GtkWidget *build_hw_unit28_page(void); -GtkWidget *build_hw_unit28_exercise_page(void); -GtkWidget *build_hw_unit29_page(void); -GtkWidget *build_hw_unit29_exercise_page(void); -void draw_chip_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_civics_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_science_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_math_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_physics_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_uk_flag(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_book_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_book_badge_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_quiz_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_order_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_globe_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_people_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void draw_bulb_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void net_lesson_notes_ensure(NetLesson *L); -void net_rescale_lesson_notes(NetLesson *L, int body, int head, int kick); -GtkWidget *make_back_button(const char *target); -void show_page(const char *name, int motion); -void on_nav_clicked(GtkButton *button, gpointer user_data); -int unit_done_count(const UnitCtx *u); -void progress_for_units(int first, int n, ProgressSum *out); -void refresh_stats_ui(void); -void on_stats_back_clicked(GtkButton *button, gpointer user_data); -void on_stats_clicked(GtkButton *button, gpointer user_data); -GtkWidget *stats_metric_card(const char *label_key, GtkWidget **value_out); -GtkWidget *make_unit_stats_row(UnitCtx *u, int num, int global); -GtkWidget *build_stats_page(void); -void on_nav_clicked(GtkButton *button, gpointer user_data); -void on_continue_clicked(GtkButton *button, gpointer user_data); -GtkWidget *make_back_button(const char *target); -GtkWidget *top_bar(const char *back_target, const char *title, - const char *subtitle); -gboolean on_window_key_pressed(GtkEventControllerKey *controller, - guint keyval, guint keycode, - GdkModifierType state, - gpointer user_data); -GtkWidget *build_welcome_page(void); -/* util.c */ -char *app_executable_path(void); -/* update.c */ -void update_init(void); -void update_check_async(gboolean interactive); -void update_clear_staging(void); -void update_apply_lang(void); -void update_on_settings_open(void); -GtkWidget *build_update_banner(void); -GtkWidget *build_update_box(void); -/* changelog.c */ -void changelog_set_seen(const char *sha); -const char *changelog_seen(void); -void changelog_apply_lang(void); -GtkWidget *build_changelog_card(void); -void draw_finish_cell(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void road_point(double t, double *ox, double *oy); -void road_path(cairo_t *cr, double t0, double t1); -void roadmap_geometry(double avail); -void road_apply_layout(void); -void road_relayout(void); -gboolean road_relayout_idle(gpointer data); -void road_relayout_later(void); -void road_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data); -void draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer user_data); -void add_path_node(GtkFixed *fixed, int index); -GtkWidget *build_roadmap_page(void); -void sub_layout_geometry(double avail); -void draw_sub_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer user_data); -void sub_apply_layout(void); -void sub_relayout(void); -gboolean sub_relayout_idle(gpointer data); -void sub_relayout_later(void); -void draw_german_flag(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -GtkWidget *build_subjects_page(void); -void ex_layout_geometry(UnitCtx *u, double avail); -void ex_point(UnitCtx *u, double t, double *ox, double *oy); -void ex_path(UnitCtx *u, cairo_t *cr, double t0, double t1); -void draw_ex_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer user_data); -void ex_apply_layout(UnitCtx *u); -void ex_relayout(UnitCtx *u); -gboolean ex_relayout_idle(gpointer data); -void ex_relayout_later(UnitCtx *u); -void ex_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data); -GtkWidget *make_bubble(UnitCtx *u, int n); -GtkWidget *build_unit_page(UnitCtx *u); -GtkWidget *ex_page_shell(const char *back_target, const char *title, - const char *subtitle, const char *btn_label, - GtkWidget **body_out, GtkWidget **feedback_out, - GtkWidget **btn_out); -GtkWidget *meaning_add(GtkWidget *body, const char *text); -GtkWidget *mcq_option_toggle(const char *text, int index, - GtkToggleButton **group_first); -GtkWidget *mcq_append_question(GtkWidget *parent, int num, const ChoiceQ *q, - GtkToggleButton **out_toggles); -GtkWidget *model_answer_add(GtkWidget *body, const char *german); -void meaning_reveal_all(GtkWidget **labels, int n); -ComboListCtx *combo_list_ctx_new(UnitCtx *unit, int ex_num, - GtkWidget *feedback); -void combo_list_add(ComboListCtx *ctx, GtkWidget *combo, const char *ans); -void combo_list_add_trans(ComboListCtx *ctx, GtkWidget *label); -GtkWidget *make_word_combo(const char **words, int n); -gboolean answer_accepts(const char *sel_norm, const char *ans); -gboolean answer_is_incomplete(const char *sel_norm, const char *ans); -void combo_list_check(GtkButton *button, gpointer data); -void sent_rebuild(SentBuilder *sb); -GdkContentProvider *asm_drag_prepare(GtkDragSource *source, - double x, double y, - gpointer data); -gboolean asm_rebuild_idle(gpointer data); -void asm_drag_end(GtkDragSource *source, GdkDrag *drag, - gboolean delete_data, gpointer data); -gboolean asm_drop_to_sentence(GtkDropTarget *target, const GValue *value, - double x, double y, gpointer data); -gboolean asm_drop_to_pool(GtkDropTarget *target, const GValue *value, - double x, double y, gpointer data); -void asm_finish_fly(FlyCtx *fc); -gboolean asm_fly_tick(gpointer data); -void asm_begin_fly(GtkWidget *chip, GtkWidget *stage, - gboolean *flying, double sx, double sy); -void asm_move_by_click(GtkButton *button, gpointer data); -void assembly_check(GtkButton *button, gpointer data); -GtkWidget *build_assembly(UnitCtx *unit, const char *title, - const char *subtitle, int ex_num, - const AssemblyItem *items, - const char **meanings, int n); -GtkWidget *build_ex1(UnitCtx *unit); -void choice_check(GtkButton *button, gpointer data); -GtkWidget *build_choice(UnitCtx *unit, const char *title, - const char *subtitle, int ex_num, - const ChoiceQ *qs, const char **meanings, int n); -void ex4_fill_sample(GtkWidget *label); -void ex4_reveal(GtkButton *button, gpointer data); -void ex4_finish(GtkButton *button, gpointer data); -GtkWidget *build_free_answer(UnitCtx *unit, int ex_num, const char *title, - const char *subtitle, const char *tip_key, - const FreeQ *qs, int n); -GtkWidget *build_ex4(UnitCtx *unit); -GtkWidget *build_ex5(UnitCtx *unit); -GtkWidget *build_ex6(UnitCtx *unit); -GtkWidget *build_ex7(UnitCtx *unit); -char *verbq_german(const char *before, const char *answer, - const char *after); -GtkWidget *build_ex8(UnitCtx *unit); -GtkWidget *build_ex12(UnitCtx *unit); -GtkWidget *build_translate(UnitCtx *unit); -void assign_rebuild(AssignCtx *ac); -void assign_chip_clicked(GtkButton *button, gpointer data); -void assign_group_toggled(GtkToggleButton *button, gpointer data); -void assign_check(GtkButton *button, gpointer data); -GtkWidget *build_assign(UnitCtx *unit, const char *title, - const char *subtitle, int ex_num, - const AssignItem *items, int n_items, - const char **group_labels, int n_groups, - const char **meanings); -void verb_rows_add(ComboListCtx *ctx, GtkWidget *body, int *counter, - const VerbQ *qs, int n, - const char **pool, int pool_n, - const char **meanings, gboolean pre_meaning); -void verb_note_reveal(VerbNoteCtx *nc); -void verb_ex_check(GtkButton *button, gpointer data); -GtkWidget *build_verb_ex(UnitCtx *unit, int ex_num, - const char *title, const char *sub, - const VerbQ *qs, int n, - const char **pool, int pool_n, - const char **meanings, gboolean pre_meaning, - const char **gloss); -void typed_check(GtkButton *button, gpointer data); -char *typed_answer_display(const char *answers); -void typed_note_reveal(TypedNoteCtx *nc); -void typed_ex_check(GtkButton *button, gpointer data); -GtkWidget *build_typed(UnitCtx *unit, int ex_num, - const char *title, const char *sub, - const TypedQ *qs, int n, - const char *word_bank, gboolean answers_note); -void s01_fill_sample(GtkWidget *label); -void s01_reveal(GtkButton *button, gpointer data); -void s01_finish(GtkButton *button, gpointer data); -GtkWidget *build_profile(UnitCtx *unit, int ex_num, const char *title, - const char *sub, const ProfileQ *qs, int n); -int hm_char_index(gunichar ch); -void hm_update_slots(HangmanCtx *hm); -gboolean hm_word_solved(HangmanCtx *hm); -void hm_set_letters_enabled(HangmanCtx *hm, gboolean enabled); -void hm_redraw(HangmanCtx *hm); -void hm_clear_feedback(HangmanCtx *hm); -gboolean hm_advance(gpointer data); -void hm_reset_word(gpointer data); -gboolean hm_retry_word(gpointer data); -void hm_guess_letter(GtkButton *button, gpointer data); -void draw_hangman(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -GtkWidget *build_hangman(UnitCtx *unit, int ex_num, const char *title, - const char *sub); -GtkWidget *u2ex1(UnitCtx *unit); -GtkWidget *u2ex2(UnitCtx *unit); -GtkWidget *u2ex3(UnitCtx *unit); -GtkWidget *u2ex4(UnitCtx *unit); -GtkWidget *u2ex5(UnitCtx *unit); -GtkWidget *u2ex6(UnitCtx *unit); -GtkWidget *u2ex7(UnitCtx *unit); -GtkWidget *u2ex8(UnitCtx *unit); -GtkWidget *u2ex9(UnitCtx *unit); -GtkWidget *u2ex10(UnitCtx *unit); -GtkWidget *u2ex11(UnitCtx *unit); -GtkWidget *u2ex12(UnitCtx *unit); -GtkWidget *u2ex13(UnitCtx *unit); -GtkWidget *u2ex14(UnitCtx *unit); -GtkWidget *u2ex15(UnitCtx *unit); -GtkWidget *u2ex16(UnitCtx *unit); -GtkWidget *u2ex17(UnitCtx *unit); -GtkWidget *u2ex18(UnitCtx *unit); -GtkWidget *u2ex19(UnitCtx *unit); -char *u3_fill_sentence(const U3Fill *f); -void u3_fill_row(ComboListCtx *ctx, GtkWidget *body, const U3Fill *f, - const char **pool, int pool_n, const char *gloss); -void u3_sample_line(GtkWidget *body, const char *text); -GtkWidget *u3_build_drop(UnitCtx *unit, int ex_num, const char *title, - const char *sub, const char *sample, - const U3Fill *rows, int n, - const char **pool, int pool_n, - const char **glosses, gboolean show_german); -GtkWidget *u3ex1(UnitCtx *unit); -const char *ex2_word_cs(const char *w); -void ex2_check(GtkButton *button, gpointer data); -GtkWidget *u3ex2(UnitCtx *unit); -GtkWidget *u3ex3(UnitCtx *unit); -U3LetCtx *u3_let_ctx_new(UnitCtx *unit, int ex_num, - GtkWidget *feedback); -char *u3_let_sentence(const U3Let *row); -void u3_let_check(GtkButton *button, gpointer data); -void u3_let_row(U3LetCtx *ctx, GtkWidget *body, const U3Let *row); -GtkWidget *u3_build_letters(UnitCtx *unit, int ex_num, - const char *title, const char *sub, - const U3Let *rows, int n); -void ex4_check(GtkButton *button, gpointer data); -GtkWidget *u3ex4(UnitCtx *unit); -GtkWidget *u3ex5(UnitCtx *unit); -GtkWidget *u3ex6(UnitCtx *unit); -void u3_table_check(GtkButton *button, gpointer data); -GtkWidget *u3ex7(UnitCtx *unit); -GtkWidget *u3ex8(UnitCtx *unit); -GtkWidget *u3ex9(UnitCtx *unit); -GtkWidget *u3ex10(UnitCtx *unit); -void u3_kw_check(GtkButton *button, gpointer data); -GtkWidget *u3_build_kw(UnitCtx *unit, int ex_num, const char *title, - const char *sub, const char *sample, - const U3Kw *qs, int n); -GtkWidget *u3ex11(UnitCtx *unit); -GtkWidget *u3ex12(UnitCtx *unit); -GtkWidget *u3ex13(UnitCtx *unit); -GtkWidget *u3ex14(UnitCtx *unit); -GtkWidget *u3ex15(UnitCtx *unit); -void draw_theme_swatch(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void on_mode_toggled(GtkToggleButton *btn, gpointer user_data); -void on_theme_toggled(GtkToggleButton *btn, gpointer user_data); -void on_lang_toggled(GtkToggleButton *btn, gpointer user_data); -GtkWidget *make_lang_chip(const char *label, UiLang lang, - GtkToggleButton *group); -GtkWidget *make_mode_chip(const char *label, ColorMode mode, - GtkToggleButton *group); -GtkWidget *make_theme_card(ThemeId id, GtkToggleButton *group); -void on_settings_clicked(GtkButton *button, gpointer user_data); -GtkWidget *build_stats_button(void); -GtkWidget *build_search_button(void); -GtkWidget *build_settings_button(void); -void search_attach(GtkOverlay *overlay); -void search_open(void); -void search_close(void); -gboolean search_is_open(void); -void search_apply_lang(void); -void settings_open(void); -void unit_meta_init(void); -void unit_configure(int idx, const char *const *names, int n); -GtkWidget *build_exercise_page(UnitCtx *u, int n); -void net_paragraph(GtkWidget *box, const char *text); -void net_heading(GtkWidget *box, const char *text); -void net_note_font(GtkWidget *l, int px); -void net_rescale_notes_at(int w); -void net_rescale_notes(void); -gboolean net_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data); -GtkWidget *net_slide_card(const char *cls); -void net_note_kicker(GtkWidget *box, const char *text); -void net_note_title(GtkWidget *box, const char *text); -void net_note_line(GtkWidget *box, const char *text, gboolean tip); -void net_slide_apply(NetLesson *L); -void net_lessons_apply_lang(void); -void net_open_unit(GtkButton *button, gpointer data); -void net_slide_prev(GtkButton *button, gpointer data); -void net_slide_next(GtkButton *button, gpointer data); -void net_point(double t, double *ox, double *oy); -void net_path(cairo_t *cr, double t0, double t1); -void net_geometry(double avail); -void net_apply_layout(void); -void net_relayout(void); -gboolean net_relayout_idle(gpointer data); -void net_relayout_later(void); -void net_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data); -void net_render_rail_to(cairo_t *cr); -void net_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data); -void net_rail_theme_reset(void); -void net_add_node(GtkFixed *fixed, int index); -GtkWidget *build_netmap_page(void); -GtkWidget *build_netyears_page(void); -GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides); -GtkWidget *build_net_unit1_page(void); -GtkWidget *build_net_unit2_page(void); -GtkWidget *build_net_unit3_page(void); -GtkWidget *build_net_unit4_page(void); -GtkWidget *build_net_unit5_page(void); -GtkWidget *build_net_unit6_page(void); -GtkWidget *build_net_unit7_page(void); -GtkWidget *build_net_unit8_page(void); -GtkWidget *build_net_unit9_page(void); -GtkWidget *build_net_unit10_page(void); -GtkWidget *build_net_unit11_page(void); -GtkWidget *build_net_unit12_page(void); -GtkWidget *build_net_unit13_page(void); -GtkWidget *build_net_unit14_page(void); -GtkWidget *build_net_unit15_page(void); -GtkWidget *build_net_unit16_page(void); -GtkWidget *build_net_unit17_page(void); -GtkWidget *build_net_unit18_page(void); -GtkWidget *build_net_unit19_page(void); -GtkWidget *build_net_unit20_page(void); -GtkWidget *build_net_unit21_page(void); -GtkWidget *build_net_unit22_page(void); -GtkWidget *build_net_unit23_page(void); -GtkWidget *build_net_unit24_page(void); -GtkWidget *build_net_unit25_page(void); -GtkWidget *build_net_unit26_page(void); -GtkWidget *build_net_unit27_page(void); -GtkWidget *net_qz_combo(void); -void net_qz_set_prefix(GtkComboBoxText *c, int pfx); -int net_qz_prefix(GtkComboBoxText *c); -gboolean net_txt_eq(const char *a, const char *b); -gboolean net_qz_entry_ok(GtkWidget *entry, const char *want); -void net_qz_check(GtkButton *button, gpointer data); -void net_qz_fill(GtkButton *button, gpointer data); -void net_qz_header(GtkWidget *box, const char *text); -GtkWidget *net_qz_make_entry(void); -GtkWidget *build_net_exercise_page(void); -void net_mcq_check(GtkButton *button, gpointer data); -GtkWidget *build_net_mcq_page(int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n); -GtkWidget *build_net_unit2_exercise_page(void); -GtkWidget *build_net_unit3_exercise_page(void); -GtkWidget *build_net_unit4_exercise_page(void); -GtkWidget *build_net_unit5_exercise_page(void); -GtkWidget *build_net_unit6_exercise_page(void); -GtkWidget *build_net_unit7_exercise_page(void); -GtkWidget *build_net_unit8_exercise_page(void); -GtkWidget *build_net_unit9_exercise_page(void); -GtkWidget *build_net_unit10_exercise_page(void); -GtkWidget *build_net_unit11_exercise_page(void); -GtkWidget *build_net_unit12_exercise_page(void); -GtkWidget *build_net_unit13_exercise_page(void); -GtkWidget *build_net_unit14_exercise_page(void); -GtkWidget *build_net_unit15_exercise_page(void); -GtkWidget *build_net_unit16_exercise_page(void); -GtkWidget *build_net_unit17_exercise_page(void); -GtkWidget *build_net_unit18_exercise_page(void); -GtkWidget *build_net_unit19_exercise_page(void); -GtkWidget *build_net_unit20_exercise_page(void); -GtkWidget *build_net_unit21_exercise_page(void); -GtkWidget *build_net_unit22_exercise_page(void); -GtkWidget *build_net_unit23_exercise_page(void); -GtkWidget *build_net_unit24_exercise_page(void); -GtkWidget *build_net_unit25_exercise_page(void); -GtkWidget *build_net_unit26_exercise_page(void); -GtkWidget *build_net_unit27_exercise_page(void); -void macos_set_dock_icon(const char *path); -void activate(GtkApplication *app, gpointer user_data); -int main(int argc, char **argv); - -#endif /* GRADUATELY_H */ diff --git a/src/hw.c b/src/hw.c deleted file mode 100644 index 24ee850..0000000 --- a/src/hw.c +++ /dev/null @@ -1,3020 +0,0 @@ -#include "graduately.h" - -/* ---- Technical equipment (Technické vybavení) --------------------- */ - -NetLesson hw_lessons[HW_LESSONS] = { - { .n_slides = HW_SLIDES, .unit_page = "hwunit1", .ex_page = "hwex1" }, - { .n_slides = HW2_SLIDES, .unit_page = "hwunit2", .ex_page = "hwex2" }, - { .n_slides = HW3_SLIDES, .unit_page = "hwunit3", .ex_page = "hwex3" }, - { .n_slides = HW4_SLIDES, .unit_page = "hwunit4", .ex_page = "hwex4" }, - { .n_slides = HW5_SLIDES, .unit_page = "hwunit5", .ex_page = "hwex5" }, - { .n_slides = HW6_SLIDES, .unit_page = "hwunit6", .ex_page = "hwex6" }, - { .n_slides = HW7_SLIDES, .unit_page = "hwunit7", .ex_page = "hwex7" }, - { .n_slides = HW8_SLIDES, .unit_page = "hwunit8", .ex_page = "hwex8" }, - { .n_slides = HW9_SLIDES, .unit_page = "hwunit9", .ex_page = "hwex9" }, -#define HW_ENTRY(n) { .n_slides = 2, .unit_page = "hwunit" #n, .ex_page = "hwex" #n } - HW_ENTRY(10), HW_ENTRY(11), HW_ENTRY(12), HW_ENTRY(13), HW_ENTRY(14), - HW_ENTRY(15), HW_ENTRY(16), HW_ENTRY(17), HW_ENTRY(18), HW_ENTRY(19), - HW_ENTRY(20), HW_ENTRY(21), HW_ENTRY(22), HW_ENTRY(23), HW_ENTRY(24), - HW_ENTRY(25), HW_ENTRY(26), HW_ENTRY(27), HW_ENTRY(28), HW_ENTRY(29), -#undef HW_ENTRY -}; - -void hw_rail_theme_reset(void); -void refresh_hw_completion_ui(void); - -GtkWidget *hw_scroll; -GtkWidget *hw_fixed; -GtkWidget *hw_rail; -GtkWidget *hw_nodes[HW_UNITS]; -GtkWidget *hw_labels[HW_UNITS]; -double hw_cx[HW_UNITS]; -double hw_cy[HW_UNITS]; -int hw_cols = 1; -int hw_rows = 1; -int hw_cw = (int)(2.0 * ROAD_MX + (HW_UNITS - 1) * PATH_SPAC); -int hw_ch = (int)(2.0 * ROAD_MY); -guint hw_idle; -double hw_last_avail = -1.0; -int hw_last_cols = -1; -int hw_last_rows = -1; -int hw_last_cw = -1; -int hw_last_ch = -1; -cairo_surface_t *hw_rail_cache; -int hw_cache_w; -int hw_cache_h; - -void hw_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= HW_UNITS - 1) { k = HW_UNITS - 2; u = 1.0; } - - p1x = hw_cx[k]; p1y = hw_cy[k]; - p2x = hw_cx[k + 1]; p2y = hw_cy[k + 1]; - if (k - 1 >= 0) { p0x = hw_cx[k - 1]; p0y = hw_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < HW_UNITS) { p3x = hw_cx[k + 2]; p3y = hw_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -void hw_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 24.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - hw_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - hw_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -void hw_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(HW_UNITS - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= HW_UNITS; rows++) { - int cols = (HW_UNITS + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > HW_UNITS) - rows = HW_UNITS; - hw_rows = rows; - hw_cols = (HW_UNITS + rows - 1) / rows; - if (hw_cols < 1) - hw_cols = 1; - hw_cw = (int)(2.0 * ROAD_MX + (hw_cols - 1) * PATH_SPAC); - hw_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * hw_cols; - int len = MIN(hw_cols, HW_UNITS - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (hw_cols - 1 - c); - hw_cx[i] = ROAD_MX + cc * PATH_SPAC; - hw_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -void hw_apply_layout(void) { - if (!hw_fixed) - return; - - if (hw_cols == hw_last_cols && hw_rows == hw_last_rows && - hw_cw == hw_last_cw && hw_ch == hw_last_ch) - return; - - hw_last_cols = hw_cols; - hw_last_rows = hw_rows; - hw_last_cw = hw_cw; - hw_last_ch = hw_ch; - if (hw_rail_cache) { - cairo_surface_destroy(hw_rail_cache); - hw_rail_cache = NULL; - } - - for (int i = 0; i < HW_UNITS; i++) { - if (!hw_nodes[i] || !hw_labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(hw_fixed), hw_nodes[i], - (int)(hw_cx[i] - NODE_SIZE / 2.0), - (int)(hw_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(hw_fixed), hw_labels[i], - (int)(hw_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(hw_cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(hw_fixed, hw_cw, hw_ch); - gtk_widget_set_size_request(hw_rail, hw_cw, hw_ch); - gtk_fixed_move(GTK_FIXED(hw_fixed), hw_rail, 0, 0); - gtk_widget_queue_draw(hw_rail); -} - -void hw_relayout(void) { - GtkAdjustment *hadj; - double avail; - - if (!hw_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(hw_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - hw_last_avail) < 1.0) - return; - hw_last_avail = avail; - hw_geometry(avail); - hw_apply_layout(); -} - -gboolean hw_relayout_idle(gpointer data) { - (void)data; - hw_idle = 0; - hw_relayout(); - return G_SOURCE_REMOVE; -} - -void hw_relayout_later(void) { - if (hw_idle == 0) - hw_idle = g_idle_add(hw_relayout_idle, NULL); -} - -void hw_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - (void)data; - hw_relayout_later(); -} - -void hw_render_rail_to(cairo_t *cr) { - const double t_end = (double)(HW_UNITS - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - hw_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - hw_path(cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -void hw_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - (void)area; - (void)width; - (void)height; - (void)data; - - if (!hw_rail_cache || hw_cache_w != hw_cw || hw_cache_h != hw_ch) { - cairo_t *rcr; - - if (hw_rail_cache) - cairo_surface_destroy(hw_rail_cache); - hw_cache_w = hw_cw; - hw_cache_h = hw_ch; - if (hw_cache_w < 1) - hw_cache_w = 1; - if (hw_cache_h < 1) - hw_cache_h = 1; - hw_rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - hw_cache_w, hw_cache_h); - rcr = cairo_create(hw_rail_cache); - hw_render_rail_to(rcr); - cairo_destroy(rcr); - } - - cairo_set_source_surface(cr, hw_rail_cache, 0, 0); - cairo_paint(cr); -} - -void hw_rail_theme_reset(void) { - if (hw_rail_cache) { - cairo_surface_destroy(hw_rail_cache); - hw_rail_cache = NULL; - } - if (hw_rail) - gtk_widget_queue_draw(hw_rail); -} - -void hw_add_node(GtkFixed *fixed, int index) { - int num = index + 1; - gboolean locked = index >= HW_LESSONS; - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - static char unit_keys[HW_LESSONS][16]; - static gboolean unit_keys_ready = FALSE; - - if (!unit_keys_ready) { - for (int i = 0; i < HW_LESSONS; i++) - g_snprintf(unit_keys[i], sizeof unit_keys[i], "hw_unit%d", i + 1); - unit_keys_ready = TRUE; - } - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_sensitive(card, !locked); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - if (locked) - gtk_widget_add_css_class(card, "locked"); - else - gtk_widget_add_css_class(card, "current"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", num); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - if (locked) { - icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 16); - gtk_box_append(GTK_BOX(vbox), icon); - } else { - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - hw_lessons[index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(net_open_unit), - &hw_lessons[index]); - } - - hw_nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - if (index < HW_LESSONS) { - i18n_bind(name, unit_keys[index], 0); - } else { - gtk_widget_add_css_class(name, "unit-name-locked"); - } - hw_labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} - -static GtkWidget *hw_year_button(int year, gboolean locked) { - static const char *year_keys[] = { - "hw_year1", "hw_year2", "hw_year3", "hw_year4", - }; - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 72); - gtk_widget_set_sensitive(btn, !locked); - if (locked) - gtk_widget_add_css_class(btn, "locked"); - else - gtk_widget_add_css_class(btn, "current"); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", year); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, year_keys[year - 1], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - if (locked) { - GtkWidget *sub = gtk_label_new(NULL); - GtkWidget *icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, - 0.4392, 18); - - i18n_bind(sub, "hw_year_locked_sub", 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_widget_add_css_class(sub, "unit-name-locked"); - gtk_box_append(GTK_BOX(texts), sub); - gtk_widget_set_valign(icon, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), icon); - } else { - static const char *pages[] = { - "hwmap", "hw2map", "hw3map", "hw4map", - }; - static const char *subs[] = { - "hw_sub", "hw2_sub", "hw3_sub", "hw4_sub", - }; - GtkWidget *sub = gtk_label_new(NULL); - - i18n_bind(sub, subs[year - 1], 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_widget_add_css_class(sub, "quiz-intro"); - gtk_box_append(GTK_BOX(texts), sub); - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(pages[year - 1]), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - } - - return btn; -} - -GtkWidget *build_hwyears_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - int y; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "Technické vybavení", "hw_years_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 360, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (y = 1; y <= 4; y++) - gtk_box_append(GTK_BOX(list), hw_year_button(y, FALSE)); - - return page; -} - -GtkWidget *build_hwmap_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - - hw_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("hwyears", "hw_year1", "hw_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - hw_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, hw_cw, hw_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - hw_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, hw_cw, hw_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), hw_draw_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - hw_rail = rail; - - for (int i = 0; i < HW_UNITS; i++) - hw_add_node(GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(hw_adjust_notify), NULL); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(hw_adjust_notify), NULL); - - hw_apply_layout(); - hw_relayout_later(); - refresh_hw_completion_ui(); - - return page; -} - - -void hw_slide_apply(NetLesson *L); -void hw_slide_prev(GtkButton *button, gpointer data); -void hw_slide_next(GtkButton *button, gpointer data); - -/* ---- Unit 1: Architektura počítače -------------------------------- */ - -static GtkWidget *hw_note_host; -static int hw_note_last_w = -1; - -static void hw_rescale_notes_at(int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < HW_LESSONS; i++) - net_rescale_lesson_notes(&hw_lessons[i], body, head, kick); -} - -static gboolean hw_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width != hw_note_last_w) { - hw_note_last_w = width; - hw_rescale_notes_at(width); - } - return G_SOURCE_CONTINUE; -} - -static GtkWidget *build_hw_unit_page(NetLesson *L, const char *title_key, - const char *sub_key, - const NetSlide *slides, guint n_slides) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar("hwmap", title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - hw_note_host = L->stack; - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "hw_slide%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, hw_note_tick, NULL, NULL); - hw_note_last_w = -1; - hw_rescale_notes_at(0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(hw_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(hw_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - hw_slide_apply(L); - return page; -} - -void hw_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "hw_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -void hw_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx > 0) { - L->idx--; - hw_slide_apply(L); - } -} - -void hw_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - hw_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -void hw_lessons_apply_lang(void) { - for (int i = 0; i < HW_LESSONS; i++) - hw_slide_apply(&hw_lessons[i]); -} - -GtkWidget *build_hw_unit1_page(void) { - static const NetSlide slides[HW_SLIDES] = { - { - "1 / 3 • Úvod", "Architektura počítače", - "Architektura popisuje, z jakých částí se počítač skládá " - "a jak spolu spolupracují.", - { - "Architektura počítače je základní model, podle kterého " - "jsou počítače navrhovány.", - "Nejznámější model je Von Neumannovo schéma.", - "Používá se dodnes u většiny běžných počítačů.", - NULL, - }, - }, - { - "2 / 3 • Osobnost", "John von Neumann", - "Tip: zapamatuj si jméno – podle něj se jmenuje celé schéma.", - { - "John von Neumann byl americký matematik.", - "Pracoval na poli digitálních počítačů a operační teorie " - "kvantové mechaniky.", - "Je autorem Von Neumannovy algebry.", - "Byl tvůrcem teorie her.", - "Podílel se na vývoji atomové a vodíkové bomby.", - NULL, - }, - }, - { - "3 / 3 • Schéma", "Von Neumannovo schéma", - "ALU = aritmeticko-logická jednotka", - { - "Von Neumannovo schéma má pět hlavních částí:", - "ALU – aritmeticko-logická jednotka (výpočty a logika)", - "Řadič – řídí činnost ostatních částí", - "Operační paměť – uchovává program i data", - "Vstupní jednotka – přivádí data do počítače", - "Výstupní jednotka – předává výsledky ven", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[0], "hw_unit1", "hw_unit1_sub", - slides, HW_SLIDES); -} - -/* ---- Quiz --------------------------------------------------------- */ - -static void hw_mcq_check(GtkButton *button, gpointer data) { - NetMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_hw_done(ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -static GtkWidget *build_hw_mcq_page(int lesson_id, const char *back_page, - const char *title_key, - const char *heading_key, - const ChoiceQ *qs, const char **hints, - int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - NetMcqCtx *ctx = g_new0(NetMcqCtx, 1); - int n_opts = qs[0].n_options; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(hw_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - - return page; -} - -GtkWidget *build_hw_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je autorem Von Neumannova schématu?", - {"Alan Turing", "John von Neumann", "Bill Gates", "Steve Jobs"}, - 4, 1}, - {"Čím byl John von Neumann?", - {"Americký matematik", "Německý fyzik", "Anglický chemik", - "Francouzský lékař"}, - 4, 0}, - {"Co znamená zkratka ALU?", - {"Automatická logická síť", "Aritmeticko-logická jednotka", - "Analogová linková sestava", "Adresová listová sekce"}, - 4, 1}, - {"Která část Von Neumannova schématu řídí ostatní části?", - {"Operační paměť", "Vstupní jednotka", "Řadič", "Výstupní jednotka"}, - 4, 2}, - {"Kde se podle Von Neumannova schématu uchovává program i data?", - {"Jen na pevném disku", "V operační paměti", "Jen ve vstupní jednotce", - "Jen v ALU"}, - 4, 1}, - {"Čím se John von Neumann také zabýval?", - {"Jen malířstvím", "Teorií her", "Jen botanikou", "Jen hudbou"}, - 4, 1}, - }; - static const char *hints[] = { - "John von Neumann – americký matematik", - "Americký matematik s objevy v digitálních počítačích", - "ALU = aritmeticko-logická jednotka", - "Řadič řídí činnost ostatních částí", - "Operační paměť uchovává program i data", - "Byl tvůrcem teorie her", - }; - return build_hw_mcq_page(0, "hwunit1", "hw_ex1_title", "hw_quiz1_head", - qs, hints, 6); -} - -GtkWidget *build_hw_unit2_page(void) { - static const NetSlide slides[HW2_SLIDES] = { - { - "1 / 6 • Přehled", "Historie počítačů", - "Generace se dělí podle součástky, která v té době počítala: relé, elektronka, tranzistor, integrovaný obvod a nakonec mikroprocesor.", - { - "Předchůdci do 19. století jsou mechanické pomůcky. Pascaline sčítala ozubenými koly, Babbage navrhl analytický stroj a Ada Lovelace k němu popsala postup výpočtu. Elektronika ještě chyběla.", - "Nultá generace, zhruba 1938–1944, spíná elektromagnetická relé. Stroje jsou kusové a často vojenské.", - "První generace, 1944–1955, bere elektronku. Počítač zabere sál a program se dává děrnými štítky.", - "Druhá generace, 1955–1964, nahrazuje elektronku tranzistorem. Objevují se vyšší programovací jazyky.", - "Třetí generace, 1964–1971, staví na integrovaném obvodu. Vznikají rodiny počítačů a operační systémy.", - "Čtvrtá generace od roku 1971 staví na mikroprocesoru. Počítač se vejde na stůl a později do kapsy.", - NULL, - }, - }, - { - "2 / 6 • 0. generace", "Počítače 0. generace (1938–1944)", - "Tip: počítačů byly jednotky kusů a často sloužily armádě. Základem je relé, ne elektronka.", - { - "Relé je elektromagnetický spínač. Je pomalejší a hlučnější než pozdější elektronka, ale umí už skládat logické obvody.", - "Konrad Zuse dokončil v roce 1941 Z3: programovatelný binární stroj s plovoucí řádovou čárkou.", - "Harvard Mark I (1944) byl elektromechanický a počítal balistické tabulky pro americkou armádu.", - "Každý stroj se stavěl na zakázku. Obsluhoval ho tým, ne jeden člověk u stolu.", - "Program býval na děrné pásce nebo na přepínačích, ne v dnešní operační paměti.", - "Typická práce byla vojenská: šifry a tabulky střelby, ne kancelář nebo domácnost.", - NULL, - }, - }, - { - "3 / 6 • 1. generace", "Počítače 1. generace (1944–1955)", - "Klíčový objev je elektronka. Spíná rychleji než relé, ale hřeje, často se pálí a počítač kvůli ní zabere celý sál.", - { - "ENIAC (1945) měl kolem 18 tisíc elektronek a počítal hlavně balistiku.", - "Von Neumannova architektura ukládá program i data do stejné paměti. Na tom stojí i dnešní počítače.", - "UNIVAC I (1951) byl první sériově prodávaný komerční počítač v USA.", - "Program a data se děrovaly do štítků. Operátor vložil balík a čekal na výsledek.", - "Operační systém ani vyšší jazyk ještě nebyl. Psalo se ve strojovém kódu.", - "Sál potřeboval klimatizaci a stálý dohled. Do domácnosti se takový stroj nevešel.", - NULL, - }, - }, - { - "4 / 6 • 2. generace", "Počítače 2. generace (1955–1964)", - "Klíčový objev je tranzistor. V Bellových laboratořích vznikl roku 1947 a do počítačů se dostal zhruba od roku 1955.", - { - "Tranzistor nahradí elektronku: je menší, spolehlivější a méně se hřeje.", - "Stroj už nemusí zabírat celý sál, pořád je to ale zařízení pro firmu nebo ústav.", - "Vnitřní paměť bývá feritová. Vnější paměť jsou magnetické pásky a bubny.", - "FORTRAN (1957) a COBOL (1959) dovolí psát program blíž lidské řeči než strojový kód.", - "Úlohy se zpracovávají dávkově. Operátor seřadí balíky a počítač je jede postupně.", - "Typické stroje této doby jsou IBM 1401 a IBM 7090.", - NULL, - }, - }, - { - "5 / 6 • 3. generace", "Počítače 3. generace (1964–1971)", - "Klíčový objev je integrovaný obvod: mnoho tranzistorů na jednom křemíkovém čipu. Kilby a Noyce ho představili na konci 50. let.", - { - "IBM System/360 (1964) je rodina počítačů se stejným instrukčním souborem. Program z menšího modelu běží i na větším.", - "Operační systém už řídí více úloh a periferie. Objevuje se sdílení času mezi uživateli.", - "Magnetický disk doplňuje pásku a zkracuje čekání na data.", - "Minipočítače jako PDP-8 se vejdou do jedné skříně. Kupují je laboratoře a firmy, ne jen stát.", - "Stroj je menší a levnější než sál první generace, pořád to ale není osobní počítač na stůl.", - "Hlavní vnější pamětí zůstává magnetické médium, ne děrný štítek.", - NULL, - }, - }, - { - "6 / 6 • 4. generace", "Počítače 4. generace", - "Klíčová součástka je programovatelný mikroprocesor: celý procesor na jednom čipu.", - { - "Intel 4004 z roku 1971 je první komerční mikroprocesor. Pozdější čipy z něj udělaly mozek osobního počítače.", - "Na stůl se počítač dostává postupně: Altair 1975, Apple II 1977 a IBM PC 1981.", - "Roku 1972 vychází Pong, první komerčně úspěšná arkádová hra. Lekce ji bere jako první počítačovou hru.", - "Roku 1971 představuje IBM osmipalcovou disketu. Menší formáty přišly až v dalších letech.", - "Roku 1979 Philips a Sony předvádějí kompaktní disk. V obchodech je od roku 1982.", - "Paměti a disky rostou, takže počítač opouští sál a později se vejde i do kapsy.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[1], "hw_unit2", "hw_unit2_sub", - slides, HW2_SLIDES); -} - -GtkWidget *build_hw_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy probíhala nultá generace počítačů?", - {"1938–1944", "1944–1955", "1955–1964", "1964–1971"}, 4, 0}, - {"Co bylo typické pro počítače 0. generace?", - {"Byly v každé domácnosti", "Jen několik kusů, často vojenský účel", - "Měly mikroprocesory", "Používaly CD"}, - 4, 1}, - {"Která technologie patří k 1. generaci?", - {"Tranzistor", "Elektronka", "Integrovaný obvod", "Mikroprocesor"}, - 4, 1}, - {"Čím se zadávaly data v 1. generaci?", - {"USB fleškou", "Děrnými štítky", "CD", "Disketou"}, 4, 1}, - {"Která technologie patří k 2. generaci?", - {"Elektronka", "Tranzistor", "Mikroprocesor", "CD"}, 4, 1}, - {"Která technologie patří k 3. generaci?", - {"Elektronka", "Tranzistor", "Integrovaný obvod", "Disketa"}, - 4, 2}, - {"Co je typické pro 4. generaci?", - {"Jen děrné štítky", "Programovatelné mikroprocesory", - "Jen vojenské použití", "Žádný software"}, - 4, 1}, - {"Kdy vznikla první počítačová hra (podle lekce)?", - {"1964", "1972", "1973", "1979"}, 4, 1}, - }; - static const char *hints[] = { - "Nultá generace: 1938–1944", - "Jen několik počítačů, většinou vojenský účel", - "1. generace – objev elektronky", - "1. generace – děrné štítky", - "2. generace – objev tranzistoru", - "3. generace – integrovaný obvod", - "4. generace – programovatelné mikroprocesory", - "1972 – první počítačová hra", - }; - return build_hw_mcq_page(1, "hwunit2", "hw_ex2_title", "hw_quiz2_head", - qs, hints, 8); -} - -GtkWidget *build_hw_unit3_page(void) { - static const NetSlide slides[HW3_SLIDES] = { - { - "1 / 2 • Bit", "Bit – nejmenší jednotka informace", - "Bit = binary digit (dvojková číslice)", - { - "Bit je dvojková číslice – nabývá hodnoty 0 nebo 1.", - "Je to nejmenší zobrazitelná jednotka informace.", - "Z bitů se skládají větší jednotky (např. byte).", - NULL, - }, - }, - { - "2 / 2 • Byte", "Byte – adresovatelná jednotka paměti", - "Tip: 1 B = 8 b", - { - "Byte je nejmenší adresovatelná jednotka paměti.", - "Počítač tedy paměť adresuje po bytech, ne po jednotlivých " - "bitech.", - "Jeden byte obvykle obsahuje 8 bitů.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[2], "hw_unit3", "hw_unit3_sub", - slides, HW3_SLIDES); -} - -GtkWidget *build_hw_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je bit?", - {"Největší jednotka paměti", "Dvojková číslice – nejmenší jednotka " - "informace", "Jen klávesa na klávesnici", "Typ procesoru"}, - 4, 1}, - {"Jaké hodnoty může nabývat bit?", - {"Jen 0", "Jen 1", "0 nebo 1", "0 až 255"}, 4, 2}, - {"Co je byte?", - {"Nejmenší adresovatelná jednotka paměti", - "Nejmenší zobrazitelná jednotka informace", - "Jen síťový kabel", "Jen grafická karta"}, - 4, 0}, - {"Kolik bitů má obvykle jeden byte?", - {"2", "4", "8", "16"}, 4, 2}, - }; - static const char *hints[] = { - "Bit = dvojková číslice, nejmenší jednotka informace", - "Bit nabývá hodnoty 0 nebo 1", - "Byte = nejmenší adresovatelná jednotka paměti", - "1 B = 8 b", - }; - return build_hw_mcq_page(2, "hwunit3", "hw_ex3_title", "hw_quiz3_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit4_page(void) { - static const NetSlide slides[HW4_SLIDES] = { - { - "1 / 2 • Integer", "Proměnná typu integer (celá čísla)", - "Tip: n bitů → 2ⁿ různých hodnot (např. 0 až 2ⁿ − 1)", - { - "Celá čísla se ukládají binárně v pevné řádové čárce.", - "Mají pevný počet bitů – standardně 16 nebo 32 " - "(tedy 2 nebo 4 byty).", - "Při 16bitovém formátu je 2¹⁶ = 65 536 různých hodnot; " - "u nezáporných čísel interval 0 až 2¹⁶ − 1, tedy 0–65 535.", - "Obecně u n bitů je M = 2ⁿ různých hodnot " - "(u 16 bitů je nejvyšší nezáporné číslo 65 535).", - "Ostatní čísla se do tohoto intervalu převádějí transformací " - "(mapováním na přirozená čísla z daného rozsahu).", - NULL, - }, - }, - { - "2 / 2 • Real", "Proměnná typu real (desetinná čísla)", - "Tip: tvar = mantisa × základ^exponent", - { - "Desetinná čísla se ukládají v pohyblivé řádové čárce " - "ve tvaru mantisa a exponent.", - "Mantisa je normalizovaná tak, že první platná číslice " - "je hned za desetinnou čárkou.", - "Posun řádové čárky vyrovná odpovídající změna exponentu.", - "Standardně zabírá 4 nebo 8 bytů v paměti.", - "Více bytů se používá jen tehdy, když potřebujeme vyšší " - "přesnost výpočtů.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[3], "hw_unit4", "hw_unit4_sub", - slides, HW4_SLIDES); -} - -GtkWidget *build_hw_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se ukládají celá čísla (integer)?", - {"Jen jako text", - "Binárně v pevné řádové čárce s pevným počtem bitů", - "Jen jako obrázek", - "Jen v pohyblivé řádové čárce bez exponentu"}, - 4, 1}, - {"Kolik různých hodnot má 16bitový nezáporný integer?", - {"256", "1024", "65 536 (0 až 65 535)", "4"}, - 4, 2}, - {"Jak se ukládají desetinná čísla (real)?", - {"Jen jako celá čísla bez tečky", - "V pohyblivé řádové čárce jako mantisa a exponent", - "Jen jako 1 bit", - "Jen jako název souboru"}, - 4, 1}, - {"Co znamená normalizace mantisy?", - {"Že se číslo smaže", - "Že první platná číslice je hned za desetinnou čárkou " - "a exponent se upraví", - "Že se použije jen 1 bit", - "Že se číslo uloží jako text"}, - 4, 1}, - }; - static const char *hints[] = { - "Integer = pevná řádová čárka, pevný počet bitů (16/32…)", - "16 bitů → 2¹⁶ = 65 536 hodnot (0–65 535 u nezáporných)", - "Real = pohyblivá řádová čárka = mantisa + exponent", - "Normalizace: 1. platná číslice hned za desetinnou čárkou", - }; - return build_hw_mcq_page(3, "hwunit4", "hw_ex4_title", "hw_quiz4_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit5_page(void) { - static const NetSlide slides[HW5_SLIDES] = { - { - "1 / 2 • Signál", "Analogový a digitální zvuk", - "Tip: analog je spojitý, digitál je posloupnost čísel.", - { - "Analogový zvuk je spojitý signál – v každém okamžiku " - "má nějakou hodnotu.", - "Digitální zvuk je posloupnost čísel, která ten signál " - "popisují.", - "Z mikrofonu vychází analogové napětí, do reproduktoru " - "musí zase jít spojitý signál.", - "Počítač umí uložit jen čísla, proto se zvuk digitalizuje.", - NULL, - }, - }, - { - "2 / 2 • Převod", "A/D a D/A převodník", - "Tip: ADC dovnitř, DAC ven. Digitalizace = vzorkování + kvantování.", - { - "A/D převodník (ADC) převede analogový signál na čísla.", - "D/A převodník (DAC) z čísel znovu složí spojitý signál.", - "Digitalizace má dva kroky: vzorkování a kvantování.", - "Vzorkování určí, kdy se hodnota změří.", - "Kvantování určí, na kolik hladin se amplituda zaokrouhlí.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[4], "hw_unit5", "hw_unit5_sub", - slides, HW5_SLIDES); -} - -GtkWidget *build_hw_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je analogový zvuk?", - {"Posloupnost celých čísel", - "Spojitý signál s hodnotou v každém okamžiku", - "Jen název souboru WAV", - "Jen bit v paměti"}, - 4, 1}, - {"Co dělá A/D převodník (ADC)?", - {"Převádí analogový signál na čísla", - "Zesiluje jen reproduktor", - "Maže vysoké tóny po uložení", - "Počítá jen velikost souboru"}, - 4, 0}, - {"Jaké jsou dva hlavní kroky digitalizace zvuku?", - {"Komprese a tisk", - "Vzorkování a kvantování", - "Šifrování a záloha", - "Násobení a dělení"}, - 4, 1}, - {"Co dělá D/A převodník (DAC)?", - {"Z čísel znovu skládá spojitý signál", - "Měří jen vzorkovací frekvenci", - "Ukládá zvuk jako text", - "Zvyšuje počet bitů v souboru"}, - 4, 0}, - }; - static const char *hints[] = { - "Analog = spojitý signál", - "ADC převádí analog na čísla", - "Digitalizace = vzorkování + kvantování", - "DAC skládá z čísel spojitý signál", - }; - return build_hw_mcq_page(4, "hwunit5", "hw_ex5_title", "hw_quiz5_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit6_page(void) { - static const NetSlide slides[HW6_SLIDES] = { - { - "1 / 2 • Vzorky", "Vzorkování", - "Tip: vzorkovací frekvence fs = počet vzorků za sekundu (Hz).", - { - "Vzorkování měří velikost signálu v pravidelných " - "okamžicích.", - "Mezi vzorky se hodnota neukládá.", - "Vzorkovací frekvence fs je počet vzorků za sekundu.", - "Jednotka je hertz (Hz). 1 kHz = 1000 vzorků za sekundu.", - "Vyšší fs zachytí rychlejší změny, tedy vyšší tóny.", - NULL, - }, - }, - { - "2 / 2 • Nyquist", "Nyquistův–Shannonův teorém", - "Tip: fs musí být vyšší než 2 × fmax. Nyquistova frekvence je fs / 2.", - { - "Pro věrnou rekonstrukci musí být fs vyšší než dvojnásobek " - "nejvyšší frekvence ve signálu.", - "Nyquistova frekvence je fs / 2 – vyšší tón už záznam neunese.", - "Člověk slyší zhruba do 20 kHz, dvojnásobek je 40 kHz.", - "CD proto používá 44,1 kHz: o něco víc než 40 kHz, " - "aby zbyl prostor pro filtr.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[5], "hw_unit6", "hw_unit6_sub", - slides, HW6_SLIDES); -} - -GtkWidget *build_hw_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je vzorkovací frekvence?", - {"Počet bitů v jednom vzorku", - "Počet vzorků za sekundu", - "Délka skladby v minutách", - "Počet kanálů (mono nebo stereo)"}, - 4, 1}, - {"V jakých jednotkách se udává vzorkovací frekvence?", - {"V bytech", "V hertzech", "Ve voltech", "V pixelech"}, - 4, 1}, - {"Co říká Nyquistův–Shannonův teorém?", - {"fs musí být vyšší než dvojnásobek nejvyšší frekvence", - "fs musí být vždy 8 kHz", - "Stačí jeden vzorek na celou skladbu", - "Bitová hloubka musí být 1"}, - 4, 0}, - {"Proč má audio CD vzorkovací frekvenci 44,1 kHz?", - {"Protože byte má 8 bitů", - "Sluch sahá asi do 20 kHz a fs musí být vyšší než dvojnásobek", - "Protože stereo má dva kanály", - "Protože minutu tvoří 60 sekund"}, - 4, 1}, - }; - static const char *hints[] = { - "fs = počet vzorků za sekundu", - "Jednotka vzorkovací frekvence je hertz", - "fs > 2 × fmax", - "20 kHz × 2 = 40 kHz, CD má 44,1 kHz", - }; - return build_hw_mcq_page(5, "hwunit6", "hw_ex6_title", "hw_quiz6_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit7_page(void) { - static const NetSlide slides[HW7_SLIDES] = { - { - "1 / 2 • Hladiny", "Kvantování", - "Tip: n bitů → 2ⁿ hladin. 8 bitů = 256, 16 bitů = 65 536.", - { - "Kvantování zaokrouhlí amplitudu každého vzorku " - "na nejbližší z konečného počtu hladin.", - "Počet hladin je 2ⁿ, kde n je bitová hloubka " - "(počet bitů na vzorek).", - "8 bitů dává 256 hladin, 16 bitů dává 65 536 hladin.", - "Vzorkování říká jak často, kvantování jak přesně.", - NULL, - }, - }, - { - "2 / 2 • Chyba", "Kvantizační chyba", - "Tip: víc bitů = jemnější hladiny, menší šum a větší soubor.", - { - "Kvantizační chyba je rozdíl mezi skutečnou hodnotou " - "a zvolenou hladinou.", - "V záznamu se projeví jako kvantizační šum.", - "Větší bitová hloubka hladiny zjemní a šum zmenší.", - "Audio CD používá 16 bitů na vzorek, studio často 24 bitů.", - "Vyšší hloubka také zvětší datový tok.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[6], "hw_unit7", "hw_unit7_sub", - slides, HW7_SLIDES); -} - -GtkWidget *build_hw_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je kvantování?", - {"Měření signálu v pravidelných okamžicích", - "Zaokrouhlení amplitudy na konečný počet hladin", - "Převod čísel zpět na analog", - "Komprese souboru MP3"}, - 4, 1}, - {"Kolik hladin má 8bitové kvantování?", - {"8", "16", "256", "65 536"}, - 4, 2}, - {"Kolik hladin má 16bitové kvantování?", - {"16", "256", "1 024", "65 536"}, - 4, 3}, - {"Co je kvantizační chyba?", - {"Rozdíl mezi skutečnou hodnotou a zvolenou hladinou", - "Příliš nízká vzorkovací frekvence", - "Počet kanálů ve stereu", - "Délka skladby v sekundách"}, - 4, 0}, - }; - static const char *hints[] = { - "Kvantování zaokrouhluje amplitudu na hladiny", - "8 bitů → 2⁸ = 256 hladin", - "16 bitů → 2¹⁶ = 65 536 hladin", - "Kvantizační chyba = rozdíl proti skutečné hodnotě", - }; - return build_hw_mcq_page(6, "hwunit7", "hw_ex7_title", "hw_quiz7_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit8_page(void) { - static const NetSlide slides[HW8_SLIDES] = { - { - "1 / 2 • PCM", "Pulzně kódová modulace", - "Tip: tok = fs × bity na vzorek × počet kanálů.", - { - "PCM uloží každý vzorek jako binární číslo.", - "Je to základní nekomprimovaný záznam (WAV, audio CD).", - "Datový tok = vzorkovací frekvence × bitová hloubka " - "× počet kanálů.", - "Mono má jeden kanál, stereo dva (levý a pravý).", - NULL, - }, - }, - { - "2 / 2 • Velikost", "Kolik dat zabere CD", - "Tip: komprese (MP3, AAC) soubor zmenší, ale část informace zahodí.", - { - "CD stereo: 44 100 Hz × 16 bit × 2 = 1 411 200 bit/s.", - "To je 176 400 B/s.", - "Za minutu je to 10 584 000 B, tedy přes 10 MB.", - "Delší záznam, vyšší fs, více bitů nebo více kanálů " - "soubor zvětší.", - "MP3 a AAC soubor zmenší za cenu ztráty části informace.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[7], "hw_unit8", "hw_unit8_sub", - slides, HW8_SLIDES); -} - -GtkWidget *build_hw_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je PCM?", - {"Každý vzorek uložený jako binární číslo", - "Jen komprimovaný formát MP3", - "Filtr před mikrofonem", - "Jednotka hlasitosti"}, - 4, 0}, - {"Jak se spočítá datový tok nekomprimovaného zvuku?", - {"fs + bity + kanály", - "fs × bitová hloubka × počet kanálů", - "jen délka skladby v minutách", - "počet hladin děleno dvěma"}, - 4, 1}, - {"Jaký je datový tok audio CD ve stereu?", - {"44 100 bit/s", "256 bit/s", "1 411 200 bit/s", "8 bit/s"}, - 4, 2}, - {"Co udělá komprese MP3 se záznamem?", - {"Zvětší soubor a přidá vzorky", - "Zmenší soubor a část informace zahodí", - "Změní jen název souboru", - "Převede digitál zpět na analog"}, - 4, 1}, - }; - static const char *hints[] = { - "PCM = vzorek jako binární číslo", - "tok = fs × bity × kanály", - "44 100 × 16 × 2 = 1 411 200 bit/s", - "MP3 soubor zmenší a část informace zahodí", - }; - return build_hw_mcq_page(7, "hwunit8", "hw_ex8_title", "hw_quiz8_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit9_page(void) { - static const NetSlide slides[HW9_SLIDES] = { - { - "1 / 2 • Aliasing", "Když je vzorkování moc řídké", - "Tip: aliasing vznikne před uložením a z hotových vzorků " - "už nejde spolehlivě odstranit.", - { - "Aliasing vznikne, když je fs příliš nízká a poruší se " - "Nyquistovo pravidlo.", - "Vysoká frekvence se v záznamu jeví jako nižší tón.", - "Příklad: tón 6 kHz vzorkovaný 8 kHz se jeví jako 2 kHz.", - "Antialiasingový filtr před převodníkem vysoké frekvence " - "ořízne.", - NULL, - }, - }, - { - "2 / 2 • Formáty", "Běžné parametry záznamu", - "Tip: vyšší fs a víc bitů znamená věrnější záznam a větší tok.", - { - "Audio CD: 44,1 kHz, 16 bitů, stereo.", - "Klasický telefonní hovor: 8 kHz a 8 bitů – řeč se vejde " - "do pásma do 4 kHz.", - "Studio často používá 48 nebo 96 kHz a 24 bitů.", - "Parametry se volí podle toho, co má záznam unést " - "a jak velký smí být.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[8], "hw_unit9", "hw_unit9_sub", - slides, HW9_SLIDES); -} - -GtkWidget *build_hw_unit9_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy vzniká aliasing?", - {"Když je vzorkovací frekvence příliš nízká", - "Když má záznam 24 bitů", - "Když je soubor ve stereu", - "Když se použije D/A převodník"}, - 4, 0}, - {"K čemu je antialiasingový filtr?", - {"Zvětší bitovou hloubku po uložení", - "Před vzorkováním ořízne frekvence nad Nyquistovu", - "Spočítá datový tok", - "Převede mono na stereo"}, - 4, 1}, - {"Jaké parametry má audio CD?", - {"8 kHz, 8 bitů, mono", - "44,1 kHz, 16 bitů, stereo", - "96 kHz, 8 bitů, mono", - "1 kHz, 1 bit, stereo"}, - 4, 1}, - {"Proč telefonnímu hovoru stačí vzorkování 8 kHz?", - {"Řeč se vejde do pásma zhruba do 4 kHz", - "Telefon nahrává na audio CD", - "8 kHz je totéž co 44,1 kHz", - "Řeč nemá žádnou frekvenci"}, - 4, 0}, - }; - static const char *hints[] = { - "Aliasing = příliš nízká fs", - "Filtr ořízne frekvence nad fs / 2 ještě před vzorkováním", - "CD = 44,1 kHz, 16 bit, stereo", - "Pásmo řeči je do asi 4 kHz, proto stačí fs = 8 kHz", - }; - return build_hw_mcq_page(8, "hwunit9", "hw_ex9_title", "hw_quiz9_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit10_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Účel", "Počítačová skříň", - "Tip: skříň má být uzavřená, ale s větracími mřížkami.", - { - "Skříň zastřešuje a drží ostatní komponenty.", - "Součásti se propojují kabely nebo přímo do základní desky.", - "Při provozu vzniká teplo a skříň ho musí odvést.", - "Uzavřená skříň s mřížkami udržuje správné proudění vzduchu " - "(airflow).", - NULL, - }, - }, - { - "2 / 2 • Stěny", "Přední a zadní stěna, desktop a tower", - "Tip: desktop leží, tower stojí.", - { - "Přední stěna: zapnutí, restart, zelená kontrolka chodu " - "a červená kontrolka disku.", - "Vpředu bývají i USB porty a audio vstupy a výstupy.", - "Zadní stěna zpřístupňuje porty desky a přídavných karet.", - "Volné otvory kryjí záslepky, aby se dovnitř neprášilo.", - "Desktop je skříň naležato, monitor se na ni pokládá.", - "Tower stojí nastojato vedle monitoru nebo pod stolem.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[9], "hw_unit10", "hw_unit10_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit10_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu slouží počítačová skříň?", - {"Jen jako ozdoba monitoru", - "Zastřešuje a uchycuje ostatní komponenty", - "Převádí 230 V na 12 V", - "Ukládá operační systém"}, - 4, 1}, - {"Proč má být skříň uzavřená a mít větrací mřížky?", - {"Aby se dovnitř vešel jen jeden disk", - "Aby uvnitř správně proudil vzduch a odvádělo se teplo", - "Aby nešel zapnout restart", - "Aby odpadly kabely"}, - 4, 1}, - {"Co typicky najdeme na přední stěně?", - {"Tlačítka, kontrolky, USB a audio", - "Jen patici procesoru", - "Jen sloty ISA", - "Jen plotny pevného disku"}, - 4, 0}, - {"Jak se liší desktop a tower?", - {"Desktop je bez zdroje, tower bez desky", - "Desktop je jen pro notebooky", - "Desktop leží, tower stojí", - "Liší se jen barvou kontrolek"}, - 4, 2}, - }; - static const char *hints[] = { - "Skříň drží a chrání komponenty", - "Airflow odvádí teplo", - "Vpředu: power, reset, LED, USB, audio", - "Desktop naležato, tower nastojato", - }; - return build_hw_mcq_page(9, "hwunit10", "hw_ex10_title", "hw_quiz10_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit11_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Převod", "Napájecí zdroj", - "Tip: ze sítě jde střídavých 230 V / 50 Hz.", - { - "Zdroj zásobuje všechny části počítače elektřinou.", - "Převádí střídavé napětí 230 V, 50 Hz na stejnosměrné " - "3,3 V, 5 V a 12 V.", - "Nejrozšířenější je standard ATX, včetně variant TFX a SFX.", - "ATX umí počítač vypnout softwarově přes základní desku.", - "Výkon se vyrábí v řadě hodnot, třeba od 350 W po 700 W " - "i víc.", - NULL, - }, - }, - { - "2 / 2 • Přívody", "Co se napájí přímo a kolik to bere", - "Tip: spotřeba není stálá.", - { - "Přímo ze zdroje: deska, pevné disky, mechaniky, aktivní " - "chladiče a grafické karty.", - "Přes desku: rozšiřující karty, některé ventilátory, " - "procesor, porty a LED kontrolky.", - "V klidu bere sestava zhruba 100 W.", - "V plné zátěži může spotřeba dosáhnout 500–600 W.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[10], "hw_unit11", "hw_unit11_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit11_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co zdroj udělá se síťovým napětím?", - {"Nechá 230 V střídavých všude v počítači", - "Převede 230 V střídavých na stejnosměrné 3,3 V, 5 V a 12 V", - "Převede všechno na 230 V stejnosměrných", - "Vyrábí jen 1,5 V pro USB"}, - 4, 1}, - {"Co umožňuje standard ATX?", - {"Softwarové vypnutí počítače přes základní desku", - "Jen napájení disketové mechaniky", - "Zrušení větracích mřížek", - "Uložení BIOSu na pásku"}, - 4, 0}, - {"Co se ze zdroje napájí přímo?", - {"Jen LED na klávesnici", - "Jen porty na zadní stěně", - "Deska, disky, mechaniky, aktivní chladiče a grafické karty", - "Jen operační paměť"}, - 4, 2}, - {"Jak se mění spotřeba počítače?", - {"Je pořád přesně 350 W", - "V klidu asi 100 W, v plné zátěži 500–600 W", - "V klidu 500 W a v zátěži 100 W", - "Nezávisí na tom, co počítač dělá"}, - 4, 1}, - }; - static const char *hints[] = { - "230 V AC → 3,3 / 5 / 12 V DC", - "ATX umí softwarové vypnutí", - "Přímo: deska, disky, mechaniky, chladiče, GPU", - "Klid cca 100 W, zátěž 500–600 W", - }; - return build_hw_mcq_page(10, "hwunit11", "hw_ex11_title", "hw_quiz11_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit12_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Páteř", "Základní deska", - "Tip: deska rozhoduje o kompatibilitě a o tom, co půjde upgradovat.", - { - "Je to vícevrstvý plošný spoj, fundament a páteř počítače.", - "Propojuje procesor se všemi ostatními částmi.", - "Čipset tvoří dva čipy: severní a jižní most.", - "Sběrnice jsou měděné cestičky pro data a signály.", - NULL, - }, - }, - { - "2 / 2 • Čipy", "Patice, mosty a BIOS", - "Tip: nastavení BIOSu drží čip CMOS na baterii.", - { - "Patice (socket) mechanicky drží procesor a elektricky " - "ho propojí.", - "Severní most je systémový řadič blízko CPU a řeší rychlé " - "přesuny: FSB, AGP a paměťovou sběrnici.", - "Jižní most připojuje pomalejší periferie, BIOS, disky, " - "USB a porty.", - "BIOS je mezistupeň mezi hardwarem a softwarem a nese " - "instrukce pro zavedení operačního systému.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[11], "hw_unit12", "hw_unit12_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit12_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je základní deska?", - {"Vícevrstvý plošný spoj, páteř počítače", - "Jen kovový kryt zdroje", - "Jen ventilátor na procesoru", - "Externí disk"}, - 4, 0}, - {"Z čeho se skládá čipset?", - {"Ze tří grafických karet", - "Ze severního a jižního mostu", - "Jen z baterie CMOS", - "Jen ze slotu ISA"}, - 4, 1}, - {"Co řeší severní most?", - {"Jen pomalé USB porty", - "Jen zvukový výstup", - "Rychlé přesuny dat: FSB, AGP a paměťovou sběrnici", - "Jen tlačítko reset"}, - 4, 2}, - {"Kde je uložené nastavení BIOSu?", - {"V čipu CMOS napájeném baterií", - "Jen na papírovém štítku skříně", - "V mechanice CD", - "V červeném vodiči zdroje"}, - 4, 0}, - }; - static const char *hints[] = { - "Deska je páteř a rozhoduje o kompatibilitě", - "Čipset = severní + jižní most", - "Severní most: FSB, AGP, paměť", - "BIOS zavádí OS, nastavení drží CMOS", - }; - return build_hw_mcq_page(11, "hwunit12", "hw_ex12_title", "hw_quiz12_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit13_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Konektory", "Napájení a datové kabely", - "Tip: F_PANEL je svazek od předního panelu skříně.", - { - "Deska bere 24pinový napájecí konektor a procesor " - "zvlášť 4pinový nebo 8pinový.", - "Disky a mechaniky se připojují přes SATA.", - "Starší rozhraní jsou IDE a FDD.", - "F_PANEL připojuje Power, Reset, LED diody a PC speaker.", - NULL, - }, - }, - { - "2 / 2 • Sloty", "ISA, PCI, AGP a PCIe", - "Tip: dnešní rychlé rozhraní je PCI Express.", - { - "ISA je zastaralý 16bitový slot.", - "PCI je nezávislé na CPU, běží na 33 MHz a má propustnost " - "264 MB/s.", - "AGP vzniklo pro grafické karty a má přímé spojení s RAM.", - "PCI Express je sériové, vysokorychlostní a umí Hot Plug.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[12], "hw_unit13", "hw_unit13_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit13_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jakými konektory se deska napájí?", - {"Jen jedním USB", - "24 piny pro desku a 4 nebo 8 piny pro CPU", - "Jen konektorem FDD", - "Jen slotem ISA"}, - 4, 1}, - {"Co se připojuje na F_PANEL?", - {"Power, Reset, LED a PC speaker", - "Jen pevný disk", - "Jen monitor", - "Jen anténa Wi-Fi"}, - 4, 0}, - {"Jaké má parametry sběrnice PCI?", - {"Sériová, jen pro tiskárny", - "16bitová a dnes jediná používaná", - "Nezávislá na CPU, 33 MHz, 264 MB/s", - "Jen pro procesor"}, - 4, 2}, - {"K čemu vzniklo AGP?", - {"Pro disketové mechaniky", - "Speciálně pro grafické karty, s přímým spojením k RAM", - "Jako náhrada napájecího zdroje", - "Pro pomalé tiskárny"}, - 4, 1}, - }; - static const char *hints[] = { - "24 pinů deska, 4/8 pinů CPU", - "F_PANEL = tlačítka, LED, speaker", - "PCI: 33 MHz, 264 MB/s", - "AGP je pro grafiku a sahá přímo na RAM", - }; - return build_hw_mcq_page(12, "hwunit13", "hw_ex13_title", "hw_quiz13_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit14_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Dělení", "Vnitřní a vnější paměť", - "Tip: RAM je rychlá, ale bez napájení data ztratí.", - { - "Vnitřní paměť je operační RAM: rychlá, pro rozpracovaná " - "data, bez napájení se smaže.", - "Vnější paměť jsou disky, USB a optická média.", - "Vnější paměť data udrží i bez napájení.", - "Je ale mnohem pomalejší než RAM.", - NULL, - }, - }, - { - "2 / 2 • Typy", "SRAM a DRAM", - "Tip: SRAM je cache v procesoru, DRAM se musí obnovovat.", - { - "SRAM (statická) je velmi rychlá a drahá.", - "Používá se jako cache v procesoru.", - "DRAM (dynamická) je levnější a data se musí neustále " - "obnovovat.", - "Patří sem SDR a řada DDR až po DDR3.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[13], "hw_unit14", "hw_unit14_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit14_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu slouží operační RAM?", - {"Pro rozpracovaná data; je rychlá a potřebuje napájení", - "Pro trvalé uložení filmů bez elektřiny", - "Jen jako náhrada zdroje", - "Jen pro větrání skříně"}, - 4, 0}, - {"Čím se vnější paměť liší od RAM?", - {"Je rychlejší a maže se při vypnutí", - "Drží data i bez napájení, ale je pomalejší", - "Je vždy jen v procesoru", - "Nepotřebuje žádný řadič"}, - 4, 1}, - {"Kde se používá SRAM?", - {"Jako jediný pevný disk", - "Jen v optické mechanice", - "Jako rychlá a drahá cache v procesoru", - "Jen na předním panelu"}, - 4, 2}, - {"Co platí o DRAM?", - {"Je levnější a data se musí obnovovat (SDR, DDR až DDR3)", - "Nikdy se neobnovuje a je dražší než SRAM", - "Slouží jen jako baterie CMOS", - "Je to jiný název pro zdroj ATX"}, - 4, 0}, - }; - static const char *hints[] = { - "RAM = rychlá vnitřní paměť, chce napájení", - "Vnější paměť je stálá a pomalejší", - "SRAM = cache CPU", - "DRAM se obnovuje, SDR a DDR až DDR3", - }; - return build_hw_mcq_page(13, "hwunit14", "hw_ex14_title", "hw_quiz14_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit15_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Mozek", "Procesor", - "Tip: takt = základní hodiny 100 MHz × násobič.", - { - "CPU je hlavní výpočetní jednotka a řídí ostatní části.", - "Je to křemíkový čip z miliard tranzistorů, které pracují " - "jako spínače.", - "Frekvence je počet cyklů za sekundu (Hz, v praxi GHz).", - "Takt vznikne jako součin base clock (100 MHz) a násobiče.", - NULL, - }, - }, - { - "2 / 3 • Jádra", "Více jader, vlákna a cache", - "Tip: cache L1, L2 a L3 zmenšují čekání na pomalejší paměť.", - { - "Více jader jsou samostatné jednotky pro souběžnou práci.", - "Hyper-Threading / SMT nechá jedno jádro zpracovat dvě " - "vlákna najednou.", - "Cache je vyrovnávací paměť mezi rychlým jádrem a pomalejšími " - "součástmi.", - "Bývá ve třech úrovních: L1, L2 a L3.", - NULL, - }, - }, - { - "3 / 3 • Teplo", "Chlazení procesoru", - "Tip: chlazení prodlužuje životnost a dovolí přetaktování.", - { - "Chladič odvádí teplo z čipu.", - "Vzduchové chlazení je pasivní blok a ventilátor.", - "Je levné a spolehlivé.", - "Vodní all-in-one vede teplo kapalinou do radiátoru.", - "U procesoru tak zabere méně místa.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[14], "hw_unit15", "hw_unit15_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit15_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak vzniká takt procesoru?", - {"Jen z napětí 12 V", - "Jako součin base clock 100 MHz a násobiče", - "Jen z počtu USB portů", - "Z rychlosti ventilátoru ve skříni"}, - 4, 1}, - {"Co umí Hyper-Threading / SMT?", - {"Jedno jádro zpracuje dvě vlákna současně", - "Vypne chlazení", - "Zdvojnásobí napětí zdroje", - "Nahradí operační paměť diskem"}, - 4, 0}, - {"K čemu je cache L1, L2 a L3?", - {"K napájení grafické karty", - "K uložení BIOSu na baterii", - "Vyrovnává rychlostní rozdíl mezi procesorem a ostatními částmi", - "K větrání zadní stěny"}, - 4, 2}, - {"Čím se vyznačuje vzduchové chlazení CPU?", - {"Jen kapalinou bez ventilátoru", - "Pasivním blokem a ventilátorem; je levné a spolehlivé", - "Tím, že procesor nehřeje", - "Tím, že se montuje jen na disk"}, - 4, 1}, - }; - static const char *hints[] = { - "Takt = 100 MHz × násobič", - "SMT = dvě vlákna na jedno jádro", - "Cache vyrovnává rychlost", - "Vzduch: blok + ventilátor", - }; - return build_hw_mcq_page(14, "hwunit15", "hw_ex15_title", "hw_quiz15_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit16_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Karty", "Přídavné karty", - "Tip: karta je plošný spoj, který počítači přidá schopnost.", - { - "Rozšiřující karta vylepší nebo rozšíří to, co počítač umí.", - "Typické jsou grafické, zvukové, síťové a televizní karty.", - "Sloty se vyvíjely, proto karta obvykle nejde zasunout " - "do libovolného slotu.", - NULL, - }, - }, - { - "2 / 2 • PCIe", "Kam se karta dává", - "Tip: grafika chce nejširší slot.", - { - "Grafické karty patří do PCI Express ×16.", - "Ostatní karty se dnes dávají do PCI Express ×1 až ×4.", - "Číslo za × říká, kolik linek slot kartě dá.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[15], "hw_unit16", "hw_unit16_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit16_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu je přídavná karta?", - {"Rozšíří nebo vylepší schopnosti počítače", - "Nahradí napájecí zdroj", - "Jen uzavře skříň", - "Ukládá BIOS"}, - 4, 0}, - {"Do jakého slotu patří grafická karta?", - {"Do ISA", "Do PCI Express ×16", "Do FDD", "Do F_PANEL"}, - 4, 1}, - {"Kam se dnes dávají ostatní karty?", - {"Jen do AGP", - "Jen na přední stěnu skříně", - "Do PCI Express ×1 až ×4", - "Přímo do patice procesoru"}, - 4, 2}, - {"Proč nejde karta zasunout do každého slotu?", - {"Sloty se liší a karta sedí jen do odpovídajícího", - "Protože všechny sloty jsou stejné", - "Protože karty nemají kontakty", - "Protože to zakazuje airflow"}, - 4, 0}, - }; - static const char *hints[] = { - "Karta rozšiřuje schopnosti PC", - "GPU → PCIe ×16", - "Ostatní karty → PCIe ×1 až ×4", - "Slot a karta k sobě musí sedět", - }; - return build_hw_mcq_page(15, "hwunit16", "hw_ex16_title", "hw_quiz16_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit17_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Obraz", "Z čeho se skládá obraz", - "Tip: hry skládají scénu hlavně z trojúhelníků.", - { - "Digitalizace obrazu je vzorkování, kvantování a kódování.", - "Jas může mít třeba 256 úrovní, nebo jen 2.", - "Pixel je bod v obraze.", - "Polygon je 2D mnohoúhelník; ve hrách často trojúhelník, " - "protože ho GPU zpracuje nejjednodušeji.", - "Vertex je vrchol, edge je hrana.", - "Textura je bitmapa namapovaná na 3D model.", - "Ray tracing je metoda sledování paprsku.", - NULL, - }, - }, - { - "2 / 3 • Typy", "Integrovaná a samostatná grafika", - "Tip: integrovaný čip šetří peníze, samostatná karta přidá výkon.", - { - "Integrovaná grafika je čip přímo na základní desce.", - "Bývá v levnějších a kancelářských sestavách i v noteboocích.", - "Má nižší výkon a nižší cenu a může brzdit zbytek systému.", - "Samostatná karta se dává do rozšiřujícího slotu.", - "Míří na hráče a náročnější uživatele.", - NULL, - }, - }, - { - "3 / 3 • Cesta", "Co je na kartě a kam jde obraz", - "Tip: obraz jde z CPU do grafické paměti, pak do GPU a dál na monitor.", - { - "Na kartě je GPU, RAMDAC, paměti, sběrnice, porty a často " - "konektor přídavného napájení (Molex).", - "GPU mívá aktivní chladič, okolo něj sedí paměťové čipy.", - "Datový tok začíná v procesoru počítače a jde do grafické " - "paměti.", - "GPU data zpracuje a pošle je do převodníku signálu.", - "Odtud obraz pokračuje do monitoru (framebuffer).", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[16], "hw_unit17", "hw_unit17_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit17_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je pixel?", - {"Bod v obraze", "Hrana polygonu", "Napájecí konektor", - "Typ pevného disku"}, - 4, 0}, - {"Proč hry často používají trojúhelník?", - {"Protože má víc hran než čtverec", - "Pro grafickou kartu je nejjednodušší na zpracování", - "Protože nepotřebuje texturu", - "Protože nahradí monitor"}, - 4, 1}, - {"Čím se vyznačuje integrovaná grafika?", - {"Je vždy rychlejší než samostatná karta", - "Sedí jen v mechanice DVD", - "Čip je na desce, bývá levnější a má nižší výkon", - "Nemá vliv na zbytek počítače"}, - 4, 2}, - {"Jakou cestou jde obraz?", - {"CPU → grafická paměť → GPU → převodník → monitor", - "Monitor → disk → zdroj → skříň", - "Jen z BIOSu přímo do reproduktoru", - "Z F_PANEL rovnou na tiskárnu"}, - 4, 0}, - }; - static const char *hints[] = { - "Pixel = bod obrazu", - "Trojúhelník je pro GPU nejjednodušší", - "Integrovaná grafika je na desce", - "CPU → VRAM → GPU → převodník → monitor", - }; - return build_hw_mcq_page(16, "hwunit17", "hw_ex17_title", "hw_quiz17_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit18_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • GPU", "Grafický procesor", - "Tip: pro výkon počítače je GPU stejně důležité jako CPU.", - { - "GPU přijímá data od CPU a počítá obraz.", - "Je to složitý čip se stovkami milionů tranzistorů.", - "Sleduje se takt v MHz, kapacita paměti a počet shaderů.", - "Dřív se počítaly vertex a pixel shadery, dnes spíš " - "unifikované, částečně programovatelné jednotky.", - NULL, - }, - }, - { - "2 / 3 • Programy", "Shader a renderování", - "Tip: vertex shader posouvá vrcholy, ale nové nevytváří.", - { - "Shader je program, který řídí části grafického řetězce.", - "Renderování tvoří obraz podle počítačového modelu, " - "nejčastěji 3D.", - "Render je vizualizace: model se přenese do 2D bitmapy.", - "Softwarový render počítá procesor. Je přesnější, ale " - "mnohonásobně pomalejší.", - "Hardwarový render slouží pro náhledy a hry.", - "Vertex shader transformuje vrcholy a nové nevytváří.", - "Pixel shader potom mapuje texturu a přidává efekty, " - "třeba ray tracing nebo bump mapping.", - NULL, - }, - }, - { - "3 / 3 • Výpočty", "CUDA a architektura GPU", - "Tip: většinu čipu tvoří mnoho jednoduchých procesorů.", - { - "CUDA je paralelní platforma NVIDIA a nechá GPU počítat " - "i jiné úlohy než obraz.", - "Zrychluje třeba lineární algebru, obraz, video a " - "hluboké učení.", - "Obdoba u AMD se jmenuje FireStream.", - "GPU vzniklo pro hry: miliony polygonů a velké textury.", - "Je stavěné na tisíce vláken, hodně počítání a málo " - "podmínek a na sekvenční čtení paměti.", - "Jednoduché skalární procesory jsou sdružené do " - "streaming multiprocesorů.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[17], "hw_unit18", "hw_unit18_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit18_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je shader?", - {"Program řídící části grafického řetězce", - "Napájecí konektor Molex", - "Typ pevného disku", - "Větrací mřížka"}, - 4, 0}, - {"Co vertex shader nedělá?", - {"Neposouvá vrcholy", - "Nevytváří nové vertexy", - "Nesahá na grafickou kartu", - "Nepoužívá se ve 3D"}, - 4, 1}, - {"Čím se liší softwarový render?", - {"Je rychlejší, protože ho počítá jen GPU", - "Umí jen černobíle", - "Počítá ho CPU, je přesnější a mnohem pomalejší", - "Nevytvoří bitmapu"}, - 4, 2}, - {"Co je CUDA?", - {"Platforma NVIDIA pro výpočty na GPU", - "Standard napájecího zdroje", - "Starý slot ISA", - "Formát diskety"}, - 4, 0}, - }; - static const char *hints[] = { - "Shader řídí řetězec karty", - "Vertex shader nové vrcholy nezakládá", - "Softwarový render = CPU, přesný a pomalý", - "CUDA je od NVIDIA, u AMD je FireStream", - }; - return build_hw_mcq_page(17, "hwunit18", "hw_ex18_title", "hw_quiz18_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit19_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Převod", "RAMDAC a grafická paměť", - "Tip: nižší CAS latency znamená kratší čekání.", - { - "RAMDAC převádí digitální data na analogová.", - "U dnešních karet je uvnitř GPU a má přednost při čtení " - "paměti.", - "Okolo GPU jsou grafické paměti, často DDR nebo GDDR5.", - "Hlavní parametry jsou kapacita a frekvence.", - "CAS latency je čekání, než se po zadání adresy sloupce " - "data objeví na pinech.", - "Čím nižší latence, tím lépe. Časy paměti se udávají " - "v nanosekundách.", - NULL, - }, - }, - { - "2 / 3 • Spojení", "Sběrnice grafické karty", - "Tip: PCIe 4.0 má na jedné lince 2 GB/s.", - { - "Typická sběrnice karty je PCI Express ×16, dřív to bylo AGP.", - "PCIe 4.0 zdvojnásobí propustnost proti předchozí verzi " - "při stejném počtu linek.", - "Rychlost jedné linky stoupla z 1 GB/s na 2 GB/s.", - "Slot ×16 tak teoreticky dává 32 GB/s.", - "M.2 se čtyřmi linkami dává 8 GB/s.", - NULL, - }, - }, - { - "3 / 3 • Výstupy", "Porty na kartě", - "Tip: stejný obraz může odejít analogově i digitálně.", - { - "Běžné výstupy jsou D-Sub, DVI, HDMI a DisplayPort.", - "Starší karty mají i TV výstup, S-Video nebo cinch.", - "Výrobci parametry přikrášlují, proto se karty srovnávají " - "benchmarkem.", - "Známý test je 3DMark. Podíl má i procesor, rozhoduje ale " - "grafická karta.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[18], "hw_unit19", "hw_unit19_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit19_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co dělá RAMDAC?", - {"Převádí analogový signál na digitální", - "Převádí digitální data na analogová a dnes je v GPU", - "Počítá jen cache procesoru", - "Formátuje pevný disk"}, - 4, 1}, - {"Co znamená nižší CAS latency?", - {"Data se objeví dřív, takže je to lepší", - "Karta má míň portů", - "Sběrnice je pomalejší", - "Monitor má nižší rozlišení"}, - 4, 0}, - {"Jakou teoretickou propustnost má PCIe 4.0 ×16?", - {"2 GB/s", "8 GB/s", "32 GB/s", "264 MB/s"}, - 4, 2}, - {"Co se stalo s rychlostí jedné linky u PCIe 4.0?", - {"Klesla z 2 GB/s na 1 GB/s", - "Stoupla z 1 GB/s na 2 GB/s", - "Zůstala 133 MB/s", - "Záleží jen na barvě slotu"}, - 4, 1}, - }; - static const char *hints[] = { - "RAMDAC = digital → analog, dnes v GPU", - "Nižší CAS = kratší čekání", - "PCIe 4.0 ×16 = 32 GB/s", - "Jedna linka: 1 GB/s → 2 GB/s", - }; - return build_hw_mcq_page(18, "hwunit19", "hw_ex19_title", "hw_quiz19_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit20_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Více karet", "SLI, CrossFire a režimy", - "Tip: první režim IBM PC byl v roce 1982 MDA.", - { - "SLI od NVIDIA spojí dvě grafické karty do jednoho celku.", - "Vychází levněji než jedna špičková karta.", - "Obdoba u ATI se jmenuje CrossFire.", - "Režim určuje rozlišení a barevnou hloubku.", - "Dnešní karty zvládnou i 3200×2400 (QUXGA) při 32 bitech.", - NULL, - }, - }, - { - "2 / 2 • Názvy", "720p, 1080p, 4K a 8K", - "Tip: 4K má čtyřikrát víc pixelů než 1080p, 8K šestnáctkrát.", - { - "720p je 1280×720, tedy HD nebo HD Ready.", - "1080p je 1920×1080, tedy Full HD.", - "1440p je 2560×1440, tedy QHD, čtyřnásobek 720p.", - "4K (2160p) je 3840×2160, čtyřnásobek Full HD.", - "8K (4320p) je 7680×4320, šestnáctinásobek Full HD.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[19], "hw_unit20", "hw_unit20_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit20_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je 1080p?", - {"1920×1080, Full HD", - "1280×720, HD Ready", - "7680×4320, 8K", - "3200×2400, QUXGA"}, - 4, 0}, - {"Co je 4K?", - {"1280×720", - "3840×2160, čtyřnásobek pixelů Full HD", - "2560×1440", - "640×480"}, - 4, 1}, - {"Kolikrát víc pixelů má 8K proti 1080p?", - {"Dvakrát", "Čtyřikrát", "Šestnáctkrát", "Stejně"}, - 4, 2}, - {"Co je SLI a co je CrossFire?", - {"SLI spojuje karty NVIDIA, CrossFire je obdoba ATI", - "Obojí je typ paměti DDR", - "SLI je port HDMI, CrossFire je D-Sub", - "Jsou to dva názvy stejné firmy"}, - 4, 0}, - }; - static const char *hints[] = { - "1080p = 1920×1080", - "4K = 3840×2160", - "8K má 16× víc pixelů než 1080p", - "SLI = NVIDIA, CrossFire = ATI", - }; - return build_hw_mcq_page(19, "hwunit20", "hw_ex20_title", "hw_quiz20_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit21_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Výstup", "Zvuková karta", - "Tip: digitalizace zvuku je vzorkování, kvantování a kódování.", - { - "Karta zajistí zvukový výstup.", - "Převede digitální signál na analogový, který zahraje " - "reproduktor.", - "Rozlišujeme integrované, interní a externí karty.", - "CD má 44,1 kHz a bitovou hloubku 16 až 24 bitů.", - NULL, - }, - }, - { - "2 / 3 • Provedení", "Integrovaná, interní, externí a herní", - "Tip: externí karta se připojuje přes USB a sedí mimo skříň.", - { - "Integrovaný zvuk je na téměř každé desce a na multimédia " - "stačí.", - "Má slabší zesílení a méně konektorů.", - "Interní karta jde do PCIe a nabízí prostorový zvuk " - "a software pro nastavení.", - "Externí karta se hodí, když integrovaná nestačí, i do " - "notebooku.", - "Herní karta, interní nebo externí, drží prostorový zvuk, " - "malou odezvu a přesnou reprodukci.", - NULL, - }, - }, - { - "3 / 3 • Čip", "DSP a nahrávání", - "Tip: kondenzátorový mikrofon chce fantomové napájení 48 V.", - { - "Zvukový čip má jádra, D/A a A/D převodníky, sluchátkový " - "zesilovač a vstupy i výstupy.", - "DSP stojí na harvardské architektuře: paměť programu je " - "oddělená od paměti dat, na rozdíl od von Neumannova modelu.", - "Počet vstupů má odpovídat počtu nástrojů nahrávaných najednou.", - "Na zpěv stačí jeden analogový vstup.", - "Některé nástroje, třeba keyboard, chtějí vysokoimpedanční " - "vstup Hi-Z.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[20], "hw_unit21", "hw_unit21_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit21_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co zvuková karta dělá se signálem?", - {"Převede digitální signál na analogový pro reproduktor", - "Převede jen obraz na texturu", - "Nahradí procesor", - "Ukládá data na pásku"}, - 4, 0}, - {"Jak se připojuje interní zvuková karta?", - {"Jen přes VGA", "Přes slot PCIe", "Jen přes FDD", "Přes baterii CMOS"}, - 4, 1}, - {"Jak se připojuje externí zvuková karta?", - {"Do patice procesoru", "Do slotu AGP", "Přes USB, mimo skříň", - "Jen na přední LED"}, - 4, 2}, - {"K čemu je fantomové napájení 48 V?", - {"Pro kondenzátorové mikrofony", - "Pro vypnutí zdroje ATX", - "Pro chlazení procesoru", - "Pro slot ISA"}, - 4, 0}, - }; - static const char *hints[] = { - "Digitál → analog pro reproduktor", - "Interní karta sedí v PCIe", - "Externí karta jde přes USB", - "48 V je fantom pro kondenzátorový mikrofon", - }; - return build_hw_mcq_page(20, "hwunit21", "hw_ex21_title", "hw_quiz21_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit22_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Síť", "Síťová karta", - "Tip: dnes nemusí jít jen o kabel, umí i Wi-Fi.", - { - "Integrovaná karta má ethernetový konektor přímo na desce.", - "Interní karta kombinuje kabel a Wi-Fi a jde do PCIe.", - "Externí karta se strčí do USB.", - "Wake on LAN umí počítač zapnout po datové síti.", - "Externí anténa zvětší dosah.", - "MIMO použije víc antén a zvedne propustnost.", - "WPS zjednoduší nastavení bezdrátového spojení.", - NULL, - }, - }, - { - "2 / 2 • Televize", "Televizní karta", - "Tip: tuner na základní desce integrovaný nebývá.", - { - "Televizní tuner na desce integrovaný není nikdy.", - "Přidá počítači příjem televizního signálu.", - "Umí signál i zaznamenat.", - "Je to další rozšiřující karta, ne součást čipsetu.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[21], "hw_unit22", "hw_unit22_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit22_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kde je integrovaná síťová karta?", - {"Ethernetový konektor přímo na desce", - "Jen v optické mechanice", - "Jen jako externí disk", - "V patici procesoru"}, - 4, 0}, - {"Co je Wake on LAN?", - {"Vypnutí monitoru při nečinnosti", - "Zapnutí počítače přes datovou síť", - "Zrychlení pevného disku", - "Jiný název pro BIOS"}, - 4, 1}, - {"Co přináší MIMO?", - {"Jednu anténu a nižší dosah", - "Jen kabelový konektor", - "Více antén a vyšší propustnost", - "Zrušení Wi-Fi"}, - 4, 2}, - {"Jak je to s televizní kartou na desce?", - {"Není integrovaná nikdy", - "Je na každé desce ATX", - "Nahrazuje zvukovou kartu", - "Je součást severního mostu"}, - 4, 0}, - }; - static const char *hints[] = { - "Integrovaná síťovka = LAN na desce", - "Wake on LAN zapne počítač po síti", - "MIMO = víc antén, vyšší propustnost", - "TV tuner na desce integrovaný nebývá", - }; - return build_hw_mcq_page(21, "hwunit22", "hw_ex22_title", "hw_quiz22_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit23_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Trvalá data", "Vnější paměti a HDD", - "Tip: HDD je mechanický, otřes ho může poškodit.", - { - "Vnější paměť drží data dlouhodobě, má kapacitu v terabajtech " - "a je energeticky nezávislá.", - "Patří sem HDD, SSD a USB flash disky.", - "Pevný disk zaznamenává data magneticky.", - "Notebookové disky mají 2,5 palce, stolní 3,5 palce.", - NULL, - }, - }, - { - "2 / 3 • Čísla", "Parametry pevného disku", - "Tip: běžné otáčky jsou 5400 a 7200 za minutu.", - { - "Kapacita se udává v terabajtech.", - "Přístupová doba je v milisekundách.", - "Přenosová rychlost je ve stovkách MB/s.", - "Cache bývá třeba 256 MB.", - NULL, - }, - }, - { - "3 / 3 • Stopy", "Zápis, čtení a struktura", - "Tip: hlavy se ploten nedotýkají, vznášejí se na vzduchu.", - { - "Zápis dělá cívka magnetickým polem.", - "Čtení používá elektromagnetickou indukci.", - "Disk je hermeticky uzavřený.", - "Formátování vytvoří stopy a sektory.", - "Cylindr jsou stejné stopy na všech plotnách.", - "Defragmentace složí rozházená data k sobě, aby se četla " - "rychleji.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[22], "hw_unit23", "hw_unit23_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit23_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Na jakém principu pracuje HDD?", - {"Na magnetickém záznamu a je mechanický", - "Jen na optickém laseru", - "Nemá pohyblivé části", - "Drží data jen při zapnutém napájení"}, - 4, 0}, - {"Jaké rozměry mají pevné disky?", - {"Jen 8 palců", - "2,5\" do notebooku a 3,5\" do stolního počítače", - "12 cm jako CD", - "Jen formát microSD"}, - 4, 1}, - {"Jaké otáčky se u HDD běžně uvádějí?", - {"100 a 200 ot/min", "1000 ot/min", "5400 a 7200 ot/min", - "48 000 ot/min"}, - 4, 2}, - {"Jak disk zapisuje a čte?", - {"Zápis cívkou, čtení elektromagnetickou indukcí", - "Zápis laserem, čtení ventilátorem", - "Obojí jen přes BIOS", - "Zápis do CMOS, čtení z baterie"}, - 4, 0}, - }; - static const char *hints[] = { - "HDD = magnetický a mechanický", - "2,5\" notebook, 3,5\" desktop", - "5400 a 7200 ot/min", - "Zápis = magnetické pole, čtení = indukce", - }; - return build_hw_mcq_page(22, "hwunit23", "hw_ex23_title", "hw_quiz23_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit24_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Bez pohybu", "SSD", - "Tip: fragmentace u SSD problém není.", - { - "SSD je polovodičový disk bez pohyblivých částí.", - "Je odolnější, tiché, úspornější a rychlejší než HDD.", - "Buňky se opotřebovávají, počet zápisů je omezený.", - "Bývá dražší než plotnový disk stejné kapacity.", - NULL, - }, - }, - { - "2 / 3 • Buňky", "FTL, TRIM a záchrana", - "Tip: smazání smaže metadata. U SSD TRIM záchranu ztěžuje.", - { - "FTL rovnoměrně rozkládá zápisy, aby se buňky sjížděly stejně.", - "TRIM řekne disku, které bloky už nikdo nepoužívá, a zápis " - "se tím zrychlí.", - "Poškození může být hardwarové (mechanika, elektronika, " - "oheň, voda) nebo softwarové (smazání, formát, virus).", - "Smazání maže metadata, obsah na HDD často zůstane a dá " - "se obnovit.", - "U SSD je obnova kvůli TRIM obtížnější.", - NULL, - }, - }, - { - "3 / 3 • Přenos", "SSHD a USB flash", - "Tip: konektor USB flash disku je počítaný asi na 1500 cyklů.", - { - "SSHD je pevný disk s malou SSD částí, zhruba 8 GB.", - "Často používané soubory si přesune na rychlou část.", - "Dává smysl, když chcete kapacitu i rychlost za rozumnou cenu.", - "USB flash je malé médium na přenos dat po sběrnici USB.", - "Životnost buněk záleží na typu SLC, MLC nebo TLC a na " - "kvalitě hardwaru.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[23], "hw_unit24", "hw_unit24_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit24_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je hlavní výhoda SSD proti HDD?", - {"Má plotny a je hlučnější", - "Nemá pohyblivé části, je tiché a rychlejší", - "Data ztratí při vypnutí", - "Nejde ho použít jako systémový disk"}, - 4, 1}, - {"Jaká je nevýhoda SSD?", - {"Buňky se opotřebovávají a disk bývá dražší", - "Musí se defragmentovat každý den", - "Nepřežije přesun po stole", - "Nemá TRIM ani FTL"}, - 4, 0}, - {"Co dělá příkaz TRIM?", - {"Zvýší otáčky ploten", - "Smaže BIOS", - "Oznámí SSD, které bloky už nejsou použité", - "Zapne fantomové napájení"}, - 4, 2}, - {"Co je SSHD?", - {"Jen jiný název pro disketu", - "HDD doplněné o malou SSD část, asi 8 GB", - "Optický disk s modrým laserem", - "Paměťová karta SD"}, - 4, 1}, - }; - static const char *hints[] = { - "SSD = bez pohyblivých částí", - "Buňky se sjíždějí a cena je vyšší", - "TRIM hlásí volné bloky", - "SSHD = HDD + asi 8 GB SSD", - }; - return build_hw_mcq_page(23, "hwunit24", "hw_ex24_title", "hw_quiz24_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit25_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Přehled", "Výměnná média", - "Tip: páska se musí převinout, proto se hodí na archiv, ne na denní práci.", - { - "Mechanická média: děrné štítky a děrné pásky.", - "Magnetická: pásky a diskety.", - "Optická: CD, DVD a Blu-ray.", - "Elektrická: paměťové karty a USB flash.", - "K souboru na pásce nejde skočit, páska se na místo přetočí.", - NULL, - }, - }, - { - "2 / 3 • Pásky", "Magnetická páska", - "Tip: páska pořád slouží velkým firmám na dlouhodobou zálohu.", - { - "Jedna raná páska unesla data asi deseti tisíc děrných štítků.", - "Kapacita začínala u stovek kilobajtů, třeba 850 kB.", - "Dlouho měla vyšší kapacitu než pevné disky; zlom přišel " - "kolem roku 2010 s terabajtovými disky.", - "Podle IBM ji v USA používá přímo nebo nepřímo až 82 % " - "velkých firem.", - "Odhad je stovky miliard gigabajtů dat na páskách po světě.", - "Sklad CSCS v Curychu má 27 PB na 17 000 páskách LTO-5 " - "po 1500 GB.", - NULL, - }, - }, - { - "3 / 3 • Diskety", "Z pásky na kotouč", - "Tip: ikona ukládání je 3,5\" disketa.", - { - "Stopa se přesunula na otáčející se mylarový kotouč.", - "Soustředné stopy umožní náhodný přístup, ne jen převíjení.", - "8\" disketa (1971) měla 100 kB a zápis z jedné strany.", - "5,25\" (1976) se dala poslat poštou; kapacita 80 až 1200 kB.", - "3,5\" zavedla Sony v roce 1981.", - "Standard 1990–1995 je 1,44 MB, pevný obal a dvířka, " - "vloží se jen správně.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[24], "hw_unit25", "hw_unit25_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit25_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč se páska hodí na archiv a ne na běžnou práci?", - {"K souboru se musí převinout, přístup není náhodný", - "Nemá žádnou kapacitu", - "Nejde ji vyjmout z mechaniky", - "Maže se při každém čtení"}, - 4, 0}, - {"Jaká byla raná 8\" disketa?", - {"Z roku 1981 a měla 1,44 MB", - "Z roku 1971 a měla 100 kB", - "Z roku 2010 a měla 1 TB", - "Byla optická"}, - 4, 1}, - {"Co platí o 3,5\" disketě?", - {"Zavedla ji IBM v roce 1960 a měla 850 kB", - "Neměla pevný obal", - "Sony, 1981, standardně 1,44 MB", - "Šla vložit oběma směry"}, - 4, 2}, - {"Čím disketa zrychlila přístup proti pásce?", - {"Soustředné stopy dovolí náhodný přístup", - "Má modrý laser", - "Nemá magnetickou vrstvu", - "Čte se jen od konce"}, - 4, 0}, - }; - static const char *hints[] = { - "Páska je sekvenční", - "8\" = 1971, 100 kB", - "3,5\" = Sony 1981, 1,44 MB", - "Stopy na kotouči = náhodný přístup", - }; - return build_hw_mcq_page(24, "hwunit25", "hw_ex25_title", "hw_quiz25_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit26_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Laser", "Jak se čte optický disk", - "Tip: land odrazí paprsek (1), pit ho rozptýlí (0).", - { - "Kotouč má průměr 12 cm a tloušťku 1,2 mm.", - "Data leží ve spirále od středu ke kraji.", - "U 700MB CD je stopa dlouhá 6,244 km.", - "Spirála střídá pity (prohlubně) a landy (plochy).", - NULL, - }, - }, - { - "2 / 3 • Generace", "CD, DVD a Blu-ray", - "Tip: Blu-ray používá modrý laser 405 nm, DVD červený 650 nm.", - { - "CD má 650–870 MB. CD-R vypálí organické barvivo asi při " - "290 °C a zápis je nevratný.", - "CD-RW jde přepsat tisíckrát až stotisíckrát. Slitina " - "AgInSbTe mění krystaly zahřátím a chlazením.", - "DVD má 1,4 až 15,82 GB, stopu 11,84 km a umí dvě vrstvy " - "i obě strany.", - "Blu-ray má 25–128 GB. Kratší vlnová délka znamená hustší " - "záznam.", - "Optika ustoupila kvůli kapacitě, pomalému zápisu, " - "spolehlivosti a tomu, že obsah je online.", - NULL, - }, - }, - { - "3 / 3 • Karty", "Flash karty", - "Tip: NAND paměť vytlačila optické mechaniky.", - { - "Flash je statická vnější paměť: malá, s velkou kapacitou, " - "odolná vůči vibracím a magnetickému poli.", - "Buňky mají plovoucí hradlo: SLC, MLC, TLC nebo QLC.", - "Karty: SD (i mini a micro), MMC, Memory Stick a " - "CompactFlash.", - "Čtečka na USB mívá víc slotů, aby vzala víc formátů.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[25], "hw_unit26", "hw_unit26_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit26_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co se stane, když laser trefí land a když trefí pit?", - {"Obojí je signál 0", - "Land se odrazí jako 1, pit se rozptýlí jako 0", - "Land je 0 a pit je 1", - "Laser se na disku nepoužívá"}, - 4, 1}, - {"Jak se zapisuje CD-R?", - {"Vypálením barviva, zápis je nevratný", - "Magnetickou cívkou jako HDD", - "Libovolně mnohokrát jako RAM", - "Jen změnou názvu souboru"}, - 4, 0}, - {"Čím se laser Blu-ray liší od DVD?", - {"Má červený laser 650 nm a menší kapacitu", - "Nemá spirálu", - "Má modrý laser 405 nm a kapacitu 25–128 GB", - "Má stejný laser jako CD"}, - 4, 2}, - {"Které karty patří mezi flash média?", - {"Jen děrné štítky", - "SD, MMC, Memory Stick a CompactFlash", - "Jen 8\" diskety", - "Jen pásky LTO"}, - 4, 1}, - }; - static const char *hints[] = { - "Land = odraz = 1, pit = rozptyl = 0", - "CD-R pálí barvivo a nejde vrátit", - "Blu-ray: 405 nm, 25–128 GB", - "SD, MMC, MS, CF", - }; - return build_hw_mcq_page(25, "hwunit26", "hw_ex26_title", "hw_quiz26_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit27_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Vstup", "Polohovací zařízení a klávesnice", - "Tip: klávesnice má šest částí.", - { - "Polohovací zařízení hýbe kurzorem a bývá drátové i bezdrátové.", - "Hlavní písmenková část.", - "Speciální a české znaky.", - "Ovládací tlačítka a posunovací tlačítka.", - "Numerická klávesnice a funkční klávesy.", - NULL, - }, - }, - { - "2 / 2 • Typy", "Membrána, guma, nůžky a laser", - "Tip: scissor-switch je notebookový, mělký a tichý.", - { - "Membránová je nejčastější u stolních počítačů. Stisk " - "propojí membránu a je velmi tichá.", - "U vodivé gumy se guma prohne ke kontaktu a sepne obvod. " - "Pod ní je izolační destička a pozlacený kontakt.", - "Scissor-switch nemá gumovou membránu. Klávesa se propadne " - "po nůžkovém mechanismu.", - "Laserová klávesnice promítá rozložení na podložku a senzor " - "snímá stisk. Hodí se k mobilu.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[26], "hw_unit27", "hw_unit27_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit27_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Z kolika částí se skládá běžná klávesnice?", - {"Ze šesti", "Ze dvou", "Z dvanácti", "Jen z numerického bloku"}, - 4, 0}, - {"Jaká je membránová klávesnice?", - {"Nejhlučnější a jen pro notebooky", - "Nejpoužívanější u stolních počítačů a velmi tichá", - "Promítá se laserem", - "Nemá žádný kontakt"}, - 4, 1}, - {"Co je scissor-switch?", - {"Gumová membrána ve stolním PC", - "Laser na podložce", - "Notebookový nůžkový mechanismus, mělký a tichý stisk", - "Jen funkční klávesy"}, - 4, 2}, - {"Jak pracuje laserová klávesnice?", - {"Promítne rozložení a senzor snímá virtuální stisk", - "Používá vodivou gumu", - "Je jen mechanická s nejhlubším stiskem", - "Čte jen numerický blok"}, - 4, 0}, - }; - static const char *hints[] = { - "Šest částí: písmena, znaky, ovládání, posun, numerická, funkce", - "Membrána = nejčastější stolní, tichá", - "Scissor = nůžky, notebook", - "Laser promítá klávesy na podložku", - }; - return build_hw_mcq_page(26, "hwunit27", "hw_ex27_title", "hw_quiz27_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit28_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Kulička", "Kuličková myš", - "Tip: pohyb se měří prosvícením otvorů v kotoučcích.", - { - "Posuv otáčí kuličkou.", - "Kulička točí válečky pro osy x a y.", - "Kotoučky na válečcích mají otvory.", - "Infračervené diody otvory prosvěcují.", - "Senzory záblesky převedou na polohu.", - NULL, - }, - }, - { - "2 / 3 • Prostor", "Spaceball, trackball, tablet a digitizér", - "Tip: tablet pozná tlak, až ve stovkách až 1024 úrovních.", - { - "Spaceball má pohyb a rotaci po třech osách. V CAD a " - "grafice zvedá efektivitu zhruba o 30–50 %.", - "Trackball je jako obrácená kuličková myš. Na rychlý " - "a přesný pohyb se nehodí.", - "Tablet má síť vodičů, která reaguje na pero. Hodí se " - "do CAD a grafiky, kreslit jde i na LCD.", - "Digitizér je speciální myš na přesnou polohu a chce " - "speciální podložku. Měří odpor mezi ukazovátkem a podložkou.", - NULL, - }, - }, - { - "3 / 3 • Notebook", "Trackpoint a touchpad", - "Tip: trackpoint sedí mezi klávesami G, H a B.", - { - "Trackpoint je malý joystick a šetří místo.", - "Touchpad je nejčastější polohovací zařízení notebooku.", - "Snímá elektrickou kapacitu prstu.", - "Hotspoty na ploše mají zvláštní účel, třeba posuvník.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[27], "hw_unit28", "hw_unit28_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit28_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak kuličková myš pozná pohyb?", - {"Laserem na podložce bez kuličky", - "Kulička točí válečky a infračervené diody prosvěcují otvory", - "Jen kapacitou prstu", - "Měřením 48 V"}, - 4, 1}, - {"Kde je trackpoint?", - {"Mezi klávesami G, H a B", - "Na zadní stěně skříně", - "V optické mechanice", - "Jen u stolní myši"}, - 4, 0}, - {"Jak touchpad snímá prst?", - {"Kuličkou a válečky", - "Magnetickou páskou", - "Elektrickou kapacitou prstu", - "Fantomovým napájením"}, - 4, 2}, - {"Co umí grafický tablet?", - {"Jen zapnout počítač", - "Reaguje na pero a tlak, až 1024 úrovní", - "Nahradí napájecí zdroj", - "Čte jen děrné štítky"}, - 4, 1}, - }; - static const char *hints[] = { - "Kulička, válečky, IR diody", - "Trackpoint je mezi G, H a B", - "Touchpad měří kapacitu", - "Tablet: pero a tlak až 1024 úrovní", - }; - return build_hw_mcq_page(27, "hwunit28", "hw_ex28_title", "hw_quiz28_head", - qs, hints, 4); -} - -GtkWidget *build_hw_unit29_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Hry", "Gamepad, joystick a volant", - "Tip: force feedback přidá vibrace a nárazy.", - { - "Gamepad ovládá hry a mívá programovatelná tlačítka.", - "DualShock přidává vibrace.", - "Joystick je páka na základně. Dřív byl analogový, " - "dnes digitální.", - "Používá se i v letadlech nebo bagrech.", - "Volant napodobuje řízení: pedály, řadící páka a " - "programovatelná tlačítka.", - NULL, - }, - }, - { - "2 / 3 • Tělo", "Kinect", - "Tip: sleduje celé tělo ve 3D, ne jen ovladač v ruce.", - { - "Kombinuje RGB kameru, hloubkové čidlo, mikrofony a " - "vlastní procesor.", - "Sleduje pohyb celého těla v prostoru.", - "Reaguje na pokyny a pozná i změnu zabarvení hlasu a emoce.", - NULL, - }, - }, - { - "3 / 3 • Displej", "Odporová a kapacitní vrstva", - "Tip: kapacitního displeje se musíte dotknout vodivě, třeba prstem.", - { - "Odporová vrstva má tvrzenou a vodivou vrstvu, odporové " - "vrstvy, vymezovací bodovou síť a sklo.", - "Dotyk vrstvy přitlačí k sobě a obvod se sepne.", - "Kapacitní displej má dvě vodivé vrstvy pod napětím, " - "oddělené mezerou.", - "Chovají se jako kondenzátor a kolem sebe mají slabé pole.", - "Změna kapacity prozradí místo dotyku.", - "Funguje to s vodivým předmětem, ne s libovolným plastem.", - NULL, - }, - }, - }; - - return build_hw_unit_page(&hw_lessons[28], "hw_unit29", "hw_unit29_sub", - slides, G_N_ELEMENTS(slides)); -} - -GtkWidget *build_hw_unit29_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co přidává DualShock?", - {"Vibrace gamepadu", - "Optickou mechaniku", - "Slot PCIe", - "Magnetickou pásku"}, - 4, 0}, - {"Co je force feedback?", - {"Jen jiné rozlišení monitoru", - "Vibrace a nárazy u joysticku a volantu", - "Typ paměti DDR3", - "Způsob formátování disku"}, - 4, 1}, - {"Co Kinect sleduje?", - {"Jen stisk jedné klávesy", - "Jen otáčky pevného disku", - "Pohyb celého těla ve 3D, pomocí kamery, hloubky a mikrofonů", - "Jen napětí zdroje"}, - 4, 2}, - {"Čím se musíte dotknout kapacitního displeje?", - {"Vodivým předmětem, například prstem", - "Jen nevodivým plastem", - "Jen speciálním perem bez elektřiny", - "Děrnou páskou"}, - 4, 0}, - }; - static const char *hints[] = { - "DualShock = vibrace", - "Force feedback = vibrace a nárazy", - "Kinect: RGB, hloubka, mikrofony, tělo ve 3D", - "Kapacitní vrstva chce vodivý dotyk", - }; - return build_hw_mcq_page(28, "hwunit29", "hw_ex29_title", "hw_quiz29_head", - qs, hints, 4); -} diff --git a/src/i18n.c b/src/i18n.c deleted file mode 100644 index 3d4b562..0000000 --- a/src/i18n.c +++ /dev/null @@ -1,2640 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* i18n */ -/* ------------------------------------------------------------------ */ - - -void ex4_fill_sample(GtkWidget *label); - -GArray *i18n_binds; - - -const TrEntry tr_ui[] = { - {"back", "Zpět", "Back"}, - {"settings", "Nastavení", "Settings"}, - {"settings_title", "Nastavení", "Settings"}, - {"mode", "REŽIM", "MODE"}, - {"mode_dark", "Tmavý", "Dark"}, - {"mode_light", "Světlý", "Light"}, - {"theme", "TÉMA", "THEME"}, - {"language", "JAZYK", "LANGUAGE"}, - {"updates", "AKTUALIZACE", "UPDATES"}, - {"update_current", "Build %s", "Build %s"}, - {"update_checking", "Hledám aktualizace…", "Checking for updates…"}, - {"update_uptodate", "Máte nejnovější build (%s).", - "You are up to date (%s)."}, - {"update_available", "Je dostupný novější build (%s).", - "A newer build is available (%s)."}, - {"update_downloading", "Stahuji aktualizaci…", "Downloading the update…"}, - {"update_staged", "Aktualizace je připravená — restartujte aplikaci.", - "The update is ready — restart the app to finish."}, - {"update_check", "Zkontrolovat", "Check"}, - {"update_install", "Aktualizovat", "Update"}, - {"update_restart", "Restartovat", "Restart"}, - {"update_later", "Později", "Later"}, - {"update_failed", "Aktualizace se nepovedla.", "The update failed."}, - {"update_err_network", "Nepodařilo se zjistit nejnovější verzi.", - "Could not find out the latest version."}, - {"update_err_download", "Stahování se nepovedlo.", "The download failed."}, - {"update_err_curl", "V systému chybí curl, aktualizace nejsou dostupné.", - "curl is missing, so updates are unavailable."}, - {"update_err_unsupported", "Pro tuto platformu se build nepublikuje.", - "No build is published for this platform."}, - {"update_err_readonly", - "Do umístění aplikace nelze zapisovat. Přesuňte ji třeba do Aplikací.", - "The app's location is not writable. Move it somewhere else, for " - "example to Applications."}, - {"update_err_stage", "Aktualizaci nešlo připravit.", - "Could not prepare the update."}, - {"update_err_devbuild", "Tento build nepochází z repozitáře (dev).", - "This build did not come from the repository (dev)."}, - {"welcome_kicker", "Graduately", "Graduately"}, - {"welcome_title", "Maturita?\nTo dáme.", "Maturita?\nWe've got this."}, - {"welcome_body", - "Procvičování k maturitě v jednom okně. Česky i anglicky, " - "napsané v C studenty ze SSŠVT.", - "Exam practice in one window. Czech and English, written in C " - "by students from SSŠVT."}, - {"welcome_body_android", - "Procvičování k maturitě v telefonu. Česky i anglicky, " - "stejný obsah jako na počítači.", - "Exam practice on your phone. Czech and English, " - "the same content as on the computer."}, - {"welcome_body_ios", - "Nativní procvičování na iPhonu. Česky i anglicky, " - "stejný obsah, rozhraní podle iOS.", - "Native exam practice on iPhone. Czech and English, " - "the same content, adapted to iOS."}, - {"welcome_body_macos", - "Nativní procvičování na Macu. Česky i anglicky, " - "stejný obsah, rozhraní podle macOS.", - "Native exam practice on the Mac. Czech and English, " - "the same content, adapted to macOS."}, - {"update_ios_sideload", - "Nový build je na GitHubu. Nainstalujte ho znovu přes Xcode nebo AltStore (%s).", - "A newer build is on GitHub. Reinstall it with Xcode or AltStore (%s)."}, - {"update_android_allow", - "Povolte této aplikaci instalovat aplikace a klepněte znovu na Aktualizovat.", - "Allow this app to install apps, then tap Update again."}, - {"update_android_installing", - "Systém teď nabídne instalaci nové verze (%s).", - "The system will now offer to install the new version (%s)."}, - {"update_err_badapk", - "Stažený soubor není platný build Graduately.", - "The downloaded file is not a valid Graduately build."}, - {"changelog_title", "Co je nového", "What's new"}, - {"changelog_dismiss", "Rozumím", "Got it"}, - {"welcome_feat1_title", "Efektivní procvičování", "Focused practice"}, - {"welcome_feat1_body", - "Cvičení, nápovědy a vokabeltraining. Aplikace si pamatuje, kde jste skončili.", - "Exercises, hints and vocabulary drills. The app remembers where you left off."}, - {"welcome_feat1_link", "Začít procvičovat", "Start practicing"}, - {"welcome_feat2_title", "Osm otevřených předmětů", "Eight open subjects"}, - {"welcome_feat2_body", - "Deutsch, sítě, hardware, čeština, občanská nauka, matematika, fyzika a přírodní vědy. Ostatní předměty čekají na svůj obsah.", - "German, networks, hardware, Czech, civics, mathematics, physics and natural sciences. The other subjects are still locked."}, - {"welcome_feat2_link", "Jaké předměty jsou otevřené?", "Which subjects are open?"}, - {"welcome_stat_value", "8", "8"}, - {"welcome_stat_label", "otevřené\npředměty", "open\nsubjects"}, - {"continue", "Pokračuj", "Continue"}, - {"roadmap_title", "Učební plán", "Learning path"}, - {"roadmap_sub", "Vyberte jednotku na cestě a začněte procvičovat.", - "Pick a unit on the path and start practicing."}, - {"unit1_sub", "Vyberte cvičení a dokončete je.", - "Choose an exercise and complete it."}, - {"check", "Zkontrolovat", "Check"}, - {"finish", "Dokončit", "Finish"}, - {"show_sample", "Ukázat vzor", "Show sample"}, - {"your_answer", "Vaše odpověď…", "Your answer…"}, - {"feedback_ok", "Výborně!", "Great!"}, - {"feedback_retry", "Ještě to není správně. Zkuste to znovu.", - "Not quite right yet. Try again."}, - {"feedback_retry_short", "Ještě to není správně.", "Not quite right yet."}, - {"feedback_sentences", "Některé věty nejsou správně. Zkuste to znovu.", - "Some sentences are not correct. Try again."}, - {"tip_ss", "Písmeno „ß“ se dá na klávesnici zaměnit za „ss“!", - "You can type “ss” instead of “ß” on the keyboard!"}, - {"hint_umlauts", - "Na klávesnici nemáte německé znaky? Můžete psát ä jako ae, ö jako oe, " - "ü jako ue a ß jako ss.", - "No German keyboard? You can type ä as ae, ö as oe, ü as ue and ß as " - "ss."}, - {"sample_fmt", "Otázka: %s\nVzor: %s (česky: %s)", - "Question: %s\nSample: %s (English: %s)"}, - {"sub_dialog", "Doplňte chybějící slova v dialogu.", - "Fill in the missing words in the dialogue."}, - {"sub_assembly", "Přetáhněte slova do správného pořadí.", - "Drag the words into the correct order."}, - {"sub_choice_num", "Vyberte správnou číslovku.", - "Choose the correct numeral."}, - {"sub_free", "Odpovězte vlastními slovy, poté klikněte na Dokončit.", - "Answer in your own words, then click Finish."}, - {"sub_zahlen", "Vyberte správné slovo pro dané číslo.", - "Choose the correct word for the given number."}, - {"sub_wieviel", "Spočítejte předměty a vyberte počet.", - "Count the items and choose the amount."}, - {"sub_reihe", "Doplňte chybějící číslovku.", - "Fill in the missing numeral."}, - {"sub_verb", "Vyberte správný tvar slovesa.", - "Choose the correct verb form."}, - {"sub_wer", "Vyberte správné tázací slovo.", - "Choose the correct question word."}, - {"sub_bild", "Vyberte správný tvar slovesa podle obrázku.", - "Choose the correct verb form for the picture."}, - {"sub_gruss", "Roztřiďte pozdravy na pozdravy a rozloučení.", - "Sort the phrases into greetings and farewells."}, - {"sub_land", "Přiřaďte symboly ke správné zemi.", - "Match the symbols to the correct country."}, - {"Vokabeltraining", NULL, "Vocabulary training"}, - {"sub_translate", - "Přeložte slovo. Špatná odpověď se vrátí na konec.", - "Translate the word. Wrong answers come back at the end."}, - {"trans_wrong", "Špatně. Správně: %s", "Wrong. Correct: %s"}, - {"trans_incomplete", "Nepřesné – něco chybí.", "Almost – something is missing."}, - {"trans_progress", "Hotovo: %d / %d", "Done: %d / %d"}, - {"trans_done", "Hotovo! Zvládl(a) jsi všechna slova.", - "Done! You mastered all the words."}, - {"assign_hint", - "Vyberte skupinu a klikněte na kartu. Kliknutím na kartu ve skupině " - "ji vrátíte zpět.", - "Pick a group and click a card. Click a card inside a group to send " - "it back."}, - {"unit2_sub", "Vyberte cvičení a dokončete je.", - "Choose an exercise and complete it."}, - {"Bei uns zu Hause", "Bei uns zu Hause", "At Home with Us"}, - {"unit3_sub", "Vyberte cvičení a dokončete je.", - "Choose an exercise and complete it."}, - {"sub3_pair", "Přiřaďte každému slovu jeho protějšek.", - "Match each word with its counterpart."}, - {"sub3_poss", "Doplňte přivlastňovací zájmena (1. pád).", - "Fill in the possessive pronouns (nominative)."}, - {"sub3_haustier", "Doplňte ein/kein ve správném tvaru.", - "Fill in ein/kein in the correct form."}, - {"sub3_buchst", "Doplňte chybějící písmena.", - "Fill in the missing letters."}, - {"sub3_marco", "Doplňte slova z nabídky.", - "Fill in the words from the box."}, - {"sub3_sort", "Roztřiďte slova do dvou skupin.", - "Sort the words into two groups."}, - {"sub3_tabelle", "Doplňte přivlastňovací zájmena do tabulky.", - "Fill the possessive pronouns into the table."}, - {"sub3_akk", "Doplňte přivlastňovací zájmena (4. pád).", - "Fill in the possessive pronouns (accusative)."}, - {"sub3_nicht", "Vyberte kein/keine/keinen/nicht.", - "Choose kein/keine/keinen/nicht."}, - {"sub3_satz", "Sestavte správné věty.", - "Build the correct sentences."}, - {"sub3_sehen", "Napište větu „Ich sehe…“.", - "Write an “Ich sehe…” sentence."}, - {"sub3_wem", "Komu to patří? Doplňte zájmeno.", - "Whose is it? Fill in the pronoun."}, - {"sub3_gibt", "Doplňte „Es gibt“ + ein/eine/einen.", - "Fill in “Es gibt” + ein/eine/einen."}, - {"sub3_saetze", "Doplňte věty podle vzoru.", - "Complete the sentences following the example."}, - {"sub3_wochen", "Doplňte chybějící písmena.", - "Fill in the missing letters."}, - {"wordbank", "Nabídka slov:", "Word bank:"}, - {"sample_line", "Příklad: %s", "Sample: %s"}, - {"sub_verben", "Doplňte sloveso ve správném tvaru.", - "Fill in the verb in the correct form."}, - {"sub_ausin", "Vyberte správnou předložku: aus nebo in.", - "Choose the correct preposition: aus or in."}, - {"sub_sprich", "Doplňte sloveso „sprechen“.", - "Fill in the verb “sprechen”."}, - {"sub_nation", "Doplňte národnost – použijte slova z nabídky.", - "Fill in the nationality – use the words in the box."}, - {"sub_woher", "Odkud lidé pocházejí? Napište zemi.", - "Where are the people from? Type the country."}, - {"sub_laender", "Doplňte chybějící písmena v názvech zemí.", - "Type the full country name (the missing letters are shown as _)."}, - {"sub_verb2", "Vyberte správný tvar slovesa.", - "Choose the correct verb form."}, - {"sub_euro", "Napište částku slovy.", - "Write the amount in words."}, - {"sub_wortsuchen", "Najděte skryté slovo a napište ho.", - "Find the hidden word and type it."}, - {"sub_ordne", "Přiřaďte správné tázací slovo a odpověď.", - "Match each phrase with the right question word and answer."}, - {"sub_luecke", "Doplňte chybějící slova do textu.", - "Fill the missing words into the text."}, - {"sub_verbinde", "Spojte každé podstatné jméno se správným slovesem.", - "Match each noun with the right verb."}, - {"sub_zahlpaar", "Spojte čísla s německými slovy.", - "Match the numbers with the German words."}, - {"sub_steckbrief", "Doplňte údaje o sobě.", - "Complete the information about yourself."}, - {"sub_berufe", "Hádejte povolání dřív, než bude oběšenec hotový.", - "Guess each job before the hangman drawing is finished."}, - {"sub_bistdu", "Odpovězte podle vlajky – jakou máte národnost?", - "Answer according to the flag – what is your nationality?"}, - {"hm_progress", "Slovo %d / %d", "Word %d / %d"}, - {"hm_hint", "Nápověda", "Hint"}, - {"hm_wrong", "Slovo je uhodnuto!", "Word guessed!"}, - {"hm_fail", "Oběšenec! Slovo bylo „%s“.", - "Hanged! The word was “%s”."}, - {"hm_retry", "Zkusit znovu", "Try again"}, - {"hm_done", "Výborně! Uhodli jste všechna povolání.", - "Great! You guessed all the jobs."}, - {"hm_guess", "Hádejte písmeno", "Guess a letter"}, - {"stats", "Statistiky", "Statistics"}, - {"stats_title", "Statistiky", "Statistics"}, - {"stats_sub", "Přehled vašeho pokroku.", "Overview of your progress."}, - {"mluv_sub", "Cvičení z mluvnice – styl maturita / přijímačky z ČJL", - "Grammar exercises in the style of the maturita and entrance exams"}, - {"stats_ex_label", "Cvičení", "Exercises"}, - {"stats_pct_label", "Hotovo", "Done"}, - {"stats_units_label", "Jednotky", "Units"}, - {"stats_section", "Předměty", "Subjects"}, - {"stats_locked", "Zamčeno", "Locked"}, - {"stats_complete", "Hotovo", "Complete"}, - {"stats_ex_fmt", "%d / %d", "%d / %d"}, - {"stats_pct_fmt", "%d %%", "%d %%"}, - {"stats_units_fmt", "%d / %d", "%d / %d"}, - {"search", "Hledat", "Search"}, - {"search_placeholder", "Hledat předmět, lekci nebo cvičení", - "Search a subject, lesson or exercise"}, - {"search_empty", "Nic se nenašlo", "No matches"}, - {"search_hint", "Zkuste předmět, lekci nebo název cvičení", - "Try a subject, lesson or exercise name"}, - {"search_subject", "Předmět", "Subject"}, - {"search_unit", "Jednotka", "Unit"}, - {"search_lesson", "Lekce", "Lesson"}, - {"search_exercise", "Cvičení", "Exercise"}, - {"search_book", "Četba", "Reading"}, - {"search_page", "Stránka", "Page"}, - {"search_home", "Úvod", "Welcome"}, - {"subjects_title", "Předměty", "Subjects"}, - {"subjects_sub", "Otevřený předmět spustí učební cestu. Zamčené zatím jen čekají.", - "An open subject opens its path. Locked ones are placeholders for now."}, - {"Český jazyk a literatura", "Český jazyk a literatura", - "Czech Language and Literature"}, - {"Občanská nauka", "Občanská nauka", "Civics"}, - {"English", "Angličtina", "English"}, - {"Deutsch", "Deutsch", "Deutsch"}, - {"Matematika", "Matematika", "Mathematics"}, - {"Fyzika", "Fyzika", "Physics"}, - {"Základy Přírodopisných věd", "Základy Přírodopisných věd", - "Fundamentals of Natural Sciences"}, - {"Technická grafika", "Technická grafika", "Technical Drawing"}, - {"Prezentační grafika", "Prezentační grafika", "Presentation Graphics"}, - {"Správa počítačových sítí", "Správa počítačových sítí", - "Computer Network Administration"}, - {"Programování", "Programování", "Programming"}, - {"Technické vybavení", "Technické vybavení", "Computer Hardware"}, - {"Programové vybavení", "Programové vybavení", "Software"}, - {"net_sub", "Vyberte lekci na cestě a začněte procvičovat.", - "Pick a unit on the path and start practicing."}, - {"net_years_title", "Správa počítačových sítí", - "Computer Network Administration"}, - {"net_years_sub", "Vyberte ročník a začněte procvičovat.", - "Pick a school year and start practicing."}, - {"net_year1", "1. ročník", "Year 1"}, - {"net_year2", "2. ročník", "Year 2"}, - {"net_year3", "3. ročník", "Year 3"}, - {"net_year4", "4. ročník", "Year 4"}, - {"net_year_locked_sub", "Zatím bez obsahu", - "No content yet"}, - {"net_unit1", "Výpočet IP adres", "IP Address Calculation"}, - {"net_unit1_sub", "4 snímky s postupem a pak cvičení.", - "4 slides with the method, then an exercise."}, - {"net_ex_title", "Cvičení: výpočet IP adres", - "Exercise: IP address calculation"}, - {"net_unit2", "Základní pojmy a rozdělení sítí", - "Basic concepts and network types"}, - {"net_unit2_sub", "5 snímků s pojmy a pak kvíz.", - "5 slides with the concepts, then a quiz."}, - {"net_ex2_title", "Kvíz: základní pojmy sítí", - "Quiz: basic networking concepts"}, - {"net_unit3", "Sítě Klient–Server a Cloud", - "Client–Server networks and Cloud"}, - {"net_unit3_sub", "4 snímky o serverech a cloudu a pak kvíz.", - "4 slides about servers and cloud, then a quiz."}, - {"net_ex3_title", "Kvíz: klient–server a cloud", - "Quiz: client–server and cloud"}, - {"net_unit4", "Přenos dat a jeho zabezpečení", - "Data transmission and security"}, - {"net_unit4_sub", "4 snímky o přenosu a zabezpečení a pak kvíz.", - "4 slides about transmission and security, then a quiz."}, - {"net_ex4_title", "Kvíz: přenos dat a zabezpečení", - "Quiz: data transmission and security"}, - {"net_unit5", "Signály a modulace", - "Signals and modulation"}, - {"net_unit5_sub", "4 snímky o signálech a modulaci a pak kvíz.", - "4 slides about signals and modulation, then a quiz."}, - {"net_ex5_title", "Kvíz: signály a modulace", - "Quiz: signals and modulation"}, - {"net_unit6", "Cesta, kanál a okruh", - "Path, channel and circuit"}, - {"net_unit6_sub", "4 snímky o cestě, kanálu a okruhu a pak kvíz.", - "4 slides about path, channel and circuit, then a quiz."}, - {"net_ex6_title", "Kvíz: cesta, kanál a okruh", - "Quiz: path, channel and circuit"}, - {"net_unit7", "Multiplex a směry přenosu", - "Multiplexing and transmission directions"}, - {"net_unit7_sub", "4 snímky o multiplexu a směrech a pak kvíz.", - "4 slides about multiplexing and directions, then a quiz."}, - {"net_ex7_title", "Kvíz: multiplex a směry přenosu", - "Quiz: multiplexing and transmission directions"}, - {"net_unit8", "Přepojování", - "Switching"}, - {"net_unit8_sub", "4 snímky o přepojování a pak kvíz.", - "4 slides about switching, then a quiz."}, - {"net_ex8_title", "Kvíz: přepojování", - "Quiz: switching"}, - {"net_unit9", "Vrstevnaté modely a protokoly", - "Layered models and protocols"}, - {"net_unit9_sub", "4 snímky o vrstvách a protokolech a pak kvíz.", - "4 slides about layers and protocols, then a quiz."}, - {"net_ex9_title", "Kvíz: vrstevnaté modely a protokoly", - "Quiz: layered models and protocols"}, - {"net_unit10", "Model ISO/OSI a TCP/IP", - "ISO/OSI and TCP/IP models"}, - {"net_unit10_sub", "3 snímky o ISO/OSI a TCP/IP a pak kvíz.", - "3 slides about ISO/OSI and TCP/IP, then a quiz."}, - {"net_ex10_title", "Kvíz: ISO/OSI a TCP/IP", - "Quiz: ISO/OSI and TCP/IP"}, - {"net_unit11", "Podrobný rozbor 7 vrstev ISO/OSI", - "Detailed review of the 7 ISO/OSI layers"}, - {"net_unit11_sub", "8 snímků o jednotlivých vrstvách a pak kvíz.", - "8 slides about each layer, then a quiz."}, - {"net_ex11_title", "Kvíz: 7 vrstev ISO/OSI", - "Quiz: 7 ISO/OSI layers"}, - {"net_unit12", "Základy architektury TCP/IP", - "Basics of TCP/IP architecture"}, - {"net_unit12_sub", "6 snímků o TCP/IP a protokolech a pak kvíz.", - "6 slides about TCP/IP and protocols, then a quiz."}, - {"net_ex12_title", "Kvíz: architektura TCP/IP", - "Quiz: TCP/IP architecture"}, - {"net_unit13", "Topologie sítě", - "Network topologies"}, - {"net_unit13_sub", "4 snímky o sběrnici, hvězdě a kruhu a pak kvíz.", - "4 slides about bus, star and ring, then a quiz."}, - {"net_ex13_title", "Kvíz: topologie sítě", - "Quiz: network topologies"}, - {"net_unit14", "Optika", - "Fiber optics"}, - {"net_unit14_sub", "5 snímků o optických vláknech a pak kvíz.", - "5 slides about optical fibers, then a quiz."}, - {"net_ex14_title", "Kvíz: optika", - "Quiz: fiber optics"}, - {"net_unit15", "Ochrana a montáž optiky", - "Fiber protection and installation"}, - {"net_unit15_sub", "3 snímky o ochraně a montáži a pak kvíz.", - "3 slides about protection and installation, then a quiz."}, - {"net_ex15_title", "Kvíz: ochrana a montáž optiky", - "Quiz: fiber protection and installation"}, - {"net_unit16", "Metody přístupu", - "Access methods"}, - {"net_unit16_sub", "4 snímky o kolizích a CSMA a pak kvíz.", - "4 slides about collisions and CSMA, then a quiz."}, - {"net_ex16_title", "Kvíz: metody přístupu", - "Quiz: access methods"}, - {"net_unit17", "Aktivní prvky", - "Active network devices"}, - {"net_unit17_sub", "7 snímků o hubu, switchi a routeru a pak kvíz.", - "7 slides about hubs, switches and routers, then a quiz."}, - {"net_ex17_title", "Kvíz: aktivní prvky", - "Quiz: active network devices"}, - {"net_unit18", "Switch (podrobně)", - "Switch in detail"}, - {"net_unit18_sub", "5 snímků o CAM a přepínání a pak kvíz.", - "5 slides about CAM and switching modes, then a quiz."}, - {"net_ex18_title", "Kvíz: switch podrobně", - "Quiz: switch in detail"}, - {"net_unit19", "Směrování (Routing)", - "Routing"}, - {"net_unit19_sub", "7 snímků o směrovacích algoritmech a pak kvíz.", - "7 slides about routing algorithms, then a quiz."}, - {"net_ex19_title", "Kvíz: směrování", - "Quiz: routing"}, - {"net_unit20", "Směrovač a brána", - "Router and gateway"}, - {"net_unit20_sub", "7 snímků o routeru a gateway a pak kvíz.", - "7 slides about routers and gateways, then a quiz."}, - {"net_ex20_title", "Kvíz: směrovač a brána", - "Quiz: router and gateway"}, - {"net_unit21", "Adresy a rámce v ethernetu", - "Ethernet addresses and frames"}, - {"net_unit21_sub", "8 snímků o MAC a typech rámců a pak kvíz.", - "8 slides about MAC and frame types, then a quiz."}, - {"net_ex21_title", "Kvíz: ethernet adresy a rámce", - "Quiz: Ethernet addresses and frames"}, - {"net_unit22", "Paket IP", - "IP packet"}, - {"net_unit22_sub", "8 snímků o IP datagramu a hlavičce a pak kvíz.", - "8 slides about the IP datagram and header, then a quiz."}, - {"net_ex22_title", "Kvíz: paket IP", - "Quiz: IP packet"}, - {"net_unit23", "ICMP", - "ICMP"}, - {"net_unit23_sub", "5 snímků o ICMP zprávách a traceroute a pak kvíz.", - "5 slides about ICMP messages and traceroute, then a quiz."}, - {"net_ex23_title", "Kvíz: ICMP", - "Quiz: ICMP"}, - {"net_unit24", "ARP", - "ARP"}, - {"net_unit24_sub", "5 snímků o ARP/RARP a cache a pak kvíz.", - "5 slides about ARP/RARP and cache, then a quiz."}, - {"net_ex24_title", "Kvíz: ARP", - "Quiz: ARP"}, - {"net_unit25", "TCP a UDP", - "TCP and UDP"}, - {"net_unit25_sub", "6 snímků o transportní vrstvě a pak kvíz.", - "6 slides about the transport layer, then a quiz."}, - {"net_ex25_title", "Kvíz: TCP a UDP", - "Quiz: TCP and UDP"}, - {"net_unit26", "Aplikační protokoly", - "Application protocols"}, - {"net_unit26_sub", "7 snímků o portech a službách a pak kvíz.", - "7 slides about ports and services, then a quiz."}, - {"net_ex26_title", "Kvíz: Aplikační protokoly", - "Quiz: Application protocols"}, - {"net_unit27", "Bezdrátové sítě", - "Wireless networks"}, - {"net_unit27_sub", "8 snímků o družicích, Wi-Fi a zabezpečení a pak kvíz.", - "8 slides about satellites, Wi-Fi and security, then a quiz."}, - {"net_ex27_title", "Kvíz: Bezdrátové sítě", - "Quiz: Wireless networks"}, - {"net_quiz_intro", - "Vyberte u každé otázky jednu správnou odpověď a stiskněte Zkontrolovat.", - "Choose one correct answer for each question and press Check."}, - {"net_quiz2_head", "Kvíz k základním pojmům sítí", - "Quiz on basic networking concepts"}, - {"net_quiz3_head", "Kvíz ke klient–server a cloudu", - "Quiz on client–server and cloud"}, - {"net_quiz4_head", "Kvíz k přenosu dat a zabezpečení", - "Quiz on data transmission and security"}, - {"net_quiz5_head", "Kvíz k signálům a modulaci", - "Quiz on signals and modulation"}, - {"net_quiz6_head", "Kvíz k cestě, kanálu a okruhu", - "Quiz on path, channel and circuit"}, - {"net_quiz7_head", "Kvíz k multiplexu a směrům přenosu", - "Quiz on multiplexing and transmission directions"}, - {"net_quiz8_head", "Kvíz k přepojování", - "Quiz on switching"}, - {"net_quiz9_head", "Kvíz k vrstevnatým modelům a protokolům", - "Quiz on layered models and protocols"}, - {"net_quiz10_head", "Kvíz k ISO/OSI a TCP/IP", - "Quiz on ISO/OSI and TCP/IP"}, - {"net_quiz11_head", "Kvíz k 7 vrstvám ISO/OSI", - "Quiz on the 7 ISO/OSI layers"}, - {"net_quiz12_head", "Kvíz k architektuře TCP/IP", - "Quiz on TCP/IP architecture"}, - {"net_quiz13_head", "Kvíz k topologiím sítě", - "Quiz on network topologies"}, - {"net_quiz14_head", "Kvíz k optice", - "Quiz on fiber optics"}, - {"net_quiz15_head", "Kvíz k ochraně a montáži optiky", - "Quiz on fiber protection and installation"}, - {"net_quiz16_head", "Kvíz k metodám přístupu", - "Quiz on access methods"}, - {"net_quiz17_head", "Kvíz k aktivním prvkům", - "Quiz on active network devices"}, - {"net_quiz18_head", "Kvíz ke switchi podrobně", - "Quiz on switches in detail"}, - {"net_quiz19_head", "Kvíz ke směrování", - "Quiz on routing"}, - {"net_quiz20_head", "Kvíz ke směrovači a bráně", - "Quiz on router and gateway"}, - {"net_quiz21_head", "Kvíz k ethernetovým adresám a rámcům", - "Quiz on Ethernet addresses and frames"}, - {"net_quiz22_head", "Kvíz k IP paketu", - "Quiz on the IP packet"}, - {"net_quiz23_head", "Kvíz k ICMP", - "Quiz on ICMP"}, - {"net_quiz24_head", "Kvíz k ARP", - "Quiz on ARP"}, - {"net_quiz25_head", "Kvíz k TCP a UDP", - "Quiz on TCP and UDP"}, - {"net_quiz26_head", "Kvíz k aplikačním protokolům", - "Quiz on application protocols"}, - {"net_quiz27_head", "Kvíz k bezdrátovým sítím", - "Quiz on wireless networks"}, - {"net_slide_next", "Další", "Next"}, - {"net_slide_prev", "Zpět", "Back"}, - {"net_slide_start", "Přejít na cvičení", "Go to the exercise"}, - {"net_solution", "Ukázat řešení", "Show solution"}, - {"net_infeasible", - "Toto zadání se do sítě /24 nevejde – vyzkoušej „Ukázat řešení“ a přečti si proč.", - "This assignment does not fit into a /24 network — tap “Show solution” to see why."}, - {"hw_sub", "Vyberte lekci na cestě a začněte procvičovat.", - "Pick a unit on the path and start practicing."}, - {"hw_years_sub", "Vyberte ročník a začněte procvičovat.", - "Pick a school year and start practicing."}, - {"hw_year1", "1. ročník", "Year 1"}, - {"hw_year2", "2. ročník", "Year 2"}, - {"hw_year3", "3. ročník", "Year 3"}, - {"hw_year4", "4. ročník", "Year 4"}, - {"hw_year_locked_sub", "Zatím bez obsahu", "No content yet"}, - {"hw_unit1", "Architektura počítače", "Computer architecture"}, - {"hw_unit1_sub", "3 snímky o Von Neumannovi a schématu a pak kvíz.", - "3 slides about von Neumann and the model, then a quiz."}, - {"hw_ex1_title", "Kvíz: architektura počítače", - "Quiz: computer architecture"}, - {"hw_quiz1_head", "Kvíz k architektuře počítače", - "Quiz on computer architecture"}, - {"hw_unit2", "Historie počítačů", "History of computers"}, - {"hw_unit2_sub", "6 snímků o generacích počítačů a pak kvíz.", - "6 slides about computer generations, then a quiz."}, - {"hw_ex2_title", "Kvíz: historie počítačů", - "Quiz: history of computers"}, - {"hw_quiz2_head", "Kvíz k historii počítačů", - "Quiz on the history of computers"}, - {"hw_unit3", "Zobrazování dat v počítači", "Data representation"}, - {"hw_unit3_sub", "2 snímky o bitu a bytu a pak kvíz.", - "2 slides about bits and bytes, then a quiz."}, - {"hw_ex3_title", "Kvíz: zobrazování dat", - "Quiz: data representation"}, - {"hw_quiz3_head", "Kvíz k zobrazování dat v počítači", - "Quiz on data representation in computers"}, - {"hw_unit4", "Celá a desetinná čísla", "Integers and reals"}, - {"hw_unit4_sub", "2 snímky o integer a real a pak kvíz.", - "2 slides about integer and real, then a quiz."}, - {"hw_ex4_title", "Kvíz: integer a real", - "Quiz: integer and real"}, - {"hw_quiz4_head", "Kvíz k celým a desetinným číslům", - "Quiz on integers and floating-point numbers"}, - {"hw_unit5", "Analogový a digitální zvuk", "Analog and digital sound"}, - {"hw_unit5_sub", "2 snímky o převodu zvuku na čísla a pak kvíz.", - "2 slides about turning sound into numbers, then a quiz."}, - {"hw_ex5_title", "Kvíz: analog a digitál", - "Quiz: analog and digital"}, - {"hw_quiz5_head", "Kvíz k analogovému a digitálnímu zvuku", - "Quiz on analog and digital sound"}, - {"hw_unit6", "Vzorkování", "Sampling"}, - {"hw_unit6_sub", "2 snímky o vzorkovací frekvenci a Nyquistovi a pak kvíz.", - "2 slides about sample rate and Nyquist, then a quiz."}, - {"hw_ex6_title", "Kvíz: vzorkování", - "Quiz: sampling"}, - {"hw_quiz6_head", "Kvíz ke vzorkování zvuku", - "Quiz on sampling sound"}, - {"hw_unit7", "Kvantování", "Quantization"}, - {"hw_unit7_sub", "2 snímky o bitové hloubce a kvantizační chybě a pak kvíz.", - "2 slides about bit depth and quantization error, then a quiz."}, - {"hw_ex7_title", "Kvíz: kvantování", - "Quiz: quantization"}, - {"hw_quiz7_head", "Kvíz ke kvantování zvuku", - "Quiz on quantizing sound"}, - {"hw_unit8", "PCM a datový tok", "PCM and data rate"}, - {"hw_unit8_sub", "2 snímky o PCM a velikosti záznamu a pak kvíz.", - "2 slides about PCM and recording size, then a quiz."}, - {"hw_ex8_title", "Kvíz: PCM a datový tok", - "Quiz: PCM and data rate"}, - {"hw_quiz8_head", "Kvíz k PCM a datovému toku", - "Quiz on PCM and data rate"}, - {"hw_unit9", "Aliasing a parametry", "Aliasing and formats"}, - {"hw_unit9_sub", "2 snímky o aliasingu a běžných formátech a pak kvíz.", - "2 slides about aliasing and common formats, then a quiz."}, - {"hw_ex9_title", "Kvíz: aliasing a parametry", - "Quiz: aliasing and formats"}, - {"hw_quiz9_head", "Kvíz k aliasingu a parametrům záznamu", - "Quiz on aliasing and recording formats"}, - {"hw_unit10", "Počítačová skříň", "Computer case"}, - {"hw_unit10_sub", "2 snímky o skříni, airflow a typech a pak kvíz.", - "2 slides about the case, airflow and types, then a quiz."}, - {"hw_ex10_title", "Kvíz: počítačová skříň", "Quiz: computer case"}, - {"hw_quiz10_head", "Kvíz k počítačové skříni", "Quiz on the computer case"}, - {"hw_unit11", "Napájecí zdroj", "Power supply"}, - {"hw_unit11_sub", "2 snímky o zdroji ATX a spotřebě a pak kvíz.", - "2 slides about the ATX supply and power draw, then a quiz."}, - {"hw_ex11_title", "Kvíz: napájecí zdroj", "Quiz: power supply"}, - {"hw_quiz11_head", "Kvíz k napájecímu zdroji", "Quiz on the power supply"}, - {"hw_unit12", "Základní deska", "Motherboard"}, - {"hw_unit12_sub", "2 snímky o desce, čipsetu a BIOSu a pak kvíz.", - "2 slides about the board, chipset and BIOS, then a quiz."}, - {"hw_ex12_title", "Kvíz: základní deska", "Quiz: motherboard"}, - {"hw_quiz12_head", "Kvíz k základní desce", "Quiz on the motherboard"}, - {"hw_unit13", "Konektory a sloty", "Connectors and slots"}, - {"hw_unit13_sub", "2 snímky o napájení, SATA a slotech a pak kvíz.", - "2 slides about power, SATA and slots, then a quiz."}, - {"hw_ex13_title", "Kvíz: konektory a sloty", "Quiz: connectors and slots"}, - {"hw_quiz13_head", "Kvíz ke konektorům a slotům", - "Quiz on connectors and slots"}, - {"hw_unit14", "Operační paměti", "Memory"}, - {"hw_unit14_sub", "2 snímky o RAM, SRAM a DRAM a pak kvíz.", - "2 slides about RAM, SRAM and DRAM, then a quiz."}, - {"hw_ex14_title", "Kvíz: paměti", "Quiz: memory"}, - {"hw_quiz14_head", "Kvíz k operačním pamětím", "Quiz on memory"}, - {"hw_unit15", "Procesor", "Processor"}, - {"hw_unit15_sub", "3 snímky o CPU, jádrech a chlazení a pak kvíz.", - "3 slides about the CPU, cores and cooling, then a quiz."}, - {"hw_ex15_title", "Kvíz: procesor", "Quiz: processor"}, - {"hw_quiz15_head", "Kvíz k procesoru", "Quiz on the processor"}, - {"hw_unit16", "Přídavné karty", "Expansion cards"}, - {"hw_unit16_sub", "2 snímky o kartách a slotech PCIe a pak kvíz.", - "2 slides about cards and PCIe slots, then a quiz."}, - {"hw_ex16_title", "Kvíz: přídavné karty", "Quiz: expansion cards"}, - {"hw_quiz16_head", "Kvíz k přídavným kartám", "Quiz on expansion cards"}, - {"hw_unit17", "Grafická karta", "Graphics card"}, - {"hw_unit17_sub", "3 snímky o obrazu, typech karet a cestě obrazu a pak kvíz.", - "3 slides about the image, card types and the image path, then a quiz."}, - {"hw_ex17_title", "Kvíz: grafická karta", "Quiz: graphics card"}, - {"hw_quiz17_head", "Kvíz ke grafické kartě", "Quiz on the graphics card"}, - {"hw_unit18", "Shadery a render", "Shaders and rendering"}, - {"hw_unit18_sub", "3 snímky o shaderech, renderu a CUDA a pak kvíz.", - "3 slides about shaders, rendering and CUDA, then a quiz."}, - {"hw_ex18_title", "Kvíz: shadery a render", "Quiz: shaders and rendering"}, - {"hw_quiz18_head", "Kvíz k shaderům a renderování", - "Quiz on shaders and rendering"}, - {"hw_unit19", "Paměť a sběrnice GPU", "GPU memory and bus"}, - {"hw_unit19_sub", "3 snímky o RAMDAC, GDDR a PCIe a pak kvíz.", - "3 slides about RAMDAC, GDDR and PCIe, then a quiz."}, - {"hw_ex19_title", "Kvíz: paměť a sběrnice GPU", "Quiz: GPU memory and bus"}, - {"hw_quiz19_head", "Kvíz k paměti a sběrnici GPU", - "Quiz on GPU memory and the bus"}, - {"hw_unit20", "Rozlišení obrazu", "Display resolutions"}, - {"hw_unit20_sub", "2 snímky o portech, rozlišení a SLI a pak kvíz.", - "2 slides about ports, resolutions and SLI, then a quiz."}, - {"hw_ex20_title", "Kvíz: rozlišení obrazu", "Quiz: display resolutions"}, - {"hw_quiz20_head", "Kvíz k rozlišení a více kartám", - "Quiz on resolutions and multi-GPU"}, - {"hw_unit21", "Zvuková karta", "Sound card"}, - {"hw_unit21_sub", "3 snímky o typech karet, čipu a nahrávání a pak kvíz.", - "3 slides about card types, the chip and recording, then a quiz."}, - {"hw_ex21_title", "Kvíz: zvuková karta", "Quiz: sound card"}, - {"hw_quiz21_head", "Kvíz ke zvukové kartě", "Quiz on the sound card"}, - {"hw_unit22", "Síťová a TV karta", "Network and TV cards"}, - {"hw_unit22_sub", "2 snímky o síťové a televizní kartě a pak kvíz.", - "2 slides about network and TV cards, then a quiz."}, - {"hw_ex22_title", "Kvíz: síťová a TV karta", "Quiz: network and TV cards"}, - {"hw_quiz22_head", "Kvíz k síťové a televizní kartě", - "Quiz on network and TV cards"}, - {"hw_unit23", "Pevný disk", "Hard drive"}, - {"hw_unit23_sub", "3 snímky o HDD, parametrech a struktuře dat a pak kvíz.", - "3 slides about HDDs, parameters and data layout, then a quiz."}, - {"hw_ex23_title", "Kvíz: pevný disk", "Quiz: hard drive"}, - {"hw_quiz23_head", "Kvíz k pevnému disku", "Quiz on the hard drive"}, - {"hw_unit24", "SSD a flash", "SSD and flash"}, - {"hw_unit24_sub", "3 snímky o SSD, TRIM, SSHD a USB a pak kvíz.", - "3 slides about SSD, TRIM, SSHD and USB, then a quiz."}, - {"hw_ex24_title", "Kvíz: SSD a flash", "Quiz: SSD and flash"}, - {"hw_quiz24_head", "Kvíz k SSD a flash paměti", "Quiz on SSD and flash"}, - {"hw_unit25", "Pásky a diskety", "Tapes and floppies"}, - {"hw_unit25_sub", "3 snímky o výměnných médiích, páskách a disketách a pak kvíz.", - "3 slides about removable media, tapes and floppies, then a quiz."}, - {"hw_ex25_title", "Kvíz: pásky a diskety", "Quiz: tapes and floppies"}, - {"hw_quiz25_head", "Kvíz k páskám a disketám", "Quiz on tapes and floppies"}, - {"hw_unit26", "Optická média", "Optical media"}, - {"hw_unit26_sub", "3 snímky o CD, DVD, Blu-ray a kartách a pak kvíz.", - "3 slides about CD, DVD, Blu-ray and memory cards, then a quiz."}, - {"hw_ex26_title", "Kvíz: optická média", "Quiz: optical media"}, - {"hw_quiz26_head", "Kvíz k optickým a flash médiím", - "Quiz on optical and flash media"}, - {"hw_unit27", "Klávesnice", "Keyboard"}, - {"hw_unit27_sub", "2 snímky o částech a typech klávesnic a pak kvíz.", - "2 slides about keyboard parts and types, then a quiz."}, - {"hw_ex27_title", "Kvíz: klávesnice", "Quiz: keyboard"}, - {"hw_quiz27_head", "Kvíz ke klávesnici", "Quiz on the keyboard"}, - {"hw_unit28", "Polohovací zařízení", "Pointing devices"}, - {"hw_unit28_sub", "3 snímky o myši, tabletu a touchpadu a pak kvíz.", - "3 slides about the mouse, tablet and touchpad, then a quiz."}, - {"hw_ex28_title", "Kvíz: polohovací zařízení", "Quiz: pointing devices"}, - {"hw_quiz28_head", "Kvíz k polohovacím zařízením", - "Quiz on pointing devices"}, - {"hw_unit29", "Herní ovladače a dotyk", "Game controls and touch"}, - {"hw_unit29_sub", "3 snímky o gamepadu, Kinectu a dotyku a pak kvíz.", - "3 slides about gamepads, Kinect and touch, then a quiz."}, - {"hw_ex29_title", "Kvíz: herní ovladače a dotyk", - "Quiz: game controls and touch"}, - {"hw_quiz29_head", "Kvíz k herním ovladačům a dotyku", - "Quiz on game controls and touch"}, - {"on_sub", "Člověk v lidském společenství. Vyberte lekci na cestě.", - "The individual and society. Pick a lesson on the path."}, - {"on_years_sub", "Vyberte ročník a začněte procvičovat.", - "Pick a school year and start practicing."}, - {"on_year1", "1. ročník", "Year 1"}, - {"on_year2", "2. ročník", "Year 2"}, - {"on_year3", "3. ročník", "Year 3"}, - {"on_year4", "4. ročník", "Year 4"}, - {"on_year_locked_sub", "Zatím bez obsahu", "No content yet"}, - {"on_unit1", "Výchova k občanství", "Civics"}, - {"on_unit1_sub", "2 snímky o smyslu předmětu a pak kvíz.", - "2 slides on what the subject is for, then a quiz."}, - {"on_ex1_title", "Kvíz: výchova k občanství", "Quiz: civics"}, - {"on_quiz1_head", "Kvíz k výchově k občanství", "Quiz on civics"}, - {"on_unit2", "Učení a volný čas", "Learning and free time"}, - {"on_unit2_sub", "2 snímky o učení a volném čase a pak kvíz.", - "2 slides on learning and free time, then a quiz."}, - {"on_ex2_title", "Kvíz: učení a volný čas", "Quiz: learning and free time"}, - {"on_quiz2_head", "Kvíz k učení a volnému času", - "Quiz on learning and free time"}, - {"on_unit3", "Osobnost člověka", "Personality"}, - {"on_unit3_sub", "2 snímky o osobnosti a socializaci a pak kvíz.", - "2 slides on personality and socialisation, then a quiz."}, - {"on_ex3_title", "Kvíz: osobnost člověka", "Quiz: personality"}, - {"on_quiz3_head", "Kvíz k osobnosti", "Quiz on personality"}, - {"on_unit4", "Etapy lidského života", "Stages of life"}, - {"on_unit4_sub", "2 snímky o etapách života a pak kvíz.", - "2 slides on the stages of life, then a quiz."}, - {"on_ex4_title", "Kvíz: etapy života", "Quiz: stages of life"}, - {"on_quiz4_head", "Kvíz k etapám života", "Quiz on the stages of life"}, - {"on_unit5", "Psychohygiena", "Mental hygiene"}, - {"on_unit5_sub", "2 snímky o náročných situacích a psychohygieně a pak kvíz.", - "2 slides on hard situations and mental hygiene, then a quiz."}, - {"on_ex5_title", "Kvíz: psychohygiena", "Quiz: mental hygiene"}, - {"on_quiz5_head", "Kvíz k psychohygieně", "Quiz on mental hygiene"}, - {"on_unit6", "Slušné chování", "Good manners"}, - {"on_unit6_sub", "2 snímky o etiketě a vztazích a pak kvíz.", - "2 slides on manners and relationships, then a quiz."}, - {"on_ex6_title", "Kvíz: slušné chování", "Quiz: good manners"}, - {"on_quiz6_head", "Kvíz ke slušnému chování", "Quiz on good manners"}, - {"on_unit7", "Komunikace a konflikty", "Communication and conflict"}, - {"on_unit7_sub", "2 snímky o komunikaci a konfliktech a pak kvíz.", - "2 slides on communication and conflict, then a quiz."}, - {"on_ex7_title", "Kvíz: komunikace a konflikty", - "Quiz: communication and conflict"}, - {"on_quiz7_head", "Kvíz ke komunikaci a konfliktům", - "Quiz on communication and conflict"}, - {"on_unit8", "Zdraví a životní styl", "Health and lifestyle"}, - {"on_unit8_sub", "2 snímky o zdraví a životním stylu a pak kvíz.", - "2 slides on health and lifestyle, then a quiz."}, - {"on_ex8_title", "Kvíz: zdraví a životní styl", "Quiz: health and lifestyle"}, - {"on_quiz8_head", "Kvíz ke zdraví a životnímu stylu", - "Quiz on health and lifestyle"}, - {"on_unit9", "Závislosti", "Addictions"}, - {"on_unit9_sub", "2 snímky o závislostech a pomoci a pak kvíz.", - "2 slides on addictions and where to get help, then a quiz."}, - {"on_ex9_title", "Kvíz: závislosti", "Quiz: addictions"}, - {"on_quiz9_head", "Kvíz k závislostem", "Quiz on addictions"}, - {"on_unit10", "Rodina a sociální skupiny", "Family and social groups"}, - {"on_unit10_sub", "2 snímky o skupinách a rodině a pak kvíz.", - "2 slides on groups and the family, then a quiz."}, - {"on_ex10_title", "Kvíz: rodina a skupiny", "Quiz: family and groups"}, - {"on_quiz10_head", "Kvíz k rodině a sociálním skupinám", - "Quiz on the family and social groups"}, - {"on_unit11", "Komunita, dav a veřejnost", "Community, crowd and the public"}, - {"on_unit11_sub", "2 snímky o komunitě, davu a veřejnosti a pak kvíz.", - "2 slides on community, crowds and the public, then a quiz."}, - {"on_ex11_title", "Kvíz: komunita a dav", "Quiz: community and crowds"}, - {"on_quiz11_head", "Kvíz ke komunitě, davu a veřejnosti", - "Quiz on community, crowds and the public"}, - {"on_unit12", "Vrstevníci a migrace", "Peers and migration"}, - {"on_unit12_sub", "2 snímky o vrstevnících, solidaritě a migraci a pak kvíz.", - "2 slides on peers, solidarity and migration, then a quiz."}, - {"on_ex12_title", "Kvíz: vrstevníci a migrace", "Quiz: peers and migration"}, - {"on_quiz12_head", "Kvíz k vrstevníkům a migraci", - "Quiz on peers and migration"}, - {"on_unit13", "Společnost a nerovnost", "Society and inequality"}, - {"on_unit13_sub", "2 snímky o společnosti, vrstvách a chudobě a pak kvíz.", - "2 slides on society, strata and poverty, then a quiz."}, - {"on_ex13_title", "Kvíz: společnost a nerovnost", - "Quiz: society and inequality"}, - {"on_quiz13_head", "Kvíz ke společnosti a nerovnosti", - "Quiz on society and inequality"}, - {"on_unit14", "Postavení mužů a žen", "Men, women and equality"}, - {"on_unit14_sub", "2 snímky o rovnosti a genderu a pak kvíz.", - "2 slides on equality and gender, then a quiz."}, - {"on_ex14_title", "Kvíz: postavení mužů a žen", "Quiz: men, women and equality"}, - {"on_quiz14_head", "Kvíz k postavení mužů a žen", - "Quiz on men, women and equality"}, - {"on_unit15", "Kultura", "Culture"}, - {"on_unit15_sub", "2 snímky o hmotné a duchovní kultuře a pak kvíz.", - "2 slides on material and non-material culture, then a quiz."}, - {"on_ex15_title", "Kvíz: kultura", "Quiz: culture"}, - {"on_quiz15_head", "Kvíz ke kultuře", "Quiz on culture"}, - {"on_unit16", "Víra a náboženství", "Faith and religion"}, - {"on_unit16_sub", "2 snímky o víře, církvích a sektách a pak kvíz.", - "2 slides on faith, churches and sects, then a quiz."}, - {"on_ex16_title", "Kvíz: víra a náboženství", "Quiz: faith and religion"}, - {"on_quiz16_head", "Kvíz k víře a náboženství", "Quiz on faith and religion"}, - {"on_unit17", "Rozpočet domácnosti", "Household budget"}, - {"on_unit17_sub", "2 snímky o rozpočtu a finanční tísni a pak kvíz.", - "2 slides on the household budget and money trouble, then a quiz."}, - {"on_ex17_title", "Kvíz: rozpočet domácnosti", "Quiz: household budget"}, - {"on_quiz17_head", "Kvíz k rozpočtu domácnosti", "Quiz on the household budget"}, - {"on2_sub", "Člověk jako občan v demokratickém státě. Vyberte lekci na cestě.", - "The citizen in a democratic state. Pick a lesson on the path."}, - {"on2_unit1", "Stát a občan", "The state and the citizen"}, - {"on2_unit1_sub", "2 snímky o státu a občanovi a pak kvíz.", - "2 slides on the state and the citizen, then a quiz."}, - {"on2_ex1_title", "Kvíz: stát a občan", "Quiz: the state and the citizen"}, - {"on2_quiz1_head", "Kvíz ke státu a občanovi", - "Quiz on the state and the citizen"}, - {"on2_unit2", "Státní občanství", "Citizenship"}, - {"on2_unit2_sub", "2 snímky o nabývání občanství a pak kvíz.", - "2 slides on how citizenship is acquired, then a quiz."}, - {"on2_ex2_title", "Kvíz: státní občanství", "Quiz: citizenship"}, - {"on2_quiz2_head", "Kvíz ke státnímu občanství", - "Quiz on citizenship"}, - {"on2_unit3", "Státní symboly", "State symbols"}, - {"on2_unit3_sub", "2 snímky o znacích, vlajce a hymně a pak kvíz.", - "2 slides on the arms, flag and anthem, then a quiz."}, - {"on2_ex3_title", "Kvíz: státní symboly", "Quiz: state symbols"}, - {"on2_quiz3_head", "Kvíz ke státním symbolům", - "Quiz on the state symbols"}, - {"on2_unit4", "Ústava České republiky", "The Constitution"}, - {"on2_unit4_sub", "2 snímky o ústavě a Listině a pak kvíz.", - "2 slides on the Constitution and the Charter, then a quiz."}, - {"on2_ex4_title", "Kvíz: ústava", "Quiz: the Constitution"}, - {"on2_quiz4_head", "Kvíz k ústavě", - "Quiz on the Constitution"}, - {"on2_unit5", "Dělba státní moci", "Separation of powers"}, - {"on2_unit5_sub", "2 snímky o složkách moci a pak kvíz.", - "2 slides on the branches of power, then a quiz."}, - {"on2_ex5_title", "Kvíz: dělba moci", "Quiz: separation of powers"}, - {"on2_quiz5_head", "Kvíz k dělbě moci", - "Quiz on the separation of powers"}, - {"on2_unit6", "Parlament", "Parliament"}, - {"on2_unit6_sub", "2 snímky o Sněmovně, Senátu a zákonech a pak kvíz.", - "2 slides on the Chamber, the Senate and laws, then a quiz."}, - {"on2_ex6_title", "Kvíz: Parlament", "Quiz: Parliament"}, - {"on2_quiz6_head", "Kvíz k Parlamentu", - "Quiz on Parliament"}, - {"on2_unit7", "Prezident a vláda", "President and government"}, - {"on2_unit7_sub", "2 snímky o hlavě státu a vládě a pak kvíz.", - "2 slides on the head of state and the government, then a quiz."}, - {"on2_ex7_title", "Kvíz: prezident a vláda", "Quiz: president and government"}, - {"on2_quiz7_head", "Kvíz k prezidentovi a vládě", - "Quiz on the president and the government"}, - {"on2_unit8", "Veřejná správa a samospráva", "Administration and self-government"}, - {"on2_unit8_sub", "2 snímky o úřadech, obci a kraji a pak kvíz.", - "2 slides on offices, the municipality and the region, then a quiz."}, - {"on2_ex8_title", "Kvíz: správa a samospráva", "Quiz: administration and self-government"}, - {"on2_quiz8_head", "Kvíz k veřejné správě a samosprávě", - "Quiz on administration and self-government"}, - {"on2_unit9", "Principy demokracie", "Principles of democracy"}, - {"on2_unit9_sub", "2 snímky o hodnotách demokracie a jejích ohroženích a pak kvíz.", - "2 slides on democratic values and what threatens them, then a quiz."}, - {"on2_ex9_title", "Kvíz: demokracie", "Quiz: democracy"}, - {"on2_quiz9_head", "Kvíz k principům demokracie", - "Quiz on the principles of democracy"}, - {"on2_unit10", "Lidská práva", "Human rights"}, - {"on2_unit10_sub", "2 snímky o Listině a ochraně práv a pak kvíz.", - "2 slides on the Charter and the protection of rights, then a quiz."}, - {"on2_ex10_title", "Kvíz: lidská práva", "Quiz: human rights"}, - {"on2_quiz10_head", "Kvíz k lidským právům", - "Quiz on human rights"}, - {"on2_unit11", "Práva dětí a ombudsman", "Children's rights and the ombudsman"}, - {"on2_unit11_sub", "2 snímky o právech dítěte a veřejném ochránci práv a pak kvíz.", - "2 slides on children's rights and the public defender of rights, then a quiz."}, - {"on2_ex11_title", "Kvíz: děti a ombudsman", "Quiz: children and the ombudsman"}, - {"on2_quiz11_head", "Kvíz k právům dětí a ombudsmanovi", - "Quiz on children's rights and the ombudsman"}, - {"on2_unit12", "Politické ideologie", "Political ideologies"}, - {"on2_unit12_sub", "2 snímky o hlavních politických směrech a pak kvíz.", - "2 slides on the main political outlooks, then a quiz."}, - {"on2_ex12_title", "Kvíz: ideologie", "Quiz: ideologies"}, - {"on2_quiz12_head", "Kvíz k politickým ideologiím", - "Quiz on political ideologies"}, - {"on2_unit13", "Politické strany a volby", "Parties and elections"}, - {"on2_unit13_sub", "2 snímky o stranách, volebním právu a systémech a pak kvíz.", - "2 slides on parties, the right to vote and electoral systems, then a quiz."}, - {"on2_ex13_title", "Kvíz: strany a volby", "Quiz: parties and elections"}, - {"on2_quiz13_head", "Kvíz ke stranám a volbám", - "Quiz on parties and elections"}, - {"on2_unit14", "Občanská společnost", "Civil society"}, - {"on2_unit14_sub", "2 snímky o spolcích a občanských ctnostech a pak kvíz.", - "2 slides on associations and civic virtues, then a quiz."}, - {"on2_ex14_title", "Kvíz: občanská společnost", "Quiz: civil society"}, - {"on2_quiz14_head", "Kvíz k občanské společnosti", - "Quiz on civil society"}, - {"on2_unit15", "Radikalismus a extremismus", "Radicalism and extremism"}, - {"on2_unit15_sub", "2 snímky o radikalismu, extremismu a terorismu a pak kvíz.", - "2 slides on radicalism, extremism and terrorism, then a quiz."}, - {"on2_ex15_title", "Kvíz: extremismus", "Quiz: extremism"}, - {"on2_quiz15_head", "Kvíz k radikalismu a extremismu", - "Quiz on radicalism and extremism"}, - {"on2_unit16", "Média", "The media"}, - {"on2_unit16_sub", "2 snímky o úloze médií a kritickém čtení a pak kvíz.", - "2 slides on the role of the media and reading them critically, then a quiz."}, - {"on2_ex16_title", "Kvíz: média", "Quiz: the media"}, - {"on2_quiz16_head", "Kvíz k médiím", - "Quiz on the media"}, - {"on3_sub", "Člověk a právo. Vyberte lekci na cestě.", - "The individual and the law. Pick a lesson on the path."}, - {"on3_unit1", "Právo a spravedlnost", "Law and justice"}, - {"on3_unit1_sub", "2 snímky o právu a spravedlnosti a pak kvíz.", - "2 slides on law and justice, then a quiz."}, - {"on3_ex1_title", "Kvíz: právo a spravedlnost", "Quiz: law and justice"}, - {"on3_quiz1_head", "Kvíz k právu a spravedlnosti", - "Quiz on law and justice"}, - {"on3_unit2", "Právní stát", "The rule of law"}, - {"on3_unit2_sub", "2 snímky o právním státu a pak kvíz.", - "2 slides on the rule of law, then a quiz."}, - {"on3_ex2_title", "Kvíz: právní stát", "Quiz: the rule of law"}, - {"on3_quiz2_head", "Kvíz k právnímu státu", - "Quiz on the rule of law"}, - {"on3_unit3", "Právní řád", "The legal order"}, - {"on3_unit3_sub", "2 snímky o předpisech a odvětvích práva a pak kvíz.", - "2 slides on legal rules and branches of law, then a quiz."}, - {"on3_ex3_title", "Kvíz: právní řád", "Quiz: the legal order"}, - {"on3_quiz3_head", "Kvíz k právnímu řádu", - "Quiz on the legal order"}, - {"on3_unit4", "Osoby a svéprávnost", "Persons and legal capacity"}, - {"on3_unit4_sub", "2 snímky o osobách, svéprávnosti a odpovědnosti a pak kvíz.", - "2 slides on persons, capacity and liability, then a quiz."}, - {"on3_ex4_title", "Kvíz: osoby a svéprávnost", "Quiz: persons and capacity"}, - {"on3_quiz4_head", "Kvíz k osobám a svéprávnosti", - "Quiz on persons and capacity"}, - {"on3_unit5", "Vlastnictví a škoda", "Ownership and damage"}, - {"on3_unit5_sub", "2 snímky o vlastnictví, duševním vlastnictví a škodě a pak kvíz.", - "2 slides on ownership, intellectual property and damage, then a quiz."}, - {"on3_ex5_title", "Kvíz: vlastnictví a škoda", "Quiz: ownership and damage"}, - {"on3_quiz5_head", "Kvíz k vlastnictví a škodě", - "Quiz on ownership and damage"}, - {"on3_unit6", "Smlouvy", "Contracts"}, - {"on3_unit6_sub", "2 snímky o smlouvách a pak kvíz.", - "2 slides on contracts, then a quiz."}, - {"on3_ex6_title", "Kvíz: smlouvy", "Quiz: contracts"}, - {"on3_quiz6_head", "Kvíz ke smlouvám", - "Quiz on contracts"}, - {"on3_unit7", "Spotřebitel", "The consumer"}, - {"on3_unit7_sub", "2 snímky o reklamaci a odstoupení od smlouvy a pak kvíz.", - "2 slides on complaints and withdrawing from a contract, then a quiz."}, - {"on3_ex7_title", "Kvíz: spotřebitel", "Quiz: the consumer"}, - {"on3_quiz7_head", "Kvíz ke spotřebiteli", - "Quiz on the consumer"}, - {"on3_unit8", "Dědictví", "Inheritance"}, - {"on3_unit8_sub", "2 snímky o dědění a dluzích a pak kvíz.", - "2 slides on inheritance and debts, then a quiz."}, - {"on3_ex8_title", "Kvíz: dědictví", "Quiz: inheritance"}, - {"on3_quiz8_head", "Kvíz k dědictví", - "Quiz on inheritance"}, - {"on3_unit9", "Rodina a právo", "Family and the law"}, - {"on3_unit9_sub", "2 snímky o manželství, partnerství a péči o dítě a pak kvíz.", - "2 slides on marriage, partnership and care of a child, then a quiz."}, - {"on3_ex9_title", "Kvíz: rodina a právo", "Quiz: family and the law"}, - {"on3_quiz9_head", "Kvíz k rodině a právu", - "Quiz on family and the law"}, - {"on3_unit10", "Pracovní právo", "Employment law"}, - {"on3_unit10_sub", "2 snímky o pracovní smlouvě, výpovědi a bezpečnosti a pak kvíz.", - "2 slides on the employment contract, notice and safety, then a quiz."}, - {"on3_ex10_title", "Kvíz: pracovní právo", "Quiz: employment law"}, - {"on3_quiz10_head", "Kvíz k pracovnímu právu", - "Quiz on employment law"}, - {"on3_unit11", "Soustava soudů", "The court system"}, - {"on3_unit11_sub", "2 snímky o soustavě soudů a pak kvíz.", - "2 slides on the court system, then a quiz."}, - {"on3_ex11_title", "Kvíz: soustava soudů", "Quiz: the court system"}, - {"on3_quiz11_head", "Kvíz k soustavě soudů", - "Quiz on the court system"}, - {"on3_unit12", "Soudní a správní řízení", "Court and administrative proceedings"}, - {"on3_unit12_sub", "2 snímky o žalobě, odvolání a správním řízení a pak kvíz.", - "2 slides on lawsuits, appeals and administrative proceedings, then a quiz."}, - {"on3_ex12_title", "Kvíz: řízení", "Quiz: proceedings"}, - {"on3_quiz12_head", "Kvíz k soudnímu a správnímu řízení", - "Quiz on court and administrative proceedings"}, - {"on3_unit13", "Právnická povolání", "Legal professions"}, - {"on3_unit13_sub", "2 snímky o soudci, žalobci, advokátovi, notáři a exekutorovi a pak kvíz.", - "2 slides on judges, prosecutors, lawyers, notaries and bailiffs, then a quiz."}, - {"on3_ex13_title", "Kvíz: právnická povolání", "Quiz: legal professions"}, - {"on3_quiz13_head", "Kvíz k právnickým povoláním", - "Quiz on legal professions"}, - {"on3_unit14", "Trestný čin a přestupek", "Crimes and misdemeanours"}, - {"on3_unit14_sub", "2 snímky o trestném činu, přestupku a vině a pak kvíz.", - "2 slides on crimes, misdemeanours and guilt, then a quiz."}, - {"on3_ex14_title", "Kvíz: trestný čin a přestupek", "Quiz: crimes and misdemeanours"}, - {"on3_quiz14_head", "Kvíz k trestnému činu a přestupku", - "Quiz on crimes and misdemeanours"}, - {"on3_unit15", "Tresty a trestní řízení", "Punishments and criminal procedure"}, - {"on3_unit15_sub", "2 snímky o trestech, vězení a průběhu řízení a pak kvíz.", - "2 slides on punishments, prison and the course of a case, then a quiz."}, - {"on3_ex15_title", "Kvíz: tresty a řízení", "Quiz: punishments and procedure"}, - {"on3_quiz15_head", "Kvíz k trestům a trestnímu řízení", - "Quiz on punishments and criminal procedure"}, - {"on3_unit16", "Mladiství, oběť a svědek", "Juveniles, victims and witnesses"}, - {"on3_unit16_sub", "2 snímky o mladistvých a o tom, co dělat jako oběť nebo svědek, a pak kvíz.", - "2 slides on juveniles and what to do as a victim or witness, then a quiz."}, - {"on3_ex16_title", "Kvíz: mladiství, oběť a svědek", "Quiz: juveniles, victims and witnesses"}, - {"on3_quiz16_head", "Kvíz k mladistvým, oběti a svědkovi", - "Quiz on juveniles, victims and witnesses"}, - {"on4_sub", "Hospodářství, svět a filozofie. Vyberte lekci na cestě.", - "The economy, the world and philosophy. Pick a lesson on the path."}, - {"on4_unit1", "Trh", "The market"}, - {"on4_unit1_sub", "2 snímky o nabídce, poptávce a ceně a pak kvíz.", - "2 slides on supply, demand and price, then a quiz."}, - {"on4_ex1_title", "Kvíz: trh", "Quiz: the market"}, - {"on4_quiz1_head", "Kvíz k trhu", - "Quiz on the market"}, - {"on4_unit2", "HDP a cyklus", "GDP and the cycle"}, - {"on4_unit2_sub", "2 snímky o hrubém domácím produktu, růstu a recesi a pak kvíz.", - "2 slides on gross domestic product, growth and recession, then a quiz."}, - {"on4_ex2_title", "Kvíz: HDP a cyklus", "Quiz: GDP and the cycle"}, - {"on4_quiz2_head", "Kvíz k HDP a cyklu", - "Quiz on GDP and the cycle"}, - {"on4_unit3", "Peníze a inflace", "Money and inflation"}, - {"on4_unit3_sub", "2 snímky o koruně, euru a inflaci a pak kvíz.", - "2 slides on the koruna, the euro and inflation, then a quiz."}, - {"on4_ex3_title", "Kvíz: peníze a inflace", "Quiz: money and inflation"}, - {"on4_quiz3_head", "Kvíz k penězům a inflaci", - "Quiz on money and inflation"}, - {"on4_unit4", "Banky a ČNB", "Banks and the CNB"}, - {"on4_unit4_sub", "2 snímky o centrální bance, úvěrech a ochraně vkladů a pak kvíz.", - "2 slides on the central bank, loans and deposit protection, then a quiz."}, - {"on4_ex4_title", "Kvíz: banky a ČNB", "Quiz: banks and the CNB"}, - {"on4_quiz4_head", "Kvíz k bankám a ČNB", - "Quiz on banks and the CNB"}, - {"on4_unit5", "Daně a rozpočet", "Taxes and the budget"}, - {"on4_unit5_sub", "2 snímky o daních, DPH, schodku a dluhu a pak kvíz.", - "2 slides on taxes, VAT, the deficit and the debt, then a quiz."}, - {"on4_ex5_title", "Kvíz: daně a rozpočet", "Quiz: taxes and the budget"}, - {"on4_quiz5_head", "Kvíz k daním a rozpočtu", - "Quiz on taxes and the budget"}, - {"on4_unit6", "Podnikání", "Enterprise"}, - {"on4_unit6_sub", "2 snímky o živnosti, s.r.o. a akciové společnosti a pak kvíz.", - "2 slides on trades, limited companies and joint-stock companies, then a quiz."}, - {"on4_ex6_title", "Kvíz: podnikání", "Quiz: enterprise"}, - {"on4_quiz6_head", "Kvíz k podnikání", - "Quiz on enterprise"}, - {"on4_unit7", "Trh práce", "The labour market"}, - {"on4_unit7_sub", "2 snímky o mzdě, nezaměstnanosti a Úřadu práce a pak kvíz.", - "2 slides on wages, unemployment and the Labour Office, then a quiz."}, - {"on4_ex7_title", "Kvíz: trh práce", "Quiz: the labour market"}, - {"on4_quiz7_head", "Kvíz k trhu práce", - "Quiz on the labour market"}, - {"on4_unit8", "Rozpočet domácnosti", "The household budget"}, - {"on4_unit8_sub", "2 snímky o příjmech, výdajích a rezervě a pak kvíz.", - "2 slides on income, spending and a reserve, then a quiz."}, - {"on4_ex8_title", "Kvíz: rozpočet domácnosti", "Quiz: the household budget"}, - {"on4_quiz8_head", "Kvíz k rozpočtu domácnosti", - "Quiz on the household budget"}, - {"on4_unit9", "Úvěry a pojištění", "Loans and insurance"}, - {"on4_unit9_sub", "2 snímky o úroku, RPSN a povinném pojištění a pak kvíz.", - "2 slides on interest, the APRC and compulsory insurance, then a quiz."}, - {"on4_ex9_title", "Kvíz: úvěry a pojištění", "Quiz: loans and insurance"}, - {"on4_quiz9_head", "Kvíz k úvěrům a pojištění", - "Quiz on loans and insurance"}, - {"on4_unit10", "Evropská unie", "The European Union"}, - {"on4_unit10_sub", "2 snímky o členství, Schengenu, euru a institucích a pak kvíz.", - "2 slides on membership, Schengen, the euro and the institutions, then a quiz."}, - {"on4_ex10_title", "Kvíz: Evropská unie", "Quiz: the European Union"}, - {"on4_quiz10_head", "Kvíz k Evropské unii", - "Quiz on the European Union"}, - {"on4_unit11", "NATO a OSN", "NATO and the UN"}, - {"on4_unit11_sub", "2 snímky o obranné alianci, společné obraně a OSN a pak kvíz.", - "2 slides on the defence alliance, collective defence and the UN, then a quiz."}, - {"on4_ex11_title", "Kvíz: NATO a OSN", "Quiz: NATO and the UN"}, - {"on4_quiz11_head", "Kvíz k NATO a OSN", - "Quiz on NATO and the UN"}, - {"on4_unit12", "Globalizace", "Globalisation"}, - {"on4_unit12_sub", "2 snímky o propojení světa, přínosech a rizicích a pak kvíz.", - "2 slides on an interconnected world, its benefits and its risks, then a quiz."}, - {"on4_ex12_title", "Kvíz: globalizace", "Quiz: globalisation"}, - {"on4_quiz12_head", "Kvíz ke globalizaci", - "Quiz on globalisation"}, - {"on4_unit13", "Filozofie", "Philosophy"}, - {"on4_unit13_sub", "2 snímky o filozofických otázkách, Sókratovi a Aristotelovi a pak kvíz.", - "2 slides on philosophical questions, Socrates and Aristotle, then a quiz."}, - {"on4_ex13_title", "Kvíz: filozofie", "Quiz: philosophy"}, - {"on4_quiz13_head", "Kvíz k filozofii", - "Quiz on philosophy"}, - {"on4_unit14", "Etika", "Ethics"}, - {"on4_unit14_sub", "2 snímky o mravnosti, svědomí, svobodě a odpovědnosti a pak kvíz.", - "2 slides on morality, conscience, freedom and responsibility, then a quiz."}, - {"on4_ex14_title", "Kvíz: etika", "Quiz: ethics"}, - {"on4_quiz14_head", "Kvíz k etice", - "Quiz on ethics"}, - {"on4_unit15", "Víra a svědomí", "Faith and conscience"}, - {"on4_unit15_sub", "2 snímky o víře, ateismu a svobodě svědomí a pak kvíz.", - "2 slides on faith, atheism and freedom of conscience, then a quiz."}, - {"on4_ex15_title", "Kvíz: víra a svědomí", "Quiz: faith and conscience"}, - {"on4_quiz15_head", "Kvíz k víře a svědomí", - "Quiz on faith and conscience"}, - {"on4_unit16", "Hodnoty", "Values"}, - {"on4_unit16_sub", "2 snímky o hodnotách, pravdě, solidaritě a svobodě a pak kvíz.", - "2 slides on values, truth, solidarity and freedom, then a quiz."}, - {"on4_ex16_title", "Kvíz: hodnoty", "Quiz: values"}, - {"on4_quiz16_head", "Kvíz k hodnotám", - "Quiz on values"}, - {"lit_years_sub", "Literatura podle osnov středních škol. Vyberte ročník.", - "Literature from the secondary-school syllabus. Pick a year."}, - {"lit_year1", "1. ročník", "Year 1"}, - {"lit_year2", "2. ročník", "Year 2"}, - {"lit_year3", "3. ročník", "Year 3"}, - {"lit_year4", "4. ročník", "Year 4"}, - {"lit_sub", "Od literární teorie po osvícenství.", - "From literary theory to the Enlightenment."}, - {"lit2_sub", "Od národního obrození k moderně.", - "From the National Revival to the modern movement."}, - {"lit3_sub", "První polovina 20. století.", - "The first half of the 20th century."}, - {"lit4_sub", "Od roku 1945 k interpretaci textu.", - "From 1945 to reading a text."}, - {"lit_unit1", "Základy literární teorie", "Basics of literary theory"}, - {"lit_unit1_sub", "Druhy, žánry, verš a obrazná pojmenování.", - "Genres, verse and figurative language."}, - {"lit_ex1_title", "Kvíz: literární teorie", "Quiz: literary theory"}, - {"lit_quiz1_head", "Ověřte si základy literární teorie", - "Check the basics of literary theory"}, - {"lit_unit2", "Starověké literatury", "Ancient literatures"}, - {"lit_unit2_sub", "Orient a Bible jako pramen evropské kultury.", - "The ancient East and the Bible."}, - {"lit_ex2_title", "Kvíz: starověk", "Quiz: antiquity"}, - {"lit_quiz2_head", "Ověřte si starověké literatury", - "Check the ancient literatures"}, - {"lit_unit3", "Antická literatura", "Classical literature"}, - {"lit_unit3_sub", "Řecký epos a drama, římská klasika.", - "Greek epic and drama, Roman classics."}, - {"lit_ex3_title", "Kvíz: antika", "Quiz: classical antiquity"}, - {"lit_quiz3_head", "Ověřte si antickou literaturu", - "Check classical literature"}, - {"lit_unit4", "Středověká literatura", "Medieval literature"}, - {"lit_unit4_sub", "Hrdinská epika, rytířská tvorba a Dante.", - "Heroic epic, courtly literature and Dante."}, - {"lit_ex4_title", "Kvíz: středověk", "Quiz: the Middle Ages"}, - {"lit_quiz4_head", "Ověřte si středověkou literaturu", - "Check medieval literature"}, - {"lit_unit5", "Česká literatura do husitství", "Early Czech literature"}, - {"lit_unit5_sub", "Staroslověnština, latina, čeština a husitství.", - "Old Church Slavonic, Latin, Czech and the Hussites."}, - {"lit_ex5_title", "Kvíz: počátky české literatury", - "Quiz: early Czech literature"}, - {"lit_quiz5_head", "Ověřte si literaturu do husitství", - "Check early Czech literature"}, - {"lit_unit6", "Humanismus a renesance", "Humanism and the Renaissance"}, - {"lit_unit6_sub", "Od Petrarky a Shakespeara k Bibli kralické.", - "From Petrarch and Shakespeare to the Kralice Bible."}, - {"lit_ex6_title", "Kvíz: renesance", "Quiz: the Renaissance"}, - {"lit_quiz6_head", "Ověřte si humanismus a renesanci", - "Check humanism and the Renaissance"}, - {"lit_unit7", "Baroko", "The Baroque"}, - {"lit_unit7_sub", "Kontrast, Bridel a Komenský.", - "Contrast, Bridel and Comenius."}, - {"lit_ex7_title", "Kvíz: baroko", "Quiz: the Baroque"}, - {"lit_quiz7_head", "Ověřte si barokní literaturu", - "Check Baroque literature"}, - {"lit_unit8", "Klasicismus a osvícenství", "Classicism and the Enlightenment"}, - {"lit_unit8_sub", "Pravidlo, rozum a preromantický cit.", - "Rules, reason and pre-Romantic feeling."}, - {"lit_ex8_title", "Kvíz: klasicismus", "Quiz: Classicism"}, - {"lit_quiz8_head", "Ověřte si klasicismus a osvícenství", - "Check Classicism and the Enlightenment"}, - {"lit2_unit1", "Národní obrození", "The Czech National Revival"}, - {"lit2_unit1_sub", "Obrana češtiny a Jungmannova generace.", - "Defending Czech and Jungmann's generation."}, - {"lit2_ex1_title", "Kvíz: národní obrození", "Quiz: the National Revival"}, - {"lit2_quiz1_head", "Ověřte si národní obrození", - "Check the National Revival"}, - {"lit2_unit2", "Světový romantismus", "Romanticism abroad"}, - {"lit2_unit2_sub", "Byron, Hugo, Puškin a Poe.", - "Byron, Hugo, Pushkin and Poe."}, - {"lit2_ex2_title", "Kvíz: světový romantismus", "Quiz: Romanticism abroad"}, - {"lit2_quiz2_head", "Ověřte si světový romantismus", - "Check Romanticism abroad"}, - {"lit2_unit3", "Český romantismus", "Czech Romanticism"}, - {"lit2_unit3_sub", "Mácha, Erben, Tyl, Němcová a Havlíček.", - "Mácha, Erben, Tyl, Němcová and Havlíček."}, - {"lit2_ex3_title", "Kvíz: český romantismus", "Quiz: Czech Romanticism"}, - {"lit2_quiz3_head", "Ověřte si český romantismus", - "Check Czech Romanticism"}, - {"lit2_unit4", "Realismus a naturalismus", "Realism and naturalism"}, - {"lit2_unit4_sub", "Balzac, Flaubert, Dickens, Tolstoj a Dostojevskij.", - "Balzac, Flaubert, Dickens, Tolstoy and Dostoevsky."}, - {"lit2_ex4_title", "Kvíz: realismus", "Quiz: realism"}, - {"lit2_quiz4_head", "Ověřte si realismus a naturalismus", - "Check realism and naturalism"}, - {"lit2_unit5", "Májovci", "The Máj generation"}, - {"lit2_unit5_sub", "Almanach Máj, Neruda, Hálek a Světlá.", - "The Máj almanac, Neruda, Hálek and Světlá."}, - {"lit2_ex5_title", "Kvíz: májovci", "Quiz: the Máj generation"}, - {"lit2_quiz5_head", "Ověřte si májovce", "Check the Máj generation"}, - {"lit2_unit6", "Ruchovci a lumírovci", "Ruchovci and lumírovci"}, - {"lit2_unit6_sub", "Čech, Vrchlický, Sládek a Zeyer.", - "Čech, Vrchlický, Sládek and Zeyer."}, - {"lit2_ex6_title", "Kvíz: ruchovci a lumírovci", "Quiz: ruchovci and lumírovci"}, - {"lit2_quiz6_head", "Ověřte si ruchovce a lumírovce", - "Check ruchovci and lumírovci"}, - {"lit2_unit7", "Česká próza 19. století", "Czech prose of the 19th century"}, - {"lit2_unit7_sub", "Rais, Jirásek a Maryša.", - "Rais, Jirásek and Maryša."}, - {"lit2_ex7_title", "Kvíz: český realismus", "Quiz: Czech realism"}, - {"lit2_quiz7_head", "Ověřte si českou prózu 19. století", - "Check Czech prose of the 19th century"}, - {"lit2_unit8", "Moderna a buřiči", "The modern movement and the rebels"}, - {"lit2_unit8_sub", "Baudelaire, česká moderna, Šrámek a Bezruč.", - "Baudelaire, the Czech modern movement, Šrámek and Bezruč."}, - {"lit2_ex8_title", "Kvíz: moderna", "Quiz: the modern movement"}, - {"lit2_quiz8_head", "Ověřte si modernu a buřiče", - "Check the modern movement and the rebels"}, - {"lit3_unit1", "Světová avantgarda", "The world avant-garde"}, - {"lit3_unit1_sub", "Futurismus, surrealismus a Apollinaire.", - "Futurism, surrealism and Apollinaire."}, - {"lit3_ex1_title", "Kvíz: avantgarda", "Quiz: the avant-garde"}, - {"lit3_quiz1_head", "Ověřte si světovou avantgardu", - "Check the world avant-garde"}, - {"lit3_unit2", "Světová próza mezi válkami", "World prose between the wars"}, - {"lit3_unit2_sub", "Ztracená generace, Kafka a experiment.", - "The Lost Generation, Kafka and experiment."}, - {"lit3_ex2_title", "Kvíz: meziválečná próza", "Quiz: interwar prose"}, - {"lit3_quiz2_head", "Ověřte si světovou prózu mezi válkami", - "Check world prose between the wars"}, - {"lit3_unit3", "Světové drama do roku 1945", "World drama to 1945"}, - {"lit3_unit3_sub", "Shaw, Pirandello a Brecht.", - "Shaw, Pirandello and Brecht."}, - {"lit3_ex3_title", "Kvíz: světové drama", "Quiz: world drama"}, - {"lit3_quiz3_head", "Ověřte si drama první poloviny století", - "Check drama of the early 20th century"}, - {"lit3_unit4", "První válka v české literatuře", "The First World War in Czech literature"}, - {"lit3_unit4_sub", "Hašek, legie a Wolker.", - "Hašek, the legions and Wolker."}, - {"lit3_ex4_title", "Kvíz: první válka", "Quiz: the First World War"}, - {"lit3_quiz4_head", "Ověřte si literaturu první války", - "Check literature of the First World War"}, - {"lit3_unit5", "Česká poezie mezi válkami", "Czech poetry between the wars"}, - {"lit3_unit5_sub", "Poetismus, surrealismus, Halas a Holan.", - "Poetism, surrealism, Halas and Holan."}, - {"lit3_ex5_title", "Kvíz: meziválečná poezie", "Quiz: interwar poetry"}, - {"lit3_quiz5_head", "Ověřte si českou poezii 1918–1938", - "Check Czech poetry of 1918–1938"}, - {"lit3_unit6", "Demokratický proud", "The democratic current"}, - {"lit3_unit6_sub", "Čapek, Vančura, Poláček a Olbracht.", - "Čapek, Vančura, Poláček and Olbracht."}, - {"lit3_ex6_title", "Kvíz: demokratický proud", "Quiz: the democratic current"}, - {"lit3_quiz6_head", "Ověřte si meziválečnou demokratickou prózu", - "Check interwar democratic prose"}, - {"lit3_unit7", "Psychologická a katolická próza", "Psychological and Catholic prose"}, - {"lit3_unit7_sub", "Havlíček, Durych a ruralismus.", - "Havlíček, Durych and ruralism."}, - {"lit3_ex7_title", "Kvíz: další próza", "Quiz: other prose"}, - {"lit3_quiz7_head", "Ověřte si psychologickou a katolickou prózu", - "Check psychological and Catholic prose"}, - {"lit3_unit8", "Literatura za okupace", "Literature under the occupation"}, - {"lit3_unit8_sub", "Orten a Skupina 42.", - "Orten and Group 42."}, - {"lit3_ex8_title", "Kvíz: okupace", "Quiz: the occupation"}, - {"lit3_quiz8_head", "Ověřte si literaturu za okupace", - "Check literature under the occupation"}, - {"lit4_unit1", "Světová próza po roce 1945", "World prose after 1945"}, - {"lit4_unit1_sub", "Orwell, Camus, Márquez a Solženicyn.", - "Orwell, Camus, Márquez and Solzhenitsyn."}, - {"lit4_ex1_title", "Kvíz: poválečná próza", "Quiz: postwar prose"}, - {"lit4_quiz1_head", "Ověřte si světovou prózu po roce 1945", - "Check world prose after 1945"}, - {"lit4_unit2", "Drama a postmoderna", "Drama and postmodernism"}, - {"lit4_unit2_sub", "Beckett, Dürrenmatt a Eco.", - "Beckett, Dürrenmatt and Eco."}, - {"lit4_ex2_title", "Kvíz: drama a postmoderna", "Quiz: drama and postmodernism"}, - {"lit4_quiz2_head", "Ověřte si absurdní drama a postmodernu", - "Check absurdist drama and postmodernism"}, - {"lit4_unit3", "Česká literatura 1945–1956", "Czech literature 1945–1956"}, - {"lit4_unit3_sub", "Krátká svoboda a budovatelský román.", - "A brief freedom and the construction novel."}, - {"lit4_ex3_title", "Kvíz: léta 1945–1956", "Quiz: 1945–1956"}, - {"lit4_quiz3_head", "Ověřte si literaturu let 1945–1956", - "Check literature of 1945–1956"}, - {"lit4_unit4", "Česká literatura 60. let", "Czech literature of the 1960s"}, - {"lit4_unit4_sub", "Hrabal, Kundera, Škvorecký a Fuks.", - "Hrabal, Kundera, Škvorecký and Fuks."}, - {"lit4_ex4_title", "Kvíz: 60. léta", "Quiz: the 1960s"}, - {"lit4_quiz4_head", "Ověřte si literaturu 60. let", - "Check the literature of the 1960s"}, - {"lit4_unit5", "Normalizace", "Normalization"}, - {"lit4_unit5_sub", "Oficiální tvorba, samizdat a exil.", - "Official writing, samizdat and exile."}, - {"lit4_ex5_title", "Kvíz: normalizace", "Quiz: Normalization"}, - {"lit4_quiz5_head", "Ověřte si tři proudy normalizace", - "Check the three currents of Normalization"}, - {"lit4_unit6", "Poezie a drama po roce 1945", "Poetry and drama after 1945"}, - {"lit4_unit6_sub", "Seifert, Havel a autorské divadlo.", - "Seifert, Havel and authorial theatre."}, - {"lit4_ex6_title", "Kvíz: poezie a drama", "Quiz: poetry and drama"}, - {"lit4_quiz6_head", "Ověřte si poválečnou poezii a drama", - "Check postwar poetry and drama"}, - {"lit4_unit7", "Literatura po roce 1989", "Literature after 1989"}, - {"lit4_unit7_sub", "Konec cenzury, Viewegh a Topol.", - "The end of censorship, Viewegh and Topol."}, - {"lit4_ex7_title", "Kvíz: literatura po roce 1989", "Quiz: literature after 1989"}, - {"lit4_quiz7_head", "Ověřte si literaturu po roce 1989", - "Check literature after 1989"}, - {"lit4_unit8", "Interpretace textu", "Interpreting a text"}, - {"lit4_unit8_sub", "Druh, jazyk, kontext a vlastní soud.", - "Genre, language, context and your own judgement."}, - {"lit4_ex8_title", "Kvíz: interpretace", "Quiz: interpretation"}, - {"lit4_quiz8_head", "Ověřte si postup rozboru textu", - "Check how to read a text"}, - {"sci_sub", "Vyberte chemii nebo biologii.", "Pick chemistry or biology."}, - {"Chemie", "Chemie", "Chemistry"}, - {"Biologie", "Biologie", "Biology"}, - {"chem_sub", "Osm lekcí od atomu po biochemii.", - "Eight lessons from the atom to biochemistry."}, - {"bio_sub", "Osm lekcí od buňky po ekologii.", - "Eight lessons from the cell to ecology."}, - {"chem_unit1", "Částice a periodická soustava", "Particles and the periodic table"}, - {"chem_unit1_sub", "Atom, protonové číslo, periody a skupiny.", - "The atom, atomic number, periods and groups."}, - {"chem_ex1_title", "Kvíz: částice", "Quiz: particles"}, - {"chem_quiz1_head", "Ověřte si stavbu atomu", "Check the structure of the atom"}, - {"chem_unit2", "Chemická vazba", "Chemical bonding"}, - {"chem_unit2_sub", "Iontová, kovalentní a kovová vazba.", - "Ionic, covalent and metallic bonds."}, - {"chem_ex2_title", "Kvíz: vazba", "Quiz: bonding"}, - {"chem_quiz2_head", "Ověřte si chemickou vazbu", "Check chemical bonding"}, - {"chem_unit3", "Reakce a výpočty", "Reactions and calculations"}, - {"chem_unit3_sub", "Zákon zachování hmotnosti, mol a molární hmotnost.", - "Conservation of mass, the mole and molar mass."}, - {"chem_ex3_title", "Kvíz: výpočty", "Quiz: calculations"}, - {"chem_quiz3_head", "Ověřte si mol a reakce", "Check the mole and reactions"}, - {"chem_unit4", "Směsi, roztoky a pH", "Mixtures, solutions and pH"}, - {"chem_unit4_sub", "Homogenní a heterogenní směsi, neutralizace.", - "Homogeneous and heterogeneous mixtures, neutralization."}, - {"chem_ex4_title", "Kvíz: roztoky", "Quiz: solutions"}, - {"chem_quiz4_head", "Ověřte si směsi a pH", "Check mixtures and pH"}, - {"chem_unit5", "Anorganické látky", "Inorganic substances"}, - {"chem_unit5_sub", "Oxidy, kyseliny, hydroxidy, soli a vybrané prvky.", - "Oxides, acids, hydroxides, salts and selected elements."}, - {"chem_ex5_title", "Kvíz: anorganika", "Quiz: inorganic chemistry"}, - {"chem_quiz5_head", "Ověřte si anorganické látky", "Check inorganic substances"}, - {"chem_unit6", "Uhlovodíky", "Hydrocarbons"}, - {"chem_unit6_sub", "Alkany, alkeny, alkyny a benzen.", - "Alkanes, alkenes, alkynes and benzene."}, - {"chem_ex6_title", "Kvíz: uhlovodíky", "Quiz: hydrocarbons"}, - {"chem_quiz6_head", "Ověřte si uhlovodíky", "Check hydrocarbons"}, - {"chem_unit7", "Deriváty a přírodní látky", "Derivatives and natural substances"}, - {"chem_unit7_sub", "Alkoholy, kyseliny, sacharidy a bílkoviny.", - "Alcohols, acids, carbohydrates and proteins."}, - {"chem_ex7_title", "Kvíz: deriváty", "Quiz: derivatives"}, - {"chem_quiz7_head", "Ověřte si deriváty a přírodní látky", - "Check derivatives and natural substances"}, - {"chem_unit8", "Biochemie", "Biochemistry"}, - {"chem_unit8_sub", "Enzymy, fotosyntéza, dýchání a nukleové kyseliny.", - "Enzymes, photosynthesis, respiration and nucleic acids."}, - {"chem_ex8_title", "Kvíz: biochemie", "Quiz: biochemistry"}, - {"chem_quiz8_head", "Ověřte si biochemii", "Check biochemistry"}, - {"bio_unit1", "Živé soustavy", "Living systems"}, - {"bio_unit1_sub", "Metabolismus a organizace od buňky k ekosystému.", - "Metabolism and organisation from the cell to the ecosystem."}, - {"bio_ex1_title", "Kvíz: živé soustavy", "Quiz: living systems"}, - {"bio_quiz1_head", "Ověřte si znaky života", "Check the features of life"}, - {"bio_unit2", "Buňka", "The cell"}, - {"bio_unit2_sub", "Prokaryota, eukaryota, organely a dělení.", - "Prokaryotes, eukaryotes, organelles and division."}, - {"bio_ex2_title", "Kvíz: buňka", "Quiz: the cell"}, - {"bio_quiz2_head", "Ověřte si stavbu buňky", "Check the structure of the cell"}, - {"bio_unit3", "Viry, bakterie, houby a rostliny", - "Viruses, bacteria, fungi and plants"}, - {"bio_unit3_sub", "Nebuněčné viry, prokaryota a autotrofní rostliny.", - "Acellular viruses, prokaryotes and autotrophic plants."}, - {"bio_ex3_title", "Kvíz: organismy", "Quiz: organisms"}, - {"bio_quiz3_head", "Ověřte si viry, houby a rostliny", - "Check viruses, fungi and plants"}, - {"bio_unit4", "Živočichové", "Animals"}, - {"bio_unit4_sub", "Bezobratlí a pět tříd obratlovců.", - "Invertebrates and five classes of vertebrates."}, - {"bio_ex4_title", "Kvíz: živočichové", "Quiz: animals"}, - {"bio_quiz4_head", "Ověřte si skupiny živočichů", "Check the animal groups"}, - {"bio_unit5", "Soustavy člověka", "Human body systems"}, - {"bio_unit5_sub", "Kostra, oběh, dýchání a trávení.", - "Skeleton, circulation, breathing and digestion."}, - {"bio_ex5_title", "Kvíz: člověk", "Quiz: the human body"}, - {"bio_quiz5_head", "Ověřte si soustavy člověka", "Check the human body systems"}, - {"bio_unit6", "Řízení, rozmnožování a imunita", - "Control, reproduction and immunity"}, - {"bio_unit6_sub", "Nervy, hormony, oplození a obrana organismu.", - "Nerves, hormones, fertilisation and the body's defence."}, - {"bio_ex6_title", "Kvíz: řízení", "Quiz: control"}, - {"bio_quiz6_head", "Ověřte si řízení a imunitu", "Check control and immunity"}, - {"bio_unit7", "Genetika", "Genetics"}, - {"bio_unit7_sub", "Gen, alela, Mendel a pohlavní chromozomy.", - "The gene, the allele, Mendel and the sex chromosomes."}, - {"bio_ex7_title", "Kvíz: genetika", "Quiz: genetics"}, - {"bio_quiz7_head", "Ověřte si dědičnost", "Check inheritance"}, - {"bio_unit8", "Ekologie", "Ecology"}, - {"bio_unit8_sub", "Ekosystém, potravní vztahy a člověk v prostředí.", - "The ecosystem, feeding relationships and humans in the environment."}, - {"bio_ex8_title", "Kvíz: ekologie", "Quiz: ecology"}, - {"bio_quiz8_head", "Ověřte si vztahy v ekosystému", - "Check relationships in an ecosystem"}, - {"fyz_years_sub", "Fyzika podle osnov středních škol. Vyberte ročník.", - "Physics from the secondary-school syllabus. Choose a year."}, - {"fyz_year1", "1. ročník", "Year 1"}, - {"fyz_year2", "2. ročník", "Year 2"}, - {"fyz_year3", "3. ročník", "Year 3"}, - {"fyz_year4", "4. ročník", "Year 4"}, - {"fyz_sub", "Mechanika: veličiny, pohyb, síly a energie.", - "Mechanics: quantities, motion, forces and energy."}, - {"fyz2_sub", "Molekulová fyzika, teplo, kmity a vlny.", - "Molecular physics, heat, oscillations and waves."}, - {"fyz3_sub", "Elektřina a magnetismus.", - "Electricity and magnetism."}, - {"fyz4_sub", "Optika, relativita, mikročástice a vesmír.", - "Optics, relativity, the micro-world and the universe."}, - {"fyz_unit1", "Fyzikální veličiny", "Physical quantities"}, - {"fyz_unit1_sub", "SI, skalár a vektor, chyba měření.", - "SI, scalar and vector, measurement error."}, - {"fyz_ex1_title", "Kvíz: veličiny", "Quiz: quantities"}, - {"fyz_quiz1_head", "Ověřte si jednotky a chyby", "Check units and errors"}, - {"fyz_unit2", "Kinematika", "Kinematics"}, - {"fyz_unit2_sub", "Dráha, rychlost a zrychlení.", - "Distance, speed and acceleration."}, - {"fyz_ex2_title", "Kvíz: kinematika", "Quiz: kinematics"}, - {"fyz_quiz2_head", "Ověřte si pohyb", "Check motion"}, - {"fyz_unit3", "Newtonovy zákony", "Newton's laws"}, - {"fyz_unit3_sub", "Setrvačnost, síla a hybnost.", - "Inertia, force and momentum."}, - {"fyz_ex3_title", "Kvíz: Newton", "Quiz: Newton"}, - {"fyz_quiz3_head", "Ověřte si zákony síly", "Check the laws of force"}, - {"fyz_unit4", "Síly v běžných situacích", "Everyday forces"}, - {"fyz_unit4_sub", "Tíha, tření, tlak a výslednice.", - "Weight, friction, pressure and the resultant."}, - {"fyz_ex4_title", "Kvíz: síly", "Quiz: forces"}, - {"fyz_quiz4_head", "Ověřte si tíhu a tlak", "Check weight and pressure"}, - {"fyz_unit5", "Práce, energie a výkon", "Work, energy and power"}, - {"fyz_unit5_sub", "Mechanická práce, energie a účinnost.", - "Mechanical work, energy and efficiency."}, - {"fyz_ex5_title", "Kvíz: energie", "Quiz: energy"}, - {"fyz_quiz5_head", "Ověřte si práci a výkon", "Check work and power"}, - {"fyz_unit6", "Gravitační pole", "Gravitational field"}, - {"fyz_unit6_sub", "Newtonův gravitační zákon a kosmické rychlosti.", - "Newton's law of gravitation and cosmic speeds."}, - {"fyz_ex6_title", "Kvíz: gravitace", "Quiz: gravity"}, - {"fyz_quiz6_head", "Ověřte si gravitační pole", "Check the gravitational field"}, - {"fyz_unit7", "Tuhé těleso", "Rigid body"}, - {"fyz_unit7_sub", "Moment síly, páka a těžiště.", - "Moment of a force, the lever and the centre of gravity."}, - {"fyz_ex7_title", "Kvíz: tuhé těleso", "Quiz: the rigid body"}, - {"fyz_quiz7_head", "Ověřte si otáčení", "Check rotation"}, - {"fyz_unit8", "Kapaliny a plyny", "Liquids and gases"}, - {"fyz_unit8_sub", "Hydrostatika, Archimédés a Bernoulli.", - "Hydrostatics, Archimedes and Bernoulli."}, - {"fyz_ex8_title", "Kvíz: tekutiny", "Quiz: fluids"}, - {"fyz_quiz8_head", "Ověřte si tlak v kapalině", "Check pressure in a liquid"}, - {"fyz2_unit1", "Částicová stavba", "Particle structure"}, - {"fyz2_unit1_sub", "Brownův pohyb, skupenství a vnitřní energie.", - "Brownian motion, states of matter and internal energy."}, - {"fyz2_ex1_title", "Kvíz: částice", "Quiz: particles"}, - {"fyz2_quiz1_head", "Ověřte si stavbu látky", "Check the structure of matter"}, - {"fyz2_unit2", "Teplota a teplo", "Temperature and heat"}, - {"fyz2_unit2_sub", "Kelvin, měrná tepelná kapacita a šíření tepla.", - "The kelvin, specific heat capacity and heat transfer."}, - {"fyz2_ex2_title", "Kvíz: teplo", "Quiz: heat"}, - {"fyz2_quiz2_head", "Ověřte si teplotu a teplo", "Check temperature and heat"}, - {"fyz2_unit3", "Kalorimetrie", "Calorimetry"}, - {"fyz2_unit3_sub", "Směšování, skupenské teplo a první zákon.", - "Mixing, latent heat and the first law."}, - {"fyz2_ex3_title", "Kvíz: kalorimetrie", "Quiz: calorimetry"}, - {"fyz2_quiz3_head", "Ověřte si tepelnou výměnu", "Check heat exchange"}, - {"fyz2_unit4", "Ideální plyn", "Ideal gas"}, - {"fyz2_unit4_sub", "Stavová rovnice a děje.", - "The equation of state and processes."}, - {"fyz2_ex4_title", "Kvíz: plyn", "Quiz: gases"}, - {"fyz2_quiz4_head", "Ověřte si stavovou rovnici", "Check the equation of state"}, - {"fyz2_unit5", "Pevné látky a kapaliny", "Solids and liquids"}, - {"fyz2_unit5_sub", "Hooke, roztažnost a povrchové napětí.", - "Hooke, expansion and surface tension."}, - {"fyz2_ex5_title", "Kvíz: látky", "Quiz: materials"}, - {"fyz2_quiz5_head", "Ověřte si deformaci a povrch", "Check deformation and surfaces"}, - {"fyz2_unit6", "Změny skupenství", "Changes of state"}, - {"fyz2_unit6_sub", "Tání, var a vlhkost vzduchu.", - "Melting, boiling and humidity."}, - {"fyz2_ex6_title", "Kvíz: skupenství", "Quiz: states of matter"}, - {"fyz2_quiz6_head", "Ověřte si tání a var", "Check melting and boiling"}, - {"fyz2_unit7", "Mechanické kmitání", "Mechanical oscillations"}, - {"fyz2_unit7_sub", "Pružina, kyvadlo a rezonance.", - "The spring, the pendulum and resonance."}, - {"fyz2_ex7_title", "Kvíz: kmity", "Quiz: oscillations"}, - {"fyz2_quiz7_head", "Ověřte si oscilátor", "Check the oscillator"}, - {"fyz2_unit8", "Vlnění a zvuk", "Waves and sound"}, - {"fyz2_unit8_sub", "Vlnová délka, frekvence a slyšitelný zvuk.", - "Wavelength, frequency and audible sound."}, - {"fyz2_ex8_title", "Kvíz: zvuk", "Quiz: sound"}, - {"fyz2_quiz8_head", "Ověřte si vlnění", "Check waves"}, - {"fyz3_unit1", "Elektrický náboj a pole", "Electric charge and field"}, - {"fyz3_unit1_sub", "Coulombův zákon a napětí.", - "Coulomb's law and voltage."}, - {"fyz3_ex1_title", "Kvíz: náboj", "Quiz: charge"}, - {"fyz3_quiz1_head", "Ověřte si elektrické pole", "Check the electric field"}, - {"fyz3_unit2", "Proud v kovech", "Current in metals"}, - {"fyz3_unit2_sub", "Ohmův zákon a odpor.", - "Ohm's law and resistance."}, - {"fyz3_ex2_title", "Kvíz: proud", "Quiz: current"}, - {"fyz3_quiz2_head", "Ověřte si Ohmův zákon", "Check Ohm's law"}, - {"fyz3_unit3", "Elektrické obvody", "Electric circuits"}, - {"fyz3_unit3_sub", "Sériové a paralelní spojení, výkon.", - "Series and parallel connection, power."}, - {"fyz3_ex3_title", "Kvíz: obvody", "Quiz: circuits"}, - {"fyz3_quiz3_head", "Ověřte si zapojení", "Check the connections"}, - {"fyz3_unit4", "Polovodiče, kapaliny a plyny", - "Semiconductors, liquids and gases"}, - {"fyz3_unit4_sub", "Dioda, elektrolýza a výboj.", - "The diode, electrolysis and discharge."}, - {"fyz3_ex4_title", "Kvíz: vodivost", "Quiz: conduction"}, - {"fyz3_quiz4_head", "Ověřte si polovodiče a ionty", - "Check semiconductors and ions"}, - {"fyz3_unit5", "Magnetické pole", "Magnetic field"}, - {"fyz3_unit5_sub", "Indukční čáry a síla na vodič.", - "Field lines and the force on a wire."}, - {"fyz3_ex5_title", "Kvíz: magnetismus", "Quiz: magnetism"}, - {"fyz3_quiz5_head", "Ověřte si magnetické pole", "Check the magnetic field"}, - {"fyz3_unit6", "Elektromagnetická indukce", "Electromagnetic induction"}, - {"fyz3_unit6_sub", "Faraday, Lenz a transformátor.", - "Faraday, Lenz and the transformer."}, - {"fyz3_ex6_title", "Kvíz: indukce", "Quiz: induction"}, - {"fyz3_quiz6_head", "Ověřte si indukci", "Check induction"}, - {"fyz3_unit7", "Střídavý proud", "Alternating current"}, - {"fyz3_unit7_sub", "Efektivní hodnota a fáze.", - "The rms value and phase."}, - {"fyz3_ex7_title", "Kvíz: střídavý proud", "Quiz: alternating current"}, - {"fyz3_quiz7_head", "Ověřte si síť 230 V", "Check the 230 V grid"}, - {"fyz3_unit8", "Elektromagnetické vlnění", "Electromagnetic waves"}, - {"fyz3_unit8_sub", "Rychlost světla a spektrum.", - "The speed of light and the spectrum."}, - {"fyz3_ex8_title", "Kvíz: spektrum", "Quiz: the spectrum"}, - {"fyz3_quiz8_head", "Ověřte si elektromagnetickou vlnu", - "Check the electromagnetic wave"}, - {"fyz4_unit1", "Vlnová optika", "Wave optics"}, - {"fyz4_unit1_sub", "Odraz, lom, interference a ohyb.", - "Reflection, refraction, interference and diffraction."}, - {"fyz4_ex1_title", "Kvíz: optika", "Quiz: optics"}, - {"fyz4_quiz1_head", "Ověřte si lom a odraz", "Check refraction and reflection"}, - {"fyz4_unit2", "Zobrazování", "Image formation"}, - {"fyz4_unit2_sub", "Zrcadla, čočky a oko.", - "Mirrors, lenses and the eye."}, - {"fyz4_ex2_title", "Kvíz: čočky", "Quiz: lenses"}, - {"fyz4_quiz2_head", "Ověřte si zobrazování", "Check image formation"}, - {"fyz4_unit3", "Speciální relativita", "Special relativity"}, - {"fyz4_unit3_sub", "Postuláty, dilatace a klidová energie.", - "The postulates, dilation and rest energy."}, - {"fyz4_ex3_title", "Kvíz: relativita", "Quiz: relativity"}, - {"fyz4_quiz3_head", "Ověřte si dva postuláty", "Check the two postulates"}, - {"fyz4_unit4", "Kvantové jevy", "Quantum phenomena"}, - {"fyz4_unit4_sub", "Foton, fotoefekt a de Broglie.", - "The photon, the photoelectric effect and de Broglie."}, - {"fyz4_ex4_title", "Kvíz: kvanta", "Quiz: quanta"}, - {"fyz4_quiz4_head", "Ověřte si foton", "Check the photon"}, - {"fyz4_unit5", "Stavba atomu", "Structure of the atom"}, - {"fyz4_unit5_sub", "Rutherford, Bohr a spektra.", - "Rutherford, Bohr and spectra."}, - {"fyz4_ex5_title", "Kvíz: atom", "Quiz: the atom"}, - {"fyz4_quiz5_head", "Ověřte si hladiny", "Check the energy levels"}, - {"fyz4_unit6", "Atomové jádro", "The atomic nucleus"}, - {"fyz4_unit6_sub", "Nukleony, vazebná energie a radioaktivita.", - "Nucleons, binding energy and radioactivity."}, - {"fyz4_ex6_title", "Kvíz: jádro", "Quiz: the nucleus"}, - {"fyz4_quiz6_head", "Ověřte si rozpad", "Check radioactive decay"}, - {"fyz4_unit7", "Jaderné reakce", "Nuclear reactions"}, - {"fyz4_unit7_sub", "Štěpení, reaktor a fúze.", - "Fission, the reactor and fusion."}, - {"fyz4_ex7_title", "Kvíz: reakce", "Quiz: reactions"}, - {"fyz4_quiz7_head", "Ověřte si štěpení a fúzi", "Check fission and fusion"}, - {"fyz4_unit8", "Astrofyzika", "Astrophysics"}, - {"fyz4_unit8_sub", "Hvězdy, galaxie a rozpínání vesmíru.", - "Stars, galaxies and the expanding universe."}, - {"fyz4_ex8_title", "Kvíz: vesmír", "Quiz: the universe"}, - {"fyz4_quiz8_head", "Ověřte si hvězdy a galaxie", "Check stars and galaxies"}, - {"czech_sub", "Vyberte oblast a začněte procvičovat.", - "Pick an area and start practicing."}, - {"Literatura", "Literatura", "Literature"}, - {"Mluvnice", "Mluvnice", "Grammar"}, - {"Maturitní četba", "Maturitní četba", "Maturita reading list"}, - {"reading_sub", "Vyberte knihu, kterou chcete studovat.", - "Pick a book to study."}, - {"book_study_hint", - "Nejdřív si projděte zápisky. Pak si látku ověřte v kvízu a seřaďte děj.", - "Read the study notes first. Then check yourself with the quiz and order the plot."}, - {"book_notes", "Zápisky k maturitě", "Study notes"}, - {"book_practice", "Procvičení", "Practice"}, - {"book_done", "Hotovo", "Done"}, - {"book_open", "Otevřít", "Open"}, - {"book_quiz_heading", "Kvíz", "Quiz"}, - {"book_1984_sub", "Antiutopický román • 1949", "Dystopian novel • 1949"}, - {"cetba1984_sub", "Přehled knihy, klíčové pojmy a cvičení.", - "Book overview, key terms and exercises."}, - {"cetba_entry_sub", "Údaje ze školního seznamu maturitní četby.", - "Details from the school maturita reading list."}, - {"cetba_stub_soon", "Podrobný přehled a cvičení zatím nejsou k dispozici.", - "A detailed overview and exercises are not available yet."}, - {"lit_quiz_title", "Kvíz: George Orwell – 1984", - "Quiz: George Orwell – 1984"}, - {"lit_quiz_sub", "U každé otázky vyberte jednu správnou odpověď.", - "Pick one correct answer for each question."}, - {"lit_plot_title", "Sestavte děj", "Order the plot"}, - {"lit_plot_sub", "Přetáhněte části příběhu do správného pořadí.", - "Drag the story parts into the correct order."}, - {"lit_next", "Další", "Next"}, - {"lit_show_result", "Zobrazit výsledek", "Show result"}, - {"lit_again", "Zkusit znovu", "Try again"}, - {"lit_question_fmt", "Otázka %d / %d", "Question %d / %d"}, - {"lit_score_fmt", "Skóre: %d / %d", "Score: %d / %d"}, - {"lit_finished", "Hotovo!", "Done!"}, - {"lit_finished_text", "Prošli jste všemi otázkami.", - "You have finished all the questions."}, - {"cetbaFuks_sub", "Přehled knihy, klíčové pojmy a cvičení.", - "Book overview, key terms and exercises."}, - {"lit_fuks_quiz_title", "Kvíz: Spalovač mrtvol", - "Quiz: The Cremator"}, - {"lit_fuks_quiz_sub", "U každé otázky vyberte jednu správnou odpověď.", - "Pick one correct answer for each question."}, - {"lit_fuks_plot_title", "Sestavte děj", "Order the plot"}, - {"lit_fuks_plot_sub", "Přetáhněte části příběhu do správného pořadí.", - "Drag the story parts into the correct order."}, -#include "english_i18n.inc" -#include "german_i18n.inc" -#include "it_years_i18n.inc" -#include "math_i18n.inc" - {NULL, NULL, NULL} -}; - -/* Exercise content: the Czech text doubles as the lookup key, so `cs` - * stays NULL and tr() falls back to the key itself. */ -const TrEntry tr_content[] = { - {"Ahoj! Jmenuji se Anna.", NULL, "Hi! My name is Anna."}, - {"Ahoj! Jmenuji se Petr.", NULL, "Hi! My name is Petr."}, - {"Jmenuji se Anna.", NULL, "My name is Anna."}, - {"Jmenuji se Petr.", NULL, "My name is Petr."}, - {"Odkud jsi?", NULL, "Where are you from?"}, - {"Odkud pocházíš?", NULL, "Where do you come from?"}, - {"Pocházím z Česka.", NULL, "I come from Czechia."}, - {"Dobré ráno!", NULL, "Good morning!"}, - {"Jak se máš?", NULL, "How are you?"}, - {"Mám se dobře, děkuji.", NULL, "I am fine, thank you."}, - {"Musím jít. Na shledanou!", NULL, "I have to go. Goodbye!"}, - {"Brzy na viděnou!", NULL, "See you soon!"}, - {"Čau!", NULL, "Bye!"}, - {"Jak se jmenuješ?", NULL, "What is your name?"}, - {"Kde bydlíš?", NULL, "Where do you live?"}, - {"Kdo to je?", NULL, "Who is that?"}, - {"Kolik je ti let?", NULL, "How old are you?"}, - {"Je mi šestnáct let.", NULL, "I am sixteen years old."}, - {"Bydlím v Praze.", NULL, "I live in Prague."}, - {"Hraji fotbal.", NULL, "I play football."}, - {"Co rád/a děláš?", NULL, "What do you like to do?"}, - {"Kolik je hodin?", NULL, "What time is it?"}, - {"Na shledanou.", NULL, "Goodbye."}, - {"Moc děkuji.", NULL, "Thank you very much."}, - {"„vierzehn“ = čtrnáct (14)", NULL, "“vierzehn” = fourteen (14)"}, - {"„siebzehn“ = sedmnáct (17)", NULL, "“siebzehn” = seventeen (17)"}, - {"„zwanzig“ = dvacet (20)", NULL, "“zwanzig” = twenty (20)"}, - {"„sechs“ = šest (6)", NULL, "“sechs” = six (6)"}, - {"1 B = 8 b", NULL, "1 B = 8 b"}, - {"2⁸ = 256 hodnot (0–255)", NULL, "2⁸ = 256 values (0–255)"}, - {"Kabely – síť zůstává připojená i po přenosu", NULL, - "Cables – the network stays connected after transfer"}, - {"WAN = Wide Area Network, např. internet", NULL, - "WAN = Wide Area Network, e.g. the internet"}, - {"Např. hvězda, kruh, sběrnice", NULL, - "E.g. star, ring, bus"}, - {"Architektura = topologie + standard", NULL, - "Architecture = topology + standard"}, - {"Bez centrálního serveru – stanice si sdílejí data a tiskárny", NULL, - "No central server – stations share data and printers"}, - {"Server řídí a poskytuje služby, má vyšší výkon", NULL, - "A server controls and provides services; higher performance"}, - {"Ověřují uživatele a povolují přístup ke službám", NULL, - "They authenticate users and grant access to services"}, - {"Fileserver = souborový server", NULL, - "Fileserver = file server"}, - {"Jeden server – při výpadku je služba nedostupná", NULL, - "One server – if it fails, the service is unavailable"}, - {"Více serverů, každý obsluhuje část – vyšší spolehlivost", NULL, - "Multiple servers, each handles a part – higher reliability"}, - {"Slouží zároveň i jako pracovní stanice", NULL, - "It also works as a workstation"}, - {"Jen síťové služby – vysoký výkon a bezpečnost, často v racku", NULL, - "Network services only – high performance and security, often in a rack"}, - {"Obří sálové počítače (IBM, Siemens) pro banky a státní správu", NULL, - "Huge mainframe computers (IBM, Siemens) for banks and government"}, - {"SaaS = software jako služba, přístup online z libovolného zařízení", NULL, - "SaaS = software as a service, online access from any device"}, - {"Více bitů najednou po více vodičích; problém jsou přeslechy", NULL, - "Multiple bits at once over multiple wires; crosstalk is the problem"}, - {"Přeslechy vznikají při delších kabelech a vysokých frekvencích", NULL, - "Crosstalk occurs on longer cables and at high frequencies"}, - {"Bit po bitu po jednom vodiči – vyšší frekvence i délky", NULL, - "Bit by bit over one wire – higher frequencies and longer distances"}, - {"Start-bit (0) synchronizuje, Stop-bit (1) ukončuje znak", NULL, - "Start bit (0) synchronizes, stop bit (1) ends the character"}, - {"Řízeno společným hodinovým signálem a přesným časováním", NULL, - "Controlled by a shared clock signal and precise timing"}, - {"Nejslabší – přidá bit pro sudý/lichý počet jedniček", NULL, - "Weakest – adds a bit for even/odd number of ones"}, - {"Součet znaků jako dvojkových čísel", NULL, - "Sum of characters treated as binary numbers"}, - {"Nejbezpečnější – počítá se z jednotlivých bitů v bloku", NULL, - "Most secure – computed from individual bits in the block"}, - {"Analogový je spojitý, digitální má diskrétní hodnoty 0 a 1", NULL, - "Analog is continuous; digital has discrete 0 and 1 values"}, - {"Frekvence f = 1/T, kde T je perioda", NULL, - "Frequency f = 1/T, where T is the period"}, - {"AM mění amplitudu, FM frekvenci, PM fázi", NULL, - "AM changes amplitude, FM frequency, PM phase"}, - {"QPSK nese 2 bity v prvku, 256-QAM nese 8 bitů", NULL, - "QPSK carries 2 bits per symbol, 256-QAM carries 8 bits"}, - {"Modulační rychlost = počet změn signálu za sekundu [Bd/s]", NULL, - "Modulation rate = number of signal changes per second [Bd/s]"}, - {"Přenosová rychlost = množství informace za sekundu [bit/s]", NULL, - "Bit rate = amount of information per second [bit/s]"}, - {"Šířka pásma určuje maximální možnou přenosovou rychlost", NULL, - "Bandwidth determines the maximum possible bit rate"}, - {"Datový spoj umožňuje výměnu informací mezi uzly", NULL, - "A data link enables information exchange between nodes"}, - {"Fyzické médium: kabely, mikrovlny nebo družice", NULL, - "Physical medium: cables, microwaves or satellites"}, - {"Kanál je jednosměrný souhrn prostředků pro spojení", NULL, - "A channel is a one-way set of means for a connection"}, - {"Okruh tvoří dva kanály pro obousměrný přenos", NULL, - "A circuit is made of two channels for two-way transfer"}, - {"Trunking spojuje více cest do jednoho okruhu", NULL, - "Trunking joins multiple paths into one circuit"}, - {"Trunking zvyšuje šířku pásma spojením cest", NULL, - "Trunking increases bandwidth by combining paths"}, - {"Multiplex dělí jeden kanál na více logických podkanálů", NULL, - "Multiplexing splits one channel into multiple logical subchannels"}, - {"FDM: každému kanálu část frekvenčního pásma", NULL, - "FDM: each channel gets part of the frequency band"}, - {"TDM: každému kanálu vyhrazený časový slot", NULL, - "TDM: each channel gets a reserved time slot"}, - {"STDM přiděluje kapacitu dle potřeby, negarantuje 100 %", NULL, - "STDM allocates capacity on demand and does not guarantee 100%"}, - {"Simplex = jen jeden směr přenosu", NULL, - "Simplex = only one transmission direction"}, - {"Half-duplex = oběma směry, ale ne současně", NULL, - "Half-duplex = both directions, but not at the same time"}, - {"Full-duplex = oběma směry současně", NULL, - "Full-duplex = both directions at the same time"}, - {"Agregace = sdílení kapacity kanálu více uživateli", NULL, - "Aggregation = sharing channel capacity among multiple users"}, - {"Cesta se vytýčí předem, kapacita je garantována", NULL, - "The path is set up in advance and capacity is guaranteed"}, - {"Data se dělí na pakety, každý může jít jinou cestou", NULL, - "Data are split into packets; each may take a different path"}, - {"Výhody: reakce na zátěž a lepší využití kapacity", NULL, - "Advantages: reaction to load and better capacity use"}, - {"Negarantuje pořadí ani plynulost – nevhodné pro živé video", NULL, - "Does not guarantee order or smoothness – unsuitable for live video"}, - {"Cesta je předem, prostředky se použijí jen při průchodu paketu", NULL, - "Path is preset; resources are used only when a packet passes"}, - {"Virtuální spoje zrychlují přenos datagramů", NULL, - "Virtual circuits speed up datagram transfer"}, - {"Standardizace zajišťuje kompatibilitu mezi výrobci", NULL, - "Standardization ensures compatibility between vendors"}, - {"Dekompozice rozkládá přenos na jednotlivé vrstvy", NULL, - "Decomposition splits transmission into individual layers"}, - {"Vrstvy komunikují jen se sousedy přes rozhraní SAP", NULL, - "Layers communicate only with neighbors through SAP interfaces"}, - {"Protokol = pravidla mezi stejnými vrstvami na různých uzlech", NULL, - "A protocol is rules between the same layers on different nodes"}, - {"Každá vrstva přidává k datům hlavičku (header)", NULL, - "Each layer adds a header to the data"}, - {"Rámec = linková, paket = síťová, segment = transportní", NULL, - "Frame = link, packet = network, segment = transport"}, - {"ISO/OSI má 7 vrstev a je univerzální model", NULL, - "ISO/OSI has 7 layers and is a universal model"}, - {"V praxi je ISO/OSI pomalejší – spolehlivost řeší každá vrstva", NULL, - "In practice ISO/OSI is slower – each layer handles reliability"}, - {"TCP/IP zvítězil, protože vycházel ze skutečných potřeb", NULL, - "TCP/IP won because it came from real-world needs"}, - {"V TCP/IP řeší spolehlivost až vyšší vrstvy", NULL, - "In TCP/IP, reliability is handled by higher layers"}, - {"Fyzická vrstva přenáší bity a řeší médium", NULL, - "The physical layer transmits bits and handles the medium"}, - {"Spojová vrstva má podvrstvy MAC a LLC", NULL, - "The data-link layer has MAC and LLC sublayers"}, - {"Síťová vrstva směruje pakety i bez přímého spojení", NULL, - "The network layer routes packets even without a direct link"}, - {"Transportní vrstva je jen v koncových uzlech, ne v routerech", NULL, - "The transport layer exists only in end nodes, not in routers"}, - {"Relační vrstva řídí relace, dialog a synchronizaci", NULL, - "The session layer manages sessions, dialogue and synchronization"}, - {"Prezentační vrstva formátuje data, komprimuje a šifruje", NULL, - "The presentation layer formats, compresses and encrypts data"}, - {"Aplikační vrstva je rozhraní pro programy a služby", NULL, - "The application layer is the interface for programs and services"}, - {"Aplikační TCP/IP = aplikační + prezentační + relační ISO/OSI", NULL, - "TCP/IP application = ISO/OSI application + presentation + session"}, - {"Síťové rozhraní TCP/IP = linková + fyzická ISO/OSI", NULL, - "TCP/IP network interface = ISO/OSI data-link + physical"}, - {"U TCP/IP vznikly nejdřív protokoly, až pak model", NULL, - "With TCP/IP, protocols came first and the model later"}, - {"TCP je spolehlivý a spojovaný", NULL, - "TCP is reliable and connection-oriented"}, - {"UDP je nespolehlivý a rychlý", NULL, - "UDP is unreliable and fast"}, - {"HTTP, DNS a SMTP jsou aplikační protokoly", NULL, - "HTTP, DNS and SMTP are application protocols"}, - {"IP, ICMP a OSPF patří na síťovou (internetovou) vrstvu", NULL, - "IP, ICMP and OSPF belong to the network (internet) layer"}, - {"Ethernet a PPP patří na vrstvu síťového rozhraní", NULL, - "Ethernet and PPP belong to the network interface layer"}, - {"Sběrnice: médium sdílí všichni", NULL, - "Bus: the medium is shared by everyone"}, - {"Sběrnice: nízká bezpečnost a porucha kabelu vyřadí síť", NULL, - "Bus: low security and a cable fault takes down the network"}, - {"Hvězda: uzly jdou přes hub nebo switch", NULL, - "Star: nodes connect through a hub or switch"}, - {"Hvězda: porucha kabelu k uzlu nevyřadí celou síť", NULL, - "Star: a cable fault to one node does not take down the whole network"}, - {"Hvězda používá kroucenou dvoulinku nebo optiku", NULL, - "Star uses twisted pair or fiber"}, - {"V kruhu zprávy obíhají, dokud nenajdou adresáta", NULL, - "In a ring, messages circulate until they find the recipient"}, - {"Optika: el. impulsy → světlo (LED/laser) → fotodioda", NULL, - "Optics: electrical pulses → light (LED/laser) → photodiode"}, - {"Jedno vlákno = jednosměrný přenos; obousměrně dvě vlákna", NULL, - "One fiber = one-way; two fibers for bidirectional use"}, - {"Nevýhody: náročná montáž a cena prvků/konektorů", NULL, - "Drawbacks: difficult installation and costly parts/connectors"}, - {"MM: jádro 50/62,5 µm a více vidů", NULL, - "MM: 50/62.5 µm core and multiple modes"}, - {"SM: jádro 7–10 µm, jeden paprsek, laser", NULL, - "SM: 7–10 µm core, one beam, laser"}, - {"MM typicky používá levnější LED zdroje", NULL, - "MM typically uses cheaper LED sources"}, - {"Primární ochrana: 250 µm", NULL, - "Primary protection: 250 µm"}, - {"Sekundární ochrana: 900 µm", NULL, - "Secondary protection: 900 µm"}, - {"Těsná sekundární ochrana: svislé instalace", NULL, - "Tight secondary protection: vertical installs"}, - {"Volná sekundární ochrana: vodorovné instalace", NULL, - "Loose secondary protection: horizontal installs"}, - {"Montáž: lámačka a svářečka optických vláken", NULL, - "Installation: cleaver and optical fiber splicer"}, - {"Lámání vyžaduje kolmost asi 0,5°", NULL, - "Cleaving requires roughly 0.5° squareness"}, - {"Kolize = více uzlů vysílá na sdíleném médiu najednou", NULL, - "A collision is multiple nodes transmitting on a shared medium at once"}, - {"Aloha: vysílej kdykoliv, při chybě znovu", NULL, - "Aloha: transmit anytime; retry if there is no acknowledgment"}, - {"CSMA/CD patří k Ethernetu", NULL, - "CSMA/CD belongs to Ethernet"}, - {"CSMA/CD nejdřív poslouchá nosnou (Carrier Sense)", NULL, - "CSMA/CD first listens for the carrier (Carrier Sense)"}, - {"Po kolizi CSMA/CD čeká náhodný čas a zkusí znovu", NULL, - "After a collision, CSMA/CD waits a random time and retries"}, - {"CSMA/CA rezervuje médium přes RTS/CTS", NULL, - "CSMA/CA reserves the medium with RTS/CTS"}, - {"Repeater zesiluje signál na fyzické vrstvě", NULL, - "A repeater amplifies the signal at the physical layer"}, - {"Transceiver převádí mezi médii (např. metalika ↔ optika)", NULL, - "A transceiver converts between media (e.g. copper ↔ fiber)"}, - {"Hub rozešle přijatá data do všech ostatních portů", NULL, - "A hub floods received data to all other ports"}, - {"Bridge/switch = linková vrstva, rámce a MAC", NULL, - "Bridge/switch = data-link layer, frames and MAC"}, - {"Switch dělí síť na kolizní domény", NULL, - "A switch splits the network into collision domains"}, - {"Router = síťová vrstva, pakety a IP, propojuje sítě", NULL, - "A router = network layer, packets and IP, connects networks"}, - {"Gateway převádí mezi odlišnými architekturami/protokoly", NULL, - "A gateway converts between different architectures/protocols"}, - {"MAC adresy switch ukládá do CAM tabulky", NULL, - "A switch stores MAC addresses in the CAM table"}, - {"Podle CAM tabulky posílá rámec jen na cílový port", NULL, - "Using the CAM table, it forwards a frame only to the target port"}, - {"Cut-through čte adresu příjemce a hned přeposílá", NULL, - "Cut-through reads the destination address and forwards immediately"}, - {"Cut-through je rychlý, ale propustí i chyby", NULL, - "Cut-through is fast but also forwards errors"}, - {"Store-and-forward kontroluje celý rámec včetně CRC", NULL, - "Store-and-forward checks the whole frame including CRC"}, - {"Fragment-free čte prvních 64 bytů kvůli kolizím", NULL, - "Fragment-free reads the first 64 bytes for collision detection"}, - {"Směrování běží na síťové (3.) vrstvě ISO/OSI", NULL, - "Routing runs on the network (3rd) ISO/OSI layer"}, - {"Adaptivní algoritmy reagují na změny a sdílí stav sítě", NULL, - "Adaptive algorithms react to changes and share network state"}, - {"Statické cesty nastaví správce a samy se nemění", NULL, - "Static routes are set by an admin and do not change themselves"}, - {"Centralizované směrování padá s výpadkem centra", NULL, - "Centralized routing fails if the center fails"}, - {"Distribuované: výměna informací a vlastní tabulky", NULL, - "Distributed: information exchange and local tables"}, - {"Nižší metrika = lepší / rychlejší trasa", NULL, - "Lower metric = better / faster route"}, - {"Distance Vector: výměna tabulek se sousedy (např. každých 30 s)", NULL, - "Distance Vector: exchange tables with neighbors (e.g. every 30 s)"}, - {"Router pracuje na síťové (3.) vrstvě", NULL, - "A router works at the network (3rd) layer"}, - {"Router segmentuje podsítě a zajišťuje WAN přístup", NULL, - "A router segments subnets and provides WAN access"}, - {"Firewall filtruje pakety a služby", NULL, - "A firewall filters packets and services"}, - {"Multiprotokolový router spojuje různé protokoly/standardy", NULL, - "A multiprotocol router joins different protocols/standards"}, - {"Router dělí síť na broadcastové domény", NULL, - "A router splits the network into broadcast domains"}, - {"Gateway připojuje LAN na odlišné prostředí", NULL, - "A gateway connects a LAN to a different environment"}, - {"Pojem brána někdy označuje router nebo LAN–WAN připojení", NULL, - "Gateway sometimes means a router or LAN–WAN connection"}, - {"MAC adresa Ethernetu má 48 bitů a je unikátní", NULL, - "An Ethernet MAC address is 48 bits and unique"}, - {"IEEE přidělí výrobci první 3 byty adresy", NULL, - "IEEE assigns the manufacturer the first 3 address bytes"}, - {"Ethernet II: EtherType > 1500 (IP = 0800h)", NULL, - "Ethernet II: EtherType > 1500 (IP = 0800h)"}, - {"IEEE 802.3: délka ≤ 1500 a rámec 802.2", NULL, - "IEEE 802.3: length ≤ 1500 and an 802.2 frame"}, - {"Raw 802.3: Novell/IPX, začíná FFFFh", NULL, - "Raw 802.3: Novell/IPX, starts with FFFFh"}, - {"Max. Ethernet II = 1518 B", NULL, - "Max Ethernet II frame = 1518 B"}, - {"Min. rámec 64 B kvůli koliznímu okénku", NULL, - "Min frame is 64 B due to the collision window"}, - {"IP je nespojovaný a nespolehlivý", NULL, - "IP is connectionless and unreliable"}, - {"Routing = rozhodnutí o směru datagramu", NULL, - "Routing = deciding the next direction of a datagram"}, - {"Forwarding = vložení do rámce a odeslání", NULL, - "Forwarding = placing into a frame and sending"}, - {"HLEN 5 = 5 × 4 B = 20 B hlavičky", NULL, - "HLEN 5 = 5 × 4 B = 20 B header"}, - {"TTL snižují směrovače proti zacyklení", NULL, - "Routers decrease TTL to prevent loops"}, - {"PROTOCOL 6 = TCP", NULL, - "PROTOCOL 6 = TCP"}, - {"PROTOCOL 17 = UDP", NULL, - "PROTOCOL 17 = UDP"}, - {"Ethernet MTU = 1500 B", NULL, - "Ethernet MTU = 1500 B"}, - {"ICMP posílá informace o chybách a stavu přenosu", NULL, - "ICMP sends information about errors and transfer status"}, - {"ICMP jede uvnitř IP datagramu", NULL, - "ICMP is carried inside an IP datagram"}, - {"Source Quench = zpomal odesílání kvůli zahlcení", NULL, - "Source Quench = slow down sending due to congestion"}, - {"Time Exceeded = TTL kleslo na 0", NULL, - "Time Exceeded = TTL dropped to 0"}, - {"Echo Request/Reply = ping", NULL, - "Echo Request/Reply = ping"}, - {"Traceroute zvyšuje TTL a čte Time Exceeded", NULL, - "Traceroute raises TTL and reads Time Exceeded"}, - {"ARP: IP → MAC", NULL, - "ARP: IP → MAC"}, - {"RARP: MAC → IP", NULL, - "RARP: MAC → IP"}, - {"Nejčastější je dynamický dotaz a odpověď", NULL, - "The most common way is a dynamic query and reply"}, - {"ARP dotaz jde broadcastem", NULL, - "An ARP request goes out as a broadcast"}, - {"ARP odpověď je unicast s MAC", NULL, - "An ARP reply is a unicast with the MAC"}, - {"ARP cache ukládá výsledky dočasně (arp -a)", NULL, - "ARP cache stores results temporarily (arp -a)"}, - {"TCP = spolehlivý a spojovaný", NULL, - "TCP = reliable and connection-oriented"}, - {"UDP = nespolehlivý, nespojovaný, malá režie", NULL, - "UDP = unreliable, connectionless, low overhead"}, - {"Porty rozlišují aplikace na uzlu", NULL, - "Ports distinguish applications on a node"}, - {"TCP se navazuje three-way handshake", NULL, - "TCP is established with a three-way handshake"}, - {"TCP hlavička 20 B, UDP 8 B", NULL, - "TCP header is 20 B, UDP is 8 B"}, - {"TCP čeká na znovudoručení – špatné pro real-time", NULL, - "TCP waits for retransmission – bad for real-time"}, - {"SCTP: multihoming a multistreaming", NULL, - "SCTP: multihoming and multistreaming"}, - {"Aplikace posílají data přes TCP/UDP", NULL, - "Applications send data over TCP/UDP"}, - {"Dva procesy nesmí sdílet stejný port", NULL, - "Two processes must not share the same port"}, - {"Well-known: 0–1023 (IANA)", NULL, - "Well-known: 0–1023 (IANA)"}, - {"Dynamické porty: 49152–65535", NULL, - "Dynamic ports: 49152–65535"}, - {"Spojení = pětice hodnot", NULL, - "A connection is a 5-tuple"}, - {"HTTP 80, HTTPS 443", NULL, - "HTTP 80, HTTPS 443"}, - {"SSH 22, DNS 53", NULL, - "SSH 22, DNS 53"}, - {"MySQL 3306, RDP 3389", NULL, - "MySQL 3306, RDP 3389"}, - {"Geostacionární družice ~36 000 km", NULL, - "Geostationary satellites ~36,000 km"}, - {"Družice: zpoždění stovky ms", NULL, - "Satellites: hundreds of ms delay"}, - {"VSAT: jen terminál ↔ hub", NULL, - "VSAT: only terminal ↔ hub"}, - {"Mikrovlny: přímá viditelnost ~50 km", NULL, - "Microwaves: line of sight ~50 km"}, - {"STA komunikují přes AP", NULL, - "STAs communicate via an AP"}, - {"Wi-Fi 6 (ax): OFDMA", NULL, - "Wi-Fi 6 (ax): OFDMA"}, - {"WEP prolomen – nepoužívat", NULL, - "WEP is broken – do not use"}, - {"Používej WPA2/WPA3 + AES", NULL, - "Use WPA2/WPA3 + AES"}, - {"čtrnáct", NULL, "fourteen"}, - {"sedmnáct", NULL, "seventeen"}, - {"dvacet", NULL, "twenty"}, - {"šest", NULL, "six"}, - {"třináct", NULL, "thirteen"}, - {"dvě jablka", NULL, "two apples"}, - {"pět hvězd", NULL, "five stars"}, - {"sedm koček", NULL, "seven cats"}, - {"devět květin", NULL, "nine flowers"}, - {"tři auta", NULL, "three cars"}, - {"jedenáct knih", NULL, "eleven books"}, - {"čtyři svíčky", NULL, "four candles"}, - {"osm míčů", NULL, "eight balls"}, - {"šest ptáků", NULL, "six birds"}, - {"šest, sedm, osm, devět", NULL, "six, seven, eight, nine"}, - {"dvanáct, třináct, čtrnáct, patnáct", NULL, - "twelve, thirteen, fourteen, fifteen"}, - {"osmnáct, devatenáct, dvacet, dvacet jedna", NULL, - "eighteen, nineteen, twenty, twenty-one"}, - {"čtyři, pět, šest, sedm", NULL, "four, five, six, seven"}, - {"deset, jedenáct, dvanáct, třináct", NULL, - "ten, eleven, twelve, thirteen"}, - {"Plave v jezeře.", NULL, "He/She is swimming in the lake."}, - {"Zpívá píseň.", NULL, "He/She is singing a song."}, - {"Vaří polévku.", NULL, "He/She is cooking soup."}, - {"Čte knihu.", NULL, "He/She is reading a book."}, - {"Řídí auto.", NULL, "He/She is driving a car."}, - {"Maluje obraz.", NULL, "He/She is painting a picture."}, - {"Hraje fotbal.", NULL, "He/She is playing football."}, - {"Spí.", NULL, "He/She is sleeping."}, - {"Ahoj", NULL, "Hi"}, - {"Dobré ráno", NULL, "Good morning"}, - {"Dobrý den", NULL, "Good day"}, - {"Dobrý večer", NULL, "Good evening"}, - {"Dobrý den (Bavorsko, Rakousko)", NULL, "Good day (Bavaria, Austria)"}, - {"Ahoj / Čau", NULL, "Hi / Hey"}, - {"Čau", NULL, "Bye"}, - {"Na shledanou", NULL, "Goodbye"}, - {"Brzy na viděnou", NULL, "See you soon"}, - {"Do zítřka", NULL, "See you tomorrow"}, - {"Dobrou noc", NULL, "Good night"}, - {"Zatím / Na viděnou", NULL, "See you later"}, - {"Preclík", NULL, "Pretzel"}, - {"Klobása", NULL, "Sausage"}, - {"Braniborská brána", NULL, "Brandenburg Gate"}, - {"Značka aut", NULL, "Car brand"}, - {"Rakouský skladatel", NULL, "Austrian composer"}, - {"Čokoládový dort (Vídeň)", NULL, "Chocolate cake (Vienna)"}, - {"Vídeňský řízek", NULL, "Viennese schnitzel"}, - {"Sýr", NULL, "Cheese"}, - {"Švýcarská hora", NULL, "Swiss mountain"}, - {"Čokoláda", NULL, "Chocolate"}, - /* ---- unit 2: grammar & vocabulary meanings ---- */ - {"Pochází z Rakouska.", NULL, "He is from Austria."}, - {"Bydlí ve Štýrském Hradci (Graz).", NULL, "He lives in Graz."}, - {"Rád hraje golf.", NULL, "He likes playing golf."}, - {"Mluví německy, anglicky a italsky.", NULL, - "He speaks German, English and Italian."}, - {"Pocházejí ze Slovenska.", NULL, "They are from Slovakia."}, - {"Bydlí v Bratislavě (ona).", NULL, "She lives in Bratislava."}, - {"Ona ráda tancuje.", NULL, "She likes dancing."}, - {"On rád cestuje.", NULL, "He likes travelling."}, - {"Jsou dobří přátelé.", NULL, "They are good friends."}, - {"Pocházím z Atén.", NULL, "I am from Athens."}, - {"Petr bydlí v Salcburku.", NULL, "Peter lives in Salzburg."}, - {"Berlín leží v Německu.", NULL, "Berlin is in Germany."}, - {"Bydlíme v Paříži.", NULL, "We live in Paris."}, - {"Pocházejí z Řecka.", NULL, "They are from Greece."}, - {"Odkud je? – Z Londýna.", NULL, "Where is he from? – From London."}, - {"Jak se jmenuje? – Andrea.", NULL, "What is her name? – Andrea."}, - {"Kdo pochází z Ruska? – Alexandr.", NULL, - "Who comes from Russia? – Alexander."}, - {"Kde leží Praha? – V Česku.", NULL, "Where is Prague? – In Czechia."}, - {"Kde bydlí? – V Bratislavě.", NULL, "Where do they live? – In Bratislava."}, - {"Co děláte? – Studujeme germanistiku.", NULL, - "What are you doing? – We're studying German studies."}, - {"Mluvím německy. A ty?", NULL, "I speak German. And you?"}, - {"Kterými jazyky mluvíte?", NULL, "Which languages do you speak?"}, - {"Mluvíš francouzsky? – Ano, trochu.", NULL, - "Do you speak French? – Yes, a little."}, - {"My mluvíme polsky a vy?", NULL, "We speak Polish and you?"}, - {"Mluvíte anglicky? – Ano, velmi dobře.", NULL, - "Do you speak English? – Yes, very well."}, - {"Nemluví ani slovo turecky.", NULL, - "He doesn't speak a word of Turkish."}, - {"Čech", NULL, "Czech man"}, - {"Španělka", NULL, "Spanish woman"}, - {"Turek", NULL, "Turk (man)"}, - {"Chorvatka", NULL, "Croatian woman"}, - {"Němka", NULL, "German woman"}, - {"Rakušanka", NULL, "Austrian woman"}, - {"Slovák", NULL, "Slovak man"}, - {"Švýcarka", NULL, "Swiss woman"}, - {"Němec", NULL, "German man"}, - {"Německo", NULL, "Germany"}, - {"Deutschland – Německo", NULL, "Deutschland – Germany"}, - {"Slowakei – Slovensko", NULL, "Slowakei – Slovakia"}, - {"Österreich – Rakousko", NULL, "Österreich – Austria"}, - {"Spanien – Španělsko", NULL, "Spanien – Spain"}, - {"England – Anglie", NULL, "England – England"}, - {"Polen – Polsko", NULL, "Polen – Poland"}, - {"Slovensko", NULL, "Slovakia"}, - {"Rakousko", NULL, "Austria"}, - {"Španělsko", NULL, "Spain"}, - {"Anglie", NULL, "England"}, - {"Polsko", NULL, "Poland"}, - {"Rusko", NULL, "Russia"}, - {"Russland – Rusko", NULL, "Russland – Russia"}, - {"Türkei – Turecko", NULL, "Türkei – Turkey"}, - {"Slowakei – Slovensko", NULL, "Slowakei – Slovakia"}, - {"Kroatien – Chorvatsko", NULL, "Kroatien – Croatia"}, - {"Griechenland – Řecko", NULL, "Griechenland – Greece"}, - {"Italien – Itálie", NULL, "Italien – Italy"}, - {"Turecko", NULL, "Turkey"}, - {"Chorvatsko", NULL, "Croatia"}, - {"Řecko", NULL, "Greece"}, - {"Itálie", NULL, "Italy"}, - {"otec", NULL, "father"}, - {"rodiče", NULL, "parents"}, - {"Češka", NULL, "Czech woman"}, - {"student", NULL, "student"}, - {"Co čte? – Knihu.", NULL, "What is he reading? – A book."}, - {"Co studuje? – Medicínu.", NULL, "What is she studying? – Medicine."}, - {"Čím Jan rád jezdí? – Autem.", NULL, - "What does Jan like to drive? – A car."}, - {"Kde bydlíte? – Ve Vídni.", NULL, "Where do you live? – In Vienna."}, - {"Kdo pracuje u Siemensu? – Moje kamarádka Věra.", NULL, - "Who works at Siemens? – My friend Vera."}, - {"Kam jedeš?", NULL, "Where are you going?"}, - {"Co rád/a čteš?", NULL, "What do you like to read?"}, - {"Co rád/a hraješ?", NULL, "What do you like to play?"}, - {"Jmenuji se Lukáš.", NULL, "My name is Lukáš."}, - {"Jedu do Německa.", NULL, "I'm going to Germany."}, - {"Rád/a čtu detektivky.", NULL, "I like reading crime novels."}, - {"Rád/a hraju golf.", NULL, "I like playing golf."}, - {"šedesát tři eur", NULL, "sixty-three euros"}, - {"třicet osm eur", NULL, "thirty-eight euros"}, - {"čtyřicet pět eur", NULL, "forty-five euros"}, - {"padesát sedm eur", NULL, "fifty-seven euros"}, - {"devadesát devět eur", NULL, "ninety-nine euros"}, - {"Agnieszka Kowalski pochází z Polska, z Krakova.", NULL, - "Agnieszka Kowalski is from Kraków, Poland."}, - {"Je jí 18 let a letos dělá maturitu.", NULL, - "She is 18 years old and is taking her A-levels this year."}, - {"Ráda chatuje se svým německým přítelem.", NULL, - "She likes chatting with her German friend."}, - {"Jmenuje se Stefan Böhmermann a bydlí v Drážďanech.", NULL, - "His name is Stefan Böhmermann and he lives in Dresden."}, - {"Agnieszce přijde ten jazyk super.", NULL, - "Agnieszka thinks the language is cool."}, - {"Už mluví velmi dobře německy.", NULL, - "She already speaks German very well."}, - {"potřebovat mobil", NULL, "to need a mobile phone"}, - {"pracovat ve BMW", NULL, "to work at BMW"}, - {"řídit auto", NULL, "to drive a car"}, - {"navštěvovat gymnázium", NULL, "to attend a grammar school"}, - {"mluvit španělsky", NULL, "to speak Spanish"}, - {"číst detektivky", NULL, "to read crime novels"}, - {"padesát čtyři", NULL, "fifty-four"}, - {"čtyřicet pět", NULL, "forty-five"}, - {"tři sta šedesát devět", NULL, "three hundred and sixty-nine"}, - {"sto dvanáct", NULL, "one hundred and twelve"}, - {"sto dvacet dva", NULL, "one hundred and twenty-two"}, - {"šedesát osm", NULL, "sixty-eight"}, - {"Petr rád čte knihy.", NULL, "Peter likes reading books."}, - {"Filip pracuje v Salcburku.", NULL, "Filip works in Salzburg."}, - {"Magda dobře mluví anglicky.", NULL, "Magda speaks English well."}, - {"Marek navštěvuje gymnázium.", NULL, "Marek attends the grammar school."}, - {"Dominice je 15 let.", NULL, "Dominika is 15 years old."}, - {"Moje sestra se jmenuje Marta.", NULL, "My sister is called Marta."}, - {"Jak se jmenují? – Jana a Michael.", NULL, - "What are their names? – Jana and Michael."}, - {"Kdo mluví polsky? – Jacek.", NULL, "Who speaks Polish? – Jacek."}, - {"Kde bydlí Eva? – V Plzni.", NULL, "Where does Eva live? – In Plzeň."}, - {"Odkud pochází Markus? – Z Německa.", NULL, - "Where is Markus from? – From Germany."}, - {"Jakým jazykem mluví Jana? – Slovensky.", NULL, - "What language does Jana speak? – Slovak."}, - /* ---- unit 2: hangman hints ---- */ - {"vaří v restauraci", NULL, "he cooks in a restaurant"}, - {"léčí nemocné lidi", NULL, "he treats sick people"}, - {"učí ve škole", NULL, "he teaches at school"}, - {"pracuje u policie", NULL, "he works for the police"}, - {"prodává v obchodě", NULL, "he sells in a shop"}, - /* ---- unit 2: word-level glosses for ex14/ex15 ---- */ - {"z", NULL, "from"}, - {"dělá", NULL, "does"}, - {"kamarád", NULL, "friend"}, - {"žije", NULL, "lives"}, - {"jazyk", NULL, "language"}, - {"dobře", NULL, "well"}, - {"potřebovat", NULL, "to need"}, - {"pracovat", NULL, "to work"}, - {"řídit", NULL, "to drive"}, - {"navštěvovat", NULL, "to attend"}, - {"mluvit", NULL, "to speak"}, - {"číst", NULL, "to read"}, - /* ---- unit 3: Bei uns zu Hause ---- */ - /* ex1 family word pairs */ - {"bratranec / sestřenice", NULL, "male cousin / female cousin"}, - {"strýc / teta", NULL, "uncle / aunt"}, - {"dědeček / babička", NULL, "grandfather / grandmother"}, - {"sestra / bratr", NULL, "sister / brother"}, - {"kamarád / kamarádka", NULL, "friend (m) / friend (f)"}, - {"dcera / syn", NULL, "daughter / son"}, - /* ex2 possessive pronouns (nominative) */ - {"Je to tvoje matka? – Ne, to není moje matka. To je jeho teta.", NULL, - "Is that your mother? – No, that is not my mother. That is his aunt."}, - /* ex2 word-level glosses for the selected possessive pronouns */ - {"tvůj", NULL, "yours (m.)"}, - {"tvoje", NULL, "yours (f.)"}, - {"můj", NULL, "mine (m.)"}, - {"moje", NULL, "mine (f.)"}, - {"jeho", NULL, "his"}, - {"Je to tvůj bratr? – Ne, to není můj bratr. To je jeho bratranec.", NULL, - "Is that your brother? – No, that is not my brother. That is his cousin."}, - {"Jsou to tvoji rodiče? – Ne, to nejsou moji rodiče. To jsou rodiče Markuse.", - NULL, "Are those your parents? – No, those are not my parents. " - "Those are Markus's parents."}, - /* ex3 ein/kein (pets) */ - {"Máš křečka? – Ne, nemám křečka. Mám želvu.", NULL, - "Have you got a hamster? – No, I haven't got a hamster. I have a tortoise."}, - {"Máš koně? – Ne, nemám koně. Mám králíka.", NULL, - "Have you got a horse? – No, I haven't got a horse. I have a rabbit."}, - {"Máš rybu? – Ne, nemám rybu. Mám ptáka.", NULL, - "Have you got a fish? – No, I haven't got a fish. I have a bird."}, - {"Máš morče? – Ne, nemám morče. Mám andulku.", NULL, - "Have you got a guinea pig? – No, I haven't got a guinea pig. I have a budgie."}, - /* ex4 missing letters (text) */ - {"Máme přátele v Rakousku. Bydlí ve Vídni.", NULL, - "We have friends in Austria. They live in Vienna."}, - {"Jmenují se Elfriede a Jiří. Mají také děti.", NULL, - "They are called Elfriede and Jiri. They also have children."}, - {"Jejich syn se jmenuje Philipp a jejich dcera Sabine.", NULL, - "Their son is called Philipp and their daughter Sabine."}, - {"Rodina ráda cestuje.", NULL, "The family likes travelling."}, - {"Často je u nás na návštěvě v Česku.", NULL, - "They often visit us in Czechia."}, - {"Rodina ráda cestuje. Často je u nás na návštěvě v Česku.", NULL, - "The family likes travelling. They often visit us in Czechia."}, - {"Děti se učí také česky.", NULL, - "The children are also learning Czech."}, - /* ex4 word-level glosses for the gapped words */ - {"mít", NULL, "to have"}, - {"přátelé", NULL, "friends"}, - {"bydlet", NULL, "to live"}, - {"jmenovat se", NULL, "to be called"}, - {"děti", NULL, "children"}, - {"syn", NULL, "son"}, - {"jejich", NULL, "their"}, - {"rodina", NULL, "family"}, - {"cestuje", NULL, "travels"}, - {"často", NULL, "often"}, - {"návštěva", NULL, "visit"}, - {"Česko", NULL, "Czechia"}, - {"učit se", NULL, "to learn"}, - {"čeština", NULL, "Czech"}, - /* ex5 Marco's family */ - {"Máme mužskou domácnost: Můj otec Johann (50), Ivo (16) a já.", NULL, - "We live in an all-male household: my father Johann (50), Ivo (16) and me."}, - {"Ivo a já jsme stejně staří – jsme totiž dvojčata.", NULL, - "Ivo and I are the same age – we are twins."}, - {"Náš otec tu má novou práci.", NULL, - "Our father has a new job here."}, - {"Naši rodiče jsou rozvedení.", NULL, - "Our parents are divorced."}, - {"Naše matka Maja (50) žije ve Vídni, ale pochází z Chorvatska.", NULL, - "Our mother Maja (50) lives in Vienna, but she comes from Croatia."}, - {"Máme v Chorvatsku hodně strýců, tet, sestřenic a bratranců.", NULL, - "We have many uncles, aunts, male and female cousins in Croatia."}, - {"Vídáme je někdy o prázdninách.", NULL, - "We sometimes see them on holiday."}, - /* ex6 sorting vocabulary */ - {"křeček", NULL, "hamster"}, - {"babička", NULL, "grandmother"}, - {"kůň", NULL, "horse"}, - {"bratr", NULL, "brother"}, - {"kočka", NULL, "cat"}, - {"dědeček", NULL, "grandfather"}, - {"dcera", NULL, "daughter"}, - {"pes", NULL, "dog"}, - {"teta", NULL, "aunt"}, - {"andulka", NULL, "budgerigar"}, - /* ex8 possessive pronouns (accusative) */ - {"Potřebuješ svůj mobil.", NULL, "You need your mobile."}, - {"Má svého koně.", NULL, "He has his horse."}, - {"Dělá svou párty.", NULL, "She is throwing her party."}, - {"Ptá se svého učitele.", NULL, "It is asking its teacher."}, - {"Navštěvujeme náš víkendový dům.", NULL, - "We are visiting our weekend house."}, - {"Vy vidíte svého psa.", NULL, "You see your dog."}, - {"Mají své nástroje.", NULL, "They have their instruments."}, - /* ex8 grey notes showing which possessive is expected */ - {"u3g_dein", "(tvůj)", "(your)"}, - {"u3g_sein", "(jeho)", "(his)"}, - {"u3g_ihr_sie", "(její)", "(her)"}, - {"u3g_sein_es", "(jeho)", "(its)"}, - {"u3g_unser", "(náš)", "(our)"}, - {"u3g_euer", "(váš)", "(your)"}, - {"u3g_ihr_sie_pl", "(jejich)", "(their)"}, - /* ex9 kein / nicht */ - {"Mluvíš španělsky? – Ne, nemluvím španělsky.", NULL, - "Do you speak Spanish? – No, I don't speak any Spanish."}, - {"Máš bratra? – Ne, nemám bratra.", NULL, - "Have you got a brother? – No, I haven't got a brother."}, - {"Je v Opavě zoo? – Ne, v Opavě žádná zoo není.", NULL, - "Is there a zoo in Opava? – No, there is no zoo in Opava."}, - {"Jdeš do bazénu? – Ne, do bazénu nejdu.", NULL, - "Are you going to the swimming pool? – No, I am not going to the swimming pool."}, - {"Rád chodí na túry? – Ne, nerad chodí na túry.", NULL, - "Does he like hiking? – No, he does not like hiking."}, - {"Navštívíš dnes zámek? – Ne, dnes nenavštívím žádný zámek.", NULL, - "Are you visiting a castle today? – No, I am not visiting a castle today."}, - /* ex10 sentence order */ - {"Mají želvu.", NULL, "They have a tortoise."}, - {"Co dělá tvoje kamarádka o víkendu?", NULL, - "What does your friend do at the weekend?"}, - {"Můj otec je povoláním učitel.", NULL, - "My father is a teacher by profession."}, - {"Je vás doma hodně?", NULL, "Are there many of you at home?"}, - {"Julie představuje svého psa Trixiho.", NULL, - "Julia is introducing her dog Trixi."}, - /* ex11 what do you see */ - {"Vidím hrad / zámek.", NULL, "I see a castle."}, - {"Vidím jezero.", NULL, "I see a lake."}, - {"Vidím rodinu.", NULL, "I see a family."}, - /* ex12 whose is it */ - {"To je jeho mobil.", NULL, "That is his mobile."}, - {"To je její králík.", NULL, "That is her rabbit."}, - {"To jsou jejich brusle.", NULL, "Those are their inline skates."}, - {"To je její dort.", NULL, "That is her cake."}, - {"To je jeho dům.", NULL, "That is his house."}, - {"To jsou jejich děti.", NULL, "Those are their children."}, - /* ex13 es gibt */ - {"Je tu koncert.", NULL, "There is a concert."}, - {"Je tu výstava.", NULL, "There is an exhibition."}, - {"Je tu sportovní slavnost.", NULL, "There is a sports festival."}, - {"Je tu rodinné setkání.", NULL, "There is a family reunion."}, - {"Je tu divadelní představení.", NULL, "There is a theatre performance."}, - {"Je tu bleší trh.", NULL, "There is a flea market."}, - /* ex14 describe (sentence pairs) */ - {"Vidím ženu.", NULL, "I see a woman."}, - {"Jezdí na kole.", NULL, "She is riding a bike."}, - {"Vidím muže.", NULL, "I see a man."}, - {"Chodí po lese.", NULL, "He is hiking in the forest."}, - {"Vidím dvě děti.", NULL, "I see two children."}, - {"Hrají fotbal.", NULL, "They are playing football."}, - /* ex15 missing letters (weekend) */ - {"Moji prarodiče jedou o víkendu do víkendového domu.", NULL, - "My grandparents are driving to their weekend house."}, - {"Můj otec a moje matka navštíví koncert.", NULL, - "My father and my mother are going to a concert."}, - {"Moje sestra jde do kina.", NULL, - "My sister is going to the cinema."}, - {"Můj bratr jede k jezeru.", NULL, - "My brother is driving to a lake."}, - {"A já? Navštívím obchodní centrum.", NULL, - "And me? I am going to a shopping centre."}, - /* ---- unit 1: Wörter übersetzen (page headers) ---- */ - {"Strana 10", NULL, "Page 10"}, - {"Strana 11", NULL, "Page 11"}, - {"Strana 12", NULL, "Page 12"}, - {"Strana 13", NULL, "Page 13"}, - {"Strana 14", NULL, "Page 14"}, - {"Strana 15", NULL, "Page 15"}, - /* ---- unit 1: Wörter übersetzen (word meanings) ---- */ - {"večer", NULL, "evening"}, - {"Dobrý večer!", NULL, "Good evening!"}, - {"ty", NULL, "you"}, - {"Těší mě.", NULL, "Nice to meet you."}, - {"dobrý", NULL, "good"}, - {"Ahoj!", NULL, "Hello!"}, - {"jmenovat se", NULL, "to be called"}, - {"Jmenuji se Jens.", NULL, "My name is Jens."}, - {"Ahoj! (neformálně)", NULL, "Hi! (informal)"}, - {"já", NULL, "I"}, - {"vy", NULL, "you (plural)"}, - {"ano", NULL, "yes"}, - {"ráno", NULL, "morning"}, - {"jméno", NULL, "name"}, - {"ne", NULL, "no"}, - {"je", NULL, "is"}, - {"den", NULL, "day"}, - {"Dobrý den!", NULL, "Good day!"}, - {"a", NULL, "and"}, - {"kdo", NULL, "who"}, - {"Kdo jsi?", NULL, "Who are you?"}, - {"jak", NULL, "how"}, - {"my", NULL, "we"}, - {"v", NULL, "in"}, - {"poblíž, v blízkosti", NULL, "near, in the vicinity"}, - {"hra", NULL, "game"}, - {"kde", NULL, "where"}, - {"bydlet", NULL, "to live"}, - {"Kde bydlíš?", NULL, "Where do you live?"}, - {"nula", NULL, "zero"}, - {"jedna", NULL, "one"}, - {"dvě", NULL, "two"}, - {"tři", NULL, "three"}, - {"čtyři", NULL, "four"}, - {"pět", NULL, "five"}, - {"sedm", NULL, "seven"}, - {"osm", NULL, "eight"}, - {"devět", NULL, "nine"}, - {"deset", NULL, "ten"}, - {"jedenáct", NULL, "eleven"}, - {"dvanáct", NULL, "twelve"}, - {"patnáct", NULL, "fifteen"}, - {"šestnáct", NULL, "sixteen"}, - {"osmnáct", NULL, "eighteen"}, - {"devatenáct", NULL, "nineteen"}, - {"starý", NULL, "old"}, - {"on", NULL, "he"}, - {"měsíc", NULL, "month"}, - {"ona", NULL, "she"}, - {"oni", NULL, "they"}, - {"ale", NULL, "but"}, - {"věk", NULL, "age"}, - {"také", NULL, "also"}, - {"(hudební) skupina", NULL, "(music) band"}, - {"chatovat", NULL, "to chat"}, - {"počítačová hra", NULL, "computer game"}, - {"e-mail", NULL, "email"}, - {"angličtina, anglicky", NULL, "English"}, - {"fanoušek", NULL, "fan"}, - {"francouzština, francouzsky", NULL, "French"}, - {"kamarádka", NULL, "friend (f.)"}, - {"nejlepší kamarádka", NULL, "best friend (f.)"}, - {"fotbal", NULL, "football"}, - {"Je fotbalový fanatik.", NULL, "He is a football fanatic."}, - {"jít", NULL, "to go"}, - {"Rád(a) chodím na koncerty.", NULL, "I like going to concerts."}, - {"rád/a", NULL, "gladly"}, - {"kytara", NULL, "guitar"}, - {"mobil", NULL, "mobile phone"}, - {"koníček", NULL, "hobby"}, - {"poslouchat", NULL, "to listen"}, - {"Rád poslouchá hudbu.", NULL, "He likes listening to music."}, - {"surfovat na internetu", NULL, "to surf the internet"}, - {"pořád, neustále", NULL, "always"}, - {"rok", NULL, "year"}, - {"žádný/žádná/žádné", NULL, "no / none"}, - {"klavír", NULL, "piano"}, - {"přicházet, pocházet (z)", NULL, "to come (from)"}, - {"Pochází z Vídně.", NULL, "He comes from Vienna."}, - {"koncert", NULL, "concert"}, - {"ležet", NULL, "to lie"}, - {"příjmení", NULL, "surname"}, - {"nedaleko od", NULL, "not far from"}, - {"cestovat", NULL, "to travel"}, - {"psát", NULL, "to write"}, - {"škola", NULL, "school"}, - {"hrát", NULL, "to play"}, - {"Hraje na kytaru.", NULL, "She plays the guitar."}, - {"tancovat", NULL, "to dance"}, - {"křestní jméno", NULL, "first name"}, - {"bydliště", NULL, "place of residence"}, - {"nesprávně, chybně", NULL, "wrong, incorrectly"}, - {"flétna", NULL, "flute"}, - {"(hudební) nástroj", NULL, "(musical) instrument"}, - {"teď", NULL, "now"}, - {"dělat", NULL, "to do"}, - {"správně", NULL, "correctly"}, - {"sport", NULL, "sport"}, - {"sportovat", NULL, "to do sport"}, - {"squash", NULL, "squash"}, - {"jóga", NULL, "yoga"}, - {"brzy", NULL, "soon"}, - {"Brzy na shledanou!", NULL, "See you soon!"}, - {"do", NULL, "until"}, - {"Do příštího setkání!", NULL, "Until next time!"}, - {"paní", NULL, "woman / Mrs."}, - {"pan", NULL, "man / Mr."}, - {"Měj se hezky!", NULL, "Take care!"}, - {"muzeum", NULL, "museum"}, - {"Jdou do muzea.", NULL, "They are going to the museum."}, - {"hezký", NULL, "beautiful"}, - {"Hezký zbytek dne!", NULL, "Have a nice rest of the day!"}, - {"Ahoj! (servus)", NULL, "Hi! (Servus)"}, - {"Ahoj! (při loučení)", NULL, "Bye!"}, - {"shledání", NULL, "reunion"}, - {"Na shledanou!", NULL, "Goodbye!"}, - {"John von Neumann – americký matematik", NULL, - "John von Neumann – American mathematician"}, - {"Americký matematik s objevy v digitálních počítačích", NULL, - "American mathematician with discoveries in digital computers"}, - {"ALU = aritmeticko-logická jednotka", NULL, - "ALU = arithmetic-logic unit"}, - {"Řadič řídí činnost ostatních částí", NULL, - "The control unit directs the other parts"}, - {"Operační paměť uchovává program i data", NULL, - "Main memory stores both the program and data"}, - {"Byl tvůrcem teorie her", NULL, "He created game theory"}, - {"Nultá generace: 1938–1944", NULL, "Zeroth generation: 1938–1944"}, - {"Jen několik počítačů, většinou vojenský účel", NULL, - "Only a few computers, mostly for military use"}, - {"1. generace – objev elektronky", NULL, - "1st generation – invention of the vacuum tube"}, - {"1. generace – děrné štítky", NULL, "1st generation – punch cards"}, - {"2. generace – objev tranzistoru", NULL, - "2nd generation – invention of the transistor"}, - {"3. generace – integrovaný obvod", NULL, - "3rd generation – integrated circuit"}, - {"4. generace – programovatelné mikroprocesory", NULL, - "4th generation – programmable microprocessors"}, - {"1972 – první počítačová hra", NULL, "1972 – first computer game"}, - {"Bit = dvojková číslice, nejmenší jednotka informace", NULL, - "A bit is a binary digit, the smallest unit of information"}, - {"Bit nabývá hodnoty 0 nebo 1", NULL, "A bit is either 0 or 1"}, - {"Byte = nejmenší adresovatelná jednotka paměti", NULL, - "A byte is the smallest addressable unit of memory"}, - {"1 B = 8 b", NULL, "1 B = 8 b"}, - {NULL, NULL, NULL} -}; - -const char *tr(const char *key) { - static GHashTable *idx; - const TrEntry *e; - int i; - - if (!key) - return NULL; - - if (!idx) { - idx = g_hash_table_new(g_str_hash, g_str_equal); - for (i = 0; tr_ui[i].key; i++) - g_hash_table_insert(idx, (gpointer)tr_ui[i].key, - (gpointer)&tr_ui[i]); - for (i = 0; tr_content[i].key; i++) - g_hash_table_insert(idx, (gpointer)tr_content[i].key, - (gpointer)&tr_content[i]); - } - - e = g_hash_table_lookup(idx, key); - if (!e) - return key; - if (app_lang == LANG_EN) - return e->en; - return e->cs ? e->cs : e->key; -} - -void i18n_ensure(void) { - if (!i18n_binds) - i18n_binds = g_array_new(FALSE, FALSE, sizeof(I18nBind)); -} - -void i18n_apply_one(const I18nBind *b) { - if (!b->widget || !b->key) - return; - switch (b->kind) { - case 0: - gtk_label_set_text(GTK_LABEL(b->widget), tr(b->key)); - break; - case 1: - gtk_button_set_label(GTK_BUTTON(b->widget), tr(b->key)); - break; - case 2: - gtk_widget_set_tooltip_text(b->widget, tr(b->key)); - break; - case 3: - gtk_entry_set_placeholder_text(GTK_ENTRY(b->widget), tr(b->key)); - break; - case 4: - ex4_fill_sample(b->widget); - break; - default: - break; - } -} - -void i18n_bind(GtkWidget *widget, const char *key, int kind) { - I18nBind b; - - i18n_ensure(); - b.widget = widget; - b.key = key; - b.kind = kind; - g_array_append_val(i18n_binds, b); - - i18n_apply_one(&b); -} - -void refresh_welcome_heading(void) { - if (!welcome_heading) - return; - gtk_label_set_text(GTK_LABEL(welcome_heading), tr("welcome_title")); -} - -void refresh_stats_ui(void); -void net_lessons_apply_lang(void); -void hw_lessons_apply_lang(void); -void on_lessons_apply_lang(void); -void on2_lessons_apply_lang(void); -void on3_lessons_apply_lang(void); -void on4_lessons_apply_lang(void); -void en_lessons_apply_lang(void); -void de_lessons_apply_lang(void); -void quizyear_apply_lang(void); -void lit_lessons_apply_lang(void); -void sci_lessons_apply_lang(void); -void fyz_lessons_apply_lang(void); -void math_lessons_apply_lang(void); -void net_rail_theme_reset(void); - -void apply_language(void) { - guint i; - - i18n_ensure(); - for (i = 0; i < i18n_binds->len; i++) - i18n_apply_one(&g_array_index(i18n_binds, I18nBind, i)); - refresh_welcome_heading(); - refresh_stats_ui(); - update_apply_lang(); - changelog_apply_lang(); - net_lessons_apply_lang(); - hw_lessons_apply_lang(); - on_lessons_apply_lang(); - on2_lessons_apply_lang(); - on3_lessons_apply_lang(); - on4_lessons_apply_lang(); - en_lessons_apply_lang(); - de_lessons_apply_lang(); - quizyear_apply_lang(); - lit_lessons_apply_lang(); - sci_lessons_apply_lang(); - fyz_lessons_apply_lang(); - math_lessons_apply_lang(); - search_apply_lang(); -} diff --git a/src/icons.c b/src/icons.c deleted file mode 100644 index befd6c3..0000000 --- a/src/icons.c +++ /dev/null @@ -1,638 +0,0 @@ -#include "graduately.h" - -/* Vector icons drawn with cairo so they never depend on the system - * icon theme (which is missing on some installs). */ - -void draw_check_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - Rgb c = color_from_hex(app_theme.on_accent); - - (void)area; - (void)data; - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - cairo_set_line_width(cr, width * 0.16); - cairo_move_to(cr, width * 0.24, height * 0.56); - cairo_line_to(cr, width * 0.43, height * 0.74); - cairo_line_to(cr, width * 0.78, height * 0.30); - cairo_stroke(cr); -} - -/* Paint a padlock centred in the size x size box with top-left (x0,y0). */ -void lock_paint(cairo_t *cr, double x0, double y0, double size, - const Rgb *c) { - double sl = MAX(1.6, size * 0.13); /* shackle stroke width */ - double bw = size * 0.60; /* body width */ - double bh = size * 0.44; /* body height */ - double cx = x0 + size / 2.0; - double body_top = y0 + size - bh - size * 0.04; - double bx = cx - bw / 2.0; - double r = bw / 2.0 - sl / 2.0; /* shackle arc radius */ - - cairo_set_source_rgb(cr, c->r, c->g, c->b); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_width(cr, sl); - - cairo_new_path(cr); - cairo_arc(cr, cx, body_top, r, G_PI, 2.0 * G_PI); - cairo_stroke(cr); - - cairo_new_path(cr); - cairo_rectangle(cr, bx, body_top, bw, bh); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_arc(cr, cx, body_top + bh * 0.42, size * 0.07, 0.0, 2.0 * G_PI); - { - Rgb hole = color_from_hex(app_theme.crust); - cairo_set_source_rgb(cr, hole.r, hole.g, hole.b); - } - cairo_fill(cr); -} - -void draw_lock_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - Rgb c = color_from_hex(app_theme.overlay); - (void)area; - (void)data; - lock_paint(cr, 0.0, 0.0, MIN(width, height), &c); -} - -/* Wireless icon: three upward arcs that fan out from a base dot. */ -void draw_wifi_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double s = MIN(width, height); - const double cx = width / 2.0; - const double cy = height * 0.68; - const double dot_r = s * 0.06; - const double radii[3] = {s * 0.15, s * 0.27, s * 0.39}; - const double phi = 0.75; - /* Keep the icon legible on the accent-gradient bubble while giving it a - * hint of the active theme: blend the contrasting on-accent colour a - * little way towards the palette's middle accent. */ - const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent), - color_from_hex(app_theme.accent2), 0.22); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_width(cr, MAX(1.5, s * 0.07)); - - for (int i = 0; i < 3; i++) { - double r = radii[i]; - - cairo_new_path(cr); - cairo_arc(cr, cx, cy, r, -G_PI / 2.0 - phi, -G_PI / 2.0 + phi); - cairo_stroke(cr); - } - - cairo_new_path(cr); - cairo_arc(cr, cx, cy, dot_r, 0.0, 2.0 * G_PI); - cairo_fill(cr); -} - -/* CPU / chip icon for Technické vybavení. */ -void draw_chip_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double s = MIN(width, height); - const double cx = width / 2.0; - const double cy = height / 2.0; - const double body = s * 0.42; - const double pin_len = s * 0.12; - const double pin_w = s * 0.055; - const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent), - color_from_hex(app_theme.accent2), 0.22); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - - cairo_rectangle(cr, cx - body / 2.0, cy - body / 2.0, body, body); - cairo_fill(cr); - - cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); - cairo_set_line_width(cr, pin_w); - for (int i = 0; i < 4; i++) { - double t = (i + 0.5) / 4.0; - double x = cx - body / 2.0 + t * body; - double y = cy - body / 2.0 + t * body; - - cairo_move_to(cr, x, cy - body / 2.0); - cairo_line_to(cr, x, cy - body / 2.0 - pin_len); - cairo_move_to(cr, x, cy + body / 2.0); - cairo_line_to(cr, x, cy + body / 2.0 + pin_len); - cairo_move_to(cr, cx - body / 2.0, y); - cairo_line_to(cr, cx - body / 2.0 - pin_len, y); - cairo_move_to(cr, cx + body / 2.0, y); - cairo_line_to(cr, cx + body / 2.0 + pin_len, y); - } - cairo_stroke(cr); - - { - Rgb hole = color_from_hex(app_theme.crust); - double core = body * 0.34; - - cairo_set_source_rgb(cr, hole.r, hole.g, hole.b); - cairo_rectangle(cr, cx - core / 2.0, cy - core / 2.0, core, core); - cairo_fill(cr); - } -} - -/* Balance scale for Občanská nauka. */ -void draw_civics_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double s = MIN(width, height); - const double cx = width / 2.0; - const double top = height / 2.0 - s * 0.34; - const double beam_y = top + s * 0.22; - const double half = s * 0.28; - const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent), - color_from_hex(app_theme.accent2), 0.22); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_width(cr, MAX(1.6, s * 0.07)); - - cairo_move_to(cr, cx, top); - cairo_line_to(cr, cx, top + s * 0.62); - cairo_stroke(cr); - - cairo_move_to(cr, cx - half, beam_y); - cairo_line_to(cr, cx + half, beam_y); - cairo_stroke(cr); - - cairo_set_line_width(cr, MAX(1.4, s * 0.05)); - cairo_move_to(cr, cx - half, beam_y); - cairo_line_to(cr, cx - half, beam_y + s * 0.16); - cairo_move_to(cr, cx + half, beam_y); - cairo_line_to(cr, cx + half, beam_y + s * 0.16); - cairo_stroke(cr); - - cairo_new_path(cr); - cairo_arc(cr, cx - half, beam_y + s * 0.24, s * 0.11, 0.15 * G_PI, 0.85 * G_PI); - cairo_stroke(cr); - cairo_new_path(cr); - cairo_arc(cr, cx + half, beam_y + s * 0.24, s * 0.11, 0.15 * G_PI, 0.85 * G_PI); - cairo_stroke(cr); - - cairo_set_line_width(cr, MAX(1.8, s * 0.08)); - cairo_move_to(cr, cx - s * 0.16, top + s * 0.66); - cairo_line_to(cr, cx + s * 0.16, top + s * 0.66); - cairo_stroke(cr); -} - -/* Round flask for Základy přírodopisných věd. */ -void draw_science_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double s = MIN(width, height); - const double cx = width / 2.0; - const double top = height / 2.0 - s * 0.38; - const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent), - color_from_hex(app_theme.accent2), 0.22); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - cairo_set_line_width(cr, MAX(1.6, s * 0.07)); - - cairo_move_to(cr, cx - s * 0.08, top); - cairo_line_to(cr, cx - s * 0.08, top + s * 0.22); - cairo_line_to(cr, cx - s * 0.28, top + s * 0.58); - cairo_curve_to(cr, cx - s * 0.34, top + s * 0.78, - cx - s * 0.16, top + s * 0.82, - cx, top + s * 0.82); - cairo_curve_to(cr, cx + s * 0.16, top + s * 0.82, - cx + s * 0.34, top + s * 0.78, - cx + s * 0.28, top + s * 0.58); - cairo_line_to(cr, cx + s * 0.08, top + s * 0.22); - cairo_line_to(cr, cx + s * 0.08, top); - cairo_stroke(cr); - - cairo_move_to(cr, cx - s * 0.14, top); - cairo_line_to(cr, cx + s * 0.14, top); - cairo_stroke(cr); - - cairo_set_line_width(cr, MAX(1.4, s * 0.055)); - cairo_move_to(cr, cx - s * 0.16, top + s * 0.62); - cairo_line_to(cr, cx + s * 0.16, top + s * 0.62); - cairo_stroke(cr); -} - -/* Atom glyph for Fyzika: nucleus and two orbits. */ -void draw_physics_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double s = MIN(width, height); - const double cx = width / 2.0; - const double cy = height / 2.0; - const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent), - color_from_hex(app_theme.accent2), 0.22); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_width(cr, MAX(1.6, s * 0.06)); - cairo_arc(cr, cx, cy, s * 0.10, 0, 2 * G_PI); - cairo_fill(cr); - - cairo_save(cr); - cairo_translate(cr, cx, cy); - cairo_scale(cr, 1.0, 0.38); - cairo_arc(cr, 0, 0, s * 0.34, 0, 2 * G_PI); - cairo_restore(cr); - cairo_stroke(cr); - - cairo_save(cr); - cairo_translate(cr, cx, cy); - cairo_rotate(cr, 1.05); - cairo_scale(cr, 1.0, 0.38); - cairo_arc(cr, 0, 0, s * 0.34, 0, 2 * G_PI); - cairo_restore(cr); - cairo_stroke(cr); -} - -/* Axes and a rising curve for Matematika. */ -void draw_math_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double s = MIN(width, height); - const double left = width * 0.22; - const double right = width * 0.82; - const double bottom = height * 0.78; - const double top = height * 0.22; - const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent), - color_from_hex(app_theme.accent2), 0.22); - - (void)area; - (void)data; - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_width(cr, MAX(1.6, s * 0.07)); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_move_to(cr, left, top); - cairo_line_to(cr, left, bottom); - cairo_line_to(cr, right, bottom); - cairo_stroke(cr); - - cairo_move_to(cr, left + s * 0.06, bottom - s * 0.08); - cairo_curve_to(cr, left + s * 0.28, bottom - s * 0.02, - width * 0.48, height * 0.62, - right - s * 0.04, top + s * 0.06); - cairo_stroke(cr); -} - -/* Open book glyph, painted in the given colour. */ -static void book_paint(cairo_t *cr, int width, int height, Rgb c) { - const double w = width; - const double h = height; - const double mid = w * 0.5; - const double gap = w * 0.045; /* spine gap so the pages read apart */ - const double lmid = mid - gap; - const double rmid = mid + gap; - const double left = w * 0.13; - const double right = w * 0.87; - const double top = h * 0.24; - const double bot = h * 0.80; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - - cairo_new_path(cr); - cairo_move_to(cr, lmid, top); - cairo_curve_to(cr, w * 0.40, top - h * 0.07, - w * 0.24, top - h * 0.02, left, top + h * 0.07); - cairo_line_to(cr, left, bot - h * 0.05); - cairo_curve_to(cr, w * 0.24, bot - h * 0.11, - w * 0.40, bot - h * 0.05, lmid, bot); - cairo_close_path(cr); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_move_to(cr, rmid, top); - cairo_curve_to(cr, w * 0.60, top - h * 0.07, - w * 0.76, top - h * 0.02, right, top + h * 0.07); - cairo_line_to(cr, right, bot - h * 0.05); - cairo_curve_to(cr, w * 0.76, bot - h * 0.11, - w * 0.60, bot - h * 0.05, rmid, bot); - cairo_close_path(cr); - cairo_fill(cr); -} - -/* Open book icon – used on light surfaces (cards, section headers). */ -void draw_book_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const Rgb c = mix_rgb(color_from_hex(app_theme.accent2), - color_from_hex(app_theme.accent3), 0.35); - - (void)area; - (void)data; - book_paint(cr, width, height, c); -} - -/* Open book icon for the accent-gradient roadmap bubbles: uses the - * contrasting on-accent colour so it stays visible on the gradient. */ -void draw_book_badge_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const Rgb c = mix_rgb(color_from_hex(app_theme.on_accent), - color_from_hex(app_theme.accent2), 0.22); - - (void)area; - (void)data; - book_paint(cr, width, height, c); -} - -/* Question mark in a circle – quiz. */ -void draw_quiz_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const Rgb c = color_from_hex(app_theme.accent); - PangoLayout *layout; - PangoFontDescription *fd; - int tw, th; - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - layout = pango_cairo_create_layout(cr); - fd = pango_font_description_new(); - pango_font_description_set_weight(fd, PANGO_WEIGHT_HEAVY); - pango_font_description_set_absolute_size( - fd, MIN(width, height) * 1.05 * PANGO_SCALE); - pango_layout_set_font_description(layout, fd); - pango_layout_set_text(layout, "?", -1); - pango_layout_get_pixel_size(layout, &tw, &th); - cairo_move_to(cr, (width - tw) / 2.0, (height - th) / 2.0); - pango_cairo_show_layout(cr, layout); - pango_font_description_free(fd); - g_object_unref(layout); -} - -/* Two opposing arrows – ordering / drag & drop. */ -void draw_order_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double w = width; - const double h = height; - const Rgb c = color_from_hex(app_theme.success2); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_width(cr, MAX(1.6, MIN(w, h) * 0.11)); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - cairo_move_to(cr, w * 0.36, h * 0.80); - cairo_line_to(cr, w * 0.36, h * 0.24); - cairo_move_to(cr, w * 0.22, h * 0.40); - cairo_line_to(cr, w * 0.36, h * 0.24); - cairo_line_to(cr, w * 0.50, h * 0.40); - cairo_stroke(cr); - - cairo_new_path(cr); - cairo_move_to(cr, w * 0.64, h * 0.20); - cairo_line_to(cr, w * 0.64, h * 0.76); - cairo_move_to(cr, w * 0.50, h * 0.60); - cairo_line_to(cr, w * 0.64, h * 0.76); - cairo_line_to(cr, w * 0.78, h * 0.60); - cairo_stroke(cr); -} - -/* Globe – the world / superpowers. */ -void draw_globe_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double cx = width / 2.0; - const double cy = height / 2.0; - const double r = MIN(width, height) * 0.36; - const Rgb c = color_from_hex(app_theme.accent2); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - cairo_set_line_width(cr, MAX(1.4, r * 0.13)); - - cairo_new_path(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_stroke(cr); - - cairo_save(cr); - cairo_translate(cr, cx, cy); - cairo_scale(cr, 0.52, 1.0); - cairo_new_path(cr); - cairo_arc(cr, 0.0, 0.0, r, 0.0, 2.0 * G_PI); - cairo_stroke(cr); - cairo_restore(cr); - - cairo_new_path(cr); - cairo_move_to(cr, cx - r, cy); - cairo_line_to(cr, cx + r, cy); - cairo_move_to(cr, cx - r * 0.86, cy - r * 0.52); - cairo_line_to(cr, cx + r * 0.86, cy - r * 0.52); - cairo_move_to(cr, cx - r * 0.86, cy + r * 0.52); - cairo_line_to(cr, cx + r * 0.86, cy + r * 0.52); - cairo_stroke(cr); -} - -/* Two people – characters. */ -void draw_people_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const Rgb c = color_from_hex(app_theme.accent3); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - - cairo_new_path(cr); - cairo_arc(cr, width * 0.38, height * 0.36, width * 0.15, - 0.0, 2.0 * G_PI); - cairo_fill(cr); - cairo_new_path(cr); - cairo_arc(cr, width * 0.38, height * 1.02, width * 0.30, - G_PI, 2.0 * G_PI); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_arc(cr, width * 0.67, height * 0.42, width * 0.13, - 0.0, 2.0 * G_PI); - cairo_fill(cr); - cairo_new_path(cr); - cairo_arc(cr, width * 0.67, height * 1.06, width * 0.27, - G_PI, 2.0 * G_PI); - cairo_fill(cr); -} - -/* Light bulb – key terms / ideas. */ -void draw_bulb_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double cx = width / 2.0; - const double r = MIN(width, height) * 0.30; - const double cy = height * 0.40; - const Rgb c = color_from_hex(app_theme.warning); - - (void)area; - (void)data; - - cairo_set_source_rgb(cr, c.r, c.g, c.b); - - cairo_new_path(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_rectangle(cr, cx - r * 0.45, cy + r * 0.72, - r * 0.90, r * 0.66); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_arc(cr, cx, cy + r * 1.72, r * 0.52, 0.0, G_PI); - cairo_fill(cr); -} - -void draw_back_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double size = 15.0; /* fixed logical icon size */ - const double stroke = 1.8; - double ox = (width - size) / 2.0; - double oy = (height - size) / 2.0; - GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET(area)); - GdkRGBA color; - - (void)data; - gtk_style_context_get_color(gtk_widget_get_style_context(parent), &color); - cairo_set_source_rgb(cr, color.red, color.green, color.blue); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - cairo_set_line_width(cr, stroke); - cairo_move_to(cr, ox + size * 0.72, oy + size * 0.24); - cairo_line_to(cr, ox + size * 0.30, oy + size * 0.50); - cairo_line_to(cr, ox + size * 0.72, oy + size * 0.76); - cairo_stroke(cr); -} - -void draw_settings_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const int teeth = 8; - const double size = 16.0; - double cx = width / 2.0; - double cy = height / 2.0; - double r_outer = size * 0.48; - double r_inner = size * 0.34; - double r_hole = size * 0.16; - double tooth_half = G_PI / (double)teeth; - GtkWidget *color_w = data ? GTK_WIDGET(data) - : gtk_widget_get_parent(GTK_WIDGET(area)); - GdkRGBA color; - int i; - - gtk_style_context_get_color(gtk_widget_get_style_context(color_w), &color); - cairo_set_source_rgb(cr, color.red, color.green, color.blue); - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); - - cairo_new_path(cr); - for (i = 0; i < teeth; i++) { - double a = -G_PI / 2.0 + (2.0 * G_PI * (double)i) / (double)teeth; - double a0 = a - tooth_half * 0.55; - double a1 = a - tooth_half * 0.28; - double a2 = a + tooth_half * 0.28; - double a3 = a + tooth_half * 0.55; - - if (i == 0) - cairo_move_to(cr, cx + cos(a0) * r_inner, cy + sin(a0) * r_inner); - else - cairo_line_to(cr, cx + cos(a0) * r_inner, cy + sin(a0) * r_inner); - - cairo_line_to(cr, cx + cos(a1) * r_outer, cy + sin(a1) * r_outer); - cairo_line_to(cr, cx + cos(a2) * r_outer, cy + sin(a2) * r_outer); - cairo_line_to(cr, cx + cos(a3) * r_inner, cy + sin(a3) * r_inner); - } - cairo_close_path(cr); - cairo_new_sub_path(cr); - cairo_arc(cr, cx, cy, r_hole, 0.0, 2.0 * G_PI); - cairo_fill(cr); -} - -void draw_stats_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - GtkWidget *color_w = data ? GTK_WIDGET(data) - : gtk_widget_get_parent(GTK_WIDGET(area)); - GdkRGBA color; - const double bar_w = 3.2; - const double gap = 2.6; - const double total_w = 3.0 * bar_w + 2.0 * gap; - const double heights[3] = {0.42, 0.72, 1.0}; - double base_x = (width - total_w) / 2.0; - double base_y = height * 0.82; - double max_h = height * 0.58; - int i; - - (void)area; - gtk_style_context_get_color(gtk_widget_get_style_context(color_w), &color); - cairo_set_source_rgb(cr, color.red, color.green, color.blue); - cairo_set_line_width(cr, 1.5); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - - for (i = 0; i < 3; i++) { - double x = base_x + (double)i * (bar_w + gap); - double h = max_h * heights[i]; - double y = base_y - h; - double r = 1.2; - - cairo_new_sub_path(cr); - cairo_arc(cr, x + r, y + r, r, G_PI, 1.5 * G_PI); - cairo_arc(cr, x + bar_w - r, y + r, r, 1.5 * G_PI, 2.0 * G_PI); - cairo_line_to(cr, x + bar_w, base_y); - cairo_line_to(cr, x, base_y); - cairo_close_path(cr); - cairo_fill(cr); - } -} - -void draw_search_icon(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - GtkWidget *color_w = data ? GTK_WIDGET(data) - : gtk_widget_get_parent(GTK_WIDGET(area)); - GdkRGBA color; - double cx = width / 2.0 - 1.4; - double cy = height / 2.0 - 1.4; - double r = MIN(width, height) * 0.28; - - (void)area; - gtk_style_context_get_color(gtk_widget_get_style_context(color_w), &color); - cairo_set_source_rgb(cr, color.red, color.green, color.blue); - cairo_set_line_width(cr, 1.7); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - - cairo_new_sub_path(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_stroke(cr); - - cairo_move_to(cr, cx + r * 0.72, cy + r * 0.72); - cairo_line_to(cr, cx + r * 1.55, cy + r * 1.55); - cairo_stroke(cr); -} - -GtkWidget *icon_area_new(GtkDrawingAreaDrawFunc fn, - double r, double g, double b, int px) { - Rgb *col = g_new(Rgb, 1); - GtkWidget *d = gtk_drawing_area_new(); - - col->r = r; - col->g = g; - col->b = b; - gtk_widget_set_size_request(d, px, px); - gtk_widget_set_halign(d, GTK_ALIGN_CENTER); - gtk_widget_set_valign(d, GTK_ALIGN_CENTER); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(d), fn, - col, (GDestroyNotify)g_free); - return d; -} diff --git a/src/it_year_pages.c b/src/it_year_pages.c deleted file mode 100644 index 764012e..0000000 --- a/src/it_year_pages.c +++ /dev/null @@ -1,2606 +0,0 @@ -#include "graduately.h" - -/* Generated by scripts/gen-it-years.py. Do not edit by hand. */ - -static GtkWidget *build_net2_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • VLAN", "Oddělení provozu", "Tip: VLAN není samostatný kabel, je to značka v rámci.", - { - "VLAN sdružuje porty do jedné vysílací domény.", - "Počítače v různých VLAN spolu přímo na druhé vrstvě nemluví.", - "Číslo VLAN se na trunku vozí ve značce 802.1Q.", - "Nativní VLAN na trunku jede neznačkovaná. Na obou koncích musí sedět.", - NULL, - }, - }, - { - "2 / 3 • Porty", "Access a trunk", "Tip: access port patří do jedné VLAN, trunk jich nese víc.", - { - "Access port se připojuje ke koncovému zařízení.", - "Trunk spojuje přepínače nebo přepínač s routerem.", - "Povolené VLAN na trunku omezí, co smí přejít.", - "Špatně nastavený trunk pustí cizí VLAN do špatné sítě.", - NULL, - }, - }, - { - "3 / 3 • Provoz", "K čemu se VLAN hodí", "Tip: oddělení hostů od školy nesmí stát jen na hesle Wi-Fi.", - { - "Hosté, škola a správa mohou sdílet jeden přepínač.", - "Hlasová VLAN oddělí telefony od dat.", - "Mezi VLAN se dostane jen směrovač nebo přepínač třetí vrstvy.", - "VLAN zmenšuje broadcast, nenahrazuje firewall.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 0, "net2_unit1", "net2_unit1_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co VLAN na přepínači dělá?", {"Sdruží porty do jedné vysílací domény", "Zrychlí procesor serveru", "Nahradí šifrování WPA3", "Přidělí veřejnou IPv4 adresu"}, 4, 0}, - {"Jak se VLAN pozná na trunku?", {"Značkou 802.1Q v rámci", "Jinou MAC adresou zdroje", "Jiným konektorem RJ11", "Bitem v ICMP"}, 4, 0}, - {"Kam patří access port?", {"Ke koncovému počítači v jedné VLAN", "Jen mezi dvěma routery", "Na optický spoj s vlnovým multiplexem", "Do napájecího zdroje"}, 4, 0}, - {"Jak spolu mluví dvě různé VLAN?", {"Přes směrování, ne přímo na druhé vrstvě", "Samy od sebe, VLAN je jen barva kabelu", "Jedině přes ARP broadcast do všech VLAN", "Jen když mají stejnou MAC adresu"}, 4, 0}, - }; - static const char *hints[] = { - "VLAN odděluje provoz na druhé vrstvě.", - "802.1Q vloží do ethernetového rámce číslo VLAN.", - "Access port má jednu VLAN a značku obvykle sundá.", - "Mezi VLAN je potřeba router nebo L3 switch.", - }; - return quizyear_quiz(qy_net2, 0, "net2_ex1_title", "net2_quiz1_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net2_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Smyčka", "Broadcastová bouře", "Tip: na druhé vrstvě není TTL, rámec může kroužit donekonečna.", - { - "Dva kabely mezi stejnými přepínači vytvoří smyčku.", - "Broadcast se kopíruje na všechny porty a vrátí se zpět.", - "Přepínač se zahltí a přestane přenášet užitečný provoz.", - "Na třetí vrstvě paket TTL snižuje, ethernetový rámec ne.", - NULL, - }, - }, - { - "2 / 3 • STP", "Jedna aktivní cesta", "Tip: STP nevybírá nejrychlejší cestu pro data, brání smyčce.", - { - "Přepínače si volí root bridge, obvykle nejnižší bridge ID.", - "Některé porty zůstanou ve stavu blocking a rámce nepřeposílají.", - "Když aktivní linka spadne, blocking port se může otevřít.", - "RSTP reaguje rychleji než původní STP.", - NULL, - }, - }, - { - "3 / 3 • Ochrana", "Porty, které nemají přepínat", "Tip: port k tiskárně nemá poslouchat cizí BPDU.", - { - "PortFast na access portu zrychlí připojení počítače.", - "BPDU Guard port shodí, když na něm přijde BPDU.", - "Root Guard brání tomu, aby se cizí switch stal rootem.", - "Záložní kabel má smysl, ale jen se zapnutým STP.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 1, "net2_unit2", "net2_unit2_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč je smyčka na přepínačích nebezpečná?", {"Broadcast může kroužit bez omezení TTL", "IPv4 přestane mít masku", "DNS přejmenuje domény", "Procesor v počítači se vypne"}, 4, 0}, - {"Co STP s nadbytečným portem udělá?", {"Nechá ho blokovat, aby nevznikla smyčka", "Zdvojnásobí rychlost obou kabelů", "Smaže MAC tabulku navždy", "Přesměruje port na VLAN 1 a vypne ostatní"}, 4, 0}, - {"K čemu je BPDU Guard?", {"Shodí access port, na kterém se objeví cizí přepínač", "Šifruje heslo k Wi-Fi", "Přiděluje IPv6 adresy", "Měří útlum optiky"}, 4, 0}, - {"Které tvrzení o RSTP sedí?", {"Na výpadek reaguje rychleji než původní STP", "Ruší potřebu VLAN", "Funguje jen na IPv6", "Nahrazuje směrovací tabulku"}, 4, 0}, - }; - static const char *hints[] = { - "Ethernetový rámec nemá TTL.", - "Blocking port rámce nepřeposílá, dokud není potřeba.", - "Na portu pro počítač nemá co dělat protokol přepínačů.", - "RSTP zkracuje čekání při změně topologie.", - }; - return quizyear_quiz(qy_net2, 1, "net2_ex2_title", "net2_quiz2_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net2_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • DHCP", "Adresa bez opisování", "Tip: DHCP dává adresu na čas, ne navždy.", - { - "Klient pošle broadcast a hledá server.", - "Nabídka obsahuje adresu, masku, bránu a DNS.", - "Zapůjčení má dobu platnosti a klient ji obnovuje.", - "Rezervace přiváže adresu ke konkrétní MAC adrese.", - NULL, - }, - }, - { - "2 / 3 • Rozsah", "Co se nesmí překrývat", "Tip: dva servery se stejnou adresou v jedné síti si škodí.", - { - "Rozsah musí ležet v síti, kterou má brána.", - "Statické adresy serverů do rozsahu nepatří, nebo se vyloučí.", - "Špatná brána v nabídce odřízne celou VLAN od internetu.", - "DHCP relay přenese požadavek z VLAN, kde server není.", - NULL, - }, - }, - { - "3 / 3 • DNS", "Jméno na adresu", "Tip: DNS není totéž co DHCP. Jedno dává adresu, druhé jméno.", - { - "A záznam ukazuje na IPv4, AAAA na IPv6.", - "Reverzní PTR překládá adresu zpět na jméno.", - "Rekurzivní resolver se ptá dál, autoritativní server zónu vlastní.", - "TTL u záznamu říká, jak dlouho se smí odpověď cacheovat.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 2, "net2_unit3", "net2_unit3_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co klient od DHCP obvykle dostane?", {"Adresu, masku, bránu a DNS", "Jen heslo k Wi-Fi", "Novou MAC adresu", "Kořenový certifikát webu"}, 4, 0}, - {"Proč se rezervace v DHCP hodí?", {"Zařízení s danou MAC dostane pořád stejnou adresu", "Vypne potřebu masky", "Nahradí směrování", "Zašifruje disk"}, 4, 0}, - {"Čím se liší A a AAAA?", {"A je IPv4, AAAA je IPv6", "A je pošta, AAAA je web", "A je jméno VLAN, AAAA je číslo portu", "Oba ukazují jen na IPv4"}, 4, 0}, - {"K čemu je DHCP relay?", {"Pošle požadavek z jiné VLAN k serveru", "Překládá jména bez DNS", "Blokuje STP", "Mění rychlost portu na 10 Gb/s"}, 4, 0}, - }; - static const char *hints[] = { - "To jsou čtyři údaje, bez kterých stanice v síti nepracuje.", - "Rezervace je vhodná pro tiskárny a kamery.", - "Čtyři A v názvu připomínají delší IPv6 adresu.", - "Broadcast DHCP jinak VLAN neopustí.", - }; - return quizyear_quiz(qy_net2, 2, "net2_ex3_title", "net2_quiz3_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net2_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • NAT", "Soukromé adresy ven", "Tip: 192.168.0.0/16 a 10.0.0.0/8 na internetu směrovat nejdou.", - { - "NAT přepíše zdrojovou adresu při odchodu z lokální sítě.", - "Zpět router podle tabulky překladů provoz vrátí.", - "Zvenku nikdo sám od sebe spojení dovnitř nenaváže.", - "To je vedlejší efekt, ne náhrada firewallu.", - NULL, - }, - }, - { - "2 / 3 • PAT", "Mnoho počítačů, jedna adresa", "Tip: PAT si pamatuje i číslo portu, ne jen adresu.", - { - "Více vnitřních adres sdílí jednu veřejnou.", - "Rozliší je zdrojový port.", - "Domácí router dělá téměř vždy PAT, ne čistý NAT jedna ku jedné.", - "Dojdou-li porty, nová spojení se neotevřou.", - NULL, - }, - }, - { - "3 / 3 • Dovnitř", "Když má server být vidět", "Tip: přesměrování portu otevře jen tu službu, kterou opravdu chcete.", - { - "Port forward pošle příchozí port na vnitřní adresu.", - "Na serveru pak musí poslouchat daná služba a firewall ji pustit.", - "DMZ na domácím routeru vystaví jeden počítač hodně otevřeně.", - "Lepší je konkrétní port než celá DMZ.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 3, "net2_unit4", "net2_unit4_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč stanice s adresou 192.168.1.20 není z internetu vidět přímo?", {"Je to soukromá adresa a ven jde až přes NAT", "IPv4 takové adresy nezná", "MAC adresa se na internetu nesmí použít jako jméno", "DNS soukromé adresy maže"}, 4, 0}, - {"Čím se PAT liší od NAT jedna ku jedné?", {"Více vnitřních adres sdílí jednu veřejnou a liší se portem", "PAT šifruje provoz", "PAT funguje jen pro IPv6", "PAT ruší potřebu brány"}, 4, 0}, - {"K čemu je přesměrování portu?", {"Příchozí spojení na daný port pošle na vnitřní server", "Přidělí VLAN", "Zapne STP", "Změní masku celé školy na /8"}, 4, 0}, - {"Proč NAT není firewall?", {"Jen překládá adresy, pravidla provozu řeší firewall", "NAT umí totéž co antivir", "NAT kontroluje hesla uživatelů", "NAT šifruje Wi-Fi"}, 4, 0}, - }; - static const char *hints[] = { - "Soukromé rozsahy se mezi poskytovateli nesměrují.", - "Překlad zahrnuje adresu i port.", - "Bez něj zvenku na vnitřní web sami nedosáhnete.", - "Nechtěný publikovaný port NAT klidně pustí.", - }; - return quizyear_quiz(qy_net2, 3, "net2_ex4_title", "net2_quiz4_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net2_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Adresa", "128 bitů", "Tip: nuly v jedné skupině za sebou smí zkrátit :: jen jednou.", - { - "Adresa má osm skupin po čtyřech hexadecimálních číslicích.", - "Prefix se píše jako /64, ne jako stará maska 255.255.255.0.", - "Link-local adresa fe80:: platí jen na tom spoji.", - "Globální adresa je vidět i mimo místní spoj.", - NULL, - }, - }, - { - "2 / 3 • Přidělení", "SLAAC a DHCPv6", "Tip: výchozí bránu v IPv6 často ohlašuje router, ne DHCP.", - { - "Router advertisement řekne prefix a jestli se stanice smí nastavit sama.", - "SLAAC složí adresu z prefixu a identifikátoru rozhraní.", - "DHCPv6 přidá adresu nebo jen DNS, podle příznaků.", - "Obě varianty mohou běžet vedle sebe.", - NULL, - }, - }, - { - "3 / 3 • Vedle IPv4", "Dual stack", "Tip: IPv6 nevypínejte jen proto, že mu nerozumíte. Rozbitý IPv6 zpomalí i weby.", - { - "Počítač může mít IPv4 i IPv6 naráz.", - "DNS AAAA záznam rozhoduje, jestli se klient zkusí spojit po IPv6.", - "NAT u IPv6 není nutný tak jako u IPv4, ale firewall ano.", - "Ping na IPv6 je jiný příkaz než ping na IPv4, podle systému.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 4, "net2_unit5", "net2_unit5_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak je IPv6 adresa dlouhá?", {"128 bitů", "32 bitů", "48 bitů", "256 bitů"}, 4, 0}, - {"Která adresa je link-local?", {"fe80::1", "192.168.1.1", "8.8.8.8", "255.255.255.255"}, 4, 0}, - {"Kdo v IPv6 často oznámí prefix?", {"Router advertisement", "ARP request", "STP hello", "Jen ruční zápis do hosts"}, 4, 0}, - {"Co znamená dual stack?", {"Zařízení používá IPv4 i IPv6", "Dva switche v jedné VLAN", "Dvě masky u jedné IPv4 adresy", "Záloha jen na pásku"}, 4, 0}, - }; - static const char *hints[] = { - "IPv4 má 32 bitů, IPv6 čtyřikrát tolik.", - "fe80:: platí jen na místním spoji.", - "Router říká stanicím, jaký prefix na spoji platí.", - "Oba protokoly běží současně.", - }; - return quizyear_quiz(qy_net2, 4, "net2_ex5_title", "net2_quiz5_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net2_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Trasa", "Kam s paketem", "Tip: směrovací tabulka se dívá na síť, ne na jednu adresu stanice.", - { - "Záznam říká síť, masku nebo prefix a další skok.", - "Další skok musí být dosažitelný na přímo připojeném rozhraní.", - "Výchozí trasa 0.0.0.0/0 chytí vše, co nemá přesnější záznam.", - "Přesnější prefix vyhraje nad kratším.", - NULL, - }, - }, - { - "2 / 3 • Metrika", "Když je cest víc", "Tip: nižší administrativní vzdálenost znamená důvěryhodnější zdroj trasy.", - { - "Statická trasa má lepší vzdálenost než OSPF nebo RIP.", - "Metrika porovnává trasy ze stejného zdroje.", - "Plovoucí statická trasa má horší vzdálenost a čeká jako záloha.", - "Špatný další skok vytvoří černou díru: paket odejde a ztratí se.", - NULL, - }, - }, - { - "3 / 3 • Meze", "Kdy ruční tabulka nestačí", "Tip: deset poboček se statickými trasami neudržíte po každé změně.", - { - "Statika je přehledná v malé síti a na okraji k poskytovateli.", - "Neumí sama obejít spadlou cestu, pokud záloha není připravená.", - "Na směrovači musí sedět trasa tam i zpět, jinak odpověď nepřijde.", - "Změna adresace znamená obejít všechny ruční záznamy.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 5, "net2_unit6", "net2_unit6_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Na co se směrovač dívá při výběru trasy?", {"Na síť a prefix, ne na jméno počítače", "Na barvu kabelu", "Na VLAN jméno v DNS", "Jen na MAC adresu cíle"}, 4, 0}, - {"Která trasa je výchozí?", {"0.0.0.0/0", "255.255.255.255/32", "192.168.1.1/32", "::1/128"}, 4, 0}, - {"Co je plovoucí statická trasa?", {"Záložní ruční trasa s horší vzdáleností", "Trasa, která plave mezi VLAN bez routeru", "Automatický OSPF", "Záznam jen v ARP"}, 4, 0}, - {"Proč odpověď ze serveru nedorazí, i když tam paket došel?", {"Chybí zpáteční trasa", "TCP nemá porty", "IPv4 neumí odpovědi", "Switch maže cílové MAC adresy"}, 4, 0}, - }; - static const char *hints[] = { - "Třetí vrstva směruje podle prefixu.", - "Nulová síť s nulovým prefixem chytí zbytek.", - "Nastoupí, až když zmizí lepší cesta.", - "Cesta musí existovat oběma směry.", - }; - return quizyear_quiz(qy_net2, 5, "net2_ex6_title", "net2_quiz6_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net2_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Pravidla", "Pořadí rozhoduje", "Tip: první shoda vyhrává. Obecné povolení na začátku pozdější zákaz schová.", - { - "ACL zkouší řádky shora dolů.", - "Na konci bývá tiché zamítnutí všeho ostatního.", - "Pravidlo umí adresu, protokol a port.", - "Jedno špatné pořadí otevře službu, kterou jste chtěli zavřít.", - NULL, - }, - }, - { - "2 / 3 • Směr", "Dovnitř a ven", "Tip: blíž zdroji filtrujte to, co nemá vůbec vstoupit.", - { - "Příchozí ACL sedí na paketech, které do rozhraní vcházejí.", - "Odchozí ACL sedí na paketech, které rozhraní opouštějí.", - "Filtr na VLAN rozhraní hlídá provoz mezi sítěmi.", - "ACL na směrovači nevidí provoz, který zůstane uvnitř jednoho switche.", - NULL, - }, - }, - { - "3 / 3 • Praxe", "Co obvykle pustit", "Tip: nejdřív povolte, co potřebujete, a zbytek nechte spadnout.", - { - "Správa směrovače nemá poslouchat z hostovské VLAN.", - "Do serverové sítě pusťte jen porty služeb, které tam jsou.", - "ICMP můžete omezit, ale úplný zákaz ztíží hledání chyb.", - "Po změně ACL ověřte, že legitimní provoz pořád prochází.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 6, "net2_unit7", "net2_unit7_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak ACL vybírá pravidlo?", {"Použije první řádek, který sedí", "Sečte všechny řádky a udělá průměr", "Vždy použije poslední řádek", "Ptá se DNS"}, 4, 0}, - {"Co udělá tiché zamítnutí na konci?", {"Zahodí provoz, který žádný řádek nepovolil", "Povolí všechno, co zbylo", "Přepne port do trunku", "Pošle paket do IPv6"}, 4, 0}, - {"Proč ACL na routeru nehlídá dva počítače v jedné VLAN?", {"Jejich rámce jdou jen přes switch a k routeru nemusí", "ACL umí jen Wi-Fi", "VLAN nemá MAC adresy", "TCP takový provoz šifruje před switchem"}, 4, 0}, - {"Kam nepatří správa routeru?", {"Do hostovské sítě", "Na konzolový port technika", "Do správní VLAN", "Na šifrované SSH z dohledu"}, 4, 0}, - }; - static const char *hints[] = { - "Pořadí je součást významu seznamu.", - "Co není povoleno, neprojde.", - "Provoz uvnitř VLAN zůstane na druhé vrstvě.", - "Host nemá mít cestu na správu infrastruktury.", - }; - return quizyear_quiz(qy_net2, 6, "net2_ex7_title", "net2_quiz7_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net2_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • SSID", "Více sítí, jedna infrastruktura", "Tip: hostovské SSID má skončit v jiné VLAN než učitelé.", - { - "Jedno rádio může ohlašovat víc SSID.", - "Každé SSID se mapuje na VLAN.", - "Schované SSID není zabezpečení, jméno jde pořád zachytit.", - "Stejné SSID na více přístupových bodech umožní přechod.", - NULL, - }, - }, - { - "2 / 3 • Klíče", "WPA2 a WPA3", "Tip: společné heslo PSK se nedá vzít jednomu člověku, aniž by ho dostali všichni.", - { - "WPA2-Personal sdílí jedno heslo.", - "WPA2-Enterprise ověřuje uživatele přes RADIUS.", - "WPA3 lépe chrání i slabší hesla a má lepší dopředné utajení.", - "Starý WEP se nepoužívá.", - NULL, - }, - }, - { - "3 / 3 • Pokrytí", "Kanály a přechod", "Tip: dva sousední body na stejném kanále si překážejí.", - { - "Pásmo 2,4 GHz má málo nepřekrývajících se kanálů.", - "5 GHz má víc kanálů a hůř prochází zdí.", - "Výkon nesmí být zbytečně vysoký, jinak buňky slyší i cizí provoz.", - "Roaming funguje, když se SSID a zabezpečení shodují.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net2, 7, "net2_unit8", "net2_unit8_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net2_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kam má vést hostovské SSID?", {"Do vlastní VLAN, oddělené od školní sítě", "Do stejné sítě jako ředitelna", "Přímo do správy routeru", "Do sítě bez DHCP i bez izolace"}, 4, 0}, - {"Čím se liší WPA2-Enterprise od společného hesla?", {"Každý uživatel se ověřuje zvlášť, často přes RADIUS", "Nemá šifrování", "Funguje jen na 2,4 GHz", "Sdílí jeden klíč napsaný na tabuli"}, 4, 0}, - {"Proč schované SSID není ochrana?", {"Jméno sítě jde při připojení stejně zachytit", "Skryté SSID nejde vůbec použít", "WPA3 ho zakazuje", "Switch ho vyhlásí v STP"}, 4, 0}, - {"Co vadí dvěma sousedním AP na stejném kanále?", {"Slyší se a kazí si přenos", "Smažou si VLAN", "Přestanou dělat DHCP", "Změní IPv6 na IPv4"}, 4, 0}, - }; - static const char *hints[] = { - "Host nemá vidět školní servery.", - "Účet jde odebrat jednomu člověku.", - "Utajené jméno není šifra.", - "Kanály se mají plánovat, ne nechat náhodě.", - }; - return quizyear_quiz(qy_net2, 7, "net2_ex8_title", "net2_quiz8_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Sousedé", "Stejná oblast", "Tip: OSPF soused nevznikne, když se neshoduje oblast nebo hello.", - { - "Směrovače v jednom spoji si vymění hello.", - "Hello interval a dead interval musí sedět.", - "Oblast 0 je páteř. Ostatní oblasti se k ní připojují.", - "Pasivní rozhraní hello neposílá, třeba k počítačům.", - NULL, - }, - }, - { - "2 / 3 • Cena", "Kratší neznamená míň skoků", "Tip: OSPF sčítá cenu linek, ne počet routerů jako RIP.", - { - "Rychlejší linka má obvykle nižší cenu.", - "Součet cen rozhodne, kudy paket půjde.", - "Ruční cena umí odtáhnout provoz ze špatné linky.", - "Změna topologie se přepočítá bez přepisování statických tras.", - NULL, - }, - }, - { - "3 / 3 • Tabulka", "Co se z OSPF stane", "Tip: v tabulce uvidíte zdroj trasy, ne jen další skok.", - { - "Naučená síť se vloží do směrovací tabulky.", - "Když lepší cesta spadne, použije se náhradní.", - "Redistribuce natáhne do OSPF i statiku nebo jiný protokol.", - "Špatná redistribuce umí do sítě pustit cizí trasy.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 0, "net3_unit1", "net3_unit1_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co musí u OSPF sousedů sedět?", {"Oblast a časy hello", "Stejná MAC adresa", "Stejné SSID", "Stejný počet VLAN na switchi"}, 4, 0}, - {"Podle čeho OSPF vybírá cestu?", {"Podle součtu cen linek", "Podle počtu písmen v názvu routeru", "Podle VLAN ID", "Podle stáří DNS záznamu"}, 4, 0}, - {"K čemu je pasivní rozhraní?", {"Neposílá hello tam, kde žádný soused být nemá", "Vypne směrování celé sítě", "Zapne NAT", "Skryje SSID"}, 4, 0}, - {"Co je oblast 0?", {"Páteř, ke které se ostatní oblasti připojují", "VLAN pro hosty", "Výchozí heslo WPA", "Číslo konzolového portu"}, 4, 0}, - }; - static const char *hints[] = { - "Nesoulad hello nebo oblasti sousedství nesestaví.", - "Cena vyjadřuje náklad cesty, často odvozený z rychlosti.", - "K uživatelům se hello zbytečně neposílá.", - "Bez páteře se víc oblastí OSPF nespojí správně.", - }; - return quizyear_quiz(qy_net3, 0, "net3_ex1_title", "net3_quiz1_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Router na tyči", "Jeden spoj, víc VLAN", "Tip: trunk k routeru nese značky a každá VLAN má své podrozhraní.", - { - "Switch pošle trunk do routeru.", - "Každá VLAN má vlastní IP bránu.", - "Stanice má jako bránu adresu své VLAN, ne cizí.", - "Bez trasy mezi VLAN k sobě sítě nedosáhnou.", - NULL, - }, - }, - { - "2 / 3 • L3 switch", "Směrování v přepínači", "Tip: přepínač třetí vrstvy má pro VLAN rozhraní SVI.", - { - "SVI je virtuální rozhraní s adresou brány.", - "Provoz mezi VLAN nemusí odejít na samostatný router.", - "ACL na SVI hlídá, která VLAN kam smí.", - "Zapomenuté SVI znamená, že VLAN nemá bránu.", - NULL, - }, - }, - { - "3 / 3 • Chyby", "Když to nejde", "Tip: nejdřív ověřte, že stanice je ve správné VLAN a má správnou bránu.", - { - "Špatná maska na bráně rozhodí celou VLAN.", - "Trunk, který VLAN nepropouští, bránu odstřihne.", - "Stanice v access portu špatné VLAN dostane cizí DHCP.", - "Kontrola: adresa, maska, brána, VLAN, trunk, ACL.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 1, "net3_unit2", "net3_unit2_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je brána pro stanici ve VLAN?", {"Adresa routeru nebo SVI v té samé VLAN", "Libovolná veřejná DNS adresa", "MAC adresa switche", "Číslo VLAN zapsané do masky"}, 4, 0}, - {"Co je SVI?", {"Virtuální rozhraní VLAN na L3 přepínači", "Typ optického vlákna", "Protokol pošty", "Záloha konfigurace"}, 4, 0}, - {"Jak router na tyči pozná VLAN?", {"Podle značky 802.1Q na trunku", "Podle barvy LED na počítači", "Podle jména v DNS", "Podle rychlosti ventilátoru"}, 4, 0}, - {"Co udělá trunk, který VLAN 20 nepropouští?", {"Střihne bránu VLAN 20 od zbytku sítě", "Smaže OSPF v celé škole", "Přepne Wi-Fi na WEP", "Zdvojí adresy DHCP"}, 4, 0}, - }; - static const char *hints[] = { - "Brána musí být dosažitelná na druhé vrstvě, tedy ve stejné VLAN.", - "SVI nese IP adresu brány dané VLAN.", - "Každé podrozhraní patří jedné značce.", - "Povolené VLAN na trunku jsou součást návrhu.", - }; - return quizyear_quiz(qy_net3, 1, "net3_ex2_title", "net3_quiz2_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Okraj", "Kde končí vaše síť", "Tip: za routerem k poskytovateli už neřídíte fyzickou cestu.", - { - "WAN spojuje vzdálené sítě přes síť, kterou nevlastníte.", - "Poskytovatel vám dá adresu, bránu a často i VLAN.", - "Výchozí trasa obvykle míří právě sem.", - "Výpadek poslední míle odřízne pobočku, i když jádro žije.", - NULL, - }, - }, - { - "2 / 3 • Technologie", "Čím se to vozí", "Tip: dnešní WAN často vypadá jako ethernet, i když pod ním je jiná síť.", - { - "Starší spoje používaly pronajaté linky a PPP.", - "MPLS u poskytovatele spojí pobočky jako jednu službu.", - "Metro Ethernet přivede do budovy běžný ethernetový port.", - "Rychlost, odezva a ztráty jsou parametry, které se sledují.", - NULL, - }, - }, - { - "3 / 3 • Návrh", "Co domluvit", "Tip: záložní spoj má smysl jen s cestou, která se na něj umí přepnout.", - { - "Jedna přípojka je jednoduchá a křehká.", - "Druhý poskytovatel sníží riziko, když nejde stejnou trasou.", - "Adresy od poskytovatele musí sedět s vaším NAT a firewallem.", - "Na okraji filtrujte, co do školy z internetu lézt nemá.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 2, "net3_unit3", "net3_unit3_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je WAN z pohledu školy?", {"Spoj mimo budovu, často přes poskytovatele", "Kabel mezi dvěma porty jednoho switche", "VLAN pro tiskárny", "Diskové pole"}, 4, 0}, - {"Kam obvykle míří výchozí trasa?", {"K poskytovateli", "Na tiskárnu", "Do STP rootu", "Na adresu 127.0.0.1"}, 4, 0}, - {"Proč dva spoje stejnou ulicí nemusí být záloha?", {"Jedna porucha překope oba naráz", "OSPF dva spoje zakazuje", "IPv4 umí jen jednu bránu na světě", "Ethernet nesmí mít zálohu"}, 4, 0}, - {"Co je metro Ethernet?", {"WAN služba, která u vás končí ethernetovým portem", "Wi-Fi ve vlaku", "Protokol místo DNS", "Typ procesoru"}, 4, 0}, - }; - static const char *hints[] = { - "WAN překračuje místní síť.", - "Co směrovač nezná, pošle ven.", - "Fyzicky oddělená trasa je součást redundance.", - "Pod portem může být síť poskytovatele, vy vidíte ethernet.", - }; - return quizyear_quiz(qy_net3, 2, "net3_ex3_title", "net3_quiz3_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tunel", "Cizí síť jako kabel", "Tip: VPN neschová provoz před sítí, ve které tunel končí.", - { - "Mezi dvěma body se postaví šifrovaný tunel.", - "Uvnitř mohou téct soukromé adresy.", - "Venku je vidět jen obal mezi konci tunelu.", - "Bez shodných klíčů nebo certifikátů tunel nevstane.", - NULL, - }, - }, - { - "2 / 3 • Dva tvary", "Pobočka a člověk", "Tip: site-to-site spojuje sítě, remote access jednoho uživatele.", - { - "Site-to-site propojí dvě pobočky trvale.", - "Remote access pustí notebook do školní sítě.", - "Uživatel se ověřuje účtem, ne jen společným heslem na zdi.", - "Split tunnel posílá tunelem jen školní sítě, zbytek jde přímo.", - NULL, - }, - }, - { - "3 / 3 • Chyby", "Když tunel stojí a data ne", "Tip: tunel může svítit zeleně a přesto chybí trasa dovnitř.", - { - "Musí sedět návrh šifry na obou koncích.", - "Firewall po cestě musí pustit port VPN.", - "Uvnitř musí existovat trasa do cílových sítí.", - "Příliš široký tunel stáhne na školu i provoz, který tam být neměl.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 3, "net3_unit4", "net3_unit4_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co VPN před cizí sítí skrývá?", {"Obsah a vnitřní adresy, venku je vidět obal tunelu", "I to, že nějaký provoz existuje", "MAC adresu switche ve třídě", "Úplně všechno včetně konců tunelu"}, 4, 0}, - {"Čím se liší site-to-site od remote access?", {"První spojuje sítě, druhá připojuje uživatele", "První je Wi-Fi, druhá je VLAN", "Obě jen mění DNS", "Remote access nejde šifrovat"}, 4, 0}, - {"Proč tunel svítí, ale server nehraje?", {"Chybí trasa nebo firewall uvnitř", "IPv4 zakazuje VPN", "STP tunely maže", "DNS přejmenuje šifru"}, 4, 0}, - {"Co je split tunnel?", {"Tunelem jde jen provoz do vnitřních sítí", "Každý paket se rozpůlí", "VPN bez šifry", "Dva SSID na jednom kanále"}, 4, 0}, - }; - static const char *hints[] = { - "Koncové adresy tunelu vidět jsou, náklad ne.", - "Notebook není druhá pobočka, i když tunel vypadá podobně.", - "Šifra a dosažitelnost jsou dvě vrstvy.", - "Internet z notebooku pak nemusí téct přes školu.", - }; - return quizyear_quiz(qy_net3, 3, "net3_ex4_title", "net3_quiz4_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Zóny", "Důvěra není stejná", "Tip: LAN, WAN a DMZ nemají stejná pravidla.", - { - "Rozhraní se sdruží do zón podle důvěry.", - "Z důvěryhodnější zóny ven se často povoluje snáz.", - "Z internetu dovnitř se povoluje jen to, co je schválené.", - "Pravidlo se píše od zóny ke zóně, ne jen na jednu adresu.", - NULL, - }, - }, - { - "2 / 3 • Stav", "Pamatuje si spojení", "Tip: stavový firewall pustí odpověď, aniž byste psali pravidlo nazpátek.", - { - "Nové spojení se kontroluje proti politice.", - "Odpověď patřící ke spojení se pustí.", - "Bezestavový filtr zkoumá každý paket zvlášť.", - "Ukončené spojení se z tabulky smaže.", - NULL, - }, - }, - { - "3 / 3 • DMZ", "Server, který má být vidět", "Tip: web v DMZ nemá mít cestu ke všem diskům ve škole.", - { - "Veřejná služba sedí v oddělené zóně.", - "Z internetu se otevře jen její port.", - "Z DMZ do LAN se pustí jen to, co služba opravdu potřebuje.", - "Kompromitovaný web pak neotevře celou školu.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 4, "net3_unit5", "net3_unit5_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč se zóny liší?", {"Mají jinou důvěru a tedy jiná pravidla", "Každá zóna musí mít vlastní DNS jméno switche", "Zóny nahrazují IP adresy", "Bez zón nejde STP"}, 4, 0}, - {"Co umí stavový firewall?", {"Pustí odpověď k už otevřenému spojení", "Smaže VLAN", "Přidělí MAC adresu", "Nahradí směrovací protokol"}, 4, 0}, - {"Kam patří veřejný web, který nemá vidět celou LAN?", {"Do DMZ", "Do stejné sítě jako účtárna", "Na access port ředitele", "Do nativní VLAN trunku bez pravidel"}, 4, 0}, - {"Co samotná zóna ještě není?", {"Náhrada za konkrétní pravidla služeb", "Způsob, jak sdružit rozhraní", "Hranice důvěry", "Místo, kam se píše politika"}, 4, 0}, - }; - static const char *hints[] = { - "Internet a učebna nejsou stejně důvěryhodné.", - "Pamatuje si, kdo spojení začal.", - "DMZ omezí, kam se útočník dostane dál.", - "Zóna bez pravidel nic nechrání.", - }; - return quizyear_quiz(qy_net3, 4, "net3_ex5_title", "net3_quiz5_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Fronty", "Ne všechno snese čekání", "Tip: QoS nevytvoří rychlost, jen rozhodne, kdo počká.", - { - "Hlas a videohovor kazí zpoždění a kolísání.", - "Záloha disku snese čekání líp než telefonát.", - "Fronta na úzké lince řadí pakety.", - "Bez označení provozu switch neví, co je hlas.", - NULL, - }, - }, - { - "2 / 3 • Značky", "Kdo si řekne o přednost", "Tip: značce z koncového portu nevěřte, uživatel si ji může nastavit sám.", - { - "IP hlavička umí nést DSCP.", - "Ethernet umí prioritu na VLAN značce.", - "Na vstupu se značka přepíše podle politiky.", - "Hlasová VLAN se často značí automaticky.", - NULL, - }, - }, - { - "3 / 3 • Praxe", "Kde to má smysl", "Tip: na prázdné gigabitové lince QoS nic viditelného neudělá.", - { - "Úzké hrdlo bývá WAN, ne páteřní switch.", - "Rezervace pro hlas nesmí sežrat celou linku.", - "Testujte hovor ve chvíli, kdy běží velká kopie.", - "Špatná politika umí zpomalit i správu sítě.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 5, "net3_unit6", "net3_unit6_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co QoS neumí?", {"Vyrobit větší rychlost linky", "Dát přednost hlasu před zálohou", "Omezit kolísání hovoru", "Označit provoz"}, 4, 0}, - {"Proč se značka z počítače přepisuje?", {"Uživatel by si jinak dal nejvyšší prioritu", "DSCP nejde číst", "IPv4 značky zakazuje", "STP značky maže"}, 4, 0}, - {"Kde QoS obvykle pomůže nejdřív?", {"Na pomalé WAN lince", "Na prázdném 10Gb portu mezi switchi", "Uvnitř jednoho počítače na smyčce", "Na vypnutém Wi-Fi"}, 4, 0}, - {"Který provoz čekání snese hůř?", {"Telefonní hovor", "Noční kopie disku", "Stahování aktualizace", "Archiv pošty"}, 4, 0}, - }; - static const char *hints[] = { - "Dělí existující kapacitu, nepřidá ji.", - "Důvěryhodná značka vznikne na vstupu podle pravidel.", - "Přednost se projeví, až když se linka plní.", - "Hlas potřebuje malé a stálé zpoždění.", - }; - return quizyear_quiz(qy_net3, 5, "net3_ex6_title", "net3_quiz6_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • SNMP", "Čísla z zařízení", "Tip: SNMPv2c posílá jméno komunity skoro jako heslo v čistém textu.", - { - "Dohled se ptá na vytížení, chyby a stav portů.", - "Komunita není ozdoba, je to přístup.", - "SNMPv3 umí uživatele a šifrování.", - "Zařízení má poslouchat SNMP jen ze sítě dohledu.", - NULL, - }, - }, - { - "2 / 3 • Syslog", "Věty o tom, co se stalo", "Tip: log na zařízení se při restartu může ztratit. Posílejte ho pryč.", - { - "Syslog odnáší hlášky na server.", - "Úrovně od ladění po nouzi se nemají všechny sypat do jedné hromady.", - "Čas na zařízeních musí sedět, jinak nejde srovnat události.", - "NTP je proto součást dohledu, ne jen hodiny na zdi.", - NULL, - }, - }, - { - "3 / 3 • Čtení", "Graf není diagnóza", "Tip: špička jednou za den může být záloha, ne útok.", - { - "Chyby na portu často znamenají kabel nebo duplex.", - "Vytrvalé vytížení WAN řekne, jestli je čas na silnější spoj.", - "Výpadek, který nikdo nevidí, se bude opakovat.", - "Upozornění má chodit člověku, který může reagovat.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 6, "net3_unit7", "net3_unit7_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč SNMPv2c nestačí na nezabezpečené síti?", {"Jméno komunity jde odposlechnout", "Neumí číst vytížení", "Funguje jen na IPv6", "Maže syslog"}, 4, 0}, - {"Proč posílat syslog pryč ze zařízení?", {"Lokální log se při restartu může ztratit", "Syslog nahrazuje heslo", "Switch jinak vypne porty", "DNS bez logu nefunguje"}, 4, 0}, - {"K čemu je při dohledu NTP?", {"Aby časy událostí šly srovnat", "Aby přidělil VLAN", "Aby šifroval Wi-Fi", "Aby nahradil SNMP"}, 4, 0}, - {"Co často znamenají rostoucí chyby na portu?", {"Špatný kabel nebo duplex", "Že je VLAN správně", "Že OSPF konverguje", "Že DNS TTL vypršelo"}, 4, 0}, - }; - static const char *hints[] = { - "Komunita cestuje bez pořádné ochrany. Lepší je SNMPv3.", - "Po restartu už příčinu pádu na zařízení nemusíte najít.", - "Bez společného času nejde říct, co bylo dřív.", - "Fyzická vrstva se v počítadlech chyb projeví dřív než v teorii.", - }; - return quizyear_quiz(qy_net3, 6, "net3_ex7_title", "net3_quiz7_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net3_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Běžící a uložená", "Restart není uložení", "Tip: změna v běžící konfiguraci po restartu zmizí, dokud ji neuložíte.", - { - "Běžící konfigurace je to, co zařízení právě dělá.", - "Startovní se načte po zapnutí.", - "Uložení zkopíruje běžící do startovní.", - "Bez uložení druhý den síť vypadá jako včera.", - NULL, - }, - }, - { - "2 / 3 • Kopie ven", "Nejen na zařízení", "Tip: záloha na tom samém přepínači shoří spolu s ním.", - { - "Konfigurace patří na server mimo to zařízení.", - "Ukládejte i verzi, ať víte, co se změnilo.", - "Hesla v exportu mohou být čitelná. Soubor chraňte.", - "Automatická záloha po změně porazí dobrý úmysl.", - NULL, - }, - }, - { - "3 / 3 • Popis", "Aby to přečetl i kolega", "Tip: port bez popisu je za půl roku hádanka.", - { - "Popis portu říká, co je na druhém konci.", - "Schéma VLAN a adres má sedět s konfigurací.", - "Změna bez poznámky se špatně vrací.", - "Nový switch postavíte z zálohy jen tehdy, když záloha existuje.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net3, 7, "net3_unit8", "net3_unit8_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net3_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co se stane se změnou, kterou neuložíte?", {"Po restartu zmizí", "Zapíše se do VLAN navždy", "Přepíše firmware", "Pošle se sama do DNS"}, 4, 0}, - {"Proč záloha jen na tom samém switchi nestačí?", {"S poškozeným switchem zmizí i ona", "Switch zálohy šifruje tak, že je nečitelné i pro vás", "STP zálohy maže", "IPv6 zálohy zakazuje"}, 4, 0}, - {"Co má být u portu napsané?", {"Co je na druhém konci", "Heslo administrátora", "Celá směrovací tabulka", "Soukromý klíč VPN"}, 4, 0}, - {"Proč chránit soubor se zálohou?", {"Může obsahovat čitelná hesla", "Soubor sám otevírá porty", "DNS ho publikuje", "Je větší než disk"}, 4, 0}, - }; - static const char *hints[] = { - "Běžící konfigurace není totéž co startovní.", - "Kopie musí žít jinde.", - "Popis portu šetří hodiny při poruše.", - "Export není vždy v zašifrované podobě.", - }; - return quizyear_quiz(qy_net3, 7, "net3_ex8_title", "net3_quiz8_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Rozsahy", "Každá VLAN má svůj prefix", "Tip: nenechávejte v každé síti jen čtyři volné adresy.", - { - "Nejdřív spočítejte stanice, tiskárny, AP a rezervu.", - "Brána, síťová a broadcast adresa se do stanic nepočítají.", - "Sousední VLAN nemají mít překryv.", - "Dokument říká, která čísla jsou volná.", - NULL, - }, - }, - { - "2 / 3 • Členění", "Škola není jedna velká síť", "Tip: /16 na celou budovu se snadno spravuje a špatně izoluje.", - { - "Učebny, správa, servery, hosté a telefony patří odděleně.", - "Stejný řád čísel ve všech budovách se líp pamatuje.", - "Souhrn tras na páteři zmenší tabulku.", - "Výjimka pro jednu tiskárnu se má zapsat, ne jen zapamatovat.", - NULL, - }, - }, - { - "3 / 3 • Změna", "Plán, který jde rozšířit", "Tip: když přidáte budovu, neměli byste přečíslovat celou školu.", - { - "Nechte v páteřním rozsahu díry pro další sítě.", - "Přechod na nový prefix znamená DHCP, DNS, brány i firewall.", - "IPv6 prefix se plánuje stejně vědomě, ne jako dodatek.", - "Tabulka adres je součást maturity i běžného provozu.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 0, "net4_unit1", "net4_unit1_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co se v síti /24 nedá přiřadit stanici?", {"Adresa sítě a broadcast", "První použitelná adresa", "Adresa brány, pokud ji stanice nemá mít", "Adresa s lichým posledním oktetem"}, 4, 0}, - {"Proč nerozdat celé škole jednu velkou síť?", {"Špatně se izoluje porucha i provoz", "IPv4 to zakazuje", "Switch umí jen 8 adres", "DNS pak nejde spustit"}, 4, 0}, - {"K čemu je souhrn tras?", {"Jedna trasa pokryje víc menších sítí", "Smaže VLAN", "Nahradí NAT", "Zapne WPA3"}, 4, 0}, - {"Co patří do adresního plánu?", {"Prefix, VLAN, brána a k čemu síť je", "Jen heslo Wi-Fi", "Typ procesoru serveru", "Seznam učitelů"}, 4, 0}, - }; - static const char *hints[] = { - "Krajní adresy mají zvláštní význam. Brána se stanicím také nedává dvakrát.", - "Menší sítě se líp hlídají a míň se ruší broadcastem.", - "Páteř nemusí znát každou učebnu zvlášť.", - "Bez účelu sítě je tabulka jen sloupec čísel.", - }; - return quizyear_quiz(qy_net4, 0, "net4_ex1_title", "net4_quiz1_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Dvojice", "Dva boxy nestačí", "Tip: dva switche se stejnou konfigurací nejsou záloha, dokud provoz neumí přejít.", - { - "Redundance chce druhou cestu i protokol, který ji hlídá.", - "STP řeší smyčku na druhé vrstvě.", - "Na třetí vrstvě zálohu hlídá směrování nebo HSRP a příbuzné protokoly.", - "Jedna brána v DHCP znamená, že pád routeru odstřihne všechny.", - NULL, - }, - }, - { - "2 / 3 • Brána", "Virtuální adresa", "Tip: stanice mají jako bránu virtuální adresu, ne jednu fyzickou krabici.", - { - "Dva směrovače sdílejí jednu adresu brány.", - "Aktivní drží provoz, druhý čeká.", - "Když aktivní ztichne, druhý adresu převezme.", - "Stanice nemusí dostat nové DHCP.", - NULL, - }, - }, - { - "3 / 3 • Zkouška", "Nevyzkoušená záloha je teorie", "Tip: vytáhněte kabel v okně, kdy smíte, ne až při maturitní písemce.", - { - "Ověřte, že záložní cesta opravdu přenáší data.", - "Sledujte, za jak dlouho se provoz vrátí.", - "Záložní zdroj má jinou pojistku a jinou fázi, když to jde.", - "Zápis z zkoušky říká, co se má stát příště.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 1, "net4_unit2", "net4_unit2_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč dva stejné routery samy o sobě nestačí?", {"Stanice musí mít kam přejít, když jeden ztichne", "IPv4 povoluje jen jeden router v budově", "Druhý router maže VLAN", "STP dva routery zakazuje"}, 4, 0}, - {"Co stanice používá při protokolu virtuální brány?", {"Virtuální adresu, ne konkrétní krabici", "Svou vlastní MAC jako bránu", "Adresu DNS", "Broadcast 255.255.255.255 jako další skok"}, 4, 0}, - {"Kdy se záloha ověřuje?", {"Nanečisto, dřív než o ni opřete provoz", "Až když síť leží", "Jen na papíře", "Záloha se ověřovat nemá, ať se nepokazí"}, 4, 0}, - {"Co na druhé vrstvě řeší náhradní kabel?", {"STP, jinak vznikne smyčka", "Jen NAT", "Jen WPA3", "Nic, ethernet smyčky umí sám"}, 4, 0}, - }; - static const char *hints[] = { - "Bez společné nebo přepínané brány počítače zůstanou na mrtvé adrese.", - "Převzetí adresy stanice nepozná jako výměnu DHCP.", - "Nevyzkoušený přepínač překvapí v nejhorší chvíli.", - "Druhý kabel bez STP je recept na bouři.", - }; - return quizyear_quiz(qy_net4, 1, "net4_ex2_title", "net4_quiz2_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Port", "Nejdřív průkaz", "Tip: dokud ověření neskončí, na portu nemá téct běžný provoz.", - { - "Počítač se prokáže certifikátem nebo jménem a heslem.", - "Switch se ptá serveru RADIUS.", - "Až pak pustí port do dané VLAN.", - "Neznámé zařízení zůstane venku nebo v omezené síti.", - NULL, - }, - }, - { - "2 / 3 • Lidé a věci", "Ne všechno umí 802.1X", "Tip: tiskárna bez klienta potřebuje výjimku, ne vypnutí celé ochrany.", - { - "Počítač v doméně zvládne ověření sám.", - "Tiskárna, kamera a telefon často ne.", - "MAB pustí zařízení podle MAC adresy. Tu jde zfalšovat.", - "Výjimka má být na konkrétní port, ne na celý switch.", - NULL, - }, - }, - { - "3 / 3 • VLAN", "Kam koho pustit", "Tip: učitel a host nemají po ověření skončit ve stejné VLAN.", - { - "Úspěch může přiřadit VLAN podle skupiny.", - "Neúspěch skončí v síti bez přístupu k serverům.", - "Účet jde odebrat, aniž by se měnilo heslo Wi-Fi.", - "Stejný princip sedí na kabel i na podnikovou Wi-Fi.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 2, "net4_unit3", "net4_unit3_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo rozhodne, že zařízení smí do sítě?", {"RADIUS na základě údajů od switche", "Sám kabel podle barvy", "DNS záznam A", "STP root"}, 4, 0}, - {"Proč MAB není silné ověření?", {"MAC adresu lze zfalšovat", "MAC adresa je jednorázové heslo", "MAB šifruje silněji než certifikát", "Funguje jen na IPv6"}, 4, 0}, - {"Kam patří zařízení, které ověřením neprojde?", {"Do omezené sítě nebo nikam", "Do VLAN serverů", "Na trunk všech VLAN", "Do správy routeru"}, 4, 0}, - {"Jaká je výhoda účtů proti jednomu heslu Wi-Fi?", {"Jednomu člověku jde přístup odebrat", "Heslo se nemusí nikdy měnit, protože účty ho ruší", "Netřeba RADIUS ani switch", "WEP pak stačí"}, 4, 0}, - }; - static const char *hints[] = { - "Switch se ptá, server odpovídá.", - "Adresa na štítku není průkaz.", - "Neúspěch nemá otevírat vnitřní síť.", - "Sdílené heslo po odchodu člověka zná pořád.", - }; - return quizyear_quiz(qy_net4, 2, "net4_ex3_title", "net4_quiz3_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Vrstvy", "Nejdřív světlo na portu", "Tip: nehledejte chybu v DNS, když port nesvítí.", - { - "Fyzická vrstva: kabel, port, napájení, duplex, chyby.", - "Druhá vrstva: VLAN, MAC tabulka, trunk, STP.", - "Třetí vrstva: adresa, maska, brána, trasa, ACL.", - "Výš: DNS, port služby, firewall na konci.", - NULL, - }, - }, - { - "2 / 3 • Jedna změna", "Ať víte, co pomohlo", "Tip: pět změn naráz nic nenaučí.", - { - "Zapište, co vidíte, než něco přepnete.", - "Ověřte jednu hypotézu.", - "Ping na bránu, pak za ni, pak jméno.", - "Když oprava sedí, uložte konfiguraci a dopište důvod.", - NULL, - }, - }, - { - "3 / 3 • Rozsah", "Koho to postihlo", "Tip: jeden počítač je jiná chyba než celá učebna.", - { - "Jeden stroj: jeho kabel, port, adresa, účet.", - "Celá VLAN: brána, DHCP, trunk, SVI.", - "Celá škola: jádro, firewall, poskytovatel.", - "Čas začátku často sedí se změnou, kterou někdo neoznámil.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 3, "net4_unit4", "net4_unit4_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co ověříte jako první, když port nesvítí?", {"Kabel, port a napájení", "Záznam AAAA", "Cenu OSPF", "Pravidlo QoS pro hlas"}, 4, 0}, - {"Proč měnit jen jednu věc?", {"Ať je vidět, která změna pomohla", "Switch víc změn zakazuje", "IPv4 umí jen jednu opravu denně", "DNS jinak smaže zónu"}, 4, 0}, - {"Celá učebna nedostane adresu. Kde začnete?", {"DHCP, VLAN a brána té sítě", "Heslem jednoho studenta k webu", "Jasem monitoru", "Verzí prohlížeče"}, 4, 0}, - {"Co uděláte, když oprava sedí?", {"Uložíte konfiguraci a zapíšete důvod", "Restartujete všechno ještě jednou", "Smažete popis portů", "Vypnete dohled, ať neruší"}, 4, 0}, - }; - static const char *hints[] = { - "Vyšší vrstvy nemají na čem jet.", - "Více zásahů naráz zamaskuje příčinu.", - "Společný příznak ukazuje na společnou službu.", - "Neuložená oprava do rána zmizí.", - }; - return quizyear_quiz(qy_net4, 3, "net4_ex4_title", "net4_quiz4_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Kam s tím", "Vlastní sál, nebo cizí", "Tip: cloud neruší síť ve škole, mění jen to, kam vede spoj.", - { - "Veřejný cloud provozuje poskytovatel a vy si berete službu.", - "Soukromý cloud je pořád vaše zařízení, jen obalené portálem.", - "Hybrid nechá část dat ve škole a část venku.", - "Účet a síťová cesta jsou pořád vaše odpovědnost.", - NULL, - }, - }, - { - "2 / 3 • Cesta", "Jak se tam školní síť dostane", "Tip: služba v cloudu bez cesty a bez jmen je jen faktura.", - { - "VPN do cloudu vypadá jako další pobočka.", - "Veřejná služba jede přes internet a firewall.", - "DNS musí ukazovat na nové adresy.", - "Výpadek WAN teď shodí i to, co dřív jelo z místního serveru.", - NULL, - }, - }, - { - "3 / 3 • Hranice", "Kdo zálohuje a kdo pustí dovnitř", "Tip: poskytovatel nezálohuje vaše data, dokud to není ve smlouvě.", - { - "Pravidla firewallu se stěhují s službou.", - "Účty v cloudu mají mít stejný řád jako účty ve škole.", - "Test obnovy platí i pro data, která nejsou ve vašem racku.", - "Škola pořád řeší osobní údaje, i když disk je jinde.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 4, "net4_unit5", "net4_unit5_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co hybridní síť znamená?", {"Část služeb je ve škole a část u poskytovatele", "Dva switche v jedné VLAN", "IPv4 i papírový sešit", "Wi-Fi bez hesla"}, 4, 0}, - {"Co se pokazí, když WAN spadne a pošta je jen v cloudu?", {"Škola se k poště nedostane", "Místní switch přestane dělat VLAN", "STP zvolí cloud jako root", "Nic, cloud WAN nepotřebuje"}, 4, 0}, - {"Kdo zálohuje data v cloudu?", {"Ten, koho to smlouva a nastavení opravdu určují", "Vždy automaticky stát", "STP", "Nikdo, cloud zálohy zakazuje"}, 4, 0}, - {"Co škola řeší i u cizího disku?", {"Kdo má přístup a jak se chrání osobní údaje", "Jen barvu loga", "Jen typ ventilátoru v sále poskytovatele", "Nic, odpovědnost přechází celá"}, 4, 0}, - }; - static const char *hints[] = { - "Hranice školy už není hranicí všech služeb.", - "Cesta ven je součást dostupnosti služby.", - "Předpoklad, že poskytovatel zálohuje vše, často neplatí.", - "Umístění dat nemaže pravidla přístupu.", - }; - return quizyear_quiz(qy_net4, 4, "net4_ex5_title", "net4_quiz5_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • SSH", "Správa bez společného hesla na lístečku", "Tip: Telnet posílá heslo čitelně. Na správu patří SSH.", - { - "Klíč jde odebrat konkrétnímu člověku.", - "Heslo v příkazu historie nemá ležet.", - "Přístup omezte na správní síť.", - "Záznam, kdo se přihlásil, patří do logu.", - NULL, - }, - }, - { - "2 / 3 • Opakování", "Stejná VLAN ve dvaceti switchích", "Tip: ruční opis se v desátém switchi liší v jednom čísle.", - { - "Šablona drží názvy VLAN a popis portů.", - "Skript změnu pošle na seznam zařízení.", - "Nejdřív ho pusťte na jednom switchi.", - "Záloha před hromadnou změnou je povinnost, ne ozdoba.", - NULL, - }, - }, - { - "3 / 3 • Mez", "Skript není výmluva", "Tip: automat neopraví špatný záměr, jen ho provede rychleji.", - { - "Kontrola po běhu srovná, co opravdu sedí.", - "Tajné heslo nepatří do veřejného souboru.", - "Člověk pořád schvaluje změnu, která shodí výuku.", - "Verzovaný soubor konfigurace ukáže, kdo řádek změnil.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 5, "net4_unit6", "net4_unit6_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč na správu nepoužívat Telnet?", {"Heslo jde po síti čitelně", "Telnet neumí IPv4", "Switch Telnet zakazuje standardem STP", "Telnet maže VLAN"}, 4, 0}, - {"Jak pustíte stejnou změnu do dvaceti switchů?", {"Šablonou a skriptem, neopisovat ji dvacetkrát", "Jen restartem všech naráz", "Přes DHCP", "Jedním broadcastem bez kontroly"}, 4, 0}, - {"Co před hromadnou změnou uděláte?", {"Zálohu konfigurací", "Vypnete dohled", "Smažete popisy portů", "Zakážete SSH"}, 4, 0}, - {"Co skript neumí?", {"Poznat, že záměr byl špatně", "Poslat stejný příkaz víckrát", "Uložit konfiguraci", "Připojit se přes SSH"}, 4, 0}, - }; - static const char *hints[] = { - "SSH spojení chrání.", - "Nejdřív jeden switch, pak ostatní.", - "Ať se máte kam vrátit.", - "Rychlost neopraví chybný příkaz.", - }; - return quizyear_quiz(qy_net4, 5, "net4_ex6_title", "net4_quiz6_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Řád", "Kdo smí co změnit", "Tip: heslo admin na lístečku u switche není provozní řád.", - { - "Účty jsou jmenné, ne jedno společné admin.", - "Změna ve výuce se hlásí dopředu.", - "Hostovská síť je oddělená a časově omezená.", - "Osobní údaje v logu se nenechávají ležet bez důvodu.", - NULL, - }, - }, - { - "2 / 3 • Výpadek", "Co říct a co udělat", "Tip: nejdřív rozsah a dopad, pak ladění detailu.", - { - "Řekněte, co nejede a koho se to týká.", - "Oddělte výpadek poskytovatele od chyby ve škole.", - "Po obnově ověřte poštu, přihlášení i tisk, ne jen ping.", - "Krátký zápis příště zkrátí stejnou poruchu.", - NULL, - }, - }, - { - "3 / 3 • U zkoušky", "Co umět ukázat", "Tip: maturita chce důvod, ne jen zkratku.", - { - "Umíte přečíst adresu, masku, bránu a VLAN.", - "Umíte říct, k čemu je trunk, NAT, firewall a záloha.", - "Schéma malé sítě nakreslíte i bez nápovědy.", - "Postup hledání chyby od kabelu po službu odvykládáte po vrstvách.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 6, "net4_unit7", "net4_unit7_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak nemají vypadat účty ke switchi?", {"Jedno heslo admin pro celou sborovnu", "Jmenný účet s možností odebrání", "Přístup jen ze správní sítě", "Záznam přihlášení"}, 4, 0}, - {"Co řeknete jako první při výpadku?", {"Co nejede a koho se to týká", "Celou směrovací tabulku zpaměti", "Typ ventilátoru v racku", "Že se to vyřeší samo"}, 4, 0}, - {"Co po obnově nestačí?", {"Jen ping na bránu", "Ověřit poštu a přihlášení", "Podívat se na tisk", "Zkontrolovat, že VLAN sedí"}, 4, 0}, - {"Co u maturity k VLAN umíte říct?", {"Odděluje provoz a mezi VLAN se směruje", "Je to typ pevného disku", "Nahrazuje zálohu konfigurace", "Je totéž co WPA3"}, 4, 0}, - }; - static const char *hints[] = { - "Společné heslo nejde vzít jednomu člověku.", - "Rozsah je důležitější než první domněnka.", - "Brána může žít a služba pořád ne.", - "Definice a důvod, ne jen zkratka.", - }; - return quizyear_quiz(qy_net4, 6, "net4_ex7_title", "net4_quiz7_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_net4_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Schéma", "Co na něm má být", "Tip: schéma z doby instalace bez datumu je pohádka.", - { - "Jsou na něm jádro, učebny, VLAN a přípojka ven.", - "Adresní plán sedí se schématem, ne s pamětí.", - "Porty páteře mají popisky na obou koncích.", - "Datum a jméno autora říkají, jak je obrázek starý.", - NULL, - }, - }, - { - "2 / 3 • Změna", "Nejdřív papír, pak kabel", "Tip: přepojit a zapsat až za měsíc znamená, že zápis už nesedí.", - { - "Změna VLAN se zapíše ve stejný den.", - "Fotka rozvaděče doplní schéma tam, kde čáry lžou.", - "Hesla do schématu nepatří. Patří do trezoru účtů.", - "Kopie schématu není jen na počítači, který ta síť živí.", - NULL, - }, - }, - { - "3 / 3 • Předání", "Až tu nebudete", "Tip: kolega má síť převzít bez vašeho telefonu.", - { - "Seznam zařízení, adres správy a kde leží zálohy.", - "Kontakt na poskytovatele a číslo spoje.", - "Co se nesmí restartovat ve výuce.", - "Jedna stránka je lepší než nikde neuložená hlava.", - NULL, - }, - }, - }; - return quizyear_unit(qy_net4, 7, "net4_unit8", "net4_unit8_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_net4_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co do schématu sítě nepatří?", {"Heslo správce", "VLAN a jejich účel", "Přípojka k poskytovateli", "Datum, kdy naposledy sedělo"}, 4, 0}, - {"Kdy se změna zapíše?", {"V den, kdy se provede", "Až se na ni někdo zeptá u maturity", "Jen když spadne celá škola", "Zápis není potřeba, stačí paměť"}, 4, 0}, - {"Proč mít kopii schématu i mimo školní server?", {"Když síť neběží, schéma na ní neotevřete", "Server schémata maže", "IPv6 schémata zakazuje", "STP obrázky nepouští"}, 4, 0}, - {"Co má kolega najít bez vašeho telefonu?", {"Adresy správy, zálohy a kontakt na poskytovatele", "Jen barvu racku", "Vaše soukromé heslo", "Nic, síť se nepředává"}, 4, 0}, - }; - static const char *hints[] = { - "Heslo patří jinam než na obrázek, který visí ve sborovně.", - "Nezapsaná změna je příští závada.", - "Dokumentace má přežít výpadek toho, co popisuje.", - "Provoz nesmí stát na jednom člověku.", - }; - return quizyear_quiz(qy_net4, 7, "net4_ex8_title", "net4_quiz8_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Panel", "LCD a OLED", "Tip: rozbité podsvícení LCD zhasne obraz, i když panel pořád kreslí.", - { - "LCD svítí podsvícením a panel světlo cloní.", - "OLED svítí samotnými body a umí opravdovou černou.", - "Lesklý panel má vyšší kontrast a víc odlesků.", - "Uhlopříčka v palcích není totéž co pracovní plocha v bodech.", - NULL, - }, - }, - { - "2 / 3 • Obraz", "Rozlišení a frekvence", "Tip: nativní rozlišení panelu je to, na které je mřížka bodů.", - { - "Nižší rozlišení interpoluje a obraz měkne.", - "Obnovovací frekvence říká, kolikrát za sekundu se obraz překreslí.", - "Odezva panelu není totéž co frekvence.", - "HDR chce vyšší jas, ne jen zaškrtnutou volbu.", - NULL, - }, - }, - { - "3 / 3 • Kabel", "Obraz musí stihnout pásmo", "Tip: starý kabel nebo slabá verze HDMI oseká frekvenci i rozlišení.", - { - "DisplayPort a HDMI mají verze s různým datovým tokem.", - "VGA je analogové a na dlouhém kabelu měkne.", - "USB-C obraz poveze jen tehdy, když port umí alternativní režim.", - "Dokovací stanice má vlastní limit, ne limit notebooku.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 0, "hw2_unit1", "hw2_unit1_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se OLED liší od běžného LCD?", {"Body samy svítí a černá je opravdu zhasnutá", "Nemá rozlišení", "Jede jen po VGA", "Nepotřebuje grafickou kartu"}, 4, 0}, - {"Co je nativní rozlišení?", {"Počet bodů, na který je panel vyroben", "Nejvyšší číslo v herním menu bez ohledu na panel", "Rychlost procesoru", "Počet USB portů"}, 4, 0}, - {"Proč 4K při 144 Hz někdy nejde?", {"Kabel nebo verze portu nestihne datový tok", "OLED zakazuje frekvenci nad 60 Hz", "IPv4 omezuje monitory", "BIOS maže rozlišení"}, 4, 0}, - {"Kdy USB-C nepřenese obraz?", {"Když port umí jen data a nabíjení", "Když je kabel černý", "Když má notebook SSD", "Když je v síti VLAN"}, 4, 0}, - }; - static const char *hints[] = { - "LCD obraz skládá cloněním podsvícení.", - "Jiné rozlišení se musí přepočítat.", - "Pásmo portu je strop, ne přání v menu.", - "Konektor stejného tvaru ještě neznamená DisplayPort v něm.", - }; - return quizyear_quiz(qy_hw2, 0, "hw2_ex1_title", "hw2_quiz1_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Princip", "Toner a kapky", "Tip: laser netaví toner na papír sám, dělá to zapékací válec.", - { - "Laser nabije válec a toner se chytí podle obrazu.", - "Inkoust stříká kapky a hodí se na fotky i občasný tisk.", - "Zaschnutá hlava je častější než porucha desky.", - "Termotransfer na štítky není totéž co kancelářský laser.", - NULL, - }, - }, - { - "2 / 3 • Síť", "Jedna tiskárna pro učebnu", "Tip: tiskárna s vlastní adresou má rezervaci v DHCP.", - { - "Sdílená tiskárna na počítači žije, jen když je ten počítač zapnutý.", - "Síťová tiskárna poslouchá sama.", - "Fronta na serveru drží ovladač na jednom místě.", - "Špatný ovladač tiskne znaky místo stránky.", - NULL, - }, - }, - { - "3 / 3 • Sken", "Obraz zpět do počítače", "Tip: rozlišení 600 dpi na text stačí, plakát chce víc.", - { - "Plochý skener i podavač mají jiný limit gramáže.", - "ADF nezvládne sešité listy.", - "Síťový sken může poslat soubor do složky nebo na poštu.", - "Sklo a podavač se mažou, jinak jsou na stránce pruhy.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 1, "hw2_unit2", "hw2_unit2_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co v laserové tiskárně připevní toner k papíru?", {"Zapékací válec", "Inkoustová hlava", "Ventilátor zdroje", "VGA kabel"}, 4, 0}, - {"Kdy sdílená tiskárna na učitelském počítači netiskne?", {"Když je ten počítač vypnutý", "Když má tiskárna vlastní IP a server", "Když je v síti DHCP", "Když je papír v zásobníku"}, 4, 0}, - {"Proč dát tiskárně rezervaci v DHCP?", {"Aby ovladače mířily pořád na stejnou adresu", "Aby se zvýšilo rozlišení", "Aby toner vydržel dýl", "Aby nešla skenovat"}, 4, 0}, - {"Co podavač skeneru nezvládne?", {"Sešitou sadu listů", "Jednotlivé běžné listy", "Černobílý text", "Odeslání do složky, pokud to umí firmware"}, 4, 0}, - }; - static const char *hints[] = { - "Teplo a tlak toner zataví.", - "Sdílení přes počítač z toho počítače dělá server.", - "Nová adresa po restartu rozbije frontu.", - "Sešit patří na sklo, ne do ADF.", - }; - return quizyear_quiz(qy_hw2, 1, "hw2_ex2_title", "hw2_quiz2_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • USB", "Versie a napájení", "Tip: port USB-A 2.0 fyzicky vezme i rychlý flash disk a stáhne ho na svou rychlost.", - { - "USB 2.0, 3.x a 4 se liší tokem dat.", - "USB-C je tvar, ne záruka rychlosti.", - "Thunderbolt po stejném tvaru umí obraz, síť i disk.", - "Hub bez napájení nestačí pro víc disků.", - NULL, - }, - }, - { - "2 / 3 • SATA", "Klasické disky", "Tip: napájení SATA a datový kabel jsou dva různé vodiče.", - { - "HDD i starší SSD sedí na SATA.", - "Rychlost rozhraní je strop, disk může být pomalejší.", - "Kabel bez západky vypadne a disk zmizí z BIOSu.", - "Externí box schová SATA za USB.", - NULL, - }, - }, - { - "3 / 3 • NVMe", "SSD přímo na PCIe", "Tip: M.2 je rozměr destičky. NVMe a SATA na M.2 nejsou totéž.", - { - "NVMe jede po PCIe a obchází starý řadič SATA.", - "Slot M.2 na desce může umět jen jednu z variant.", - "Dlouhá destička do krátkého slotu nepatří.", - "Bez chlazení rychlé SSD ve špičce zpomalí.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 2, "hw2_unit3", "hw2_unit3_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co říká samotný tvar USB-C?", {"Jen tvar konektoru, ne rychlost ani obraz", "Vždy Thunderbolt", "Vždy 40 Gb/s", "Vždy nabíjení 100 W a DisplayPort"}, 4, 0}, - {"Čím se NVMe liší od SATA SSD?", {"Jede po PCIe, ne po starém SATA", "Nemá paměťové buňky", "Jde zapojit jen do VGA", "Nepotřebuje desku"}, 4, 0}, - {"Co může umět slot M.2?", {"Jen SATA, jen NVMe, nebo obojí, podle desky", "Vždy obojí", "Jen grafickou kartu", "Jen operační paměť"}, 4, 0}, - {"Proč rychlé SSD ve špičce zpomalí?", {"Přehřeje se a stáhne výkon", "SATA mu sebere VLAN", "BIOS maže buňky", "USB-C ho přepne na 2.0 vždy"}, 4, 0}, - }; - static const char *hints[] = { - "Schopnosti určuje řadič a kabel, ne obrys.", - "Protokol a sběrnice jsou rychlejší cesta.", - "Manuál desky je závaznější než tvar zářezu.", - "Řadič hlídá teplotu.", - }; - return quizyear_quiz(qy_hw2, 2, "hw2_ex3_title", "hw2_quiz3_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tok", "Podtlak a přetlak", "Tip: všechny ventilátory foukající dovnitř bez odtahu jen víří prach.", - { - "Vpředu a dole se vzduch nasává, vzadu a nahoře odchází.", - "Filtr patří na vstup, ne na výfuk.", - "Zavřená přední stěna designové skříně škrtí přívod.", - "Kabel přes ventilátor je ucpaný filtr.", - NULL, - }, - }, - { - "2 / 3 • CPU", "Chladič musí sednout", "Tip: pasta není vrstva másla. Má vyplnit nerovnosti.", - { - "Vzduchový chladič potřebuje místo k bočnici.", - "Voda odvede teplo do radiátoru, který pořád potřebuje vzduch.", - "Špatně dotažený chladič pustí teplotu hned po startu.", - "Limit teploty v BIOSu je pojistka, ne pracovní režim.", - NULL, - }, - }, - { - "3 / 3 • Prach", "Tichý vrah zdroje", "Tip: vrstva prachu na žebru je izolace.", - { - "Zdroj s filtrem se čistí, nezalepuje.", - "Notebookový výfuk do měkké deky se udusí.", - "Po roce bez čištění rostou otáčky a teplota.", - "Čištění stlačeným vzduchem nedrží ventilátor v roztočeném stavu naslepo.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 3, "hw2_unit4", "hw2_unit4_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kam patří prachový filtr?", {"Na vstup vzduchu", "Jen na výfuk vzadu", "Dovnitř zdroje bez mřížky", "Na displej"}, 4, 0}, - {"Co dělá příliš silná vrstva pasty?", {"Zhorší přestup tepla", "Zvýší takt samo", "Nahradí chladič", "Opraví špatný socket"}, 4, 0}, - {"Proč vodní chlazení pořád potřebuje vzduch?", {"Radiátor musí teplo předat do místnosti", "Voda chladí jen při otevřeném okně skříně", "Čerpadlo jede na VGA", "Bez ventilátoru se voda vaří vždy do minuty"}, 4, 0}, - {"Co udělá notebook na dece?", {"Zakryje sání a přehřeje se", "Zvýší jas panelu", "Přepne disk na NVMe", "Opraví ventilátor"}, 4, 0}, - }; - static const char *hints[] = { - "Filtruje se to, co teprve vstupuje.", - "Pasta vede hůř než kov chladiče.", - "Okruh teplo přesune, radiátor ho odvede.", - "Sání bývá zespodu.", - }; - return quizyear_quiz(qy_hw2, 3, "hw2_ex4_title", "hw2_quiz4_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Příprava", "Nejdřív mimo skříň", "Tip: sestavu nejdřív oživte na stole. Ve skříni se špatně hledá nedosedlá paměť.", - { - "Deska, procesor, chladič a jeden modul paměti.", - "Zdroj mimo skříň a obraz na základní grafiku.", - "Až potom disk, karty a zbytek paměti.", - "Antistatická podložka a klidné ruce porazí koberec.", - NULL, - }, - }, - { - "2 / 3 • Socket", "Procesor nemá kam spadnout", "Tip: ohnutý pin na desce LGA nevrátíte pinzetou naslepo.", - { - "Trojúhelník na procesoru sedí se značkou na socketu.", - "Páka se zavírá až když procesor leží rovně.", - "Pasta až po usazení, ne do socketu.", - "Chladič se dotahuje křížem, ne jednou stranou nadoraz.", - NULL, - }, - }, - { - "3 / 3 • Skříň", "Kabely jsou součást airflow", "Tip: distanční sloupky pod deskou musí sedět s otvory, jinak deska zkratuje.", - { - "Nejdřív zdroj a distanční sloupky, potom deska.", - "Napájení desky, procesoru a karty jsou tři různé konektory.", - "Přední USB a tlačítko mají malé konektory podle manuálu.", - "První start se sleduje: ventilátory, obraz, pípnutí nebo LED.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 4, "hw2_unit5", "hw2_unit5_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč oživit sestavu nejdřív mimo skříň?", {"Nedosedlá paměť se ve skříni hledá hůř", "Ve skříni nejde zapnout zdroj", "BIOS ve skříni neběží", "Pasta venku schne"}, 4, 0}, - {"Co se nesmí stát pinům na socketu LGA?", {"Ohnout je", "Nechat je v socketu", "Srovnat procesor podle značky", "Zavřít páku až po usazení"}, 4, 0}, - {"K čemu jsou distanční sloupky?", {"Drží desku dál od plechu skříně", "Napájí ventilátor", "Jsou to šrouby do disku", "Uzemňují jen přední LED"}, 4, 0}, - {"Který konektor nepatří do napájení procesoru?", {"PCIe konektor grafické karty místo EPS", "Hlavní 24pin na desku", "EPS konektor k socketu", "SATA napájení disku"}, 4, 0}, - }; - static const char *hints[] = { - "Minimum dílů na stole ukáže, jestli jádro žije.", - "Pin na desce je křehký.", - "Bez nich nebo se špatnými sloupky deska zkratuje.", - "Konektory si jsou podobné a sedí špatně záměrně.", - }; - return quizyear_quiz(qy_hw2, 4, "hw2_ex5_title", "hw2_quiz5_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Firmware", "BIOS a UEFI", "Tip: UEFI není jen barevné menu. Umí jiné dělení disku a Secure Boot.", - { - "Firmware otestuje železo a najde disk se systémem.", - "UEFI používá tabulku GPT, starý BIOS často MBR.", - "Secure Boot pustí jen podepsaný zavaděč.", - "Vypnutí Secure Bootu je výjimka, ne výchozí rada.", - NULL, - }, - }, - { - "2 / 3 • Pořadí", "Z čeho se startuje", "Tip: flash disk v pořadí před systémem nabootuje omylem instalaci.", - { - "Nabídka bootu umí jednorázově vybrat zařízení.", - "Disk bez zavaděče se v seznamu nechytí.", - "Více systémů potřebuje bootovací nabídku, ne přepisování pořád dokola.", - "Síťový boot PXE hledá obraz na serveru.", - NULL, - }, - }, - { - "3 / 3 • Heslo", "Menu není pro celou třídu", "Tip: heslo BIOSu bez záznamu je past, až se bude měnit disk.", - { - "Heslo na setup brání přehazování bootu.", - "Heslo na disk je silnější a bez něj jsou data nedostupná.", - "Clear CMOS heslo setupu často smaže a vezme i nastavení.", - "Po změně profilu paměti ověřte, že systém naběhne dvakrát.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 5, "hw2_unit6", "hw2_unit6_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co Secure Boot hlídá?", {"Aby se spustil jen důvěryhodný zavaděč", "Aby měl disk aspoň 1 TB", "Aby ventilátor točil na maximum", "Aby nešel USB flash disk vůbec zapojit"}, 4, 0}, - {"Čím se liší GPT od MBR?", {"GPT je tabulka oddílů pro UEFI a větší disky", "GPT je typ pasty", "MBR je jen pro NVMe", "Jsou to totéž"}, 4, 0}, - {"Proč nenechat flash disk trvale první v bootu?", {"Omylem z něj naběhne cizí systém", "Flash disk vypne Secure Boot navždy", "UEFI flash disky zakazuje", "Smaže TPM"}, 4, 0}, - {"Co často udělá vymazání CMOS?", {"Smaže heslo setupu i ostatní volby", "Smaže jen soubory na ploše", "Přepne Windows na jiný jazyk", "Opraví ohnutý pin"}, 4, 0}, - }; - static const char *hints[] = { - "Nepodepsaný zavaděč se nespustí.", - "Starý MBR má omezení, na která velký disk naráží.", - "Jednorázová nabídka bootu je bezpečnější.", - "Je to návrat firmware k výchozímu stavu.", - }; - return quizyear_quiz(qy_hw2, 5, "hw2_ex6_title", "hw2_quiz6_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • POST", "Test hned po zapnutí", "Tip: žádný obraz a žádné pípnutí neznamená automaticky mrtvý procesor.", - { - "Firmware zkouší procesor, paměť a grafiku.", - "Kódy na displeji desky jsou přesnější než staré pípání.", - "Reproduktor skříně musí být zapojený, jinak ticho nic neřekne.", - "Manuál desky překládá kódy. Nejsou u všech stejné.", - NULL, - }, - }, - { - "2 / 3 • Minimum", "Uberte, co může lhát", "Tip: jeden modul paměti v doporučeném slotu porazí čtyři najednou.", - { - "Ven grafika, pokud má procesor vlastní obraz.", - "Ven disky a karty.", - "Zkuste jiný kabel obrazu a jiný port.", - "Až jádro naběhne, vracejte díly po jednom.", - NULL, - }, - }, - { - "3 / 3 • Paměť a disk", "Náhodné pády", "Tip: pád až ve Windows může být paměť, ne jen ovladač.", - { - "Test paměti běží déle než jedno pípnutí.", - "Chyby čtení disku se projeví v jeho vlastních statistikách.", - "Přehřátí shodí stroj až při zátěži, ne v menu BIOSu.", - "Vyměněný díl ověřte stejnou zkouškou, která předtím selhala.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 6, "hw2_unit7", "hw2_unit7_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co POST dělá?", {"Po zapnutí zkouší základní díly", "Instaluje systém", "Formátuje SSD", "Stahuje ovladače z internetu"}, 4, 0}, - {"Proč začít s jedním modulem paměti?", {"Špatný modul nebo slot se snáz odhalí", "Deska víc modulů zakazuje", "BIOS umí jen 4 GB", "Druhý modul maže UEFI"}, 4, 0}, - {"Kdy se přehřátí často neprojeví?", {"V menu BIOSu bez zátěže", "Při dlouhém testu procesoru", "Ve hře", "Při kódování videa"}, 4, 0}, - {"Co ověří výměnu dílu?", {"Stejná zkouška, která předtím selhala", "Jen to, že ventilátor se točí", "Nová tapeta", "Jiná barva skříně"}, 4, 0}, - }; - static const char *hints[] = { - "Je to první test firmware, ne operační systém.", - "Minimum dílů zužuje chybu.", - "Teplota roste až s odběrem.", - "Bez opakování testu nevíte, jestli to byla příčina.", - }; - return quizyear_quiz(qy_hw2, 6, "hw2_ex7_title", "hw2_quiz7_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw2_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Dok", "Jeden kabel, mnoho omezení", "Tip: levný USB hub není dok. Nepřenese obraz, který port neumí.", - { - "Dok může nést obraz, síť i napájení.", - "Limit je nejslabší článek: port, kabel nebo dok.", - "Dva externí monitory chtějí port, který to umí, ne přání uživatele.", - "Napájení přes dok nemusí stačit hernímu notebooku.", - NULL, - }, - }, - { - "2 / 3 • Síť", "Kabel z notebooku", "Tip: mnoho tenkých notebooků už ethernet nemá a potřebuje adaptér.", - { - "USB adaptér je síťová karta mimo šasi.", - "Rychlost adaptéru bývá 1 Gb/s, ne rychlost školní páteře.", - "Dok s vlastní síťovkou má vlastní MAC adresu.", - "Rezervace DHCP na MAC notebooku pak neplatí pro dok.", - NULL, - }, - }, - { - "3 / 3 • Výběr", "Na co se ptát", "Tip: stejný USB-C na dvou noteboocích nemá stejné schopnosti.", - { - "Kolik obrazů, jaké rozlišení a jestli se notebook nabíjí.", - "Jestli síť jede z doku, nebo se čeká Wi-Fi.", - "Jestli čtečka karet a USB sedí verzi, kterou škola používá.", - "Manuál portu je důležitější než fotka konektoru.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw2, 7, "hw2_unit8", "hw2_unit8_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw2_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy USB-C dok nepřenese dva monitory?", {"Když port notebooku umí jen data", "Když je dok černý", "Když je v učebně VLAN", "Když má disk NVMe"}, 4, 0}, - {"Proč DHCP rezervace na notebook neplatí přes dok?", {"Dok má vlastní MAC adresu", "DHCP doky zakazuje", "VLAN maže rezervace", "Ethernet nemá MAC"}, 4, 0}, - {"Co je nejslabší článek řetězu obrazu?", {"Port, kabel nebo dok, podle toho, co umí nejmíň", "Vždy monitor", "Vždy procesor", "Vždy tapeta"}, 4, 0}, - {"Čím se liší USB hub od doku s obrazem?", {"Hub sám o sobě obraz z datového portu nevyrobí", "Hub je vždy rychlejší", "Dok neumí napájení", "Jsou to totéž"}, 4, 0}, - }; - static const char *hints[] = { - "Dok neumí vyrobit schopnost, kterou port nemá.", - "Rezervace sedí na adresu, kterou server vidí.", - "Datový tok musí projít všemi.", - "Obraz chce alternativní režim nebo DisplayPort v kabelu.", - }; - return quizyear_quiz(qy_hw2, 7, "hw2_ex8_title", "hw2_quiz8_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Zrcadlo", "RAID 1", "Tip: zrcadlo přežije pád jednoho disku, ne smazání souboru.", - { - "Stejná data jsou na dvou discích.", - "Kapacita je jako jeden disk.", - "Čtení může být rychlejší, zápis ne dvojnásobný.", - "Po výměně disku se pole musí obnovit.", - NULL, - }, - }, - { - "2 / 3 • Prokládání", "RAID 0 a 5", "Tip: RAID 0 při pádu jednoho disku ztratí všechno.", - { - "RAID 0 skládá rychlost a kapacitu a nemá ochranu.", - "RAID 5 snese pád jednoho disku z aspoň tří.", - "Parita zabere kapacitu jednoho disku.", - "Obnova velkého pole trvá dlouho a druhý pád v té době je zkáza.", - NULL, - }, - }, - { - "3 / 3 • Řadič", "Hardware a software", "Tip: pole z jiného řadiče v novém serveru nemusí naběhnout.", - { - "Hardwarový řadič má vlastní cache a baterii.", - "Softwarové pole řeší systém a je přenosnější.", - "Cache bez ochrany při výpadku proudu rozbije zápis.", - "RAID nenahrazuje zálohu na jiné místo.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 0, "hw3_unit1", "hw3_unit1_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co RAID 1 přežije?", {"Pád jednoho z dvojice disků", "Smazání souboru uživatelem", "Požár místnosti", "Ransomware na obou discích naráz"}, 4, 0}, - {"Co je RAID 0?", {"Prokládání bez ochrany při pádu disku", "Zrcadlo", "Záloha na pásku", "Šifrování disku"}, 4, 0}, - {"Proč RAID není záloha?", {"Neochrání před smazáním, malwarem ani požárem skříně", "Protože neumí víc než dva disky", "Protože Windows RAID zakazuje", "Protože parita maže soubory"}, 4, 0}, - {"Co hrozí velkému poli při obnově?", {"Druhý disk spadne dřív, než se obnova dopočítá", "Pole se samo přepne na RAID 0", "BIOS smaže paritu", "NIC se při obnově nesmí točit"}, 4, 0}, - }; - static const char *hints[] = { - "Oba disky mají stejná data, včetně chyby, kterou tam zapíšete.", - "Rychlost a kapacita, nulová odolnost.", - "Záloha je další kopie jinde a v jiném čase.", - "Obnova je dlouhá a disky jsou stejně staré.", - }; - return quizyear_quiz(qy_hw3, 0, "hw3_ex1_title", "hw3_quiz1_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • NAS", "Souborový server v krabici", "Tip: NAS v učebně bez zálohy je jen jeden košík na všechna data.", - { - "Nabízí složky po síti.", - "Má vlastní účty nebo se ptá školního adresáře.", - "Dva porty se dají spojit, ale jen když to umí i switch.", - "Hlučný diskový provoz nepatří do tiché učebny.", - NULL, - }, - }, - { - "2 / 3 • SAN", "Disk jako místní", "Tip: SAN nedává složku, dává blokové zařízení.", - { - "Server vidí disk, i když leží jinde.", - "Síť pro SAN se nemíchá s provozem žáků.", - "Špatné zónování vystaví disk cizímu serveru.", - "Výpadek této sítě shodí systémy, které na disku jedou.", - NULL, - }, - }, - { - "3 / 3 • Soubor", "Práva a snímky", "Tip: snímek disku není záloha, dokud leží na stejném poli.", - { - "Práva na složce mají sedět se skupinami, ne s jedním účtem učitele.", - "Snímek umí vrátit soubor smazaný dopoledne.", - "Plný svazek zastaví i zdánlivě nesouvisející službu.", - "Kapacita se hlídá dřív, než svítí červeně.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 1, "hw3_unit2", "hw3_unit2_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co NAS obvykle nabízí?", {"Složky po síti", "Blokový disk celé škole bez oprávnění", "Náhradu procesoru v noteboocích", "Obraz monitoru"}, 4, 0}, - {"Čím se SAN liší?", {"Server dostane disk jako bloky, ne jako složku", "Je to jen jiné jméno pro USB flash disk", "Jede jen po Wi-Fi", "Nemá disky"}, 4, 0}, - {"Proč snímek na stejném poli není záloha?", {"Pád pole vezme i snímek", "Snímek nejde vytvořit", "Snímek maže RAID", "SMB snímky zakazuje"}, 4, 0}, - {"Kam nepatří hlučné diskové pole?", {"Do tiché učebny vedle žáků", "Do racku s odtahem", "Do místnosti se zámek", "Do sítě oddělené od hostů"}, 4, 0}, - }; - static const char *hints[] = { - "Je to souborová služba.", - "Souborový systém si na těch blocích dělá až server.", - "Záloha musí přežít ztrátu původního úložiště.", - "Hluk a přístup jsou součást návrhu.", - }; - return quizyear_quiz(qy_hw3, 1, "hw3_ex2_title", "hw3_quiz2_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tvar", "Racková jednotka", "Tip: 1U je výška, ne výkon.", - { - "Server v racku se měří v jednotkách U.", - "Kolejnice musí unést hloubku skříně.", - "Napájecí lišta není prodlužovačka z kuchyně.", - "Proud a teplo se počítají dopředu, ne až když jistič spadne.", - NULL, - }, - }, - { - "2 / 3 • Vzduch", "Studená ulička", "Tip: servery v racku sají vepředu a foukají dozadu. Otočený kus kazí ostatním.", - { - "Studený vzduch jde před servery, teplý za ně.", - "Zaslepení prázdných pozic nutí vzduch přes stroje.", - "Kabelová armáda před sáním je ucpávka.", - "Teplota v místnosti není teplota uvnitř 1U serveru.", - NULL, - }, - }, - { - "3 / 3 • Vzdáleně", "Když nejste ve škole", "Tip: vzdálená správa má vlastní port a vlastní heslo.", - { - "IPMI nebo iDRAC žije i když systém ne.", - "Patří do správní sítě, ne do učebny.", - "Konzole v racku je záloha, když síť správy spadne.", - "Štítek na serveru říká, co na něm jede.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 2, "hw3_unit3", "hw3_unit3_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co znamená 1U?", {"Výšku zařízení v racku", "Výkon jednoho jádra", "Rychlost disku", "Počet zdrojů"}, 4, 0}, - {"Kudy má server v racku sát vzduch?", {"Vepředu a foukat dozadu", "Zezadu dopředu", "Jen shora bez mřížky", "Z podlahy dírami v desce"}, 4, 0}, - {"K čemu je vzdálená správa serveru?", {"Ovládáte ho, i když systém neběží", "Nahrazuje zálohu dat", "Je to Wi-Fi pro žáky", "Maže RAID"}, 4, 0}, - {"Kam nepatří port vzdálené správy?", {"Do žákovské VLAN", "Do správní sítě", "Za firewall", "Na heslo jiné než admin na lístečku"}, 4, 0}, - }; - static const char *hints[] = { - "Je to rozměr, ne třída výkonu.", - "Otočený server ohřívá sousedům sání.", - "Vidíte obraz a umíte stroj zapnout po síti.", - "Je to klíče od serveru.", - }; - return quizyear_quiz(qy_hw3, 2, "hw3_ex3_title", "hw3_quiz3_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Hypervizor", "Kdo rozděluje železo", "Tip: virtuální počítač nemá vlastní zdroj. Dělí se o ten fyzický.", - { - "Hypervizor pouští více systémů nad jedním hardwarem.", - "Každý systém má vlastní diskový soubor a virtuální síťovku.", - "Paměť, kterou slíbíte navíc, se ve špičce potká.", - "Pád fyzického serveru shodí všechny hosty naráz.", - NULL, - }, - }, - { - "2 / 3 • Síť", "Virtuální switch", "Tip: VLAN ve virtuálu musí sedět s trunkem na fyzické kartě.", - { - "Virtuální switch propojí hosty mezi sebou.", - "Most je pustí ven fyzickým portem.", - "Izolovaná síť jen mezi virtuály ven nevede.", - "Špatný trunk vystaví správní virtuál do učebny.", - NULL, - }, - }, - { - "3 / 3 • Disk", "Soubor není kouzlo", "Tip: tenký disk roste a může zaplnit svazek, na kterém leží.", - { - "Tenké provizionování slíbí víc, než je na začátku obsazeno.", - "Snímek před změnou umí vrátit systém.", - "Zapomenuté snímky zpomalí disk a zaplní úložiště.", - "Záloha virtuálu patří mimo ten samý disk.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 3, "hw3_unit4", "hw3_unit4_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co se stane, když spadne fyzický server s pěti virtuály?", {"Spadnou všechny, pokud nemají kam utéct", "Přežije aspoň správní virtuál", "Hypervizor je přenese na notebook", "Nic, virtuál zdroj nepotřebuje"}, 4, 0}, - {"K čemu je most virtuálního switche?", {"Pustí virtuál do fyzické sítě", "Smaže VLAN", "Nahradí RAID", "Zapne Secure Boot hostitele"}, 4, 0}, - {"Čím je tenký disk nebezpečný?", {"Doroste a zaplní úložiště pod sebou", "Nejde zálohovat", "Nemá souborový systém", "Vypne hypervizor"}, 4, 0}, - {"Co udělá zapomenutý snímek?", {"Roste a zpomaluje disk", "Smaže heslo BIOSu", "Opraví RAID 0", "Přidá paměť"}, 4, 0}, - }; - static const char *hints[] = { - "Sdílejí jedno železo.", - "Bez mostu virtuál ven neodejde.", - "Slíbená kapacita není volné místo.", - "Snímek je dočasná pojistka, ne trvalý režim.", - }; - return quizyear_quiz(qy_hw3, 3, "hw3_ex4_title", "hw3_quiz4_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Pravidlo", "Tři místa", "Tip: kopie na tom samém disku přežije jen omyl v koši, ne pád disku.", - { - "Jedna kopie je málo, když leží u originálu.", - "Druhá má být mimo stroj a třetí mimo budovu, když na tom záleží.", - "Verze v čase vrátí soubor z pátku, ne jen ze včerejška.", - "Šifrovaná záloha bez klíče je hromada nic.", - NULL, - }, - }, - { - "2 / 3 • Co zálohovat", "Ne jen plochu", "Tip: obraz systému bez dat školy je pěkná, ale prázdná záchrana.", - { - "Data, účty a konfigurace sítě jsou různé věci.", - "Poštovní schránka v cloudu má vlastní nastavení retence.", - "Databáze se nezálohuje kopírováním otevřeného souboru naslepo.", - "Seznam, co se nezálohuje, má být vědomý.", - NULL, - }, - }, - { - "3 / 3 • Zkouška", "Obnova je součást zálohy", "Tip: záloha, kterou jste nikdy neobnovili, je hypotéza.", - { - "Jednou za čas obnovte soubor i celý systém nanečisto.", - "Měřte, jak dlouho obnova trvá.", - "Zápis říká, kdo má klíče a kde leží média.", - "Po ransomware rozhoduje stáří poslední čisté kopie.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 4, "hw3_unit5", "hw3_unit5_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč nestačí kopie na stejném disku?", {"Pád disku vezme originál i kopii", "Systém druhou složku zakazuje", "RAID ji sám smaže", "NTFS umí jen jeden soubor"}, 4, 0}, - {"Co není pořádná zkouška zálohy?", {"Jen to, že noční úloha svítí zeleně", "Obnova jednoho souboru", "Změřený čas obnovy systému", "Ověření, že klíč k šifře existuje"}, 4, 0}, - {"Co rozhoduje po ransomware?", {"Jestli existuje čistá kopie starší než nákaza", "Barva skříně", "Počet ventilátorů", "Verze spořiče obrazovky"}, 4, 0}, - {"Proč nekopírovat otevřenou databázi jako obyčejný soubor?", {"Rozpracovaný zápis bude nekonzistentní", "Databáze nemá soubor", "SMB databáze zakazuje", "Kopie by smazala RAID"}, 4, 0}, - }; - static const char *hints[] = { - "Chyba média je společná.", - "Zelená fajfka neznamená, že data jdou otevřít.", - "Šifrovaná záloha z doby, kdy už malware běžel, je taky šifrovaná.", - "Běžící databáze se zálohuje nástrojem, který umí konzistentní snímek.", - }; - return quizyear_quiz(qy_hw3, 4, "hw3_ex5_title", "hw3_quiz5_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Úkol", "Překlenout výpadek", "Tip: malá UPS neutáhne učebnu. Utáhne server, než se uloží.", - { - "Při výpadku přejde na baterii.", - "Čas běhu závisí na odběru, ne na nálepce bez zátěže.", - "Server dostane signál a vypne se po pořádku.", - "Tiskárna a monitor na UPS servery okrádají o minuty.", - NULL, - }, - }, - { - "2 / 3 • Tvar", "Ne každá UPS je pro zdroj serveru", "Tip: levná UPS s obdélníkovým průběhem modernímu zdroji vadí.", - { - "Sinusový výstup je jistější pro aktivní PFC zdroje.", - "Výkon ve voltampérech není totéž co watty na štítku zdroje.", - "Přetížená UPS spadne právě ve výpadku.", - "Zkouška pod zátěží ukáže skutečné minuty.", - NULL, - }, - }, - { - "3 / 3 • Baterie", "Spotřební díl", "Tip: baterie po třech letech v teple už slíbené minuty nedá.", - { - "Test baterie nečeká na první bouřku.", - "Výměna se dělá dřív, než článek nabobtná.", - "Teplá místnost baterii ničí rychleji.", - "UPS není náhrada za zálohu dat.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 5, "hw3_unit6", "hw3_unit6_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu malá UPS u serveru je?", {"Aby se systém stihl uložit a vypnout", "Aby učebna jela celé odpoledne", "Aby nahradila zálohu disků", "Aby chladila rack"}, 4, 0}, - {"Proč na UPS nepatří laserová tiskárna?", {"Má velký odběr a sebere čas serverům", "Tiskárna UPS zničí vždy okamžitě", "USB tiskárny UPS zakazuje", "Toner potřebuje jinou frekvenci"}, 4, 0}, - {"Co ukáže jen nálepka bez zátěže?", {"Optimistický čas, který v provozu neplatí", "Přesné minuty při plném serveru", "Stav RAID", "Teplotu procesoru"}, 4, 0}, - {"Jak často baterie přestane držet slib?", {"Po letech, dřív v teple", "Nikdy, je součástí zdroje navždy", "Až po deseti minutách prvního provozu", "Jen když je UPS černá"}, 4, 0}, - }; - static const char *hints[] = { - "Jsou to minuty, ne směna.", - "Špička zapékání baterii vybíjí zbytečně.", - "Měří se s tím, co na UPS opravdu visí.", - "Je to spotřební díl a má se zkoušet.", - }; - return quizyear_quiz(qy_hw3, 5, "hw3_ex6_title", "hw3_quiz6_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Co to je", "Program v železe", "Tip: firmware není ovladač ve Windows. Žije v zařízení i bez systému.", - { - "Deska, disk, switch i BIOS mají vlastní verzi.", - "Chyba ve firmware shodí zařízení bez ohledu na systém.", - "Výrobce vydává opravy i roky po prodeji.", - "Neznámá verze se nejdřív zjistí, potom se teprve stahuje.", - NULL, - }, - }, - { - "2 / 3 • Postup", "Jedno zařízení, zdroj, záloha", "Tip: aktualizace při bouřce bez UPS je způsob, jak dostat cihlu.", - { - "Přečtěte, co verze opravuje a co rozbije.", - "Záloha konfigurace switche jde bokem.", - "Napájení nesmí vypadnout v půlce zápisu.", - "Po dokončení ověřte, že naběhla i služba, ne jen dioda.", - NULL, - }, - }, - { - "3 / 3 • Řada", "Ne všechno v pátek odpoledne", "Tip: neaktualizujte jádro sítě a jediný server ve stejné hodině.", - { - "Nejdřív méně důležité zařízení.", - "Okno, kdy smí síť ležet, je domluvené.", - "Když nová verze zlobí, musíte umět předchozí.", - "Zápis verze patří k zařízení, ne do hlavy jednoho člověka.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 6, "hw3_unit7", "hw3_unit7_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se firmware liší od ovladače?", {"Je v zařízení a běží i bez operačního systému", "Je to jen soubor na ploše", "Maže se s přeinstalací vždy", "Umí ho jen tiskárna"}, 4, 0}, - {"Co před aktualizací switche uložíte?", {"Konfiguraci a zajistíte napájení", "Jen tapetu na ploše", "Heslo Wi-Fi na tabuli", "Nic, aktualizace si pamatuje sama"}, 4, 0}, - {"Proč neaktualizovat jádro a jediný server naráz?", {"Když obojí selže, nemáte z čeho učit ani spravovat", "Výrobce to technicky zakazuje vždy", "Firmware umí jen jedno zařízení na budovu", "UPS to nesežere"}, 4, 0}, - {"Co po aktualizaci ověříte?", {"Že služba opravdu naběhla, ne jen že svítí dioda", "Že je krabice teplejší", "Že se změnila barva menu", "Nic, firmware se neověřuje"}, 4, 0}, - }; - static const char *hints[] = { - "BIOS a firmware disku přežijí nový systém.", - "Přerušený zápis a chybějící záloha jsou dvě pasti.", - "Nechte si cestu zpět.", - "Start zařízení není totéž co fungující síť.", - }; - return quizyear_quiz(qy_hw3, 6, "hw3_ex7_title", "hw3_quiz7_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw3_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Co měřit", "Úzké hrdlo", "Tip: rychlý procesor nezachrání pomalý disk, na kterém systém čeká.", - { - "Sledujte procesor, paměť, disk a síť zvlášť.", - "Vytížení 100 % chvíli není chyba, trvale ano.", - "Fronta na disku řekne víc než otáčky ventilátoru.", - "Jedno číslo z herního testu není návrh školního serveru.", - NULL, - }, - }, - { - "2 / 3 • Podmínky", "Stejná zkouška", "Tip: srovnávejte stejný test, stejná data a stejný čas běhu.", - { - "Studený start a druhý běh z cache nejsou totéž.", - "Notebook na baterii schválně zpomalí.", - "Antivirus v testu umí sežrat výsledek.", - "Zapište verzi systému i to, co na pozadí jelo.", - NULL, - }, - }, - { - "3 / 3 • Rozhodnutí", "Kdy dokoupit", "Tip: nejdřív paměť nebo disk, ne automaticky nejnovější procesor.", - { - "Málo paměti žene systém na disk a všechno zpomalí.", - "Plný a pomalý disk kazí i silný procesor.", - "Slabé Wi-Fi nezrychlíte výměnou grafické karty.", - "Nákup bez měření je odhad.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw3, 7, "hw3_unit8", "hw3_unit8_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw3_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co neznamená krátká špička procesoru na 100 %?", {"Že je procesor nutně slabý", "Že je všechno v pořádku navždy", "Že disk neexistuje", "Že se má hned vyměnit deska"}, 4, 0}, - {"Proč druhý běh testu bývá rychlejší?", {"Data už jsou v cache", "Procesor se sám přetaktuje natrvalo", "Disk se zmenší", "BIOS test podruhé vynechá"}, 4, 0}, - {"Co často zpomalí celý systém dřív než procesor?", {"Málo paměti a pomalý disk", "Příliš mnoho USB myš", "Barva skříně", "Počet ikon na ploše"}, 4, 0}, - {"Co k výsledku testu patří zapsat?", {"Verze, napájení a co jelo na pozadí", "Jen nejvyšší číslo", "Jméno učitele", "Heslo k BIOSu"}, 4, 0}, - }; - static const char *hints[] = { - "Záleží, jestli špička trvá a jestli na ní někdo čeká.", - "Cache není výkon železa v prvním čtení.", - "Systém pak pořád čeká na stránkování.", - "Bez podmínek číslo nejde zopakovat.", - }; - return quizyear_quiz(qy_hw3, 7, "hw3_ex8_title", "hw3_quiz8_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Prašnost", "Řád, ne až když hučí", "Tip: otevřená skříň vysátá naslepo umí nasát prach dovnitř zdroje.", - { - "Filtry se perou dřív, než zčernají.", - "Zdroj se neotevírá. Čistí se zvenku.", - "Klávesnice a myš učebny jsou spotřební a špinavé.", - "Zápis, kdy se učebna dělala, příště určí interval.", - NULL, - }, - }, - { - "2 / 3 • Kontakty", "Uvolněný kabel vypadá jako mrtvá deska", "Tip: než objednáte desku, domáčkněte napájení a vyzkoušejte jiný kabel obrazu.", - { - "Oxidy na stolních konektorech kazí obraz i USB.", - "Ohnutý konektor HDMI se do portu necpe silou.", - "Napájecí kabel s poškozenou izolací se vyřadí, nelepí páskou.", - "Prodlužovačka pod kobercem je požár, ne úspora místa.", - NULL, - }, - }, - { - "3 / 3 • Evidence", "Co ve třídě vůbec je", "Tip: bez inventárního čísla nepoznáte, který zdroj se vrací do záruky.", - { - "Štítek, umístění a rok pořízení.", - "Záruka a doklad nejsou v šuplíku jednoho člověka.", - "Odepsaný stroj se nevrací do sítě s původním účtem.", - "Pravidelná prohlídka je levnější než hodina bez učebny.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 0, "hw4_unit1", "hw4_unit1_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co se při údržbě se zdrojem nedělá?", {"Neotevírá se", "Omývá se mu mřížka zvenku", "Kontroluje se kabel", "Píše se, kdy byl čištěný"}, 4, 0}, - {"Co uděláte s kabelem s porušenou izolací?", {"Vyřadíte ho", "Zalepíte izolepou a vrátíte pod koberec", "Schováte ho za skříň", "Dáte ho k žákovskému počítači"}, 4, 0}, - {"K čemu je inventární číslo?", {"Aby šlo dohledat záruku a umístění", "Aby zrychlilo procesor", "Nahrazuje heslo BIOSu", "Je to sériové číslo Windows"}, 4, 0}, - {"Kam nepatří odepsaný počítač?", {"Zpět do sítě s původními účty", "Do evidence odpadu", "K smazání disků", "Mimo žákovskou VLAN"}, 4, 0}, - }; - static const char *hints[] = { - "Uvnitř je napětí i po odpojení.", - "Poškozená izolace je požár a úraz.", - "Bez něj je reklamace hádanka.", - "Starý účet na mrtvém stroji je pořád díra, když ho někdo zapne.", - }; - return quizyear_quiz(qy_hw4, 0, "hw4_ex1_title", "hw4_quiz1_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • TPM", "Klíče mimo disk", "Tip: TPM není heslo, které uživatel píše při každém startu.", - { - "Čip drží klíče použité při startu a šifrování disku.", - "Bez něj některé systémy šifrování disku odmítnou.", - "Vymazání TPM bez zálohy klíčů znamená ztrátu přístupu k disku.", - "Na virtuálu bývá TPM také virtuální a patří k tomu stroji.", - NULL, - }, - }, - { - "2 / 3 • Start", "Řetěz důvěry", "Tip: Secure Boot a TPM řeší start, ne to, co uživatel spustí odpoledne.", - { - "Firmware ověří zavaděč.", - "Zavaděč ověří jádro.", - "Cizí systém z flash disku bez podpisu nenaběhne.", - "V laboratoři se výjimka zapíše, nenechá vypnutá navždy.", - NULL, - }, - }, - { - "3 / 3 • Zámek", "Kensington není šifra", "Tip: lankový zámek zdrží odnesení, data chrání šifrování disku.", - { - "Zámek skříně zpomalí toho, kdo chce odnést RAM.", - "Heslo BIOSu zpomalí toho, kdo chce přeházet boot.", - "Šifra disku zastaví toho, kdo disk odnese.", - "Všechny tři vrstvy řeší jiného zloděje.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 1, "hw4_unit2", "hw4_unit2_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co TPM drží?", {"Klíče pro start a šifrování", "Zálohu všech dokumentů školy", "Obraz monitoru", "Seznam VLAN"}, 4, 0}, - {"Co se stane po vymazání TPM bez zálohy klíčů?", {"Šifrovaný disk nemusí jít otevřít", "Zrychlí se start", "Smaže se jen spořič", "Nic, TPM klíče nepoužívá"}, 4, 0}, - {"Co Secure Boot nezastaví?", {"Program, který uživatel spustí v už naběhlém systému", "Nepodepsaný zavaděč", "Cizí systém z flashe, pokud podpis chybí", "Změnu řetězu startu"}, 4, 0}, - {"Co ochrání data na odcizeném disku?", {"Šifrování disku", "Jen lankový zámek skříně", "Heslo spořiče", "Inventární štítek"}, 4, 0}, - }; - static const char *hints[] = { - "Není to úložiště souborů.", - "Klíč v čipu bez kopie je pryč.", - "Hlídá start, ne každé pozdější kliknutí.", - "Zámek zdrží odnesení celé skříně, ne čtení disku na jiném stroji.", - }; - return quizyear_quiz(qy_hw4, 1, "hw4_ex2_title", "hw4_quiz2_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Účel", "Učebna není střih videa", "Tip: stejná sestava pro psaní a pro CAD je buď drahá, nebo pomalá.", - { - "Kancelář chce spolehlivost, ticho a dost paměti na prohlížeč.", - "Střih a CAD chtějí procesor, paměť a často grafiku.", - "Server chce ECC nebo aspoň diskové pole a správu, ne podsvícení.", - "Počet portů a dokování je součást ceny, ne doplněk potom.", - NULL, - }, - }, - { - "2 / 3 • Čísla", "Co srovnávat", "Tip: více jader nepomůže programu, který umí jen jedno.", - { - "Paměť berte s rezervou na čtyři roky, ne na dnešní minimum.", - "SSD jako systémový disk je základ. Velký sklad může být pomalejší.", - "Zdroj má rezervu nad součtem štítků, ne jen přesný součet.", - "Záruka na místě je u učebny levnější než odvoz dvaceti strojů.", - NULL, - }, - }, - { - "3 / 3 • Stejnost", "Jedna image", "Tip: dvacet různých desek znamená dvacet ovladačů.", - { - "Stejný model v učebně zjednoduší image i náhradní díl.", - "Dokoupit za dva roky stejnou desku často nejde. Pište, co je uvnitř.", - "Nejlevnější kus bez portů, které učebna používá, levný není.", - "Příkon a hluk patří do zadání, ne až do reklamace.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 2, "hw4_unit3", "hw4_unit3_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Podle čeho se volí sestava?", {"Podle práce, kterou na ní škola dělá", "Podle barvy krabice", "Podle nejvyššího čísla v reklamě", "Podle počtu RGB ventilátorů"}, 4, 0}, - {"Proč v učebně stejný model?", {"Jedna image a jeden náhradní díl", "Aby se lišily ovladače", "Aby každý stroj bootoval jinak", "Zákon to vyžaduje kvůli VLAN"}, 4, 0}, - {"Co u zdroje nestačí?", {"Součet štítků bez rezervy", "Rezerva nad typický odběr", "Správný formát do skříně", "Pojistka, která sedí k rozvodu"}, 4, 0}, - {"Co zdraží zdánlivě levný notebook?", {"Chybějící porty a dok, který musíte dokoupit", "To, že má SSD", "To, že má záruku", "To, že je tichý"}, 4, 0}, - }; - static const char *hints[] = { - "CAD a psaní dopisu nechtějí stejné železo.", - "Různé desky znamenají různou údržbu.", - "Špička a stárnutí se do přesného součtu nevejdou.", - "Učebna bez obrazových výstupů potřebuje doky.", - }; - return quizyear_quiz(qy_hw4, 2, "hw4_ex3_title", "hw4_quiz3_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Správa", "Cizí kapsy", "Tip: telefon žáka není školní majetek a nepatří mu školní certifikát natrvalo.", - { - "Školní tablet se dá zapsat do správy a na dálku smazat.", - "Soukromý telefon do správy školy nepatří.", - "Účet školy na soukromém zařízení má jít odebrat.", - "Ztracený školní tablet bez správy je cizí počítač s vašimi daty.", - NULL, - }, - }, - { - "2 / 3 • Síť", "Kam ho pustit", "Tip: telefon učitelů ve stejné VLAN jako servery je zbytečné riziko.", - { - "Hostovská nebo mobilní síť je oddělená.", - "Školní tablet může dostat jinou síť než návštěva.", - "Sdílené tablety se mezi žáky mažou nebo přepínají profil.", - "Nabíjení ve třídě je otázka pojistek, ne jen kabelů na stole.", - NULL, - }, - }, - { - "3 / 3 • Život", "Baterie a pád", "Tip: cyklování baterie v nabíjecím kufru ji po dvou letech unaví.", - { - "Obal a popruh jsou součást nákupu, ne charita.", - "Aktualizace systému se dělají hromadně, ne podle nálady.", - "Rozbitý displej se nevrací do oběhu s trčícím sklem.", - "Evidence IMEI nebo sériového čísla patří k inventuře.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 3, "hw4_unit4", "hw4_unit4_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se liší školní tablet od soukromého telefonu?", {"Školní jde zapsat do správy a na dálku vymazat", "Soukromý musí mít školní certifikát navždy", "Jsou to stejné režimy", "Tablet nepatří do inventury"}, 4, 0}, - {"Kam nepatří učitelský telefon?", {"Do VLAN se servery", "Do oddělené mobilní sítě", "Na účet, který jde odebrat", "Mimo žákovská data, pokud to jde"}, 4, 0}, - {"Co sdílený tablet mezi žáky potřebuje?", {"Mazání profilu nebo oddělené účty", "Jedno heslo napsané na obalu", "Trvalou složku předchozího žáka", "Vypnuté aktualizace"}, 4, 0}, - {"Co patří do evidence tabletu?", {"Sériové číslo a umístění", "Jen barva obalu", "Heslo žáka", "Soukromé fotky"}, 4, 0}, - }; - static const char *hints[] = { - "Majetek školy se dá spravovat, kapsa žáka ne.", - "Ztracený telefon nemá být klíč k serverům.", - "Cizí účet na dalším žákovi je únik.", - "Bez čísla ho nepoznáte v kupě stejných.", - }; - return quizyear_quiz(qy_hw4, 3, "hw4_ex4_title", "hw4_quiz4_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Projektor", "Lampa a síť", "Tip: lampa má hodiny. Nečekejte, až praskne uprostřed hodiny.", - { - "Zdroj obrazu a kabel jsou častější chyba než deska.", - "Filtr projektoru se ucpe prachem a přístroj se vypne.", - "Stropní držák se dotahuje, nevěší se na něj.", - "Náhradní kabel ve třídě je levnější než přestávka.", - NULL, - }, - }, - { - "2 / 3 • Tisk", "Fronta a toner", "Tip: prázdný toner a zaseknutý papír jsou dvě různé hlášky.", - { - "Sklad toneru má být suchý, ne na topení.", - "Účet tisku omezí náhodné desítky stran.", - "Síťová tiskárna se po výměně adresy musí najít znovu.", - "Servisní interval bubnu není totéž co výměna toneru.", - NULL, - }, - }, - { - "3 / 3 • Drobnosti", "Myš, sluchátka, kamera", "Tip: bezdrátová myš bez náhradní baterie je v hodině mrtvá.", - { - "Sluchátka ve třídě mají být omyvatelná.", - "Kamera na dálkovou výuku chce světlo před obličejem, ne za zády.", - "USB přijímač myši ztracený v portu projektoru se špatně hledá.", - "Spotřební věci se objednávají dřív, než dojde poslední kus.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 4, "hw4_unit5", "hw4_unit5_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co u projektoru kontrolovat dřív než desku?", {"Zdroj obrazu, kabel a filtr", "Jen typ žárovky ve stropě učebny", "Heslo Wi-Fi", "Verzi BIOSu učitelského telefonu"}, 4, 0}, - {"Čím se liší toner a buben?", {"Toner je prach s barvou, buben je díl, který obraz přenáší", "Jsou to totéž", "Buben se mění každý den", "Toner je jen u inkoustové tiskárny"}, 4, 0}, - {"Proč účty tisku?", {"Omezí náhodné velké tisky", "Zvýší rozlišení", "Nahradí papír", "Vypnou skener"}, 4, 0}, - {"Co ve třídě dochází bez náhrady jako první?", {"Baterie, kabely a spotřební díly", "Procesory", "Rackové lišty", "TPM čipy"}, 4, 0}, - }; - static const char *hints[] = { - "Obraz často končí na kabelu.", - "Prázdný toner a unavený buben vypadají na stránce jinak.", - "Fronta bez limitu tiskne omylem celé knihy.", - "Drobnost zastaví hodinu stejně jako velká porucha.", - }; - return quizyear_quiz(qy_hw4, 4, "hw4_ex5_title", "hw4_quiz5_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Disk", "Smazat neznamená vyhodit", "Tip: rychlé formátování nechá data čitelná.", - { - "Před vyřazením se disk smaže tak, aby nešel běžně obnovit.", - "Nefunkční disk se fyzicky zničí, ne jen odloží.", - "SSD se maže příkazem, který buňky opravdu uvolní.", - "Potvrzení o likvidaci patří k inventuře.", - NULL, - }, - }, - { - "2 / 3 • Železo", "Není to směsný odpad", "Tip: monitor a deska nepatří do popelnice za školou.", - { - "Elektroodpad se odevzdává na určené místo.", - "Baterie zvlášť, a nabobtnané ještě opatrněji.", - "Toner je taky odpad s režimem, ne koš ve sborovně.", - "Štítek s jménem žáka se před odvozem sundá.", - NULL, - }, - }, - { - "3 / 3 • Darování", "Starý stroj ven ze školy", "Tip: darovaný počítač bez smazání účtů je dar i s přístupy.", - { - "Nejdřív data, potom majetek.", - "Licence vázaná na školu se nesmí odstěhovat s počítačem.", - "Zápis, komu stroj připadl, chrání školu.", - "Nefunkční dar je jen přesun odpadu.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 5, "hw4_unit6", "hw4_unit6_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč nestačí rychlé formátování?", {"Data jdou často obnovit", "Formát disk fyzicky rozbije", "SSD formát zakazuje", "Smaže i TPM v jiném počítači"}, 4, 0}, - {"Kam nepatří stará deska?", {"Do směsného koše", "Do elektroodpadu", "K evidované likvidaci", "Po smazání dat, pokud se vyřazuje"}, 4, 0}, - {"Co před darem počítače uděláte?", {"Smažete data a ověříte licence", "Necháte účty, ať se nový majitel přihlásí", "Jen umyjete skříň", "Přilepíte heslo na víko"}, 4, 0}, - {"Čím se maže SSD líp než jedním přepisem naslepo?", {"Příkazem, který buňky opravdu uvolní", "Smazáním koše", "Změnou tapety", "Vypnutím Secure Boot"}, 4, 0}, - }; - static const char *hints[] = { - "Zmizí odkaz, ne obsah buněk.", - "Elektroodpad má vlastní režim.", - "Dar není předání školní sítě.", - "Řadič SSD přepis naslepo nemusí uložit tam, kde čekáte.", - }; - return quizyear_quiz(qy_hw4, 5, "hw4_ex6_title", "hw4_quiz6_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Příznak", "Co přesně nejde", "Tip: ‚nejde počítač‘ může být černý obraz, špatné heslo i spadlá síť.", - { - "Zeptejte se, co uživatel čekal a co vidí.", - "Od kdy a jestli to jde jinde.", - "Jedna učebna, nebo jen jeden stůl.", - "Bez příznaku se mění díly naslepo.", - NULL, - }, - }, - { - "2 / 3 • Izolace", "Nejužší místo", "Tip: fungující kabel a fungující port rozdělí chybu na dvě hromady.", - { - "Vyměňte kabel, port, účet nebo zařízení, vždy jen jedno.", - "Když náhradní kus funguje, původní je vinný nebo špatně nastavený.", - "Když nefunguje ani náhradní, chyba je ve společné věci.", - "Pište si mezivýsledky. Paměť po obědě lže.", - NULL, - }, - }, - { - "3 / 3 • Závěr", "Oprava a prevence", "Tip: vyměněný kabel bez zápisu se příští měsíc tváří jako záhada.", - { - "Opravte příčinu, ne jen příznak na jednom stole.", - "Řekněte uživateli, co se změnilo.", - "Díly do opravy nepatří zpátky do skříně potichu.", - "Opakovaná závada chce úpravu nákupu nebo zapojení.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 6, "hw4_unit7", "hw4_unit7_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je první otázka?", {"Co přesně nejde a od kdy", "Jakou má deska barvu", "Jestli je ve škole VLAN 20", "Kolik stojí nový notebook"}, 4, 0}, - {"Proč měnit jen jeden díl?", {"Ať víte, který rozdíl pomohl", "Sklad má jen jeden kabel", "BIOS víc výměn zakazuje", "Uživatel jinak zapomene heslo"}, 4, 0}, - {"Náhradní kabel taky nejde. Co z toho plyne?", {"Chyba je spíš ve portu, účtu nebo zařízení", "Oba kabely jsou vždy špatné", "Síť nemá smysl", "Je rozbitý TPM"}, 4, 0}, - {"Co patří do zápisu opravy?", {"Příznak, příčina a co se vyměnilo", "Jen ‚hotovo‘", "Heslo uživatele", "Soukromý názor na učitele"}, 4, 0}, - }; - static const char *hints[] = { - "Příznak zužuje vrstvu, kterou budete zkoušet.", - "Dvě výměny naráz nic nedokážou.", - "Společné selhání ukazuje na společnou část.", - "Příště podle zápisu nezačínáte od nuly.", - }; - return quizyear_quiz(qy_hw4, 6, "hw4_ex7_title", "hw4_quiz7_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -static GtkWidget *build_hw4_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tok dat", "Od kliknutí k disku", "Tip: maturita chce cestu, ne seznam zkratek.", - { - "Vstup, paměť, procesor, sběrnice, disk a výstup.", - "RAM je pracovní, disk je trvalý. Není to totéž.", - "Grafika může mít vlastní paměť a pořád jede po sběrnici.", - "Úzké hrdlo je nejpomalejší článek této cesty.", - NULL, - }, - }, - { - "2 / 3 • Spolehlivost", "Co drží učebnu", "Tip: záloha, RAID a UPS řeší tři různé nehody.", - { - "RAID drží provoz při pádu disku.", - "Záloha vrátí data z jiného místa a času.", - "UPS dá čas na vypnutí.", - "Firmware a čištění jsou prevence, ne oprava po požáru.", - NULL, - }, - }, - { - "3 / 3 • Rozhodnutí", "Proč právě tahle krabice", "Tip: umíte obhájit paměť, disk a porty pro konkrétní učebnu.", - { - "Kancelář, střih a server mají jiné priority.", - "Stejný model ve třídě šetří image.", - "Vyřazení začíná smazáním dat.", - "Závadu vedete od příznaku po jedné změně.", - NULL, - }, - }, - }; - return quizyear_unit(qy_hw4, 7, "hw4_unit8", "hw4_unit8_sub", slides, (int)(sizeof slides / sizeof slides[0])); -} - -static GtkWidget *build_hw4_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se liší RAM a disk?", {"RAM je pracovní paměť, disk drží data i bez napájení", "Jsou to totéž", "Disk je vždy rychlejší", "RAM se zálohuje na pásku"}, 4, 0}, - {"Co vrátí soubor smazaný před týdnem?", {"Záloha z dřívějšího dne, ne RAID", "RAID 1 sám", "UPS", "Secure Boot"}, 4, 0}, - {"Co dá UPS?", {"Čas na pořádné vypnutí", "Kopii dat v jiné budově", "Rychlejší procesor", "Nový disk"}, 4, 0}, - {"Čím začíná vyřazení počítače?", {"Smazáním dat", "Sundáním obalu", "Darem bez kontroly", "Zápisem do VLAN"}, 4, 0}, - }; - static const char *hints[] = { - "Vypnutí smaže obsah RAM, ne uložený soubor na disku.", - "RAID má pořád aktuální, tedy i smazaný stav.", - "Baterie není archiv.", - "Nejdřív obsah, potom plech.", - }; - return quizyear_quiz(qy_hw4, 7, "hw4_ex8_title", "hw4_quiz8_head", qs, hints, (int)(sizeof qs / sizeof qs[0])); -} - -void add_it_year_pages(GtkStack *stack) { - quizyear_boot(); - gtk_stack_add_named(stack, quizyear_map(qy_net2), "net2map"); - gtk_stack_add_named(stack, quizyear_map(qy_net3), "net3map"); - gtk_stack_add_named(stack, quizyear_map(qy_net4), "net4map"); - gtk_stack_add_named(stack, quizyear_map(qy_hw2), "hw2map"); - gtk_stack_add_named(stack, quizyear_map(qy_hw3), "hw3map"); - gtk_stack_add_named(stack, quizyear_map(qy_hw4), "hw4map"); - gtk_stack_add_named(stack, build_net2_unit1_page(), "net2unit1"); - gtk_stack_add_named(stack, build_net2_unit1_exercise_page(), "net2ex1"); - gtk_stack_add_named(stack, build_net2_unit2_page(), "net2unit2"); - gtk_stack_add_named(stack, build_net2_unit2_exercise_page(), "net2ex2"); - gtk_stack_add_named(stack, build_net2_unit3_page(), "net2unit3"); - gtk_stack_add_named(stack, build_net2_unit3_exercise_page(), "net2ex3"); - gtk_stack_add_named(stack, build_net2_unit4_page(), "net2unit4"); - gtk_stack_add_named(stack, build_net2_unit4_exercise_page(), "net2ex4"); - gtk_stack_add_named(stack, build_net2_unit5_page(), "net2unit5"); - gtk_stack_add_named(stack, build_net2_unit5_exercise_page(), "net2ex5"); - gtk_stack_add_named(stack, build_net2_unit6_page(), "net2unit6"); - gtk_stack_add_named(stack, build_net2_unit6_exercise_page(), "net2ex6"); - gtk_stack_add_named(stack, build_net2_unit7_page(), "net2unit7"); - gtk_stack_add_named(stack, build_net2_unit7_exercise_page(), "net2ex7"); - gtk_stack_add_named(stack, build_net2_unit8_page(), "net2unit8"); - gtk_stack_add_named(stack, build_net2_unit8_exercise_page(), "net2ex8"); - gtk_stack_add_named(stack, build_net3_unit1_page(), "net3unit1"); - gtk_stack_add_named(stack, build_net3_unit1_exercise_page(), "net3ex1"); - gtk_stack_add_named(stack, build_net3_unit2_page(), "net3unit2"); - gtk_stack_add_named(stack, build_net3_unit2_exercise_page(), "net3ex2"); - gtk_stack_add_named(stack, build_net3_unit3_page(), "net3unit3"); - gtk_stack_add_named(stack, build_net3_unit3_exercise_page(), "net3ex3"); - gtk_stack_add_named(stack, build_net3_unit4_page(), "net3unit4"); - gtk_stack_add_named(stack, build_net3_unit4_exercise_page(), "net3ex4"); - gtk_stack_add_named(stack, build_net3_unit5_page(), "net3unit5"); - gtk_stack_add_named(stack, build_net3_unit5_exercise_page(), "net3ex5"); - gtk_stack_add_named(stack, build_net3_unit6_page(), "net3unit6"); - gtk_stack_add_named(stack, build_net3_unit6_exercise_page(), "net3ex6"); - gtk_stack_add_named(stack, build_net3_unit7_page(), "net3unit7"); - gtk_stack_add_named(stack, build_net3_unit7_exercise_page(), "net3ex7"); - gtk_stack_add_named(stack, build_net3_unit8_page(), "net3unit8"); - gtk_stack_add_named(stack, build_net3_unit8_exercise_page(), "net3ex8"); - gtk_stack_add_named(stack, build_net4_unit1_page(), "net4unit1"); - gtk_stack_add_named(stack, build_net4_unit1_exercise_page(), "net4ex1"); - gtk_stack_add_named(stack, build_net4_unit2_page(), "net4unit2"); - gtk_stack_add_named(stack, build_net4_unit2_exercise_page(), "net4ex2"); - gtk_stack_add_named(stack, build_net4_unit3_page(), "net4unit3"); - gtk_stack_add_named(stack, build_net4_unit3_exercise_page(), "net4ex3"); - gtk_stack_add_named(stack, build_net4_unit4_page(), "net4unit4"); - gtk_stack_add_named(stack, build_net4_unit4_exercise_page(), "net4ex4"); - gtk_stack_add_named(stack, build_net4_unit5_page(), "net4unit5"); - gtk_stack_add_named(stack, build_net4_unit5_exercise_page(), "net4ex5"); - gtk_stack_add_named(stack, build_net4_unit6_page(), "net4unit6"); - gtk_stack_add_named(stack, build_net4_unit6_exercise_page(), "net4ex6"); - gtk_stack_add_named(stack, build_net4_unit7_page(), "net4unit7"); - gtk_stack_add_named(stack, build_net4_unit7_exercise_page(), "net4ex7"); - gtk_stack_add_named(stack, build_net4_unit8_page(), "net4unit8"); - gtk_stack_add_named(stack, build_net4_unit8_exercise_page(), "net4ex8"); - gtk_stack_add_named(stack, build_hw2_unit1_page(), "hw2unit1"); - gtk_stack_add_named(stack, build_hw2_unit1_exercise_page(), "hw2ex1"); - gtk_stack_add_named(stack, build_hw2_unit2_page(), "hw2unit2"); - gtk_stack_add_named(stack, build_hw2_unit2_exercise_page(), "hw2ex2"); - gtk_stack_add_named(stack, build_hw2_unit3_page(), "hw2unit3"); - gtk_stack_add_named(stack, build_hw2_unit3_exercise_page(), "hw2ex3"); - gtk_stack_add_named(stack, build_hw2_unit4_page(), "hw2unit4"); - gtk_stack_add_named(stack, build_hw2_unit4_exercise_page(), "hw2ex4"); - gtk_stack_add_named(stack, build_hw2_unit5_page(), "hw2unit5"); - gtk_stack_add_named(stack, build_hw2_unit5_exercise_page(), "hw2ex5"); - gtk_stack_add_named(stack, build_hw2_unit6_page(), "hw2unit6"); - gtk_stack_add_named(stack, build_hw2_unit6_exercise_page(), "hw2ex6"); - gtk_stack_add_named(stack, build_hw2_unit7_page(), "hw2unit7"); - gtk_stack_add_named(stack, build_hw2_unit7_exercise_page(), "hw2ex7"); - gtk_stack_add_named(stack, build_hw2_unit8_page(), "hw2unit8"); - gtk_stack_add_named(stack, build_hw2_unit8_exercise_page(), "hw2ex8"); - gtk_stack_add_named(stack, build_hw3_unit1_page(), "hw3unit1"); - gtk_stack_add_named(stack, build_hw3_unit1_exercise_page(), "hw3ex1"); - gtk_stack_add_named(stack, build_hw3_unit2_page(), "hw3unit2"); - gtk_stack_add_named(stack, build_hw3_unit2_exercise_page(), "hw3ex2"); - gtk_stack_add_named(stack, build_hw3_unit3_page(), "hw3unit3"); - gtk_stack_add_named(stack, build_hw3_unit3_exercise_page(), "hw3ex3"); - gtk_stack_add_named(stack, build_hw3_unit4_page(), "hw3unit4"); - gtk_stack_add_named(stack, build_hw3_unit4_exercise_page(), "hw3ex4"); - gtk_stack_add_named(stack, build_hw3_unit5_page(), "hw3unit5"); - gtk_stack_add_named(stack, build_hw3_unit5_exercise_page(), "hw3ex5"); - gtk_stack_add_named(stack, build_hw3_unit6_page(), "hw3unit6"); - gtk_stack_add_named(stack, build_hw3_unit6_exercise_page(), "hw3ex6"); - gtk_stack_add_named(stack, build_hw3_unit7_page(), "hw3unit7"); - gtk_stack_add_named(stack, build_hw3_unit7_exercise_page(), "hw3ex7"); - gtk_stack_add_named(stack, build_hw3_unit8_page(), "hw3unit8"); - gtk_stack_add_named(stack, build_hw3_unit8_exercise_page(), "hw3ex8"); - gtk_stack_add_named(stack, build_hw4_unit1_page(), "hw4unit1"); - gtk_stack_add_named(stack, build_hw4_unit1_exercise_page(), "hw4ex1"); - gtk_stack_add_named(stack, build_hw4_unit2_page(), "hw4unit2"); - gtk_stack_add_named(stack, build_hw4_unit2_exercise_page(), "hw4ex2"); - gtk_stack_add_named(stack, build_hw4_unit3_page(), "hw4unit3"); - gtk_stack_add_named(stack, build_hw4_unit3_exercise_page(), "hw4ex3"); - gtk_stack_add_named(stack, build_hw4_unit4_page(), "hw4unit4"); - gtk_stack_add_named(stack, build_hw4_unit4_exercise_page(), "hw4ex4"); - gtk_stack_add_named(stack, build_hw4_unit5_page(), "hw4unit5"); - gtk_stack_add_named(stack, build_hw4_unit5_exercise_page(), "hw4ex5"); - gtk_stack_add_named(stack, build_hw4_unit6_page(), "hw4unit6"); - gtk_stack_add_named(stack, build_hw4_unit6_exercise_page(), "hw4ex6"); - gtk_stack_add_named(stack, build_hw4_unit7_page(), "hw4unit7"); - gtk_stack_add_named(stack, build_hw4_unit7_exercise_page(), "hw4ex7"); - gtk_stack_add_named(stack, build_hw4_unit8_page(), "hw4unit8"); - gtk_stack_add_named(stack, build_hw4_unit8_exercise_page(), "hw4ex8"); -} - diff --git a/src/it_years_i18n.inc b/src/it_years_i18n.inc deleted file mode 100644 index 3bfe82d..0000000 --- a/src/it_years_i18n.inc +++ /dev/null @@ -1,198 +0,0 @@ - {"net2_sub", "VLAN, STP, DHCP, DNS, NAT, IPv6, statické směrování a ACL.", "VLANs, STP, DHCP, DNS, NAT, IPv6, static routing and ACLs."}, - {"net2_unit1", "VLAN a trunk", "VLANs and trunks"}, - {"net2_unit1_sub", "Logické sítě na jednom přepínači a značkovaný spoj.", "Logical networks on one switch and a tagged link."}, - {"net2_ex1_title", "Kvíz: VLAN a trunk", "Quiz: VLANs and trunks"}, - {"net2_quiz1_head", "Kvíz k tématu VLAN a trunk", "Quiz on VLANs and trunks"}, - {"net2_unit2", "STP a smyčky", "STP and loops"}, - {"net2_unit2_sub", "Proč smyčka na druhé vrstvě shodí síť a jak ji STP přeruší.", "Why a layer-2 loop takes the network down, and how STP breaks it."}, - {"net2_ex2_title", "Kvíz: STP a smyčky", "Quiz: STP and loops"}, - {"net2_quiz2_head", "Kvíz k tématu STP a smyčky", "Quiz on STP and loops"}, - {"net2_unit3", "DHCP a DNS", "DHCP and DNS"}, - {"net2_unit3_sub", "Kdo přiděluje adresu a kdo překládá jméno.", "Who hands out an address, and who translates a name."}, - {"net2_ex3_title", "Kvíz: DHCP a DNS", "Quiz: DHCP and DNS"}, - {"net2_quiz3_head", "Kvíz k tématu DHCP a DNS", "Quiz on DHCP and DNS"}, - {"net2_unit4", "NAT a PAT", "NAT and PAT"}, - {"net2_unit4_sub", "Jedna veřejná adresa pro mnoho počítačů.", "One public address for many computers."}, - {"net2_ex4_title", "Kvíz: NAT a PAT", "Quiz: NAT and PAT"}, - {"net2_quiz4_head", "Kvíz k tématu NAT a PAT", "Quiz on NAT and PAT"}, - {"net2_unit5", "IPv6 základy", "IPv6 basics"}, - {"net2_unit5_sub", "Delší adresa, jiný zápis a co se nemění.", "A longer address, a different notation, and what stays the same."}, - {"net2_ex5_title", "Kvíz: IPv6 základy", "Quiz: IPv6 basics"}, - {"net2_quiz5_head", "Kvíz k tématu IPv6 základy", "Quiz on IPv6 basics"}, - {"net2_unit6", "Statické směrování", "Static routing"}, - {"net2_unit6_sub", "Ruční cesta, metrika a kdy přestane stačit.", "A hand-written route, the metric, and when it is no longer enough."}, - {"net2_ex6_title", "Kvíz: Statické směrování", "Quiz: Static routing"}, - {"net2_quiz6_head", "Kvíz k tématu Statické směrování", "Quiz on Static routing"}, - {"net2_unit7", "ACL a filtrování", "ACLs and filtering"}, - {"net2_unit7_sub", "Seznam, který provoz pustí a který zahodí.", "A list that permits traffic or drops it."}, - {"net2_ex7_title", "Kvíz: ACL a filtrování", "Quiz: ACLs and filtering"}, - {"net2_quiz7_head", "Kvíz k tématu ACL a filtrování", "Quiz on ACLs and filtering"}, - {"net2_unit8", "Podniková Wi-Fi", "Enterprise Wi-Fi"}, - {"net2_unit8_sub", "SSID, WPA3 a proč jedno heslo na nástěnce nestačí.", "SSIDs, WPA3, and why one password on the wall is not enough."}, - {"net2_ex8_title", "Kvíz: Podniková Wi-Fi", "Quiz: Enterprise Wi-Fi"}, - {"net2_quiz8_head", "Kvíz k tématu Podniková Wi-Fi", "Quiz on Enterprise Wi-Fi"}, - {"net3_sub", "OSPF, směrování mezi VLAN, WAN, VPN, firewall, QoS a dohled.", "OSPF, inter-VLAN routing, WAN, VPN, firewalls, QoS and monitoring."}, - {"net3_unit1", "OSPF", "OSPF"}, - {"net3_unit1_sub", "Směrovače si samy řeknou, jaké sítě znají.", "Routers tell each other which networks they know."}, - {"net3_ex1_title", "Kvíz: OSPF", "Quiz: OSPF"}, - {"net3_quiz1_head", "Kvíz k tématu OSPF", "Quiz on OSPF"}, - {"net3_unit2", "Směrování mezi VLAN", "Inter-VLAN routing"}, - {"net3_unit2_sub", "Jedna brána pro každou VLAN.", "One gateway for each VLAN."}, - {"net3_ex2_title", "Kvíz: Směrování mezi VLAN", "Quiz: Inter-VLAN routing"}, - {"net3_quiz2_head", "Kvíz k tématu Směrování mezi VLAN", "Quiz on Inter-VLAN routing"}, - {"net3_unit3", "WAN", "WAN"}, - {"net3_unit3_sub", "Spoj mezi pobočkami a k poskytovateli.", "A link between sites and towards the provider."}, - {"net3_ex3_title", "Kvíz: WAN", "Quiz: WAN"}, - {"net3_quiz3_head", "Kvíz k tématu WAN", "Quiz on WAN"}, - {"net3_unit4", "VPN", "VPN"}, - {"net3_unit4_sub", "Šifrovaný tunel přes síť, které nevěříte.", "An encrypted tunnel across a network you do not trust."}, - {"net3_ex4_title", "Kvíz: VPN", "Quiz: VPN"}, - {"net3_quiz4_head", "Kvíz k tématu VPN", "Quiz on VPN"}, - {"net3_unit5", "Firewall a zóny", "Firewalls and zones"}, - {"net3_unit5_sub", "Kdo s kým smí mluvit, ne jen jestli kabel svítí.", "Who may talk to whom, not only whether the cable is lit."}, - {"net3_ex5_title", "Kvíz: Firewall a zóny", "Quiz: Firewalls and zones"}, - {"net3_quiz5_head", "Kvíz k tématu Firewall a zóny", "Quiz on Firewalls and zones"}, - {"net3_unit6", "QoS", "QoS"}, - {"net3_unit6_sub", "Když je linka plná, někdo musí dostat přednost.", "When the link is full, someone has to go first."}, - {"net3_ex6_title", "Kvíz: QoS", "Quiz: QoS"}, - {"net3_quiz6_head", "Kvíz k tématu QoS", "Quiz on QoS"}, - {"net3_unit7", "Dohled sítě", "Watching the network"}, - {"net3_unit7_sub", "SNMP, syslog a co z grafu opravdu plyne.", "SNMP, syslog, and what a graph really tells you."}, - {"net3_ex7_title", "Kvíz: Dohled sítě", "Quiz: Watching the network"}, - {"net3_quiz7_head", "Kvíz k tématu Dohled sítě", "Quiz on Watching the network"}, - {"net3_unit8", "Záloha konfigurace", "Configuration backups"}, - {"net3_unit8_sub", "Co uložit, než se přepínač vymění.", "What to save before a switch is replaced."}, - {"net3_ex8_title", "Kvíz: Záloha konfigurace", "Quiz: Configuration backups"}, - {"net3_quiz8_head", "Kvíz k tématu Záloha konfigurace", "Quiz on Configuration backups"}, - {"net4_sub", "Návrh adres, redundance, 802.1X, hledání chyb, cloud a maturita.", "Address plans, redundancy, 802.1X, troubleshooting, cloud and the exam."}, - {"net4_unit1", "Adresní plán", "An address plan"}, - {"net4_unit1_sub", "Sítě se navrhují dřív, než se zapojí první kabel.", "Networks are designed before the first cable is patched."}, - {"net4_ex1_title", "Kvíz: Adresní plán", "Quiz: An address plan"}, - {"net4_quiz1_head", "Kvíz k tématu Adresní plán", "Quiz on An address plan"}, - {"net4_unit2", "Redundance", "Redundancy"}, - {"net4_unit2_sub", "Druhá cesta, která se opravdu použije.", "A second path that is actually used."}, - {"net4_ex2_title", "Kvíz: Redundance", "Quiz: Redundancy"}, - {"net4_quiz2_head", "Kvíz k tématu Redundance", "Quiz on Redundancy"}, - {"net4_unit3", "802.1X", "802.1X"}, - {"net4_unit3_sub", "Port pustí data, až když se zařízení představí.", "A port forwards data only after the device identifies itself."}, - {"net4_ex3_title", "Kvíz: 802.1X", "Quiz: 802.1X"}, - {"net4_quiz3_head", "Kvíz k tématu 802.1X", "Quiz on 802.1X"}, - {"net4_unit4", "Hledání chyby", "Troubleshooting"}, - {"net4_unit4_sub", "Postup zdola nahoru, ne náhodné restarty.", "Bottom-up steps, not random reboots."}, - {"net4_ex4_title", "Kvíz: Hledání chyby", "Quiz: Troubleshooting"}, - {"net4_quiz4_head", "Kvíz k tématu Hledání chyby", "Quiz on Troubleshooting"}, - {"net4_unit5", "Cloud a hybrid", "Cloud and hybrid networks"}, - {"net4_unit5_sub", "Část služeb není ve skříni na chodbě.", "Some services are no longer in the cupboard in the corridor."}, - {"net4_ex5_title", "Kvíz: Cloud a hybrid", "Quiz: Cloud and hybrid networks"}, - {"net4_quiz5_head", "Kvíz k tématu Cloud a hybrid", "Quiz on Cloud and hybrid networks"}, - {"net4_unit6", "Automatizace", "Automation"}, - {"net4_unit6_sub", "Opakovanou práci ať dělá skript, ne deset kliknutí.", "Let a script do the repeated work, not ten clicks."}, - {"net4_ex6_title", "Kvíz: Automatizace", "Quiz: Automation"}, - {"net4_quiz6_head", "Kvíz k tématu Automatizace", "Quiz on Automation"}, - {"net4_unit7", "Provoz a maturita", "Operations and the exam"}, - {"net4_unit7_sub", "Síť ve škole má pravidla, ne jen blikající porty.", "A school network has rules, not only blinking ports."}, - {"net4_ex7_title", "Kvíz: Provoz a maturita", "Quiz: Operations and the exam"}, - {"net4_quiz7_head", "Kvíz k tématu Provoz a maturita", "Quiz on Operations and the exam"}, - {"net4_unit8", "Dokumentace sítě", "Network documentation"}, - {"net4_unit8_sub", "Schéma, které sedí s tím, co je ve zdi.", "A diagram that matches what is actually in the wall."}, - {"net4_ex8_title", "Kvíz: Dokumentace sítě", "Quiz: Network documentation"}, - {"net4_quiz8_head", "Kvíz k tématu Dokumentace sítě", "Quiz on Network documentation"}, - {"hw2_sub", "Monitory, tisk, sběrnice, chlazení, sestavení, UEFI a diagnostika.", "Displays, printing, buses, cooling, assembly, UEFI and diagnostics."}, - {"hw2_unit1", "Monitory", "Displays"}, - {"hw2_unit1_sub", "Panel, rozlišení a proč 60 Hz není jediné číslo.", "The panel, the resolution, and why 60 Hz is not the only number."}, - {"hw2_ex1_title", "Kvíz: Monitory", "Quiz: Displays"}, - {"hw2_quiz1_head", "Kvíz k tématu Monitory", "Quiz on Displays"}, - {"hw2_unit2", "Tisk a sken", "Print and scan"}, - {"hw2_unit2_sub", "Laser, inkoust a síťová fronta.", "Laser, inkjet, and a network queue."}, - {"hw2_ex2_title", "Kvíz: Tisk a sken", "Quiz: Print and scan"}, - {"hw2_quiz2_head", "Kvíz k tématu Tisk a sken", "Quiz on Print and scan"}, - {"hw2_unit3", "Sběrnice a disky", "Buses and drives"}, - {"hw2_unit3_sub", "USB, SATA a NVMe nejsou zaměnitelné jen konektorem.", "USB, SATA and NVMe are not interchangeable just because of the plug."}, - {"hw2_ex3_title", "Kvíz: Sběrnice a disky", "Quiz: Buses and drives"}, - {"hw2_quiz3_head", "Kvíz k tématu Sběrnice a disky", "Quiz on Buses and drives"}, - {"hw2_unit4", "Chlazení", "Cooling"}, - {"hw2_unit4_sub", "Vzduch musí mít kudy dovnitř a ven.", "Air needs a way in and a way out."}, - {"hw2_ex4_title", "Kvíz: Chlazení", "Quiz: Cooling"}, - {"hw2_quiz4_head", "Kvíz k tématu Chlazení", "Quiz on Cooling"}, - {"hw2_unit5", "Sestavení", "Building a PC"}, - {"hw2_unit5_sub", "Pořadí, které nerozbije desku.", "An order that does not break the board."}, - {"hw2_ex5_title", "Kvíz: Sestavení", "Quiz: Building a PC"}, - {"hw2_quiz5_head", "Kvíz k tématu Sestavení", "Quiz on Building a PC"}, - {"hw2_unit6", "UEFI a boot", "UEFI and boot"}, - {"hw2_unit6_sub", "Co se děje, než naběhne systém.", "What happens before the operating system starts."}, - {"hw2_ex6_title", "Kvíz: UEFI a boot", "Quiz: UEFI and boot"}, - {"hw2_quiz6_head", "Kvíz k tématu UEFI a boot", "Quiz on UEFI and boot"}, - {"hw2_unit7", "Diagnostika", "Diagnostics"}, - {"hw2_unit7_sub", "POST, pípání a minimum, které ještě naběhne.", "POST, beep codes, and the smallest build that still starts."}, - {"hw2_ex7_title", "Kvíz: Diagnostika", "Quiz: Diagnostics"}, - {"hw2_quiz7_head", "Kvíz k tématu Diagnostika", "Quiz on Diagnostics"}, - {"hw2_unit8", "Porty a dokování", "Ports and docks"}, - {"hw2_unit8_sub", "Co z notebooku opravdu vyleze.", "What a laptop can actually drive."}, - {"hw2_ex8_title", "Kvíz: Porty a dokování", "Quiz: Ports and docks"}, - {"hw2_quiz8_head", "Kvíz k tématu Porty a dokování", "Quiz on Ports and docks"}, - {"hw3_sub", "RAID, NAS, servery, virtualizace, zálohy, UPS a firmware.", "RAID, NAS, servers, virtualisation, backups, UPS and firmware."}, - {"hw3_unit1", "RAID", "RAID"}, - {"hw3_unit1_sub", "Více disků jako jeden svazek, ne jako záloha.", "Several drives as one volume, not as a backup."}, - {"hw3_ex1_title", "Kvíz: RAID", "Quiz: RAID"}, - {"hw3_quiz1_head", "Kvíz k tématu RAID", "Quiz on RAID"}, - {"hw3_unit2", "NAS a sítě disků", "NAS and storage networks"}, - {"hw3_unit2_sub", "Disky, které nejsou uvnitř jednoho počítače.", "Drives that are not inside one computer."}, - {"hw3_ex2_title", "Kvíz: NAS a sítě disků", "Quiz: NAS and storage networks"}, - {"hw3_quiz2_head", "Kvíz k tématu NAS a sítě disků", "Quiz on NAS and storage networks"}, - {"hw3_unit3", "Servery a rack", "Servers and racks"}, - {"hw3_unit3_sub", "Skříň, do které se nedává herní počítač naležato.", "A cabinet that is not a gaming PC on its side."}, - {"hw3_ex3_title", "Kvíz: Servery a rack", "Quiz: Servers and racks"}, - {"hw3_quiz3_head", "Kvíz k tématu Servery a rack", "Quiz on Servers and racks"}, - {"hw3_unit4", "Virtualizace", "Virtualisation"}, - {"hw3_unit4_sub", "Více systémů na jednom železe.", "Several systems on one piece of hardware."}, - {"hw3_ex4_title", "Kvíz: Virtualizace", "Quiz: Virtualisation"}, - {"hw3_quiz4_head", "Kvíz k tématu Virtualizace", "Quiz on Virtualisation"}, - {"hw3_unit5", "Zálohování", "Backups"}, - {"hw3_unit5_sub", "Kopie, kterou umíte vrátit.", "A copy you can actually restore."}, - {"hw3_ex5_title", "Kvíz: Zálohování", "Quiz: Backups"}, - {"hw3_quiz5_head", "Kvíz k tématu Zálohování", "Quiz on Backups"}, - {"hw3_unit6", "UPS", "UPS"}, - {"hw3_unit6_sub", "Minuty na uložení, ne náhradní elektrárna.", "Minutes to shut down cleanly, not a spare power station."}, - {"hw3_ex6_title", "Kvíz: UPS", "Quiz: UPS"}, - {"hw3_quiz6_head", "Kvíz k tématu UPS", "Quiz on UPS"}, - {"hw3_unit7", "Firmware", "Firmware"}, - {"hw3_unit7_sub", "Aktualizace, která nejde udělat uprostřed hodiny.", "An update that is not applied in the middle of a lesson."}, - {"hw3_ex7_title", "Kvíz: Firmware", "Quiz: Firmware"}, - {"hw3_quiz7_head", "Kvíz k tématu Firmware", "Quiz on Firmware"}, - {"hw3_unit8", "Měření výkonu", "Measuring performance"}, - {"hw3_unit8_sub", "Číslo bez podmínek nic neznamená.", "A number without the conditions means nothing."}, - {"hw3_ex8_title", "Kvíz: Měření výkonu", "Quiz: Measuring performance"}, - {"hw3_quiz8_head", "Kvíz k tématu Měření výkonu", "Quiz on Measuring performance"}, - {"hw4_sub", "Údržba, TPM, nákup, mobily, periferie, ekologie a maturita.", "Maintenance, TPM, buying, mobiles, peripherals, disposal and the exam."}, - {"hw4_unit1", "Údržba", "Maintenance"}, - {"hw4_unit1_sub", "Čištění a revize dřív, než něco shoří.", "Cleaning and checks before something burns."}, - {"hw4_ex1_title", "Kvíz: Údržba", "Quiz: Maintenance"}, - {"hw4_quiz1_head", "Kvíz k tématu Údržba", "Quiz on Maintenance"}, - {"hw4_unit2", "TPM a Secure Boot", "TPM and Secure Boot"}, - {"hw4_unit2_sub", "Železo, které hlídá start systému.", "Hardware that watches the system start."}, - {"hw4_ex2_title", "Kvíz: TPM a Secure Boot", "Quiz: TPM and Secure Boot"}, - {"hw4_quiz2_head", "Kvíz k tématu TPM a Secure Boot", "Quiz on TPM and Secure Boot"}, - {"hw4_unit3", "Nákup sestavy", "Buying a computer"}, - {"hw4_unit3_sub", "Nejdřív práce, potom krabice.", "The work comes first, then the box."}, - {"hw4_ex3_title", "Kvíz: Nákup sestavy", "Quiz: Buying a computer"}, - {"hw4_quiz3_head", "Kvíz k tématu Nákup sestavy", "Quiz on Buying a computer"}, - {"hw4_unit4", "Mobilní zařízení", "Mobile devices"}, - {"hw4_unit4_sub", "Tablet a telefon ve školní síti.", "Tablets and phones on the school network."}, - {"hw4_ex4_title", "Kvíz: Mobilní zařízení", "Quiz: Mobile devices"}, - {"hw4_quiz4_head", "Kvíz k tématu Mobilní zařízení", "Quiz on Mobile devices"}, - {"hw4_unit5", "Periferie v provozu", "Peripherals in daily use"}, - {"hw4_unit5_sub", "Tiskárny, projektory a co se na nich láme.", "Printers, projectors, and what actually breaks."}, - {"hw4_ex5_title", "Kvíz: Periferie v provozu", "Quiz: Peripherals in daily use"}, - {"hw4_quiz5_head", "Kvíz k tématu Periferie v provozu", "Quiz on Peripherals in daily use"}, - {"hw4_unit6", "Ekologie a data", "Disposal and data"}, - {"hw4_unit6_sub", "Vyhozený disk pořád obsahuje školu.", "A discarded drive still contains the school."}, - {"hw4_ex6_title", "Kvíz: Ekologie a data", "Quiz: Disposal and data"}, - {"hw4_quiz6_head", "Kvíz k tématu Ekologie a data", "Quiz on Disposal and data"}, - {"hw4_unit7", "Metodika závady", "A fault method"}, - {"hw4_unit7_sub", "Jedna věta, která drží celý postup.", "One sentence that holds the whole procedure."}, - {"hw4_ex7_title", "Kvíz: Metodika závady", "Quiz: A fault method"}, - {"hw4_quiz7_head", "Kvíz k tématu Metodika závady", "Quiz on A fault method"}, - {"hw4_unit8", "Opakování k maturitě", "Exam review"}, - {"hw4_unit8_sub", "Železo, které umíte pojmenovat a zdůvodnit.", "Hardware you can name and justify."}, - {"hw4_ex8_title", "Kvíz: Opakování k maturitě", "Quiz: Exam review"}, - {"hw4_quiz8_head", "Kvíz k tématu Opakování k maturitě", "Quiz on Exam review"}, diff --git a/src/lit_year1.c b/src/lit_year1.c deleted file mode 100644 index 603779f..0000000 --- a/src/lit_year1.c +++ /dev/null @@ -1,614 +0,0 @@ -#include "graduately.h" - -/* Year 1: literary theory, antiquity, the Middle Ages, Renaissance, - * Baroque, Classicism and the Enlightenment. */ - -NetLesson lit_lessons[LIT_N] = { - { .n_slides = 3, .unit_page = "litunit1", .ex_page = "litex1" }, - { .n_slides = 3, .unit_page = "litunit2", .ex_page = "litex2" }, - { .n_slides = 3, .unit_page = "litunit3", .ex_page = "litex3" }, - { .n_slides = 3, .unit_page = "litunit4", .ex_page = "litex4" }, - { .n_slides = 3, .unit_page = "litunit5", .ex_page = "litex5" }, - { .n_slides = 3, .unit_page = "litunit6", .ex_page = "litex6" }, - { .n_slides = 3, .unit_page = "litunit7", .ex_page = "litex7" }, - { .n_slides = 3, .unit_page = "litunit8", .ex_page = "litex8" }, -}; - -static GtkWidget *build_lit_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Úvod", "Literatura jako umění slova", - "Tip: nejdřív druh a žánr, potom jazyk a dobový kontext.", - { - "Literatura sděluje zážitek uměleckým jazykem, nejen holou informaci.", - "Od publicistiky ji odlišuje estetická funkce a práce s obrazností.", - "Má i funkci poznávací, výchovnou a zábavnou.", - "Ve škole se sleduje vývoj v kulturních a historických souvislostech.", - NULL, - }, - }, - { - "2 / 3 • Druhy", "Lyrika, epika a drama", - "Tip: žánr je užší typ uvnitř literárního druhu.", - { - "Lyrika vyjadřuje niterný zážitek, epika vypráví příběh.", - "Drama je určeno k jevištnímu provedení a stojí na dialogu.", - "Epika: epos, román, povídka, novela, bajka. Lyrika: píseň, óda, elegie, sonet, balada.", - "Drama: tragédie, komedie, činohra. Vypravěč bývá v ich-formě, nebo er-formě.", - NULL, - }, - }, - { - "3 / 3 • Jazyk", "Verš, tropy a figury", - "Tip: metafora pojmenuje podobnost přímo, přirovnání použije jako.", - { - "Rým je sdružený (AABB), střídavý (ABAB), obkročný (ABBA) nebo přerývaný.", - "Volný verš se neváže pravidelným rýmem ani stopou.", - "Stopy: trochej, jamb a daktyl. Tropy: metafora, metonymie, personifikace, symbol, alegorie.", - "Figury: anafora, epifora, gradace, inverze, oxymóron a apostrofa.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[0], "lit_unit1", "lit_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Které jsou tři literární druhy?", - {"Lyrika, epika a drama", "Román, povídka a novela", - "Metafora, metonymie a symbol", "Baroko, romantismus a realismus"}, - 4, 0}, - {"Co je metafora?", - {"Přímé přirovnání se slovem jako", - "Pojmenování na základě podobnosti", - "Opakování slov na začátku veršů", "Báseň bez rýmu"}, - 4, 1}, - {"Který rým má schéma ABAB?", - {"Sdružený", "Obkročný", "Střídavý", "Přerývaný"}, - 4, 2}, - {"Co znamená ich-forma?", - {"Vyprávění v první osobě", "Vyprávění v třetí osobě", - "Drama beze slov", "Volný verš"}, - 4, 0}, - }; - static const char *hints[] = { - "Druh je základní členění, žánr je užší typ uvnitř druhu.", - "Přirovnání používá jako, metafora podobnost pojmenuje přímo.", - "Sdružený je AABB, obkročný ABBA, střídavý ABAB.", - "Ich-forma je já, er-forma je on nebo ona.", - }; - - return lit_mcq_page(0, 0, "litunit1", "lit_ex1_title", "lit_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_lit_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Orient", "Nejstarší písemnictví", - "Tip: Epos o Gilgamešovi je nejstarší dochovaný epos.", - { - "Mezopotámie zanechala Epos o Gilgamešovi, příběh o přátelství a hledání nesmrtelnosti.", - "Egypt známe z Knihy mrtvých, hymnů a milostné lyriky.", - "Indie má Védy, eposy Mahábhárata a Rámájana a divadelní hry Kálidásovy.", - "Čínská Kniha písní sbírá lidovou i obřadní lyriku.", - NULL, - }, - }, - { - "2 / 3 • Bible", "Hebrejská a křesťanská tradice", - "Tip: Bible je pramen motivů celé evropské kultury.", - { - "Starý zákon tvoří Tóra, historické a prorocké knihy, žalmy a mudrosloví.", - "Kazatel, Job a Píseň písní patří k nejčtenějším starozákonním knihám.", - "Nový zákon přináší evangelia, Skutky, epištoly a Zjevení.", - "Biblické postavy a obrazy se vracejí v literatuře všech pozdějších epoch.", - NULL, - }, - }, - { - "3 / 3 • Paměť", "Co si z orientu odnést", - "Tip: u eposu sledujte hrdinu, cestu a střet s osudem.", - { - "Společná témata jsou stvoření, potopa, zákon, láska a smrt.", - "Texty často vznikaly ústně a teprve později byly zapsány.", - "Anonymita a náboženský výklad světa převažují nad autorským já.", - "Na maturitě stačí zařadit dílo do kultury a říct, čím ovlivnilo Evropu.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[1], "lit_unit2", "lit_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Odkud pochází Epos o Gilgamešovi?", - {"Ze starého Egypta", "Z Mezopotámie", "Z antického Říma", "Ze středověké Francie"}, - 4, 1}, - {"Které knihy patří k indické epice?", - {"Ilias a Odyssea", "Mahábhárata a Rámájana", - "Aeneis a Proměny", "Božská komedie a Dekameron"}, - 4, 1}, - {"Co tvoří jádro Starého zákona?", - {"Čtyři evangelia", "Tóra a další knihy hebrejské bible", - "Korán", "Védy"}, - 4, 1}, - {"Proč se Bible probírá v literatuře?", - {"Je to učebnice zeměpisu", - "Je pramenem motivů evropské kultury", - "Vznikla v národním obrození", - "Patří k absurdnímu dramatu"}, - 4, 1}, - }; - static const char *hints[] = { - "Gilgameš je nejstarší dochovaný epos, zapsaný klínovým písmem.", - "Mahábhárata a Rámájana jsou velké indické eposy.", - "Starý zákon je hebrejská bible, Nový zákon evangelia a epištoly.", - "Biblické obrazy se vracejí od středověku po současnost.", - }; - - return lit_mcq_page(0, 1, "litunit2", "lit_ex2_title", "lit_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_lit_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Řecko", "Homér a attické drama", - "Tip: katarze je očištění diváka soucitem a bázní.", - { - "Homérova Ilias a Odyssea jsou vrchol řeckého eposu, veršovaný hexametrem.", - "Lyriku představují Sapfó, Anakreón a Pindaros.", - "Tragédie: Aischylos, Sofoklés (Král Oidipus, Antigona) a Eurípidés (Médeia).", - "Aristofanés psal komedie. Ideál kalokagathia spojoval krásu a dobro.", - NULL, - }, - }, - { - "2 / 3 • Řím", "Vergilius, Ovidius, Horatius", - "Tip: Aeneis vědomě navazuje na Homéra a zakládá římský mýtus.", - { - "Vergiliova Aeneis vypráví o útěku z Tróje a založení římského rodu.", - "Ovidiovy Proměny shrnují antické mýty, Umění milovat je milostný návod.", - "Horatius proslul ódami a myšlenkou zlaté střední cesty.", - "Římská literatura přejímá řecké vzory a předává je středověké Evropě.", - NULL, - }, - }, - { - "3 / 3 • Pojmy", "Co si z antiky pamatovat", - "Tip: u tragédie hledejte vinu, osud a poznání.", - { - "Epos začíná často in medias res a vzývá Múzu.", - "Tragický hrdina naráží na osud; divák prožívá katarzi.", - "Mýtus vysvětluje svět příběhem bohů a hrdinů.", - "Antika je stálý zdroj námětů pro renesanci, klasicismus i pozdější doby.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[2], "lit_unit3", "lit_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo napsal Iliadu a Odysseu?", - {"Sofoklés", "Homér", "Vergilius", "Ovidius"}, - 4, 1}, - {"Které dílo napsal Sofoklés?", - {"Médeia", "Král Oidipus", "Aeneis", "Proměny"}, - 4, 1}, - {"Co je katarze?", - {"Začátek eposu uprostřed děje", - "Očištění diváka soucitem a bázní", - "Římský název pro komedii", - "Volný verš bez stopy"}, - 4, 1}, - {"Kdo složil Aeneis?", - {"Horatius", "Homér", "Vergilius", "Aristofanés"}, - 4, 2}, - }; - static const char *hints[] = { - "Ilias a Odyssea jsou homérské eposy.", - "Sofoklés: Král Oidipus a Antigona. Médeia je Eurípidés.", - "Pojem katarze vychází z Aristotelovy Poetiky.", - "Aeneis je římský epos Vergiliův, Proměny napsal Ovidius.", - }; - - return lit_mcq_page(0, 2, "litunit3", "lit_ex3_title", "lit_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_lit_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Doba", "Středověký pohled na svět", - "Tip: texty bývají anonymní a často nábožensky alegorické.", - { - "Středověk vykládá svět křesťansky: pozemský život je cestou ke spáse.", - "Převažuje latina, postupně se prosazují národní jazyky.", - "Autor často ustupuje, dílo má sloužit víře, poučení nebo oslavě hrdiny.", - "Vedle učené tvorby žije ústní lidová slovesnost.", - NULL, - }, - }, - { - "2 / 3 • Žánry", "Hrdinská, rytířská a městská literatura", - "Tip: Dante uzavírá středověk a otevírá cestu k renesanci.", - { - "Hrdinská epika: Píseň o Rolandovi, Píseň o Nibelunzích, Beowulf.", - "Rytířská epika a dvorská lyrika: artušovské romány, Tristan a Isolda, trubadúři.", - "Náboženská literatura: legendy, hymny, exempla a duchovní drama.", - "Městská satira a Danteho Božská komedie, psaná tercínou.", - NULL, - }, - }, - { - "3 / 3 • Paměť", "Jak středověk číst", - "Tip: alegorie říká jednu věc a míní jinou, hlubší.", - { - "Hrdina ztělesňuje čest, věrnost, víru nebo rytířskou lásku.", - "Symbol a alegorie jsou důležitější než psychologická kresba.", - "Božská komedie provádí poutníka Peklem, Očistcem a Rájem.", - "Středověké látky se vracejí v romantismu i v moderní kultuře.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[3], "lit_unit4", "lit_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Které dílo patří k hrdinské epice?", - {"Dekameron", "Píseň o Rolandovi", "Hamlet", "Lakomec"}, - 4, 1}, - {"Čím je typický středověký text?", - {"Důrazem na individuální autorské já", - "Náboženským výkladem a častou anonymitou", - "Volným veršem avantgardy", - "Naturalistickým popisem dědičnosti"}, - 4, 1}, - {"Kdo napsal Božskou komedii?", - {"Francesco Petrarca", "Dante Alighieri", - "Giovanni Boccaccio", "William Shakespeare"}, - 4, 1}, - {"Jakou strofou je psána Božská komedie?", - {"Sonetem", "Tercínou", "Blankversem", "Hexametrem"}, - 4, 1}, - }; - static const char *hints[] = { - "Píseň o Rolandovi je francouzská chanson de geste.", - "Středověk klade víru a poučení nad autorskou originalitu.", - "Dante, Petrarca a Boccaccio jsou tři velcí Italové, Božská komedie je Dantova.", - "Tercína je trojverší, které Dante v komedii používá.", - }; - - return lit_mcq_page(0, 3, "litunit4", "lit_ex4_title", "lit_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_lit_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Počátky", "Staroslověnština a latina", - "Tip: rok 863 je příchod Konstantina a Metoděje na Velkou Moravu.", - { - "Konstantin a Metoděj přinesli staroslověnské písmo a překlady bohoslužebných textů.", - "K památkám patří Proglas, Život Konstantinův a Metodějův a Kyjevské listy.", - "Po vyhnání slovanské liturgie přebírá vzdělanost latina.", - "Kosmova kronika je nejstarší česká kronika, psaná latinsky.", - NULL, - }, - }, - { - "2 / 3 • Čeština", "Literatura 14. století", - "Tip: Dalimil píše česky a z hlediska české šlechty.", - { - "Dalimilova kronika je první veršovaná kronika v češtině.", - "Alexandreida přenáší antický příběh o Alexandrovi do rytířského světa.", - "Mastičkář je nejstarší české drama, Hradecký rukopis sbírá legendy a satiru.", - "Doba Karla IV. posiluje češtinu vedle latiny a němčiny.", - NULL, - }, - }, - { - "3 / 3 • Husitství", "Hus, píseň a Chelčický", - "Tip: husitství je vrchol starší české literatury v národním jazyce.", - { - "Jan Hus kritizuje církev v českých kázáních a latinském spise O církvi.", - "Jistebnický kancionál uchoval píseň Ktož jsú boží bojovníci.", - "Petr Chelčický v Sieti viery odmítá násilí a spojení víry s mocí.", - "Husitská čeština zjednodušuje pravopis a posiluje srozumitelnost.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[4], "lit_unit5", "lit_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy přišli Konstantin a Metoděj na Velkou Moravu?", - {"Roku 863", "Roku 1415", "Roku 1348", "Roku 1620"}, - 4, 0}, - {"Která kronika je první v češtině?", - {"Kosmova kronika", "Dalimilova kronika", - "Hájkova kronika", "Vita Caroli"}, - 4, 1}, - {"Kterou píseň uchoval Jistebnický kancionál?", - {"Kde domov můj", "Ktož jsú boží bojovníci", - "Ach synku, synku", "Hej, Slované"}, - 4, 1}, - {"Čím je Petr Chelčický?", - {"Autorem renesančních sonetů", - "Myslitelem, který odmítá násilí a spojení víry s mocí", - "Barokním kazatelem protireformace", - "Obrozenským jazykovědcem"}, - 4, 1}, - }; - static const char *hints[] = { - "863 je cyrilometodějská misie, 1415 upálení Husa.", - "Kosmas psal latinsky, Dalimil česky.", - "Ktož jsú boží bojovníci je husitská bojová píseň.", - "Sieť viery pravé je Chelčického hlavní spis.", - }; - - return lit_mcq_page(0, 4, "litunit5", "lit_ex5_title", "lit_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_lit_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Doba", "Člověk se vrací do středu", - "Tip: humanismus staví na antice, renesance na smyslovém světě.", - { - "Humanismus obnovuje zájem o antiku, jazyk a vzdělání člověka.", - "Renesance oslavuje pozemský život, individualitu a smyslovou krásu.", - "Itálie udává tón: Petrarcův sonet a Boccacciův Dekameron.", - "Proti středověkému teocentrismu stojí zájem o člověka a přírodu.", - NULL, - }, - }, - { - "2 / 3 • Evropa", "Od Cervantese k Shakespearovi", - "Tip: Hamlet je renesanční hrdina, který pochybuje a zkoumá.", - { - "Francie: Rabelais (Gargantua a Pantagruel) a Montaignovy Eseje.", - "Španělsko: Cervantesův Důmyslný rytíř don Quijote de la Mancha.", - "Anglie: Shakespeare, tragédie Hamlet, Romeo a Julie, Macbeth, Othello a komedie.", - "Sonet má 14 veršů a pevné schéma; Shakespeare ho užívá i v milostné lyrice.", - NULL, - }, - }, - { - "3 / 3 • Čechy", "Veleslavín a Bible kralická", - "Tip: Bible kralická je vrchol humanistické češtiny.", - { - "Jednota bratrská vydává Bibli kralickou, vzor spisovného jazyka.", - "Daniel Adam z Veleslavína podporuje tisk, překlady a vzdělanost.", - "Jan Blahoslav pečuje o jazyk a bratrský zpěvník.", - "Český humanismus končí porážkou stavovského povstání a pobělohorskou změnou.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[5], "lit_unit6", "lit_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je autorem Dekameronu?", - {"Dante Alighieri", "Giovanni Boccaccio", - "Francesco Petrarca", "Miguel de Cervantes"}, - 4, 1}, - {"Které dílo napsal Shakespeare?", - {"Don Quijote", "Hamlet", "Gargantua a Pantagruel", "Božská komedie"}, - 4, 1}, - {"Co je sonet?", - {"Báseň o 14 verších s pevnou stavbou", - "Středověká hrdinská píseň", - "Dramatická jednota času", - "Barokní kázání"}, - 4, 0}, - {"Která kniha je vrcholem humanistické češtiny?", - {"Kosmova kronika", "Bible kralická", "Labyrint světa", "Máj"}, - 4, 1}, - }; - static const char *hints[] = { - "Petrarca je sonet, Boccaccio Dekameron, Dante Božská komedie.", - "Hamlet, Romeo a Julie, Macbeth a Othello jsou Shakespearovy tragédie.", - "Sonet má 14 veršů, obvykle dvě čtyřverší a dvě trojverší.", - "Bibli kralickou vydala Jednota bratrská na přelomu 16. a 17. století.", - }; - - return lit_mcq_page(0, 5, "litunit6", "lit_ex6_title", "lit_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_lit_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Styl", "Kontrast a napětí", - "Tip: baroko miluje protiklad těla a duše, světa a věčnosti.", - { - "Baroko vzniká v napětí reformace a protireformace.", - "Vyhledává kontrast, nadsázku, emblém a smyslovou okázalost.", - "Častý je motiv marnosti, smrti a touhy po Bohu.", - "Ve světě sem patří Calderónův Život je sen a Miltonův Ztracený ráj.", - NULL, - }, - }, - { - "2 / 3 • Čechy", "Pobělohorská tvorba", - "Tip: po roce 1620 se dělí domácí katolická tvorba a exil.", - { - "Bedřich Bridel v básni Co Bůh? Člověk? staví nicotu člověka proti Bohu.", - "Bohuslav Balbín brání v latině český jazyk a dějiny.", - "Lidová a pololidová tvorba, kramářské písně a legendy udržují češtinu.", - "Oficiální kultura je katolická, mnoho vzdělanců odchází do exilu.", - NULL, - }, - }, - { - "3 / 3 • Komenský", "Labyrint světa a ráj srdce", - "Tip: Komenský je vrchol českého baroka i evropského pedagogického myšlení.", - { - "Jan Amos Komenský, poslední biskup Jednoty bratrské, píše v exilu.", - "Labyrint světa a ráj srdce je alegorické putování za smyslem života.", - "Informatorium školy mateřské a Orbis pictus zakládají moderní pedagogiku.", - "Kšaft umírající matky Jednoty bratrské je odkaz národu a jazyku.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[6], "lit_unit7", "lit_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Který rys vystihuje baroko?", - {"Klidná vyváženost a tři jednoty", - "Kontrast, nadsázka a napětí těla a duše", - "Popis všedního dne bez obraznosti", - "Odmítání náboženství"}, - 4, 1}, - {"Kdo napsal Co Bůh? Člověk?", - {"Jan Amos Komenský", "Bedřich Bridel", - "Bohuslav Balbín", "Daniel Adam z Veleslavína"}, - 4, 1}, - {"O čem je Labyrint světa a ráj srdce?", - {"O alegorickém putování za smyslem života", - "O válce s mloky", - "O národním obrození", - "O životě Švejka"}, - 4, 0}, - {"Kam patří Komenského pedagogické spisy?", - {"K poetismu", "K baroku a počátkům moderní pedagogiky", - "K májovcům", "K existencialismu"}, - 4, 1}, - }; - static const char *hints[] = { - "Baroko pracuje s protikladem, světlem a stínem, tělem a věčností.", - "Bridel je autor básně Co Bůh? Člověk?, Komenský napsal Labyrint.", - "Poutník prochází marným světem a nalézá klid v srdci u Boha.", - "Informatorium a Orbis pictus jsou Komenského učební spisy.", - }; - - return lit_mcq_page(0, 6, "litunit7", "lit_ex7_title", "lit_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_lit_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Klasicismus", "Rozum a pravidlo", - "Tip: tři jednoty jsou jednota času, místa a děje.", - { - "Klasicismus 17. století navazuje na antiku a žádá kázeň, harmonii a pravidla.", - "Vyvrcholil ve Francii: Corneille, Racine a Molièrovy komedie.", - "Molièrův Lakomec a Tartuffe zesměšňují lidskou vadu jako typ.", - "La Fontaine převyprávěl bajky, Boileau sepsal pravidla básnictví.", - NULL, - }, - }, - { - "2 / 3 • Osvícenství", "Rozum má měnit společnost", - "Tip: Candide se vysmívá lehké víře, že žijeme v nejlepším z světů.", - { - "Osvícenství věří rozumu, vzdělání, toleranci a kritice předsudků.", - "Voltairův Candide a Swiftovy Gulliverovy cesty jsou satirické prózy.", - "Defoeův Robinson Crusoe oslavuje práci a praktický rozum.", - "Encyklopedisté včetně Diderota chtějí zpřístupnit vědění.", - NULL, - }, - }, - { - "3 / 3 • Cit", "Preromantismus a cesta k obrození", - "Tip: Werther otevírá literaturu citovému jednotlivci.", - { - "Preromantismus staví cit, přírodu a středověk proti chladnému rozumu.", - "Goethovo Utrpení mladého Werthera a Faust spojují cit i filozofii.", - "Schillerovy Loupežníci hájí svobodu proti útisku.", - "V Čechách na osvícenskou učenost naváže národní obrození.", - NULL, - }, - }, - }; - - return lit_unit_page(0, &lit_lessons[7], "lit_unit8", "lit_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co jsou tři jednoty klasicistního dramatu?", - {"Jednota času, místa a děje", - "Jednota autora, hrdiny a čtenáře", - "Jednota rýmu, stopy a sloky", - "Jednota lyriky, epiky a dramatu"}, - 4, 0}, - {"Kdo napsal Lakomce?", - {"William Shakespeare", "Molière", "Johann Wolfgang Goethe", "Voltaire"}, - 4, 1}, - {"Které dílo je osvícenská satira?", - {"Kytice", "Candide", "Máj", "Babička"}, - 4, 1}, - {"Čím preromantismus překonává klasicismus?", - {"Důrazem na cit, přírodu a individuální prožitek", - "Přísnějšími pravidly rýmu", - "Návratem výhradně k latině", - "Odmítnutím divadla"}, - 4, 0}, - }; - static const char *hints[] = { - "Klasicistní tragédie se má odehrát v jednom dni, na jednom místě a v jedné linii.", - "Molière je autorem Lakomce a Tartuffa.", - "Candide napsal Voltaire, Gulliverovy cesty Swift.", - "Werther a Schillerovi Loupežníci už staví cit proti pravidlu.", - }; - - return lit_mcq_page(0, 7, "litunit8", "lit_ex8_title", "lit_quiz8_head", - qs, hints, 4); -} - -void add_lit_pages(GtkStack *stack) { - typedef GtkWidget *(*LitBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - LitBuilder build_unit; - LitBuilder build_ex; - } pages[] = { - {"litunit1", "litex1", build_lit_unit1_page, build_lit_unit1_exercise_page}, - {"litunit2", "litex2", build_lit_unit2_page, build_lit_unit2_exercise_page}, - {"litunit3", "litex3", build_lit_unit3_page, build_lit_unit3_exercise_page}, - {"litunit4", "litex4", build_lit_unit4_page, build_lit_unit4_exercise_page}, - {"litunit5", "litex5", build_lit_unit5_page, build_lit_unit5_exercise_page}, - {"litunit6", "litex6", build_lit_unit6_page, build_lit_unit6_exercise_page}, - {"litunit7", "litex7", build_lit_unit7_page, build_lit_unit7_exercise_page}, - {"litunit8", "litex8", build_lit_unit8_page, build_lit_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/lit_year2.c b/src/lit_year2.c deleted file mode 100644 index af0f2b4..0000000 --- a/src/lit_year2.c +++ /dev/null @@ -1,611 +0,0 @@ -#include "graduately.h" - -/* Year 2: National Revival, Romanticism, Realism, the Máj generation, - * ruchovci and lumírovci, Czech realism, the modern movement. */ - -NetLesson lit2_lessons[LIT_N] = { - { .n_slides = 3, .unit_page = "lit2unit1", .ex_page = "lit2ex1" }, - { .n_slides = 3, .unit_page = "lit2unit2", .ex_page = "lit2ex2" }, - { .n_slides = 3, .unit_page = "lit2unit3", .ex_page = "lit2ex3" }, - { .n_slides = 3, .unit_page = "lit2unit4", .ex_page = "lit2ex4" }, - { .n_slides = 3, .unit_page = "lit2unit5", .ex_page = "lit2ex5" }, - { .n_slides = 3, .unit_page = "lit2unit6", .ex_page = "lit2ex6" }, - { .n_slides = 3, .unit_page = "lit2unit7", .ex_page = "lit2ex7" }, - { .n_slides = 3, .unit_page = "lit2unit8", .ex_page = "lit2ex8" }, -}; - -static GtkWidget *build_lit2_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Smysl", "Proč obrození vzniklo", - "Tip: obrození zachraňuje češtinu jako jazyk vzdělanosti a národa.", - { - "Na konci 18. století je čeština hlavně jazykem venkova a kuchyně.", - "Osvícenství a herderovská myšlenka národa dávají podnět k obraně jazyka.", - "Cíl je vrátit češtinu do vědy, školy, divadla a krásné literatury.", - "Obrození se obvykle dělí na fázi obrannou a ofenzivní.", - NULL, - }, - }, - { - "2 / 3 • Obrana", "Dobrovský a první generace", - "Tip: Dobrovský češtinu vědecky popisuje, ale o její budoucnosti pochybuje.", - { - "Josef Dobrovský píše Zevrubnou mluvnici a zkoumá staroslověnštinu.", - "Václav Thám a Kramerius vydávají české knihy a noviny pro lid.", - "Vzniká české divadlo, Bouda a snaha hrát v národním jazyce.", - "První fáze jazyk brání a popisuje, ještě ho plně nerozvíjí v umění.", - NULL, - }, - }, - { - "3 / 3 • Útok", "Jungmann, Kollár, Čelakovský", - "Tip: Rukopisy královédvorský a zelenohorský měly dodat národu starou epiku.", - { - "Josef Jungmann vytváří česko-německý slovník a překládá z evropských literatur.", - "František Palacký píše dějiny jako příběh národa.", - "Kollárova Slávy dcera a Čelakovského Ohlasy spojují slovanskou myšlenku s lidovou písní.", - "Rukopisy z let 1817 a 1818 literaturu na čas ovlivnily, později byly odhaleny jako padělky.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[0], "lit2_unit1", "lit2_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaký byl hlavní cíl národního obrození?", - {"Nahradit češtinu latinou", - "Obnovit češtinu jako jazyk kultury a národa", - "Zavést romantický román podle Francie", - "Zrušit divadlo"}, - 4, 1}, - {"Čím je Josef Dobrovský?", - {"Autorem Máje", "Jazykovědcem obranné fáze", - "Lumírovcem", "Autorem Bible kralické"}, - 4, 1}, - {"Kdo sestavil velký česko-německý slovník?", - {"Josef Jungmann", "Karel Hynek Mácha", - "Jan Neruda", "Jaroslav Vrchlický"}, - 4, 0}, - {"Co jsou Rukopisy královédvorský a zelenohorský?", - {"Díla Kosmy", "Padělky, které měly dokázat starobylost české epiky", - "Husitské kroniky", "Barokní kancionály"}, - 4, 1}, - }; - static const char *hints[] = { - "Obrození brání a potom rozvíjí národní jazyk.", - "Dobrovský patří k obranné fázi, Jungmann k ofenzivní.", - "Jungmannův slovník a překlady otevírají češtinu vysoké literatuře.", - "RKZ vznikly 1817 a 1818 a později byly rozpoznány jako podvrhy.", - }; - - return lit_mcq_page(1, 0, "lit2unit1", "lit2_ex1_title", "lit2_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_lit2_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Postoj", "Jedinec proti světu", - "Tip: romantik hledá v minulosti, přírodě a výjimečném hrdinovi to, co současnost nedává.", - { - "Romantismus staví cit, obraznost a svobodu jednotlivce proti pravidlům klasicismu.", - "Hrdina je výjimečný, často vyvržený, a střetává se se společností.", - "Oblíbené je středověk, lidová slovesnost, exotika a tajemno.", - "Rozpor mezi snem a skutečností je základní romantické napětí.", - NULL, - }, - }, - { - "2 / 3 • Evropa", "Byron, Hugo, Puškin", - "Tip: Byronův hrdina je unavený, hrdý a v rozporu se světem.", - { - "Anglie: Byron, Shelley, Scottovy historické romány a jezerní básníci.", - "Francie: Victor Hugo, Chrám Matky Boží v Paříži a Bídníci, předmluva ke Cromwellovi.", - "Německo: bratři Grimmové, Novalis a Heinrich Heine.", - "Rusko: Puškinův Evžen Oněgin a Lermontov. Polsko: Mickiewicz.", - NULL, - }, - }, - { - "3 / 3 • Amerika", "Poe a romantické tajemno", - "Tip: Poe stojí u hororu, detektivky i teorie básně.", - { - "Edgar Allan Poe píše Havrana, hrůzostrašné povídky a detektivní záhady.", - "Romantismus otevírá i gotický román a téma dvojnictví.", - "Historický román učí číst dějiny jako osud národa.", - "Tyto vzory silně působí na český romantismus v čele s Máchou.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[1], "lit2_unit2", "lit2_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je pro romantismus typické?", - {"Tři jednoty a rozumová kázeň", - "Cit, rozpor jedince se společností a zájem o minulost", - "Přesný popis všední práce", - "Odmítnutí obraznosti"}, - 4, 1}, - {"Kdo napsal Evžena Oněgina?", - {"Victor Hugo", "Alexandr Sergejevič Puškin", - "George Gordon Byron", "Edgar Allan Poe"}, - 4, 1}, - {"Které dílo patří Victoru Hugovi?", - {"Bídníci", "Lakomec", "Candide", "Král Oidipus"}, - 4, 0}, - {"Čím je Edgar Allan Poe?", - {"Autorem realistického románu o venkově", - "Romantikem hororu, tajemna a detektivní povídky", - "Klasicistním dramatikem", - "Autorem husitské kroniky"}, - 4, 1}, - }; - static const char *hints[] = { - "Romantický hrdina stojí proti obyčejnému světu.", - "Evžen Oněgin je veršovaný román Puškinův.", - "Hugo napsal Bídníky a Chrám Matky Boží v Paříži.", - "Havran a povídky tajemna jsou Poeova romantická tvorba.", - }; - - return lit_mcq_page(1, 1, "lit2unit2", "lit2_ex2_title", "lit2_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_lit2_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Máj", "Karel Hynek Mácha", - "Tip: Máj vyšel 1836 a doba mu vytýkala, že není dost vlastenecký.", - { - "Máj je lyrickoepická skladba o vině, času a rozporu snu se skutečností.", - "Vilém zabije svůdce milenky a neví, že zabil vlastního otce.", - "Příroda je krásná a lhostejná k lidskému utrpení.", - "Báseň je psána jambem a patří k vrcholům české poezie.", - NULL, - }, - }, - { - "2 / 3 • Balada", "Erben, Tyl a Němcová", - "Tip: v Kytici trestá osud vinu, často vinu rodičů na dětech.", - { - "Karel Jaromír Erben vydal 1853 Kytici, soubor balad z lidové víry.", - "Josef Kajetán Tyl píše Strakonického dudáka a hru Fidlovačka s písní Kde domov můj.", - "Božena Němcová v Babičce staví ideál lidskosti a venkovského řádu.", - "Její povídky, třeba Divá Bára, hájí právo ženy na vlastní cestu.", - NULL, - }, - }, - { - "3 / 3 • Satira", "Havlíček a vyvrcholení obrození", - "Tip: Havlíček už romantický patos ironizuje a měří ho politikou.", - { - "Karel Havlíček Borovský píše epigramy, Tyrolské elegie a Křest svatého Vladimíra.", - "Satira míří na absolutismus, církevní moc a národní pózu.", - "Třetí fáze obrození splývá s romantismem a politickým ruchem roku 1848.", - "Mácha, Erben, Tyl, Němcová a Havlíček jsou jádro českého romantismu.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[2], "lit2_unit3", "lit2_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy vyšel Máchův Máj?", - {"Roku 1836", "Roku 1853", "Roku 1858", "Roku 1895"}, - 4, 0}, - {"O čem jsou Erbenovy balady v Kytici?", - {"O budování továren", "O vině a trestu podle lidové víry", - "O legionářích", "O absurdním čekání"}, - 4, 1}, - {"Kde zazní píseň Kde domov můj?", - {"V Máji", "Ve Fidlovačce Josefa Kajetána Tyla", - "V Babičce", "V Labyrintu světa"}, - 4, 1}, - {"Které dílo napsal Karel Havlíček Borovský?", - {"Tyrolské elegie", "Povídky malostranské", - "Psohlavci", "R.U.R."}, - 4, 0}, - }; - static const char *hints[] = { - "Máj 1836, Kytice 1853, almanach Máj 1858.", - "Erbenova balada spojuje lidový příběh s mravním řádem.", - "Tylova Fidlovačka obsahuje píseň, z níž vznikla hymna.", - "Havlíček: epigramy, Tyrolské elegie, Křest svatého Vladimíra.", - }; - - return lit_mcq_page(1, 2, "lit2unit3", "lit2_ex3_title", "lit2_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_lit2_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Metoda", "Vidět společnost takovou, jaká je", - "Tip: realismus typizuje, naturalismus přidává dědičnost a prostředí.", - { - "Realismus popisuje současnost, společenské vrstvy a všední konflikty.", - "Postava je typ: nese rysy své doby, třídy a prostředí.", - "Vypravěč bývá střízlivý a dává prostor detailu.", - "Naturalismus jde dál: člověka určuje dědičnost, pudy a hmotné podmínky.", - NULL, - }, - }, - { - "2 / 3 • Francie a Anglie", "Od Balzaca k Zolovi", - "Tip: Paní Bovaryová ukazuje střet romantického snu s provincií.", - { - "Honoré de Balzac v Lidské komedii mapuje francouzskou společnost.", - "Stendhalův Červený a černý sleduje ctižádost v porevoluční Francii.", - "Flaubertova Paní Bovaryová je vrchol psychologického realismu.", - "Zola (Zabiják) je naturalista. Dickens (Oliver Twist) kritizuje bídu průmyslové Anglie.", - NULL, - }, - }, - { - "3 / 3 • Rusko", "Tolstoj, Dostojevskij, Čechov", - "Tip: Dostojevskij zkoumá vinu svědomí, Tolstoj široký obraz doby.", - { - "Nikolaj Gogol spojuje satiru a grotesku, Revizor je komedie o strachu z moci.", - "Lev Tolstoj píše Vojnu a mír a Annu Kareninu.", - "Fjodor Michajlovič Dostojevskij ve Zločinu a trestu řeší vinu a trest svědomí.", - "Anton Pavlovič Čechov zklidňuje drama i povídku do zdánlivě obyčejného života.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[3], "lit2_unit4", "lit2_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se realismus liší od romantismu?", - {"Hledá výjimečného hrdinu mimo společnost", - "Zobrazuje současnou společnost a typické postavy", - "Drží se tří jednot klasicismu", - "Píše jen duchovní legendy"}, - 4, 1}, - {"Kdo je autorem Paní Bovaryové?", - {"Émile Zola", "Gustave Flaubert", "Charles Dickens", "Lev Tolstoj"}, - 4, 1}, - {"Které dílo napsal Dostojevskij?", - {"Zločin a trest", "Oliver Twist", "Evžen Oněgin", "Bídníci"}, - 4, 0}, - {"Co zdůrazňuje naturalismus?", - {"Jen šťastný konec pohádky", - "Vliv dědičnosti, pudů a prostředí", - "Pravidla antické tragédie", - "Slovanskou vzájemnost"}, - 4, 1}, - }; - static const char *hints[] = { - "Realistický hrdina je typ své vrstvy a doby.", - "Flaubert napsal Paní Bovaryovou, Zola je naturalista.", - "Zločin a trest je román o vině Raskolnikova.", - "Zola chápe člověka jako určeného tělem a prostředím.", - }; - - return lit_mcq_page(1, 3, "lit2unit4", "lit2_ex4_title", "lit2_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_lit2_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Program", "Almanach Máj 1858", - "Tip: májovci chtějí literaturu světovou, pravdivou a současnou.", - { - "Mladá generace se hlásí k Máchovi a odmítá vlasteneckou frázi.", - "Almanach Máj žádá umění otevřené Evropě a skutečnému životu.", - "K okruhu patří Neruda, Hálek, Světlá a Pfleger.", - "Generace reaguje na Bachův absolutismus a politické zklamání.", - NULL, - }, - }, - { - "2 / 3 • Neruda", "Poezie, fejeton a Malá Strana", - "Tip: Povídky malostranské jsou galerie typů, ne idyla.", - { - "Jan Neruda píše Hřbitovní kvítí, Knihy veršů, Písně kosmické a Balady a romance.", - "Povídky malostranské zachycují pražskou čtvrť s ironií i soucitem.", - "Fejeton v Národních listech je Nerudova škola pohledu na den.", - "Balady a romance spojují legendu, lidový tón a moderní skepsi.", - NULL, - }, - }, - { - "3 / 3 • Vedle něj", "Hálek, Světlá, Arbes", - "Tip: Arbesovo romaneto je napínavý příběh s racionálním vysvětlením.", - { - "Vítězslav Hálek je lyrik májovců, autor Večerních písní.", - "Karolina Světlá píše Vesnický román a prosazuje ženskou vzdělanost.", - "Jakub Arbes vytváří romaneto, třeba Newtonův mozek.", - "Májovci otevírají cestu pozdějšímu realismu.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[4], "lit2_unit5", "lit2_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy vyšel almanach Máj?", - {"Roku 1836", "Roku 1858", "Roku 1868", "Roku 1895"}, - 4, 1}, - {"Kdo napsal Povídky malostranské?", - {"Jan Neruda", "Božena Němcová", "Alois Jirásek", "Karel Čapek"}, - 4, 0}, - {"Co je romaneto?", - {"Lidová balada", "Napínavý příběh s racionálním jádrem", - "Klasicistní tragédie", "Husitská píseň"}, - 4, 1}, - {"Jaký program měli májovci?", - {"Návrat výhradně k latině", - "Literatura světová, pravdivá a současná", - "Jen oslavné ódy na panovníka", - "Odmítnutí Máje"}, - 4, 1}, - }; - static const char *hints[] = { - "Almanach Máj je 1858, Máchův Máj je 1836, Ruch 1868.", - "Neruda v nich kreslí typy z Malé Strany.", - "Romaneto je žánr Jakuba Arbesa.", - "Májovci navazují na Máchu a chtějí umění bez fráze.", - }; - - return lit_mcq_page(1, 4, "lit2unit5", "lit2_ex5_title", "lit2_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_lit2_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Spor", "Dvě odpovědi na smysl literatury", - "Tip: ruchovci brání národní tradici, lumírovci otevírají okno do Evropy.", - { - "Po májovcích se generace rozchází v tom, čemu má literatura sloužit.", - "Ruchovci kolem almanachu Ruch 1868 zdůrazňují národ a domácí látky.", - "Lumírovci kolem časopisu Lumír chtějí světovost a dokonalou formu.", - "Spor není osobní hádka, ale dvě představy o úkolu českého umění.", - NULL, - }, - }, - { - "2 / 3 • Ruch", "Svatopluk Čech", - "Tip: Písně otroka jsou politická alegorie nesvobody.", - { - "Svatopluk Čech píše Písně otroka, Evropy a satiru o panu Broučkovi.", - "Eliška Krásnohorská hájí srozumitelnost a národní úkol poezie.", - "Ruchovci navazují na obrozenskou představu básníka jako mluvčího národa.", - "Forma bývá rétorická, téma často vlastenecké a slovanské.", - NULL, - }, - }, - { - "3 / 3 • Lumír", "Vrchlický, Sládek, Zeyer", - "Tip: Vrchlický přináší do češtiny formy i látky z celé Evropy.", - { - "Jaroslav Vrchlický je mimořádně plodný lyrik, epik i dramatik, autor Noci na Karlštejně.", - "Josef Václav Sládek píše intimní a venkovskou lyriku a překládá.", - "Julius Zeyer čerpá z mýtů a legend, Radúz a Mahulena je pohádkové drama.", - "Lumírovci připravují půdu pro českou modernu.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[5], "lit2_unit6", "lit2_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se lumírovci liší od ruchovců?", - {"Odmítají veškerou poezii", - "Kladou důraz na světovost a uměleckou formu", - "Píšou jen latinsky", - "Patří k baroku"}, - 4, 1}, - {"Kdo napsal Písně otroka?", - {"Svatopluk Čech", "Jaroslav Vrchlický", "Jan Neruda", "Karel Hynek Mácha"}, - 4, 0}, - {"Které drama napsal Vrchlický?", - {"Maryša", "Noc na Karlštejně", "Lakomec", "Audience"}, - 4, 1}, - {"Kam patří Julius Zeyer?", - {"K májovcům", "K lumírovcům", "K proletářské poezii", "K samizdatu"}, - 4, 1}, - }; - static const char *hints[] = { - "Lumír znamená otevření české literatury Evropě.", - "Svatopluk Čech je hlavní básník ruchovců.", - "Noc na Karlštejně je veršovaná komedie Vrchlického.", - "Zeyer, Vrchlický a Sládek tvoří jádro lumírovců.", - }; - - return lit_mcq_page(1, 5, "lit2unit6", "lit2_ex6_title", "lit2_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_lit2_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Venkov", "Realistická próza", - "Tip: venkovský realismus neidealizuje, ukazuje bídu, víru i krutost zvyku.", - { - "Český realismus se obrací k venkovu, městu i historii.", - "Karel Václav Rais v Kalibově zločinu sleduje chudobu a vinu.", - "Teréza Nováková a Ignát Herrmann přidávají region a město.", - "Postava je určena prostředím, majetkem a mravem obce.", - NULL, - }, - }, - { - "2 / 3 • Historie", "Jirásek a historická próza", - "Tip: Jirásek vykládá dějiny jako posilu národního vědomí.", - { - "Alois Jirásek píše Psohlavce, Temno, F. L. Věka a Staré pověsti české.", - "Zikmund Winter přidává kulturněhistorický detail městského života.", - "Historická próza navazuje na Palackého pojetí českých dějin.", - "Na jevišti ji doplňuje drama z venkova a z dějin.", - NULL, - }, - }, - { - "3 / 3 • Drama", "Maryša a naturalismus", - "Tip: Maryša je tragédie nevolené svatby a bezmoci ženy.", - { - "Alois a Vilém Mrštíkové napsali Maryšu, hru o vynuceném sňatku.", - "Gabriela Preissová v Gazdině robě otevírá ženský osud na vesnici.", - "Naturalismus u nás zastupuje Karel Matěj Čapek-Chod.", - "Konec století už připravuje modernu, symbol a individuální senzibilitu.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[6], "lit2_unit7", "lit2_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo napsal Kalibův zločin?", - {"Karel Václav Rais", "Alois Jirásek", "Jan Neruda", "Julius Zeyer"}, - 4, 0}, - {"Které dílo patří Aloisi Jiráskovi?", - {"Temno", "Máj", "Babička", "R.U.R."}, - 4, 0}, - {"O čem je Maryša?", - {"O kosmických písních", - "O vynuceném sňatku a tragédii venkovské ženy", - "O cestě do Itálie", - "O robotovi"}, - 4, 1}, - {"Kam patří historická próza Jiráska a Wintra?", - {"K českému realismu druhé poloviny 19. století", - "K antice", "K poetismu", "K literatuře po roce 1989"}, - 4, 0}, - }; - static const char *hints[] = { - "Rais je představitel venkovského realismu.", - "Temno, Psohlavci a Staré pověsti české jsou Jiráskovy.", - "Maryšu napsali bratři Mrštíkové.", - "Historický román tu slouží i národní paměti.", - }; - - return lit_mcq_page(1, 6, "lit2unit7", "lit2_ex7_title", "lit2_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_lit2_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Evropa", "Prokletí básníci a dekadence", - "Tip: Baudelairovy Květy zla otevírají moderní městskou obraznost.", - { - "Konec století hledá nový jazyk: symbol, náladu, smyslovost a skepsi.", - "Charles Baudelaire, Paul Verlaine a Arthur Rimbaud jsou prokletí básníci.", - "Oscar Wilde v Obrazu Doriana Graye spojuje krásu, morálku a rozklad.", - "Symbol nesděluje věc přímo, nýbrž ji naznačuje.", - NULL, - }, - }, - { - "2 / 3 • Čechy", "Česká moderna", - "Tip: Manifest české moderny vyšel roku 1895.", - { - "Manifest žádá individualitu, kritičnost a konec vlastenecké rutiny.", - "K modernistům patří Antonín Sova, Otokar Březina a Karel Hlaváček.", - "Jiří Karásek ze Lvovic reprezentuje dekadenci, Josef Svatopluk Machar skepsi a satiru.", - "Impresionismus v básni zachycuje prchavý dojem, symbolismus skrytý smysl.", - NULL, - }, - }, - { - "3 / 3 • Buřiči", "Generace anarchistů", - "Tip: buřiči spojují vzdor, erotiku a soucit se sociálním dnem.", - { - "Fráňa Šrámek píše Stříbrný vítr a drama Měsíc nad řekou.", - "Viktor Dyk je autorem Krysaře a vzdorné politické lyriky.", - "Petr Bezruč ve Slezských písních mluví hlasem utiskovaného regionu.", - "S modernou končí 19. století a otevírá se literatura století dvacátého.", - NULL, - }, - }, - }; - - return lit_unit_page(1, &lit2_lessons[7], "lit2_unit8", "lit2_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit2_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy vyšel Manifest české moderny?", - {"Roku 1858", "Roku 1895", "Roku 1918", "Roku 1948"}, - 4, 1}, - {"Kdo napsal Květy zla?", - {"Charles Baudelaire", "Oscar Wilde", "Antonín Sova", "Jan Neruda"}, - 4, 0}, - {"Které dílo napsal Viktor Dyk?", - {"Krysař", "Babička", "Maryša", "Edison"}, - 4, 0}, - {"Čím jsou Slezské písně Petra Bezruče?", - {"Oslavou pražského salonu", - "Hlasem sociálního a národního útisku ve Slezsku", - "Barokní legendou", - "Antickým eposem"}, - 4, 1}, - }; - static const char *hints[] = { - "1895 je programový rok české moderny.", - "Baudelaire je ústřední prokletý básník.", - "Krysař je Dykova novela o moci a pomstě.", - "Bezruč mluví za chudý a utlačovaný kraj.", - }; - - return lit_mcq_page(1, 7, "lit2unit8", "lit2_ex8_title", "lit2_quiz8_head", - qs, hints, 4); -} - -void add_lit2_pages(GtkStack *stack) { - typedef GtkWidget *(*LitBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - LitBuilder build_unit; - LitBuilder build_ex; - } pages[] = { - {"lit2unit1", "lit2ex1", build_lit2_unit1_page, build_lit2_unit1_exercise_page}, - {"lit2unit2", "lit2ex2", build_lit2_unit2_page, build_lit2_unit2_exercise_page}, - {"lit2unit3", "lit2ex3", build_lit2_unit3_page, build_lit2_unit3_exercise_page}, - {"lit2unit4", "lit2ex4", build_lit2_unit4_page, build_lit2_unit4_exercise_page}, - {"lit2unit5", "lit2ex5", build_lit2_unit5_page, build_lit2_unit5_exercise_page}, - {"lit2unit6", "lit2ex6", build_lit2_unit6_page, build_lit2_unit6_exercise_page}, - {"lit2unit7", "lit2ex7", build_lit2_unit7_page, build_lit2_unit7_exercise_page}, - {"lit2unit8", "lit2ex8", build_lit2_unit8_page, build_lit2_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/lit_year3.c b/src/lit_year3.c deleted file mode 100644 index bdd30dd..0000000 --- a/src/lit_year3.c +++ /dev/null @@ -1,616 +0,0 @@ -#include "graduately.h" - -/* Year 3: the first half of the 20th century, world and Czech. */ - -NetLesson lit3_lessons[LIT_N] = { - { .n_slides = 3, .unit_page = "lit3unit1", .ex_page = "lit3ex1" }, - { .n_slides = 3, .unit_page = "lit3unit2", .ex_page = "lit3ex2" }, - { .n_slides = 3, .unit_page = "lit3unit3", .ex_page = "lit3ex3" }, - { .n_slides = 3, .unit_page = "lit3unit4", .ex_page = "lit3ex4" }, - { .n_slides = 3, .unit_page = "lit3unit5", .ex_page = "lit3ex5" }, - { .n_slides = 3, .unit_page = "lit3unit6", .ex_page = "lit3ex6" }, - { .n_slides = 3, .unit_page = "lit3unit7", .ex_page = "lit3ex7" }, - { .n_slides = 3, .unit_page = "lit3unit8", .ex_page = "lit3ex8" }, -}; - -static GtkWidget *build_lit3_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Zlom", "Umění po roce 1900", - "Tip: avantgarda chce tvořit budoucnost, ne jen zdobit přítomnost.", - { - "Nové směry odmítají popisnou iluzi 19. století.", - "Futurismus oslavuje rychlost, stroj a rozchod s muzeem.", - "Expresionismus křičí vnitřní úzkost, dadaismus se vysmívá smyslu války.", - "Surrealismus, vedený Bretonem, čerpá ze snu a nevědomí.", - NULL, - }, - }, - { - "2 / 3 • Báseň", "Apollinaire a pásmo", - "Tip: Pásmo ruší pravidelnou sloku a skládá báseň z volných obrazů.", - { - "Guillaume Apollinaire píše Pásmo a dává jméno kubismu i novému lyrismu.", - "Báseň může být bez interpunkce, jako proud vjemů velkoměsta.", - "Vladimir Majakovskij spojuje futurismus s politickým gestem.", - "Volný verš a asociace se stávají běžným nástrojem moderny.", - NULL, - }, - }, - { - "3 / 3 • Smysl", "Proč avantgardu znát", - "Tip: český poetismus a surrealismus z těchto podnětů přímo vyrůstají.", - { - "Avantgarda je mezinárodní a časopisy i manifesty putují přes hranice.", - "Umění se chápe jako experiment, ne jako hotový vzor.", - "Válka 1914–1918 tyto směry radikalizuje.", - "Bez avantgardy nelze číst Nezvala, Seiferta ani evropskou poezii 20. století.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[0], "lit3_unit1", "lit3_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co chce avantgarda?", - {"Vrátit se k třem jednotám", - "Experimentovat a tvořit nové umění", - "Psát jen historické romány", - "Obnovit latinskou kroniku"}, - 4, 1}, - {"Kdo napsal Pásmo?", - {"Guillaume Apollinaire", "Franz Kafka", - "Ernest Hemingway", "Karel Čapek"}, - 4, 0}, - {"Odkud čerpá surrealismus?", - {"Z úředního jazyka", "Ze snu a nevědomí", - "Z antické jednoty času", "Z kramářské písně"}, - 4, 1}, - {"Který směr oslavuje rychlost a stroj?", - {"Klasicismus", "Futurismus", "Venkovský realismus", "Baroko"}, - 4, 1}, - }; - static const char *hints[] = { - "Avantgarda je programová moderna počátku 20. století.", - "Apollinairovo Pásmo je vzor moderní volné básně.", - "Bretonův surrealismus navazuje na Freudovo nevědomí.", - "Futurismus vyhlašuje Marinetti, v Rusku Majakovskij.", - }; - - return lit_mcq_page(2, 0, "lit3unit1", "lit3_ex1_title", "lit3_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_lit3_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Válka", "Ztracená generace a Remarque", - "Tip: ztracená generace jsou autoři, které první válka připravila o iluze.", - { - "Ernest Hemingway píše Sbohem, armádo a později Stařec a moře.", - "Francis Scott Fitzgerald zachycuje Velkého Gatsbyho a lesk i prázdnotu úspěchu.", - "Erich Maria Remarque v románu Na západní frontě klid ukazuje zákop očima vojáka.", - "John Steinbeck přidává sociální prózu, třeba O myších a lidech.", - NULL, - }, - }, - { - "2 / 3 • Experiment", "Kafka, Joyce, Proust", - "Tip: Proměna začíná tím, že se člověk probudí jako hmyz, a nikdo se nad tím nepozastaví dost.", - { - "Franz Kafka v Proměně a Procesu zobrazuje úzkost a nepřehlednou moc.", - "James Joyce v Odysseovi rozbíjí tradiční vyprávění proudem vědomí.", - "Marcel Proust staví román na paměti a čase.", - "Moderní próza už nespoléhá na vševědoucího vypravěče a lineární děj.", - NULL, - }, - }, - { - "3 / 3 • Varování", "Antiutopie a svědomí", - "Tip: antiutopie ukazuje společnost, která štěstí vynucuje a svobodu ruší.", - { - "Aldous Huxley v Konci civilizace líčí svět řízený technikou a konzumem.", - "Thomas Mann v Kouzelném vrchu spojuje nemoc, čas a evropskou krizi.", - "Michail Bulgakov v Mistrovi a Markétce hájí umění proti násilné moci.", - "Tyto prózy připravují poválečné antiutopie Orwella a Bradburyho.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[1], "lit3_unit2", "lit3_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo patří ke ztracené generaci?", - {"Homér", "Ernest Hemingway", "Dante Alighieri", "Molière"}, - 4, 1}, - {"Které dílo napsal Franz Kafka?", - {"Proměna", "Babička", "Evžen Oněgin", "Maryša"}, - 4, 0}, - {"O čem je Remarquův román Na západní frontě klid?", - {"O salonu 18. století", - "O zážitku vojáka v první světové válce", - "O husitském zpěvu", - "O národním obrození"}, - 4, 1}, - {"Co je proud vědomí?", - {"Lidová balada", - "Záznam vnitřní řeči a vjemů bez tradičního děje", - "Klasicistní prolog", - "Barokní kázání"}, - 4, 1}, - }; - static const char *hints[] = { - "Hemingway, Fitzgerald a další píšou po první válce o ztrátě jistot.", - "Proměna a Proces jsou Kafkovy klíčové prózy.", - "Remarque bourá představu války jako hrdinského dobrodružství.", - "Proud vědomí užívá Joyce a další modernisté.", - }; - - return lit_mcq_page(2, 1, "lit3unit2", "lit3_ex2_title", "lit3_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_lit3_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Jeviště", "Drama se rozchází s iluzí", - "Tip: epické divadlo Brechtovo chce, aby divák přemýšlel, ne jen prožíval.", - { - "Moderní drama opouští měšťanskou konverzaci jako jediný vzor.", - "George Bernard Shaw spojuje komedii s myšlenkou a kritikou.", - "Luigi Pirandello tematizuje, že člověk hraje role a pravda se tříští.", - "Expresionistické drama křičí úzkost rozbitého světa.", - NULL, - }, - }, - { - "2 / 3 • Brecht", "Epické divadlo", - "Tip: zcizovací efekt brání divákovi, aby se v postavě jen rozplynul.", - { - "Bertolt Brecht píše Matku Kuráž a Kavkazský křídový kruh.", - "Písně, komentář a přerušení děje nutí zaujmout postoj.", - "Divadlo má být politické a rozumové, ne jen dojemné.", - "Brecht silně ovlivnil české divadlo druhé poloviny století.", - NULL, - }, - }, - { - "3 / 3 • Amerika", "O'Neill a počátek absurdity", - "Tip: absurdní drama v plné podobě přijde až po druhé válce.", - { - "Eugene O'Neill přináší do Ameriky psychologické a tragické drama.", - "Meziválečné jeviště zkouší masku, sbor i sen.", - "Po roce 1945 na to naváže Beckett a Ionesco.", - "Na maturitu patří Shaw, Pirandello a Brecht jako tři různé moderní cesty.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[2], "lit3_unit3", "lit3_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je epické divadlo?", - {"Divadlo, které chce diváka dojmout až k slzám a nic víc", - "Brechtovo divadlo, které nutí přemýšlet a zaujímat postoj", - "Středověký mysterijní cyklus", - "Opera bez textu"}, - 4, 1}, - {"Kdo napsal Matku Kuráž?", - {"Bertolt Brecht", "William Shakespeare", - "Molière", "Václav Havel"}, - 4, 0}, - {"Čím se Pirandello zabývá?", - {"Husitskou písní", "Tím, že člověk hraje role a skutečnost se tříští", - "Venkovským realismem", "Eposem o Gilgamešovi"}, - 4, 1}, - {"Kdy se plně rozvine absurdní drama?", - {"V antice", "Až po druhé světové válce", - "V národním obrození", "Ve 14. století"}, - 4, 1}, - }; - static const char *hints[] = { - "Zcizovací efekt je hlavní nástroj Brechtova epického divadla.", - "Matka Kuráž je brechtovská hra o válce a obchodu.", - "Pirandello patří k moderně, která pochybuje o jedné pravdě postavy.", - "Beckettovo Čekání na Godota je 1952, tedy po válce.", - }; - - return lit_mcq_page(2, 2, "lit3unit3", "lit3_ex3_title", "lit3_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_lit3_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Švejk", "Jaroslav Hašek", - "Tip: Švejk není jen vtip, je to obrana malého člověka proti mašinerii.", - { - "Osudy dobrého vojáka Švejka za světové války vyšly 1921–1923.", - "Hašek zesměšňuje rakouskou armádu, úřad a velkou frázi.", - "Švejk poslouchá tak doslova, až rozkaz ztrácí smysl.", - "Román zůstal nedokončený a přesto se stal světovým.", - NULL, - }, - }, - { - "2 / 3 • Legie", "Válka a legionářská próza", - "Tip: legionářská literatura vypráví anabázi československých legií.", - { - "Rudolf Medek a Josef Kopta píšou o legiích v Rusku.", - "Válka vstupuje i do Vančurova Pole orná a válečná.", - "Proti hrdinské legendě stojí Haškova groteska.", - "Oba póly, patos i výsměch, patří k české paměti první války.", - NULL, - }, - }, - { - "3 / 3 • Poezie", "Wolker a proletářská poezie", - "Tip: Wolker chce, aby báseň sloužila chudým a byla srozumitelná.", - { - "Jiří Wolker vydává Host do domu a Těžkou hodinu.", - "Balady, třeba Balada o nenarozeném dítěti, spojují sociální téma s lidovým tónem.", - "Proletářská poezie věří kolektivu a změně světa.", - "Devětsil, založený 1920, z ní brzy přejde k poetismu.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[3], "lit3_unit4", "lit3_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo napsal Osudy dobrého vojáka Švejka?", - {"Jaroslav Hašek", "Karel Čapek", "Jiří Wolker", "Viktor Dyk"}, - 4, 0}, - {"Jak Švejk vzdoruje armádě?", - {"Hrdinským útokem v čele legií", - "Doslovnou poslušností, která rozkaz zesměšní", - "Útěkem do exilu po roce 1968", - "Psaním manifestu moderny"}, - 4, 1}, - {"Které sbírky napsal Jiří Wolker?", - {"Host do domu a Těžká hodina", "Kytice a Máj", - "Květy zla a Havran", "Edison a Pásmo"}, - 4, 0}, - {"Co je Devětsil?", - {"Barokní řád", "Umělecký svaz založený roku 1920", - "Husitská píseň", "Nakladatelství exilu v Torontu"}, - 4, 1}, - }; - static const char *hints[] = { - "Švejk je Haškův nedokončený román z první války.", - "Groteskní poslušnost je Švejkova zbraň.", - "Wolker je hlavní básník proletářské poezie.", - "Z Devětsilu vyroste poetismus.", - }; - - return lit_mcq_page(2, 3, "lit3unit4", "lit3_ex4_title", "lit3_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_lit3_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Poetismus", "Radost, město a asociace", - "Tip: poetismus je český směr, teoretikem je Karel Teige.", - { - "Poetismus chce báseň jako hru obrazů, cestu a oslavu moderního života.", - "Vítězslav Nezval píše Podivuhodného kouzelníka a Edison.", - "Jaroslav Seifert debutuje Na vlnách TSF a zůstane u konkrétního, smyslového verše.", - "Konstantin Biebl přidává exotiku a později smutek.", - NULL, - }, - }, - { - "2 / 3 • Surrealismus", "Sen a úzkost", - "Tip: Nezvalův Absolutní hrobař už není radostný poetismus.", - { - "Ve 30. letech část poetistů přechází k surrealismu.", - "Skupina surrealistů v ČSR vzniká 1934 kolem Nezvala.", - "Obraz se stává snovějším a úzkostnějším.", - "Vedle toho roste meditativní poezie, která avantgardu přijímá jen zčásti.", - NULL, - }, - }, - { - "3 / 3 • Jiný hlas", "Halas, Holan, Zahradníček", - "Tip: Halasova Torzo naděje je odpověď na Mnichov, ne na karneval města.", - { - "František Halas píše temnou, zhuštěnou lyriku a Torzo naděje.", - "Vladimír Holan je básník meditace a později svědectví.", - "Jan Zahradníček představuje spirituální a katolickou poezii.", - "Meziválečná poezie tedy není jen Devětsil: má i pól víry a úzkosti.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[4], "lit3_unit5", "lit3_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je teoretikem poetismu?", - {"Karel Teige", "Josef Dobrovský", "Jan Hus", "Bertolt Brecht"}, - 4, 0}, - {"Kterou skladbu napsal Vítězslav Nezval?", - {"Edison", "Máj", "Kytice", "Babička"}, - 4, 0}, - {"Kdy vznikla Skupina surrealistů v ČSR?", - {"Roku 1858", "Roku 1934", "Roku 863", "Roku 1989"}, - 4, 1}, - {"Čím je Halasovo Torzo naděje?", - {"Poetistickou oslavou velkoměsta", - "Básnickou odpovědí na ohrožení republiky", - "Legionářským románem", - "Klasicistní komedií"}, - 4, 1}, - }; - static const char *hints[] = { - "Teige formuluje poetismus jako umění života.", - "Edison je Nezvalova pásmová báseň o vynálezci a noci.", - "1934 je rok českého surrealistického seskupení.", - "Torzo naděje reaguje na krizi konce 30. let.", - }; - - return lit_mcq_page(2, 4, "lit3unit5", "lit3_ex5_title", "lit3_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_lit3_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Čapek", "Demokratický proud", - "Tip: Čapek brání obyčejného člověka a varuje před mocí, která se vymkne.", - { - "Karel Čapek píše R.U.R., kde zazní slovo robot, Krakatit a Válku s mloky.", - "Bílá nemoc a Matka jsou dramata o válce a odpovědnosti.", - "Hordubal, Povětroň a Obyčejný život jsou noetická trilogie: pravda není jedna.", - "Povídky z jedné a druhé kapsy a fejetony drží lidský rozměr.", - NULL, - }, - }, - { - "2 / 3 • Vančura", "Jazyk jako událost", - "Tip: Vančura píše obrazně a vědomě proti všednímu novinovému stylu.", - { - "Vladislav Vančura je autorem Rozmarného léta a Markéty Lazarové.", - "Jeho věta je rytmická, metaforická a často archaicky zbarvená.", - "Patří k levicové avantgardě, ale není schematický.", - "Vedle něj stojí reportážní a novinářská próza meziválečné demokracie.", - NULL, - }, - }, - { - "3 / 3 • Smích", "Poláček, Olbracht a další", - "Tip: Bylo nás pět je dětská perspektiva, která odhaluje svět dospělých.", - { - "Karel Poláček píše Bylo nás pět a Muže v offsidu.", - "Ivan Olbracht: Nikola Šuhaj loupežník a Golet v údolí.", - "Eduard Bass a Karel Poláček představují humoristickou a novinářskou linii.", - "Demokratický proud věří republice, rozumu a občanské slušnosti.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[5], "lit3_unit6", "lit3_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Ve kterém díle zazní slovo robot?", - {"V R.U.R. Karla Čapka", "V Máji", "V Kytici", "V Švejkovi"}, - 4, 0}, - {"Kdo napsal Rozmarné léto?", - {"Vladislav Vančura", "Jaroslav Hašek", "Božena Němcová", "Alois Jirásek"}, - 4, 0}, - {"Kterou knihu napsal Karel Poláček?", - {"Bylo nás pět", "Temno", "Labyrint světa", "Krysař"}, - 4, 0}, - {"O čem varuje Válka s mloky?", - {"O nebezpečí moci, která využije lidskou chtivost", - "O pravidlech sonetu", - "O příchodu věrozvěstů", - "O barokním emblému"}, - 4, 0}, - }; - static const char *hints[] = { - "Slovo robot vymyslel Josef Čapek, svět je zná z dramatu R.U.R.", - "Rozmarné léto a Markéta Lazarová jsou Vančurovy prózy.", - "Poláček je autor Bylo nás pět a Mužů v offsidu.", - "Mloci jsou podobenství o civilizaci, která si vypěstuje zhoubu.", - }; - - return lit_mcq_page(2, 5, "lit3unit6", "lit3_ex6_title", "lit3_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_lit3_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Duše", "Psychologická próza", - "Tip: psychologická próza sleduje vnitřní motiv, ne jen vnější děj.", - { - "Jaroslav Havlíček píše Petrolejové lampy a Neviditelného.", - "Jarmila Glazarová v Adventu zobrazuje krutost a závislost na vesnici.", - "Egon Hostovský a Václav Řezáč přidávají úzkost a mravní selhání.", - "Člověk tu není typ vrstvy, ale spleť nutkání a vin.", - NULL, - }, - }, - { - "2 / 3 • Víra", "Katolický proud", - "Tip: katolická literatura není jen pobožnost, je to svébytný umělecký názor.", - { - "Jaroslav Durych píše historický román Bloudění.", - "Jakub Deml tvoří deníkovou a spirituální prózu.", - "Jan Čep a Jan Zahradníček drží venkov a víru jako řád.", - "Proud stojí vedle avantgardy a často s ní polemizuje.", - NULL, - }, - }, - { - "3 / 3 • Venkov", "Ruralismus", - "Tip: ruralismus idealizuje venkov jako zdroj řádu proti městu.", - { - "Ruralisté, třeba Josef Knap a František Křelina, brání selskou tradici.", - "Liší se od kritického realismu, který vesnici nešetřil.", - "Ve 30. letech je to vlivný, dnes diskutovaný proud.", - "Maturita má umět tyto proudy rozlišit, ne je slepit v jednu meziválečnou prózu.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[6], "lit3_unit7", "lit3_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo napsal Petrolejové lampy?", - {"Jaroslav Havlíček", "Karel Čapek", "Ivan Olbracht", "Jiří Wolker"}, - 4, 0}, - {"Kam patří Jaroslav Durych?", - {"Ke katolickému proudu", "K poetismu", - "Ke ztracené generaci", "K ruchovcům"}, - 4, 0}, - {"Co zdůrazňuje ruralismus?", - {"Velkoměstský kaleidoskop", - "Venkov a selský řád", - "Antickou tragédii", - "Absenci děje"}, - 4, 1}, - {"Čím se psychologická próza zabývá především?", - {"Vnitřním motivem a vinou postavy", - "Překladem antických eposů", - "Pravidly klasicistního verše", - "Kronikou Velké Moravy"}, - 4, 0}, - }; - static const char *hints[] = { - "Havlíček je autor Petrolejových lamp a Neviditelného.", - "Durychovo Bloudění je historický román katolického proudu.", - "Ruralismus staví vesnici proti rozkladnému městu.", - "Děj je tu hlavně cesta do nitra.", - }; - - return lit_mcq_page(2, 6, "lit3unit7", "lit3_ex7_title", "lit3_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_lit3_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Okupace", "Literatura za protektorátu", - "Tip: po roce 1939 mizí svobodný tisk a řada autorů píše do šuplíku nebo umírá.", - { - "Německá okupace zavírá českou kulturu do cenzury a perzekuce.", - "Mladí básníci kolem Jiřího Ortena píšou elegii a deník ohroženého života.", - "Ortenovy sbírky, třeba Ohnice, vycházejí pod cizím jménem.", - "Halas, Holan a Seifert reagují na válku zhuštěným veršem.", - NULL, - }, - }, - { - "2 / 3 • Skupina", "Skupina 42", - "Tip: Skupina 42 bere město, periferii a civilní řeč, ne snový symbol.", - { - "Skupina 42 vzniká za války a programově se dívá na civilizaci města.", - "Patří k ní Josef Kainar, Jiří Kolář, Ivan Blatný a teoretik Jindřich Chalupecký.", - "Báseň i próza zaznamenávají banalitu, která je pod tlakem dějin přízračná.", - "Skupina působí i po válce, než ji politický režim umlčí.", - NULL, - }, - }, - { - "3 / 3 • Svědectví", "Co se o válce píše hned a co později", - "Tip: velké prózy o šoa často vzniknou až po roce 1945.", - { - "Za války vzniká poezie, deník a ilegální text, ne velký románový odstup.", - "Julius Fučík píše Reportáž psanou na oprátce ve vězení.", - "Lustig, Fuks, Hrabal nebo Otčenášek válku zpracují až v dalších desetiletích.", - "Na maturitu oddělte dobu vzniku od doby, o které dílo vypráví.", - NULL, - }, - }, - }; - - return lit_unit_page(2, &lit3_lessons[7], "lit3_unit8", "lit3_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit3_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je básník Ohnice?", - {"Jiří Orten", "Jaroslav Seifert", "Vítězslav Nezval", "Petr Bezruč"}, - 4, 0}, - {"Čím se vyznačuje Skupina 42?", - {"Návratem ke klasicistní tragédii", - "Civilním pohledem na město a periferii", - "Venkovským ruralismem", - "Psaním jen v latině"}, - 4, 1}, - {"Kdo patří ke Skupině 42?", - {"Josef Kainar a Jiří Kolář", "Karel Hynek Mácha a Karel Jaromír Erben", - "Homér a Vergilius", "Jungmann a Dobrovský"}, - 4, 0}, - {"Proč velké romány o válce často nejsou z let okupace?", - {"Protože za cenzury a bez odstupu vznikala spíš poezie, deník a svědectví", - "Protože se o válce nesmělo psát ani po roce 1945", - "Protože próza vznikla až ve středověku", - "Protože autoři neznali téma města"}, - 4, 0}, - }; - static const char *hints[] = { - "Orten publikoval za okupace pod pseudonymem a zahynul roku 1941.", - "Program Skupiny 42 formuluje civilizační a městský pohled.", - "Kainar, Kolář a Blatný jsou její básníci.", - "Lustig, Fuks a další válečné prózy jsou poválečné.", - }; - - return lit_mcq_page(2, 7, "lit3unit8", "lit3_ex8_title", "lit3_quiz8_head", - qs, hints, 4); -} - -void add_lit3_pages(GtkStack *stack) { - typedef GtkWidget *(*LitBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - LitBuilder build_unit; - LitBuilder build_ex; - } pages[] = { - {"lit3unit1", "lit3ex1", build_lit3_unit1_page, build_lit3_unit1_exercise_page}, - {"lit3unit2", "lit3ex2", build_lit3_unit2_page, build_lit3_unit2_exercise_page}, - {"lit3unit3", "lit3ex3", build_lit3_unit3_page, build_lit3_unit3_exercise_page}, - {"lit3unit4", "lit3ex4", build_lit3_unit4_page, build_lit3_unit4_exercise_page}, - {"lit3unit5", "lit3ex5", build_lit3_unit5_page, build_lit3_unit5_exercise_page}, - {"lit3unit6", "lit3ex6", build_lit3_unit6_page, build_lit3_unit6_exercise_page}, - {"lit3unit7", "lit3ex7", build_lit3_unit7_page, build_lit3_unit7_exercise_page}, - {"lit3unit8", "lit3ex8", build_lit3_unit8_page, build_lit3_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/lit_year4.c b/src/lit_year4.c deleted file mode 100644 index ac167da..0000000 --- a/src/lit_year4.c +++ /dev/null @@ -1,631 +0,0 @@ -#include "graduately.h" - -/* Year 4: literature after 1945, Czech writing under censorship and after - * 1989, and how to interpret a text at the school-leaving exam. */ - -NetLesson lit4_lessons[LIT_N] = { - { .n_slides = 3, .unit_page = "lit4unit1", .ex_page = "lit4ex1" }, - { .n_slides = 3, .unit_page = "lit4unit2", .ex_page = "lit4ex2" }, - { .n_slides = 3, .unit_page = "lit4unit3", .ex_page = "lit4ex3" }, - { .n_slides = 3, .unit_page = "lit4unit4", .ex_page = "lit4ex4" }, - { .n_slides = 3, .unit_page = "lit4unit5", .ex_page = "lit4ex5" }, - { .n_slides = 3, .unit_page = "lit4unit6", .ex_page = "lit4ex6" }, - { .n_slides = 3, .unit_page = "lit4unit7", .ex_page = "lit4ex7" }, - { .n_slides = 3, .unit_page = "lit4unit8", .ex_page = "lit4ex8" }, -}; - -static GtkWidget *build_lit4_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Po válce", "Svět, který už nevěří velkým frázím", - "Tip: antiutopie varuje před státem, který ovládne pravdu i soukromí.", - { - "Druhá světová válka a totalitní režimy mění téma viny, moci a paměti.", - "George Orwell píše Farmu zvířat a román 1984.", - "Ray Bradbury v 451 stupních Fahrenheita brání knihu proti cenzuře.", - "William Golding v Pánu much ukazuje, jak rychle se zboří civilizovaný řád.", - NULL, - }, - }, - { - "2 / 3 • Hlasy", "Existencialismus, beatnici a magický realismus", - "Tip: existencialismus říká, že člověk je svoboda a musí volit bez hotové opory.", - { - "Albert Camus píše Cizince a Mor, Jean-Paul Sartre Nevolnost.", - "Jack Kerouac v románu Na cestě dává hlas beat generation.", - "Gabriel García Márquez ve Sto rocích samoty mísí skutečnost a zázrak.", - "Jorge Luis Borges staví povídku jako filozofickou hru s nekonečnem.", - NULL, - }, - }, - { - "3 / 3 • Východ", "Svědectví o nesvobodě", - "Tip: Solženicyn a Bulgakov se čtou jako literatura i jako svědectví.", - { - "Alexandr Solženicyn v Jednom dni Ivana Děnisoviče otevírá téma lágru.", - "Michail Bulgakov hájí v Mistrovi a Markétce umění proti strachu.", - "Joseph Heller v Hlavě XXII zesměšňuje válečnou byrokracii.", - "Poválečná próza tedy není jeden styl, ale několik odpovědí na stejné století.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[0], "lit4_unit1", "lit4_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo napsal román 1984?", - {"George Orwell", "Ray Bradbury", "Albert Camus", "Umberto Eco"}, - 4, 0}, - {"O čem je 451 stupňů Fahrenheita?", - {"O cenzuře a pálení knih", "O národním obrození", - "O antickém osudu", "O husitské písni"}, - 4, 0}, - {"Který román patří Gabrielu Garcíovi Márquezovi?", - {"Sto roků samoty", "Babička", "Evžen Oněgin", "R.U.R."}, - 4, 0}, - {"Co je existencialismus v próze Camuse a Sartra?", - {"Víra, že osud je předem dán bohy", - "Důraz na svobodu volby, absurditu a odpovědnost", - "Návrat ke třem jednotám", - "Popis venkova bez psychologie"}, - 4, 1}, - }; - static const char *hints[] = { - "Orwell: Farma zvířat a 1984. Bradbury: 451 stupňů Fahrenheita.", - "Hasiči u Bradburyho knihy pálí, lidé je zachraňují tím, že je umějí zpaměti.", - "Sto roků samoty je základní román magického realismu.", - "Cizinec a Mor jsou Camusovy, Nevolnost Sartrova.", - }; - - return lit_mcq_page(3, 0, "lit4unit1", "lit4_ex1_title", "lit4_quiz1_head", - qs, hints, 4); -} - -static GtkWidget *build_lit4_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Absurdita", "Čekání, které nekončí", - "Tip: v absurdním dramatu se děj neuzavře, protože svět sám nedává smysl.", - { - "Samuel Beckett v Čekání na Godota nechává dva tuláky čekat na někoho, kdo nepřijde.", - "Eugene Ionesco v Plešaté zpěvačce rozkládá obyčejnou řeč.", - "Postavy jednají, ale jejich jednání cíl nenaplní.", - "Smích a hrůza tu nejsou oddělené.", - NULL, - }, - }, - { - "2 / 3 • Myšlenka", "Sartre, Dürrenmatt a podobenství", - "Tip: Návštěva staré dámy je podobenství o tom, zač je město ochotné prodat spravedlnost.", - { - "Sartrovy Mouchy a S vyloučením veřejnosti jsou existencialistická dramata.", - "Friedrich Dürrenmatt píše Návštěvu staré dámy a Fyziky.", - "Podobenství dovoluje mluvit o vině, aniž hra kopíruje noviny.", - "Divadlo po roce 1945 často soudí diváka spolu s postavou.", - NULL, - }, - }, - { - "3 / 3 • Postmoderna", "Hra s tím, co už bylo napsáno", - "Tip: postmoderna cituje starší texty a nedůvěřuje jedinému velkému výkladu.", - { - "Umberto Eco v Jménu růže spojuje detektivku, středověk a učenou hru.", - "Intertextualita znamená, že dílo vědomě navazuje na jiná díla.", - "Vypravěč může být nespolehlivý a závěr otevřený.", - "Na maturitě postmoderu poznáte podle ironie, citace a pochybnosti o jedné pravdě.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[1], "lit4_unit2", "lit4_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo napsal Čekání na Godota?", - {"Samuel Beckett", "Molière", "William Shakespeare", "Karel Čapek"}, - 4, 0}, - {"Co je typické pro absurdní drama?", - {"Jasný hrdinský konec", - "Jednání, které nevede k smysluplnému završení", - "Dodržení tří jednot", - "Jen historický námět z antiky"}, - 4, 1}, - {"Kdo napsal Návštěvu staré dámy?", - {"Friedrich Dürrenmatt", "Bertolt Brecht", - "Václav Havel", "Victor Hugo"}, - 4, 0}, - {"Čím se vyznačuje Jméno růže?", - {"Je to barokní kázání", - "Postmoderní román, který spojuje detektivku a středověk", - "Proletářská balada", - "Klasicistní tragédie"}, - 4, 1}, - }; - static const char *hints[] = { - "Beckettovo Čekání na Godota je základní absurdní drama.", - "Godot nepřijde a čekání se opakuje.", - "Dürrenmattova hra zkoumá, za co obec prodá svědomí.", - "Eco pracuje s citací, ironií a učenou hrou.", - }; - - return lit_mcq_page(3, 1, "lit4unit2", "lit4_ex2_title", "lit4_quiz2_head", - qs, hints, 4); -} - -static GtkWidget *build_lit4_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • 1945–1948", "Krátká svoboda", - "Tip: mezi květnem 1945 a únorem 1948 ještě vedle sebe žijí různé směry.", - { - "Po válce se vracejí zakázaní autoři a vycházejí odložené rukopisy.", - "Skupina 42 ještě působí, katolická literatura má poslední veřejný prostor.", - "Zároveň sílí požadavek, aby umění sloužilo nové moci.", - "Únor 1948 tento spor rozhodne politicky.", - NULL, - }, - }, - { - "2 / 3 • Schematismus", "Budovatelský román", - "Tip: schematická postava nemá pochybnost, protože dějiny už mají vyhráno.", - { - "Na počátku 50. let vládne socialistický realismus a budovatelský román.", - "Hrdina je dělník nebo funkcionář, konflikt je mezi pokrokem a zpátečníkem.", - "Jazyk je průhledný, závěr optimistický, kritika režimu nemožná.", - "Mnoho autorů starších generací mlčí, překládá, nebo píše do zásuvky.", - NULL, - }, - }, - { - "3 / 3 • 1956", "První trhlina", - "Tip: rok 1956 je kritika kultu osobnosti a počátek opatrného uvolnění.", - { - "II. sjezd spisovatelů a světové události narušují jistotu schématu.", - "Časopis Květen a poezie všedního dne vracejí do verše obyčejný život.", - "Ještě to není svoboda 60. let, ale konec nejtvrdšího schématu.", - "Na maturitu odlište budovatelský román od literatury, která přišla po něm.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[2], "lit4_unit3", "lit4_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co se v české literatuře děje po únoru 1948?", - {"Návrat ke klasicismu", - "Nástup socialistického realismu a budovatelského románu", - "Vznik poetismu", - "Konec cenzury"}, - 4, 1}, - {"Čím je schematická postava?", - {"Má jednoznačnou politickou roli a nepochybuje", - "Je romantický vyvrženec", - "Je vypravěč v ich-formě antického eposu", - "Je autor Bible kralické"}, - 4, 0}, - {"Co znamená rok 1956 pro českou literaturu?", - {"Založení Devětsilu", - "Kritiku kultu osobnosti a první uvolnění schématu", - "Příchod Konstantina a Metoděje", - "Vydání Máje"}, - 4, 1}, - {"Kdy končí krátké poválečné období otevřenější kultury?", - {"Únorem 1948", "Manifestem české moderny", - "Almanachem Máj", "Rokem 863"}, - 4, 0}, - }; - static const char *hints[] = { - "Budovatelský román je oficiální žánr počátku 50. let.", - "Schéma dělí postavy na kladné a záporné podle vztahu k režimu.", - "1956 oslabuje kult osobnosti, svoboda 60. let přijde později.", - "Únor 1948 je politický zlom, po němž mizí nezávislé proudy z veřejné scény.", - }; - - return lit_mcq_page(3, 2, "lit4unit3", "lit4_ex3_title", "lit4_quiz3_head", - qs, hints, 4); -} - -static GtkWidget *build_lit4_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Uvolnění", "Léta, kdy se smělo víc", - "Tip: 60. léta nejsou bez cenzury, ale cenzura polevila a experiment se vrátil.", - { - "Literatura znovu zkouší formu, ironii a tabuizovaná témata.", - "Válka, stalinismus i soukromí se dají pojmenovat otevřeněji.", - "Vrcholí to Pražským jarem 1968 a končí srpnovou okupací.", - "Mnoho knih, které tehdy vznikly, později vyjde jen v samizdatu nebo v exilu.", - NULL, - }, - }, - { - "2 / 3 • Próza", "Hrabal, Kundera, Škvorecký", - "Tip: pábitel je Hrabalův vypravěč, který skutečnost přetaví v proud řeči.", - { - "Bohumil Hrabal píše Pábitelé, Ostře sledované vlaky a Taneční hodiny.", - "Milan Kundera vydává Směšné lásky a Žert.", - "Josef Škvorecký v Zbabělcích vypráví konec války očima mladíka.", - "Arnošt Lustig a Ladislav Fuks vracejí téma šoa: Modlitba pro Kateřinu Horovitzovou, Spalovač mrtvol.", - NULL, - }, - }, - { - "3 / 3 • Kritika", "Vaculík, Páral a meze svobody", - "Tip: Žert ukazuje, jak jedna věta a jeden režim zničí život.", - { - "Ludvík Vaculík píše Sekyru a později Dva tisíce slov.", - "Vladimír Páral zachycuje konzumní stereotyp.", - "Divadlo a film 60. let jdou s literaturou ruku v ruce.", - "Okupace 1968 tuto vlnu utne a rozdělí autory na oficiální, samizdat a exil.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[3], "lit4_unit4", "lit4_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo napsal Ostře sledované vlaky?", - {"Bohumil Hrabal", "Milan Kundera", "Josef Škvorecký", "Ladislav Fuks"}, - 4, 0}, - {"Který román napsal Milan Kundera v 60. letech?", - {"Žert", "Babička", "Temno", "1984"}, - 4, 0}, - {"O čem jsou Zbabělci Josefa Škvoreckého?", - {"O konci války v českém městě očima mladíka", - "O barokním exilu Komenského", - "O antickém osudu", - "O národním obrození"}, - 4, 0}, - {"Kdo napsal Spalovače mrtvol?", - {"Ladislav Fuks", "Jiří Wolker", "Karel Jaromír Erben", "Victor Hugo"}, - 4, 0}, - }; - static const char *hints[] = { - "Hrabal: Ostře sledované vlaky, Pábitelé, později Obsluhoval jsem anglického krále.", - "Žert je Kunderův román o trestu za vtip.", - "Zbabělci vyšli na konci 50. let a patří k uvolnění.", - "Fuksův Spalovač mrtvol ukazuje, jak se obyčejný člověk stane nástrojem zla.", - }; - - return lit_mcq_page(3, 3, "lit4unit4", "lit4_ex4_title", "lit4_quiz4_head", - qs, hints, 4); -} - -static GtkWidget *build_lit4_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tři proudy", "Normalizace", - "Tip: po roce 1968 se česká literatura dělí na oficiální, samizdatovou a exilovou.", - { - "Normalizace vyřazuje nepohodlné autory z nakladatelství, novin i zaměstnání.", - "Oficiální scéna tiskne jen to, co projde cenzurou.", - "Samizdat opisuje rukopisy, známá je Vaculíkova Edice Petlice.", - "Exil vydává v cizině, Škvoreckého nakladatelství 68 Publishers vzniká v Torontu.", - NULL, - }, - }, - { - "2 / 3 • Autoři", "Kdo kam patří", - "Tip: jeden autor může v různých letech stát na různých stranách této hranice.", - { - "V exilu publikují Kundera, Škvorecký, Pavel Kohout a další.", - "V samizdatu píšou Václav Havel, Ludvík Vaculík, Ivan Klíma a Jiří Gruša.", - "Hrabal po nucených úpravách zčásti vychází oficiálně a zároveň koluje v opisech.", - "Underground, Egon Bondy a Ivan Jirous, stojí mimo oficiální kulturu zcela.", - NULL, - }, - }, - { - "3 / 3 • Charta", "Literatura a občanský postoj", - "Tip: Charta 77 není román, ale bez ní nelze normalizaci vysvětlit.", - { - "Charta 77 žádá dodržování práv, která stát sám podepsal.", - "Mnoho signatářů jsou spisovatelé a zakázaní autoři.", - "Čtení samizdatu je v té době čin, ne jen záliba.", - "Na maturitu vždy řekněte, v kterém z tří proudů dílo vyšlo.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[4], "lit4_unit5", "lit4_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se dělí česká literatura v normalizaci?", - {"Na lyriku, epiku a drama", - "Na oficiální tvorbu, samizdat a exil", - "Na ruchovce a lumírovce", - "Na antiku a středověk"}, - 4, 1}, - {"Co je Edice Petlice?", - {"Samizdatová edice Ludvíka Vaculíka", - "Oficiální nakladatelství 50. let", - "Barokní tiskárna", - "Almanach májovců"}, - 4, 0}, - {"Kde působilo nakladatelství 68 Publishers?", - {"V Torontu", "V Praze jako oficiální dům", - "Na Velké Moravě", "V Národním divadle"}, - 4, 0}, - {"Kdo patří k undergroundu normalizace?", - {"Egon Bondy a Ivan Jirous", "Josef Dobrovský a Josef Jungmann", - "Homér a Sofoklés", "Božena Němcová a Karel Jaromír Erben"}, - 4, 0}, - }; - static const char *hints[] = { - "Tři okruhy publikování jsou základní schéma učebnic.", - "Petlici řídil Vaculík, opisy šly z ruky do ruky.", - "68 Publishers založili Škvorecký a Zdena Salivarová.", - "Underground odmítá oficiální kulturu i její kompromisy.", - }; - - return lit_mcq_page(3, 4, "lit4unit5", "lit4_ex5_title", "lit4_quiz5_head", - qs, hints, 4); -} - -static GtkWidget *build_lit4_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Verš", "Poezie po roce 1945", - "Tip: Seifert dostal Nobelovu cenu roku 1984, v době, kdy doma nebyl režimní básník.", - { - "Jaroslav Seifert píše po válce intimní a paměťovou lyriku, Morový sloup vychází v samizdatu.", - "Jan Skácel a Miroslav Holub představují dvě polohy: něhu a věcnou metaforu.", - "Oficiální poezie 50. let je agitační, později se vrací civilní tón.", - "Písničkáři Karel Kryl, Jaromír Nohavica a Vladimír Merta nesou verš mimo knižní cenzuru.", - NULL, - }, - }, - { - "2 / 3 • Havel", "Drama, které mluví o moci řeči", - "Tip: Zahradní slavnost ukazuje, jak fráze pohltí člověka.", - { - "Václav Havel debutuje Zahradní slavností a Vyrozuměním.", - "Audience, Vernisáž a Protest jsou jednoaktovky o přizpůsobení.", - "Havel navazuje na absurdní drama, ale dá mu konkrétní českou situaci.", - "Hry kolují v samizdatu a hrají se v cizině, doma dlouho ne.", - NULL, - }, - }, - { - "3 / 3 • Jeviště", "Semafor, Cimrman a autorské divadlo", - "Tip: Divadlo Járy Cimrmana si vymyslelo génia, aby se smělo smát dějinám.", - { - "Malá divadla 60. let, Semafor a další, vracela jevišti písničku a improvizaci.", - "Zdeněk Svěrák a Ladislav Smoljak vytvářejí hry o Járovi Cimrmanovi.", - "České nebe později shrne národní mýty s nadsázkou.", - "Poezie a drama této doby často říkají víc mezi řádky než v hesle.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[5], "lit4_unit6", "lit4_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy dostal Jaroslav Seifert Nobelovu cenu?", - {"Roku 1895", "Roku 1984", "Roku 1836", "Roku 1415"}, - 4, 1}, - {"Kterou hru napsal Václav Havel?", - {"Zahradní slavnost", "Maryša", "Lakomec", "Noc na Karlštejně"}, - 4, 0}, - {"Co jsou Audience a Vernisáž?", - {"Havlovy jednoaktovky o přizpůsobení", - "Erbenovy balady", - "Legionářské romány", - "Klasicistní tragédie"}, - 4, 0}, - {"Kdo vytvořil Divadlo Járy Cimrmana?", - {"Zdeněk Svěrák a Ladislav Smoljak", - "Karel a Josef Čapkovi", - "Alois a Vilém Mrštíkové", - "Vítězslav Nezval a Karel Teige"}, - 4, 0}, - }; - static const char *hints[] = { - "Nobelova cena za literaturu 1984 patří Seifertovi.", - "Zahradní slavnost je Havlova první velká hra.", - "Audience se odehrává v pivovaře a ukazuje tlak na zakázaného spisovatele.", - "Cimrman je mystifikace, která paroduje národní dějiny.", - }; - - return lit_mcq_page(3, 5, "lit4unit6", "lit4_ex6_title", "lit4_quiz6_head", - qs, hints, 4); -} - -static GtkWidget *build_lit4_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • 1989", "Konec cenzury", - "Tip: po listopadu se najednou tiskne to, co čtyřicet let chodilo v opisech.", - { - "Samizdat a exil se vracejí do knihkupectví.", - "Čtenář dohání Kundera, Škvoreckého, Havla i zapadlé básníky.", - "Zároveň vzniká trh: kniha se musí i prodat.", - "Literatura ztrácí roli jediného místa, kde se říkala pravda.", - NULL, - }, - }, - { - "2 / 3 • Próza", "Viewegh, Topol a další", - "Tip: Báječná léta pod psa jsou generační vzpomínka na normalizaci, napsaná už svobodně.", - { - "Michal Viewegh v Báječných letech pod psa spojuje rodinnou kroniku a humor.", - "Jáchym Topol v Sestře píše syrovým, téměř mluveným jazykem o podzemí a svobodě.", - "Michal Ajvaz, Miloš Urban a Petra Hůlová ukazují, jak se próza rozběhla do různých směrů.", - "Autobiografie, groteska i náročný experiment stojí vedle sebe.", - NULL, - }, - }, - { - "3 / 3 • Dnešek", "Co z toho plyne pro školu", - "Tip: současný text se čte stejně poctivě jako klasika: druh, jazyk, kontext.", - { - "Po roce 1989 už nelze mluvit o jednom oficiálním stylu.", - "Poezie žije i mimo velká nakladatelství, na čteních a na webu.", - "Drama se vrací na scény, které čtyřicet let nesměly hrát zakázané hry.", - "Maturita žádá, abyste současnost uměli zařadit, ne jen převyprávět.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[6], "lit4_unit7", "lit4_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co se s literaturou stalo po roce 1989?", - {"Cenzura zesílila", - "Skončila cenzura a vrátily se samizdat a exil", - "Zanikla veškerá próza", - "Povinně se psal jen budovatelský román"}, - 4, 1}, - {"Kdo napsal Báječná léta pod psa?", - {"Michal Viewegh", "Bohumil Hrabal", "Karel Hynek Mácha", "Jan Neruda"}, - 4, 0}, - {"Který román napsal Jáchym Topol?", - {"Sestra", "Babička", "Máj", "Král Oidipus"}, - 4, 0}, - {"Proč literatura po roce 1989 ztratila výsadní politickou roli?", - {"Protože pravda se směla říkat i jinde než v opisech", - "Protože zanikl český jazyk", - "Protože se vrátila jen latina", - "Protože maturita literaturu zrušila"}, - 4, 0}, - }; - static const char *hints[] = { - "Listopad 1989 otevírá nakladatelství i archivy.", - "Vieweghova kniha je humoristická kronika normalizace.", - "Sestra je syrový román o svobodě po roce 1989.", - "Dokud byla cenzura, kniha často nahrazovala veřejnou debatu.", - }; - - return lit_mcq_page(3, 6, "lit4unit7", "lit4_ex7_title", "lit4_quiz7_head", - qs, hints, 4); -} - -static GtkWidget *build_lit4_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Postup", "Jak číst text k maturitě", - "Tip: nejdřív řekněte, co text je, teprve potom, co si o něm myslíte.", - { - "Určete literární druh a žánr a dobu, do které text patří.", - "Pojmenujte téma a hlavní motivy, ne jen děj větu po větě.", - "U prózy si všimněte vypravěče, kompozice a postav.", - "U lyriky rozlište autora a lyrický subjekt.", - NULL, - }, - }, - { - "2 / 3 • Jazyk", "Čím text působí", - "Tip: jeden konkrétní prostředek, který umíte pojmenovat, je víc než obecná chvála.", - { - "Hledejte metaforu, přirovnání, symbol, kontrast nebo opakování.", - "U verše určete rým, stopu, nebo řekněte, že jde o volný verš.", - "Všimněte si slovníku: knižní, hovorový, biblický, ironický.", - "Kompozice může být chronologická, retrospektivní, nebo pásmo obrazů.", - NULL, - }, - }, - { - "3 / 3 • Kontext", "Text není ostrov", - "Tip: vlastní názor má stát na textu, ne místo něj.", - { - "Zařaďte ukázku k autorovi, směru a historické situaci.", - "Srovnání s jiným dílem ukáže, že látce rozumíte.", - "Řekněte, co text sděluje dnes, a opřete to o konkrétní místo.", - "Struktura odpovědi: zařazení, téma, jazyk, kontext, vlastní soud.", - NULL, - }, - }, - }; - - return lit_unit_page(3, &lit4_lessons[7], "lit4_unit8", "lit4_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_lit4_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím má začít rozbor textu?", - {"Určením druhu, žánru a doby", - "Převyprávěním celého dějepisu", - "Vlastním dojmem bez textu", - "Seznamem všech autorů století"}, - 4, 0}, - {"Koho nesmíme zaměnit v lyrice?", - {"Autora a lyrický subjekt", - "Nakladatele a tiskaře", - "Čtenáře a cenzora", - "Rým a stopu"}, - 4, 0}, - {"Co je volný verš?", - {"Verš vázaný povinným sdruženým rýmem", - "Verš bez pravidelného rýmu a stopy", - "Jen antický hexametr", - "Dramatická replika"}, - 4, 1}, - {"Jak má vypadat vlastní názor u maturity?", - {"Má nahradit rozbor", - "Má vycházet z konkrétního místa v textu", - "Má být co nejdelší bez argumentu", - "Má zůstat nevysloven"}, - 4, 1}, - }; - static const char *hints[] = { - "Zařazení je rám, bez kterého jazykový rozbor visí ve vzduchu.", - "Lyrický subjekt je hlas básně, ne automaticky občanský průkaz autora.", - "Volný verš je běžný od avantgardy po současnost.", - "Soud bez citace z textu maturita nepočítá jako rozbor.", - }; - - return lit_mcq_page(3, 7, "lit4unit8", "lit4_ex8_title", "lit4_quiz8_head", - qs, hints, 4); -} - -void add_lit4_pages(GtkStack *stack) { - typedef GtkWidget *(*LitBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - LitBuilder build_unit; - LitBuilder build_ex; - } pages[] = { - {"lit4unit1", "lit4ex1", build_lit4_unit1_page, build_lit4_unit1_exercise_page}, - {"lit4unit2", "lit4ex2", build_lit4_unit2_page, build_lit4_unit2_exercise_page}, - {"lit4unit3", "lit4ex3", build_lit4_unit3_page, build_lit4_unit3_exercise_page}, - {"lit4unit4", "lit4ex4", build_lit4_unit4_page, build_lit4_unit4_exercise_page}, - {"lit4unit5", "lit4ex5", build_lit4_unit5_page, build_lit4_unit5_exercise_page}, - {"lit4unit6", "lit4ex6", build_lit4_unit6_page, build_lit4_unit6_exercise_page}, - {"lit4unit7", "lit4ex7", build_lit4_unit7_page, build_lit4_unit7_exercise_page}, - {"lit4unit8", "lit4ex8", build_lit4_unit8_page, build_lit4_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/literatura.c b/src/literatura.c deleted file mode 100644 index b5d6e6c..0000000 --- a/src/literatura.c +++ /dev/null @@ -1,947 +0,0 @@ -#include "graduately.h" - -/* Literature for Český jazyk a literatura. - * Four years follow the chronology used in secondary-school syllabi - * (RVP G, literární komunikace, and RVP for vocational schools, - * estetické vzdělávání): antiquity through the present, then a lesson - * on interpreting a text. Each lesson is a short overview and a quiz. */ - -typedef struct { - const char *map_page; - const char *back_page; - const char *title_key; - const char *sub_key; - const char *unit_keys[LIT_N]; - char **progress_path; - NetLesson *lessons; - GtkWidget *scroll; - GtkWidget *fixed; - GtkWidget *rail; - GtkWidget *nodes[LIT_N]; - GtkWidget *labels[LIT_N]; - double cx[LIT_N]; - double cy[LIT_N]; - int cols; - int rows; - int cw; - int ch; - guint idle; - double last_avail; - int last_cols; - int last_rows; - int last_cw; - int last_ch; - cairo_surface_t *rail_cache; - int cache_w; - int cache_h; - int note_last_w; -} LitTrack; - -static LitTrack lit_tracks[4]; - -static void lit_ensure(void); - -static void lit_point(LitTrack *T, double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= LIT_N - 1) { k = LIT_N - 2; u = 1.0; } - - p1x = T->cx[k]; p1y = T->cy[k]; - p2x = T->cx[k + 1]; p2y = T->cy[k + 1]; - if (k - 1 >= 0) { p0x = T->cx[k - 1]; p0y = T->cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < LIT_N) { p3x = T->cx[k + 2]; p3y = T->cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -static void lit_path(LitTrack *T, cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 24.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - lit_point(T, t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - lit_point(T, t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -static void lit_geometry(LitTrack *T, double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(LIT_N - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= LIT_N; rows++) { - int cols = (LIT_N + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > LIT_N) - rows = LIT_N; - T->rows = rows; - T->cols = (LIT_N + rows - 1) / rows; - if (T->cols < 1) - T->cols = 1; - T->cw = (int)(2.0 * ROAD_MX + (T->cols - 1) * PATH_SPAC); - T->ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * T->cols; - int len = MIN(T->cols, LIT_N - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - int cc = fwd ? c : (T->cols - 1 - c); - i = base + c; - T->cx[i] = ROAD_MX + cc * PATH_SPAC; - T->cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -static void lit_apply_layout(LitTrack *T) { - if (!T->fixed) - return; - if (T->cols == T->last_cols && T->rows == T->last_rows && - T->cw == T->last_cw && T->ch == T->last_ch) - return; - - T->last_cols = T->cols; - T->last_rows = T->rows; - T->last_cw = T->cw; - T->last_ch = T->ch; - if (T->rail_cache) { - cairo_surface_destroy(T->rail_cache); - T->rail_cache = NULL; - } - - for (int i = 0; i < LIT_N; i++) { - if (!T->nodes[i] || !T->labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(T->fixed), T->nodes[i], - (int)(T->cx[i] - NODE_SIZE / 2.0), - (int)(T->cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(T->fixed), T->labels[i], - (int)(T->cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(T->cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(T->fixed, T->cw, T->ch); - gtk_widget_set_size_request(T->rail, T->cw, T->ch); - gtk_fixed_move(GTK_FIXED(T->fixed), T->rail, 0, 0); - gtk_widget_queue_draw(T->rail); -} - -static void lit_relayout(LitTrack *T) { - GtkAdjustment *hadj; - double avail; - - if (!T->scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(T->scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - T->last_avail) < 1.0) - return; - T->last_avail = avail; - lit_geometry(T, avail); - lit_apply_layout(T); -} - -static gboolean lit_relayout_idle(gpointer data) { - LitTrack *T = data; - - T->idle = 0; - lit_relayout(T); - return G_SOURCE_REMOVE; -} - -static void lit_relayout_later(LitTrack *T) { - if (T->idle == 0) - T->idle = g_idle_add(lit_relayout_idle, T); -} - -static void lit_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - lit_relayout_later(data); -} - -static void lit_render_rail(LitTrack *T, cairo_t *cr) { - const double t_end = (double)(LIT_N - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - lit_path(T, cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - lit_path(T, cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -static void lit_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - LitTrack *T = data; - cairo_t *rcr; - - (void)area; - (void)width; - (void)height; - - if (!T->rail_cache || T->cache_w != T->cw || T->cache_h != T->ch) { - if (T->rail_cache) - cairo_surface_destroy(T->rail_cache); - T->cache_w = T->cw > 0 ? T->cw : 1; - T->cache_h = T->ch > 0 ? T->ch : 1; - T->rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - T->cache_w, T->cache_h); - rcr = cairo_create(T->rail_cache); - lit_render_rail(T, rcr); - cairo_destroy(rcr); - } - - cairo_set_source_surface(cr, T->rail_cache, 0, 0); - cairo_paint(cr); -} - -void lit_rail_theme_reset(void) { - for (int y = 0; y < 4; y++) { - LitTrack *T = &lit_tracks[y]; - - if (T->rail_cache) { - cairo_surface_destroy(T->rail_cache); - T->rail_cache = NULL; - } - if (T->rail) - gtk_widget_queue_draw(T->rail); - } -} - -static void lit_save(LitTrack *T) { - GKeyFile *kf; - char *path; - gchar *data; - - if (!T->progress_path || !*T->progress_path) - return; - path = *T->progress_path; - kf = g_key_file_new(); - for (int i = 0; i < LIT_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, T->lessons[i].done); - } - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - if (data) { - GError *err = NULL; - - g_file_set_contents(path, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -static void lit_load_one(LitTrack *T) { - GKeyFile *kf; - GError *err = NULL; - const char *path; - - if (!T->progress_path || !*T->progress_path) - return; - path = *T->progress_path; - kf = g_key_file_new(); - if (!g_key_file_load_from_file(kf, path, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - for (int i = 0; i < LIT_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - T->lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - g_key_file_free(kf); -} - -void lit_load_progress(void) { - lit_ensure(); - for (int y = 0; y < 4; y++) - lit_load_one(&lit_tracks[y]); -} - -static void lit_refresh(LitTrack *T) { - for (int i = 0; i < LIT_N; i++) { - GtkWidget *node = T->nodes[i]; - GtkWidget *icon = T->lessons[i].done_icon; - - if (!node) - continue; - if (T->lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -static void lit_mark_done(LitTrack *T, int lesson_id) { - if (lesson_id < 0 || lesson_id >= LIT_N) - return; - if (T->lessons[lesson_id].done) - return; - T->lessons[lesson_id].done = TRUE; - lit_save(T); - lit_refresh(T); - refresh_stats_ui(); -} - -void progress_for_lit(ProgressSum *out) { - if (!out) - return; - lit_ensure(); - for (int y = 0; y < 4; y++) { - LitTrack *T = &lit_tracks[y]; - - out->total_ex += LIT_N; - out->open_units += LIT_N; - for (int i = 0; i < LIT_N; i++) { - if (T->lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - } -} - -static void lit_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof(name), "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static void lit_add_node(LitTrack *T, GtkFixed *fixed, int index) { - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_add_css_class(card, "current"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", index + 1); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - T->lessons[index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(lit_open_unit), - &T->lessons[index]); - - T->nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - i18n_bind(name, T->unit_keys[index], 0); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_label_set_max_width_chars(GTK_LABEL(name), 18); - gtk_widget_add_css_class(name, "unit-name"); - T->labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} - -static GtkWidget *lit_build_map(LitTrack *T) { - GtkWidget *page; - - lit_ensure(); - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - - T->last_avail = -1.0; - lit_geometry(T, 1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar(T->back_page, T->title_key, T->sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - T->scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, T->cw, T->ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - T->fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, T->cw, T->ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), lit_draw_rail, - T, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - T->rail = rail; - - for (int i = 0; i < LIT_N; i++) - lit_add_node(T, GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(lit_adjust_notify), T); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(lit_adjust_notify), T); - - lit_apply_layout(T); - lit_relayout_later(T); - lit_refresh(T); - return page; -} - -static GtkWidget *lit_year_button(int year, const char *target, - const char *title_key, const char *sub_key) { - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - GtkWidget *sub; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 84); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", year); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, title_key, 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - sub = gtk_label_new(NULL); - i18n_bind(sub, sub_key, 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0.0); - gtk_widget_add_css_class(sub, "hint"); - gtk_box_append(GTK_BOX(texts), sub); - - g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - return btn; -} - -GtkWidget *build_lityears_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - static const char *targets[] = {"litmap", "lit2map", "lit3map", "lit4map"}; - static const char *titles[] = { - "lit_year1", "lit_year2", "lit_year3", "lit_year4", - }; - static const char *subs[] = {"lit_sub", "lit2_sub", "lit3_sub", "lit4_sub"}; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("czechmap", "Literatura", "lit_years_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 420, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (int y = 0; y < 4; y++) - gtk_box_append(GTK_BOX(list), - lit_year_button(y + 1, targets[y], titles[y], subs[y])); - return page; -} - -GtkWidget *build_litmap_page(void) { return lit_build_map(&lit_tracks[0]); } -GtkWidget *build_lit2map_page(void) { return lit_build_map(&lit_tracks[1]); } -GtkWidget *build_lit3map_page(void) { return lit_build_map(&lit_tracks[2]); } -GtkWidget *build_lit4map_page(void) { return lit_build_map(&lit_tracks[3]); } - -static void lit_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void lit_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L || L->idx == 0) - return; - L->idx--; - lit_slide_apply(L); -} - -static void lit_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - lit_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -static void lit_rescale(LitTrack *T, int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < LIT_N; i++) - net_rescale_lesson_notes(&T->lessons[i], body, head, kick); -} - -static gboolean lit_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - LitTrack *T = data; - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - if (width != T->note_last_w) { - T->note_last_w = width; - lit_rescale(T, width); - } - return G_SOURCE_CONTINUE; -} - -GtkWidget *lit_unit_page(int year, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides) { - LitTrack *T; - - lit_ensure(); - T = &lit_tracks[year]; - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar(T->map_page, title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "s%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, lit_note_tick, T, NULL); - T->note_last_w = -1; - lit_rescale(T, 0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(lit_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(lit_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - lit_slide_apply(L); - return page; -} - -void lit_lessons_apply_lang(void) { - lit_ensure(); - for (int y = 0; y < 4; y++) { - for (int i = 0; i < LIT_N; i++) - lit_slide_apply(&lit_tracks[y].lessons[i]); - } -} - -typedef struct { - const ChoiceQ *qs; - int n; - int n_opts; - LitTrack *track; - int lesson_id; - GtkWidget *feedback; - GtkToggleButton **toggles; - GtkWidget **hints; -} LitMcqCtx; - -static void lit_mcq_check(GtkButton *button, gpointer data) { - LitMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - lit_mark_done(ctx->track, ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -GtkWidget *lit_mcq_page(int year, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - LitMcqCtx *ctx = g_new0(LitMcqCtx, 1); - int n_opts = qs[0].n_options; - - lit_ensure(); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->track = &lit_tracks[year]; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(lit_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - return page; -} - -static gboolean lit_ready; - -static void lit_tracks_init(void) { - static const char *keys0[] = { - "lit_unit1", "lit_unit2", "lit_unit3", "lit_unit4", - "lit_unit5", "lit_unit6", "lit_unit7", "lit_unit8", - }; - static const char *keys1[] = { - "lit2_unit1", "lit2_unit2", "lit2_unit3", "lit2_unit4", - "lit2_unit5", "lit2_unit6", "lit2_unit7", "lit2_unit8", - }; - static const char *keys2[] = { - "lit3_unit1", "lit3_unit2", "lit3_unit3", "lit3_unit4", - "lit3_unit5", "lit3_unit6", "lit3_unit7", "lit3_unit8", - }; - static const char *keys3[] = { - "lit4_unit1", "lit4_unit2", "lit4_unit3", "lit4_unit4", - "lit4_unit5", "lit4_unit6", "lit4_unit7", "lit4_unit8", - }; - static const char *const *all_keys[4] = {keys0, keys1, keys2, keys3}; - static const char *maps[] = {"litmap", "lit2map", "lit3map", "lit4map"}; - static const char *titles[] = { - "lit_year1", "lit_year2", "lit_year3", "lit_year4", - }; - static const char *subs[] = {"lit_sub", "lit2_sub", "lit3_sub", "lit4_sub"}; - NetLesson *lessons[4] = { - lit_lessons, lit2_lessons, lit3_lessons, lit4_lessons, - }; - char **paths[4] = { - &app_progress_lit, &app_progress_lit2, - &app_progress_lit3, &app_progress_lit4, - }; - - for (int y = 0; y < 4; y++) { - LitTrack *T = &lit_tracks[y]; - - T->map_page = maps[y]; - T->back_page = "lityears"; - T->title_key = titles[y]; - T->sub_key = subs[y]; - T->progress_path = paths[y]; - T->lessons = lessons[y]; - T->last_avail = -1.0; - T->last_cols = -1; - T->note_last_w = -1; - for (int i = 0; i < LIT_N; i++) - T->unit_keys[i] = all_keys[y][i]; - } -} - -static void lit_ensure(void) { - if (lit_ready) - return; - lit_ready = TRUE; - lit_tracks_init(); -} diff --git a/src/macos_dock.c b/src/macos_dock.c deleted file mode 100644 index ed7dbea..0000000 --- a/src/macos_dock.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "graduately.h" - -#ifdef __APPLE__ -#include -#include - -/* Set the macOS Dock tile icon. GTK's window icon-name is ignored on - * Quartz, so we talk to AppKit directly via the Objective-C runtime. */ -void macos_set_dock_icon(const char *path) { - Class nsstring; - Class nsimage; - Class nsapp; - id path_str; - id image; - id app; - - if (!path || !path[0]) - return; - - nsstring = objc_getClass("NSString"); - nsimage = objc_getClass("NSImage"); - nsapp = objc_getClass("NSApplication"); - if (!nsstring || !nsimage || !nsapp) - return; - - path_str = ((id (*)(Class, SEL, const char *))objc_msgSend)( - nsstring, sel_registerName("stringWithUTF8String:"), path); - if (!path_str) - return; - - /* NSImage has -initWithContentsOfFile:, not +imageWithContentsOfFile:. */ - image = ((id (*)(id, SEL, id))objc_msgSend)( - ((id (*)(Class, SEL))objc_msgSend)( - nsimage, sel_registerName("alloc")), - sel_registerName("initWithContentsOfFile:"), - path_str); - if (!image) - return; - - app = ((id (*)(Class, SEL))objc_msgSend)( - nsapp, sel_registerName("sharedApplication")); - if (!app) { - ((void (*)(id, SEL))objc_msgSend)(image, sel_registerName("release")); - return; - } - - ((void (*)(id, SEL, id))objc_msgSend)( - app, sel_registerName("setApplicationIconImage:"), image); - ((void (*)(id, SEL))objc_msgSend)(image, sel_registerName("release")); -} -#else -void macos_set_dock_icon(const char *path) { - (void)path; -} -#endif diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 1c960f3..0000000 --- a/src/main.c +++ /dev/null @@ -1,800 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Activate */ -/* ------------------------------------------------------------------ */ - -void unit_meta_init(void) { - static const char *titles[NUM_UNITS] = { - "Neue Freunde", "Aus aller Welt", "Bei uns zu Hause", - "Schule und Freizeit", "Guten Appetit!", "Mein Tagesablauf", - "Meine Freunde", "Wir treffen uns in Salzburg", - "Mein Haus ist meine Burg", "Urlaub in Österreich", - }; - static const char *pages[NUM_UNITS] = { - "unit1", "unit2", "unit3", NULL, NULL, NULL, NULL, NULL, NULL, NULL, - }; - static const char *tags[NUM_UNITS] = { - "u1", "u2", "u3", NULL, NULL, NULL, NULL, NULL, NULL, NULL, - }; - - for (int i = 0; i < NUM_UNITS; i++) { - units[i].title = titles[i]; - units[i].page = pages[i]; - units[i].ex_tag = tags[i]; - units[i].sub_key = NULL; - units[i].unlocked = (i < NUM_UNLOCKED); - } - units[0].sub_key = "unit1_sub"; - units[0].progress_file = PROGRESS_U1; - units[1].sub_key = "unit2_sub"; - units[1].progress_file = PROGRESS_U2; - units[2].sub_key = "unit3_sub"; - units[2].progress_file = PROGRESS_U3; - - /* Off-path branch hanging above exercise 2 of unit 1. */ - units[0].has_branch = TRUE; - units[0].branch_name = "Vokabeltraining"; - units[0].branch_target = "u1vocab"; - units[0].branch_ex = MAX_UNIT_EX; - units[0].trans_sections = u1_trans_sections; - units[0].n_trans_sections = u1_trans_sections_n; - - /* Same vocabulary-training branch for unit 2 ("Aus aller Welt"). */ - units[1].has_branch = TRUE; - units[1].branch_name = "Vokabeltraining"; - units[1].branch_target = "u2vocab"; - units[1].branch_ex = MAX_UNIT_EX; - units[1].trans_sections = u2_trans_sections; - units[1].n_trans_sections = u2_trans_sections_n; - - /* Same vocabulary-training branch for unit 3 ("Bei uns zu Hause"). */ - units[2].has_branch = TRUE; - units[2].branch_name = "Vokabeltraining"; - units[2].branch_target = "u3vocab"; - units[2].branch_ex = MAX_UNIT_EX; - units[2].trans_sections = u3_trans_sections; - units[2].n_trans_sections = u3_trans_sections_n; -} - -void unit_configure(int idx, const char *const *names, int n) { - UnitCtx *u = &units[idx]; - - u->n_ex = n; - for (int i = 1; i <= n; i++) - u->ex_names[i] = names[i]; -} - -GtkWidget *build_exercise_page(UnitCtx *u, int n) { - if (u->ex_tag[1] == '1') { - switch (n) { - case 1: return build_ex1(u); - case 2: return build_assembly(u, "Sätze bilden", "sub_assembly", 2, - ex2_items, ex2_meaning, - 4); - case 3: return build_choice(u, "Was ist richtig?", "sub_choice_num", - 3, ex3_questions, ex3_meaning, - 4); - case 4: return build_ex4(u); - case 5: return build_ex5(u); - case 6: return build_ex6(u); - case 7: return build_ex7(u); - case 8: return build_ex8(u); - case 9: return build_choice(u, "Wer? Wie? Wo?", "sub_wer", - 9, ex9_questions, ex9_meaning, - 5); - case 10: return build_assembly(u, "Wörter trennen", "sub_assembly", - 10, ex10_items, ex10_meaning, - 5); - case 11: return build_assign(u, "Grußformen", "sub_gruss", - 11, ex11_items, - 12, - ex11_groups, 2, - ex11_meaning); - case 12: return build_ex12(u); - case 13: return build_assign(u, "Länder", "sub_land", - 13, ex13_items, - 10, - ex13_groups, 3, - ex13_meaning); - default: return NULL; - } - } else if (u->ex_tag[1] == '2') { - switch (n) { - case 1: return u2ex1(u); - case 2: return u2ex2(u); - case 3: return u2ex3(u); - case 4: return u2ex4(u); - case 5: return u2ex5(u); - case 6: return u2ex6(u); - case 7: return u2ex7(u); - case 8: return u2ex8(u); - case 9: return u2ex9(u); - case 10: return u2ex10(u); - case 11: return u2ex11(u); - case 12: return u2ex12(u); - case 13: return u2ex13(u); - case 14: return u2ex14(u); - case 15: return u2ex15(u); - case 16: return u2ex16(u); - case 17: return u2ex17(u); - case 18: return u2ex18(u); - case 19: return u2ex19(u); - default: return NULL; - } - } else { - switch (n) { - case 1: return u3ex1(u); - case 2: return u3ex2(u); - case 3: return u3ex3(u); - case 4: return u3ex4(u); - case 5: return u3ex5(u); - case 6: return u3ex6(u); - case 7: return u3ex7(u); - case 8: return u3ex8(u); - case 9: return u3ex9(u); - case 10: return u3ex10(u); - case 11: return u3ex11(u); - case 12: return u3ex12(u); - case 13: return u3ex13(u); - case 14: return u3ex14(u); - case 15: return u3ex15(u); - default: return NULL; - } - } -} - -static int ui_scale_last_w = -1; -static guint ui_scale_timer = 0; -static int ui_scale_pending_w = 0; - -static gboolean ui_scale_apply(gpointer data) { - double scale; - - (void)data; - ui_scale_timer = 0; - scale = 1.0 + (ui_scale_pending_w - 760) / 1900.0; - if (scale < 1.0) - scale = 1.0; - if (scale > 1.5) - scale = 1.5; - scale = (double)((int)(scale * 20.0 + 0.5)) / 20.0; - if (scale != app_ui_scale) { - app_ui_scale = scale; - apply_theme(); - } - return G_SOURCE_REMOVE; -} - -/* Grow the interface's text as the window gets wider, so it stays comfortable - * when maximised on a large or high-DPI display. Debounced to avoid reloading - * the stylesheet on every frame while dragging. */ -static gboolean ui_scale_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width < 200 || width == ui_scale_last_w) - return G_SOURCE_CONTINUE; - ui_scale_last_w = width; - ui_scale_pending_w = width; - if (ui_scale_timer) - g_source_remove(ui_scale_timer); - ui_scale_timer = g_timeout_add(120, ui_scale_apply, NULL); - return G_SOURCE_CONTINUE; -} - -static const char *find_app_icon_file(void) { - static const char *paths[] = { - ICON_FILE, - "../assets/app-icon.png", - ICON_THEME_DIR "/hicolor/512x512/apps/" ICON_NAME ".png", - SHARE_DIR "/icons/hicolor/512x512/apps/" ICON_NAME ".png", - ICON_FILE_ALT, - NULL, - }; - int i; - - for (i = 0; paths[i]; i++) { - if (g_file_test(paths[i], G_FILE_TEST_IS_REGULAR)) - return paths[i]; - } - return NULL; -} - -/* Kept alive for gdk_toplevel_set_icon_list() which does not take ownership. */ -static GList *app_icon_textures; - -static void clear_app_icon_textures(void) { - g_list_free_full(app_icon_textures, g_object_unref); - app_icon_textures = NULL; -} - -/* X11 / some compositors use the toplevel icon list for the taskbar tile. */ -static void apply_toplevel_icon(GtkWindow *window) { - GdkSurface *surface; - const char *path; - GError *err = NULL; - GdkTexture *tex; - - surface = gtk_native_get_surface(GTK_NATIVE(window)); - if (!surface || !GDK_IS_TOPLEVEL(surface)) - return; - - path = find_app_icon_file(); - if (!path) - return; - - tex = gdk_texture_new_from_filename(path, &err); - if (!tex) { - g_clear_error(&err); - return; - } - - clear_app_icon_textures(); - app_icon_textures = g_list_append(NULL, tex); - gdk_toplevel_set_icon_list(GDK_TOPLEVEL(surface), app_icon_textures); -} - -static void on_window_realize_icon(GtkWidget *widget, gpointer data) { - (void)data; - apply_toplevel_icon(GTK_WINDOW(widget)); -} - -/* Prepend ./share to XDG_DATA_DIRS so Wayland can find our .desktop file and - * hicolor icons without a system install (matches APP_ID). */ -static void setup_portable_share_dir(void) { - char *abs; - const char *old; - char *neu; - - if (!g_file_test(SHARE_DIR "/applications", G_FILE_TEST_IS_DIR) && - !g_file_test(SHARE_DIR "/icons", G_FILE_TEST_IS_DIR)) - return; - - abs = g_canonicalize_filename(SHARE_DIR, NULL); - if (!abs) - return; - - old = g_getenv("XDG_DATA_DIRS"); - if (old && old[0]) - neu = g_strconcat(abs, G_SEARCHPATH_SEPARATOR_S, old, NULL); - else - neu = g_strconcat(abs, - G_SEARCHPATH_SEPARATOR_S "/usr/local/share" - G_SEARCHPATH_SEPARATOR_S "/usr/share", - NULL); - g_setenv("XDG_DATA_DIRS", neu, TRUE); - g_free(neu); - g_free(abs); -} - -/* Register icon theme paths + window icon-name (Linux), AppKit Dock (macOS), - * and toplevel textures (X11 / fallbacks). Windows uses the .ico embedded - * via maturita.rc at link time. */ -static void setup_window_icon(GtkWindow *window) { - GtkIconTheme *theme; - static const char *dirs[] = { - ICON_THEME_DIR, - ICON_THEME_DIR_ALT, - SHARE_DIR "/icons", - NULL, - }; - const char *icon_file; - int i; - - theme = gtk_icon_theme_get_for_display(gdk_display_get_default()); - for (i = 0; dirs[i]; i++) { - if (g_file_test(dirs[i], G_FILE_TEST_IS_DIR)) - gtk_icon_theme_add_search_path(theme, dirs[i]); - } - - if (gtk_icon_theme_has_icon(theme, ICON_NAME)) { - gtk_window_set_default_icon_name(ICON_NAME); - gtk_window_set_icon_name(window, ICON_NAME); - } else { - g_warning("App icon '%s' not found (tried %s/, %s/, %s/icons/)", - ICON_NAME, ICON_THEME_DIR, ICON_THEME_DIR_ALT, SHARE_DIR); - } - - icon_file = find_app_icon_file(); - if (icon_file) - macos_set_dock_icon(icon_file); -#ifdef __APPLE__ - else - g_warning("Dock icon PNG not found (tried %s and %s)", - ICON_FILE, ICON_FILE_ALT); -#endif - - g_signal_connect(window, "realize", - G_CALLBACK(on_window_realize_icon), NULL); -} - -static gboolean open_settings_later(gpointer data) { - (void)data; - settings_open(); - return G_SOURCE_REMOVE; -} - -static gboolean save_window_png(const char *path) { - GtkWidget *widget; - int width, height; - GdkPaintable *paintable; - GtkSnapshot *snapshot; - GskRenderNode *node; - cairo_surface_t *surface; - cairo_t *cr; - cairo_status_t st; - - if (!main_window || !path || !path[0]) - return FALSE; - - widget = GTK_WIDGET(main_window); - width = gtk_widget_get_width(widget); - height = gtk_widget_get_height(widget); - if (width < 80 || height < 80) - return FALSE; - - paintable = gtk_widget_paintable_new(widget); - snapshot = gtk_snapshot_new(); - gdk_paintable_snapshot(paintable, snapshot, width, height); - node = gtk_snapshot_free_to_node(snapshot); - g_object_unref(paintable); - if (!node) - return FALSE; - - surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cr = cairo_create(surface); - gsk_render_node_draw(node, cr); - gsk_render_node_unref(node); - cairo_destroy(cr); - st = cairo_surface_write_to_png(surface, path); - cairo_surface_destroy(surface); - return st == CAIRO_STATUS_SUCCESS; -} - -static void smoke_quit(int code) { - GtkApplication *app = main_window - ? gtk_window_get_application(main_window) : NULL; - - if (app) - g_application_quit(G_APPLICATION(app)); - else - exit(code); -} - -static gboolean shot_later(gpointer data) { - const char *path = g_getenv("MATURITA_SHOT"); - int *tries = data; - - if (!save_window_png(path)) { - if (tries && *tries < 20) { - (*tries)++; - return G_SOURCE_CONTINUE; - } - g_printerr("MATURITA_SHOT: could not capture window\n"); - smoke_quit(1); - return G_SOURCE_REMOVE; - } - if (g_getenv("MATURITA_SHOT_QUIT")) - smoke_quit(0); - return G_SOURCE_REMOVE; -} - -static gboolean run_smoke_test(gpointer data) { - static const char *pages[] = { - "welcome", "subjects", "roadmap", "stats", - "netyears", "netmap", "hwyears", "hwmap", "onyears", "onmap", "on2map", - "on3map", "on4map", - "czechmap", - "lityears", "litmap", "lit2map", "lit3map", "lit4map", - "scimap", "chemmap", "biomap", - "matyears", "mat0map", "matmap", "mat2map", "mat3map", "mat4map", - "mat0unit1", "mat0ex1", "matunit1", "matex1", - "mat4unit8", "mat4ex8", - "fyzyears", "fyzmap", "fyz2map", "fyz3map", "fyz4map", - "fyzunit1", "fyzex1", "fyzunit8", "fyzex8", - "fyz2unit1", "fyz2ex1", "fyz3unit1", "fyz4unit1", - "fyz4unit8", "fyz4ex8", - "chemunit1", "chemex1", "chemunit8", "chemex8", - "biounit1", "bioex1", "biounit8", "bioex8", - "litunit1", "litex1", "litunit8", "litex8", - "lit2unit1", "lit2ex1", "lit3unit1", "lit3ex1", - "lit4unit1", "lit4ex1", "lit4unit8", "lit4ex8", - "mluvnice", "readinglist", - "cetba1984", "cetba1984quiz", "cetba1984dej", - "cetbaFuks", "cetbaFuksQuiz", "cetbaFuksDej", - "hwunit1", "hwex1", "hwunit2", "hwex2", "hwunit3", "hwex3", - "hwunit4", "hwex4", - "hwunit5", "hwex5", "hwunit6", "hwex6", "hwunit7", "hwex7", - "hwunit8", "hwex8", "hwunit9", "hwex9", - "hwunit10", "hwex10", "hwunit15", "hwex15", - "hwunit20", "hwex20", "hwunit25", "hwex25", - "hwunit29", "hwex29", - "onunit1", "onex1", "onunit17", "onex17", - "on2unit1", "on2ex1", "on2unit16", "on2ex16", - "on3unit1", "on3ex1", "on3unit16", "on3ex16", - "on4unit1", "on4ex1", "on4unit16", "on4ex16", - "enyears", "en1map", "en4map", - "en1unit1", "en1ex1", "en4unit8", "en4ex8", - "dehome", "de1map", "de4map", - "de1unit1", "de1ex1", "de4unit6", "de4ex6", - "unit1", "unit2", "unit3", - "u1e1", "u1e13", "u2e1", "u2e19", "u3e1", "u3e15", - "u1vocab", "u2vocab", "u3vocab", - "mluve1", "mluve20", - "netunit1", "netex1", "netunit10", "netex10", - "netunit27", "netex27", - "net2map", "net2unit1", "net2ex1", "net4unit8", "net4ex8", - "hw2map", "hw2unit1", "hw2ex1", "hw4unit8", "hw4ex8", - NULL - }; - const char *report = g_getenv("MATURITA_SMOKE"); - FILE *f; - int missing = 0; - int i; - - (void)data; - f = report && report[0] ? fopen(report, "w") : stdout; - if (!f) { - g_printerr("MATURITA_SMOKE: cannot write %s\n", report); - smoke_quit(1); - return G_SOURCE_REMOVE; - } - - fprintf(f, "commit=%s\n", APP_COMMIT); - fprintf(f, "css=%s\n", - g_file_test(CSS_FILE, G_FILE_TEST_IS_REGULAR) ? "ok" : "MISSING"); - fprintf(f, "changelog=%s\n", - g_file_test(CHANGELOG_FILE, G_FILE_TEST_IS_REGULAR) ? "ok" : "MISSING"); - fprintf(f, "progress_dir=%s\n", app_progress_dir ? app_progress_dir : "?"); - - for (i = 0; pages[i]; i++) { - GtkWidget *child = gtk_stack_get_child_by_name(main_stack, pages[i]); - - if (child) { - fprintf(f, "OK %s\n", pages[i]); - } else { - fprintf(f, "MISSING %s\n", pages[i]); - missing++; - } - } - - fprintf(f, "missing=%d\n", missing); - if (f != stdout) - fclose(f); - smoke_quit(missing ? 1 : 0); - return G_SOURCE_REMOVE; -} - -void activate(GtkApplication *app, gpointer user_data) { - GtkWindow *window; - GtkWidget *headerbar; - GtkWidget *title_label; - GtkWidget *welcome_page; - GtkWidget *roadmap_page; - GtkEventController *keys; - - (void)user_data; - - load_settings(); - unit_meta_init(); - unit_configure(0, u1_ex_names, 13); - unit_configure(1, u2_ex_names, 19); - unit_configure(2, u3_ex_names, 15); - load_progress(); - mluvnice_init(); - app_theme = theme_palette(app_theme_id, app_color_mode); - - window = GTK_WINDOW(gtk_application_window_new(app)); - main_window = window; - gtk_window_set_title(window, "Graduately"); - gtk_window_set_default_size(window, 1080, 720); - setup_window_icon(window); - - headerbar = gtk_header_bar_new(); - gtk_widget_add_css_class(headerbar, "titlebar"); - title_label = gtk_label_new("Graduately"); - gtk_widget_add_css_class(title_label, "app-title"); - gtk_header_bar_set_title_widget(GTK_HEADER_BAR(headerbar), title_label); - gtk_window_set_titlebar(window, headerbar); - apply_theme(); - gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), build_settings_button()); - gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), build_stats_button()); - gtk_header_bar_pack_end(GTK_HEADER_BAR(headerbar), build_search_button()); - - main_stack = GTK_STACK(gtk_stack_new()); - gtk_stack_set_transition_type(GTK_STACK(main_stack), - GTK_STACK_TRANSITION_TYPE_CROSSFADE); - - /* The update banner sits above the pages and stays hidden until there is - * something to report, so it never shifts the layout unprompted. */ - { - GtkWidget *root = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *overlay = gtk_overlay_new(); - - gtk_box_append(GTK_BOX(root), build_update_banner()); - gtk_widget_set_vexpand(GTK_WIDGET(main_stack), TRUE); - gtk_box_append(GTK_BOX(root), GTK_WIDGET(main_stack)); - gtk_overlay_set_child(GTK_OVERLAY(overlay), root); - gtk_window_set_child(window, overlay); - search_attach(GTK_OVERLAY(overlay)); - } - - welcome_page = build_welcome_page(); - roadmap_page = build_roadmap_page(); - gtk_stack_add_named(main_stack, welcome_page, "welcome"); - gtk_stack_add_named(main_stack, build_subjects_page(), "subjects"); - gtk_stack_add_named(main_stack, roadmap_page, "roadmap"); - gtk_stack_add_named(main_stack, build_dehome_page(), "dehome"); - add_de_pages(main_stack); - gtk_stack_add_named(main_stack, build_stats_page(), "stats"); - gtk_stack_add_named(main_stack, build_netyears_page(), "netyears"); - gtk_stack_add_named(main_stack, build_netmap_page(), "netmap"); - gtk_stack_add_named(main_stack, build_hwyears_page(), "hwyears"); - gtk_stack_add_named(main_stack, build_hwmap_page(), "hwmap"); - add_it_year_pages(main_stack); - gtk_stack_add_named(main_stack, build_onyears_page(), "onyears"); - gtk_stack_add_named(main_stack, build_onmap_page(), "onmap"); - add_on_pages(main_stack); - gtk_stack_add_named(main_stack, build_on2map_page(), "on2map"); - add_on2_pages(main_stack); - gtk_stack_add_named(main_stack, build_on3map_page(), "on3map"); - add_on3_pages(main_stack); - gtk_stack_add_named(main_stack, build_on4map_page(), "on4map"); - gtk_stack_add_named(main_stack, build_enyears_page(), "enyears"); - add_en_pages(main_stack); - add_on4_pages(main_stack); - gtk_stack_add_named(main_stack, build_matyears_page(), "matyears"); - gtk_stack_add_named(main_stack, build_mat0map_page(), "mat0map"); - add_mat0_pages(main_stack); - gtk_stack_add_named(main_stack, build_matmap_page(), "matmap"); - add_mat_pages(main_stack); - gtk_stack_add_named(main_stack, build_mat2map_page(), "mat2map"); - add_mat2_pages(main_stack); - gtk_stack_add_named(main_stack, build_mat3map_page(), "mat3map"); - add_mat3_pages(main_stack); - gtk_stack_add_named(main_stack, build_mat4map_page(), "mat4map"); - add_mat4_pages(main_stack); - gtk_stack_add_named(main_stack, build_fyzyears_page(), "fyzyears"); - gtk_stack_add_named(main_stack, build_fyzmap_page(), "fyzmap"); - add_fyz_pages(main_stack); - gtk_stack_add_named(main_stack, build_fyz2map_page(), "fyz2map"); - add_fyz2_pages(main_stack); - gtk_stack_add_named(main_stack, build_fyz3map_page(), "fyz3map"); - add_fyz3_pages(main_stack); - gtk_stack_add_named(main_stack, build_fyz4map_page(), "fyz4map"); - add_fyz4_pages(main_stack); - gtk_stack_add_named(main_stack, build_scimap_page(), "scimap"); - gtk_stack_add_named(main_stack, build_chemmap_page(), "chemmap"); - add_chem_pages(main_stack); - gtk_stack_add_named(main_stack, build_biomap_page(), "biomap"); - add_bio_pages(main_stack); - gtk_stack_add_named(main_stack, build_czechmap_page(), "czechmap"); - gtk_stack_add_named(main_stack, build_lityears_page(), "lityears"); - gtk_stack_add_named(main_stack, build_litmap_page(), "litmap"); - add_lit_pages(main_stack); - gtk_stack_add_named(main_stack, build_lit2map_page(), "lit2map"); - add_lit2_pages(main_stack); - gtk_stack_add_named(main_stack, build_lit3map_page(), "lit3map"); - add_lit3_pages(main_stack); - gtk_stack_add_named(main_stack, build_lit4map_page(), "lit4map"); - add_lit4_pages(main_stack); - gtk_stack_add_named(main_stack, build_mluvnice_page(), "mluvnice"); - for (int n = 1; n <= 20; n++) { - char name[16]; - - g_snprintf(name, sizeof(name), "mluve%d", n); - gtk_stack_add_named(main_stack, - build_mluvnice_exercise_page(n), name); - } - gtk_stack_add_named(main_stack, build_readinglist_page(), "readinglist"); - gtk_stack_add_named(main_stack, build_cetba1984_page(), "cetba1984"); - gtk_stack_add_named(main_stack, build_cetba1984_quiz_page(), - "cetba1984quiz"); - gtk_stack_add_named(main_stack, build_cetba1984_plot_page(), - "cetba1984dej"); - gtk_stack_add_named(main_stack, build_cetba_fuks_page(), "cetbaFuks"); - gtk_stack_add_named(main_stack, build_cetba_fuks_quiz_page(), - "cetbaFuksQuiz"); - gtk_stack_add_named(main_stack, build_cetba_fuks_plot_page(), - "cetbaFuksDej"); - gtk_stack_add_named(main_stack, build_cetba_stub_page(), "cetbastub"); - gtk_stack_add_named(main_stack, build_cetba_stub_quiz_page(), - "cetbastubquiz"); - gtk_stack_add_named(main_stack, build_cetba_stub_plot_page(), - "cetbastubdej"); - gtk_stack_add_named(main_stack, build_hw_unit1_page(), "hwunit1"); - gtk_stack_add_named(main_stack, build_hw_unit1_exercise_page(), "hwex1"); - gtk_stack_add_named(main_stack, build_hw_unit2_page(), "hwunit2"); - gtk_stack_add_named(main_stack, build_hw_unit2_exercise_page(), "hwex2"); - gtk_stack_add_named(main_stack, build_hw_unit3_page(), "hwunit3"); - gtk_stack_add_named(main_stack, build_hw_unit3_exercise_page(), "hwex3"); - gtk_stack_add_named(main_stack, build_hw_unit4_page(), "hwunit4"); - gtk_stack_add_named(main_stack, build_hw_unit4_exercise_page(), "hwex4"); - gtk_stack_add_named(main_stack, build_hw_unit5_page(), "hwunit5"); - gtk_stack_add_named(main_stack, build_hw_unit5_exercise_page(), "hwex5"); - gtk_stack_add_named(main_stack, build_hw_unit6_page(), "hwunit6"); - gtk_stack_add_named(main_stack, build_hw_unit6_exercise_page(), "hwex6"); - gtk_stack_add_named(main_stack, build_hw_unit7_page(), "hwunit7"); - gtk_stack_add_named(main_stack, build_hw_unit7_exercise_page(), "hwex7"); - gtk_stack_add_named(main_stack, build_hw_unit8_page(), "hwunit8"); - gtk_stack_add_named(main_stack, build_hw_unit8_exercise_page(), "hwex8"); - gtk_stack_add_named(main_stack, build_hw_unit9_page(), "hwunit9"); - gtk_stack_add_named(main_stack, build_hw_unit9_exercise_page(), "hwex9"); - gtk_stack_add_named(main_stack, build_hw_unit10_page(), "hwunit10"); - gtk_stack_add_named(main_stack, build_hw_unit10_exercise_page(), "hwex10"); - gtk_stack_add_named(main_stack, build_hw_unit11_page(), "hwunit11"); - gtk_stack_add_named(main_stack, build_hw_unit11_exercise_page(), "hwex11"); - gtk_stack_add_named(main_stack, build_hw_unit12_page(), "hwunit12"); - gtk_stack_add_named(main_stack, build_hw_unit12_exercise_page(), "hwex12"); - gtk_stack_add_named(main_stack, build_hw_unit13_page(), "hwunit13"); - gtk_stack_add_named(main_stack, build_hw_unit13_exercise_page(), "hwex13"); - gtk_stack_add_named(main_stack, build_hw_unit14_page(), "hwunit14"); - gtk_stack_add_named(main_stack, build_hw_unit14_exercise_page(), "hwex14"); - gtk_stack_add_named(main_stack, build_hw_unit15_page(), "hwunit15"); - gtk_stack_add_named(main_stack, build_hw_unit15_exercise_page(), "hwex15"); - gtk_stack_add_named(main_stack, build_hw_unit16_page(), "hwunit16"); - gtk_stack_add_named(main_stack, build_hw_unit16_exercise_page(), "hwex16"); - gtk_stack_add_named(main_stack, build_hw_unit17_page(), "hwunit17"); - gtk_stack_add_named(main_stack, build_hw_unit17_exercise_page(), "hwex17"); - gtk_stack_add_named(main_stack, build_hw_unit18_page(), "hwunit18"); - gtk_stack_add_named(main_stack, build_hw_unit18_exercise_page(), "hwex18"); - gtk_stack_add_named(main_stack, build_hw_unit19_page(), "hwunit19"); - gtk_stack_add_named(main_stack, build_hw_unit19_exercise_page(), "hwex19"); - gtk_stack_add_named(main_stack, build_hw_unit20_page(), "hwunit20"); - gtk_stack_add_named(main_stack, build_hw_unit20_exercise_page(), "hwex20"); - gtk_stack_add_named(main_stack, build_hw_unit21_page(), "hwunit21"); - gtk_stack_add_named(main_stack, build_hw_unit21_exercise_page(), "hwex21"); - gtk_stack_add_named(main_stack, build_hw_unit22_page(), "hwunit22"); - gtk_stack_add_named(main_stack, build_hw_unit22_exercise_page(), "hwex22"); - gtk_stack_add_named(main_stack, build_hw_unit23_page(), "hwunit23"); - gtk_stack_add_named(main_stack, build_hw_unit23_exercise_page(), "hwex23"); - gtk_stack_add_named(main_stack, build_hw_unit24_page(), "hwunit24"); - gtk_stack_add_named(main_stack, build_hw_unit24_exercise_page(), "hwex24"); - gtk_stack_add_named(main_stack, build_hw_unit25_page(), "hwunit25"); - gtk_stack_add_named(main_stack, build_hw_unit25_exercise_page(), "hwex25"); - gtk_stack_add_named(main_stack, build_hw_unit26_page(), "hwunit26"); - gtk_stack_add_named(main_stack, build_hw_unit26_exercise_page(), "hwex26"); - gtk_stack_add_named(main_stack, build_hw_unit27_page(), "hwunit27"); - gtk_stack_add_named(main_stack, build_hw_unit27_exercise_page(), "hwex27"); - gtk_stack_add_named(main_stack, build_hw_unit28_page(), "hwunit28"); - gtk_stack_add_named(main_stack, build_hw_unit28_exercise_page(), "hwex28"); - gtk_stack_add_named(main_stack, build_hw_unit29_page(), "hwunit29"); - gtk_stack_add_named(main_stack, build_hw_unit29_exercise_page(), "hwex29"); - { - typedef GtkWidget *(*NetBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - NetBuilder build_unit; - NetBuilder build_ex; - } net_pages[] = { - {"netunit1", "netex1", build_net_unit1_page, build_net_exercise_page}, - {"netunit2", "netex2", build_net_unit2_page, build_net_unit2_exercise_page}, - {"netunit3", "netex3", build_net_unit3_page, build_net_unit3_exercise_page}, - {"netunit4", "netex4", build_net_unit4_page, build_net_unit4_exercise_page}, - {"netunit5", "netex5", build_net_unit5_page, build_net_unit5_exercise_page}, - {"netunit6", "netex6", build_net_unit6_page, build_net_unit6_exercise_page}, - {"netunit7", "netex7", build_net_unit7_page, build_net_unit7_exercise_page}, - {"netunit8", "netex8", build_net_unit8_page, build_net_unit8_exercise_page}, - {"netunit9", "netex9", build_net_unit9_page, build_net_unit9_exercise_page}, - {"netunit10", "netex10", build_net_unit10_page, build_net_unit10_exercise_page}, - {"netunit11", "netex11", build_net_unit11_page, build_net_unit11_exercise_page}, - {"netunit12", "netex12", build_net_unit12_page, build_net_unit12_exercise_page}, - {"netunit13", "netex13", build_net_unit13_page, build_net_unit13_exercise_page}, - {"netunit14", "netex14", build_net_unit14_page, build_net_unit14_exercise_page}, - {"netunit15", "netex15", build_net_unit15_page, build_net_unit15_exercise_page}, - {"netunit16", "netex16", build_net_unit16_page, build_net_unit16_exercise_page}, - {"netunit17", "netex17", build_net_unit17_page, build_net_unit17_exercise_page}, - {"netunit18", "netex18", build_net_unit18_page, build_net_unit18_exercise_page}, - {"netunit19", "netex19", build_net_unit19_page, build_net_unit19_exercise_page}, - {"netunit20", "netex20", build_net_unit20_page, build_net_unit20_exercise_page}, - {"netunit21", "netex21", build_net_unit21_page, build_net_unit21_exercise_page}, - {"netunit22", "netex22", build_net_unit22_page, build_net_unit22_exercise_page}, - {"netunit23", "netex23", build_net_unit23_page, build_net_unit23_exercise_page}, - {"netunit24", "netex24", build_net_unit24_page, build_net_unit24_exercise_page}, - {"netunit25", "netex25", build_net_unit25_page, build_net_unit25_exercise_page}, - {"netunit26", "netex26", build_net_unit26_page, build_net_unit26_exercise_page}, - {"netunit27", "netex27", build_net_unit27_page, build_net_unit27_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(net_pages); i++) { - gtk_stack_add_named(main_stack, net_pages[i].build_unit(), - net_pages[i].unit_name); - gtk_stack_add_named(main_stack, net_pages[i].build_ex(), - net_pages[i].ex_name); - } - } - - for (int i = 0; i < NUM_UNLOCKED; i++) { - UnitCtx *u = &units[i]; - GtkWidget *map = build_unit_page(u); - - if (map) - gtk_stack_add_named(main_stack, map, u->page); - for (int n = 1; n <= u->n_ex; n++) { - GtkWidget *page = build_exercise_page(u, n); - char name[16]; - - if (!page) - continue; - g_snprintf(name, sizeof(name), "%se%d", u->ex_tag, n); - gtk_stack_add_named(main_stack, page, name); - } - if (u->has_branch && u->branch_target) { - GtkWidget *branch = build_translate(u); - - if (branch) - gtk_stack_add_named(main_stack, branch, u->branch_target); - } - } - - { - const char *start = g_getenv("MATURITA_PAGE"); - const char *size = g_getenv("MATURITA_SIZE"); - int w, h; - - gtk_stack_set_transition_type(main_stack, GTK_STACK_TRANSITION_TYPE_NONE); - if (start && *start) - gtk_stack_set_visible_child_name(main_stack, start); - else - gtk_stack_set_visible_child_name(main_stack, "welcome"); - gtk_stack_set_transition_type(main_stack, GTK_STACK_TRANSITION_TYPE_CROSSFADE); - gtk_stack_set_transition_duration(main_stack, 180); - if (size && sscanf(size, "%dx%d", &w, &h) == 2) - gtk_window_set_default_size(window, w, h); - } - - refresh_completion_ui(); - - keys = gtk_event_controller_key_new(); - gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(keys), - GTK_PHASE_CAPTURE); - g_signal_connect(keys, "key-pressed", - G_CALLBACK(on_window_key_pressed), window); - gtk_widget_add_controller(GTK_WIDGET(window), GTK_EVENT_CONTROLLER(keys)); - - apply_theme(); - apply_language(); - - gtk_widget_add_tick_callback(GTK_WIDGET(window), ui_scale_tick, NULL, NULL); - - update_init(); - - gtk_window_present(window); - - if (g_getenv("MATURITA_SETTINGS")) - g_timeout_add(350, open_settings_later, NULL); - if (g_getenv("MATURITA_SMOKE")) - g_timeout_add(200, run_smoke_test, NULL); - if (g_getenv("MATURITA_SHOT")) { - static int shot_tries; - - shot_tries = 0; - g_timeout_add(g_getenv("MATURITA_SETTINGS") ? 700 : 400, - shot_later, &shot_tries); - } -} - -int main(int argc, char **argv) { - GtkApplication *app; - int status; - - /* Resolve style.css / icons next to the binary (or AppImage / .app) and - * point progress files at a writable location before any I/O. */ - setup_portable_paths(); - - /* Must run before GtkApplication so Wayland can resolve our .desktop - * file / icons via the application id. */ - setup_portable_share_dir(); - - app = gtk_application_new(APP_ID, G_APPLICATION_DEFAULT_FLAGS); - g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); - status = g_application_run(G_APPLICATION(app), argc, argv); - clear_app_icon_textures(); - g_object_unref(app); - - return status; -} diff --git a/src/mat_year0.c b/src/mat_year0.c deleted file mode 100644 index ec7dbdf..0000000 --- a/src/mat_year0.c +++ /dev/null @@ -1,469 +0,0 @@ -#include "graduately.h" - -NetLesson mat0_lessons[MATH_N] = { - { .n_slides = 3, .unit_page = "mat0unit1", .ex_page = "mat0ex1" }, - { .n_slides = 3, .unit_page = "mat0unit2", .ex_page = "mat0ex2" }, - { .n_slides = 3, .unit_page = "mat0unit3", .ex_page = "mat0ex3" }, - { .n_slides = 3, .unit_page = "mat0unit4", .ex_page = "mat0ex4" }, - { .n_slides = 3, .unit_page = "mat0unit5", .ex_page = "mat0ex5" }, - { .n_slides = 3, .unit_page = "mat0unit6", .ex_page = "mat0ex6" }, - { .n_slides = 3, .unit_page = "mat0unit7", .ex_page = "mat0ex7" }, - { .n_slides = 3, .unit_page = "mat0unit8", .ex_page = "mat0ex8" }, -}; - -static GtkWidget *build_mat0_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Pravidlo", "Co se počítá dřív", - "Tip: násobení a dělení jsou stejně silné a jdou zleva doprava.", - { - "Nejprve se vyřeší závorky, zevnitř ven.", - "Pak jsou mocniny a odmocniny.", - "Násobení a dělení mají přednost před sčítáním a odčítáním.", - "Sčítání a odčítání se také provádějí zleva doprava.", - NULL, - }, - }, - { - "2 / 3 • Bez závorek", "Násobení má přednost", - "Tip: 2 + 3 · 4 není 20.", - { - "Ve výrazu 2 + 3 · 4 se nejdřív násobí: 3 · 4 = 12.", - "Teprve potom se přičtou dvě: 2 + 12 = 14.", - "Ve výrazu 20 − 6 / 2 se nejdřív dělí: 6 / 2 = 3.", - "Pak 20 − 3 = 17.", - NULL, - }, - }, - { - "3 / 3 • Závorky", "Závorka změní pořadí", - "Tip: závorka se chová jako jeden počet.", - { - "(8 − 3) · 2 začíná v závorce: 5 · 2 = 10.", - "3 · (4 + 1) je 3 · 5 = 15.", - "Bez závorky by 3 · 4 + 1 vyšlo 13.", - "Závorku proto pište vždy, když má sčítání předběhnout násobení.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[0], "mat0_unit1", "mat0_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit1_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte 2 + 3 · 4.", "num:14", "Násobení má přednost: 3 · 4 = 12 a 2 + 12 = 14. Výsledek je 14."}, - {"Spočítejte (8 − 3) · 2.", "num:10", "Nejdřív závorka: 8 − 3 = 5, potom 5 · 2 = 10. Výsledek je 10."}, - {"Spočítejte 20 − 6 / 2.", "num:17", "Nejdřív dělení: 6 / 2 = 3, potom 20 − 3 = 17. Výsledek je 17."}, - {"Spočítejte 3 · (4 + 1).", "num:15", "Nejdřív závorka: 4 + 1 = 5, potom 3 · 5 = 15. Výsledek je 15."}, - }; - - return math_practice_page(0, 0, "mat0unit1", - "mat0_ex1_title", "mat0_quiz1_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat0_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Součet", "Společný jmenovatel", - "Tip: zlomek v základním tvaru má nesoudělný čitatel a jmenovatel.", - { - "Sčítat a odčítat lze zlomky se stejným jmenovatelem.", - "Jinak se jmenovatelé rozšíří na nejmenší společný násobek.", - "1/2 + 1/3 má společný jmenovatel 6: 3/6 + 2/6 = 5/6.", - "3/4 − 1/4 = 2/4 = 1/2.", - NULL, - }, - }, - { - "2 / 3 • Součin", "Čitatel s čitatelem", - "Tip: před násobením jde často krátit křížem.", - { - "Zlomky se násobí čitatel čitatelem a jmenovatel jmenovatelem.", - "2/3 · 3/5 = 6/15 = 2/5.", - "Krátit se smí jen čitatel se jmenovatelem, ne dvě horní čísla mezi sebou.", - "Smíšené číslo se před počtem převede na zlomek.", - NULL, - }, - }, - { - "3 / 3 • Podíl", "Dělit znamená násobit převráceným", - "Tip: převrácený zlomek k a/b je b/a.", - { - "Dělení zlomkem je násobení jeho převrácenou hodnotou.", - "(3/4) : (1/2) = 3/4 · 2/1 = 6/4 = 3/2.", - "Výsledek se uvede v základním tvaru.", - "Nulou se dělit nesmí, proto jmenovatel nesmí vyjít 0.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[1], "mat0_unit2", "mat0_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit2_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte 1/2 + 1/3. Zlomek v základním tvaru.", "num:5/6", "Společný jmenovatel je 6: 3/6 + 2/6 = 5/6. Výsledek je 5/6."}, - {"Spočítejte 3/4 − 1/4.", "num:1/2", "Jmenovatel už je stejný: 2/4 = 1/2. Výsledek je 1/2."}, - {"Spočítejte 2/3 · 3/5.", "num:2/5", "6/15 se zkrátí třemi na 2/5. Výsledek je 2/5."}, - {"Spočítejte (3/4) : (1/2).", "num:3/2", "Násobí se převráceným zlomkem: 3/4 · 2/1 = 3/2. Výsledek je 3/2."}, - }; - - return math_practice_page(0, 1, "mat0unit2", - "mat0_ex2_title", "mat0_quiz2_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat0_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Zápis", "Čárka i tečka", - "Tip: 0,5 je totéž co 1/2.", - { - "Desetinná čárka odděluje celou část od desetin, setin a tisícin.", - "0,1 je jedna desetina, 0,01 je jedna setina.", - "Při sčítání se čárky píšou pod sebe.", - "2,5 + 1,5 = 4.", - NULL, - }, - }, - { - "2 / 3 • Násobení", "Čárka se posouvá", - "Tip: násobení deseti posune čárku o jedno místo doprava.", - { - "Počet desetinných míst součinu je součet počtů míst činitelů.", - "0,2 · 5 = 1, protože dvě desetiny pětkrát jsou jedna celá.", - "1,25 − 0,5 = 0,75, což je 3/4.", - "Výsledek lze psát desetinně i zlomkem.", - NULL, - }, - }, - { - "3 / 3 • Dělení", "Dělit desetinným číslem", - "Tip: dělitel se nejdřív upraví na celé číslo.", - { - "3,6 : 0,3 se rozšíří deseti na 36 : 3 = 12.", - "Čárka se v děliteli i děleném posune o stejný počet míst.", - "Dělení deseti posune čárku o jedno místo doleva.", - "Nulou se ani u desetinných čísel dělit nesmí.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[2], "mat0_unit3", "mat0_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit3_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte 2,5 + 1,5.", "num:4", "Pět desetin a pět desetin je jedna celá, celkem 4. Výsledek je 4."}, - {"Spočítejte 0,2 · 5.", "num:1", "Dvě desetiny pětkrát jsou 10 desetin, tedy 1. Výsledek je 1."}, - {"Spočítejte 3,6 : 0,3.", "num:12", "Posun čárky dá 36 : 3 = 12. Výsledek je 12."}, - {"Spočítejte 1,25 − 0,5.", "num:3/4", "1,25 − 0,50 = 0,75, tedy 3/4. Výsledek je 3/4."}, - }; - - return math_practice_page(0, 2, "mat0unit3", - "mat0_ex3_title", "mat0_quiz3_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat0_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Základ", "Jedno procento je setina", - "Tip: pište jen číslo, znak procenta ne.", - { - "1 % ze základu je jedna setina základu.", - "p % ze základu z je (p/100) · z.", - "20 % ze 150 je 0,2 · 150 = 30.", - "Základ, procentová část a počet procent jsou tři veličiny.", - NULL, - }, - }, - { - "2 / 3 • Kolik procent", "Část dělená základem", - "Tip: výsledek 0,25 znamená 25 %.", - { - "Počet procent je (část / základ) · 100.", - "15 ze 60 je 15/60 = 1/4, tedy 25 %.", - "Do odpovědi se píše 25, ne 0,25 a ne 25 %.", - "Zlomek se na procenta násobí stem.", - NULL, - }, - }, - { - "3 / 3 • Sleva a základ", "Dopočítání celku", - "Tip: sleva 10 % nechá z ceny 90 %.", - { - "Po slevě 10 % zbývá 90 % původní ceny.", - "400 − 10 % je 0,9 · 400 = 360.", - "Když 20 % základu je 18, je 1 % rovno 18/20.", - "Celý základ je pak 100 takových dílů: 90.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[3], "mat0_unit4", "mat0_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit4_exercise_page(void) { - static const MathItem qs[] = { - {"Kolik je 20 % ze 150? Napište jen číslo.", "num:30", "20 % je 0,2 a 0,2 · 150 = 30. Výsledek je 30."}, - {"15 je kolik procent z 60? Napište jen číslo, bez znaku %.", "num:25", "15/60 = 1/4 = 25 %. Výsledek je 25."}, - {"Cena 400 se sníží o 10 %. Jaká bude nová cena?", "num:360", "Zůstane 90 %: 0,9 · 400 = 360. Výsledek je 360."}, - {"20 % základu je 18. Jak velký je základ?", "num:90", "1 % je 18/20 = 0,9 a 100 % je 90. Výsledek je 90."}, - }; - - return math_practice_page(0, 3, "mat0unit4", - "mat0_ex4_title", "mat0_quiz4_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat0_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Poměr", "Díly celku", - "Tip: poměr 2 : 3 má dohromady 5 dílů.", - { - "Poměr a : b říká, na kolik stejných dílů se celek rozdělí.", - "Počet dílů je a + b.", - "První část je a/(a + b) z celku.", - "Z 20 v poměru 2 : 3 připadá na první část 8.", - NULL, - }, - }, - { - "2 / 3 • Úměra", "Součin vnějších a vnitřních členů", - "Tip: 3 : 5 = x : 20 znamená 3/5 = x/20.", - { - "V úměře a : b = c : d platí a · d = b · c.", - "Z 3/5 = x/20 vyjde x = 3/5 · 20 = 12.", - "Stejný poměr lze rozšiřovat i krátit.", - "Neznámý člen se dopočítá jedním násobením a jedním dělením.", - NULL, - }, - }, - { - "3 / 3 • Měřítko", "Mapa a skutečnost", - "Tip: 1 : 1000 znamená, že 1 cm na mapě je 10 m ve skutečnosti.", - { - "Měřítko 1 : k zmenšuje: skutečnost je k-krát větší než plán.", - "5 cm na mapě 1 : 1000 je 5000 cm, tedy 50 m.", - "Měřítko 5 : 1 je zvětšení, obraz je pětkrát větší.", - "4 cm v měřítku 5 : 1 odpovídá obrazu 20 cm.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[4], "mat0_unit5", "mat0_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit5_exercise_page(void) { - static const MathItem qs[] = { - {"Číslo 20 rozdělte v poměru 2 : 3. Jak velká je první část?", "num:8", "Dílů je 5 a první část jsou 2 z nich: 2/5 · 20 = 8. Výsledek je 8."}, - {"Na mapě 1 : 1000 jsou 5 cm. Kolik metrů je to ve skutečnosti?", "num:50", "5 cm · 1000 = 5000 cm = 50 m. Výsledek je 50."}, - {"Platí 3 : 5 = x : 20. Kolik je x?", "num:12", "x = 3/5 · 20 = 12. Výsledek je 12."}, - {"Úsečka 4 cm se zobrazí v měřítku 5 : 1. Jak dlouhý je obraz v centimetrech?", "num:20", "Měřítko 5 : 1 zvětšuje pětkrát: 4 · 5 = 20. Výsledek je 20."}, - }; - - return math_practice_page(0, 4, "mat0unit5", - "mat0_ex5_title", "mat0_quiz5_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat0_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Číselná osa", "Vpravo roste, vlevo klesá", - "Tip: přičíst kladné číslo znamená posun doprava.", - { - "Kladná čísla leží vpravo od nuly, záporná vlevo.", - "−3 + 8 je posun z −3 o 8 kroků doprava, tedy na 5.", - "Odčítání záporného čísla je totéž co přičítání kladného.", - "6 − (−2) = 6 + 2 = 8.", - NULL, - }, - }, - { - "2 / 3 • Násobení", "Znaménka", - "Tip: dvě záporná znaménka dají kladný součin.", - { - "Součin kladného a záporného čísla je záporný.", - "Součin dvou záporných čísel je kladný.", - "(−4) · (−5) = 20.", - "Stejné pravidlo platí pro dělení.", - NULL, - }, - }, - { - "3 / 3 • Absolutní hodnota", "Vzdálenost od nuly", - "Tip: absolutní hodnota nikdy není záporná.", - { - "|a| je vzdálenost čísla a od nuly na ose.", - "|−7| = 7 a |7| = 7.", - "|0| = 0.", - "Absolutní hodnota smaže znaménko, ale číslo jinak nezmění.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[5], "mat0_unit6", "mat0_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit6_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte −3 + 8.", "num:5", "Z −3 se jde o 8 doprava, na 5. Výsledek je 5."}, - {"Spočítejte (−4) · (−5).", "num:20", "Součin dvou záporných čísel je kladný: 20. Výsledek je 20."}, - {"Spočítejte |−7|.", "num:7", "Vzdálenost −7 od nuly je 7. Výsledek je 7."}, - {"Spočítejte 6 − (−2).", "num:8", "Odčítat −2 znamená přičíst 2: 6 + 2 = 8. Výsledek je 8."}, - }; - - return math_practice_page(0, 5, "mat0unit6", - "mat0_ex6_title", "mat0_quiz6_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat0_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Rovnováha", "Stejně na obě strany", - "Tip: co uděláte vlevo, udělejte i vpravo.", - { - "Rovnice říká, že levá strana se rovná pravé.", - "K oběma stranám lze přičíst stejné číslo.", - "Obě strany lze vynásobit stejným nenulovým číslem.", - "Cílem je osamostatnit neznámou.", - NULL, - }, - }, - { - "2 / 3 • Kroky", "Nejdřív číslo, pak koeficient", - "Tip: 2x − 4 = 10 se nejdřív zbaví čtyřky.", - { - "x + 5 = 12 se odečtením pěti změní na x = 7.", - "3x = 15 se vydělí třemi: x = 5.", - "2x − 4 = 10 dá po přičtení čtyř 2x = 14, tedy x = 7.", - "Zkouška dosadí výsledek do původní rovnice.", - NULL, - }, - }, - { - "3 / 3 • Dělení neznámé", "Zlomek s x", - "Tip: x/2 = 6 se násobí dvěma.", - { - "x/2 je totéž co (1/2) · x.", - "Násobení obou stran dvěma dá x = 12.", - "Násobit nulou se nesmí, rovnice by ztratila význam.", - "U lineární rovnice s nenulovým koeficientem je řešení jedno.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[6], "mat0_unit7", "mat0_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit7_exercise_page(void) { - static const MathItem qs[] = { - {"Vyřešte x + 5 = 12. Napište x.", "num:7", "Od obou stran se odečte 5. Výsledek je 7."}, - {"Vyřešte 3x = 15. Napište x.", "num:5", "Obě strany se vydělí 3. Výsledek je 5."}, - {"Vyřešte 2x − 4 = 10. Napište x.", "num:7", "2x = 14, takže x = 7. Výsledek je 7."}, - {"Vyřešte x/2 = 6. Napište x.", "num:12", "Obě strany se násobí 2. Výsledek je 12."}, - }; - - return math_practice_page(0, 6, "mat0unit7", - "mat0_ex7_title", "mat0_quiz7_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat0_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Obdélník", "Obvod a obsah", - "Tip: obvod je součet všech stran, obsah je součin dvou sousedních.", - { - "Obdélník a × b má obvod 2 · (a + b).", - "Obdélník 5 × 3 má obvod 2 · 8 = 16.", - "Obsah je a · b. Obdélník 6 × 4 má obsah 24.", - "Jednotky obvodu jsou délkové, jednotky obsahu čtvereční.", - NULL, - }, - }, - { - "2 / 3 • Trojúhelník", "Základna a výška", - "Tip: výška je kolmá na základnu, ne délka šikmé strany.", - { - "Součet vnitřních úhlů trojúhelníku je 180°.", - "Třetí úhel je 180° minus součet dvou známých.", - "Úhly 60° a 50° doplňuje 70°.", - "Obsah je (základna · výška) / 2. Pro 8 a 5 je to 20.", - NULL, - }, - }, - { - "3 / 3 • Čtverec", "Doplnění na mřížce", - "Tip: osa y míří nahoru. Klepnutím na bod ho odeberete.", - { - "Čtverec má čtyři shodné strany a čtyři pravé úhly.", - "Druhé dva vrcholy vzniknou posunutím strany o stejnou délku kolmo.", - "U vodorovné strany leží zbývající vrcholy přímo nad ní, nebo pod ní.", - "Na mřížce jsou platné jen oba vrcholy téže strany.", - NULL, - }, - }, - }; - - return math_unit_page(0, &mat0_lessons[7], "mat0_unit8", "mat0_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat0_unit8_exercise_page(void) { - static const MathItem qs[] = { - {"Obdélník má strany 5 a 3. Jaký je jeho obvod?", "num:16", "2 · (5 + 3) = 16. Výsledek je 16."}, - {"Obdélník má strany 6 a 4. Jaký je jeho obsah?", "num:24", "Obsah je 6 · 4 = 24. Výsledek je 24."}, - {"Trojúhelník má základnu 8 a výšku 5. Jaký je jeho obsah?", "num:20", "Obsah je (8 · 5) / 2 = 20. Výsledek je 20."}, - {"Dva úhly trojúhelníku jsou 60° a 50°. Jak velký je třetí úhel ve stupních?", "num:70", "Součet je 180°, takže třetí úhel je 70°. Výsledek je 70."}, - {"Na mřížce je strana čtverce od A = [2; 3] k B = [5; 3]. Doplňte zbývající dva vrcholy.", "square:2,3;5,3", "Strana má délku 3. Druhé dva vrcholy jsou [2; 6] a [5; 6], nebo [2; 0] a [5; 0]."}, - }; - - return math_practice_page(0, 7, "mat0unit8", - "mat0_ex8_title", "mat0_quiz8_head", - qs, G_N_ELEMENTS(qs)); -} - -void add_mat0_pages(GtkStack *stack) { - typedef GtkWidget *(*MathBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - MathBuilder build_unit; - MathBuilder build_ex; - } pages[] = { - {"mat0unit1", "mat0ex1", build_mat0_unit1_page, build_mat0_unit1_exercise_page}, - {"mat0unit2", "mat0ex2", build_mat0_unit2_page, build_mat0_unit2_exercise_page}, - {"mat0unit3", "mat0ex3", build_mat0_unit3_page, build_mat0_unit3_exercise_page}, - {"mat0unit4", "mat0ex4", build_mat0_unit4_page, build_mat0_unit4_exercise_page}, - {"mat0unit5", "mat0ex5", build_mat0_unit5_page, build_mat0_unit5_exercise_page}, - {"mat0unit6", "mat0ex6", build_mat0_unit6_page, build_mat0_unit6_exercise_page}, - {"mat0unit7", "mat0ex7", build_mat0_unit7_page, build_mat0_unit7_exercise_page}, - {"mat0unit8", "mat0ex8", build_mat0_unit8_page, build_mat0_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/mat_year1.c b/src/mat_year1.c deleted file mode 100644 index e14e245..0000000 --- a/src/mat_year1.c +++ /dev/null @@ -1,468 +0,0 @@ -#include "graduately.h" - -NetLesson mat_lessons[MATH_N] = { - { .n_slides = 3, .unit_page = "matunit1", .ex_page = "matex1" }, - { .n_slides = 3, .unit_page = "matunit2", .ex_page = "matex2" }, - { .n_slides = 3, .unit_page = "matunit3", .ex_page = "matex3" }, - { .n_slides = 3, .unit_page = "matunit4", .ex_page = "matex4" }, - { .n_slides = 3, .unit_page = "matunit5", .ex_page = "matex5" }, - { .n_slides = 3, .unit_page = "matunit6", .ex_page = "matex6" }, - { .n_slides = 3, .unit_page = "matunit7", .ex_page = "matex7" }, - { .n_slides = 3, .unit_page = "matunit8", .ex_page = "matex8" }, -}; - -static GtkWidget *build_mat_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Dělitel", "Čísla, která dělí beze zbytku", - "Tip: prvočíslo má právě dva dělitele, jedničku a sebe.", - { - "Dělitel čísla a je celé číslo, kterým a dělí beze zbytku.", - "Číslo 12 má dělitele 1, 2, 3, 4, 6 a 12, tedy šest dělitelů.", - "Prvočíslo nelze rozložit na součin dvou menších celých čísel větších než 1.", - "Jednička prvočíslo není.", - NULL, - }, - }, - { - "2 / 3 • NSD a NSN", "Společný dělitel a násobek", - "Tip: NSD · NSN dvou čísel je jejich součin.", - { - "Největší společný dělitel je největší číslo, které dělí obě čísla.", - "NSD(24, 36) = 12.", - "Nejmenší společný násobek je nejmenší kladné číslo, které je násobkem obou.", - "NSN(6, 8) = 24.", - NULL, - }, - }, - { - "3 / 3 • Rozklad", "Součin mocnin prvočísel", - "Tip: společné prvočinitele berte v nejmenší mocnině pro NSD.", - { - "Každé celé číslo větší než 1 má jediný rozklad na prvočísla.", - "72 = 2³ · 3².", - "V NSD se bere nižší exponent, v NSN vyšší.", - "Rozklad usnadní krácení zlomků i hledání společného jmenovatele.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[0], "mat_unit1", "mat_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit1_exercise_page(void) { - static const MathItem qs[] = { - {"Jaký je největší společný dělitel čísel 24 a 36?", "num:12", "Společní dělitelé jsou 1, 2, 3, 4, 6 a 12. Výsledek je 12."}, - {"Jaký je nejmenší společný násobek čísel 6 a 8?", "num:24", "Násobky 6 jsou 6, 12, 18, 24, … a 24 je první z nich dělitelné osmi. Výsledek je 24."}, - {"Spočítejte 2³ · 3².", "num:72", "8 · 9 = 72. Výsledek je 72."}, - {"Kolik kladných dělitelů má číslo 12?", "num:6", "Jsou to 1, 2, 3, 4, 6 a 12. Výsledek je 6."}, - }; - - return math_practice_page(1, 0, "matunit1", - "mat_ex1_title", "mat_quiz1_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Mocnina", "Opakované násobení", - "Tip: aⁿ je a násobené sebou n-krát.", - { - "2⁵ = 2 · 2 · 2 · 2 · 2 = 32.", - "10³ = 1000, tři nuly za jedničkou.", - "Každé číslo na první je ono samo a a⁰ = 1 pro a ≠ 0.", - "Záporný exponent znamená převrácenou hodnotu mocniny.", - NULL, - }, - }, - { - "2 / 3 • Pravidla", "Stejný základ", - "Tip: (aᵐ)ⁿ = aᵐ·ⁿ.", - { - "aᵐ · aⁿ = aᵐ⁺ⁿ.", - "aᵐ : aⁿ = aᵐ⁻ⁿ pro a ≠ 0.", - "(a · b)ⁿ = aⁿ · bⁿ.", - "(2³)² = 2⁶ = 64.", - NULL, - }, - }, - { - "3 / 3 • Odmocnina", "Druhá odmocnina", - "Tip: √a je nezáporné číslo, jehož druhá mocnina je a.", - { - "√81 = 9, protože 9² = 81.", - "√0 = 0 a √1 = 1.", - "Ze záporného čísla se v reálných číslech druhá odmocnina nedělá.", - "√(a²) = |a|, ne vždy a.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[1], "mat_unit2", "mat_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit2_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte 2⁵.", "num:32", "Pět dvojkových činitelů je 32. Výsledek je 32."}, - {"Spočítejte 10³.", "num:1000", "10 · 10 · 10 = 1000. Výsledek je 1000."}, - {"Spočítejte √81.", "num:9", "9 · 9 = 81. Výsledek je 9."}, - {"Spočítejte (2³)².", "num:64", "(8)² = 64, nebo 2⁶ = 64. Výsledek je 64."}, - }; - - return math_practice_page(1, 1, "matunit2", - "mat_ex2_title", "mat_quiz2_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Dosazení", "Písmeno je číslo", - "Tip: nejdřív závorky, potom mocniny a násobení.", - { - "Do výrazu se za proměnnou dosadí dané číslo.", - "2(x + 3) při x = 4 je 2 · 7 = 14.", - "3x − 2x + 5 se nejdřív sloučí na x + 5.", - "Při x = 2 je x + 5 = 7.", - NULL, - }, - }, - { - "2 / 3 • Vzorce", "Druhá mocnina dvojčlenu", - "Tip: (a + b)² není a² + b².", - { - "(a + b)² = a² + 2ab + b².", - "(a − b)² = a² − 2ab + b².", - "a² − b² = (a − b)(a + b).", - "Pro a = 3 a b = 1 je (a + b)² = 16.", - NULL, - }, - }, - { - "3 / 3 • Zkrácení", "Rozdíl čtverců", - "Tip: krátit lze jen pro x, která nejsou kořenem jmenovatele.", - { - "x² − 9 = (x − 3)(x + 3).", - "(x² − 9)/(x − 3) = x + 3 pro x ≠ 3.", - "Při x = 5 je hodnota 8.", - "Dosazení x = 3 by dělilo nulou, výraz tam není definován.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[2], "mat_unit3", "mat_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit3_exercise_page(void) { - static const MathItem qs[] = { - {"Do výrazu 2(x + 3) dosažte x = 4.", "num:14", "2 · (4 + 3) = 14. Výsledek je 14."}, - {"Do výrazu (a + b)² dosažte a = 3 a b = 1.", "num:16", "4² = 16. Rozepsáno 9 + 6 + 1 = 16. Výsledek je 16."}, - {"Do výrazu 3x − 2x + 5 dosažte x = 2.", "num:7", "Výraz je x + 5, při x = 2 je 7. Výsledek je 7."}, - {"Do výrazu (x² − 9)/(x − 3) dosažte x = 5.", "num:8", "Pro x ≠ 3 je výraz roven x + 3, tedy 8. Výsledek je 8."}, - }; - - return math_practice_page(1, 2, "matunit3", - "mat_ex3_title", "mat_quiz3_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Převod", "Neznámé na jednu stranu", - "Tip: člen s x se převádí s opačným znaménkem.", - { - "2x + 1 = 9 se odečtením jedné změní na 2x = 8.", - "x = 4.", - "Členy s x patří obvykle vlevo, čísla vpravo.", - "Po každé úpravě zůstává rovnost zachovaná.", - NULL, - }, - }, - { - "2 / 3 • Obě strany", "Stejný člen vlevo i vpravo", - "Tip: 5x − 3 = 2x + 9 se zbaví 2x odečtením.", - { - "5x − 2x = 9 + 3.", - "3x = 12 a x = 4.", - "Zkouška: levá strana 5 · 4 − 3 = 17, pravá 8 + 9 = 17.", - "Když koeficient u x vyjde 0, rovnice buď nemá řešení, nebo jich má nekonečně mnoho.", - NULL, - }, - }, - { - "3 / 3 • Závorka a zlomek", "Nejdřív roznásobit", - "Tip: x/2 + 1 = 5 se nejdřív zbaví jedničky.", - { - "x/2 + 1 = 5 dá x/2 = 4, tedy x = 8.", - "3(x − 2) = 12 se vydělí třemi: x − 2 = 4.", - "Nebo se závorka roznásobí: 3x − 6 = 12.", - "Obě cesty dají x = 6.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[3], "mat_unit4", "mat_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit4_exercise_page(void) { - static const MathItem qs[] = { - {"Vyřešte 2x + 1 = 9. Napište x.", "num:4", "2x = 8, takže x = 4. Výsledek je 4."}, - {"Vyřešte 5x − 3 = 2x + 9. Napište x.", "num:4", "3x = 12, takže x = 4. Výsledek je 4."}, - {"Vyřešte x/2 + 1 = 5. Napište x.", "num:8", "x/2 = 4, takže x = 8. Výsledek je 8."}, - {"Vyřešte 3(x − 2) = 12. Napište x.", "num:6", "x − 2 = 4, takže x = 6. Výsledek je 6."}, - }; - - return math_practice_page(1, 3, "matunit4", - "mat_ex4_title", "mat_quiz4_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Dráha", "Rychlost krát čas", - "Tip: jednotky času a rychlosti musí patřit k sobě.", - { - "Při stálé rychlosti je dráha s = v · t.", - "60 km/h po dobu 2,5 h urazí 150 km.", - "2,5 h je dvě a půl hodiny, ne dvě hodiny a padesát minut.", - "Z dráhy a času se rychlost dopočítá jako s/t.", - NULL, - }, - }, - { - "2 / 3 • Práce a směs", "Sčítají se výkony, ne časy", - "Tip: kdo práci udělá za 3 hodiny, udělá za hodinu třetinu.", - { - "První pracovník udělá za hodinu 1/6 práce, druhý 1/3.", - "Společně udělají 1/6 + 2/6 = 1/2 práce za hodinu, tedy celou za 2 hodiny.", - "U směsi se sčítá množství čisté látky.", - "2 kg dvacetiprocentní a 3 kg desetiprocentní směsi obsahují 0,4 + 0,3 = 0,7 kg, tedy 14 %.", - NULL, - }, - }, - { - "3 / 3 • Sleva", "Nová cena je část základu", - "Tip: po slevě 20 % zbývá 80 % původní ceny.", - { - "Když je nová cena 160 a sleva byla 20 %, je 160 rovno 80 % původní ceny.", - "Původní cena je 160 / 0,8 = 200.", - "Sleva v korunách je pak 40.", - "Nepleťte si slevu 20 % s tím, že se k nové ceně přičte 20 %.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[4], "mat_unit5", "mat_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit5_exercise_page(void) { - static const MathItem qs[] = { - {"Auto jede 2,5 hodiny rychlostí 60 km/h. Kolik kilometrů ujede?", "num:150", "s = v · t = 60 · 2,5 = 150. Výsledek je 150."}, - {"První pracovník práci udělá za 6 hodin, druhý za 3 hodiny. Za kolik hodin ji udělají společně?", "num:2", "Za hodinu spolu udělají 1/2 práce, celou tedy za 2 hodiny. Výsledek je 2."}, - {"Smíchají se 2 kg směsi s 20 % látky a 3 kg směsi s 10 % látky. Kolik procent látky má směs? Napište jen číslo.", "num:14", "Čisté látky je 0,7 kg z 5 kg, tedy 14 %. Výsledek je 14."}, - {"Po slevě 20 % stojí zboží 160. Jaká byla původní cena?", "num:200", "160 je 80 % původní ceny, základ je 200. Výsledek je 200."}, - }; - - return math_practice_page(1, 4, "matunit5", - "mat_ex5_title", "mat_quiz5_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Trojúhelník", "Součet 180°", - "Tip: rovnoramenný trojúhelník má dvě ramena a dva úhly u základny shodné.", - { - "Součet vnitřních úhlů každého trojúhelníku je 180°.", - "V rovnoramenném trojúhelníku jsou úhly při základně shodné.", - "Když jsou úhly při základně 70°, je úhel proti základně 40°.", - "Rovnostranný trojúhelník má všechny strany shodné a každý úhel 60°.", - NULL, - }, - }, - { - "2 / 3 • Vnější úhel", "Součet dvou vzdálených vnitřních", - "Tip: vnější úhel a sousední vnitřní úhel dávají 180°.", - { - "Vnější úhel vznikne prodloužením jedné strany.", - "Je roven součtu dvou vnitřních úhlů, které s ním nesousedí.", - "Vnitřní úhly 40° a 60° dávají vnější úhel 100° u zbývajícího vrcholu.", - "Součet vnějšího úhlu a přilehlého vnitřního je 180°.", - NULL, - }, - }, - { - "3 / 3 • Mnohoúhelník", "Pravidelný šestiúhelník", - "Tip: součet vnitřních úhlů n-úhelníku je (n − 2) · 180°.", - { - "Trojúhelník má součet 180°, čtyřúhelník 360°.", - "Obecný vzorec je (n − 2) · 180°.", - "Pravidelný mnohoúhelník má všechny strany i úhly shodné.", - "Pravidelný šestiúhelník má vnitřní úhel 720° / 6 = 120°.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[5], "mat_unit6", "mat_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit6_exercise_page(void) { - static const MathItem qs[] = { - {"Vnější úhel trojúhelníku je součet vnitřních úhlů 40° a 60°. Jak je velký ve stupních?", "num:100", "Vnější úhel se rovná součtu dvou nesousedních vnitřních úhlů: 100°. Výsledek je 100."}, - {"Rovnoramenný trojúhelník má úhly při základně 70°. Jak velký je úhel proti základně?", "num:40", "180° − 140° = 40°. Výsledek je 40."}, - {"Rovnostranný trojúhelník má stranu 6. Jaký je jeho obvod?", "num:18", "Tři shodné strany: 3 · 6 = 18. Výsledek je 18."}, - {"Jak velký je jeden vnitřní úhel pravidelného šestiúhelníku ve stupních?", "num:120", "Součet je (6 − 2) · 180° = 720° a jeden úhel je 120°. Výsledek je 120."}, - }; - - return math_practice_page(1, 5, "matunit6", - "mat_ex6_title", "mat_quiz6_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Kružnice", "Obvod a obsah", - "Tip: u výsledku s π nechte π ve výrazu a pište ho jako pi.", - { - "Kružnice s poloměrem r má obvod 2πr.", - "Obsah kruhu je πr².", - "Pro r = 7 je obvod 14π.", - "Pro r = 3 je obsah 9π.", - NULL, - }, - }, - { - "2 / 3 • Lichoběžník", "Dvě základny a výška", - "Tip: obsah je průměr základen krát výška.", - { - "Lichoběžník má právě jednu dvojici rovnoběžných stran, základny a a c.", - "Obsah je (a + c) · v / 2.", - "Základny 4 a 6 a výška 3 dávají obsah 15.", - "Výška je kolmá vzdálenost základen.", - NULL, - }, - }, - { - "3 / 3 • Pythagoras", "Pravoúhlý trojúhelník", - "Tip: přepona je nejdelší strana a leží proti pravému úhlu.", - { - "V pravoúhlém trojúhelníku je a² + b² = c².", - "c je přepona, a a b jsou odvěsny.", - "Trojúhelník 5, 12, 13 je pravoúhlý, protože 25 + 144 = 169.", - "Přepona je 13.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[6], "mat_unit7", "mat_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit7_exercise_page(void) { - static const MathItem qs[] = { - {"Jaký je obvod kružnice s poloměrem 7? Nechte výsledek v násobcích π.", "num:14*pi", "Obvod je 2πr = 14π. Výsledek je 14π."}, - {"Jaký je obsah kruhu s poloměrem 3? Nechte výsledek v násobcích π.", "num:9*pi", "Obsah je πr² = 9π. Výsledek je 9π."}, - {"Lichoběžník má základny 4 a 6 a výšku 3. Jaký je jeho obsah?", "num:15", "(4 + 6) · 3 / 2 = 15. Výsledek je 15."}, - {"Pravoúhlý trojúhelník má odvěsny 5 a 12. Jak dlouhá je přepona?", "num:13", "5² + 12² = 25 + 144 = 169 = 13². Výsledek je 13."}, - }; - - return math_practice_page(1, 6, "matunit7", - "mat_ex7_title", "mat_quiz7_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Body", "Vzdálenost na mřížce", - "Tip: u svislé nebo vodorovné úsečky stačí rozdíl souřadnic.", - { - "Bod v rovině má souřadnice [x; y].", - "Vzdálenost [x₁; y₁] a [x₂; y₂] je √((x₂ − x₁)² + (y₂ − y₁)²).", - "A = [1; 1] a B = [5; 1] mají vzdálenost 4.", - "Osa y na naší mřížce míří nahoru.", - NULL, - }, - }, - { - "2 / 3 • SSS", "Trojúhelník ze tří stran", - "Tip: třetí vrchol je průsečík dvou kružnic.", - { - "Konstrukce SSS použije tři strany.", - "Z bodu A se rýsuje kružnice o poloměru |AC|, z bodu B o poloměru |BC|.", - "Kružnice se protnou ve dvou bodech, pokud trojúhelník existuje.", - "Trojúhelníková nerovnost: součet dvou stran je větší než třetí.", - NULL, - }, - }, - { - "3 / 3 • Příklad", "Strany 4, 3 a 5", - "Tip: 3² + 4² = 5², pravý úhel je u bodu A.", - { - "A = [1; 1], B = [5; 1], takže |AB| = 4.", - "Hledáme C tak, aby |AC| = 3 a |BC| = 5.", - "Na mřížce od 0 do 10 a od 0 do 8 leží jen C = [1; 4].", - "Druhý průsečík [1; −2] je pod mřížkou.", - NULL, - }, - }, - }; - - return math_unit_page(1, &mat_lessons[7], "mat_unit8", "mat_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat_unit8_exercise_page(void) { - static const MathItem qs[] = { - {"Jaká je vzdálenost bodů A = [1; 1] a B = [5; 1]?", "num:4", "Body mají stejné y, vzdálenost je 5 − 1 = 4. Výsledek je 4."}, - {"Jaký je obsah pravoúhlého trojúhelníku s odvěsnami 3 a 4?", "num:6", "Obsah je (3 · 4) / 2 = 6. Výsledek je 6."}, - {"Jaký je obvod trojúhelníku se stranami 3, 4 a 5?", "num:12", "3 + 4 + 5 = 12. Výsledek je 12."}, - {"A = [1; 1] a B = [5; 1] jsou dané. Zakreslete C, pro které je |AC| = 3 a |BC| = 5.", "points:1,4;fix:1,1;fix:5,1", "Kružnice se na mřížce protnou v [1; 4]. Bod [1; −2] už na ní není."}, - }; - - return math_practice_page(1, 7, "matunit8", - "mat_ex8_title", "mat_quiz8_head", - qs, G_N_ELEMENTS(qs)); -} - -void add_mat_pages(GtkStack *stack) { - typedef GtkWidget *(*MathBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - MathBuilder build_unit; - MathBuilder build_ex; - } pages[] = { - {"matunit1", "matex1", build_mat_unit1_page, build_mat_unit1_exercise_page}, - {"matunit2", "matex2", build_mat_unit2_page, build_mat_unit2_exercise_page}, - {"matunit3", "matex3", build_mat_unit3_page, build_mat_unit3_exercise_page}, - {"matunit4", "matex4", build_mat_unit4_page, build_mat_unit4_exercise_page}, - {"matunit5", "matex5", build_mat_unit5_page, build_mat_unit5_exercise_page}, - {"matunit6", "matex6", build_mat_unit6_page, build_mat_unit6_exercise_page}, - {"matunit7", "matex7", build_mat_unit7_page, build_mat_unit7_exercise_page}, - {"matunit8", "matex8", build_mat_unit8_page, build_mat_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/mat_year2.c b/src/mat_year2.c deleted file mode 100644 index 91df414..0000000 --- a/src/mat_year2.c +++ /dev/null @@ -1,468 +0,0 @@ -#include "graduately.h" - -NetLesson mat2_lessons[MATH_N] = { - { .n_slides = 3, .unit_page = "mat2unit1", .ex_page = "mat2ex1" }, - { .n_slides = 3, .unit_page = "mat2unit2", .ex_page = "mat2ex2" }, - { .n_slides = 3, .unit_page = "mat2unit3", .ex_page = "mat2ex3" }, - { .n_slides = 3, .unit_page = "mat2unit4", .ex_page = "mat2ex4" }, - { .n_slides = 3, .unit_page = "mat2unit5", .ex_page = "mat2ex5" }, - { .n_slides = 3, .unit_page = "mat2unit6", .ex_page = "mat2ex6" }, - { .n_slides = 3, .unit_page = "mat2unit7", .ex_page = "mat2ex7" }, - { .n_slides = 3, .unit_page = "mat2unit8", .ex_page = "mat2ex8" }, -}; - -static GtkWidget *build_mat2_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Předpis", "y = ax + b", - "Tip: a je směrnice, b je úsek na ose y.", - { - "Lineární funkce má předpis f(x) = ax + b.", - "Grafem je přímka.", - "b je hodnota f(0), tedy průsečík s osou y.", - "Pro f(x) = 2x − 3 je průsečík s osou y číslo −3.", - NULL, - }, - }, - { - "2 / 3 • Směrnice", "O kolik y vzroste", - "Tip: směrnice je podíl změny y a změny x.", - { - "Mezi body [x₁; y₁] a [x₂; y₂] je a = (y₂ − y₁)/(x₂ − x₁).", - "Body [1; 2] a [3; 8] dávají směrnici (8 − 2)/(3 − 1) = 3.", - "Kladná směrnice znamená růst, záporná pokles.", - "Nulová směrnice je vodorovná přímka.", - NULL, - }, - }, - { - "3 / 3 • Hodnota a kořen", "Dosazení a rovnice", - "Tip: nulový bod je x, pro které je f(x) = 0.", - { - "f(4) u funkce 2x − 3 je 8 − 3 = 5.", - "Rovnice 2x − 6 = 0 má řešení x = 3.", - "To je průsečík přímky y = 2x − 6 s osou x.", - "Lineární funkce s a ≠ 0 má právě jeden nulový bod.", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[0], "mat2_unit1", "mat2_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit1_exercise_page(void) { - static const MathItem qs[] = { - {"Funkce f(x) = 2x − 3. Kolik je f(4)?", "num:5", "2 · 4 − 3 = 5. Výsledek je 5."}, - {"Jaký je průsečík funkce f(x) = 2x − 3 s osou y?", "num:-3", "f(0) = −3. Výsledek je -3."}, - {"Jaká je směrnice přímky body [1; 2] a [3; 8]?", "num:3", "(8 − 2)/(3 − 1) = 3. Výsledek je 3."}, - {"Vyřešte 2x − 6 = 0. Napište x.", "num:3", "2x = 6, takže x = 3. Výsledek je 3."}, - }; - - return math_practice_page(2, 0, "mat2unit1", - "mat2_ex1_title", "mat2_quiz1_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat2_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Dvojice", "Jedno x a jedno y", - "Tip: výsledek pište x;y, nejdřív x.", - { - "Soustava dvou lineárních rovnic hledá dvojici [x; y], která vyhovuje oběma.", - "Řešením je průsečík dvou přímek.", - "Sčítací metoda sečte rovnice tak, aby jedna neznámá zmizela.", - "Dosazovací metoda vyjádří jednu neznámou a dosadí ji do druhé rovnice.", - NULL, - }, - }, - { - "2 / 3 • Sčítání", "Opačné koeficienty", - "Tip: x + y = 10 a x − y = 2 se sčítají na 2x = 12.", - { - "Součet dá 2x = 12, tedy x = 6.", - "Z x + y = 10 je y = 4.", - "Zkouška ve druhé rovnici: 6 − 4 = 2.", - "Odečtení rovnic se použije, když má neznámá v obou stejný koeficient.", - NULL, - }, - }, - { - "3 / 3 • Odečtení", "Stejný koeficient", - "Tip: rovnice lze před odečtením násobit.", - { - "2x + y = 8 a x + y = 5 se odečtou na x = 3.", - "Pak y = 2.", - "3x + y = 10 a x + y = 6 dají 2x = 4, tedy x = 2 a y = 4.", - "x + y = 7 a x − y = 1 dají x = 4 a y = 3.", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[1], "mat2_unit2", "mat2_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit2_exercise_page(void) { - static const MathItem qs[] = { - {"Vyřešte soustavu x + y = 10 a x − y = 2. Napište x a y oddělené středníkem.", "pair:6;4", "Sečtení dá 2x = 12, x = 6 a y = 4. Napište 6;4."}, - {"Vyřešte soustavu 2x + y = 8 a x + y = 5. Napište x a y oddělené středníkem.", "pair:3;2", "Odečtení dá x = 3 a y = 2. Napište 3;2."}, - {"Vyřešte soustavu x + y = 7 a x − y = 1. Napište x a y oddělené středníkem.", "pair:4;3", "Sečtení dá 2x = 8, x = 4 a y = 3. Napište 4;3."}, - {"Vyřešte soustavu 3x + y = 10 a x + y = 6. Napište x a y oddělené středníkem.", "pair:2;4", "Odečtení dá 2x = 4, x = 2 a y = 4. Napište 2;4."}, - }; - - return math_practice_page(2, 1, "mat2unit2", - "mat2_ex2_title", "mat2_quiz2_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat2_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tvar", "ax² + bx + c = 0", - "Tip: kořeny pište oddělené středníkem, pořadí nehraje roli.", - { - "Kvadratická rovnice má a ≠ 0.", - "Kořeny rovnice x² − 5x + 6 = 0 jsou 2 a 3, protože (x − 2)(x − 3) = 0.", - "x² − 4 = 0 má kořeny −2 a 2.", - "Součin je nula, právě když je nula aspoň jeden činitel.", - NULL, - }, - }, - { - "2 / 3 • Diskriminant", "D = b² − 4ac", - "Tip: D > 0 znamená dva různé reálné kořeny.", - { - "Pro ax² + bx + c = 0 je D = b² − 4ac.", - "U x² − 2x − 3 je a = 1, b = −2, c = −3 a D = 4 + 12 = 16.", - "D = 0 znamená jeden dvojnásobný kořen.", - "D < 0 znamená, že v reálných číslech řešení není.", - NULL, - }, - }, - { - "3 / 3 • Vzorec", "Kořen je (−b ± √D) / (2a)", - "Tip: dvojnásobný kořen x² + 6x + 9 = 0 je −3.", - { - "x = (−b ± √D) / (2a).", - "x² + 6x + 9 = (x + 3)², takže kořen −3 je dvojnásobný.", - "U dvojnásobného kořene stačí napsat číslo jednou.", - "Zkouška dosadí kořen zpět do rovnice.", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[2], "mat2_unit3", "mat2_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit3_exercise_page(void) { - static const MathItem qs[] = { - {"Najděte kořeny rovnice x² − 5x + 6 = 0. Oddělte je středníkem.", "set:2;3", "(x − 2)(x − 3) = 0. Napište 2;3."}, - {"Najděte kořeny rovnice x² − 4 = 0. Oddělte je středníkem.", "set:-2;2", "x² = 4, takže x = −2 nebo x = 2. Napište -2;2."}, - {"Jaký je diskriminant rovnice x² − 2x − 3 = 0?", "num:16", "D = (−2)² − 4 · 1 · (−3) = 4 + 12 = 16. Výsledek je 16."}, - {"Jaký je dvojnásobný kořen rovnice x² + 6x + 9 = 0?", "num:-3", "(x + 3)² = 0, kořen je −3. Výsledek je -3."}, - }; - - return math_practice_page(2, 2, "mat2unit3", - "mat2_ex3_title", "mat2_quiz3_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat2_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Obor", "Jmenovatel nesmí být nula", - "Tip: podmínku pište dřív, než krátíte.", - { - "Lomený výraz je podíl dvou mnohočlenů.", - "Není definován tam, kde je jmenovatel nula.", - "(x + 2)/(x − 2) nemá smysl pro x = 2.", - "Po krácení se vyloučené hodnoty do oboru nevracejí.", - NULL, - }, - }, - { - "2 / 3 • Krácení", "Rozdíl čtverců", - "Tip: x² − 1 = (x − 1)(x + 1).", - { - "(x² − 1)/(x − 1) = x + 1 pro x ≠ 1.", - "Při x = 4 je hodnota 5.", - "(x² − 4)/(x + 2) = x − 2 pro x ≠ −2.", - "Při x = 5 je hodnota 3.", - NULL, - }, - }, - { - "3 / 3 • Násobení", "Čitatel s čitatelem", - "Tip: x ve jmenovateli se zkrátí jen pro x ≠ 0.", - { - "Zlomky se násobí stejně jako číselné.", - "(2x/4) · (6/x) = 12x/(4x) = 3 pro x ≠ 0.", - "6x/(3x) = 2 pro x ≠ 0.", - "Než se zkrátí písmeno, ověří se, že není nula.", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[3], "mat2_unit4", "mat2_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit4_exercise_page(void) { - static const MathItem qs[] = { - {"Do výrazu (x² − 1)/(x − 1) dosažte x = 4.", "num:5", "Pro x ≠ 1 je výraz x + 1, tedy 5. Výsledek je 5."}, - {"Pro které x nemá výraz (x + 2)/(x − 2) smysl?", "num:2", "Jmenovatel x − 2 je nula právě při x = 2. Výsledek je 2."}, - {"Upravte (2x/4) · (6/x) pro x ≠ 0.", "num:3", "12x/(4x) = 3. Výsledek je 3."}, - {"Do výrazu (x² − 4)/(x + 2) dosažte x = 5.", "num:3", "Pro x ≠ −2 je výraz x − 2, tedy 3. Výsledek je 3."}, - }; - - return math_practice_page(2, 3, "mat2unit4", - "mat2_ex4_title", "mat2_quiz4_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat2_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Odmocnina jako exponent", "a^(1/n)", - "Tip: a^(1/2) je druhá odmocnina z a.", - { - "Pro a > 0 je a^(1/n) n-tá odmocnina z a.", - "16^(1/2) = 4.", - "a^(m/n) je n-tá odmocnina z aᵐ, nebo m-tá mocnina odmocniny.", - "8^(2/3) = (8^(1/3))² = 2² = 4.", - NULL, - }, - }, - { - "2 / 3 • Stejný základ", "Exponenty se sčítají", - "Tip: 3² · 3³ = 3⁵.", - { - "aᵐ · aⁿ = aᵐ⁺ⁿ.", - "3² · 3³ = 3⁵ = 243.", - "(aᵐ)ⁿ = aᵐ·ⁿ.", - "Základ musí být při sčítání exponentů stejný.", - NULL, - }, - }, - { - "3 / 3 • Záporný exponent", "Převrácená hodnota", - "Tip: a⁻ⁿ = 1/aⁿ pro a ≠ 0.", - { - "10⁻² = 1/100.", - "10⁻¹ = 0,1 a 10⁰ = 1.", - "Záporný exponent nepřevrací znaménko základu, ale celou mocninu.", - "(−2)⁻² = 1/4, protože (−2)² = 4.", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[4], "mat2_unit5", "mat2_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit5_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte 16^(1/2).", "num:4", "Druhá odmocnina z 16 je 4. Výsledek je 4."}, - {"Spočítejte 8^(2/3).", "num:4", "Třetí odmocnina z 8 je 2 a 2² = 4. Výsledek je 4."}, - {"Spočítejte 3² · 3³.", "num:243", "3⁵ = 243. Výsledek je 243."}, - {"Spočítejte 10⁻².", "num:1/100", "10⁻² = 1/10² = 1/100. Výsledek je 1/100."}, - }; - - return math_practice_page(2, 4, "mat2unit5", - "mat2_ex5_title", "mat2_quiz5_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat2_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Poměry", "Odvěsny a přepona", - "Tip: sinus je protilehlá odvěsna ku přeponě.", - { - "V pravoúhlém trojúhelníku je sin α = protilehlá / přepona.", - "cos α = přilehlá / přepona.", - "tan α = protilehlá / přilehlá.", - "Přepona je strana proti pravému úhlu.", - NULL, - }, - }, - { - "2 / 3 • Tabulkové úhly", "30°, 45° a 60°", - "Tip: sinus 30° je 1/2.", - { - "sin 30° = 1/2 a cos 60° = 1/2.", - "sin 60° = cos 30° = √3/2.", - "sin 45° = cos 45° = √2/2.", - "tan 45° = 1.", - NULL, - }, - }, - { - "3 / 3 • Dopočet strany", "Přepona a úhel", - "Tip: proti úhlu 30° je polovina přepony.", - { - "Známe-li přeponu a úhel, protilehlá odvěsna je přepona · sin α.", - "Proti 30° při přeponě 10 je odvěsna 5.", - "Přilehlá odvěsna by byla 10 · cos 30°.", - "Tangens se hodí, když jsou známé dvě odvěsny a ne přepona.", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[5], "mat2_unit6", "mat2_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit6_exercise_page(void) { - static const MathItem qs[] = { - {"Kolik je sin 30°?", "num:1/2", "Sinus 30° je 1/2. Výsledek je 1/2."}, - {"Kolik je cos 60°?", "num:1/2", "Kosinus 60° je 1/2. Výsledek je 1/2."}, - {"Kolik je tan 45°?", "num:1", "Protilehlá a přilehlá odvěsna jsou u 45° stejně dlouhé. Výsledek je 1."}, - {"Přepona pravoúhlého trojúhelníku je 10 a jeden úhel je 30°. Jak dlouhá je odvěsna proti tomuto úhlu?", "num:5", "10 · sin 30° = 10 · 1/2 = 5. Výsledek je 5."}, - }; - - return math_practice_page(2, 5, "mat2unit6", - "mat2_ex6_title", "mat2_quiz6_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat2_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Pythagoras", "a² + b² = c²", - "Tip: 8² + 15² = 64 + 225 = 289 = 17².", - { - "V pravoúhlém trojúhelníku se součet čtverců nad odvěsnami rovná čtverci nad přeponou.", - "Trojúhelník 8, 15, 17 je pravoúhlý a přepona je 17.", - "Čtverec nad přeponou trojúhelníku 3, 4, 5 má obsah 25.", - "Věta platí jen v pravoúhlém trojúhelníku.", - NULL, - }, - }, - { - "2 / 3 • Eukleides", "Úsek přepony", - "Tip: a² = c · a_c, kde a_c je úsek přepony přilehlý k odvěsně a.", - { - "Odvěsna je geometrický průměr přepony a svého úseku.", - "a² = c · a_c a b² = c · b_c.", - "Úseky a_c a b_c dají dohromady přeponu c.", - "U odvěsen 6 a 8 je přepona 10 a úsek u odvěsny 6 je 36/10 = 18/5.", - NULL, - }, - }, - { - "3 / 3 • Výška", "v² = a_c · b_c", - "Tip: také platí a · b = c · v.", - { - "Výška k přeponě je geometrický průměr obou úseků.", - "Z a · b = c · v plyne v = ab/c.", - "Pro odvěsny 6 a 8 a přeponu 10 je v = 48/10 = 24/5.", - "Obsah trojúhelníku je pak (c · v) / 2, stejně jako (a · b) / 2.", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[6], "mat2_unit7", "mat2_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit7_exercise_page(void) { - static const MathItem qs[] = { - {"Pravoúhlý trojúhelník má odvěsny 8 a 15. Jak dlouhá je přepona?", "num:17", "64 + 225 = 289 = 17². Výsledek je 17."}, - {"Jaký obsah má čtverec sestrojený nad přeponou pravoúhlého trojúhelníku se stranami 3, 4 a 5?", "num:25", "Přepona je 5 a 5² = 25. Výsledek je 25."}, - {"Odvěsny jsou 6 a 8, přepona je 10. Jak dlouhý je úsek přepony přilehlý k odvěsně 6?", "num:18/5", "a² = c · a_c, takže a_c = 36/10 = 18/5. Výsledek je 18/5."}, - {"Odvěsny jsou 6 a 8, přepona je 10. Jak dlouhá je výška k přeponě?", "num:24/5", "v = ab/c = 48/10 = 24/5. Výsledek je 24/5."}, - }; - - return math_practice_page(2, 6, "mat2unit7", - "mat2_ex7_title", "mat2_quiz7_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat2_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Úhly", "Obvodový je polovina středového", - "Tip: oba úhly musí být nad stejným obloukem.", - { - "Středový úhel má vrchol ve středu kružnice.", - "Obvodový úhel má vrchol na kružnici.", - "Nad stejným obloukem je obvodový úhel polovinou středového.", - "Středový úhel 80° patří k obvodovému úhlu 40°.", - NULL, - }, - }, - { - "2 / 3 • Oblouk", "Část obvodu", - "Tip: délka oblouku je (α/360°) · 2πr.", - { - "Celý obvod je 2πr.", - "Oblouk 60° je šestina obvodu.", - "Při r = 6 je jeho délka 2π.", - "Výsledek nechte v násobcích π.", - NULL, - }, - }, - { - "3 / 3 • Thales", "Pravý úhel nad průměrem", - "Tip: vrchol pravého úhlu leží na kružnici s průměrem AB.", - { - "Thaletova věta: úhel nad průměrem je pravý.", - "Je-li AB průměr, je úhel ACB pravý pro každé C na kružnici různé od A a B.", - "Na mřížce má průměr od [2; 4] do [8; 4] střed [5; 4] a poloměr 3.", - "Vyhovují body [5; 7] a [5; 1].", - NULL, - }, - }, - }; - - return math_unit_page(2, &mat2_lessons[7], "mat2_unit8", "mat2_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat2_unit8_exercise_page(void) { - static const MathItem qs[] = { - {"Středový úhel je 80°. Jak velký je obvodový úhel nad stejným obloukem ve stupních?", "num:40", "Obvodový úhel je polovina středového. Výsledek je 40."}, - {"Kružnice má poloměr 6. Jak dlouhý je oblouk 60°? Nechte π ve výsledku.", "num:2*pi", "(60/360) · 2π · 6 = 2π. Výsledek je 2π."}, - {"Obvodový úhel je 35°. Jak velký je středový úhel nad stejným obloukem ve stupních?", "num:70", "Středový úhel je dvojnásobek obvodového. Výsledek je 70."}, - {"AB je průměr od [2; 4] do [8; 4]. Zakreslete bod C na kružnici, ve kterém je úhel ACB pravý.", "right:2,4;8,4", "Thaletova kružnice má střed [5; 4] a poloměr 3. Na mřížce vyhovuje [5; 7] nebo [5; 1]."}, - }; - - return math_practice_page(2, 7, "mat2unit8", - "mat2_ex8_title", "mat2_quiz8_head", - qs, G_N_ELEMENTS(qs)); -} - -void add_mat2_pages(GtkStack *stack) { - typedef GtkWidget *(*MathBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - MathBuilder build_unit; - MathBuilder build_ex; - } pages[] = { - {"mat2unit1", "mat2ex1", build_mat2_unit1_page, build_mat2_unit1_exercise_page}, - {"mat2unit2", "mat2ex2", build_mat2_unit2_page, build_mat2_unit2_exercise_page}, - {"mat2unit3", "mat2ex3", build_mat2_unit3_page, build_mat2_unit3_exercise_page}, - {"mat2unit4", "mat2ex4", build_mat2_unit4_page, build_mat2_unit4_exercise_page}, - {"mat2unit5", "mat2ex5", build_mat2_unit5_page, build_mat2_unit5_exercise_page}, - {"mat2unit6", "mat2ex6", build_mat2_unit6_page, build_mat2_unit6_exercise_page}, - {"mat2unit7", "mat2ex7", build_mat2_unit7_page, build_mat2_unit7_exercise_page}, - {"mat2unit8", "mat2ex8", build_mat2_unit8_page, build_mat2_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/mat_year3.c b/src/mat_year3.c deleted file mode 100644 index 04e3bae..0000000 --- a/src/mat_year3.c +++ /dev/null @@ -1,468 +0,0 @@ -#include "graduately.h" - -NetLesson mat3_lessons[MATH_N] = { - { .n_slides = 3, .unit_page = "mat3unit1", .ex_page = "mat3ex1" }, - { .n_slides = 3, .unit_page = "mat3unit2", .ex_page = "mat3ex2" }, - { .n_slides = 3, .unit_page = "mat3unit3", .ex_page = "mat3ex3" }, - { .n_slides = 3, .unit_page = "mat3unit4", .ex_page = "mat3ex4" }, - { .n_slides = 3, .unit_page = "mat3unit5", .ex_page = "mat3ex5" }, - { .n_slides = 3, .unit_page = "mat3unit6", .ex_page = "mat3ex6" }, - { .n_slides = 3, .unit_page = "mat3unit7", .ex_page = "mat3ex7" }, - { .n_slides = 3, .unit_page = "mat3unit8", .ex_page = "mat3ex8" }, -}; - -static GtkWidget *build_mat3_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Parabola", "f(x) = ax² + bx + c", - "Tip: pro a > 0 má parabola minimum, pro a < 0 maximum.", - { - "Grafem kvadratické funkce je parabola.", - "Průsečík s osou y je bod [0; c].", - "U f(x) = x² − 4x + 3 je f(0) = 3.", - "Osa paraboly je svislá.", - NULL, - }, - }, - { - "2 / 3 • Vrchol", "x = −b/(2a)", - "Tip: souřadnice vrcholu pište x;y.", - { - "x-ová souřadnice vrcholu je −b/(2a).", - "U x² − 4x + 3 je to −(−4)/2 = 2.", - "f(2) = 4 − 8 + 3 = −1.", - "Vrchol je tedy [2; −1].", - NULL, - }, - }, - { - "3 / 3 • Kořeny", "Průsečíky s osou x", - "Tip: kořeny jsou řešení f(x) = 0.", - { - "x² − 4x + 3 = (x − 1)(x − 3).", - "Kořeny jsou 1 a 3.", - "Leží symetricky kolem osy paraboly.", - "f(4) = 16 − 16 + 3 = 3, stejně jako f(0).", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[0], "mat3_unit1", "mat3_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit1_exercise_page(void) { - static const MathItem qs[] = { - {"Najděte vrchol funkce f(x) = x² − 4x + 3. Napište x a y oddělené středníkem.", "pair:2;-1", "x = 4/2 = 2 a f(2) = −1. Napište 2;-1."}, - {"Najděte kořeny funkce f(x) = x² − 4x + 3. Oddělte je středníkem.", "set:1;3", "(x − 1)(x − 3) = 0. Napište 1;3."}, - {"Kolik je f(0) u funkce f(x) = x² − 4x + 3?", "num:3", "f(0) = 3, to je absolutní člen. Výsledek je 3."}, - {"Kolik je f(4) u funkce f(x) = x² − 4x + 3?", "num:3", "16 − 16 + 3 = 3. Výsledek je 3."}, - }; - - return math_practice_page(3, 0, "mat3unit1", - "mat3_ex1_title", "mat3_quiz1_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat3_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Definice", "Logaritmus je exponent", - "Tip: log_b(x) = y právě tehdy, když bʸ = x.", - { - "Základ logaritmu je kladný a různý od 1.", - "Argument logaritmu je kladný.", - "log₁₀(1000) = 3, protože 10³ = 1000.", - "log₂(32) = 5, protože 2⁵ = 32.", - NULL, - }, - }, - { - "2 / 3 • Rovnice", "Stejný základ", - "Tip: 2ˣ = 16 se přepíše jako 2ˣ = 2⁴.", - { - "Exponentialní rovnice se stejným základem porovná exponenty.", - "2ˣ = 16 má řešení x = 4.", - "log₃(81) = 4, protože 3⁴ = 81.", - "log_b(b) = 1 a log_b(1) = 0.", - NULL, - }, - }, - { - "3 / 3 • Pravidla", "Součin a podíl", - "Tip: logaritmus součinu je součet logaritmů.", - { - "log_b(xy) = log_b(x) + log_b(y).", - "log_b(x/y) = log_b(x) − log_b(y).", - "log_b(xⁿ) = n · log_b(x).", - "Těmito pravidly se argument zjednodušuje, ne základ.", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[1], "mat3_unit2", "mat3_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit2_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte logaritmus o základu 10 z 1000.", "num:3", "10³ = 1000, takže logaritmus je 3. Výsledek je 3."}, - {"Spočítejte logaritmus o základu 2 z 32.", "num:5", "2⁵ = 32. Výsledek je 5."}, - {"Vyřešte 2ˣ = 16. Napište x.", "num:4", "16 = 2⁴, takže x = 4. Výsledek je 4."}, - {"Spočítejte logaritmus o základu 3 z 81.", "num:4", "3⁴ = 81. Výsledek je 4."}, - }; - - return math_practice_page(3, 1, "mat3unit2", - "mat3_ex2_title", "mat3_quiz2_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat3_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Jednotková kružnice", "Úhel od kladné poloosy x", - "Tip: sinus je y-ová souřadnice, kosinus x-ová.", - { - "Bod na jednotkové kružnici pod úhlem α má souřadnice [cos α; sin α].", - "cos 0° = 1 a sin 0° = 0.", - "sin 90° = 1 a cos 90° = 0.", - "cos 180° = −1 a sin 180° = 0.", - NULL, - }, - }, - { - "2 / 3 • 45°", "Polovina pravého úhlu", - "Tip: sin 45° = cos 45° = √2/2.", - { - "Úhel 45° půlí čtvrtkružnici.", - "Souřadnice bodu splňují x = y a x² + y² = 1.", - "Kladné řešení je √2/2.", - "Odpověď lze psát jako sqrt(2)/2 nebo 1/sqrt(2).", - NULL, - }, - }, - { - "3 / 3 • Znaménka", "Čtyři kvadranty", - "Tip: v prvním kvadrantu jsou sinus i kosinus kladné.", - { - "Ve druhém kvadrantu je sinus kladný a kosinus záporný.", - "Ve třetím jsou oba záporné.", - "Ve čtvrtém je kosinus kladný a sinus záporný.", - "Tangens je sinus dělený kosinem a není definován při cos α = 0.", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[2], "mat3_unit3", "mat3_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit3_exercise_page(void) { - static const MathItem qs[] = { - {"Kolik je sin 90°?", "num:1", "Bod [0; 1] má y-ovou souřadnici 1. Výsledek je 1."}, - {"Kolik je cos 180°?", "num:-1", "Bod [−1; 0] má x-ovou souřadnici −1. Výsledek je -1."}, - {"Kolik je sin 45°? Můžete psát sqrt(2)/2.", "num:sqrt(2)/2", "sin 45° = √2/2. Stejnou hodnotu má 1/√2."}, - {"Kolik je cos 0°?", "num:1", "Úhel 0° je bod [1; 0]. Výsledek je 1."}, - }; - - return math_practice_page(3, 2, "mat3unit3", - "mat3_ex3_title", "mat3_quiz3_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat3_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Sinová věta", "a/sin α = 2R", - "Tip: poměr strany a sinu protilehlého úhlu je pro všechny strany stejný.", - { - "a/sin α = b/sin β = c/sin γ = 2R.", - "R je poloměr kružnice opsané.", - "Když a = 10 a α = 30°, je 10 / (1/2) = 20 = 2R.", - "Poloměr R je 10.", - NULL, - }, - }, - { - "2 / 3 • Kosinová věta", "c² = a² + b² − 2ab cos γ", - "Tip: pro pravý úhel je cos 90° = 0 a věta přejde v Pythagora.", - { - "Kosinová věta dopočítá stranu proti známému úhlu.", - "Jsou-li dvě strany 2 a sevřený úhel 60°, je třetí strana také 2.", - "a² = 4 + 4 − 2 · 2 · 2 · cos 60° = 8 − 8 · 1/2 = 4.", - "Rovnostranný trojúhelník má všechny úhly 60°.", - NULL, - }, - }, - { - "3 / 3 • Obsah", "Dvě strany a sevřený úhel", - "Tip: S = (1/2) · b · c · sin α.", - { - "Obsah je polovina součinu dvou stran a sinu sevřeného úhlu.", - "(1/2) · 4 · 6 · sin 30° = 12 · 1/2 = 6.", - "Sinová věta také dopočítá další stranu: b = a · sin β / sin α.", - "Pro a = 8, α = 30° a β = 45° je b = 8√2.", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[3], "mat3_unit4", "mat3_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit4_exercise_page(void) { - static const MathItem qs[] = { - {"Strana a = 10 leží proti úhlu 30°. Jaký je poloměr kružnice opsané?", "num:10", "a/sin 30° = 20 = 2R, takže R = 10. Výsledek je 10."}, - {"Dvě strany trojúhelníku mají délku 2 a svírají úhel 60°. Jak dlouhá je třetí strana?", "num:2", "a² = 4 + 4 − 8 · 1/2 = 4, takže a = 2. Výsledek je 2."}, - {"Dvě strany mají délky 4 a 6 a svírají úhel 30°. Jaký je obsah trojúhelníku?", "num:6", "(1/2) · 4 · 6 · 1/2 = 6. Výsledek je 6."}, - {"Strana a = 8 je proti 30° a úhel β je 45°. Jak dlouhá je strana b? Sin 45° je √2/2.", "num:8*sqrt(2)", "b = 8 · sin 45° / sin 30° = 8 · (√2/2) / (1/2) = 8√2."}, - }; - - return math_practice_page(3, 3, "mat3unit4", - "mat3_ex4_title", "mat3_quiz4_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat3_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Aritmetická", "Stálý rozdíl", - "Tip: aₙ = a₁ + (n − 1)d.", - { - "Aritmetická posloupnost přičítá stále stejný rozdíl d.", - "Pro a₁ = 3 a d = 2 je a₅ = 3 + 4 · 2 = 11.", - "Součet prvních n členů je sₙ = n/2 · (2a₁ + (n − 1)d).", - "s₅ = 5/2 · (6 + 8) = 35.", - NULL, - }, - }, - { - "2 / 3 • Geometrická", "Stálý kvocient", - "Tip: aₙ = a₁ · qⁿ⁻¹.", - { - "Geometrická posloupnost násobí stále stejným kvocientem q.", - "Pro a₁ = 2 a q = 3 je a₄ = 2 · 3³ = 54.", - "q = 1 znamená, že se členy nemění.", - "q = 0 je po prvním členu samá nula, pokud je první člen definován.", - NULL, - }, - }, - { - "3 / 3 • Nekonečná řada", "Součet pro |q| < 1", - "Tip: s = a₁ / (1 − q).", - { - "Nekonečná geometrická řada má součet jen pro |q| < 1.", - "Pro a₁ = 6 a q = 1/2 je s = 6 / (1/2) = 12.", - "Pro |q| ≥ 1 se součet členů neblíží ke konečnému číslu, kromě případu q = 1 a a₁ = 0.", - "Řada 6 + 3 + 3/2 + … se tedy blíží ke 12.", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[4], "mat3_unit5", "mat3_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit5_exercise_page(void) { - static const MathItem qs[] = { - {"Aritmetická posloupnost má a₁ = 3 a d = 2. Kolik je a₅?", "num:11", "a₅ = 3 + 4 · 2 = 11. Výsledek je 11."}, - {"Aritmetická posloupnost má a₁ = 3 a d = 2. Kolik je součet prvních pěti členů?", "num:35", "s₅ = 5/2 · (6 + 8) = 35. Výsledek je 35."}, - {"Geometrická posloupnost má a₁ = 2 a q = 3. Kolik je a₄?", "num:54", "a₄ = 2 · 27 = 54. Výsledek je 54."}, - {"Nekonečná geometrická řada má a₁ = 6 a q = 1/2. Jaký je její součet?", "num:12", "s = 6 / (1/2) = 12. Výsledek je 12."}, - }; - - return math_practice_page(3, 4, "mat3unit5", - "mat3_ex5_title", "mat3_quiz5_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat3_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Permutace", "Pořadí všech prvků", - "Tip: n! = 1 · 2 · … · n a 0! = 1.", - { - "Permutace je uspořádání všech n různých prvků.", - "Počet je n!.", - "4! = 24 a 3! = 6.", - "Na prvním místě je n možností, na dalším n − 1, a tak dál.", - NULL, - }, - }, - { - "2 / 3 • Variace", "Pořadí vybraných prvků", - "Tip: variace bez opakování V(n, k) = n! / (n − k)!.", - { - "Variace vybírá k prvků z n a záleží na pořadí.", - "V(5, 2) = 5 · 4 = 20.", - "Opakování by dovolilo vybrat stejný prvek víckrát.", - "Permutace je variace, která vybírá všech n prvků.", - NULL, - }, - }, - { - "3 / 3 • Kombinace", "Pořadí nehraje roli", - "Tip: C(n, k) = n! / (k! · (n − k)!).", - { - "Kombinace vybírá k prvků a dvě vybrané skupiny se stejným obsahem jsou jedna.", - "C(5, 2) = 10.", - "C(n, k) = C(n, n − k).", - "Počet variací je k! krát větší než počet kombinací.", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[5], "mat3_unit6", "mat3_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit6_exercise_page(void) { - static const MathItem qs[] = { - {"Kolik je permutací čtyř různých prvků?", "num:24", "4! = 24. Výsledek je 24."}, - {"Kolik je kombinací 2 prvků z 5?", "num:10", "C(5, 2) = (5 · 4) / 2 = 10. Výsledek je 10."}, - {"Kolik je variací 2 prvků z 5 bez opakování?", "num:20", "V(5, 2) = 5 · 4 = 20. Výsledek je 20."}, - {"Kolik je 3!?", "num:6", "3 · 2 · 1 = 6. Výsledek je 6."}, - }; - - return math_practice_page(3, 5, "mat3unit6", - "mat3_ex6_title", "mat3_quiz6_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat3_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Definice", "Příznivé ku všem", - "Tip: všechny výsledky musí být stejně možné.", - { - "Klasická pravděpodobnost je počet příznivých výsledků dělený počtem všech.", - "Hodnota leží od 0 do 1.", - "Jev jistý má pravděpodobnost 1, jev nemožný 0.", - "Na kostce je sudé číslo ve třech případech ze šesti, tedy 1/2.", - NULL, - }, - }, - { - "2 / 3 • Nezávislost", "Součin pravděpodobností", - "Tip: dvě mince mají čtyři stejně možné dvojice výsledků.", - { - "U dvou nezávislých mincí jsou možnosti PP, PO, OP a OO.", - "Dva panny jsou jedna možnost ze čtyř, tedy 1/4.", - "U dvou kostek je 36 stejně možných dvojic.", - "Součet 7 nastane u šesti dvojic: 1+6, 2+5, 3+4, 4+3, 5+2 a 6+1.", - NULL, - }, - }, - { - "3 / 3 • Karty", "Čtyři esa v balíčku 32 karet", - "Tip: mariášový balíček má 32 karet.", - { - "Pravděpodobnost esa je 4/32 = 1/8.", - "Tažení jedné karty považuje každou kartu za stejně možnou.", - "Doplňkový jev má pravděpodobnost 1 − p.", - "Výsledek se krátí do základního tvaru.", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[6], "mat3_unit7", "mat3_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit7_exercise_page(void) { - static const MathItem qs[] = { - {"Jaká je pravděpodobnost sudého čísla při hodu hrací kostkou?", "num:1/2", "Sudá jsou 2, 4 a 6, tedy 3 ze 6, čili 1/2. Výsledek je 1/2."}, - {"Jaká je pravděpodobnost, že na dvou mincích padnou dvě panny?", "num:1/4", "Ze čtyř dvojic je příznivá jedna. Výsledek je 1/4."}, - {"V balíčku 32 karet jsou 4 esa. Jaká je pravděpodobnost, že tažená karta je eso?", "num:1/8", "4/32 = 1/8. Výsledek je 1/8."}, - {"Jaká je pravděpodobnost, že součet na dvou hracích kostkách je 7?", "num:1/6", "Příznivých dvojic je 6 z 36, tedy 1/6. Výsledek je 1/6."}, - }; - - return math_practice_page(3, 6, "mat3unit7", - "mat3_ex7_title", "mat3_quiz7_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat3_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Krychle", "Objem a povrch", - "Tip: krychle o hraně a má objem a³ a povrch 6a².", - { - "Objem je počet jednotkových krychlí, které se do tělesa vejdou.", - "Krychle o hraně 3 má objem 27.", - "Povrch je součet obsahů všech stěn: 6 · 9 = 54.", - "Jednotky objemu jsou krychlové, jednotky povrchu čtvereční.", - NULL, - }, - }, - { - "2 / 3 • Válec a koule", "Vzorce s π", - "Tip: výsledek nechte v násobcích π.", - { - "Objem válce je πr²v.", - "Pro r = 2 a v = 5 je objem 20π.", - "Objem koule je (4/3)πr³.", - "Pro r = 3 je objem (4/3)π · 27 = 36π.", - NULL, - }, - }, - { - "3 / 3 • Jehlan", "Třetina hranolu", - "Tip: objem jehlanu je (1/3) · obsah podstavy · výška.", - { - "Jehlan má stejný objem jako třetina hranolu se stejnou podstavou a výškou.", - "Podstava o obsahu 12 a výška 4 dávají objem 16.", - "Výška je kolmá vzdálenost vrcholu od roviny podstavy.", - "Stejný vztah třetiny platí i pro kužel vůči válci.", - NULL, - }, - }, - }; - - return math_unit_page(3, &mat3_lessons[7], "mat3_unit8", "mat3_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat3_unit8_exercise_page(void) { - static const MathItem qs[] = { - {"Krychle má hranu 3. Jaký je její objem?", "num:27", "3³ = 27. Výsledek je 27."}, - {"Krychle má hranu 3. Jaký je její povrch?", "num:54", "Šest stěn o obsahu 9 dává 54. Výsledek je 54."}, - {"Válec má poloměr 2 a výšku 5. Jaký je jeho objem? Nechte π ve výsledku.", "num:20*pi", "πr²v = π · 4 · 5 = 20π. Výsledek je 20π."}, - {"Koule má poloměr 3. Jaký je její objem? Nechte π ve výsledku.", "num:36*pi", "(4/3)π · 27 = 36π. Výsledek je 36π."}, - }; - - return math_practice_page(3, 7, "mat3unit8", - "mat3_ex8_title", "mat3_quiz8_head", - qs, G_N_ELEMENTS(qs)); -} - -void add_mat3_pages(GtkStack *stack) { - typedef GtkWidget *(*MathBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - MathBuilder build_unit; - MathBuilder build_ex; - } pages[] = { - {"mat3unit1", "mat3ex1", build_mat3_unit1_page, build_mat3_unit1_exercise_page}, - {"mat3unit2", "mat3ex2", build_mat3_unit2_page, build_mat3_unit2_exercise_page}, - {"mat3unit3", "mat3ex3", build_mat3_unit3_page, build_mat3_unit3_exercise_page}, - {"mat3unit4", "mat3ex4", build_mat3_unit4_page, build_mat3_unit4_exercise_page}, - {"mat3unit5", "mat3ex5", build_mat3_unit5_page, build_mat3_unit5_exercise_page}, - {"mat3unit6", "mat3ex6", build_mat3_unit6_page, build_mat3_unit6_exercise_page}, - {"mat3unit7", "mat3ex7", build_mat3_unit7_page, build_mat3_unit7_exercise_page}, - {"mat3unit8", "mat3ex8", build_mat3_unit8_page, build_mat3_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/mat_year4.c b/src/mat_year4.c deleted file mode 100644 index 3e4ebea..0000000 --- a/src/mat_year4.c +++ /dev/null @@ -1,472 +0,0 @@ -#include "graduately.h" - -NetLesson mat4_lessons[MATH_N] = { - { .n_slides = 3, .unit_page = "mat4unit1", .ex_page = "mat4ex1" }, - { .n_slides = 3, .unit_page = "mat4unit2", .ex_page = "mat4ex2" }, - { .n_slides = 3, .unit_page = "mat4unit3", .ex_page = "mat4ex3" }, - { .n_slides = 3, .unit_page = "mat4unit4", .ex_page = "mat4ex4" }, - { .n_slides = 3, .unit_page = "mat4unit5", .ex_page = "mat4ex5" }, - { .n_slides = 3, .unit_page = "mat4unit6", .ex_page = "mat4ex6" }, - { .n_slides = 3, .unit_page = "mat4unit7", .ex_page = "mat4ex7" }, - { .n_slides = 3, .unit_page = "mat4unit8", .ex_page = "mat4ex8" }, -}; - -static GtkWidget *build_mat4_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Souřadnice", "Velikost a součet", - "Tip: velikost vektoru (a; b) je √(a² + b²).", - { - "Vektor má velikost a směr.", - "|(3; 4)| = 5, protože 9 + 16 = 25.", - "Vektory se sčítají po souřadnicích.", - "(1; 2) + (3; −1) = (4; 1).", - NULL, - }, - }, - { - "2 / 3 • Skalární součin", "Číslo, ne vektor", - "Tip: (a; b) · (c; d) = ac + bd.", - { - "Skalární součin dvou vektorů je číslo.", - "(1; 2) · (3; 4) = 3 + 8 = 11.", - "Nulový skalární součin znamená kolmé vektory.", - "Velikost lze psát jako odmocninu ze skalárního součinu vektoru se sebou.", - NULL, - }, - }, - { - "3 / 3 • Vzdálenost", "Velikost rozdílu", - "Tip: na mřížce osa y míří nahoru.", - { - "Vzdálenost bodů je velikost vektoru mezi nimi.", - "Od [1; 1] do [4; 5] je vektor (3; 4) a vzdálenost 5.", - "Koncový bod vektoru (3; 2) umístěného do [1; 1] je [4; 3].", - "Pořadí souřadnic je x a potom y.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[0], "mat4_unit1", "mat4_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit1_exercise_page(void) { - static const MathItem qs[] = { - {"Jaká je velikost vektoru (3; 4)?", "num:5", "√(9 + 16) = √25 = 5. Výsledek je 5."}, - {"Sečtěte vektory (1; 2) a (3; −1). Napište souřadnice oddělené středníkem.", "pair:4;1", "(1 + 3; 2 + (−1)) = (4; 1). Napište 4;1."}, - {"Spočítejte skalární součin vektorů (1; 2) a (3; 4).", "num:11", "1 · 3 + 2 · 4 = 11. Výsledek je 11."}, - {"Jaká je vzdálenost bodů [1; 1] a [4; 5]?", "num:5", "Rozdíl je (3; 4) a jeho velikost je 5. Výsledek je 5."}, - {"Z bodu A = [1; 1] naneste vektor (3; 2). Zakreslete koncový bod.", "points:4,3;fix:1,1", "Ke každé souřadnici se přičte složka vektoru: [1 + 3; 1 + 2] = [4; 3]."}, - }; - - return math_practice_page(4, 0, "mat4unit1", - "mat4_ex1_title", "mat4_quiz1_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat4_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Směrnice", "y = ax + b", - "Tip: a = (y₂ − y₁)/(x₂ − x₁).", - { - "Body [1; 2] a [4; 8] určují směrnici (8 − 2)/(4 − 1) = 2.", - "Přímka procházející bodem [0; 1] se směrnicí 2 má rovnici y = 2x + 1.", - "Úsek na ose y je 1.", - "Svislá přímka směrnici tohoto tvaru nemá.", - NULL, - }, - }, - { - "2 / 3 • Parametr", "Bod a směrový vektor", - "Tip: X = A + t · u.", - { - "Parametrické vyjádření je x = x₀ + t · u₁, y = y₀ + t · u₂.", - "Přímka (1; 3) + t(2; 0) má při t = 2 bod [5; 3].", - "Každé t dá právě jeden bod přímky.", - "Směrový vektor (2; 0) je vodorovný.", - NULL, - }, - }, - { - "3 / 3 • Vzdálenost", "Bod od přímky", - "Tip: pro ax + by + c = 0 je vzdálenost |ax₀ + by₀ + c| / √(a² + b²).", - { - "Přímka 3x + 4y − 10 = 0 má a = 3, b = 4 a c = −10.", - "Vzdálenost počátku je |−10| / √(9 + 16) = 10/5 = 2.", - "Čitatel je absolutní hodnota, vzdálenost není záporná.", - "Čtvrtý vrchol rovnoběžníku k bodům A, B a C je B + C − A.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[1], "mat4_unit2", "mat4_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit2_exercise_page(void) { - static const MathItem qs[] = { - {"Jaká je směrnice přímky body [1; 2] a [4; 8]?", "num:2", "(8 − 2)/(4 − 1) = 2. Výsledek je 2."}, - {"Přímka má rovnici y = 2x + 1. Jaký je její úsek na ose y?", "num:1", "Úsek je absolutní člen, tedy 1. Výsledek je 1."}, - {"Bod přímky je (1; 3) + t(2; 0). Kam přímka dojde pro t = 2? Napište x a y středníkem.", "pair:5;3", "(1; 3) + 2 · (2; 0) = (5; 3). Napište 5;3."}, - {"Jaká je vzdálenost bodu [0; 0] od přímky 3x + 4y − 10 = 0?", "num:2", "|−10| / √(9 + 16) = 10/5 = 2. Výsledek je 2."}, - {"A = [1; 1], B = [4; 1] a C = [2; 3]. Zakreslete čtvrtý vrchol rovnoběžníku, ve kterém jsou AB a AC sousední strany.", "para:1,1;4,1;2,3", "D = B + C − A = [4 + 2 − 1; 1 + 3 − 1] = [5; 3]."}, - }; - - return math_practice_page(4, 1, "mat4unit2", - "mat4_ex2_title", "mat4_quiz2_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat4_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Kružnice", "Střed a poloměr", - "Tip: (x − m)² + (y − n)² = r² má střed [m; n].", - { - "Kružnice je množina bodů stejně vzdálených od středu.", - "(x − 1)² + (y + 2)² = 9 má střed [1; −2].", - "y + 2 je totéž co y − (−2).", - "Poloměr je √9 = 3, ne 9.", - NULL, - }, - }, - { - "2 / 3 • Elipsa", "Dvě poloosy", - "Tip: ve tvaru x²/a² + y²/b² = 1 je a poloosa na ose x.", - { - "Elipsa v osové poloze se středem v počátku má rovnici x²/a² + y²/b² = 1.", - "U x²/25 + y²/9 = 1 je a = 5 a b = 3.", - "Delší poloosa je hlavní, kratší vedlejší.", - "Vrcholy na ose x jsou [±a; 0], na ose y [0; ±b].", - NULL, - }, - }, - { - "3 / 3 • Excentricita", "Vzdálenost ohniska od středu", - "Tip: pro a > b je e = √(a² − b²).", - { - "Lineární výstřednost e splňuje e² = a² − b², když je a hlavní poloosa.", - "√(25 − 9) = √16 = 4.", - "Ohniska elipsy jsou [±e; 0].", - "Součet vzdáleností bodu elipsy od obou ohnisek je 2a.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[2], "mat4_unit3", "mat4_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit3_exercise_page(void) { - static const MathItem qs[] = { - {"Kružnice má rovnici (x − 1)² + (y + 2)² = 9. Napište souřadnice středu jako x;y.", "pair:1;-2", "Střed je [1; −2]. Napište 1;-2."}, - {"Jaký je poloměr kružnice (x − 1)² + (y + 2)² = 9?", "num:3", "Pravá strana je r², takže r = 3. Výsledek je 3."}, - {"Elipsa má rovnici x²/25 + y²/9 = 1. Jak dlouhá je poloosa a na ose x?", "num:5", "a² = 25, takže a = 5. Výsledek je 5."}, - {"Elipsa má rovnici x²/25 + y²/9 = 1. Jak dlouhá je poloosa b na ose y?", "num:3", "b² = 9, takže b = 3. Výsledek je 3."}, - {"Elipsa má a = 5 a b = 3. Jaká je její lineární výstřednost e?", "num:4", "e = √(25 − 9) = √16 = 4. Výsledek je 4."}, - }; - - return math_practice_page(4, 2, "mat4unit3", - "mat4_ex3_title", "mat4_quiz3_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat4_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Tvar", "a + bi", - "Tip: i² = −1. Reálnou a imaginární část pište oddělené středníkem.", - { - "Komplexní číslo a + bi má reálnou část a a imaginární část b.", - "i je imaginární jednotka a i² = −1.", - "Čísla se sčítají po složkách.", - "(2 + 3i) + (1 − i) = 3 + 2i.", - NULL, - }, - }, - { - "2 / 3 • Násobení", "Jako dvojčlen", - "Tip: (1 + i)(1 − i) je rozdíl čtverců.", - { - "(a + bi)(c + di) = ac + adi + bci + bdi².", - "bdi² = −bd, proto se imaginární jednotka ve výsledku nemusí objevit.", - "(1 + i)(1 − i) = 1 − (i)² = 1 − (−1) = 2.", - "Komplexní čísla lze násobit i v goniometrickém tvaru sčítáním argumentů.", - NULL, - }, - }, - { - "3 / 3 • Absolutní hodnota", "Vzdálenost od nuly", - "Tip: |a + bi| = √(a² + b²).", - { - "Absolutní hodnota je vzdálenost obrazu čísla od počátku Gaussovy roviny.", - "|3 + 4i| = 5.", - "|z| je vždy reálné nezáporné číslo.", - "i² = −1, i³ = −i a i⁴ = 1.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[3], "mat4_unit4", "mat4_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit4_exercise_page(void) { - static const MathItem qs[] = { - {"Sečtěte 2 + 3i a 1 − i. Napište reálnou a imaginární část středníkem.", "pair:3;2", "(2 + 1) + (3 − 1)i = 3 + 2i. Napište 3;2."}, - {"Spočítejte (1 + i)(1 − i).", "num:2", "1 − i² = 1 − (−1) = 2. Výsledek je 2."}, - {"Jaká je absolutní hodnota čísla 3 + 4i?", "num:5", "√(9 + 16) = 5. Výsledek je 5."}, - {"Kolik je i²?", "num:-1", "Imaginární jednotka splňuje i² = −1. Výsledek je -1."}, - }; - - return math_practice_page(4, 3, "mat4unit4", - "mat4_ex4_title", "mat4_quiz4_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat4_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Mocnina", "(xⁿ)' = n xⁿ⁻¹", - "Tip: derivace je směrnice tečny.", - { - "Derivace funkce v bodě je směrnice tečny grafu v tom bodě.", - "(x³)' = 3x². V bodě x = 2 je 3 · 4 = 12.", - "(5x²)' = 10x. V bodě x = 1 je 10.", - "Derivace konstanty je 0 a konstanta se vytýká.", - NULL, - }, - }, - { - "2 / 3 • Tečna", "Směrnice v bodě", - "Tip: u f(x) = x² je f'(x) = 2x.", - { - "Tečna ke grafu y = x² v bodě x = 1 má směrnici 2.", - "Rovnice tečny používá bod [1; 1] a tuto směrnici.", - "Kladná derivace znamená, že funkce v bodě roste.", - "Záporná derivace znamená, že funkce klesá.", - NULL, - }, - }, - { - "3 / 3 • Sinus", "Derivace sinu je kosinus", - "Tip: (sin x)' = cos x a cos 0 = 1.", - { - "Derivace funkce sin x je cos x.", - "Derivace funkce cos x je −sin x.", - "V bodě x = 0 je derivace sinu rovna cos 0 = 1.", - "Úhel v tomto vzorci je v radiánech, ale nula je nula v obou jednotkách.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[4], "mat4_unit5", "mat4_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit5_exercise_page(void) { - static const MathItem qs[] = { - {"Jaká je derivace funkce x³ v bodě x = 2?", "num:12", "(x³)' = 3x² a 3 · 4 = 12. Výsledek je 12."}, - {"Jaká je derivace funkce 5x² v bodě x = 1?", "num:10", "(5x²)' = 10x a v jedničce je 10. Výsledek je 10."}, - {"Jakou směrnici má tečna ke grafu y = x² v bodě x = 1?", "num:2", "Derivace 2x je v bodě 1 rovna 2. Výsledek je 2."}, - {"Jaká je derivace funkce sin x v bodě x = 0? Derivace sinu je kosinus.", "num:1", "(sin x)' = cos x a cos 0 = 1. Výsledek je 1."}, - }; - - return math_practice_page(4, 4, "mat4unit5", - "mat4_ex5_title", "mat4_quiz5_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat4_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Stacionární bod", "Derivace je nula", - "Tip: f'(x) = 0 je vodorovná tečna.", - { - "V lokálním extrému diferencovatelné funkce je derivace nulová.", - "U f(x) = x³ − 3x je f'(x) = 3x² − 3.", - "3(x² − 1) = 0 dává x = −1 a x = 1.", - "To jsou jediní kandidáti na lokální extrém.", - NULL, - }, - }, - { - "2 / 3 • Maximum a minimum", "Znaménko druhé derivace", - "Tip: f''(x) = 6x. Záporná druhá derivace znamená lokální maximum.", - { - "V x = −1 je f''(−1) = −6 < 0, takže jde o lokální maximum.", - "f(−1) = −1 + 3 = 2.", - "V x = 1 je f''(1) = 6 > 0, takže jde o lokální minimum.", - "f(1) = 1 − 3 = −2.", - NULL, - }, - }, - { - "3 / 3 • Jiný příklad", "Lineární derivace", - "Tip: g'(x) = 2x − 4 je nula při x = 2.", - { - "Kde je derivace nula, má graf vodorovnou tečnu.", - "Rovnice 2x − 4 = 0 má řešení x = 2.", - "Pro x < 2 je derivace 2x − 4 záporná, funkce klesá.", - "Pro x > 2 je derivace kladná, funkce roste.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[5], "mat4_unit6", "mat4_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit6_exercise_page(void) { - static const MathItem qs[] = { - {"Funkce f(x) = x³ − 3x. Ve kterém x má lokální maximum?", "num:-1", "f'(x) = 3x² − 3 = 0 pro x = ±1 a v −1 je maximum. Výsledek je -1."}, - {"Funkce f(x) = x³ − 3x. Jaká je hodnota lokálního maxima?", "num:2", "f(−1) = −1 + 3 = 2. Výsledek je 2."}, - {"Funkce f(x) = x³ − 3x. Ve kterém x má lokální minimum?", "num:1", "Druhá derivace 6x je v x = 1 kladná. Výsledek je 1."}, - {"Derivace funkce je g'(x) = 2x − 4. Pro které x je derivace nulová?", "num:2", "2x − 4 = 0 dává x = 2. Výsledek je 2."}, - }; - - return math_practice_page(4, 5, "mat4unit6", - "mat4_ex6_title", "mat4_quiz6_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat4_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Primitivní funkce", "Opačný postup k derivaci", - "Tip: primitivní funkce k xⁿ je xⁿ⁺¹/(n + 1) pro n ≠ −1.", - { - "Neurčitý integrál je množina primitivních funkcí.", - "Liší se o konstantu, protože derivace konstanty je nula.", - "Primitivní funkce k 2x je x².", - "Primitivní funkce k x² je x³/3.", - NULL, - }, - }, - { - "2 / 3 • Určitý integrál", "Newtonův vzorec", - "Tip: ∫ od a do b z f je F(b) − F(a).", - { - "Určitý integrál nezáporné funkce je obsah plochy pod grafem.", - "∫ od 0 do 3 z 2x dx = [x²] od 0 do 3 = 9.", - "∫ od 0 do 2 z x² dx = [x³/3] od 0 do 2 = 8/3.", - "Dolní mez 0 u těchto mocnin často vynuluje první člen.", - NULL, - }, - }, - { - "3 / 3 • Konstanta", "Násobek lze vytknout", - "Tip: integrál z c · f je c krát integrál z f.", - { - "∫ od 0 do 1 z 3x² dx = [x³] od 0 do 1 = 1.", - "∫ od 0 do 2 z 6x dx = [3x²] od 0 do 2 = 12.", - "Záporná funkce dává záporný integrál, nejde vždy o obsah beze znaménka.", - "Součet funkcí se integruje člen po členu.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[6], "mat4_unit7", "mat4_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit7_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte integrál od 0 do 3 z funkce 2x.", "num:9", "Primitivní funkce je x² a 9 − 0 = 9. Výsledek je 9."}, - {"Spočítejte integrál od 0 do 2 z funkce x².", "num:8/3", "Primitivní funkce je x³/3 a 8/3 − 0 = 8/3. Výsledek je 8/3."}, - {"Spočítejte integrál od 0 do 1 z funkce 3x².", "num:1", "Primitivní funkce je x³ a 1 − 0 = 1. Výsledek je 1."}, - {"Spočítejte integrál od 0 do 2 z funkce 6x.", "num:12", "Primitivní funkce je 3x² a 12 − 0 = 12. Výsledek je 12."}, - }; - - return math_practice_page(4, 6, "mat4unit7", - "mat4_ex7_title", "mat4_quiz7_head", - qs, G_N_ELEMENTS(qs)); -} - -static GtkWidget *build_mat4_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 3 • Číslo", "Logaritmus a zlomek", - "Tip: log₂(8) = 3, protože 2³ = 8.", - { - "Logaritmus vrací exponent.", - "1/2 + 1/3 = 5/6.", - "Společný jmenovatel se hledá i v maturitním příkladu stejně jako na základní škole.", - "Výsledek se krátí.", - NULL, - }, - }, - { - "2 / 3 • Počet a vektor", "Kombinace a velikost", - "Tip: C(6, 2) = 15 a |(3; 4)| = 5.", - { - "C(6, 2) = (6 · 5) / 2 = 15.", - "Pořadí vybrané dvojice se nepočítá dvakrát.", - "Velikost vektoru (3; 4) je přepona trojúhelníku 3-4-5.", - "Skalární součin by u kolmých vektorů vyšel nula.", - NULL, - }, - }, - { - "3 / 3 • Rovnice", "x² − 1 = 0", - "Tip: rozdíl čtverců (x − 1)(x + 1).", - { - "x² − 1 = 0 má kořeny −1 a 1.", - "Oba se napíšou, oddělené středníkem.", - "Diskriminant je 0 − 4 · 1 · (−1) = 4.", - "Zkouška: 1 − 1 = 0 a 1 − 1 = 0.", - NULL, - }, - }, - }; - - return math_unit_page(4, &mat4_lessons[7], "mat4_unit8", "mat4_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_mat4_unit8_exercise_page(void) { - static const MathItem qs[] = { - {"Spočítejte logaritmus o základu 2 z 8.", "num:3", "2³ = 8. Výsledek je 3."}, - {"Kolik je kombinací 2 prvků ze 6?", "num:15", "C(6, 2) = 15. Výsledek je 15."}, - {"Jaká je velikost vektoru (3; 4)?", "num:5", "√(9 + 16) = 5. Výsledek je 5."}, - {"Spočítejte 1/2 + 1/3.", "num:5/6", "3/6 + 2/6 = 5/6. Výsledek je 5/6."}, - {"Najděte kořeny rovnice x² − 1 = 0. Oddělte je středníkem.", "set:-1;1", "(x − 1)(x + 1) = 0. Napište -1;1."}, - }; - - return math_practice_page(4, 7, "mat4unit8", - "mat4_ex8_title", "mat4_quiz8_head", - qs, G_N_ELEMENTS(qs)); -} - -void add_mat4_pages(GtkStack *stack) { - typedef GtkWidget *(*MathBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - MathBuilder build_unit; - MathBuilder build_ex; - } pages[] = { - {"mat4unit1", "mat4ex1", build_mat4_unit1_page, build_mat4_unit1_exercise_page}, - {"mat4unit2", "mat4ex2", build_mat4_unit2_page, build_mat4_unit2_exercise_page}, - {"mat4unit3", "mat4ex3", build_mat4_unit3_page, build_mat4_unit3_exercise_page}, - {"mat4unit4", "mat4ex4", build_mat4_unit4_page, build_mat4_unit4_exercise_page}, - {"mat4unit5", "mat4ex5", build_mat4_unit5_page, build_mat4_unit5_exercise_page}, - {"mat4unit6", "mat4ex6", build_mat4_unit6_page, build_mat4_unit6_exercise_page}, - {"mat4unit7", "mat4ex7", build_mat4_unit7_page, build_mat4_unit7_exercise_page}, - {"mat4unit8", "mat4ex8", build_mat4_unit8_page, build_mat4_unit8_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/matematika.c b/src/matematika.c deleted file mode 100644 index 14705ec..0000000 --- a/src/matematika.c +++ /dev/null @@ -1,955 +0,0 @@ -#include "graduately.h" - -#include - -/* Mathematics: elementary review plus four gymnasium years. - * Lessons are slides, then typed examples. A few lessons also - * ask for a point snapped to the grid. */ - -#define MATH_CELL 28.0 -#define MATH_PAD 18.0 -#define MATH_GX 10 -#define MATH_GY 8 -#define MATH_PTS 16 - -typedef struct { - const char *map_page; - const char *back_page; - const char *title_key; - const char *sub_key; - char **progress_path; - NetLesson *lessons; - const char *unit_keys[MATH_N]; - const char *sub_keys[MATH_N]; - GtkWidget *nodes[MATH_N]; - int note_last_w; -} MathTrack; - -typedef struct { - const char *spec; - int ux[MATH_PTS]; - int uy[MATH_PTS]; - int n; - int fx[8]; - int fy[8]; - int nf; - int need; - int checked; - int correct; - GtkWidget *area; -} MathBoard; - -typedef struct { - const MathItem *items; - int n; - MathTrack *track; - int lesson_id; - GtkWidget *feedback; - GtkWidget **entries; - MathBoard **boards; - GtkWidget **hints; -} MathExCtx; - -static MathTrack math_tracks[5]; -static gboolean math_ready; -static char math_key_store[5][MATH_N][32]; -static char math_sub_store[5][MATH_N][40]; - -static void math_ensure(void) { - static const char *prefixes[] = {"mat0", "mat", "mat2", "mat3", "mat4"}; - static const char *maps[] = { - "mat0map", "matmap", "mat2map", "mat3map", "mat4map", - }; - static const char *titles[] = { - "mat0_year", "mat_year1", "mat_year2", "mat_year3", "mat_year4", - }; - static const char *subs[] = { - "mat0_sub", "mat_sub", "mat2_sub", "mat3_sub", "mat4_sub", - }; - NetLesson *lessons[5] = { - mat0_lessons, mat_lessons, mat2_lessons, mat3_lessons, mat4_lessons, - }; - char **paths[5] = { - &app_progress_mat0, &app_progress_mat, &app_progress_mat2, - &app_progress_mat3, &app_progress_mat4, - }; - int y, i; - - if (math_ready) - return; - for (y = 0; y < 5; y++) { - MathTrack *T = &math_tracks[y]; - - T->map_page = maps[y]; - T->back_page = "matyears"; - T->title_key = titles[y]; - T->sub_key = subs[y]; - T->progress_path = paths[y]; - T->lessons = lessons[y]; - T->note_last_w = -1; - for (i = 0; i < MATH_N; i++) { - g_snprintf(math_key_store[y][i], sizeof math_key_store[y][i], - "%s_unit%d", prefixes[y], i + 1); - g_snprintf(math_sub_store[y][i], sizeof math_sub_store[y][i], - "%s_unit%d_sub", prefixes[y], i + 1); - T->unit_keys[i] = math_key_store[y][i]; - T->sub_keys[i] = math_sub_store[y][i]; - } - } - math_ready = TRUE; -} - -static void math_save(MathTrack *T) { - GKeyFile *kf; - gchar *data; - - if (!T->progress_path || !*T->progress_path) - return; - kf = g_key_file_new(); - for (int i = 0; i < MATH_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof key, "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, T->lessons[i].done); - } - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - if (data) { - GError *err = NULL; - - g_file_set_contents(*T->progress_path, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -static void math_load_one(MathTrack *T) { - GKeyFile *kf; - GError *err = NULL; - - if (!T->progress_path || !*T->progress_path) - return; - kf = g_key_file_new(); - if (!g_key_file_load_from_file(kf, *T->progress_path, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - for (int i = 0; i < MATH_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof key, "%d", i + 1); - T->lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - g_key_file_free(kf); -} - -void math_load_progress(void) { - math_ensure(); - for (int y = 0; y < 5; y++) - math_load_one(&math_tracks[y]); -} - -void math_rail_theme_reset(void) { -} - -static void math_refresh(MathTrack *T) { - for (int i = 0; i < MATH_N; i++) { - GtkWidget *node = T->nodes[i]; - GtkWidget *icon = T->lessons[i].done_icon; - - if (!node) - continue; - if (T->lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -static void math_mark_done(MathTrack *T, int lesson_id) { - if (lesson_id < 0 || lesson_id >= MATH_N) - return; - if (T->lessons[lesson_id].done) - return; - T->lessons[lesson_id].done = TRUE; - math_save(T); - math_refresh(T); - refresh_stats_ui(); -} - -void progress_for_math(ProgressSum *out) { - if (!out) - return; - math_ensure(); - for (int y = 0; y < 5; y++) { - MathTrack *T = &math_tracks[y]; - - out->total_ex += MATH_N; - out->open_units += MATH_N; - for (int i = 0; i < MATH_N; i++) { - if (T->lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - } -} - -static void math_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof name, "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static GtkWidget *math_lesson_button(MathTrack *T, int index) { - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - GtkWidget *sub; - GtkWidget *icon; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 84); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", index + 1); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, T->unit_keys[index], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - sub = gtk_label_new(NULL); - i18n_bind(sub, T->sub_keys[index], 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0.0); - gtk_widget_add_css_class(sub, "hint"); - gtk_box_append(GTK_BOX(texts), sub); - - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_widget_set_valign(icon, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), icon); - T->lessons[index].done_icon = icon; - T->nodes[index] = btn; - g_signal_connect(btn, "clicked", G_CALLBACK(math_open_unit), - &T->lessons[index]); - return btn; -} - -static GtkWidget *math_build_list(MathTrack *T) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - - math_ensure(); - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar(T->back_page, T->title_key, T->sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_START); - gtk_widget_set_size_request(list, 520, -1); - gtk_widget_set_margin_bottom(list, 12); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (int i = 0; i < MATH_N; i++) - gtk_box_append(GTK_BOX(list), math_lesson_button(T, i)); - math_refresh(T); - return page; -} - -GtkWidget *build_mat0map_page(void) { return math_build_list(&math_tracks[0]); } -GtkWidget *build_matmap_page(void) { return math_build_list(&math_tracks[1]); } -GtkWidget *build_mat2map_page(void) { return math_build_list(&math_tracks[2]); } -GtkWidget *build_mat3map_page(void) { return math_build_list(&math_tracks[3]); } -GtkWidget *build_mat4map_page(void) { return math_build_list(&math_tracks[4]); } - -static GtkWidget *math_year_button(const char *badge, const char *target, - const char *title_key, const char *sub_key) { - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - GtkWidget *sub; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 84); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num = gtk_label_new(badge); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, title_key, 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - sub = gtk_label_new(NULL); - i18n_bind(sub, sub_key, 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0.0); - gtk_widget_add_css_class(sub, "hint"); - gtk_box_append(GTK_BOX(texts), sub); - - g_object_set_data_full(G_OBJECT(btn), "target", g_strdup(target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - return btn; -} - -GtkWidget *build_matyears_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - static const char *badges[] = {"ZŠ", "1.", "2.", "3.", "4."}; - static const char *targets[] = { - "mat0map", "matmap", "mat2map", "mat3map", "mat4map", - }; - static const char *titles[] = { - "mat0_year", "mat_year1", "mat_year2", "mat_year3", "mat_year4", - }; - static const char *subs[] = { - "mat0_sub", "mat_sub", "mat2_sub", "mat3_sub", "mat4_sub", - }; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "Matematika", "mat_years_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 480, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (int y = 0; y < 5; y++) - gtk_box_append(GTK_BOX(list), - math_year_button(badges[y], targets[y], titles[y], subs[y])); - return page; -} - -static void math_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof name, "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void math_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L || L->idx == 0) - return; - L->idx--; - math_slide_apply(L); -} - -static void math_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - math_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -static void math_rescale(MathTrack *T, int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) - body = 14; - if (body > 26) - body = 26; - head = body + 14; - if (head > 46) - head = 46; - kick = body - 3; - if (kick < 11) - kick = 11; - for (int i = 0; i < MATH_N; i++) - net_rescale_lesson_notes(&T->lessons[i], body, head, kick); -} - -static gboolean math_note_tick(GtkWidget *w, GdkFrameClock *clock, gpointer data) { - MathTrack *T = data; - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - if (width != T->note_last_w) { - T->note_last_w = width; - math_rescale(T, width); - } - return G_SOURCE_CONTINUE; -} - -GtkWidget *math_unit_page(int year, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides) { - MathTrack *T; - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - math_ensure(); - if (year < 0 || year > 4) - year = 0; - T = &math_tracks[year]; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar(T->map_page, title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof name, "s%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, math_note_tick, T, NULL); - T->note_last_w = -1; - math_rescale(T, 0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(math_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(math_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - math_slide_apply(L); - return page; -} - -void math_lessons_apply_lang(void) { - math_ensure(); - for (int y = 0; y < 5; y++) { - for (int i = 0; i < MATH_N; i++) - math_slide_apply(&math_tracks[y].lessons[i]); - } -} - -static void paint_hex(cairo_t *cr, unsigned hex) { - cairo_set_source_rgb(cr, ((hex >> 16) & 255) / 255.0, - ((hex >> 8) & 255) / 255.0, (hex & 255) / 255.0); -} - -static int board_px_w(void) { - return (int)(MATH_PAD * 2 + MATH_GX * MATH_CELL); -} - -static int board_px_h(void) { - return (int)(MATH_PAD * 2 + MATH_GY * MATH_CELL); -} - -static void board_to_screen(int gx, int gy, double *sx, double *sy) { - *sx = MATH_PAD + gx * MATH_CELL; - *sy = board_px_h() - MATH_PAD - gy * MATH_CELL; -} - -static gboolean board_snap(double x, double y, int *gx, int *gy) { - double cx = (x - MATH_PAD) / MATH_CELL; - double cy = (board_px_h() - MATH_PAD - y) / MATH_CELL; - int ix = (int)lround(cx); - int iy = (int)lround(cy); - - if (ix < 0 || ix > MATH_GX || iy < 0 || iy > MATH_GY) - return FALSE; - if (fabs(cx - ix) > 0.45 || fabs(cy - iy) > 0.45) - return FALSE; - *gx = ix; - *gy = iy; - return TRUE; -} - -static void board_draw(GtkDrawingArea *area, cairo_t *cr, int width, int height, - gpointer data) { - MathBoard *b = data; - int i; - static const char *names[] = {"A", "B", "C", "D"}; - - (void)area; - (void)width; - (void)height; - paint_hex(cr, app_theme.surface1); - cairo_rectangle(cr, 0, 0, board_px_w(), board_px_h()); - cairo_fill(cr); - - cairo_set_line_width(cr, 1); - cairo_set_source_rgba(cr, - ((app_theme.subtext >> 16) & 255) / 255.0, - ((app_theme.subtext >> 8) & 255) / 255.0, - (app_theme.subtext & 255) / 255.0, 0.55); - for (i = 0; i <= MATH_GX; i++) { - double x = MATH_PAD + i * MATH_CELL; - - cairo_move_to(cr, x, MATH_PAD); - cairo_line_to(cr, x, board_px_h() - MATH_PAD); - } - for (i = 0; i <= MATH_GY; i++) { - double y = MATH_PAD + i * MATH_CELL; - - cairo_move_to(cr, MATH_PAD, y); - cairo_line_to(cr, board_px_w() - MATH_PAD, y); - } - cairo_stroke(cr); - - paint_hex(cr, app_theme.text); - cairo_set_line_width(cr, 1.6); - cairo_move_to(cr, MATH_PAD, board_px_h() - MATH_PAD); - cairo_line_to(cr, board_px_w() - MATH_PAD, board_px_h() - MATH_PAD); - cairo_move_to(cr, MATH_PAD, board_px_h() - MATH_PAD); - cairo_line_to(cr, MATH_PAD, MATH_PAD); - cairo_stroke(cr); - - if (b->nf >= 2) { - double x0, y0, x1, y1; - - paint_hex(cr, app_theme.accent); - cairo_set_line_width(cr, 2); - board_to_screen(b->fx[0], b->fy[0], &x0, &y0); - board_to_screen(b->fx[1], b->fy[1], &x1, &y1); - cairo_move_to(cr, x0, y0); - cairo_line_to(cr, x1, y1); - if (b->nf >= 3) { - double x2, y2; - - board_to_screen(b->fx[2], b->fy[2], &x2, &y2); - cairo_move_to(cr, x0, y0); - cairo_line_to(cr, x2, y2); - } - cairo_stroke(cr); - } - - for (i = 0; i < b->nf && i < 4; i++) { - double x, y; - - board_to_screen(b->fx[i], b->fy[i], &x, &y); - paint_hex(cr, app_theme.accent); - cairo_arc(cr, x, y, 5.5, 0, 2 * G_PI); - cairo_fill(cr); - paint_hex(cr, app_theme.text); - cairo_set_font_size(cr, 13); - cairo_move_to(cr, x + 7, y - 7); - cairo_show_text(cr, names[i]); - } - for (i = 0; i < b->n; i++) { - double x, y; - char label[8]; - - board_to_screen(b->ux[i], b->uy[i], &x, &y); - if (b->checked) - paint_hex(cr, b->correct ? app_theme.success : app_theme.error); - else - paint_hex(cr, app_theme.success); - cairo_arc(cr, x, y, 5.5, 0, 2 * G_PI); - cairo_fill(cr); - paint_hex(cr, app_theme.text); - g_snprintf(label, sizeof label, "%d", i + 1); - cairo_set_font_size(cr, 13); - cairo_move_to(cr, x + 7, y + 14); - cairo_show_text(cr, label); - } -} - -static int board_has_fixed(MathBoard *b, int x, int y) { - for (int i = 0; i < b->nf; i++) - if (b->fx[i] == x && b->fy[i] == y) - return 1; - return 0; -} - -static void board_pressed(GtkGestureClick *gesture, int n_press, double x, double y, - gpointer data) { - MathBoard *b = data; - int gx, gy, i; - - (void)gesture; - (void)n_press; - if (!board_snap(x, y, &gx, &gy) || board_has_fixed(b, gx, gy)) - return; - for (i = 0; i < b->n; i++) { - if (b->ux[i] == gx && b->uy[i] == gy) { - memmove(&b->ux[i], &b->ux[i + 1], (b->n - i - 1) * sizeof(int)); - memmove(&b->uy[i], &b->uy[i + 1], (b->n - i - 1) * sizeof(int)); - b->n--; - b->checked = 0; - gtk_widget_queue_draw(b->area); - return; - } - } - if (b->n >= b->need || b->n >= MATH_PTS) - return; - b->ux[b->n] = gx; - b->uy[b->n] = gy; - b->n++; - b->checked = 0; - gtk_widget_queue_draw(b->area); -} - -static void board_undo(GtkButton *button, gpointer data) { - MathBoard *b = data; - - (void)button; - if (b->n <= 0) - return; - b->n--; - b->checked = 0; - gtk_widget_queue_draw(b->area); -} - -static void board_clear(GtkButton *button, gpointer data) { - MathBoard *b = data; - - (void)button; - b->n = 0; - b->checked = 0; - gtk_widget_queue_draw(b->area); -} - -static void math_ex_check(GtkButton *button, gpointer data) { - MathExCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int good = 0; - - if (ctx->boards[i]) { - MathBoard *b = ctx->boards[i]; - - good = math_draw_ok(b->spec, b->ux, b->uy, b->n); - b->checked = 1; - b->correct = good; - gtk_widget_queue_draw(b->area); - } else if (ctx->entries[i]) { - const char *text = gtk_editable_get_text(GTK_EDITABLE(ctx->entries[i])); - - gtk_widget_remove_css_class(ctx->entries[i], "ok"); - gtk_widget_remove_css_class(ctx->entries[i], "wrong"); - good = math_answer_ok(ctx->items[i].answer, text); - gtk_widget_add_css_class(ctx->entries[i], good ? "ok" : "wrong"); - } - if (good) - ok++; - if (ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - math_mark_done(ctx->track, ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -GtkWidget *math_practice_page(int year, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const MathItem *items, int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *head; - GtkWidget *intro; - MathExCtx *ctx = g_new0(MathExCtx, 1); - - math_ensure(); - if (year < 0 || year > 4) - year = 0; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_widget_set_margin_bottom(body, 12); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "math_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_label_set_xalign(GTK_LABEL(intro), 0); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_box_append(GTK_BOX(body), intro); - - ctx->items = items; - ctx->n = n; - ctx->track = &math_tracks[year]; - ctx->lesson_id = lesson_id; - ctx->entries = g_new0(GtkWidget *, n); - ctx->boards = g_new0(MathBoard *, n); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - GtkWidget *prompt = gtk_label_new(items[i].prompt); - GtkWidget *hint = gtk_label_new(items[i].hint); - - gtk_widget_set_halign(card, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), card); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_label_set_xalign(GTK_LABEL(prompt), 0); - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(card), prompt); - - if (math_is_draw(items[i].answer)) { - MathBoard *b = g_new0(MathBoard, 1); - GtkWidget *area = gtk_drawing_area_new(); - GtkGesture *click = gtk_gesture_click_new(); - GtkWidget *tools = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - GtkWidget *undo = gtk_button_new(); - GtkWidget *clear = gtk_button_new(); - GtkWidget *note = gtk_label_new(NULL); - - b->spec = items[i].answer; - b->need = math_draw_need(items[i].answer); - if (b->need < 1) - b->need = 1; - b->nf = math_draw_fixed(items[i].answer, b->fx, b->fy, 8); - b->area = area; - ctx->boards[i] = b; - - gtk_widget_set_size_request(area, board_px_w(), board_px_h()); - gtk_widget_set_halign(area, GTK_ALIGN_START); - gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(area), board_px_w()); - gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(area), board_px_h()); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), board_draw, b, NULL); - gtk_widget_add_controller(area, GTK_EVENT_CONTROLLER(click)); - g_signal_connect(click, "pressed", G_CALLBACK(board_pressed), b); - gtk_box_append(GTK_BOX(card), area); - - i18n_bind(note, "math_draw_hint", 0); - gtk_label_set_wrap(GTK_LABEL(note), TRUE); - gtk_widget_add_css_class(note, "hint"); - gtk_widget_set_halign(note, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(card), note); - - i18n_bind(undo, "math_undo", 1); - i18n_bind(clear, "math_clear", 1); - g_signal_connect(undo, "clicked", G_CALLBACK(board_undo), b); - g_signal_connect(clear, "clicked", G_CALLBACK(board_clear), b); - gtk_box_append(GTK_BOX(tools), undo); - gtk_box_append(GTK_BOX(tools), clear); - gtk_box_append(GTK_BOX(card), tools); - } else { - GtkWidget *entry = gtk_entry_new(); - - gtk_entry_set_placeholder_text(GTK_ENTRY(entry), tr("math_answer_ph")); - gtk_widget_set_hexpand(entry, TRUE); - gtk_widget_set_size_request(entry, 280, -1); - gtk_box_append(GTK_BOX(card), entry); - ctx->entries[i] = entry; - } - - gtk_label_set_wrap(GTK_LABEL(hint), TRUE); - gtk_label_set_xalign(GTK_LABEL(hint), 0); - gtk_widget_set_halign(hint, GTK_ALIGN_START); - gtk_widget_add_css_class(hint, "hint"); - gtk_widget_set_visible(hint, FALSE); - gtk_box_append(GTK_BOX(card), hint); - ctx->hints[i] = hint; - } - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), check); - g_signal_connect(check, "clicked", G_CALLBACK(math_ex_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - return page; -} diff --git a/src/math_check.c b/src/math_check.c deleted file mode 100644 index ce98d44..0000000 --- a/src/math_check.c +++ /dev/null @@ -1,1362 +0,0 @@ -/* Numeric and construction checker for mathematics. - * No GTK: the same rules are ported to Swift and Kotlin. - * A rational matches exactly, or within 0.0005. - * A square root also matches a decimal within 0.001. - * Pi stays symbolic: 3.14 is not accepted for pi. */ -#include -#include -#include -#include -#include -#include - -#define MC_TOKS 96 -#define MC_PARTS 8 -#define MC_PART 192 - -typedef struct { - int ok; - long an, ad; - long bn, bd; - int rad; - long pn, pd; -} Term; - -typedef enum { - TK_END, TK_NUM, TK_SQRT, TK_PI, TK_ADD, TK_SUB, TK_MUL, TK_DIV, TK_LP, TK_RP -} TokKind; - -typedef struct { - TokKind kind; - long n, d; -} Tok; - -static long igcd(long a, long b) { - if (a < 0) - a = -a; - if (b < 0) - b = -b; - while (b) { - long t = a % b; - a = b; - b = t; - } - return a ? a : 1; -} - -static int safe_mul(long a, long b, long *out) { - __int128 p = (__int128)a * (__int128)b; - - if (p > (__int128)LONG_MAX || p < (__int128)LONG_MIN) - return 0; - *out = (long)p; - return 1; -} - -static int set_frac(long n, long d, long *on, long *od) { - long g; - - if (d == 0) - return 0; - if (d < 0) { - n = -n; - d = -d; - } - g = igcd(n, d); - *on = n / g; - *od = d / g; - return 1; -} - -static int mul_frac(long n1, long d1, long n2, long d2, long *on, long *od) { - long n, d; - - if (!safe_mul(n1, n2, &n) || !safe_mul(d1, d2, &d)) - return 0; - return set_frac(n, d, on, od); -} - -static int add_frac(long n1, long d1, long n2, long d2, long *on, long *od) { - long a, b, den, s; - - if (!safe_mul(n1, d2, &a) || !safe_mul(n2, d1, &b) || !safe_mul(d1, d2, &den)) - return 0; - if ((b > 0 && a > LONG_MAX - b) || (b < 0 && a < LONG_MIN - b)) - return 0; - s = a + b; - return set_frac(s, den, on, od); -} - -static Term term_zero(void) { - Term t; - - memset(&t, 0, sizeof t); - t.ok = 1; - t.ad = t.bd = t.pd = 1; - return t; -} - -static int term_zero_p(Term t) { - return t.an == 0 && t.bn == 0 && t.pn == 0; -} - -static int norm_sqrt(Term *t) { - int r, f; - long pull, nb; - - if (t->bn == 0) { - t->bd = 1; - t->rad = 0; - return 1; - } - if (t->rad < 0) - return 0; - if (t->rad == 0) { - t->bn = 0; - t->bd = 1; - return 1; - } - if (t->rad > 1000000) - return 0; - r = t->rad; - pull = 1; - for (f = 2; f * f <= r; f++) { - int sq = f * f; - - while (r % sq == 0) { - r /= sq; - if (!safe_mul(pull, f, &pull)) - return 0; - } - } - if (!safe_mul(t->bn, pull, &nb)) - return 0; - t->bn = nb; - t->rad = r; - if (t->rad == 1 || t->rad == 0) { - if (!add_frac(t->an, t->ad, t->bn, t->bd, &t->an, &t->ad)) - return 0; - t->bn = 0; - t->bd = 1; - t->rad = 0; - } - if (t->bn == 0) { - t->bd = 1; - t->rad = 0; - } - return 1; -} - -static int term_add(Term a, Term b, Term *o) { - Term r = term_zero(); - - if (!a.ok || !b.ok) - return 0; - if (!add_frac(a.an, a.ad, b.an, b.ad, &r.an, &r.ad)) - return 0; - if (!add_frac(a.pn, a.pd, b.pn, b.pd, &r.pn, &r.pd)) - return 0; - if (a.bn == 0 && b.bn == 0) { - r.rad = 0; - } else if (a.bn == 0) { - r.bn = b.bn; - r.bd = b.bd; - r.rad = b.rad; - } else if (b.bn == 0) { - r.bn = a.bn; - r.bd = a.bd; - r.rad = a.rad; - } else if (a.rad != b.rad) { - return 0; - } else if (!add_frac(a.bn, a.bd, b.bn, b.bd, &r.bn, &r.bd)) { - return 0; - } else { - r.rad = a.rad; - if (r.bn == 0) { - r.bd = 1; - r.rad = 0; - } - } - *o = r; - return 1; -} - -static int add_sqrt_piece(Term *dst, long cn, long cd, int rad) { - Term piece = term_zero(); - - if (cn == 0 || rad <= 0) - return 1; - if (!set_frac(cn, cd, &piece.bn, &piece.bd)) - return 0; - piece.rad = rad; - if (!norm_sqrt(&piece)) - return 0; - return term_add(*dst, piece, dst); -} - -static int term_mul(Term a, Term b, Term *o) { - Term r = term_zero(); - long n, d, n2, d2; - - if (!a.ok || !b.ok) - return 0; - if ((a.pn && (b.bn || b.pn)) || (b.pn && (a.bn || a.pn))) - return 0; - if (!mul_frac(a.an, a.ad, b.an, b.ad, &r.an, &r.ad)) - return 0; - if (!mul_frac(a.an, a.ad, b.pn, b.pd, &n, &d)) - return 0; - if (!mul_frac(a.pn, a.pd, b.an, b.ad, &n2, &d2)) - return 0; - if (!add_frac(n, d, n2, d2, &r.pn, &r.pd)) - return 0; - if (b.bn && b.rad > 0) { - if (!mul_frac(a.an, a.ad, b.bn, b.bd, &n, &d)) - return 0; - if (!add_sqrt_piece(&r, n, d, b.rad)) - return 0; - } - if (a.bn && a.rad > 0) { - if (!mul_frac(b.an, b.ad, a.bn, a.bd, &n, &d)) - return 0; - if (!add_sqrt_piece(&r, n, d, a.rad)) - return 0; - } - if (a.bn && a.rad > 0 && b.bn && b.rad > 0) { - long radp; - - if (!mul_frac(a.bn, a.bd, b.bn, b.bd, &n, &d)) - return 0; - if (!safe_mul(a.rad, b.rad, &radp) || radp <= 0 || radp > 1000000) - return 0; - if (!add_sqrt_piece(&r, n, d, (int)radp)) - return 0; - } - *o = r; - return 1; -} - -static int term_div(Term a, Term b, Term *o) { - Term inv; - - if (!b.ok || term_zero_p(b)) - return 0; - if (b.bn == 0 && b.pn == 0) { - inv = term_zero(); - if (!set_frac(b.ad, b.an, &inv.an, &inv.ad)) - return 0; - return term_mul(a, inv, o); - } - if (b.an == 0 && b.pn == 0 && b.bn != 0 && b.rad > 1) { - long den; - - inv = term_zero(); - if (!safe_mul(b.bn, b.rad, &den)) - return 0; - if (!set_frac(b.bd, den, &inv.bn, &inv.bd)) - return 0; - inv.rad = b.rad; - if (!norm_sqrt(&inv)) - return 0; - return term_mul(a, inv, o); - } - if (b.an == 0 && b.bn == 0 && b.pn != 0) { - long n, d; - - if (a.an || a.bn) - return 0; - if (!mul_frac(a.pn, a.pd, b.pd, b.pn, &n, &d)) - return 0; - *o = term_zero(); - return set_frac(n, d, &o->an, &o->ad); - } - return 0; -} - -static int terms_exact(Term a, Term b) { - return a.ok && b.ok && a.an == b.an && a.ad == b.ad && a.bn == b.bn && - a.bd == b.bd && a.rad == b.rad && a.pn == b.pn && a.pd == b.pd; -} - -static double term_double(Term t) { - double v = (double)t.an / (double)t.ad + (double)t.pn / (double)t.pd * G_PI; - - if (t.bn && t.rad > 0) - v += (double)t.bn / (double)t.bd * sqrt((double)t.rad); - return v; -} - -static int terms_close(Term a, Term b) { - double diff; - - if (!a.ok || !b.ok) - return 0; - if (terms_exact(a, b)) - return 1; - if (a.pn || b.pn) - return 0; - diff = fabs(term_double(a) - term_double(b)); - if (a.bn || b.bn) - return diff <= 0.001; - return diff <= 0.0005; -} - -static int utf8_next(const char *s, int i, unsigned *cp) { - const unsigned char *u = (const unsigned char *)s; - unsigned c = u[i]; - - if (c < 0x80) { - *cp = c; - return 1; - } - if ((c & 0xE0) == 0xC0 && u[i + 1]) { - *cp = ((c & 0x1F) << 6) | (u[i + 1] & 0x3F); - return 2; - } - if ((c & 0xF0) == 0xE0 && u[i + 1] && u[i + 2]) { - *cp = ((c & 0x0F) << 12) | ((u[i + 1] & 0x3F) << 6) | (u[i + 2] & 0x3F); - return 3; - } - *cp = c; - return 1; -} - -static char fold_char(unsigned cp) { - switch (cp) { - case 0xE1: case 0xC1: return 'a'; - case 0x10D: case 0x10C: return 'c'; - case 0x10F: case 0x10E: return 'd'; - case 0xE9: case 0xC9: case 0x11B: case 0x11A: return 'e'; - case 0xED: case 0xCD: return 'i'; - case 0x148: case 0x147: return 'n'; - case 0xF3: case 0xD3: return 'o'; - case 0x159: case 0x158: return 'r'; - case 0x161: case 0x160: return 's'; - case 0x165: case 0x164: return 't'; - case 0xFA: case 0xDA: case 0x16F: case 0x16E: return 'u'; - case 0xFD: case 0xDD: return 'y'; - case 0x17E: case 0x17D: return 'z'; - default: - if (cp >= 'A' && cp <= 'Z') - return (char)(cp - 'A' + 'a'); - if (cp >= 'a' && cp <= 'z') - return (char)cp; - if (cp >= '0' && cp <= '9') - return (char)cp; - return 0; - } -} - -static void fold_word(const char *s, char *out, int cap) { - int i = 0, n = 0; - - while (s[i] && n + 1 < cap) { - unsigned cp; - int len = utf8_next(s, i, &cp); - char f = fold_char(cp); - - if (f) - out[n++] = f; - i += len > 0 ? len : 1; - } - out[n] = 0; -} - -static int word_ok(const char *alts, const char *user) { - char folded[128]; - char buf[256]; - char *save = NULL; - char *part; - - fold_word(user ? user : "", folded, sizeof folded); - if (!folded[0]) - return 0; - g_strlcpy(buf, alts ? alts : "", sizeof buf); - for (part = strtok_r(buf, "|", &save); part; part = strtok_r(NULL, "|", &save)) { - char one[128]; - - fold_word(part, one, sizeof one); - if (one[0] && strcmp(one, folded) == 0) - return 1; - } - return 0; -} - -static void strip_units(char *s) { - static const char *units[] = { - "procenta", "procent", "cm", "mm", "dm", "km", "m", NULL - }; - - for (;;) { - int n = (int)strlen(s); - int cut = 0; - unsigned cp; - int i; - - while (n > 0 && isspace((unsigned char)s[n - 1])) - s[--n] = 0; - if (n >= 2) { - utf8_next(s + n - 2, 0, &cp); - if (cp == 0xB0) { /* degree sign */ - s[n - 2] = 0; - continue; - } - } - if (n > 0 && s[n - 1] == '%') { - s[n - 1] = 0; - continue; - } - if (n > 0 && s[n - 1] == '.') { - s[n - 1] = 0; - continue; - } - for (i = 0; units[i]; i++) { - int m = (int)strlen(units[i]); - unsigned char prev; - - if (n <= m) - continue; - if (g_ascii_strncasecmp(s + n - m, units[i], m) != 0) - continue; - prev = (unsigned char)s[n - m - 1]; - if (g_ascii_isalpha(prev)) - continue; - s[n - m] = 0; - cut = 1; - break; - } - if (!cut) - break; - } -} - -static void trim_copy(const char *src, char *dst, int cap) { - int n; - - while (src && isspace((unsigned char)*src)) - src++; - g_strlcpy(dst, src ? src : "", cap); - n = (int)strlen(dst); - while (n > 0 && isspace((unsigned char)dst[n - 1])) - dst[--n] = 0; - if (n >= 2 && (dst[0] == '{' || dst[0] == '[' || dst[0] == '(') && - (dst[n - 1] == '}' || dst[n - 1] == ']' || dst[n - 1] == ')')) { - memmove(dst, dst + 1, n - 2); - dst[n - 2] = 0; - trim_copy(dst, dst, cap); - } -} - -static int lex_number(const char *s, int i, Tok *tok) { - int start = i; - long whole = 0, frac = 0, den = 1; - int neg = 0; - int saw = 0; - - if (s[i] == '+') - i++; - else if (s[i] == '-') { - neg = 1; - i++; - } - while (isdigit((unsigned char)s[i])) { - if (whole > LONG_MAX / 10) - return -1; - whole = whole * 10 + (s[i] - '0'); - saw = 1; - i++; - } - if (s[i] == '.' || s[i] == ',') { - i++; - while (isdigit((unsigned char)s[i])) { - if (frac > LONG_MAX / 10 || den > LONG_MAX / 10) - return -1; - frac = frac * 10 + (s[i] - '0'); - den *= 10; - saw = 1; - i++; - } - } - if (!saw || i == start) - return -1; - if (!safe_mul(whole, den, &whole)) - return -1; - if ((frac > 0 && whole > LONG_MAX - frac) || frac < 0) - return -1; - whole += frac; - if (neg) - whole = -whole; - tok->kind = TK_NUM; - if (!set_frac(whole, den, &tok->n, &tok->d)) - return -1; - return i; -} - -static int starts_ident(unsigned cp) { - return (cp >= 'A' && cp <= 'Z') || (cp >= 'a' && cp <= 'z') || cp == 0x221A || - cp == 0x3C0; -} - -static int lex(const char *s, Tok *toks, int cap) { - int i = 0, n = 0; - - while (s[i]) { - unsigned cp; - int len; - Tok tok; - - if (n + 2 >= cap) - return -1; - if (isspace((unsigned char)s[i])) { - i++; - continue; - } - memset(&tok, 0, sizeof tok); - tok.d = 1; - if (isdigit((unsigned char)s[i]) || - ((s[i] == '.' || s[i] == ',') && isdigit((unsigned char)s[i + 1]))) { - int ni = lex_number(s, i, &tok); - - if (ni < 0) - return -1; - toks[n++] = tok; - i = ni; - continue; - } - len = utf8_next(s, i, &cp); - if (cp == '+' || cp == '-' || cp == 0x2212 || cp == 0x2013) { - tok.kind = cp == '+' ? TK_ADD : TK_SUB; - toks[n++] = tok; - i += cp < 128 ? 1 : len; - continue; - } - if (cp == '*' || cp == 0xD7 || cp == 0xB7) { - tok.kind = TK_MUL; - toks[n++] = tok; - i += cp < 128 ? 1 : len; - continue; - } - if (cp == '/' || cp == ':') { - tok.kind = TK_DIV; - toks[n++] = tok; - i++; - continue; - } - if (cp == '(') { - tok.kind = TK_LP; - toks[n++] = tok; - i++; - continue; - } - if (cp == ')') { - tok.kind = TK_RP; - toks[n++] = tok; - i++; - continue; - } - if (cp == 0x221A) { - tok.kind = TK_SQRT; - toks[n++] = tok; - i += len; - continue; - } - if (cp == 0x3C0) { - tok.kind = TK_PI; - toks[n++] = tok; - i += len; - continue; - } - if (starts_ident(cp)) { - char ident[16]; - int k = 0; - - while (s[i] && k + 1 < (int)sizeof ident) { - unsigned c2; - int l2 = utf8_next(s, i, &c2); - - if (!((c2 >= 'A' && c2 <= 'Z') || (c2 >= 'a' && c2 <= 'z'))) - break; - ident[k++] = (char)((c2 >= 'A' && c2 <= 'Z') ? c2 - 'A' + 'a' : c2); - i += l2; - } - ident[k] = 0; - if (strcmp(ident, "sqrt") == 0) - tok.kind = TK_SQRT; - else if (strcmp(ident, "pi") == 0) - tok.kind = TK_PI; - else - return -1; - toks[n++] = tok; - continue; - } - return -1; - } - toks[n].kind = TK_END; - toks[n].d = 1; - return n; -} - -typedef struct { - const Tok *t; - int i; - int n; - int bad; -} Parse; - -static Term parse_expr(Parse *p); - -static int at_primary(const Tok *t) { - return t->kind == TK_NUM || t->kind == TK_SQRT || t->kind == TK_PI || - t->kind == TK_LP; -} - -static Term parse_primary(Parse *p) { - Term r = term_zero(); - Tok tok; - - if (p->bad || p->i >= p->n) { - p->bad = 1; - r.ok = 0; - return r; - } - tok = p->t[p->i]; - if (tok.kind == TK_NUM) { - /* Mixed number: 1 1/2 means 1 + 1/2. A leading minus is unary. */ - if (p->i + 3 < p->n && p->t[p->i + 1].kind == TK_NUM && - p->t[p->i + 2].kind == TK_DIV && p->t[p->i + 3].kind == TK_NUM && - p->t[p->i + 1].d == 1 && p->t[p->i + 3].d == 1 && tok.d == 1) { - Term whole = term_zero(); - Term frac = term_zero(); - - whole.an = tok.n; - whole.ad = tok.d; - if (!set_frac(p->t[p->i + 1].n, p->t[p->i + 3].n, &frac.an, &frac.ad)) { - p->bad = 1; - r.ok = 0; - return r; - } - if (!term_add(whole, frac, &r)) { - p->bad = 1; - r.ok = 0; - return r; - } - p->i += 4; - return r; - } - r.an = tok.n; - r.ad = tok.d; - p->i++; - return r; - } - if (tok.kind == TK_PI) { - r.pn = 1; - r.pd = 1; - p->i++; - return r; - } - if (tok.kind == TK_SQRT) { - Term inner; - - p->i++; - /* √2 and sqrt2 are the root of the following whole number. */ - if (p->i < p->n && p->t[p->i].kind == TK_NUM && p->t[p->i].d == 1 && - p->t[p->i].n >= 0) { - r.bn = 1; - r.bd = 1; - r.rad = (int)p->t[p->i].n; - p->i++; - if (!norm_sqrt(&r)) { - p->bad = 1; - r.ok = 0; - } - return r; - } - if (p->i >= p->n || p->t[p->i].kind != TK_LP) { - p->bad = 1; - r.ok = 0; - return r; - } - p->i++; - inner = parse_expr(p); - if (p->bad || p->i >= p->n || p->t[p->i].kind != TK_RP || !inner.ok || - inner.bn || inner.pn || inner.an < 0) { - p->bad = 1; - r.ok = 0; - return r; - } - p->i++; - if (inner.ad != 1) { - /* sqrt of a fraction is not asked; reject rather than guess. */ - p->bad = 1; - r.ok = 0; - return r; - } - r.bn = 1; - r.bd = 1; - r.rad = (int)inner.an; - if (!norm_sqrt(&r)) { - p->bad = 1; - r.ok = 0; - } - return r; - } - if (tok.kind == TK_LP) { - p->i++; - r = parse_expr(p); - if (p->bad || p->i >= p->n || p->t[p->i].kind != TK_RP) { - p->bad = 1; - r.ok = 0; - return r; - } - p->i++; - return r; - } - p->bad = 1; - r.ok = 0; - return r; -} - -static Term parse_unary(Parse *p) { - if (p->i < p->n && (p->t[p->i].kind == TK_ADD || p->t[p->i].kind == TK_SUB)) { - int neg = p->t[p->i].kind == TK_SUB; - Term r; - - p->i++; - r = parse_unary(p); - if (!r.ok) - return r; - if (neg) { - r.an = -r.an; - r.bn = -r.bn; - r.pn = -r.pn; - } - return r; - } - return parse_primary(p); -} - -static Term parse_term(Parse *p) { - Term left = parse_unary(p); - - if (!left.ok) - return left; - while (!p->bad && p->i < p->n) { - TokKind k = p->t[p->i].kind; - Term right; - int juxt = 0; - - if (k != TK_MUL && k != TK_DIV) { - if (at_primary(&p->t[p->i]) && - (p->t[p->i].kind == TK_SQRT || p->t[p->i].kind == TK_PI || - p->t[p->i].kind == TK_LP)) - juxt = 1; - else - break; - } - if (!juxt) - p->i++; - right = parse_unary(p); - if (!right.ok) { - left.ok = 0; - return left; - } - if (k == TK_DIV && !juxt) { - if (!term_div(left, right, &left)) { - p->bad = 1; - left.ok = 0; - return left; - } - } else if (!term_mul(left, right, &left)) { - p->bad = 1; - left.ok = 0; - return left; - } - } - return left; -} - -static Term parse_expr(Parse *p) { - Term left = parse_term(p); - - while (!p->bad && left.ok && p->i < p->n && - (p->t[p->i].kind == TK_ADD || p->t[p->i].kind == TK_SUB)) { - int sub = p->t[p->i].kind == TK_SUB; - Term right; - - p->i++; - right = parse_term(p); - if (!right.ok) { - left.ok = 0; - return left; - } - if (sub) { - right.an = -right.an; - right.bn = -right.bn; - right.pn = -right.pn; - } - if (!term_add(left, right, &left)) { - p->bad = 1; - left.ok = 0; - return left; - } - } - return left; -} - -static int parse_term_text(const char *text, Term *out) { - char buf[MC_PART]; - Tok toks[MC_TOKS]; - Parse p; - int n; - - trim_copy(text, buf, sizeof buf); - strip_units(buf); - trim_copy(buf, buf, sizeof buf); - if (!buf[0]) - return 0; - n = lex(buf, toks, MC_TOKS); - if (n < 0) - return 0; - p.t = toks; - p.i = 0; - p.n = n; - p.bad = 0; - *out = parse_expr(&p); - if (p.bad || !out->ok || p.i != n) - return 0; - return 1; -} - -static int split_parts(const char *text, char parts[][MC_PART], int max) { - char buf[512]; - int n = 0; - const char *s; - int use_semi; - - trim_copy(text, buf, sizeof buf); - if (!buf[0]) - return -1; - use_semi = strchr(buf, ';') != NULL; - s = buf; - while (*s && n < max) { - const char *end = s; - int len; - - if (use_semi) { - end = strchr(s, ';'); - if (!end) - end = s + strlen(s); - } else { - end = strstr(s, ", "); - if (!end) - end = s + strlen(s); - } - len = (int)(end - s); - if (len >= MC_PART) - return -1; - memcpy(parts[n], s, len); - parts[n][len] = 0; - trim_copy(parts[n], parts[n], MC_PART); - if (!parts[n][0]) - return -1; - n++; - s = end; - if (*s == 0) - break; - s += use_semi ? 1 : 2; - } - if (*s) - return -1; - return n; -} - -static int num_ok(const char *spec, const char *user) { - Term a, b; - - if (!parse_term_text(spec, &a) || !parse_term_text(user, &b)) - return 0; - return terms_close(a, b); -} - -static int list_ok(const char *spec, const char *user, int ordered) { - char sp[MC_PARTS][MC_PART]; - char up[MC_PARTS][MC_PART]; - Term st[MC_PARTS], ut[MC_PARTS]; - int ns, nu, i, j; - int used[MC_PARTS]; - - ns = split_parts(spec, sp, MC_PARTS); - nu = split_parts(user, up, MC_PARTS); - if (ns < 1 || ns != nu) - return 0; - for (i = 0; i < ns; i++) { - if (!parse_term_text(sp[i], &st[i]) || !parse_term_text(up[i], &ut[i])) - return 0; - used[i] = 0; - } - if (ordered) { - for (i = 0; i < ns; i++) - if (!terms_close(st[i], ut[i])) - return 0; - return 1; - } - for (i = 0; i < ns; i++) { - int hit = -1; - - for (j = 0; j < nu; j++) { - if (!used[j] && terms_exact(st[i], ut[j])) { - hit = j; - break; - } - } - if (hit < 0) { - for (j = 0; j < nu; j++) { - if (!used[j] && terms_close(st[i], ut[j])) { - hit = j; - break; - } - } - } - if (hit < 0) - return 0; - used[hit] = 1; - } - return 1; -} - -gboolean math_answer_ok(const char *spec, const char *user) { - if (!spec || !user) - return FALSE; - while (*spec && isspace((unsigned char)*spec)) - spec++; - if (g_str_has_prefix(spec, "word:")) - return word_ok(spec + 5, user); - if (g_str_has_prefix(spec, "set:")) - return list_ok(spec + 4, user, 0); - if (g_str_has_prefix(spec, "pair:")) - return list_ok(spec + 5, user, 1); - if (g_str_has_prefix(spec, "num:")) - return num_ok(spec + 4, user); - return FALSE; -} - -static int on_board(int x, int y) { - return x >= 0 && x <= 10 && y >= 0 && y <= 8; -} - -static int parse_xy(const char **ps, int *x, int *y) { - char *end; - long vx, vy; - const char *s = *ps; - - while (*s && (isspace((unsigned char)*s) || *s == ';')) - s++; - if (!*s) - return 0; - vx = strtol(s, &end, 10); - if (end == s || *end != ',') - return 0; - s = end + 1; - vy = strtol(s, &end, 10); - if (end == s) - return 0; - if (vx < -100 || vx > 100 || vy < -100 || vy > 100) - return 0; - *x = (int)vx; - *y = (int)vy; - *ps = end; - return 1; -} - -static const char *draw_body(const char *spec, const char *kind) { - int n = (int)strlen(kind); - - if (!spec || strncmp(spec, kind, n) != 0 || spec[n] != ':') - return NULL; - return spec + n + 1; -} - -gboolean math_is_draw(const char *spec) { - return draw_body(spec, "square") || draw_body(spec, "mid") || - draw_body(spec, "right") || draw_body(spec, "para") || - draw_body(spec, "points"); -} - -static int points_scan(const char *body, int *fx, int *fy, int *fn, - int *rx, int *ry, int *rn, int cap) { - const char *s = body; - - *fn = 0; - *rn = 0; - while (*s) { - int fix = 0; - int x, y; - - while (*s && (isspace((unsigned char)*s) || *s == ';')) - s++; - if (!*s) - break; - if (g_str_has_prefix(s, "fix:")) { - fix = 1; - s += 4; - } - if (!parse_xy(&s, &x, &y)) - return 0; - if (fix) { - if (*fn >= cap) - return 0; - fx[*fn] = x; - fy[*fn] = y; - (*fn)++; - } else { - if (*rn >= cap) - return 0; - rx[*rn] = x; - ry[*rn] = y; - (*rn)++; - } - } - return 1; -} - -int math_draw_need(const char *spec) { - int fx[8], fy[8], rx[8], ry[8], fn = 0, rn = 0; - - if (draw_body(spec, "square")) - return 2; - if (draw_body(spec, "mid") || draw_body(spec, "right") || draw_body(spec, "para")) - return 1; - if (draw_body(spec, "points")) { - if (!points_scan(draw_body(spec, "points"), fx, fy, &fn, rx, ry, &rn, 8)) - return -1; - return rn; - } - return -1; -} - -int math_draw_fixed(const char *spec, int *xs, int *ys, int cap) { - const char *body; - int n = 0; - int x, y; - - if (!xs || !ys || cap <= 0) - return 0; - if ((body = draw_body(spec, "square")) || (body = draw_body(spec, "mid")) || - (body = draw_body(spec, "right")) || (body = draw_body(spec, "para"))) { - const char *s = body; - - while (*s && n < cap) { - while (*s && (isspace((unsigned char)*s) || *s == ';')) - s++; - if (!*s) - break; - if (!parse_xy(&s, &x, &y)) - return 0; - xs[n] = x; - ys[n] = y; - n++; - } - return n; - } - if ((body = draw_body(spec, "points"))) { - int fx[8], fy[8], rx[8], ry[8], fn = 0, rn = 0, i; - - if (!points_scan(body, fx, fy, &fn, rx, ry, &rn, 8)) - return 0; - for (i = 0; i < fn && i < cap; i++) { - xs[i] = fx[i]; - ys[i] = fy[i]; - } - return fn < cap ? fn : cap; - } - return 0; -} - -static int same_pair(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy) { - return (ax == cx && ay == cy && bx == dx && by == dy) || - (ax == dx && ay == dy && bx == cx && by == cy); -} - -static int user_ok_board(const int *xs, const int *ys, int n) { - int i, j; - - for (i = 0; i < n; i++) { - if (!on_board(xs[i], ys[i])) - return 0; - for (j = i + 1; j < n; j++) - if (xs[i] == xs[j] && ys[i] == ys[j]) - return 0; - } - return 1; -} - -gboolean math_draw_ok(const char *spec, const int *xs, const int *ys, int n) { - const char *body; - int ax, ay, bx, by, cx, cy; - const char *s; - - if (!spec || n < 0 || (n > 0 && (!xs || !ys))) - return FALSE; - if (!user_ok_board(xs, ys, n)) - return FALSE; - if ((body = draw_body(spec, "square"))) { - int dx, dy; - int p1x, p1y, q1x, q1y, p2x, p2y, q2x, q2y; - - s = body; - if (n != 2 || !parse_xy(&s, &ax, &ay) || !parse_xy(&s, &bx, &by)) - return FALSE; - dx = bx - ax; - dy = by - ay; - if (dx == 0 && dy == 0) - return FALSE; - p1x = bx - dy; - p1y = by + dx; - q1x = ax - dy; - q1y = ay + dx; - p2x = bx + dy; - p2y = by - dx; - q2x = ax + dy; - q2y = ay - dx; - if (on_board(p1x, p1y) && on_board(q1x, q1y) && - same_pair(xs[0], ys[0], xs[1], ys[1], p1x, p1y, q1x, q1y)) - return TRUE; - if (on_board(p2x, p2y) && on_board(q2x, q2y) && - same_pair(xs[0], ys[0], xs[1], ys[1], p2x, p2y, q2x, q2y)) - return TRUE; - return FALSE; - } - if ((body = draw_body(spec, "mid"))) { - s = body; - if (n != 1 || !parse_xy(&s, &ax, &ay) || !parse_xy(&s, &bx, &by)) - return FALSE; - if (((ax + bx) & 1) || ((ay + by) & 1)) - return FALSE; - return xs[0] == (ax + bx) / 2 && ys[0] == (ay + by) / 2 && on_board(xs[0], ys[0]); - } - if ((body = draw_body(spec, "right"))) { - long v1x, v1y, v2x, v2y; - - s = body; - if (n != 1 || !parse_xy(&s, &ax, &ay) || !parse_xy(&s, &bx, &by)) - return FALSE; - cx = xs[0]; - cy = ys[0]; - if ((cx == ax && cy == ay) || (cx == bx && cy == by)) - return FALSE; - v1x = ax - cx; - v1y = ay - cy; - v2x = bx - cx; - v2y = by - cy; - return v1x * v2x + v1y * v2y == 0; - } - if ((body = draw_body(spec, "para"))) { - int dx, dy; - - s = body; - if (n != 1 || !parse_xy(&s, &ax, &ay) || !parse_xy(&s, &bx, &by) || - !parse_xy(&s, &cx, &cy)) - return FALSE; - dx = bx + cx - ax; - dy = by + cy - ay; - return xs[0] == dx && ys[0] == dy && on_board(dx, dy); - } - if ((body = draw_body(spec, "points"))) { - int fx[8], fy[8], rx[8], ry[8], fn = 0, rn = 0, i, j; - int used[8]; - - if (!points_scan(body, fx, fy, &fn, rx, ry, &rn, 8) || n != rn) - return FALSE; - for (i = 0; i < n; i++) - used[i] = 0; - for (i = 0; i < rn; i++) { - int hit = 0; - - for (j = 0; j < n; j++) { - if (!used[j] && xs[j] == rx[i] && ys[j] == ry[i]) { - used[j] = 1; - hit = 1; - break; - } - } - if (!hit) - return FALSE; - } - return TRUE; - } - return FALSE; -} - -#ifdef MATH_CHECK_TEST -static int fails; - -static void expect(const char *spec, const char *user, int want) { - int got = math_answer_ok(spec, user); - - if (got != want) { - fprintf(stderr, "FAIL %s vs %s got %d want %d\n", spec, user, got, want); - fails++; - } -} - -static void expect_draw(const char *spec, const int *xs, const int *ys, int n, int want) { - int got = math_draw_ok(spec, xs, ys, n); - - if (got != want) { - fprintf(stderr, "FAIL draw %s got %d want %d\n", spec, got, want); - fails++; - } -} - -static int run_file(const char *path) { - FILE *f = fopen(path, "r"); - char line[512]; - - if (!f) { - perror(path); - return 1; - } - while (fgets(line, sizeof line, f)) { - char *spec, *user, *flag, *nl; - int want; - - if (line[0] == '#' || line[0] == '\n') - continue; - nl = strchr(line, '\n'); - if (nl) - *nl = 0; - spec = line; - user = strchr(spec, '\t'); - if (!user) - continue; - *user++ = 0; - flag = strchr(user, '\t'); - if (!flag) - continue; - *flag++ = 0; - want = atoi(flag); - if (g_str_has_prefix(spec, "draw ")) { - int xs[8], ys[8], n = 0; - const char *s = user; - - while (*s && n < 8) { - while (*s == ' ' || *s == ';') - s++; - if (!*s) - break; - if (!parse_xy(&s, &xs[n], &ys[n])) { - fprintf(stderr, "bad draw user %s\n", user); - fails++; - n = -1; - break; - } - n++; - } - if (n >= 0) - expect_draw(spec + 5, xs, ys, n, want); - } else { - expect(spec, user, want); - } - } - fclose(f); - return fails ? 1 : 0; -} - -int main(int argc, char **argv) { - const int sq_hi[] = {5, 2}; - const int sq_hi_y[] = {6, 6}; - const int sq_lo[] = {5, 2}; - const int sq_lo_y[] = {0, 0}; - const int badpt[] = {5, 2}; - const int badpt_y[] = {6, 5}; - const int midp[] = {4}; - const int midy[] = {3}; - const int th1[] = {5}; - const int th1y[] = {7}; - const int th2[] = {5}; - const int th2y[] = {1}; - const int thbad[] = {5}; - const int thbady[] = {4}; - const int par[] = {5}; - const int pary[] = {3}; - const int pt[] = {1}; - const int pty[] = {4}; - const int ptoff[] = {1}; - const int ptoffy[] = {-2}; - - expect("num:5/6", "5/6", 1); - expect("num:5/6", "0,833", 1); - expect("num:5/6", "0.833", 1); - expect("num:5/6", "0,83", 0); - expect("num:-3/4", "-3/4", 1); - expect("num:-3/4", "-(3/4)", 1); - expect("num:3/4", "0,75", 1); - expect("num:3/4", "0.75", 1); - expect("num:14*pi", "14pi", 1); - expect("num:14*pi", "14*pi", 1); - expect("num:14*pi", "14π", 1); - expect("num:14*pi", "43,98", 0); - expect("num:14*pi", "44", 0); - expect("num:pi", "3,14", 0); - expect("num:pi", "22/7", 0); - expect("num:pi", "3", 0); - expect("num:2*sqrt(3)", "2√3", 1); - expect("num:2*sqrt(3)", "sqrt(12)", 1); - expect("num:sqrt(12)", "2*sqrt(3)", 1); - expect("num:3/2", "1 1/2", 1); - expect("num:sqrt(2)/2", "√2/2", 1); - expect("num:sqrt(2)/2", "1/sqrt(2)", 1); - expect("num:sqrt(2)", "1,414", 1); - expect("num:sqrt(2)", "1.414", 1); - expect("num:sqrt(2)", "1,41", 0); - expect("num:1/3", "0,333", 1); - expect("num:1/3", "0,33", 0); - expect("num:12", "12 cm", 1); - expect("num:25", "25%", 1); - expect("num:25", "25 %", 1); - expect("num:50", "50 m", 1); - expect("num:70", "70°", 1); - expect("num:0", "0", 1); - expect("num:14", "2+3*4", 1); - expect("num:8/3", "8/3", 1); - expect("num:8/3", "2,667", 1); - expect("num:8/3", "2,66", 0); - expect("num:-1", "-1", 1); - expect("set:2;3", "3;2", 1); - expect("set:2;3", "2; 3", 1); - expect("set:-2;2", "2;-2", 1); - expect("set:2;3", "2;4", 0); - expect("pair:6;4", "6;4", 1); - expect("pair:6;4", "6; 4", 1); - expect("pair:6;4", "4;6", 0); - expect("pair:1;-2", "1;-2", 1); - expect("word:pravouhly", "pravoúhlý", 1); - expect("word:ano|ne", "Ano", 1); - expect("word:ano|ne", "ne", 1); - expect("word:ano", "ne", 0); - expect("num:5/6", "", 0); - expect("num:5/6", "abc", 0); - - expect_draw("square:2,3;5,3", sq_hi, sq_hi_y, 2, 1); - expect_draw("square:2,3;5,3", sq_lo, sq_lo_y, 2, 1); - expect_draw("square:2,3;5,3", badpt, badpt_y, 2, 0); - expect_draw("mid:1,2;7,4", midp, midy, 1, 1); - expect_draw("right:2,4;8,4", th1, th1y, 1, 1); - expect_draw("right:2,4;8,4", th2, th2y, 1, 1); - expect_draw("right:2,4;8,4", thbad, thbady, 1, 0); - expect_draw("para:1,1;4,1;2,3", par, pary, 1, 1); - expect_draw("points:1,4;fix:1,1;fix:5,1", pt, pty, 1, 1); - expect_draw("points:1,4;fix:1,1;fix:5,1", ptoff, ptoffy, 1, 0); - if (math_draw_need("square:2,3;5,3") != 2 || math_draw_need("right:2,4;8,4") != 1) - fails++; - - if (argc > 1) - return run_file(argv[1]) || fails; - if (fails) { - fprintf(stderr, "%d failed\n", fails); - return 1; - } - printf("math_check ok\n"); - return 0; -} -#endif diff --git a/src/math_i18n.inc b/src/math_i18n.inc deleted file mode 100644 index 6fecfaf..0000000 --- a/src/math_i18n.inc +++ /dev/null @@ -1,176 +0,0 @@ - {"mat_years_sub", "Opakování základní školy a čtyři ročníky gymnázia.", "Elementary review and four years of gymnasium mathematics."}, - {"math_quiz_intro", "Napište výsledek. Zlomky jako 3/4, desetinnou čárku i tečku, π jako pi, odmocninu jako sqrt(2) nebo √2. Více čísel oddělte středníkem.", "Write the result. Fractions as 3/4, a decimal comma or point, π as pi, a root as sqrt(2) or √2. Separate several numbers with a semicolon."}, - {"math_answer_ph", "výsledek", "result"}, - {"math_undo", "Zpět", "Undo"}, - {"math_clear", "Smazat body", "Clear points"}, - {"math_draw_hint", "Klepněte na mřížku. Osa y směřuje nahoru.", "Tap the grid. The y-axis points up."}, - {"mat0_year", "Opakování základní školy", "Elementary-school review"}, - {"mat0_sub", "Pořadí operací, zlomky, procenta, rovnice a rýsování.", "Order of operations, fractions, percentages, equations and a construction."}, - {"mat0_unit1", "Pořadí operací", "Order of operations"}, - {"mat0_unit1_sub", "Závorky, násobení a dělení, sčítání a odčítání.", "Brackets, then multiplication and division, then addition and subtraction."}, - {"mat0_ex1_title", "Příklady", "Practice"}, - {"mat0_quiz1_head", "Pořadí operací", "Order of operations"}, - {"mat0_unit2", "Zlomky", "Fractions"}, - {"mat0_unit2_sub", "Sčítání, odčítání, násobení a dělení zlomků.", "Adding, subtracting, multiplying and dividing fractions."}, - {"mat0_ex2_title", "Příklady", "Practice"}, - {"mat0_quiz2_head", "Zlomky", "Fractions"}, - {"mat0_unit3", "Desetinná čísla", "Decimals"}, - {"mat0_unit3_sub", "Sčítání, násobení a dělení desetinných čísel.", "Adding, multiplying and dividing decimals."}, - {"mat0_ex3_title", "Příklady", "Practice"}, - {"mat0_quiz3_head", "Desetinná čísla", "Decimals"}, - {"mat0_unit4", "Procenta", "Percentages"}, - {"mat0_unit4_sub", "Procento ze základu, počet procent a cena po slevě.", "A percentage of a base, the rate, and a price after a discount."}, - {"mat0_ex4_title", "Příklady", "Practice"}, - {"mat0_quiz4_head", "Procenta", "Percentages"}, - {"mat0_unit5", "Poměr a měřítko", "Ratio and scale"}, - {"mat0_unit5_sub", "Dělení v poměru, úměra a měřítko mapy.", "Sharing in a ratio, proportion and the scale of a map."}, - {"mat0_ex5_title", "Příklady", "Practice"}, - {"mat0_quiz5_head", "Poměr a měřítko", "Ratio and scale"}, - {"mat0_unit6", "Záporná čísla", "Negative numbers"}, - {"mat0_unit6_sub", "Sčítání, násobení a absolutní hodnota.", "Addition, multiplication and absolute value."}, - {"mat0_ex6_title", "Příklady", "Practice"}, - {"mat0_quiz6_head", "Záporná čísla", "Negative numbers"}, - {"mat0_unit7", "Lineární rovnice", "Linear equations"}, - {"mat0_unit7_sub", "Ekvivalentní úpravy a jednoduché rovnice.", "Equivalent steps and simple equations."}, - {"mat0_ex7_title", "Příklady", "Practice"}, - {"mat0_quiz7_head", "Lineární rovnice", "Linear equations"}, - {"mat0_unit8", "Obvod, obsah a čtverec", "Perimeter, area and a square"}, - {"mat0_unit8_sub", "Obdélník, trojúhelník a doplnění čtverce na mřížce.", "A rectangle, a triangle, and completing a square on the grid."}, - {"mat0_ex8_title", "Příklady", "Practice"}, - {"mat0_quiz8_head", "Obvod, obsah a čtverec", "Perimeter, area and a square"}, - {"mat_year1", "1. ročník", "Year 1"}, - {"mat_sub", "Dělitelnost, výrazy, rovnice, planimetrie a konstrukce.", "Divisibility, expressions, equations, plane figures and a construction."}, - {"mat_unit1", "Dělitelnost a prvočísla", "Divisibility and primes"}, - {"mat_unit1_sub", "Největší společný dělitel, násobek a rozklad.", "Highest common factor, lowest common multiple and factorisation."}, - {"mat_ex1_title", "Příklady", "Practice"}, - {"mat_quiz1_head", "Dělitelnost a prvočísla", "Divisibility and primes"}, - {"mat_unit2", "Mocniny a odmocniny", "Powers and roots"}, - {"mat_unit2_sub", "Mocniny se stejným základem a druhá odmocnina.", "Powers with the same base and the square root."}, - {"mat_ex2_title", "Příklady", "Practice"}, - {"mat_quiz2_head", "Mocniny a odmocniny", "Powers and roots"}, - {"mat_unit3", "Algebraické výrazy", "Algebraic expressions"}, - {"mat_unit3_sub", "Dosazení, druhá mocnina součtu a rozklad rozdílu čtverců.", "Substitution, the square of a sum and a difference of squares."}, - {"mat_ex3_title", "Příklady", "Practice"}, - {"mat_quiz3_head", "Algebraické výrazy", "Algebraic expressions"}, - {"mat_unit4", "Lineární rovnice s úpravami", "Linear equations"}, - {"mat_unit4_sub", "Rovnice s koeficientem, závorkou a zlomkem.", "Equations with a coefficient, a bracket and a fraction."}, - {"mat_ex4_title", "Příklady", "Practice"}, - {"mat_quiz4_head", "Lineární rovnice s úpravami", "Linear equations"}, - {"mat_unit5", "Slovní úlohy", "Word problems"}, - {"mat_unit5_sub", "Dráha, společná práce, směs a sleva.", "Distance, joint work, a mixture and a discount."}, - {"mat_ex5_title", "Příklady", "Practice"}, - {"mat_quiz5_head", "Slovní úlohy", "Word problems"}, - {"mat_unit6", "Planimetrie", "Plane figures"}, - {"mat_unit6_sub", "Úhly trojúhelníku, vnější úhel a pravidelný mnohoúhelník.", "Angles of a triangle, the exterior angle and a regular polygon."}, - {"mat_ex6_title", "Příklady", "Practice"}, - {"mat_quiz6_head", "Planimetrie", "Plane figures"}, - {"mat_unit7", "Obvody a obsahy", "Perimeter and area"}, - {"mat_unit7_sub", "Kružnice, lichoběžník a Pythagorova věta.", "The circle, the trapezium and Pythagoras."}, - {"mat_ex7_title", "Příklady", "Practice"}, - {"mat_quiz7_head", "Obvody a obsahy", "Perimeter and area"}, - {"mat_unit8", "Konstrukce trojúhelníku", "Constructing a triangle"}, - {"mat_unit8_sub", "Vzdálenost bodů a trojúhelník daný třemi stranami.", "The distance between points and a triangle given by three sides."}, - {"mat_ex8_title", "Příklady", "Practice"}, - {"mat_quiz8_head", "Konstrukce trojúhelníku", "Constructing a triangle"}, - {"mat_year2", "2. ročník", "Year 2"}, - {"mat2_sub", "Funkce, soustavy, kvadratické rovnice, goniometrie a kružnice.", "Functions, systems, quadratic equations, trigonometry and circles."}, - {"mat2_unit1", "Lineární funkce", "Linear functions"}, - {"mat2_unit1_sub", "Předpis, průsečík s osou y, směrnice a nulový bod.", "The formula, the y-intercept, the slope and a root."}, - {"mat2_ex1_title", "Příklady", "Practice"}, - {"mat2_quiz1_head", "Lineární funkce", "Linear functions"}, - {"mat2_unit2", "Soustavy rovnic", "Systems of equations"}, - {"mat2_unit2_sub", "Dvě lineární rovnice o dvou neznámých.", "Two linear equations in two unknowns."}, - {"mat2_ex2_title", "Příklady", "Practice"}, - {"mat2_quiz2_head", "Soustavy rovnic", "Systems of equations"}, - {"mat2_unit3", "Kvadratické rovnice", "Quadratic equations"}, - {"mat2_unit3_sub", "Rozklad, diskriminant a dvojnásobný kořen.", "Factoring, the discriminant and a double root."}, - {"mat2_ex3_title", "Příklady", "Practice"}, - {"mat2_quiz3_head", "Kvadratické rovnice", "Quadratic equations"}, - {"mat2_unit4", "Lomené výrazy", "Rational expressions"}, - {"mat2_unit4_sub", "Krácení, definiční obor a násobení zlomků s proměnnou.", "Cancelling, the domain and multiplying algebraic fractions."}, - {"mat2_ex4_title", "Příklady", "Practice"}, - {"mat2_quiz4_head", "Lomené výrazy", "Rational expressions"}, - {"mat2_unit5", "Mocniny s racionálním exponentem", "Rational exponents"}, - {"mat2_unit5_sub", "Odmocniny, součin mocnin a záporný exponent.", "Roots, a product of powers and a negative exponent."}, - {"mat2_ex5_title", "Příklady", "Practice"}, - {"mat2_quiz5_head", "Mocniny s racionálním exponentem", "Rational exponents"}, - {"mat2_unit6", "Goniometrie pravoúhlého trojúhelníku", "Right-triangle trigonometry"}, - {"mat2_unit6_sub", "Sinus, kosinus a tangens ostrého úhlu.", "Sine, cosine and tangent of an acute angle."}, - {"mat2_ex6_title", "Příklady", "Practice"}, - {"mat2_quiz6_head", "Goniometrie pravoúhlého trojúhelníku", "Right-triangle trigonometry"}, - {"mat2_unit7", "Pythagorova a Eukleidovy věty", "Pythagoras and Euclid"}, - {"mat2_unit7_sub", "Přepona, obsah čtverce nad ní a úseky přepony.", "The hypotenuse, the square on it, and the projections on it."}, - {"mat2_ex7_title", "Příklady", "Practice"}, - {"mat2_quiz7_head", "Pythagorova a Eukleidovy věty", "Pythagoras and Euclid"}, - {"mat2_unit8", "Kružnice a Thaletova věta", "Circles and Thales"}, - {"mat2_unit8_sub", "Obvodový a středový úhel, délka oblouku a pravý úhel nad průměrem.", "An inscribed and a central angle, arc length, and the right angle in a semicircle."}, - {"mat2_ex8_title", "Příklady", "Practice"}, - {"mat2_quiz8_head", "Kružnice a Thaletova věta", "Circles and Thales"}, - {"mat_year3", "3. ročník", "Year 3"}, - {"mat3_sub", "Logaritmus, posloupnosti, pravděpodobnost a stereometrie.", "Logarithms, sequences, probability and solid geometry."}, - {"mat3_unit1", "Kvadratická funkce", "The quadratic function"}, - {"mat3_unit1_sub", "Vrchol, kořeny a hodnota paraboly.", "The vertex, the roots and a value of a parabola."}, - {"mat3_ex1_title", "Příklady", "Practice"}, - {"mat3_quiz1_head", "Kvadratická funkce", "The quadratic function"}, - {"mat3_unit2", "Exponenciální funkce a logaritmus", "Exponentials and logarithms"}, - {"mat3_unit2_sub", "Mocnina se základem a logaritmus jako její opak.", "A power and the logarithm as its inverse."}, - {"mat3_ex2_title", "Příklady", "Practice"}, - {"mat3_quiz2_head", "Exponenciální funkce a logaritmus", "Exponentials and logarithms"}, - {"mat3_unit3", "Goniometrické funkce", "Trigonometric functions"}, - {"mat3_unit3_sub", "Sinus a kosinus na jednotkové kružnici.", "Sine and cosine on the unit circle."}, - {"mat3_ex3_title", "Příklady", "Practice"}, - {"mat3_quiz3_head", "Goniometrické funkce", "Trigonometric functions"}, - {"mat3_unit4", "Sinová a kosinová věta", "The sine and cosine rules"}, - {"mat3_unit4_sub", "Obecný trojúhelník, poloměr kružnice a obsah.", "A general triangle, the circumradius and the area."}, - {"mat3_ex4_title", "Příklady", "Practice"}, - {"mat3_quiz4_head", "Sinová a kosinová věta", "The sine and cosine rules"}, - {"mat3_unit5", "Posloupnosti a řady", "Sequences and series"}, - {"mat3_unit5_sub", "Aritmetická a geometrická posloupnost a nekonečná řada.", "An arithmetic and a geometric sequence, and an infinite series."}, - {"mat3_ex5_title", "Příklady", "Practice"}, - {"mat3_quiz5_head", "Posloupnosti a řady", "Sequences and series"}, - {"mat3_unit6", "Kombinatorika", "Combinatorics"}, - {"mat3_unit6_sub", "Permutace, variace a kombinace.", "Permutations, variations and combinations."}, - {"mat3_ex6_title", "Příklady", "Practice"}, - {"mat3_quiz6_head", "Kombinatorika", "Combinatorics"}, - {"mat3_unit7", "Pravděpodobnost", "Probability"}, - {"mat3_unit7_sub", "Klasická pravděpodobnost, kostka, mince a karty.", "Classical probability with a die, a coin and cards."}, - {"mat3_ex7_title", "Příklady", "Practice"}, - {"mat3_quiz7_head", "Pravděpodobnost", "Probability"}, - {"mat3_unit8", "Stereometrie", "Solid geometry"}, - {"mat3_unit8_sub", "Krychle, válec, koule a jehlan.", "The cube, the cylinder, the sphere and a pyramid."}, - {"mat3_ex8_title", "Příklady", "Practice"}, - {"mat3_quiz8_head", "Stereometrie", "Solid geometry"}, - {"mat_year4", "4. ročník", "Year 4"}, - {"mat4_sub", "Analytická geometrie, derivace, integrál a maturitní opakování.", "Coordinate geometry, derivatives, integrals and a maturita review."}, - {"mat4_unit1", "Vektory", "Vectors"}, - {"mat4_unit1_sub", "Velikost, součet, skalární součin a koncový bod.", "Magnitude, a sum, the dot product and an endpoint."}, - {"mat4_ex1_title", "Příklady", "Practice"}, - {"mat4_quiz1_head", "Vektory", "Vectors"}, - {"mat4_unit2", "Analytická přímka", "The line in the plane"}, - {"mat4_unit2_sub", "Směrnice, úsek, parametrické vyjádření a vzdálenost od přímky.", "Slope, intercept, a parametric equation and the distance from a line."}, - {"mat4_ex2_title", "Příklady", "Practice"}, - {"mat4_quiz2_head", "Analytická přímka", "The line in the plane"}, - {"mat4_unit3", "Kuželosečky", "Conic sections"}, - {"mat4_unit3_sub", "Kružnice a elipsa v osové poloze.", "A circle and an ellipse aligned with the axes."}, - {"mat4_ex3_title", "Příklady", "Practice"}, - {"mat4_quiz3_head", "Kuželosečky", "Conic sections"}, - {"mat4_unit4", "Komplexní čísla", "Complex numbers"}, - {"mat4_unit4_sub", "Součet, součin, absolutní hodnota a mocnina i.", "A sum, a product, the modulus and a power of i."}, - {"mat4_ex4_title", "Příklady", "Practice"}, - {"mat4_quiz4_head", "Komplexní čísla", "Complex numbers"}, - {"mat4_unit5", "Derivace", "The derivative"}, - {"mat4_unit5_sub", "Derivace mocniny, tečna a derivace sinu.", "The derivative of a power, a tangent and the derivative of sine."}, - {"mat4_ex5_title", "Příklady", "Practice"}, - {"mat4_quiz5_head", "Derivace", "The derivative"}, - {"mat4_unit6", "Průběh funkce", "The shape of a function"}, - {"mat4_unit6_sub", "Stacionární body, lokální extrémy a nulová derivace.", "Stationary points, local extrema and a zero derivative."}, - {"mat4_ex6_title", "Příklady", "Practice"}, - {"mat4_quiz6_head", "Průběh funkce", "The shape of a function"}, - {"mat4_unit7", "Integrál", "The integral"}, - {"mat4_unit7_sub", "Určitý integrál mocniny jako obsah pod grafem.", "The definite integral of a power as the area under the graph."}, - {"mat4_ex7_title", "Příklady", "Practice"}, - {"mat4_quiz7_head", "Integrál", "The integral"}, - {"mat4_unit8", "Maturitní mix", "Maturita mix"}, - {"mat4_unit8_sub", "Logaritmus, kombinace, vektor, zlomek a kvadratická rovnice.", "A logarithm, a combination, a vector, a fraction and a quadratic equation."}, - {"mat4_ex8_title", "Příklady", "Practice"}, - {"mat4_quiz8_head", "Maturitní mix", "Maturita mix"}, diff --git a/src/mluvnice.c b/src/mluvnice.c deleted file mode 100644 index 30454ae..0000000 --- a/src/mluvnice.c +++ /dev/null @@ -1,795 +0,0 @@ -#include "graduately.h" - -#define MLUV_N_EX 20 -#define MLUV_MAX_BLANK 5 -#define MLUV_MAX_OPT 5 - -typedef struct { - const char *prompt; - const char *shown; - int nblank; - const char *hint[MLUV_MAX_BLANK]; - const char *answers[MLUV_MAX_BLANK]; -} MluvItem; - -typedef struct { - const char *prompt; - const char *solution; -} MluvRevealItem; - -typedef struct { - const MluvItem *items; - int n; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget **entries; - GtkWidget **reveal; -} MluvCtx; - -typedef struct { - const MluvRevealItem *items; - int n; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkWidget **sol; -} MluvRevealCtx; - -typedef struct { - const ChoiceQ *qs; - const char **expls; - int n; - UnitCtx *unit; - int ex_num; - GtkWidget *feedback; - GtkToggleButton **toggles; - GtkWidget **expl_labels; -} MluvChoiceCtx; - -static UnitCtx mluv_unit; - -static const char *mluv_names[MLUV_N_EX] = { - "i/y", "Velká písmena", "Slovní druhy", "Podst. jména", "Slovesa", - "Slovotvorba", "Větné členy", "Vedlejší věty", "Synonyma", "Antonyma", - "s/z", "Najdi chybu", "Tvary", "Test A–D", "Přímá řeč", - "Rozdíly", "Interpunkce", "Obrazná pojmen.", "Slohové útvary", - "Opakování", -}; - -void mluvnice_init(void) { - mluv_unit.title = "Mluvnice"; - mluv_unit.page = "mluvnice"; - mluv_unit.ex_tag = "mluv"; - mluv_unit.sub_key = "mluv_sub"; - mluv_unit.back_target = "czechmap"; - mluv_unit.progress_file = app_progress_mluvnice; - mluv_unit.n_ex = MLUV_N_EX; - for (int i = 0; i < MLUV_N_EX; i++) - mluv_unit.ex_names[i + 1] = mluv_names[i]; - unit_load_progress(&mluv_unit); -} - -void progress_for_mluvnice(ProgressSum *out) { - int d; - - if (!out || mluv_unit.n_ex <= 0) - return; - d = unit_done_count(&mluv_unit); - out->total_ex += mluv_unit.n_ex; - out->open_units += 1; - out->done_ex += d; - if (d == mluv_unit.n_ex) - out->done_units++; -} - -void mluvnice_refresh_ui(void) { - for (int i = 0; i < mluv_unit.n_ex; i++) { - GtkWidget *btn = mluv_unit.ex_cells[i]; - - if (!btn) - continue; - if (mluv_unit.done[i + 1]) { - gtk_widget_add_css_class(btn, "done"); - if (mluv_unit.ex_icons[i + 1]) - gtk_widget_set_visible(mluv_unit.ex_icons[i + 1], TRUE); - } else { - gtk_widget_remove_css_class(btn, "done"); - if (mluv_unit.ex_icons[i + 1]) - gtk_widget_set_visible(mluv_unit.ex_icons[i + 1], FALSE); - } - } - - if (mluv_unit.ex_rail) - gtk_widget_queue_draw(mluv_unit.ex_rail); -} - -static void mluv_check(GtkButton *button, gpointer data) { - MluvCtx *ctx = data; - int total = 0; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - const MluvItem *it = &ctx->items[i]; - - for (int j = 0; j < it->nblank; j++) { - GtkWidget *e = ctx->entries[i * MLUV_MAX_BLANK + j]; - const gchar *txt = gtk_editable_get_text(GTK_EDITABLE(e)); - gchar *norm = normalize_answer(txt); - gboolean good = txt && txt[0] && - answer_accepts(norm, it->answers[j]); - - g_free(norm); - answer_mark(e, good); - total++; - if (good) - ok++; - } - if (ctx->reveal[i]) - gtk_widget_set_visible(ctx->reveal[i], TRUE); - } - - if (total > 0 && ok == total) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry")); - } -} - -static GtkWidget *mluv_typed_page(int ex_num, const char *title, - const char *sub, const char *note, - const MluvItem *items, int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell("mluvnice", title, sub, "check", - &body, &feedback, &check); - MluvCtx *ctx = g_new0(MluvCtx, 1); - - ctx->items = items; - ctx->n = n; - ctx->unit = &mluv_unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->entries = g_new0(GtkWidget *, n * MLUV_MAX_BLANK); - ctx->reveal = g_new0(GtkWidget *, n); - - if (note) { - GtkWidget *l = gtk_label_new(note); - - gtk_widget_set_halign(l, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(l), TRUE); - gtk_label_set_xalign(GTK_LABEL(l), 0.0); - gtk_widget_add_css_class(l, "hint"); - gtk_widget_set_margin_bottom(l, 4); - gtk_box_append(GTK_BOX(body), l); - } - - for (int i = 0; i < n; i++) { - const MluvItem *it = &items[i]; - GtkWidget *card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - GtkWidget *prompt = gtk_label_new(it->prompt); - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - char *rev = g_strdup_printf("Řešení: %s", it->shown); - GtkWidget *rl = gtk_label_new(rev); - - g_free(rev); - gtk_widget_add_css_class(card, "notes-card"); - gtk_box_append(GTK_BOX(body), card); - - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_label_set_xalign(GTK_LABEL(prompt), 0.0); - gtk_widget_add_css_class(prompt, "ex-prompt"); - gtk_box_append(GTK_BOX(card), prompt); - - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(card), row); - - for (int j = 0; j < it->nblank; j++) { - GtkWidget *e = gtk_entry_new(); - - gtk_editable_set_width_chars(GTK_EDITABLE(e), 18); - if (it->hint[j]) - gtk_entry_set_placeholder_text(GTK_ENTRY(e), it->hint[j]); - gtk_box_append(GTK_BOX(row), e); - ctx->entries[i * MLUV_MAX_BLANK + j] = e; - } - - gtk_widget_set_halign(rl, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(rl), TRUE); - gtk_label_set_xalign(GTK_LABEL(rl), 0.0); - gtk_widget_add_css_class(rl, "meaning"); - gtk_widget_set_visible(rl, FALSE); - gtk_box_append(GTK_BOX(card), rl); - ctx->reveal[i] = rl; - } - - g_signal_connect(check, "clicked", G_CALLBACK(mluv_check), ctx); - return page; -} - -static void mluv_reveal_check(GtkButton *button, gpointer data) { - MluvRevealCtx *ctx = data; - - (void)button; - - for (int i = 0; i < ctx->n; i++) - gtk_widget_set_visible(ctx->sol[i], TRUE); - - set_feedback(ctx->feedback, TRUE, "Zobrazili jste si vzorové řešení."); - mark_done(ctx->unit, ctx->ex_num); -} - -static GtkWidget *mluv_reveal_page(int ex_num, const char *title, - const char *sub, const char *note, - const MluvRevealItem *items, int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell("mluvnice", title, sub, - "Zobrazit řešení", - &body, &feedback, &check); - MluvRevealCtx *ctx = g_new0(MluvRevealCtx, 1); - - ctx->items = items; - ctx->n = n; - ctx->unit = &mluv_unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->sol = g_new0(GtkWidget *, n); - - if (note) { - GtkWidget *l = gtk_label_new(note); - - gtk_widget_set_halign(l, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(l), TRUE); - gtk_label_set_xalign(GTK_LABEL(l), 0.0); - gtk_widget_add_css_class(l, "hint"); - gtk_widget_set_margin_bottom(l, 4); - gtk_box_append(GTK_BOX(body), l); - } - - for (int i = 0; i < n; i++) { - GtkWidget *card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - GtkWidget *prompt = gtk_label_new(items[i].prompt); - GtkWidget *sol = gtk_label_new(items[i].solution); - - gtk_widget_add_css_class(card, "notes-card"); - gtk_box_append(GTK_BOX(body), card); - - gtk_widget_set_halign(prompt, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); - gtk_label_set_xalign(GTK_LABEL(prompt), 0.0); - gtk_widget_add_css_class(prompt, "ex-prompt"); - gtk_box_append(GTK_BOX(card), prompt); - - gtk_widget_set_halign(sol, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sol), TRUE); - gtk_label_set_xalign(GTK_LABEL(sol), 0.0); - gtk_widget_add_css_class(sol, "meaning"); - gtk_widget_set_visible(sol, FALSE); - gtk_box_append(GTK_BOX(card), sol); - ctx->sol[i] = sol; - } - - g_signal_connect(check, "clicked", G_CALLBACK(mluv_reveal_check), ctx); - return page; -} - -static void mluv_choice_check(GtkButton *button, gpointer data) { - MluvChoiceCtx *ctx = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - const ChoiceQ *q = &ctx->qs[i]; - int active = -1; - - for (int o = 0; o < q->n_options; o++) { - GtkToggleButton *tb = ctx->toggles[i * MLUV_MAX_OPT + o]; - - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - gtk_widget_set_sensitive(GTK_WIDGET(tb), FALSE); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - - if (active == q->correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * MLUV_MAX_OPT + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * MLUV_MAX_OPT + active]), "wrong"); - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * MLUV_MAX_OPT + q->correct]), "ok"); - } else { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * MLUV_MAX_OPT + q->correct]), "ok"); - } - - if (ctx->expl_labels && ctx->expl_labels[i]) - gtk_widget_set_visible(ctx->expl_labels[i], TRUE); - } - - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_done(ctx->unit, ctx->ex_num); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -static GtkWidget *mluv_choice_page(int ex_num, const char *title, - const char *sub, const char *note, - const ChoiceQ *qs, const char **expls, - int n) { - GtkWidget *body, *feedback, *check; - GtkWidget *page = ex_page_shell("mluvnice", title, sub, "check", - &body, &feedback, &check); - MluvChoiceCtx *ctx = g_new0(MluvChoiceCtx, 1); - - ctx->qs = qs; - ctx->expls = expls; - ctx->n = n; - ctx->unit = &mluv_unit; - ctx->ex_num = ex_num; - ctx->feedback = feedback; - ctx->toggles = g_new0(GtkToggleButton *, n * MLUV_MAX_OPT); - ctx->expl_labels = g_new0(GtkWidget *, n); - - if (note) { - GtkWidget *l = gtk_label_new(note); - - gtk_widget_set_halign(l, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(l), TRUE); - gtk_label_set_xalign(GTK_LABEL(l), 0.0); - gtk_widget_add_css_class(l, "hint"); - gtk_widget_set_margin_bottom(l, 4); - gtk_box_append(GTK_BOX(body), l); - } - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question( - body, i + 1, &qs[i], &ctx->toggles[i * MLUV_MAX_OPT]); - - if (expls && expls[i]) { - GtkWidget *e = gtk_label_new(expls[i]); - - gtk_widget_set_halign(e, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(e), TRUE); - gtk_label_set_xalign(GTK_LABEL(e), 0.0); - gtk_widget_add_css_class(e, "meaning"); - gtk_widget_set_visible(e, FALSE); - gtk_box_append(GTK_BOX(card), e); - ctx->expl_labels[i] = e; - } - } - - g_signal_connect(check, "clicked", G_CALLBACK(mluv_choice_check), ctx); - return page; -} - -/* ---- Exercise content --------------------------------------------- */ - -static const MluvItem e1_items[] = { - {"Stará bab_čka sed_la na lav_čce.", "babička, seděla, lavičce", 3, - {"i/í/y/ý", "i/í/y/ý", "i/í/y/ý"}, - {"babička", "seděla|sedla", "lavičce"}}, - {"Na obloze sv_tily hv_zdy.", "svítily, hvězdy", 2, - {"i/í/y/ý", "i/í/y/ý"}, - {"svítily", "hvězdy"}}, - {"M_sl_m, že m_š pravdu.", "Myslím, myš", 2, - {"i/í/y/ý", "i/í/y/ý"}, - {"Myslím", "myš"}}, - {"V_soký muž nes_l těžký kuf_r.", "Vysoký, nesl, kufr", 3, - {"i/í/y/ý", "i/í/y/ý", "i/í/y/ý"}, - {"Vysoký", "nesl", "kufr"}}, - {"Ryb_ář čekal cel_ den u řek_.", "Rybář, celý, řeky", 3, - {"i/í/y/ý", "i/í/y/ý", "i/í/y/ý"}, - {"Rybář", "celý", "řeky"}}, -}; - -static const ChoiceQ e2_qs[] = { - {"Narodil se v ______ v malé vesnici.", - {"Čechách", "čechách"}, 2, 0}, - {"Přečetl jsem román od ______.", - {"Boženy Němcové", "boženy němcové"}, 2, 0}, - {"Jedeme na ______.", {"Moravu", "moravu"}, 2, 0}, - {"V ______ žije přes milion lidí.", {"Praze", "praze"}, 2, 0}, - {"Navštívili jsme ______.", - {"Národní muzeum", "národní muzeum"}, 2, 0}, -}; - -static const MluvItem e3_items[] = { - {"Krásný den se chýlil ke konci. — slovo „Krásný“", - "přídavné jméno", 1, {"slovní druh"}, - {"přídavné jméno|přídavné jmeno|adjektivum"}}, - {"Šel rychle domů. — slovo „rychle“", - "příslovce", 1, {"slovní druh"}, - {"příslovce|adverbium"}}, - {"Sedím před školou. — slovo „před“", - "předložka", 1, {"slovní druh"}, - {"předložka|prepozice"}}, - {"To je jeho kniha. — slovo „jeho“", - "zájmeno", 1, {"slovní druh"}, - {"zájmeno|zájmeno|pronomen"}}, - {"Ach, to je škoda! — slovo „Ach“", - "citoslovce", 1, {"slovní druh"}, - {"citoslovce|interjekce"}}, - {"Přišel jsem, ale bylo pozdě. — slovo „ale“", - "spojka", 1, {"slovní druh"}, - {"spojka|konjunkce"}}, - {"Napočítal jsem pět jablek. — slovo „pět“", - "číslovka", 1, {"slovní druh"}, - {"číslovka|cislovka|numerale"}}, - {"Učitel vysvětloval látku. — slovo „Učitel“", - "podstatné jméno", 1, {"slovní druh"}, - {"podstatné jméno|podstatné jmeno|substantivum"}}, -}; - -static const MluvItem e4_items[] = { - {"Kniha leží na stole. — slovo „stole“ (stůl)", - "mužský rod, jednotné číslo, 6. pád (lokál)", 3, - {"rod", "číslo", "pád"}, - {"mužský|mužský rod|maskulinum", - "jednotné|jednotné číslo|singulár", - "6|lokál|šestý|6. pád"}}, - {"Povídám si s kamarády. — slovo „kamarády“ (kamarád)", - "mužský rod, množné číslo, 7. pád (instrumentál)", 3, - {"rod", "číslo", "pád"}, - {"mužský|mužský rod|maskulinum", - "množné|množné číslo|plurál", - "7|instrumentál|sedmý|7. pád"}}, - {"Vidím krásnou horu. — slovo „horu“ (hora)", - "ženský rod, jednotné číslo, 4. pád (akuzativ)", 3, - {"rod", "číslo", "pád"}, - {"ženský|ženský rod|femininum", - "jednotné|jednotné číslo|singulár", - "4|akuzativ|čtvrtý|4. pád"}}, - {"To je dům mého souseda. — slovo „souseda“ (soused)", - "mužský rod, jednotné číslo, 2. pád (genitiv)", 3, - {"rod", "číslo", "pád"}, - {"mužský|mužský rod|maskulinum", - "jednotné|jednotné číslo|singulár", - "2|genitiv|druhý|2. pád"}}, - {"Děti si hrají na zahradě. — slovo „Děti“ (dítě)", - "střední rod, množné číslo, 1. pád (nominativ)", 3, - {"rod", "číslo", "pád"}, - {"střední|střední rod|neutrum", - "množné|množné číslo|plurál", - "1|nominativ|první|1. pád"}}, -}; - -static const MluvItem e5_items[] = { - {"čteme", "1. osoba, množné číslo, přítomný čas, oznamovací způsob", 4, - {"osoba", "číslo", "čas", "způsob"}, - {"1|1.|první|první osoba|1. osoba", - "množné|množné číslo|plurál", - "přítomný|přítomný čas|přítomný čas", - "oznamovací|oznamovací způsob|indikativ"}}, - {"běžel", "3. osoba, jednotné číslo, minulý čas, oznamovací způsob", 4, - {"osoba", "číslo", "čas", "způsob"}, - {"3|3.|třetí|třetí osoba|3. osoba", - "jednotné|jednotné číslo|singulár", - "minulý|minulý čas|minulý čas", - "oznamovací|oznamovací způsob|indikativ"}}, - {"přečtěte", - "2. osoba, množné číslo, rozkazovací způsob (čas se neurčuje)", 4, - {"osoba", "číslo", "čas", "způsob"}, - {"2|2.|druhý|druhá osoba|2. osoba", - "množné|množné číslo|plurál", - "neurčitý|nestanovený|neurčený", - "rozkazovací|rozkazovací způsob|imperativ"}}, - {"by zpíval", - "3. osoba, jednotné číslo, podmiňovací způsob přítomný", 4, - {"osoba", "číslo", "čas", "způsob"}, - {"3|3.|třetí|třetí osoba|3. osoba", - "jednotné|jednotné číslo|singulár", - "neurčitý|nestanovený|přítomný", - "podmiňovací|podmiňovací způsob|kondicionál"}}, - {"budou pracovat", - "3. osoba, množné číslo, budoucí čas, oznamovací způsob", 4, - {"osoba", "číslo", "čas", "způsob"}, - {"3|3.|třetí|třetí osoba|3. osoba", - "množné|množné číslo|plurál", - "budoucí|budoucí čas|futurum", - "oznamovací|oznamovací způsob|indikativ"}}, -}; - -static const MluvRevealItem e6_items[] = { - {"napsali", "na- / ps- / -a- / -li"}, - {"přečíst", "pře- / číst"}, - {"zahradník", "za- / hrad- / -ník / -Ø"}, - {"nepřátelský", "ne- / přátel- / -ský / -Ø"}, - {"výběr", "vý- / bér- / -Ø / -Ø"}, -}; - -static const MluvItem e7_items[] = { - {"Malá holčička plakala. — větný člen „Malá holčička“", - "podmět", 1, {"větný člen"}, {"podmět|subjekt"}}, - {"Otec pracuje v garáži. — větný člen „v garáži“", - "příslovečné určení místa", 1, {"větný člen"}, - {"příslovečné určení místa|příslovečné určení místa (PU místa)|" - "příslovečné určení|adverbiále místa"}}, - {"Sestra je učitelka. — větný člen „je učitelka“", - "přísudek jmenný se sponou", 1, {"větný člen"}, - {"přísudek jmenný se sponou|přísudek jmenný|jmenný přísudek se sponou|" - "přísudek se sponou"}}, - {"Dal jsem knihu bratrovi. — větný člen „knihu“", - "předmět", 1, {"větný člen"}, {"předmět|objekt"}}, - {"Přišel unavený. — větný člen „unavený“", - "doplněk", 1, {"větný člen"}, {"doplněk"}}, - {"Pomalu šel domů. — větný člen „Pomalu“", - "příslovečné určení způsobu", 1, {"větný člen"}, - {"příslovečné určení způsobu|příslovečné určení způsobu (PU způsobu)|" - "příslovečné určení|adverbiále způsobu"}}, -}; - -static const MluvItem e8_items[] = { - {"Věřím, že uspěješ.", "vedlejší věta předmětná", 1, {"druh vedlejší věty"}, - {"vedlejší věta předmětná|věta předmětná|předmětná"}}, - {"Udělám to, jak budu moci.", "vedlejší věta příslovečná způsobová", 1, - {"druh vedlejší věty"}, - {"vedlejší věta příslovečná způsobová|příslovečná způsobová|způsobová"}}, - {"Přišel, protože chtěl pomoci.", "vedlejší věta příslovečná příčinná", 1, - {"druh vedlejší věty"}, - {"vedlejší věta příslovečná příčinná|příslovečná příčinná|příčinná"}}, - {"Řekni mi, kde bydlíš.", "vedlejší věta předmětná", 1, - {"druh vedlejší věty"}, - {"vedlejší věta předmětná|věta předmětná|předmětná"}}, - {"Byl tak unavený, že usnul okamžitě.", - "vedlejší věta příslovečná následková", 1, {"druh vedlejší věty"}, - {"vedlejší věta příslovečná následková|příslovečná následková|následková"}}, -}; - -static const MluvItem e9_items[] = { - {"rychlý", "hbitý, svižný", 1, {"synonymum"}, - {"hbitý|svižný|rychlý|čilý|bystrý|prudký"}}, - {"smutný", "nešťastný, zarmoucený", 1, {"synonymum"}, - {"nešťastný|zarmoucený|tesklivý|skličený|žalostný"}}, - {"začít", "zahájit, započít", 1, {"synonymum"}, - {"zahájit|započít|začínat|rozpoutat|zahajovat"}}, - {"krásný", "nádherný, překrásný", 1, {"synonymum"}, - {"nádherný|překrásný|kouzelný|půvabný|okouzlující"}}, - {"mluvit", "hovořit, promlouvat", 1, {"synonymum"}, - {"hovořit|promlouvat|vyprávět|říkat|povídat"}}, -}; - -static const MluvItem e10_items[] = { - {"starý ×", "nový", 1, {"opak"}, {"nový|mladý"}}, - {"začátek ×", "konec", 1, {"opak"}, {"konec|závěr"}}, - {"přijít ×", "odejít", 1, {"opak"}, {"odejít|odjet|odcházet"}}, - {"radost ×", "smutek", 1, {"opak"}, {"smutek|žal|zármutek"}}, - {"vysoký ×", "nízký", 1, {"opak"}, {"nízký|malý"}}, -}; - -static const MluvItem e11_items[] = { - {"(s/z)kočit dolů ze stromu", "skočit", 1, {"s-/z-"}, {"skočit"}}, - {"(s/z)epsat úkol", "sepsat", 1, {"s-/z-"}, {"sepsat"}}, - {"(s/z)budovat nový dům", "zbudovat", 1, {"s-/z-"}, {"zbudovat"}}, - {"(s/z)vednout těžký kámen", "zvednout", 1, {"s-/z-"}, {"zvednout"}}, - {"(s/z)pravit auto", "spravit", 1, {"s-/z-"}, {"spravit"}}, -}; - -static const MluvRevealItem e12_items[] = { - {"Koupil jsem novej kabát.", "nový („novej“ je nespisovné)"}, - {"Přišli jsme tam, kdy jsme měli.", - "kdy → když: „Přišli jsme tam, když jsme měli.“"}, - {"Ona mě o tom neřekla nic.", - "mě → mi (dativ): „Ona mi o tom neřekla nic.“"}, - {"Je to nejlepší film, který jsem viděl vůbec.", - "„vůbec nejlepší film“: „Je to vůbec nejlepší film, který jsem viděl.“"}, - {"Byl jsem na nákupu a koupil chléb.", - "„Byl jsem nakupovat a koupil jsem chléb.“"}, -}; - -static const MluvItem e13_items[] = { - {"Viděl jsem (ten starý muž) ______.", "toho starého muže", 1, - {"správný tvar"}, {"toho starého muže|toho starého muže,"}}, - {"Mluvil jsem s (moje sestra) ______.", "mojí sestrou", 1, - {"správný tvar"}, {"mojí sestrou|mou sestrou|svou sestrou"}}, - {"Jdu do (škola) ______.", "školy", 1, {"správný tvar"}, {"školy"}}, - {"Sedím vedle (kamarád) ______.", "kamaráda", 1, - {"správný tvar"}, {"kamaráda"}}, - {"Vzpomínám na (dětství) ______.", "dětství", 1, - {"správný tvar"}, {"dětství"}}, -}; - -static const ChoiceQ e14_qs[] = { - {"Slovo „záříjový“ je:", {"správně", "chybně"}, 2, 1}, - {"Které slovo je přídavné jméno?", - {"rychle", "rychlost", "rychlý", "zrychlení"}, 4, 2}, - {"Věta „Petr čte knihu.“ je:", - {"souvětí", "věta jednoduchá", "věta bez podmětu", "věta zvolací"}, 4, 1}, - {"Slovo „příroda“ je utvořeno:", - {"odvozením", "skládáním", "zkracováním", "přejímáním"}, 4, 0}, - {"Která dvojice jsou synonyma?", - {"rychlý – pomalý", "jít – přijít", "smutný – nešťastný", - "velký – malý"}, 4, 2}, -}; - -static const char *e14_expl[] = { - "Správně je „zářijový“ (nikoli „záříjový“).", - "„rychlý“ je přídavné jméno; „rychle“ je příslovce.", - "Věta má jen jeden přísudek („čte“), jde o větu jednoduchou.", - "„příroda“ je utvořena odvozením, není to složenina.", - "Synonyma vyjadřují stejný význam: „smutný“ a „nešťastný“.", -}; - -static const MluvRevealItem e15_items[] = { - {"Matka řekla: „Pojď se najíst.“", - "Matka řekla, abych přišel se najíst."}, - {"Učitel řekl: „Zítra bude písemka.“", - "Učitel řekl, že zítra bude písemka."}, - {"Kamarád se zeptal: „Kde bydlíš?“", - "Kamarád se zeptal, kde bydlím."}, -}; - -static const MluvRevealItem e16_items[] = { - {"bydlet × žít", - "bydlet = mít domov někde; žít = existovat, prožívat život"}, - {"říkat × vyprávět", - "říkat = sdělovat informaci; vyprávět = podrobně popisovat příběh"}, - {"dívat se × vidět", - "dívat se = záměrně sledovat; vidět = vnímat zrakem (i neúmyslně)"}, - {"učit × učit se", - "učit = předávat znalosti druhým; učit se = sám nabývat znalosti"}, - {"přinést × donést", - "přinést = přinést sem (k mluvčímu); donést = odnést tam (od mluvčího)"}, -}; - -static const MluvRevealItem e17_items[] = { - {"Přišel jsem domů unavený hladový a promrzlý.", - "Přišel jsem domů unavený, hladový a promrzlý."}, - {"Když dorazil vlak nastoupili všichni cestující.", - "Když dorazil vlak, nastoupili všichni cestující."}, - {"Myslím že dnes bude pršet.", "Myslím, že dnes bude pršet."}, - {"Jana která je moje nejlepší kamarádka bydlí vedle.", - "Jana, která je moje nejlepší kamarádka, bydlí vedle."}, - {"Pes štěkal ale nikdo nepřicházel.", - "Pes štěkal, ale nikdo nepřicházel."}, -}; - -static const MluvItem e18_items[] = { - {"Slunce se usmívalo na celé město.", "personifikace", 1, - {"druh pojmenování"}, {"personifikace|zosobnění"}}, - {"Je silný jako býk.", "přirovnání", 1, - {"druh pojmenování"}, {"přirovnání|komparace"}}, - {"Moře hněvu ho zaplavilo.", "metafora", 1, - {"druh pojmenování"}, {"metafora"}}, - {"Čekal jsem na tebe věčnost.", "hyperbola", 1, - {"druh pojmenování"}, {"hyperbola|nadsázka"}}, - {"Přečetl celého Shakespeara.", "metonymie", 1, - {"druh pojmenování"}, {"metonymie"}}, -}; - -static const MluvItem e19_items[] = { - {"Narodil se roku 1890 v Praze. Vystudoval práva a poté pracoval jako " - "úředník…", "životopis", 1, {"slohový útvar"}, {"životopis|biografie"}}, - {"Byl to chlapec střední postavy, s hnědýma očima a klidným výrazem…", - "charakteristika", 1, {"slohový útvar"}, {"charakteristika"}}, - {"Jednoho dne jsem šel lesem, když tu najednou jsem zaslechl podivný " - "zvuk…", "vyprávění", 1, {"slohový útvar"}, {"vyprávění"}}, - {"Mnozí se ptají, zda má smysl číst knihy v době internetu. Domnívám " - "se…", "úvaha", 1, {"slohový útvar"}, {"úvaha"}}, - {"Místnost byla malá, se dvěma okny na jih. U zdi stála stará skříň…", - "popis", 1, {"slohový útvar"}, {"popis"}}, -}; - -static const ChoiceQ e20_qs[] = { - {"Které slovo není příslovce?", - {"rychle", "tam", "hezký", "brzy"}, 4, 2}, - {"Ve větě „Petr dal Pavlovi knihu“ je slovo „Pavlovi“:", - {"podmět", "přísudek", "předmět", "příslovečné určení"}, 4, 2}, - {"Slovo „nejhezčí“ obsahuje:", - {"předponu a příponu", "pouze předponu", "kořen a příponu", - "pouze příponu"}, 4, 0}, - {"Která věta je souvětí souřadné slučovací?", - {"Přišel, protože chtěl pomoci.", "Šel domů a spal.", - "Věřím, že přijdeš.", "Udělám to, jak budeš chtít."}, 4, 1}, - {"Příslovce „rychle“ je stupňováno jako:", - {"rychle – rychleji – nejrychleji", - "rychle – více rychle – nejvíce rychle", - "rychle – rychlé – nejrychlejší", "nelze stupňovat"}, 4, 0}, -}; - -GtkWidget *build_mluvnice_exercise_page(int n) { - switch (n) { - case 1: - return mluv_typed_page(1, - "Pravopis – i/y po obojetných souhláskách", - "Doplňte i/í nebo y/ý.", NULL, - e1_items, G_N_ELEMENTS(e1_items)); - case 2: - return mluv_choice_page(2, "Pravopis – velká/malá písmena", - "Vyberte správnou variantu.", NULL, - e2_qs, NULL, G_N_ELEMENTS(e2_qs)); - case 3: - return mluv_typed_page(3, "Slovní druhy", - "Určete slovní druh podtržených slov.", - "Do pole napište název slovního druhu.", - e3_items, G_N_ELEMENTS(e3_items)); - case 4: - return mluv_typed_page(4, - "Mluvnické kategorie – podstatná jména", - "Určete rod, číslo a pád podtržených slov.", - "Vyplňte tři pole: rod, číslo a pád.", - e4_items, G_N_ELEMENTS(e4_items)); - case 5: - return mluv_typed_page(5, "Mluvnické kategorie – slovesa", - "Určete osobu, číslo, čas a způsob u těchto sloves.", - "U rozkazovacího a podmiňovacího způsobu napište do pole " - "čas „neurčitý“.", - e5_items, G_N_ELEMENTS(e5_items)); - case 6: - return mluv_reveal_page(6, "Slovotvorba", - "Rozeberte slova na morfémy.", - "Určete předponu, kořen, příponu a koncovku.", - e6_items, G_N_ELEMENTS(e6_items)); - case 7: - return mluv_typed_page(7, "Větné členy", - "Určete větný člen podtržených výrazů.", NULL, - e7_items, G_N_ELEMENTS(e7_items)); - case 8: - return mluv_typed_page(8, "Druhy vedlejších vět", - "Určete druh vedlejší věty.", NULL, - e8_items, G_N_ELEMENTS(e8_items)); - case 9: - return mluv_typed_page(9, "Synonyma", - "Ke každému slovu napište synonymum.", NULL, - e9_items, G_N_ELEMENTS(e9_items)); - case 10: - return mluv_typed_page(10, "Antonyma", "Napište opak.", NULL, - e10_items, G_N_ELEMENTS(e10_items)); - case 11: - return mluv_typed_page(11, - "Pravopis – s/z na začátku slova", - "Vyberte správnou předponu s-/z-.", NULL, - e11_items, G_N_ELEMENTS(e11_items)); - case 12: - return mluv_reveal_page(12, "Skladba – najděte chybu", - "Každá věta obsahuje jednu chybu. Najděte ji a opravte.", - NULL, e12_items, G_N_ELEMENTS(e12_items)); - case 13: - return mluv_typed_page(13, "Tvarosloví – správný tvar", - "Dejte slovo do správného tvaru.", NULL, - e13_items, G_N_ELEMENTS(e13_items)); - case 14: - return mluv_choice_page(14, "Výběr ze čtyř možností", - "Vyberte správnou odpověď.", NULL, - e14_qs, e14_expl, G_N_ELEMENTS(e14_qs)); - case 15: - return mluv_reveal_page(15, "Přímá a nepřímá řeč", - "Přepište přímou řeč na nepřímou.", NULL, - e15_items, G_N_ELEMENTS(e15_items)); - case 16: - return mluv_reveal_page(16, "Slovní zásoba – rozdíly", - "Vysvětlete rozdíl mezi těmito dvojicemi slov.", NULL, - e16_items, G_N_ELEMENTS(e16_items)); - case 17: - return mluv_reveal_page(17, "Interpunkce", - "Doplňte čárky tam, kde patří.", NULL, - e17_items, G_N_ELEMENTS(e17_items)); - case 18: - return mluv_typed_page(18, "Obrazná pojmenování", - "Určete, o jaký druh obrazného pojmenování jde.", NULL, - e18_items, G_N_ELEMENTS(e18_items)); - case 19: - return mluv_typed_page(19, "Stylistika – slohové útvary", - "Přiřaďte ukázku ke správnému slohovému útvaru.", NULL, - e19_items, G_N_ELEMENTS(e19_items)); - case 20: - return mluv_choice_page(20, "Souhrnné opakování", - "Vyberte správnou odpověď.", NULL, - e20_qs, NULL, G_N_ELEMENTS(e20_qs)); - default: - return NULL; - } -} - -GtkWidget *build_mluvnice_page(void) { - return build_unit_page(&mluv_unit); -} diff --git a/src/navigation.c b/src/navigation.c deleted file mode 100644 index 59eaa74..0000000 --- a/src/navigation.c +++ /dev/null @@ -1,287 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Navigation */ -/* ------------------------------------------------------------------ */ - -/* motion: -1 slides back, 0 crossfades, 1 slides forward. */ -void show_page(const char *name, int motion) { - GtkStackTransitionType type = GTK_STACK_TRANSITION_TYPE_CROSSFADE; - guint ms = 180; - - if (!main_stack || !name || !name[0]) - return; - if (!gtk_stack_get_child_by_name(main_stack, name)) - return; - if (motion > 0) { - type = GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT; - ms = 200; - } else if (motion < 0) { - type = GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT; - ms = 200; - } - gtk_stack_set_transition_type(main_stack, type); - gtk_stack_set_transition_duration(main_stack, ms); - gtk_stack_set_visible_child_name(main_stack, name); -} - -void on_nav_clicked(GtkButton *button, gpointer user_data) { - const char *target = g_object_get_data(G_OBJECT(button), "target"); - int back = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "nav-back")); - - (void)user_data; - if (target) - show_page(target, back ? -1 : 1); -} - -void on_continue_clicked(GtkButton *button, gpointer user_data) { - (void)button; - (void)user_data; - show_page("subjects", 1); -} - -GtkWidget *make_back_button(const char *target) { - GtkWidget *back = gtk_button_new(); - GtkWidget *icon = gtk_drawing_area_new(); - - gtk_widget_set_size_request(icon, 14, 14); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(icon), draw_back_icon, - NULL, NULL); - gtk_button_set_child(GTK_BUTTON(back), icon); - gtk_widget_add_css_class(back, "back-btn"); - gtk_widget_set_valign(back, GTK_ALIGN_CENTER); - i18n_bind(back, "back", 2); - g_signal_connect_swapped(back, "state-flags-changed", - G_CALLBACK(gtk_widget_queue_draw), icon); - g_object_set_data_full(G_OBJECT(back), "target", g_strdup(target), g_free); - g_object_set_data(G_OBJECT(back), "nav-back", GINT_TO_POINTER(1)); - g_signal_connect(back, "clicked", G_CALLBACK(on_nav_clicked), NULL); - return back; -} - -GtkWidget *top_bar(const char *back_target, const char *title, - const char *subtitle) { - GtkWidget *top = gtk_center_box_new(); - gtk_widget_add_css_class(top, "page-top"); - gtk_widget_set_margin_top(top, 8); - gtk_widget_set_margin_bottom(top, 18); - - GtkWidget *back = make_back_button(back_target); - gtk_center_box_set_start_widget(GTK_CENTER_BOX(top), back); - - GtkWidget *center = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_widget_set_valign(center, GTK_ALIGN_CENTER); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(top), center); - - GtkWidget *heading = gtk_label_new(NULL); - i18n_bind(heading, title, 0); - gtk_widget_set_halign(heading, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(heading, "roadmap-title"); - gtk_box_append(GTK_BOX(center), heading); - - if (subtitle) { - GtkWidget *sub = gtk_label_new(NULL); - i18n_bind(sub, subtitle, 0); - gtk_widget_set_halign(sub, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(sub, "roadmap-sub"); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_max_width_chars(GTK_LABEL(sub), 56); - gtk_box_append(GTK_BOX(center), sub); - } - - return top; -} - -gboolean on_window_key_pressed(GtkEventControllerKey *controller, - guint keyval, guint keycode, - GdkModifierType state, - gpointer user_data) { - GtkWindow *window = user_data; - - (void)controller; - (void)keycode; - - if ((keyval == GDK_KEY_q && - (state & (GDK_SUPER_MASK | GDK_META_MASK)) != 0) || - (keyval == GDK_KEY_F4 && - (state & GDK_ALT_MASK) != 0)) { - GtkApplication *app = gtk_window_get_application(window); - if (app != NULL) - g_application_quit(G_APPLICATION(app)); - return GDK_EVENT_STOP; - } - - if (search_is_open() && keyval == GDK_KEY_Escape) { - search_close(); - return GDK_EVENT_STOP; - } - - if ((keyval == GDK_KEY_k || keyval == GDK_KEY_K || - keyval == GDK_KEY_f || keyval == GDK_KEY_F) && - (state & (GDK_CONTROL_MASK | GDK_SUPER_MASK | GDK_META_MASK)) != 0) { - search_open(); - return GDK_EVENT_STOP; - } - - return GDK_EVENT_PROPAGATE; -} - -/* ------------------------------------------------------------------ */ -/* Welcome page */ -/* ------------------------------------------------------------------ */ - -static GtkWidget *welcome_feature(const char *title_key, const char *body_key, - const char *link_key) { - GtkWidget *card; - GtkWidget *title; - GtkWidget *body; - GtkWidget *link; - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - gtk_widget_add_css_class(card, "welcome-feature"); - gtk_widget_set_hexpand(card, TRUE); - - title = gtk_label_new(NULL); - i18n_bind(title, title_key, 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "welcome-feature-title"); - gtk_box_append(GTK_BOX(card), title); - - body = gtk_label_new(NULL); - i18n_bind(body, body_key, 0); - gtk_widget_set_halign(body, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(body), TRUE); - gtk_label_set_xalign(GTK_LABEL(body), 0.0); - gtk_label_set_max_width_chars(GTK_LABEL(body), 52); - gtk_widget_add_css_class(body, "welcome-feature-body"); - gtk_box_append(GTK_BOX(card), body); - - link = gtk_button_new(); - i18n_bind(link, link_key, 1); - gtk_widget_set_halign(link, GTK_ALIGN_START); - gtk_widget_add_css_class(link, "welcome-link"); - gtk_box_append(GTK_BOX(card), link); - g_signal_connect(link, "clicked", G_CALLBACK(on_continue_clicked), NULL); - - return card; -} - -static GtkWidget *welcome_stat(void) { - GtkWidget *badge; - GtkWidget *value; - GtkWidget *label; - - badge = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_add_css_class(badge, "welcome-badge"); - gtk_widget_set_valign(badge, GTK_ALIGN_CENTER); - gtk_widget_set_halign(badge, GTK_ALIGN_CENTER); - - value = gtk_label_new(NULL); - i18n_bind(value, "welcome_stat_value", 0); - gtk_widget_add_css_class(value, "welcome-badge-value"); - gtk_box_append(GTK_BOX(badge), value); - - label = gtk_label_new(NULL); - i18n_bind(label, "welcome_stat_label", 0); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); - gtk_widget_add_css_class(label, "welcome-badge-label"); - gtk_box_append(GTK_BOX(badge), label); - - return badge; -} - -GtkWidget *build_welcome_page(void) { - GtkWidget *scroll; - GtkWidget *page; - GtkWidget *hero; - GtkWidget *copy; - GtkWidget *kicker; - GtkWidget *heading; - GtkWidget *body; - GtkWidget *actions; - GtkWidget *button; - GtkWidget *features; - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_hexpand(scroll, TRUE); - gtk_widget_set_vexpand(scroll, TRUE); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class(page, "welcome-page"); - gtk_widget_set_halign(page, GTK_ALIGN_CENTER); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_size_request(page, 760, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), page); - - hero = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 40); - gtk_widget_add_css_class(hero, "welcome-hero"); - gtk_widget_set_hexpand(hero, TRUE); - gtk_box_append(GTK_BOX(page), hero); - - copy = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(copy, TRUE); - gtk_box_append(GTK_BOX(hero), copy); - - kicker = gtk_label_new(NULL); - i18n_bind(kicker, "welcome_kicker", 0); - gtk_widget_set_halign(kicker, GTK_ALIGN_START); - gtk_widget_add_css_class(kicker, "welcome-kicker"); - gtk_box_append(GTK_BOX(copy), kicker); - - heading = gtk_label_new(NULL); - welcome_heading = heading; - i18n_bind(heading, "welcome_title", 0); - gtk_widget_set_halign(heading, GTK_ALIGN_START); - gtk_label_set_justify(GTK_LABEL(heading), GTK_JUSTIFY_LEFT); - gtk_label_set_xalign(GTK_LABEL(heading), 0.0); - gtk_label_set_wrap(GTK_LABEL(heading), TRUE); - gtk_widget_add_css_class(heading, "heading"); - gtk_widget_set_margin_top(heading, 10); - gtk_box_append(GTK_BOX(copy), heading); - - body = gtk_label_new(NULL); - i18n_bind(body, "welcome_body", 0); - gtk_label_set_wrap(GTK_LABEL(body), TRUE); - gtk_label_set_xalign(GTK_LABEL(body), 0.0); - gtk_label_set_max_width_chars(GTK_LABEL(body), 42); - gtk_widget_set_halign(body, GTK_ALIGN_START); - gtk_widget_set_margin_top(body, 14); - gtk_widget_add_css_class(body, "welcome-body"); - gtk_box_append(GTK_BOX(copy), body); - - actions = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_widget_set_margin_top(actions, 28); - gtk_box_append(GTK_BOX(copy), actions); - - button = gtk_button_new(); - i18n_bind(button, "continue", 1); - gtk_widget_set_halign(button, GTK_ALIGN_START); - gtk_widget_add_css_class(button, "btn-primary"); - gtk_box_append(GTK_BOX(actions), button); - g_signal_connect(button, "clicked", G_CALLBACK(on_continue_clicked), NULL); - - gtk_box_append(GTK_BOX(hero), welcome_stat()); - - { - GtkWidget *notes = build_changelog_card(); - - gtk_widget_set_margin_top(notes, 28); - gtk_box_append(GTK_BOX(page), notes); - } - - features = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_margin_top(features, 36); - gtk_box_append(GTK_BOX(page), features); - gtk_box_append(GTK_BOX(features), - welcome_feature("welcome_feat1_title", - "welcome_feat1_body", - "welcome_feat1_link")); - gtk_box_append(GTK_BOX(features), - welcome_feature("welcome_feat2_title", - "welcome_feat2_body", - "welcome_feat2_link")); - - return scroll; -} diff --git a/src/net.c b/src/net.c deleted file mode 100644 index f970e4b..0000000 --- a/src/net.c +++ /dev/null @@ -1,4003 +0,0 @@ -#include "graduately.h" - -/* ---- Computer networks: subject path, lesson & exercise ------------ */ - - -NetLesson net_lessons[NET_LESSONS] = { - /* UI unit N maps to lesson content: unit 1 = IP/VLSM (extra); - * units 2–27 = source topics (Základní pojmy … bezdrátové sítě). */ - { .n_slides = NET_SLIDES, .unit_page = "netunit1", .ex_page = "netex1" }, - { .n_slides = NET2_SLIDES, .unit_page = "netunit2", .ex_page = "netex2" }, - { .n_slides = NET3_SLIDES, .unit_page = "netunit3", .ex_page = "netex3" }, - { .n_slides = NET4_SLIDES, .unit_page = "netunit4", .ex_page = "netex4" }, - { .n_slides = NET5_SLIDES, .unit_page = "netunit5", .ex_page = "netex5" }, - { .n_slides = NET6_SLIDES, .unit_page = "netunit6", .ex_page = "netex6" }, - { .n_slides = NET7_SLIDES, .unit_page = "netunit7", .ex_page = "netex7" }, - { .n_slides = NET8_SLIDES, .unit_page = "netunit8", .ex_page = "netex8" }, - { .n_slides = NET9_SLIDES, .unit_page = "netunit9", .ex_page = "netex9" }, - { .n_slides = NET10_SLIDES, .unit_page = "netunit10", .ex_page = "netex10" }, - { .n_slides = NET11_SLIDES, .unit_page = "netunit11", .ex_page = "netex11" }, - { .n_slides = NET12_SLIDES, .unit_page = "netunit12", .ex_page = "netex12" }, - { .n_slides = NET13_SLIDES, .unit_page = "netunit13", .ex_page = "netex13" }, - { .n_slides = NET14_SLIDES, .unit_page = "netunit14", .ex_page = "netex14" }, - { .n_slides = NET15_SLIDES, .unit_page = "netunit15", .ex_page = "netex15" }, - { .n_slides = NET16_SLIDES, .unit_page = "netunit16", .ex_page = "netex16" }, - { .n_slides = NET17_SLIDES, .unit_page = "netunit17", .ex_page = "netex17" }, - { .n_slides = NET18_SLIDES, .unit_page = "netunit18", .ex_page = "netex18" }, - { .n_slides = NET19_SLIDES, .unit_page = "netunit19", .ex_page = "netex19" }, - { .n_slides = NET20_SLIDES, .unit_page = "netunit20", .ex_page = "netex20" }, - { .n_slides = NET21_SLIDES, .unit_page = "netunit21", .ex_page = "netex21" }, - { .n_slides = NET22_SLIDES, .unit_page = "netunit22", .ex_page = "netex22" }, - { .n_slides = NET23_SLIDES, .unit_page = "netunit23", .ex_page = "netex23" }, - { .n_slides = NET24_SLIDES, .unit_page = "netunit24", .ex_page = "netex24" }, - { .n_slides = NET25_SLIDES, .unit_page = "netunit25", .ex_page = "netex25" }, - { .n_slides = NET26_SLIDES, .unit_page = "netunit26", .ex_page = "netex26" }, - { .n_slides = NET27_SLIDES, .unit_page = "netunit27", .ex_page = "netex27" }, -}; - -void net_paragraph(GtkWidget *box, const char *text) { - GtkWidget *l = gtk_label_new(text); - - gtk_widget_set_halign(l, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(l), TRUE); - gtk_widget_add_css_class(l, "ex-prompt"); - gtk_box_append(GTK_BOX(box), l); -} - -void net_heading(GtkWidget *box, const char *text) { - GtkWidget *l = gtk_label_new(text); - - gtk_widget_set_halign(l, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(l), TRUE); - gtk_widget_set_margin_top(l, 6); - gtk_widget_add_css_class(l, "ex-sub"); - gtk_box_append(GTK_BOX(box), l); -} - -/* Note-card slides with text that scales with the window. */ -GtkWidget *net_note_host; -int net_note_last_w = -1; -NetLesson *net_notes_target; - -void net_lesson_notes_ensure(NetLesson *L) { - if (L->note_kicks) - return; - L->note_kicks = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - L->note_titles = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); - L->note_bodies = g_array_new(FALSE, FALSE, sizeof(GtkWidget *)); -} - -void net_note_font(GtkWidget *l, int px) { - PangoAttrList *attrs = pango_attr_list_new(); - - pango_attr_list_insert(attrs, pango_attr_size_new(px * PANGO_SCALE)); - gtk_label_set_attributes(GTK_LABEL(l), attrs); - pango_attr_list_unref(attrs); -} - -void net_rescale_lesson_notes(NetLesson *L, int body, int head, int kick) { - if (!L || !L->note_kicks) - return; - for (guint i = 0; i < L->note_kicks->len; i++) - net_note_font(g_array_index(L->note_kicks, GtkWidget *, i), kick); - for (guint i = 0; i < L->note_titles->len; i++) - net_note_font(g_array_index(L->note_titles, GtkWidget *, i), head); - for (guint i = 0; i < L->note_bodies->len; i++) - net_note_font(g_array_index(L->note_bodies, GtkWidget *, i), body); -} - -void net_rescale_notes_at(int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - - for (int i = 0; i < NET_LESSONS; i++) - net_rescale_lesson_notes(&net_lessons[i], body, head, kick); -} - -void net_rescale_notes(void) { - int w = net_note_host ? gtk_widget_get_allocated_width(net_note_host) : 0; - - net_rescale_notes_at(w); -} - -gboolean net_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width != net_note_last_w) { - net_note_last_w = width; - net_rescale_notes_at(width); - } - return G_SOURCE_CONTINUE; -} - -GtkWidget *net_slide_card(const char *cls) { - GtkWidget *l = gtk_label_new(NULL); - - gtk_widget_add_css_class(l, cls); - gtk_label_set_wrap(GTK_LABEL(l), TRUE); - gtk_label_set_justify(GTK_LABEL(l), GTK_JUSTIFY_CENTER); - gtk_widget_set_hexpand(l, TRUE); - gtk_widget_set_halign(l, GTK_ALIGN_FILL); - return l; -} - -void net_note_kicker(GtkWidget *box, const char *text) { - GtkWidget *l = net_slide_card("notes-kicker"); - - gtk_label_set_text(GTK_LABEL(l), text); - gtk_box_append(GTK_BOX(box), l); - if (net_notes_target) - g_array_append_val(net_notes_target->note_kicks, l); -} - -void net_note_title(GtkWidget *box, const char *text) { - GtkWidget *l = net_slide_card("notes-title"); - - gtk_label_set_text(GTK_LABEL(l), text); - gtk_box_append(GTK_BOX(box), l); - if (net_notes_target) - g_array_append_val(net_notes_target->note_titles, l); -} - -void net_note_line(GtkWidget *box, const char *text, gboolean tip) { - GtkWidget *l = net_slide_card(tip ? "notes-tip" : "notes-body"); - - gtk_label_set_text(GTK_LABEL(l), text); - gtk_widget_set_margin_top(l, 2); - gtk_box_append(GTK_BOX(box), l); - if (net_notes_target) - g_array_append_val(net_notes_target->note_bodies, l); -} - -void net_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - - g_snprintf(name, sizeof(name), "net_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -void net_lessons_apply_lang(void) { - for (int i = 0; i < NET_LESSONS; i++) - net_slide_apply(&net_lessons[i]); -} - -void net_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - net_slide_apply(L); - show_page(L->unit_page, 1); -} - -void net_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx > 0) { - L->idx--; - net_slide_apply(L); - } -} - -void net_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - net_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -GtkWidget *net_scroll; -GtkWidget *net_fixed; -GtkWidget *net_rail; -GtkWidget *net_nodes[NET_UNITS]; -GtkWidget *net_labels[NET_UNITS]; -double net_cx[NET_UNITS]; -double net_cy[NET_UNITS]; -int net_cols = 1; -int net_rows = 1; -int net_cw = (int)(2.0 * ROAD_MX + (NET_UNITS - 1) * PATH_SPAC); -int net_ch = (int)(2.0 * ROAD_MY); -guint net_idle; -double net_last_avail = -1.0; -int net_last_cols = -1; -int net_last_rows = -1; -int net_last_cw = -1; -int net_last_ch = -1; -cairo_surface_t *net_rail_cache; -int net_cache_w; -int net_cache_h; - -void net_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= NET_UNITS - 1) { k = NET_UNITS - 2; u = 1.0; } - - p1x = net_cx[k]; p1y = net_cy[k]; - p2x = net_cx[k + 1]; p2y = net_cy[k + 1]; - if (k - 1 >= 0) { p0x = net_cx[k - 1]; p0y = net_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < NET_UNITS) { p3x = net_cx[k + 2]; p3y = net_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -void net_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 24.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - net_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - net_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -void net_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(NET_UNITS - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= NET_UNITS; rows++) { - int cols = (NET_UNITS + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > NET_UNITS) - rows = NET_UNITS; - net_rows = rows; - net_cols = (NET_UNITS + rows - 1) / rows; - if (net_cols < 1) - net_cols = 1; - net_cw = (int)(2.0 * ROAD_MX + (net_cols - 1) * PATH_SPAC); - net_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * net_cols; - int len = MIN(net_cols, NET_UNITS - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (net_cols - 1 - c); - net_cx[i] = ROAD_MX + cc * PATH_SPAC; - net_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -void net_apply_layout(void) { - if (!net_fixed) - return; - - if (net_cols == net_last_cols && net_rows == net_last_rows && - net_cw == net_last_cw && net_ch == net_last_ch) - return; - - net_last_cols = net_cols; - net_last_rows = net_rows; - net_last_cw = net_cw; - net_last_ch = net_ch; - if (net_rail_cache) { - cairo_surface_destroy(net_rail_cache); - net_rail_cache = NULL; - } - - for (int i = 0; i < NET_UNITS; i++) { - if (!net_nodes[i] || !net_labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(net_fixed), net_nodes[i], - (int)(net_cx[i] - NODE_SIZE / 2.0), - (int)(net_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(net_fixed), net_labels[i], - (int)(net_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(net_cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(net_fixed, net_cw, net_ch); - gtk_widget_set_size_request(net_rail, net_cw, net_ch); - gtk_fixed_move(GTK_FIXED(net_fixed), net_rail, 0, 0); - gtk_widget_queue_draw(net_rail); -} - -void net_relayout(void) { - GtkAdjustment *hadj; - double avail; - - if (!net_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(net_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - net_last_avail) < 1.0) - return; - net_last_avail = avail; - net_geometry(avail); - net_apply_layout(); -} - -gboolean net_relayout_idle(gpointer data) { - (void)data; - net_idle = 0; - net_relayout(); - return G_SOURCE_REMOVE; -} - -void net_relayout_later(void) { - if (net_idle == 0) - net_idle = g_idle_add(net_relayout_idle, NULL); -} - -void net_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - (void)data; - net_relayout_later(); -} - -void net_render_rail_to(cairo_t *cr) { - const double t_end = (double)(NET_UNITS - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - net_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - net_path(cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -void net_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - (void)area; - (void)width; - (void)height; - (void)data; - - if (!net_rail_cache || net_cache_w != net_cw || net_cache_h != net_ch) { - cairo_t *rcr; - - if (net_rail_cache) - cairo_surface_destroy(net_rail_cache); - net_cache_w = net_cw; - net_cache_h = net_ch; - if (net_cache_w < 1) - net_cache_w = 1; - if (net_cache_h < 1) - net_cache_h = 1; - net_rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - net_cache_w, net_cache_h); - rcr = cairo_create(net_rail_cache); - net_render_rail_to(rcr); - cairo_destroy(rcr); - } - - cairo_set_source_surface(cr, net_rail_cache, 0, 0); - cairo_paint(cr); -} - -void net_rail_theme_reset(void) { - if (net_rail_cache) { - cairo_surface_destroy(net_rail_cache); - net_rail_cache = NULL; - } - if (net_rail) - gtk_widget_queue_draw(net_rail); -} - -void net_add_node(GtkFixed *fixed, int index) { - int num = index + 1; - gboolean locked = index >= NET_LESSONS; - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - static const char *unit_keys[NET_LESSONS] = { - "net_unit1", "net_unit2", "net_unit3", "net_unit4", "net_unit5", - "net_unit6", "net_unit7", "net_unit8", "net_unit9", "net_unit10", - "net_unit11", "net_unit12", "net_unit13", "net_unit14", "net_unit15", - "net_unit16", "net_unit17", "net_unit18", "net_unit19", "net_unit20", - "net_unit21", "net_unit22", "net_unit23", "net_unit24", "net_unit25", - "net_unit26", "net_unit27" - }; - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_sensitive(card, !locked); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - if (locked) - gtk_widget_add_css_class(card, "locked"); - else - gtk_widget_add_css_class(card, "current"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", num); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - if (locked) { - icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 16); - gtk_box_append(GTK_BOX(vbox), icon); - } else { - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - net_lessons[index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(net_open_unit), - &net_lessons[index]); - } - - net_nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - if (index < NET_LESSONS) { - i18n_bind(name, unit_keys[index], 0); - } else { - gtk_widget_add_css_class(name, "unit-name-locked"); - } - net_labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} - -static GtkWidget *net_year_button(int year, gboolean locked) { - static const char *year_keys[] = { - "net_year1", "net_year2", "net_year3", "net_year4", - }; - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 72); - gtk_widget_set_sensitive(btn, !locked); - if (locked) - gtk_widget_add_css_class(btn, "locked"); - else - gtk_widget_add_css_class(btn, "current"); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", year); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, year_keys[year - 1], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - if (locked) { - GtkWidget *sub = gtk_label_new(NULL); - GtkWidget *icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, - 0.4392, 18); - - i18n_bind(sub, "net_year_locked_sub", 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_widget_add_css_class(sub, "unit-name-locked"); - gtk_box_append(GTK_BOX(texts), sub); - gtk_widget_set_valign(icon, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), icon); - } else { - static const char *pages[] = { - "netmap", "net2map", "net3map", "net4map", - }; - static const char *subs[] = { - "net_sub", "net2_sub", "net3_sub", "net4_sub", - }; - GtkWidget *sub = gtk_label_new(NULL); - - i18n_bind(sub, subs[year - 1], 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_widget_add_css_class(sub, "quiz-intro"); - gtk_box_append(GTK_BOX(texts), sub); - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(pages[year - 1]), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - } - - return btn; -} - -GtkWidget *build_netyears_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - int y; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "net_years_title", "net_years_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 360, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (y = 1; y <= 4; y++) - gtk_box_append(GTK_BOX(list), net_year_button(y, FALSE)); - - return page; -} - -GtkWidget *build_netmap_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - - net_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("netyears", "Správa počítačových sítí", "net_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - net_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, net_cw, net_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - net_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, net_cw, net_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), net_draw_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - net_rail = rail; - - for (int i = 0; i < NET_UNITS; i++) - net_add_node(GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(net_adjust_notify), NULL); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(net_adjust_notify), NULL); - - net_apply_layout(); - net_relayout_later(); - refresh_net_completion_ui(); - - return page; -} - -GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - /* sub_key must be a stable string (i18n_bind keeps the pointer). */ - gtk_box_append(GTK_BOX(page), top_bar("netmap", title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - net_note_host = L->stack; - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "net_slide%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, net_note_tick, NULL, NULL); - net_note_last_w = -1; - net_rescale_notes(); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(net_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(net_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - net_slide_apply(L); - - return page; -} - -GtkWidget *build_net_unit1_page(void) { - static const NetSlide slides[NET_SLIDES] = { - { - "1 / 4 • VLSM", "Podsíťování sítí", - "Tip: prefix /n = počet jedniček v masce. /24 = 255.255.255.0", - { - "Cíl: rozdělit jednu IP síť na menší podsítě podle počtu uzlů.", - "Pamatuj si tři role adres v každém bloku:", - "síťová = první adresa bloku", - "broadcast = poslední adresa bloku", - "uzly = vše mezi nimi (síť + 1 až broadcast − 1)", - NULL, - }, - }, - { - "2 / 4 • Velikosti", "Jak velký blok potřebuji?", - "Počet bitů pro uzly h = log₂(velikost), prefix = 32 − h", - { - "Pro X uzlů potřebuješ blok, do kterého se vejde X + 2 adresy " - "(síť a broadcast).", - "Velikost bloku je vždy mocnina dvojky – vezmi nejmenší blok, " - "který je větší nebo roven X + 2.", - "60 uzlů → 62 → blok 64 → /26", - "30 uzlů → 32 → blok 32 → /27", - "14 uzlů → 16 → blok 16 → /28", - "7 uzlů → 9 → blok 16 → /28", - NULL, - }, - }, - { - "3 / 4 • Postup", "Jak na to krok za krokem", - NULL, - { - "1. Seřaď podsítě od největší po nejmenší.", - "2. Pro každou najdi potřebný prefix.", - "3. Začni na síťové adrese ze zadání.", - "4. Rozsah podsítě = od síťové adresy po broadcast.", - "5. Rozsah uzlů = síťová + 1 až broadcast − 1.", - "6. Posuň se hned za broadcast a pokračuj dál.", - NULL, - }, - }, - { - "4 / 4 • Příklad", "Ukázka: 10.0.0.0/24", - "A: 60 uzlů, B: 30, C: 14, D: 7", - { - "A → 10.0.0.0/26 uzly 10.0.0.1–10.0.0.62 " - "broadcast 10.0.0.63", - "B → 10.0.0.64/27 uzly 10.0.0.65–10.0.0.94 " - "broadcast 10.0.0.95", - "C → 10.0.0.96/28 uzly 10.0.0.97–10.0.0.110 " - "broadcast 10.0.0.111", - "D → 10.0.0.112/28 uzly 10.0.0.113–10.0.0.126 " - "broadcast 10.0.0.127", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[0], "net_unit1", "net_unit1_sub", - slides, NET_SLIDES); -} - -GtkWidget *build_net_unit2_page(void) { - static const NetSlide slides[NET2_SLIDES] = { - { - "1 / 5 • Jednotky", "Bit, byte a počítačová síť", - "Tip: 1 B = 8 b → 2⁸ = 256 možných hodnot", - { - "Bit (1 b): základní jednotka informace – 0 nebo 1.", - "0 = nevede proud, 1 = vede proud.", - "Byte (1 B): 1 B = 8 b, nabývá 256 hodnot.", - "Počítačová síť: propojení uzlů (PC a dalších prvků).", - "Vyžaduje hardwarové i softwarové prostředky.", - NULL, - }, - }, - { - "2 / 5 • Propojení", "Trvalé, dočasné a důvody zapojení", - NULL, - { - "Trvalé propojení: kabely – síť zůstává připojená i po přenosu.", - "Dočasné propojení: modem, Wi‑Fi – po přenosu se odpojuje.", - "Důvody zapojení do sítě:", - "sdílení dat (nutná podpora aplikací)", - "sdílení HW (tiskárny, disky) a SW (databáze)", - "vyšší spolehlivost, bezpečnost (přístupová práva)", - "komunikace (e‑mail, hlas)", - NULL, - }, - }, - { - "3 / 5 • Pojmy", "Terminologie sítí", - "Architektura = topologie + standard", - { - "Uzel: jakékoli zařízení (stanice, server, aktivní prvek).", - "Topologie: způsob propojení (hvězda, kruh, sběrnice).", - "Standard: normy pro zpracování dat.", - "Architektura: topologie + standard.", - NULL, - }, - }, - { - "4 / 5 • Rozlehlost", "WAN, MAN a LAN", - NULL, - { - "WAN: rozsáhlé sítě (státy, kontinenty), např. internet.", - "MAN: městské sítě – propojují lokální sítě.", - "LAN: lokální sítě (budova), kabeláž v řádu km,", - "jednotná architektura.", - NULL, - }, - }, - { - "5 / 5 • Uzly", "Server, stanice a peer‑to‑peer", - NULL, - { - "Server: nadřazený, řídící, poskytuje služby, vyšší výkon.", - "Pracovní stanice: pro uživatele, jednodušší konfigurace.", - "Peer‑to‑peer: síť bez serverů – jen stanice,", - "které sdílejí data a tiskárny.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[1], "net_unit2", "net_unit2_sub", - slides, NET2_SLIDES); -} - -GtkWidget *build_net_unit3_page(void) { - static const NetSlide slides[NET3_SLIDES] = { - { - "1 / 4 • Servery", "Role serverů a typy podle služby", - NULL, - { - "Servery ověřují uživatele a povolují přístup.", - "Souborový server (fileserver): sdílení souborů.", - "Tiskový server: sdílení tiskáren.", - "Poštovní server: e‑mailové služby.", - "Databázový server: správa a přístup k databázím.", - NULL, - }, - }, - { - "2 / 4 • Rozložení", "Centralizovaný a distribuovaný server", - NULL, - { - "Centralizovaný: jeden server v síti.", - "Výpadek = nedostupnost služby.", - "Distribuovaný: více serverů, každý obsluhuje část.", - "Vyšší spolehlivost a rychlost.", - NULL, - }, - }, - { - "3 / 4 • Využití", "Vyhrazený, nevyhrazený a mainframe", - NULL, - { - "Nevyhrazený: slouží i jako stanice (levnější).", - "Vyhrazený: jen síťové služby – vysoký výkon a bezpečnost,", - "typicky v racku.", - "Mainframe: obří sálové počítače (IBM, Siemens),", - "stovky procesorů, OS Unix (AIX, Solaris).", - "Použití: banky a státní správa.", - NULL, - }, - }, - { - "4 / 4 • Cloud", "Cloudové služby", - "Tip: SaaS = software jako služba", - { - "Cloud: globální síť vzdálených serverů propojených internetem.", - "Fungují jako jeden systém: ukládání dat, SaaS,", - "streamování, webová pošta.", - "Přístup online z jakéhokoli zařízení.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[2], "net_unit3", "net_unit3_sub", - slides, NET3_SLIDES); -} - -GtkWidget *build_net_unit4_page(void) { - static const NetSlide slides[NET4_SLIDES] = { - { - "1 / 4 • Přenos", "Paralelní a sériový přenos", - NULL, - { - "Paralelní: více bitů současně po více vodičích.", - "Problém: přeslechy (rušení) při delších kabelech", - "a vysokých frekvencích.", - "Sériový: bit po bitu po jednom vodiči.", - "Umožňuje vyšší frekvence i délky – celkově rychlejší.", - NULL, - }, - }, - { - "2 / 4 • Časování", "Asynchronní přenos", - "Tip: Start-bit = 0, Stop-bit = 1", - { - "Data se posílají v blocích (znaky 5–8 bitů).", - "Start-bit (0) synchronizuje začátek znaku.", - "Stop-bit (1) znak ukončuje.", - NULL, - }, - }, - { - "3 / 4 • Časování", "Synchronní přenos", - NULL, - { - "Řízeno společným hodinovým signálem.", - "Přesné časování mezi vysílačem a přijímačem.", - NULL, - }, - }, - { - "4 / 4 • Zabezpečení", "Parita, checksum a CRC", - "Tip: CRC je nejbezpečnější z těchto tří metod", - { - "Parita: nejslabší – přidá bit pro sudý/lichý počet jedniček.", - "Checksum: součet znaků jako dvojkových čísel.", - "CRC (cyklické kódy): nejbezpečnější,", - "počítá se z jednotlivých bitů v bloku.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[3], "net_unit4", "net_unit4_sub", - slides, NET4_SLIDES); -} - -GtkWidget *build_net_unit5_page(void) { - static const NetSlide slides[NET5_SLIDES] = { - { - "1 / 4 • Signál", "Analogový a digitální signál", - "Tip: frekvence a perioda jsou převrácené hodnoty. Platí f = 1/T.", - { - "Analogový signál je spojitý. Mezi dvěma hodnotami nabývá i všech hodnot mezi nimi, třeba napětí na mikrofonu nebo teplota.", - "Digitální signál je diskrétní. V počítači nabývá jen hodnot 0 a 1, takže se dá uložit a zkopírovat bez postupného šumu.", - "Perioda T je doba jednoho opakování. Frekvence f = 1/T říká, kolikrát za sekundu se průběh zopakuje. Jednotka je hertz.", - "Amplituda A je velikost výchylky od středu. Fázový posun Φ říká, o kolik je průběh posunutý proti jinému signálu se stejnou frekvencí.", - NULL, - }, - }, - { - "2 / 4 • Modulace", "Základní typy modulace", - "Modulace nasadí zprávu na nosnou vlnu, aby prošla kabelem nebo éterem. Tomu se říká přenos v přeloženém pásmu.", - { - "AM, amplitudová modulace, mění velikost nosné podle zprávy. Používá ji třeba rozhlas na středních vlnách. Rušení amplitudu snadno pokazí.", - "FM, frekvenční modulace, mění kmitočet nosné a amplitudu nechává. VKV rádio je odolnější proti šumu než AM.", - "PM, fázová modulace, posouvá fázi nosné. Změna fáze a změna frekvence spolu souvisejí, proto se FM a PM často popisují podobně.", - "Bez modulace by pomalá zpráva, třeba hlas, na rádiové frekvenci sama neodešla. Nosná je rychlá vlna, zpráva ji jen tvaruje.", - NULL, - }, - }, - { - "3 / 4 • Kombinované", "QPSK a 256-QAM", - "Jeden stav signálu, symbol, může nést víc než jeden bit. Čím víc stavů, tím víc bitů, ale tím snáz se stavy zamění.", - { - "QPSK má čtyři fázové stavy. Čtyři možnosti jsou dva bity, takže jeden symbol nese 2 bity.", - "256-QAM skládá amplitudu i fázi do 256 stavů. 256 = 2^8, takže jeden symbol nese 8 bitů.", - "Wi-Fi a kabelové modemy QAM používají, protože za stejnou šířku pásma přenesou víc dat než prosté AM.", - "Hustší konstelace chce čistší signál. Když je rušení velké, přijímač spadne na řidší modulaci s menším počtem bitů na symbol.", - NULL, - }, - }, - { - "4 / 4 • Rychlosti", "Modulační, přenosová a šířka pásma", - "Baud a bit za sekundu nejsou totéž. Baud počítá změny signálu, bit za sekundu počítá přenesenou informaci.", - { - "Modulační rychlost je počet změn signálu za sekundu. Jednotka je baud, Bd/s. U QPSK jedna změna nese 2 bity, takže bitů je víc než baudů.", - "Přenosová rychlost je množství informace za sekundu, v bit/s. Když symbol nese víc bitů, přenosová rychlost je vyšší než modulační.", - "Šířka pásma je rozsah frekvencí, který kanál propustí. U vozovky je to počet pruhů: užší pásmo znamená nižší strop rychlosti.", - "Nyquistův a Shannonův vztah z šířky pásma a šumu odvozují, kolik bitů za sekundu kanál vůbec unese. Větší pásmo nebo čistší signál strop zvedne.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[4], "net_unit5", "net_unit5_sub", - slides, NET5_SLIDES); -} - -GtkWidget *build_net_unit6_page(void) { - static const NetSlide slides[NET6_SLIDES] = { - { - "1 / 4 • Spoj", "Datový spoj", - NULL, - { - "Datový spoj umožňuje výměnu informací.", - "Může být dvoubodový nebo vícebodový.", - NULL, - }, - }, - { - "2 / 4 • Cesta", "Přenosová cesta", - NULL, - { - "Přenosová cesta je fyzické médium.", - "Příklady: metalické nebo optické kabely,", - "mikrovlny, družice.", - NULL, - }, - }, - { - "3 / 4 • Kanál a okruh", "Přenosový kanál a okruh", - "Tip: okruh = dva kanály → obousměrný přenos", - { - "Přenosový kanál: jednosměrný souhrn prostředků pro spojení.", - "Okruh: tvořen dvěma kanály – umožňuje obousměrný přenos.", - NULL, - }, - }, - { - "4 / 4 • Trunking", "Spojování cest", - NULL, - { - "Trunking spojuje více cest do jednoho okruhu.", - "Cíl: zvýšení šířky pásma.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[5], "net_unit6", "net_unit6_sub", - slides, NET6_SLIDES); -} - -GtkWidget *build_net_unit7_page(void) { - static const NetSlide slides[NET7_SLIDES] = { - { - "1 / 4 • Multiplex", "Rozdělení kanálu", - NULL, - { - "Multiplex: rozdělení jednoho kanálu", - "na více logických podkanálů.", - NULL, - }, - }, - { - "2 / 4 • Typy", "FDM, TDM a STDM", - NULL, - { - "FDM (frekvenční): každému kanálu část frekvenčního pásma.", - "TDM (časový): každému kanálu vyhrazený časový slot.", - "STDM (statistický): kapacita dle potřeby (paketový přenos),", - "negarantuje 100% dostupnost.", - NULL, - }, - }, - { - "3 / 4 • Směry", "Simplex, poloduplex a duplex", - NULL, - { - "Simplex: jen jeden směr (např. optické vlákno).", - "Poloduplex (half-duplex): oběma směry, ne současně.", - "Duplex (full-duplex): oběma směry současně.", - NULL, - }, - }, - { - "4 / 4 • Agregace", "Sdílení kapacity", - NULL, - { - "Agregace: sdílení kapacity kanálu více uživateli.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[6], "net_unit7", "net_unit7_sub", - slides, NET7_SLIDES); -} - -GtkWidget *build_net_unit8_page(void) { - static const NetSlide slides[NET8_SLIDES] = { - { - "1 / 4 • Okruhy", "Přepojování okruhů", - "Tip: spojovaná služba – jako telefon", - { - "Cesta se vytýčí předem (spojovaná služba).", - "Kapacita je garantována.", - "Přenos probíhá v reálném čase.", - NULL, - }, - }, - { - "2 / 4 • Pakety", "Přepojování paketů", - NULL, - { - "Data se dělí na pakety s adresami.", - "Každý paket může jít jinou cestou.", - NULL, - }, - }, - { - "3 / 4 • Hodnocení", "Výhody a nevýhody paketů", - NULL, - { - "Výhody: reakce na zátěž, lepší využití kapacity.", - "Nevýhody: negarantuje pořadí ani plynulost.", - "Nevhodné pro video v reálném čase.", - NULL, - }, - }, - { - "4 / 4 • Virtuální", "Virtuální spoje", - NULL, - { - "Cesta je vytýčena předem,", - "ale prostředky se využívají jen při průchodu paketu.", - "Výsledek: zrychlení datagramů.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[7], "net_unit8", "net_unit8_sub", - slides, NET8_SLIDES); -} - -GtkWidget *build_net_unit9_page(void) { - static const NetSlide slides[NET9_SLIDES] = { - { - "1 / 4 • Proč", "Standardizace a dekompozice", - NULL, - { - "Standardizace zajišťuje kompatibilitu mezi výrobci.", - "Dekompozice: rozklad složitého problému přenosu na vrstvy.", - NULL, - }, - }, - { - "2 / 4 • Vrstvy", "Komunikace mezi vrstvami", - "Tip: SAP = Service Access Point", - { - "Vrstvy komunikují jen se sousedy přes rozhraní (SAP).", - NULL, - }, - }, - { - "3 / 4 • Protokol", "Pravidla komunikace", - NULL, - { - "Protokol: pravidla komunikace mezi stejnými vrstvami", - "na různých uzlech.", - NULL, - }, - }, - { - "4 / 4 • Jednotky", "Hlavičky a PDU", - NULL, - { - "Každá vrstva přidá k datům hlavičku (header).", - "Rámec – linková vrstva.", - "Paket – síťová vrstva.", - "Segment – transportní vrstva.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[8], "net_unit9", "net_unit9_sub", - slides, NET9_SLIDES); -} - -GtkWidget *build_net_unit10_page(void) { - static const NetSlide slides[NET10_SLIDES] = { - { - "1 / 3 • ISO/OSI", "Sedmivrstvý model", - NULL, - { - "ISO/OSI: 7vrstvý model.", - "Je univerzální – popisuje komunikaci obecně.", - "V praxi je ale pomalejší: každá vrstva řešila spolehlivost.", - NULL, - }, - }, - { - "2 / 3 • TCP/IP", "Praktická architektura", - NULL, - { - "TCP/IP: architektura, která zvítězila v praxi.", - "Vycházela ze skutečných potřeb sítí.", - "Spolehlivost řeší až vyšší vrstvy.", - NULL, - }, - }, - { - "3 / 3 • Srovnání", "Proč zvítězil TCP/IP", - "Tip: méně režie na nižších vrstvách = rychlejší provoz", - { - "ISO/OSI: teoretický, univerzální, těžší a pomalejší.", - "TCP/IP: praktický, jednodušší dělení odpovědností.", - "Proto se TCP/IP stal základem dnešního internetu.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[9], "net_unit10", "net_unit10_sub", - slides, NET10_SLIDES); -} - -GtkWidget *build_net_unit11_page(void) { - static const NetSlide slides[NET11_SLIDES] = { - { - "1 / 8 • Přehled", "Tři skupiny vrstev", - "Tip: přenos → přizpůsobení → aplikace", - { - "Vrstvy orientované na přenos: fyzická, spojová, síťová.", - "Přizpůsobovací vrstva: transportní.", - "Vrstvy orientované na aplikace: relační, prezentační,", - "aplikační.", - NULL, - }, - }, - { - "2 / 8 • Fyzická", "Přenos bitů", - NULL, - { - "Přenos bitů po médiu.", - "Definuje napětí, kabely, konektory, kódování a modulaci.", - "Řeší také duplex / simplex.", - NULL, - }, - }, - { - "3 / 8 • Spojová", "Rámce a MAC", - "Tip: podvrstvy MAC (přístup k médiu) a LLC (logické řízení)", - { - "Tvorba rámců a fyzické (MAC) adresy.", - "Kontrola chyb (CRC) a řízení toku mezi sousedními uzly.", - "Podvrstvy: MAC a LLC.", - NULL, - }, - }, - { - "4 / 8 • Síťová", "Směrování paketů", - NULL, - { - "Směrování (routing) paketů.", - "Funguje i v sítích bez přímého spojení mezi uzly.", - NULL, - }, - }, - { - "5 / 8 • Transportní", "Segmenty end-to-end", - "Tip: v routerech transportní vrstva není", - { - "Rozklad zpráv na segmenty a jejich zpětné složení.", - "Kontrola pořadí a náprava chyb.", - "Existuje jen v koncových uzlech – není v routerech.", - NULL, - }, - }, - { - "6 / 8 • Relační", "Relace a dialog", - NULL, - { - "Navazuje, udržuje a ukončuje relace.", - "Řídí dialog („neskákat si do řeči“).", - "Synchronizace – navázání po přerušení.", - NULL, - }, - }, - { - "7 / 8 • Prezentační", "Formát dat", - NULL, - { - "Formátování dat (např. ASCII).", - "Komprese a šifrování.", - "Převod mezi různými standardy.", - NULL, - }, - }, - { - "8 / 8 • Aplikační", "Rozhraní pro programy", - NULL, - { - "Rozhraní pro aplikace a služby.", - "Například e-mail, HTTP, FTP nebo terminál.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[10], "net_unit11", "net_unit11_sub", - slides, NET11_SLIDES); -} - -GtkWidget *build_net_unit12_page(void) { - static const NetSlide slides[NET12_SLIDES] = { - { - "1 / 6 • Mapování", "TCP/IP vs ISO/OSI", - NULL, - { - "Aplikační TCP/IP = aplikační + prezentační + relační ISO/OSI.", - "Transportní TCP/IP = transportní ISO/OSI.", - "Síťová (internetová) = síťová ISO/OSI.", - "Vrstva síťového rozhraní = linková + fyzická ISO/OSI.", - NULL, - }, - }, - { - "2 / 6 • Vznik", "Nejprve protokoly", - "Tip: opačný postup než u ISO/OSI", - { - "Nejprve vznikly protokoly pro Internet.", - "Až poté byl definován model TCP/IP.", - "U ISO/OSI to bylo naopak: nejdřív model, pak protokoly.", - NULL, - }, - }, - { - "3 / 6 • Aplikace", "Aplikační protokoly", - NULL, - { - "HTTP, HTTPS, FTP, DHCP, DNS.", - "Pošta: POP3, IMAP, SMTP.", - NULL, - }, - }, - { - "4 / 6 • Transport", "TCP a UDP", - NULL, - { - "TCP: spolehlivý, spojovaný.", - "UDP: nespolehlivý, rychlý.", - NULL, - }, - }, - { - "5 / 6 • Síť", "Internetové protokoly", - NULL, - { - "IP – základní přenos paketů.", - "ICMP, ARP.", - "Směrování: RIP, OSPF.", - NULL, - }, - }, - { - "6 / 6 • Rozhraní", "Síťové rozhraní", - NULL, - { - "Ethernet, Token Ring, PPP, ATM.", - "Odpovídá linkové a fyzické vrstvě ISO/OSI.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[11], "net_unit12", "net_unit12_sub", - slides, NET12_SLIDES); -} - -GtkWidget *build_net_unit13_page(void) { - static const NetSlide slides[NET13_SLIDES] = { - { - "1 / 4 • Přehled", "Topologie sítě", - NULL, - { - "Topologie popisuje, jak jsou uzly propojené.", - "Základní typy: sběrnice, hvězda a kruh.", - NULL, - }, - }, - { - "2 / 4 • Sběrnice", "Bus", - "Tip: dříve typicky koaxiální kabel", - { - "Médium sdílí všichni – jednoduchá a levná topologie.", - "Malá délka kabelů.", - "Nevýhody: nízká bezpečnost (všichni slyší vše).", - "Přerušení kabelu nebo terminátoru vyřadí celou síť.", - NULL, - }, - }, - { - "3 / 4 • Hvězda", "Star", - "Tip: kroucená dvoulinka nebo optika", - { - "Uzly jdou přes centrální prvek (hub nebo switch).", - "Výhody: odolnost proti poruchám kabelů k uzlům,", - "snadná diagnostika.", - "Nevýhody: aktivní prvky a více kabeláže.", - NULL, - }, - }, - { - "4 / 4 • Kruh", "Ring", - "Tip: často zdvojený kruh pro odolnost", - { - "Kabely tvoří souvislý kruh.", - "Zprávy obíhají, dokud nenajdou adresáta.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[12], "net_unit13", "net_unit13_sub", - slides, NET13_SLIDES); -} - -GtkWidget *build_net_unit14_page(void) { - static const NetSlide slides[NET14_SLIDES] = { - { - "1 / 5 • Princip", "Světlo místo proudu", - "Tip: obousměrný provoz = dvě vlákna", - { - "Elektrické impulsy se převádí na světlo (LED nebo laser).", - "Zpět je zachytí fotodioda.", - "Přenos jedním vláknem je jednosměrný.", - NULL, - }, - }, - { - "2 / 5 • Výhody", "Proč optika", - NULL, - { - "Imunita vůči elektromagnetickému rušení.", - "Obrovská šířka pásma a dosah až kolem 100 km.", - "Lepší bezpečnost proti odposlechu.", - "Malý průměr a nízká váha.", - NULL, - }, - }, - { - "3 / 5 • Nevýhody", "Cena a montáž", - NULL, - { - "Náročná montáž.", - "Dražší aktivní prvky a konektory.", - NULL, - }, - }, - { - "4 / 5 • MM", "Mnohovidová vlákna", - NULL, - { - "Větší jádro: 50 / 62,5 µm.", - "Více cest světla (vidů).", - "Levnější zdroje – typicky LED.", - NULL, - }, - }, - { - "5 / 5 • SM", "Jednovidová vlákna", - NULL, - { - "Malé jádro: 7–10 µm.", - "Jen jeden paprsek osou vlákna.", - "Velký dosah, vyžaduje laser.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[13], "net_unit14", "net_unit14_sub", - slides, NET14_SLIDES); -} - -GtkWidget *build_net_unit15_page(void) { - static const NetSlide slides[NET15_SLIDES] = { - { - "1 / 3 • Primární", "Ochrana 250 µm", - NULL, - { - "Primární ochrana má průměr 250 µm.", - "Chrání samotné vlákno hned po výrobě.", - NULL, - }, - }, - { - "2 / 3 • Sekundární", "Ochrana 900 µm", - "Tip: těsná pro svislé, volná pro vodorovné instalace", - { - "Sekundární ochrana má průměr 900 µm.", - "Těsná varianta: vhodné pro svislé instalace.", - "Volná varianta: vhodné pro vodorovné instalace.", - NULL, - }, - }, - { - "3 / 3 • Montáž", "Lámání a sváření", - "Tip: kolmost lomu do 0,5°", - { - "Vyžaduje precizní lámání lámačkou.", - "Spojování se dělá svářečkou optických vláken.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[14], "net_unit15", "net_unit15_sub", - slides, NET15_SLIDES); -} - -GtkWidget *build_net_unit16_page(void) { - static const NetSlide slides[NET16_SLIDES] = { - { - "1 / 4 • Kolize", "Sdílené médium", - NULL, - { - "Kolize nastane, když na sdíleném médiu vysílá více uzlů najednou.", - NULL, - }, - }, - { - "2 / 4 • Aloha", "Vysílej kdykoliv", - "Tip: časté kolize, primitivní metoda", - { - "Uzel vysílá kdykoliv chce.", - "Když nepřijde potvrzení, pošle data znovu.", - "Kolize jsou časté.", - NULL, - }, - }, - { - "3 / 4 • CSMA/CD", "Ethernet", - "Tip: Carrier Sense + Collision Detection", - { - "Nejdřív se poslouchá nosná (Carrier Sense).", - "Je-li ticho, uzel vysílá.", - "Při kolizi se vysílání zastaví a zkusí se znovu", - "po náhodném čase.", - NULL, - }, - }, - { - "4 / 4 • CSMA/CA", "Wi-Fi", - "Tip: Collision Avoidance přes RTS/CTS", - { - "Předchází kolizím (Collision Avoidance).", - "RTS (Request to Send) a CTS (Clear to Send)", - "rezervují médium před vysíláním.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[15], "net_unit16", "net_unit16_sub", - slides, NET16_SLIDES); -} - -GtkWidget *build_net_unit17_page(void) { - static const NetSlide slides[NET17_SLIDES] = { - { - "1 / 7 • Přehled", "Aktivní prvky", - NULL, - { - "Aktivní prvky zpracovávají nebo převádí signál / data.", - "Liší se podle vrstvy ISO/OSI, na které pracují.", - NULL, - }, - }, - { - "2 / 7 • Repeater", "Opakovač", - "Tip: fyzická vrstva", - { - "Zesiluje signál a tím zvyšuje dosah.", - NULL, - }, - }, - { - "3 / 7 • Transceiver", "Konvertor", - "Tip: fyzická vrstva", - { - "Převádí signál mezi různými médii.", - "Například metaliku na optiku.", - NULL, - }, - }, - { - "4 / 7 • Hub", "Rozbočovač", - "Tip: fyzická vrstva – „hloupý“ prvek", - { - "Co přijme na jednom portu, rozešle do všech ostatních.", - NULL, - }, - }, - { - "5 / 7 • Bridge/Switch", "Most a přepínač", - "Tip: linková vrstva – rámce a MAC", - { - "Pracují s rámci a MAC adresami.", - "Switch dělí síť na kolizní domény.", - NULL, - }, - }, - { - "6 / 7 • Router", "Směrovač", - "Tip: síťová vrstva – pakety a IP", - { - "Pracuje s pakety a IP adresami.", - "Propojuje různé sítě.", - NULL, - }, - }, - { - "7 / 7 • Gateway", "Brána", - "Tip: vyšší vrstvy", - { - "Převádí mezi odlišnými architekturami nebo protokoly.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[16], "net_unit17", "net_unit17_sub", - slides, NET17_SLIDES); -} - -GtkWidget *build_net_unit18_page(void) { - static const NetSlide slides[NET18_SLIDES] = { - { - "1 / 5 • Funkce", "Učení MAC adres", - "Tip: CAM tabulka = adresa → port", - { - "Switch se učí MAC adresy odesílatelů.", - "Ukládá je do CAM tabulky.", - "Rámce pak posílá jen na konkrétní port.", - NULL, - }, - }, - { - "2 / 5 • Metody", "Tři způsoby přepínání", - NULL, - { - "Cut-through, store-and-forward a fragment-free.", - "Liší se rychlostí a kontrolou chyb.", - NULL, - }, - }, - { - "3 / 5 • Cut-through", "Hned po adrese", - NULL, - { - "Čte jen adresu příjemce a hned posílá dál.", - "Nejrychlejší metoda.", - "Nevýhoda: posílá i chybné rámce.", - NULL, - }, - }, - { - "4 / 5 • Store-and-forward", "Celý rámec + CRC", - NULL, - { - "Přijme celý rámec a zkontroluje CRC.", - "Teprve pak rámec pošle.", - "Nejpomalejší, ale nejbezpečnější metoda.", - NULL, - }, - }, - { - "5 / 5 • Fragment-free", "Modifikovaný cut-through", - "Tip: prvních 64 bytů = detekce kolizí", - { - "Čte prvních 64 bytů rámce.", - "To stačí k odhalení kolizních fragmentů.", - "Kompromis mezi rychlostí a bezpečností.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[17], "net_unit18", "net_unit18_sub", - slides, NET18_SLIDES); -} - -GtkWidget *build_net_unit19_page(void) { - static const NetSlide slides[NET19_SLIDES] = { - { - "1 / 7 • Princip", "Směrování paketů", - "Tip: 3. vrstva ISO/OSI – síťová", - { - "Rozhodování o dalším směru přenosu paketů do cílové sítě.", - "Probíhá na síťové vrstvě modelu ISO/OSI.", - "K rozhodování se používají směrovací algoritmy.", - NULL, - }, - }, - { - "2 / 7 • Adaptivní", "Dynamické algoritmy", - NULL, - { - "Reagují na změny v síti (výpadek linky, přetížení).", - "Vyžadují pravidelnou výměnu informací mezi směrovači.", - NULL, - }, - }, - { - "3 / 7 • Neadaptivní", "Statické algoritmy", - NULL, - { - "Nereagují na změny v síti.", - "Cesty pevně definuje správce.", - "Při výpadku části sítě může spojení spadnout.", - NULL, - }, - }, - { - "4 / 7 • Řízení", "Centralizované a izolované", - NULL, - { - "Centralizované: centrum počítá cesty pro všechny směrovače.", - "Výpadek centra = pád směrování; v praxi skoro nepoužívané.", - "Izolované: směrovač se rozhoduje sám z lokálních informací.", - "Izolované se používá spíš jako doplněk při přetížení.", - NULL, - }, - }, - { - "5 / 7 • Distribuované", "Výměna mezi směrovači", - NULL, - { - "Směrovače si vyměňují informace.", - "Každý si udržuje vlastní směrovací tabulku.", - NULL, - }, - }, - { - "6 / 7 • Tabulka", "Next Hop a metrika", - "Tip: nižší metrika = lepší / rychlejší trasa", - { - "Záznam: cílová síť, next hop a metrika.", - "Next hop = nejbližší soused, kterému paket předáme.", - "Metrika číselně ohodnocuje cestu.", - "Při více cestách se volí ta s nejnižší metrikou.", - NULL, - }, - }, - { - "7 / 7 • Distance Vector", "Příklad algoritmu", - "Tip: např. výměna tabulek každých 30 s", - { - "Směrovače znají jen své přímé sousedy.", - "Pravidelně si posílají kopie směrovacích tabulek.", - "Informace se šíří krok za krokem po celé síti.", - "Každý směrovač si spočítá nejlepší trasu do známých sítí.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[18], "net_unit19", "net_unit19_sub", - slides, NET19_SLIDES); -} - -GtkWidget *build_net_unit20_page(void) { - static const NetSlide slides[NET20_SLIDES] = { - { - "1 / 7 • Router", "Síťová vrstva", - "Tip: má vlastní IP a je vidět např. pingen", - { - "Pracuje na 3. (síťové) vrstvě.", - "Segmentuje síť na podsítě nebo propojuje LAN do většího celku.", - "Umožňuje přístup na WAN (např. internet).", - "Podporuje soustavy protokolů (např. TCP/IP) a má vlastní adresu.", - NULL, - }, - }, - { - "2 / 7 • Bezpečnost", "Firewall na routeru", - NULL, - { - "Router s firewallem filtruje pakety.", - "Může zakázat nebo povolit určité síťové služby.", - NULL, - }, - }, - { - "3 / 7 • Multiprotokol", "Různé standardy", - NULL, - { - "Multiprotokolový router spojuje různé soustavy protokolů.", - "Například TCP/IP se sítěmi IPX/SPX.", - "Umí i různý síťový hardware (Ethernet ↔ Token Ring).", - "Konvertuje formát rámců i paketů.", - NULL, - }, - }, - { - "4 / 7 • Routing", "Směrování a tabulky", - NULL, - { - "Každému paketu hledá vhodnou cestu k cíli.", - "Zohledňuje např. okamžité zatížení sítí.", - "Používá směrovací tabulky a musí znát topologii.", - "Směrovače si tabulky vyměňují (např. broadcastem).", - NULL, - }, - }, - { - "5 / 7 • Broadcast", "Broadcastové domény", - NULL, - { - "Router rozděluje síť na broadcastové domény.", - "Broadcasty lze filtrovat – nešíří se na všechny porty.", - NULL, - }, - }, - { - "6 / 7 • Gateway", "Brána", - "Tip: pracuje až na aplikační vrstvě (i nižších)", - { - "Připojuje LAN na zcela odlišné prostředí.", - "Například mainframe nebo GSM síť.", - "Často PC s kartou/emulací terminálu nebo s modemem na WAN.", - NULL, - }, - }, - { - "7 / 7 • Poznámka", "Gateway vs router", - NULL, - { - "Někdy se pod pojmem brána rozumí spíše router.", - "Gateway také označuje připojení LAN na WAN / internet.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[19], "net_unit20", "net_unit20_sub", - slides, NET20_SLIDES); -} - -GtkWidget *build_net_unit21_page(void) { - static const NetSlide slides[NET21_SLIDES] = { - { - "1 / 8 • Ethernet", "Síťový hardware", - NULL, - { - "Jeden ze standardů síťového hardware.", - "Dnes nejpoužívanější.", - NULL, - }, - }, - { - "2 / 8 • Adresy", "48bitová MAC", - "Tip: IEEE přidělí první 3 B, výrobce další 3 B", - { - "Adresa má 48 bitů (6 bytů) a je celosvětově jedinečná.", - "Je pevně v síťové kartě už od výroby.", - "Výrobci dostávají bloky adres od IEEE.", - NULL, - }, - }, - { - "3 / 8 • Rámce", "Typy hlaviček", - NULL, - { - "Rámec = skupina bitů na linkové vrstvě.", - "Hlavička má adresy odesílatele/příjemce a typ obsahu.", - "Typy: Ethernet II, IEEE 802.3, 802.3 SNAP, raw 802.3.", - NULL, - }, - }, - { - "4 / 8 • Ethernet II", "DIX + EtherType", - "Tip: EtherType > 1500 (např. IP = 0800h)", - { - "Původní DIX Ethernet.", - "Hlavička: příjemce 6 B, odesílatel 6 B, EtherType 2 B.", - "EtherType identifikuje protokol (IP, IPX…).", - NULL, - }, - }, - { - "5 / 8 • IEEE 802.3", "Délka místo typu", - NULL, - { - "Místo EtherType je údaj o délce (vždy ≤ 1500).", - "Uvnitř je rámec 802.2 (stejný i pro Token Ring).", - "Typ protokolu je v SAP mezi linkovou a síťovou vrstvou.", - NULL, - }, - }, - { - "6 / 8 • Raw 802.3", "Novell / IPX", - NULL, - { - "„Holý“ rámec 802.3 bez 802.2 (Novell).", - "Funguje jen v prostředí IPX.", - "Paket začíná dvěma byty FFFFh.", - NULL, - }, - }, - { - "7 / 8 • SNAP", "802.2 SNAP", - "Tip: byty 15–16 za délkou = AAAAh", - { - "Vložen do rámce 802.3.", - "Rozšiřuje identifikaci protokolu až na 5 bytů.", - NULL, - }, - }, - { - "8 / 8 • Velikost", "Min / max / MTU", - NULL, - { - "Max. Ethernet II: 1500 + 18 = 1518 B.", - "Min. velikost: 64 B (kolizní okénko).", - "MTU je obvyklé omezení velikosti na routerech.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[20], "net_unit21", "net_unit21_sub", - slides, NET21_SLIDES); -} - -GtkWidget *build_net_unit22_page(void) { - static const NetSlide slides[NET22_SLIDES] = { - { - "1 / 8 • Paket", "Header a data", - NULL, - { - "Paket/segment: hlavička (pro partnerskou vrstvu) + data.", - "Protokol určuje strukturu a pravidla stejnolehlých vrstev.", - "Může běžet na různých platformách.", - NULL, - }, - }, - { - "2 / 8 • TCP/IP", "Protokoly po vrstvách", - NULL, - { - "Aplikační: aplikační protokoly.", - "Transportní: TCP, UDP.", - "Síťová: IP, ARP, RARP, ICMP, IGMP, RIP, OSPF.", - "Síťové rozhraní: Ethernet, Token Ring, ATM, PPP…", - NULL, - }, - }, - { - "3 / 8 • IP", "Univerzální přenos", - "Tip: nespojovaný a nespolehlivý", - { - "Jediný přenosový protokol TCP/IP nad libovolnou technologií.", - "Pracuje s virtuálními pakety – IP datagramy.", - "Stará se o směrování a přenos; velikost volí odesílatel.", - "Nezaručuje pořadí, dobu ani nepoškozené doručení.", - NULL, - }, - }, - { - "4 / 8 • Routing", "Routing vs forwarding", - NULL, - { - "Routing: rozhodnutí o dalším směru datagramu.", - "Forwarding: vložení do linkového rámce a odeslání.", - "Linkové adresy se mění podle konkrétní sítě.", - NULL, - }, - }, - { - "5 / 8 • Datagram", "Velikost a HLEN", - "Tip: Length 5 = 20 B hlavičky", - { - "Velikost: od 576 B do 64 kB.", - "Části: hlavička + data.", - "HLEN: délka hlavičky ve 32bitových slovech.", - "TOTAL LENGTH: délka celého paketu v bytech.", - NULL, - }, - }, - { - "6 / 8 • Hlavička", "Klíčová pole", - NULL, - { - "VERSION (IPv4 = 4), LENGTH, TOTAL LENGTH.", - "IDENTIFICATION + FLAGS + OFFSET = fragmentace.", - "TTL: čítač směrovačů proti zacyklení.", - "PROTOCOL, HEADER CHECKSUM, zdrojová/cílová IP.", - NULL, - }, - }, - { - "7 / 8 • PROTOCOL", "Čísla protokolů", - NULL, - { - "1 = ICMP, 2 = IGMP, 6 = TCP.", - "17 = UDP, 89 = OSPF.", - "Položka je 8bitová → max. 256 hodnot.", - NULL, - }, - }, - { - "8 / 8 • Fragmentace", "MTU a Ethernet", - "Tip: Ethernet MTU = 1500 B", - { - "Fragmentace, když se datagram nevejde do menšího rámce.", - "MTU udává max. velikost rámce podle hardwaru.", - "DF = nefragmentuj; MF = další fragmenty.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[21], "net_unit22", "net_unit22_sub", - slides, NET22_SLIDES); -} - -GtkWidget *build_net_unit23_page(void) { - static const NetSlide slides[NET23_SLIDES] = { - { - "1 / 5 • ICMP", "Řídicí zprávy", - "Tip: síťová vrstva, ale nese se v IP datagramu", - { - "Zasílá informace o chybách a stavu přenosu.", - "ICMP paket jede přímo v IP datagramu.", - "Směrovače s ním pracují i bez transportní vrstvy.", - NULL, - }, - }, - { - "2 / 5 • Zprávy I", "Quench, TTL, Unreachable", - NULL, - { - "Source Quench: hrozí zahlcení – zpomal odesílání.", - "Time Exceeded: TTL kleslo na 0, paket zahozen (tracert).", - "Destination Unreachable: cíl (síť/uzel/protokol/port)", - "není dostupný.", - NULL, - }, - }, - { - "3 / 5 • Zprávy II", "Redirect a Echo", - NULL, - { - "Redirect: přesměruj přenos na jiný (rychlejší) router.", - "Echo Request / Echo Reply: test dostupnosti (ping).", - NULL, - }, - }, - { - "4 / 5 • Traceroute", "Princip TTL", - "Tip: typicky max. 30 skoků", - { - "Odešle paket s TTL = 1; první router odpoví Time Exceeded.", - "Pak TTL = 2, 3… a tak se zjišťují skoky na cestě.", - "Pokračuje, dokud paket nedorazí do cíle nebo nevyprší limit.", - NULL, - }, - }, - { - "5 / 5 • Shrnutí", "K čemu ICMP slouží", - NULL, - { - "Diagnostika a hlášení chyb na síťové vrstvě.", - "Základ příkazů ping a traceroute / tracert.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[22], "net_unit23", "net_unit23_sub", - slides, NET23_SLIDES); -} - -GtkWidget *build_net_unit24_page(void) { - static const NetSlide slides[NET24_SLIDES] = { - { - "1 / 5 • ARP / RARP", "Převod adres", - NULL, - { - "ARP: z IP adresy na MAC (fyzickou) adresu.", - "RARP: z MAC adresy na IP adresu.", - NULL, - }, - }, - { - "2 / 5 • Způsoby", "Jak zjistit MAC", - NULL, - { - "Tabulkový převod: ruční správa (malé sítě).", - "Výpočet: funkce, kde MAC plyne z IP.", - "Dotaz a odpověď: dynamické zjišťování (nejčastější).", - NULL, - }, - }, - { - "3 / 5 • Mechanismus", "Broadcast a unicast", - "Tip: „Kdo má IP x.x.x.x?“", - { - "ARP využívá broadcast v Ethernetu.", - "Odpoví jen uzel s danou IP.", - "Odpověď jde unicastem a obsahuje MAC adresu.", - NULL, - }, - }, - { - "4 / 5 • Cache", "Dočasná paměť", - "Tip: zobrazení příkazem arp -a", - { - "Výsledky se ukládají do ARP cache.", - "Dotazy se tak nemusí stále opakovat.", - "Položky: dynamické (učené) nebo statické (ruční).", - NULL, - }, - }, - { - "5 / 5 • Shrnutí", "K čemu ARP slouží", - NULL, - { - "Propojuje síťovou adresu (IP) s linkovou (MAC).", - "Bez ARP by IP datagram nešel vložit do Ethernet rámce.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[23], "net_unit24", "net_unit24_sub", - slides, NET24_SLIDES); -} - -GtkWidget *build_net_unit25_page(void) { - static const NetSlide slides[NET25_SLIDES] = { - { - "1 / 6 • TCP vs UDP", "Základní rozdíly", - NULL, - { - "TCP: spolehlivý a spojovaný přenos.", - "Potvrzování, kontrola pořadí a řízení toku.", - "UDP: nespolehlivý a nespojovaný.", - "Minimální režie – neřeší potvrzení ani pořadí.", - NULL, - }, - }, - { - "2 / 6 • Porty", "Multiplex a demultiplex", - NULL, - { - "Porty rozlišují aplikace (procesy) na jednom uzlu.", - "Multiplex: sběr dat od aplikací do segmentů/datagramů.", - "Demultiplex: doručení příchozích dat správné aplikaci", - "podle čísla portu.", - NULL, - }, - }, - { - "3 / 6 • TCP", "Spojení a vlastnosti", - "Tip: three-way handshake", - { - "Navázání spojení: třícestné podání ruky.", - "Streamově orientovaný a full duplex.", - "Jen unicast – bez multicastu a broadcastu.", - NULL, - }, - }, - { - "4 / 6 • Nevýhody TCP", "Režie a real-time", - NULL, - { - "Větší režie: hlavička 20 B (UDP má 8 B).", - "Nevhodný pro real-time média: ztráta segmentu", - "zastaví proud a čeká se na znovudoručení.", - "Bez multihomingu – výpadek rozhraní shodí spojení.", - NULL, - }, - }, - { - "5 / 6 • Alternativy", "SCTP a DCCP", - NULL, - { - "SCTP: multihoming a multistreaming (až 64k proudů).", - "DCCP: datagramy s řízením zahlcení", - "(streaming, IP telefonie).", - NULL, - }, - }, - { - "6 / 6 • Shrnutí", "Kdy co použít", - NULL, - { - "TCP: spolehlivá data (web, pošta, soubory).", - "UDP: rychlost a nízká režie (DNS, hry, real-time).", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[24], "net_unit25", "net_unit25_sub", - slides, NET25_SLIDES); -} - -GtkWidget *build_net_unit26_page(void) { - static const NetSlide slides[NET26_SLIDES] = { - { - "1 / 7 • Úvod", "Aplikační protokoly", - NULL, - { - "Na uzlu běží více síťových aplikací současně.", - "Běžící aplikace = v operační paměti (1+ procesů).", - "Pracují podle pravidel – protokolů aplikační vrstvy.", - "Data posílají po síti přes TCP nebo UDP.", - NULL, - }, - }, - { - "2 / 7 • Porty", "Procesy a porty", - NULL, - { - "Port v TCP/UDP říká, které aplikaci data patří.", - "Jeden proces může používat více portů.", - "Dva procesy nesmí používat stejný port.", - NULL, - }, - }, - { - "3 / 7 • Rozsahy", "Well-known, registrované, dynamické", - "Tip: IANA", - { - "Well-known: 0–1023 – vyhrazené službám (norma IANA).", - "Registrované: 1024–49151 – IANA jen registruje použití.", - "Dynamické/privátní: 49152–65535 – volně k použití.", - NULL, - }, - }, - { - "4 / 7 • Spojení", "Pětice hodnot", - NULL, - { - "Aplikační spojení určuje pětice:", - "(transport, IP1, port1, IP2, port2).", - "Klient osloví server na well-known portu.", - NULL, - }, - }, - { - "5 / 7 • Více spojení", "Stejný server, různí klienti", - NULL, - { - "Na jeden uzel (např. web server) může být", - "více aplikačních spojení z různých klientů.", - "Rozlišují je IP a porty klientů (i transport).", - NULL, - }, - }, - { - "6 / 7 • Porty I", "Časté well-known služby", - NULL, - { - "20/21 FTP, 22 SSH, 23 Telnet, 25 SMTP, 53 DNS.", - "67/68 DHCP, 80 HTTP, 110 POP3, 143 IMAP.", - "123 NTP, 161 SNMP, 389 LDAP, 443 HTTPS.", - NULL, - }, - }, - { - "7 / 7 • Porty II", "Zabezpečené a registrované", - NULL, - { - "587 SMTPS, 636 LDAPS, 993 IMAPS, 995 POP3S.", - "Registrované: 3306 MySQL, 3389 RDP, 5900 VNC.", - "Dynamické porty: 49152–65535.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[25], "net_unit26", "net_unit26_sub", - slides, NET26_SLIDES); -} - -GtkWidget *build_net_unit27_page(void) { - static const NetSlide slides[NET27_SLIDES] = { - { - "1 / 8 • Úvod", "Bezdrátové sítě", - NULL, - { - "Patří sem hlavně: družicové, mikrovlnné a optické spoje.", - "Dále Wi-Fi (LAN), WiMAX/LTE (MAN/WAN) a další.", - NULL, - }, - }, - { - "2 / 8 • Družice", "Geostacionární spoje", - NULL, - { - "Geostacionární družice: ~36 000 km, stále nad stejným bodem.", - "Pasivní odrážejí; aktivní mají transpondéry (převod + zisk).", - "C-band ~6/4 GHz; KU-band 12–14 GHz (menší antény).", - "Nevýhoda: zpoždění ~250–300 ms (RTT až ~600 ms).", - NULL, - }, - }, - { - "3 / 8 • VSAT", "Přístup a topologie", - NULL, - { - "Bod–bod, broadcast (TV) i multiple access.", - "VSAT: terminály + centrální hub.", - "Komunikace jen terminál ↔ hub (ne přímo mezi terminály).", - NULL, - }, - }, - { - "4 / 8 • Mikrovlny", "Pozemní spoje", - "Tip: přímá viditelnost", - { - "Frekvence 1–12 GHz, směrování parabolou, malý rozptyl.", - "Dosah typicky do ~50 km; retranslační stanice.", - "Troposférické spoje: odraz ve ~16 km, dosah až ~500 km.", - NULL, - }, - }, - { - "5 / 8 • Wi-Fi pojmy", "AP, BSS, ESS", - NULL, - { - "AP = přístupový bod; STA komunikují přes AP (ne přímo).", - "BSS = stanice v buňce BSA; ESS = více buněk přes DS.", - "Roaming při překrytí; ad-hoc = P2P bez AP; hotspot = Wi-Fi.", - "ESSID identifikuje síť při přístupu k AP.", - NULL, - }, - }, - { - "6 / 8 • Standardy", "802.11 a … ax", - NULL, - { - "b: 11 Mb/s, 2,4 GHz; a/g: 54 Mb/s; n: MIMO, až 600 Mb/s.", - "ac (Wi-Fi 5): 256-QAM, široké kanály; ax (Wi-Fi 6): OFDMA.", - "OFDM: mnoho ortogonálních subnosných v kanálu.", - NULL, - }, - }, - { - "7 / 8 • Zabezpečení", "WEP → WPA3", - NULL, - { - "WEP: RC4, krátký IV – prolomeno (2001), nepoužívat.", - "WPA: TKIP; WPA2: AES (doporučený základ).", - "WPA3: SAE místo PSK, silnější ochrana hesla.", - "802.1X/EAP: ověření klienta přes AP (RADIUS).", - NULL, - }, - }, - { - "8 / 8 • Shrnutí", "Dosahy a další", - NULL, - { - "PAN <10 m (Bluetooth); LAN = Wi-Fi; MAN = WiMAX.", - "WAN/mobilita: 802.16e, LTE; licencovaná pásma = méně rušení.", - "Používej WPA2/WPA3 + AES, ne WEP.", - NULL, - }, - }, - }; - - return build_net_unit_page(&net_lessons[26], "net_unit27", "net_unit27_sub", - slides, NET27_SLIDES); -} - -/* Solutions below are the canonical "largest subnet first, in order A–D" - * allocation. Scenario 3 does not fit into a /24 as written, which is why - * its "solution" explains that instead. */ - -const NetTask net_tasks[] = { - { - "1.) Síť má adresu 10.0.0.0/24. Rozdělte ji do podsítí s následujícími " - "požadavky:\n\n" - "Podsíť A: 60 uzlů\nPodsíť B: 30 uzlů\nPodsíť C: 14 uzlů\n" - "Podsíť D: 7 uzlů", - "A: 10.0.0.0/26 síť 10.0.0.0 uzly 10.0.0.1–10.0.0.62 " - "broadcast 10.0.0.63\n" - "B: 10.0.0.64/27 síť 10.0.0.64 uzly 10.0.0.65–10.0.0.94 " - "broadcast 10.0.0.95\n" - "C: 10.0.0.96/28 síť 10.0.0.96 uzly 10.0.0.97–10.0.0.110 " - "broadcast 10.0.0.111\n" - "D: 10.0.0.112/28 síť 10.0.0.112 uzly 10.0.0.113–10.0.0.126 " - "broadcast 10.0.0.127", - }, - { - "2.) Síť má adresu 172.16.0.0/16. Rozdělte ji do podsítí s " - "následujícími požadavky:\n\n" - "Podsíť A: 500 uzlů\nPodsíť B: 200 uzlů\nPodsíť C: 100 uzlů\n" - "Podsíť D: 50 uzlů", - "A: 172.16.0.0/23 síť 172.16.0.0 uzly 172.16.0.1–172.16.1.254 " - "broadcast 172.16.1.255\n" - "B: 172.16.2.0/24 síť 172.16.2.0 uzly 172.16.2.1–172.16.2.254 " - "broadcast 172.16.2.255\n" - "C: 172.16.3.0/25 síť 172.16.3.0 uzly 172.16.3.1–172.16.3.126 " - "broadcast 172.16.3.127\n" - "D: 172.16.3.128/26 síť 172.16.3.128 uzly 172.16.3.129–172.16.3.190 " - "broadcast 172.16.3.191", - }, - { - "3.) Síť má adresu 192.168.10.0/24. Rozdělte ji do podsítí s " - "následujícími požadavky:\n\n" - "Podsíť A: 120 uzlů\nPodsíť B: 70 uzlů\nPodsíť C: 35 uzlů\n" - "Podsíť D: 15 uzlů", - "Do sítě /24 se tyto požadavky nevejdou: A i B potřebují /25 " - "(2 × 128 = 256 adres), na C a D už nezbude žádný blok. " - "Při zachování velikostí by bylo nutné větší síť (např. /23).", - }, - { - "4.) Síť má adresu 192.168.2.0/25. Rozdělte ji do podsítí s " - "následujícími požadavky:\n\n" - "Podsíť A: 50 uzlů\nPodsíť B: 25 uzlů\nPodsíť C: 12 uzlů\n" - "Podsíť D: 5 uzlů", - "A: 192.168.2.0/26 síť 192.168.2.0 uzly 192.168.2.1–192.168.2.62 " - "broadcast 192.168.2.63\n" - "B: 192.168.2.64/27 síť 192.168.2.64 " - "uzly 192.168.2.65–192.168.2.94 broadcast 192.168.2.95\n" - "C: 192.168.2.96/28 síť 192.168.2.96 " - "uzly 192.168.2.97–192.168.2.110 broadcast 192.168.2.111\n" - "D: 192.168.2.112/28 síť 192.168.2.112 " - "uzly 192.168.2.113–192.168.2.126 broadcast 192.168.2.127", - }, -}; - -/* Interactive subnet calculator for the practice sheet: the student - * chooses a prefix and types the network address, broadcast and the - * usable host range. */ - -const NetAns net_ans[4][4] = { - { /* 10.0.0.0/24 */ - {26, "10.0.0.0", "10.0.0.63", "10.0.0.1", "10.0.0.62"}, - {27, "10.0.0.64", "10.0.0.95", "10.0.0.65", "10.0.0.94"}, - {28, "10.0.0.96", "10.0.0.111", "10.0.0.97", "10.0.0.110"}, - {28, "10.0.0.112", "10.0.0.127", "10.0.0.113", "10.0.0.126"}, - }, - { /* 172.16.0.0/16 */ - {23, "172.16.0.0", "172.16.1.255", "172.16.0.1", "172.16.1.254"}, - {24, "172.16.2.0", "172.16.2.255", "172.16.2.1", "172.16.2.254"}, - {25, "172.16.3.0", "172.16.3.127", "172.16.3.1", "172.16.3.126"}, - {26, "172.16.3.128", "172.16.3.191", "172.16.3.129", "172.16.3.190"}, - }, - { /* does not fit into a /24 */ - {-1, NULL, NULL, NULL, NULL}, - {-1, NULL, NULL, NULL, NULL}, - {-1, NULL, NULL, NULL, NULL}, - {-1, NULL, NULL, NULL, NULL}, - }, - { /* 192.168.2.0/25 */ - {26, "192.168.2.0", "192.168.2.63", "192.168.2.1", "192.168.2.62"}, - {27, "192.168.2.64", "192.168.2.95", "192.168.2.65", "192.168.2.94"}, - {28, "192.168.2.96", "192.168.2.111", "192.168.2.97", "192.168.2.110"}, - {28, "192.168.2.112", "192.168.2.127", "192.168.2.113", "192.168.2.126"}, - }, -}; - - -GtkWidget *net_qz_combo(void) { - GtkWidget *c = gtk_combo_box_text_new(); - - for (int p = 8; p <= 30; p++) { - char buf[8]; - - g_snprintf(buf, sizeof(buf), "/%d", p); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(c), NULL, buf); - } - gtk_combo_box_set_active(GTK_COMBO_BOX(c), -1); - return c; -} - -void net_qz_set_prefix(GtkComboBoxText *c, int pfx) { - if (pfx >= 8 && pfx <= 30) - gtk_combo_box_set_active(GTK_COMBO_BOX(c), pfx - 8); - else - gtk_combo_box_set_active(GTK_COMBO_BOX(c), -1); -} - -int net_qz_prefix(GtkComboBoxText *c) { - gchar *txt = gtk_combo_box_text_get_active_text(c); - int p = txt ? atoi(txt + (txt[0] == '/' ? 1 : 0)) : -1; - - g_free(txt); - return p; -} - -/* Case- and space-insensitive comparison of typed address answers. */ -gboolean net_txt_eq(const char *a, const char *b) { - const char *x, *y; - - if (!a || !b) - return a == b; - x = a; - y = b; - while (*x && *y) { - while (*x == ' ' || *x == '\t') - x++; - while (*y == ' ' || *y == '\t') - y++; - if (g_ascii_tolower((guchar)*x) != g_ascii_tolower((guchar)*y)) - return FALSE; - if (*x) - x++; - if (*y) - y++; - } - while (*x == ' ' || *x == '\t') - x++; - while (*y == ' ' || *y == '\t') - y++; - return *x == '\0' && *y == '\0'; -} - -gboolean net_qz_entry_ok(GtkWidget *entry, const char *want) { - const gchar *got = gtk_editable_get_text(GTK_EDITABLE(entry)); - - return got && net_txt_eq(got, want); -} - -static gboolean net_u1_task_ok[4]; - -void net_qz_check(GtkButton *button, gpointer data) { - NetQz *q = data; - int ok = 0; - - (void)button; - - if (q->infeasible) { - set_feedback(q->feed, FALSE, - "Toto zadání se do sítě /24 nevejde – vyzkoušej " - "„Ukázat řešení“ a přečti si proč."); - return; - } - - for (int i = 0; i < 4; i++) { - const NetAns *a = &net_ans[q->id][i]; - gboolean p_ok = a->pfx > 0 && - net_qz_prefix(GTK_COMBO_BOX_TEXT(q->combo[i])) == a->pfx; - gboolean net_ok = net_qz_entry_ok(q->net[i], a->net); - gboolean bc_ok = net_qz_entry_ok(q->bcast[i], a->bcast); - gboolean lo_ok = net_qz_entry_ok(q->lo[i], a->lo); - gboolean hi_ok = net_qz_entry_ok(q->hi[i], a->hi); - - answer_mark(q->combo[i], p_ok); - answer_mark(q->net[i], net_ok); - answer_mark(q->bcast[i], bc_ok); - answer_mark(q->lo[i], lo_ok); - answer_mark(q->hi[i], hi_ok); - if (p_ok && net_ok && bc_ok && lo_ok && hi_ok) - ok++; - } - - if (ok == 4) { - set_feedback(q->feed, TRUE, tr("feedback_ok")); - net_u1_task_ok[q->id] = TRUE; - if (net_u1_task_ok[0] && net_u1_task_ok[1] && net_u1_task_ok[2] && - net_u1_task_ok[3]) - mark_net_done(0); - } else { - set_feedback(q->feed, FALSE, tr("feedback_retry")); - } -} - -void net_qz_fill(GtkButton *button, gpointer data) { - NetQz *q = data; - - (void)button; - for (int i = 0; i < 4; i++) { - const NetAns *a = &net_ans[q->id][i]; - - if (a->pfx <= 0) - continue; - net_qz_set_prefix(GTK_COMBO_BOX_TEXT(q->combo[i]), a->pfx); - gtk_editable_set_text(GTK_EDITABLE(q->net[i]), a->net); - gtk_editable_set_text(GTK_EDITABLE(q->bcast[i]), a->bcast); - gtk_editable_set_text(GTK_EDITABLE(q->lo[i]), a->lo); - gtk_editable_set_text(GTK_EDITABLE(q->hi[i]), a->hi); - } - if (q->note) - gtk_widget_set_visible(q->note, TRUE); - if (q->infeasible) { - net_u1_task_ok[q->id] = TRUE; - if (net_u1_task_ok[0] && net_u1_task_ok[1] && net_u1_task_ok[2] && - net_u1_task_ok[3]) - mark_net_done(0); - } -} - -void net_qz_header(GtkWidget *box, const char *text) { - GtkWidget *l = gtk_label_new(text); - - gtk_widget_add_css_class(l, "meaning"); - gtk_widget_set_halign(l, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(box), l); -} - -GtkWidget *net_qz_make_entry(void) { - GtkWidget *e = gtk_entry_new(); - - gtk_widget_set_hexpand(e, TRUE); - /* Four address columns must share the window; 15 chars each pushed the - * last column past the right edge. */ - gtk_editable_set_width_chars(GTK_EDITABLE(e), 7); - gtk_editable_set_max_width_chars(GTK_EDITABLE(e), 16); - return e; -} - -GtkWidget *build_net_exercise_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("netunit1", "net_ex_title", NULL)); - - scroll = gtk_scrolled_window_new(); - /* Never scroll sideways: the address table must shrink to the window - * instead of pushing its last column off screen. */ - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - net_heading(body, - "Zadání pro výpočet IP adres – k procvičení"); - net_paragraph(body, - "Určete pro každou podsíť:\n" - "• Maska podsítě (prefix)\n" - "• Rozsah IP adres podsítě\n" - "• Rozsah IP adres pro uzly\n" - "• Síťovou adresu\n" - "• Broadcast adresu"); - - for (guint t = 0; t < G_N_ELEMENTS(net_tasks); t++) { - GtkWidget *task = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - GtkWidget *table; - GtkWidget *btns; - GtkWidget *reveal; - GtkWidget *check; - GtkWidget *sol; - NetQz *q = g_new0(NetQz, 1); - - q->infeasible = (t == 2); - q->id = (int)t; - gtk_widget_set_margin_top(task, 10); - gtk_box_append(GTK_BOX(body), task); - - net_paragraph(task, net_tasks[t].prompt); - - if (q->infeasible) { - net_qz_header(task, net_tasks[t].solution); - } else { - static const char *cols[] = {"Prefix", "Síťová adresa", - "Broadcast", "Uzly od", "Uzly do"}; - table = gtk_grid_new(); - gtk_grid_set_row_spacing(GTK_GRID(table), 6); - gtk_grid_set_column_spacing(GTK_GRID(table), 8); - gtk_widget_set_margin_top(table, 6); - gtk_widget_set_hexpand(table, TRUE); - gtk_box_append(GTK_BOX(task), table); - - for (guint c = 1; c < 6; c++) { - GtkWidget *h = gtk_label_new(cols[c - 1]); - gtk_widget_add_css_class(h, "meaning"); - gtk_grid_attach(GTK_GRID(table), h, (int)c, 0, 1, 1); - } - - for (int i = 0; i < 4; i++) { - char letter[8]; - GtkWidget *lab = gtk_label_new(NULL); - int row = i + 1; - - g_snprintf(letter, sizeof(letter), "%c", 'A' + i); - gtk_label_set_text(GTK_LABEL(lab), letter); - gtk_widget_add_css_class(lab, "ex-prompt"); - gtk_grid_attach(GTK_GRID(table), lab, 0, row, 1, 1); - - q->combo[i] = net_qz_combo(); - gtk_grid_attach(GTK_GRID(table), q->combo[i], 1, row, 1, 1); - q->net[i] = net_qz_make_entry(); - gtk_grid_attach(GTK_GRID(table), q->net[i], 2, row, 1, 1); - q->bcast[i] = net_qz_make_entry(); - gtk_grid_attach(GTK_GRID(table), q->bcast[i], 3, row, 1, 1); - q->lo[i] = net_qz_make_entry(); - gtk_grid_attach(GTK_GRID(table), q->lo[i], 4, row, 1, 1); - q->hi[i] = net_qz_make_entry(); - gtk_grid_attach(GTK_GRID(table), q->hi[i], 5, row, 1, 1); - } - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_box_append(GTK_BOX(task), btns); - - if (!q->infeasible) { - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "pill"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(net_qz_check), q); - } - - reveal = gtk_button_new(); - i18n_bind(reveal, "net_solution", 1); - gtk_widget_add_css_class(reveal, "pill"); - gtk_widget_set_halign(reveal, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), reveal); - g_signal_connect(reveal, "clicked", G_CALLBACK(net_qz_fill), q); - - q->feed = gtk_label_new(""); - gtk_widget_set_halign(q->feed, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(task), q->feed); - - sol = gtk_label_new(net_tasks[t].solution); - gtk_widget_set_halign(sol, GTK_ALIGN_START); - gtk_label_set_xalign(GTK_LABEL(sol), 0.0); - gtk_label_set_wrap(GTK_LABEL(sol), TRUE); - gtk_widget_set_margin_start(sol, 8); - gtk_widget_add_css_class(sol, "meaning"); - gtk_widget_set_visible(sol, FALSE); - gtk_box_append(GTK_BOX(task), sol); - q->note = sol; - } - - return page; -} - -/* ---- Units 2–10: shared multiple-choice quizzes -------------------- */ - -void net_mcq_check(GtkButton *button, gpointer data) { - NetMcqCtx *ctx = data; - int ok = 0; - - (void)button; - - for (int i = 0; i < ctx->n; i++) { - int active = -1; - - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_net_done(ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -GtkWidget *build_net_mcq_page(int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - NetMcqCtx *ctx = g_new0(NetMcqCtx, 1); - int n_opts = qs[0].n_options; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(net_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - - return page; -} - -const ChoiceQ net2_qs[] = { - {"Kolik bitů má jeden byte?", - {"4", "8", "16", "32"}, 4, 1}, - {"Kolik různých hodnot nabývá jeden byte?", - {"128", "255", "256", "512"}, 4, 2}, - {"Co je trvalé propojení sítě?", - {"Modem", "Wi‑Fi", "Kabely", "Bluetooth"}, 4, 2}, - {"Co označuje zkratka WAN?", - {"Lokální síť v budově", "Městskou síť", - "Rozsáhlou síť (státy, kontinenty)", "Bezdrátovou síť"}, 4, 2}, - {"Co je topologie sítě?", - {"Norma pro zpracování dat", "Způsob propojení uzlů", - "Název serveru", "Rychlost přenosu"}, 4, 1}, - {"Architektura sítě je:", - {"Jen topologie", "Jen standard", "Topologie + standard", - "Pouze typ kabelu"}, 4, 2}, - {"Peer‑to‑peer síť znamená:", - {"Síť s jedním výkonným serverem", - "Síť bez serverů – stanice sdílejí data", - "Jen internetovou síť", "Síť pouze s tiskárnami"}, 4, 1}, - {"Server v síti je:", - {"Jednoduchá stanice pro uživatele", - "Nadřazený uzel poskytující služby", - "Jen aktivní prvek kabeláže", "Dočasné Wi‑Fi připojení"}, 4, 1}, -}; - -const char *net2_hints[] = { - "1 B = 8 b", - "2⁸ = 256 hodnot (0–255)", - "Kabely – síť zůstává připojená i po přenosu", - "WAN = Wide Area Network, např. internet", - "Např. hvězda, kruh, sběrnice", - "Architektura = topologie + standard", - "Bez centrálního serveru – stanice si sdílejí data a tiskárny", - "Server řídí a poskytuje služby, má vyšší výkon", -}; - -GtkWidget *build_net_unit2_exercise_page(void) { - return build_net_mcq_page(1, "netunit2", "net_ex2_title", "net_quiz2_head", - net2_qs, net2_hints, - (int)G_N_ELEMENTS(net2_qs)); -} - -const ChoiceQ net3_qs[] = { - {"Co typicky dělají servery v síti?", - {"Jen tisknou dokumenty", "Ověřují uživatele a povolují přístup", - "Nahrazují kabely", "Slouží jen jako Wi‑Fi"}, 4, 1}, - {"Fileserver je:", - {"Tiskový server", "Poštovní server", "Souborový server", - "Databázový server"}, 4, 2}, - {"Centralizovaný server znamená:", - {"Více serverů v síti", "Jeden server – výpadek = nedostupnost služby", - "Server jen pro tisk", "Cloud bez internetu"}, 4, 1}, - {"Distribuovaný model serverů nabízí hlavně:", - {"Nižší spolehlivost", "Vyšší spolehlivost a rychlost", - "Jen levnější kabely", "Odstranění uživatelů"}, 4, 1}, - {"Nevyhrazený server:", - {"Slouží jen síťovým službám", "Slouží i jako pracovní stanice", - "Je vždy mainframe", "Nemůže ověřovat uživatele"}, 4, 1}, - {"Vyhrazený server je určen:", - {"Jen jako stanice uživatele", "Jen pro síťové služby", - "Jen pro Bluetooth", "Jen pro dočasné Wi‑Fi"}, 4, 1}, - {"Mainframe se typicky používá:", - {"Jen v domácnostech", "V bankách a státní správě", - "Jen pro streamování hudby", "Jen jako tiskárna"}, 4, 1}, - {"Cloud a SaaS znamenají především:", - {"Lokální síť bez internetu", - "Vzdálené servery a software jako služba online", - "Jen jeden kabel v budově", "Peer‑to‑peer bez serverů"}, 4, 1}, -}; - -const char *net3_hints[] = { - "Ověřují uživatele a povolují přístup ke službám", - "Fileserver = souborový server", - "Jeden server – při výpadku je služba nedostupná", - "Více serverů, každý obsluhuje část – vyšší spolehlivost", - "Slouží zároveň i jako pracovní stanice", - "Jen síťové služby – vysoký výkon a bezpečnost, často v racku", - "Obří sálové počítače (IBM, Siemens) pro banky a státní správu", - "SaaS = software jako služba, přístup online z libovolného zařízení", -}; - -GtkWidget *build_net_unit3_exercise_page(void) { - return build_net_mcq_page(2, "netunit3", "net_ex3_title", "net_quiz3_head", - net3_qs, net3_hints, - (int)G_N_ELEMENTS(net3_qs)); -} - -const ChoiceQ net4_qs[] = { - {"Paralelní přenos znamená:", - {"Bit po bitu po jednom vodiči", - "Více bitů současně po více vodičích", - "Jen Wi‑Fi bez kabelů", "Jen cloudové ukládání"}, 4, 1}, - {"Hlavní problém paralelního přenosu při delších kabelech je:", - {"Absence serveru", "Přeslechy (rušení)", "Chybějící SaaS", - "Peer‑to‑peer režim"}, 4, 1}, - {"Sériový přenos je oproti paralelnímu celkově:", - {"Vždy pomalejší", "Rychlejší díky vyšším frekvencím a délkám", - "Jen pro tiskárny", "Bez jakéhokoli kabelu"}, 4, 1}, - {"V asynchronním přenosu start-bit má hodnotu:", - {"1", "0", "8", "255"}, 4, 1}, - {"Synchronní přenos je řízen:", - {"Jen stop-bitem", "Společným hodinovým signálem", - "Jen paritou", "Jen checksumem"}, 4, 1}, - {"Nejslabší metoda zabezpečení z uvedených je:", - {"CRC", "Checksum", "Parita", "Mainframe"}, 4, 2}, - {"Checksum spočívá v:", - {"Přidání start-bitu", "Součtu znaků jako dvojkových čísel", - "Jen Wi‑Fi šifrování", "Výměně kabelů"}, 4, 1}, - {"CRC (cyklické kódy) je z uvedených metod:", - {"Nejslabší", "Stejně slabá jako parita", "Nejbezpečnější", - "Jen pro paralelní přenos"}, 4, 2}, -}; - -const char *net4_hints[] = { - "Více bitů najednou po více vodičích; problém jsou přeslechy", - "Přeslechy vznikají při delších kabelech a vysokých frekvencích", - "Bit po bitu po jednom vodiči – vyšší frekvence i délky", - "Start-bit (0) synchronizuje, Stop-bit (1) ukončuje znak", - "Řízeno společným hodinovým signálem a přesným časováním", - "Nejslabší – přidá bit pro sudý/lichý počet jedniček", - "Součet znaků jako dvojkových čísel", - "Nejbezpečnější – počítá se z jednotlivých bitů v bloku", -}; - -GtkWidget *build_net_unit4_exercise_page(void) { - return build_net_mcq_page(3, "netunit4", "net_ex4_title", "net_quiz4_head", - net4_qs, net4_hints, - (int)G_N_ELEMENTS(net4_qs)); -} - -const ChoiceQ net5_qs[] = { - {"Digitální signál nabývá:", - {"Libovolných spojitých hodnot", "Diskrétních hodnot 0 a 1", - "Jen frekvence FM", "Jen šířky pásma"}, 4, 1}, - {"Frekvence f je:", - {"Stejná jako amplituda", "f = 1/T", "Jen fázový posun", - "Počet bitů v QPSK"}, 4, 1}, - {"AM, FM a PM jsou:", - {"Typy kabelů", "Základní typy modulace", "Jen CRC metody", - "Typy serverů"}, 4, 1}, - {"QPSK přenáší v jednom prvku:", - {"1 bit", "2 bity", "8 bitů", "256 bitů"}, 4, 1}, - {"256-QAM přenáší v jednom prvku:", - {"2 bity", "4 bity", "8 bitů", "16 bitů"}, 4, 2}, - {"Modulační rychlost se udává v:", - {"Jen bit/s", "Baud (Bd/s)", "Jen metrech", "Jen hertzech amplitudy"}, 4, 1}, - {"Přenosová rychlost vyjadřuje:", - {"Počet změn signálu za sekundu", "Velikost přenesené informace [bit/s]", - "Jen fázový posun", "Jen periodu T"}, 4, 1}, - {"Šířka pásma určuje:", - {"Jen barvu kabelu", "Maximální možnou přenosovou rychlost", - "Jen počet serverů", "Jen start-bit"}, 4, 1}, -}; - -const char *net5_hints[] = { - "Analogový je spojitý, digitální má diskrétní hodnoty 0 a 1", - "Frekvence f = 1/T, kde T je perioda", - "AM mění amplitudu, FM frekvenci, PM fázi", - "QPSK nese 2 bity v prvku, 256-QAM nese 8 bitů", - "QPSK nese 2 bity v prvku, 256-QAM nese 8 bitů", - "Modulační rychlost = počet změn signálu za sekundu [Bd/s]", - "Přenosová rychlost = množství informace za sekundu [bit/s]", - "Šířka pásma určuje maximální možnou přenosovou rychlost", -}; - -GtkWidget *build_net_unit5_exercise_page(void) { - return build_net_mcq_page(4, "netunit5", "net_ex5_title", "net_quiz5_head", - net5_qs, net5_hints, - (int)G_N_ELEMENTS(net5_qs)); -} - -const ChoiceQ net6_qs[] = { - {"Datový spoj slouží k:", - {"Jen měření amplitudy", "Výměně informací", "Jen FM modulaci", - "Jen tisku dokumentů"}, 4, 1}, - {"Přenosová cesta je:", - {"Jen softwarová služba", "Fyzické médium přenosu", - "Jen CRC kód", "Jen peer‑to‑peer účet"}, 4, 1}, - {"Mezi přenosová média patří:", - {"Jen parita", "Kabely, mikrovlny a družice", "Jen Baud", - "Jen start-bit"}, 4, 1}, - {"Přenosový kanál je:", - {"Obousměrný vždy", "Jednosměrný souhrn prostředků pro spojení", - "Jen název serveru", "Jen typ QPSK"}, 4, 1}, - {"Okruh vzniká:", - {"Z jednoho kanálu", "Ze dvou kanálů pro obousměrný přenos", - "Jen z parity", "Jen z Wi‑Fi hesla"}, 4, 1}, - {"Trunking znamená:", - {"Odpojení všech kabelů", "Spojení více cest do jednoho okruhu", - "Jen asynchronní stop-bit", "Jen digitální 0 a 1"}, 4, 1}, - {"Hlavní cíl trunkingu je:", - {"Snížit šířku pásma", "Zvýšit šířku pásma", "Zrušit kanály", - "Nahradit mainframe"}, 4, 1}, -}; - -const char *net6_hints[] = { - "Datový spoj umožňuje výměnu informací mezi uzly", - "Fyzické médium: kabely, mikrovlny nebo družice", - "Fyzické médium: kabely, mikrovlny nebo družice", - "Kanál je jednosměrný souhrn prostředků pro spojení", - "Okruh tvoří dva kanály pro obousměrný přenos", - "Trunking spojuje více cest do jednoho okruhu", - "Trunking zvyšuje šířku pásma spojením cest", -}; - -GtkWidget *build_net_unit6_exercise_page(void) { - return build_net_mcq_page(5, "netunit6", "net_ex6_title", "net_quiz6_head", - net6_qs, net6_hints, - (int)G_N_ELEMENTS(net6_qs)); -} - -const ChoiceQ net7_qs[] = { - {"Multiplex znamená:", - {"Jen jeden uživatel na kanál", - "Rozdělení jednoho kanálu na více logických podkanálů", - "Jen CRC kontrolu", "Jen digitální 0 a 1"}, 4, 1}, - {"FDM přiděluje každému kanálu:", - {"Časový slot", "Část frekvenčního pásma", "Jen start-bit", - "Jen mainframe"}, 4, 1}, - {"TDM přiděluje každému kanálu:", - {"Část frekvenčního pásma", "Vyhrazený časový slot", - "Jen SaaS účet", "Jen paritu"}, 4, 1}, - {"STDM:", - {"Garantuje vždy 100% dostupnost", - "Přiděluje kapacitu dle potřeby a negarantuje 100%", - "Je jen simplex", "Je jen trunking kabelů"}, 4, 1}, - {"Simplex umožňuje přenos:", - {"Oběma směry současně", "Jen jedním směrem", - "Oběma směry, ale ne současně", "Jen přes CRC"}, 4, 1}, - {"Half-duplex znamená:", - {"Jen jeden směr", "Oběma směry, ne současně", - "Oběma směry současně", "Jen FDM"}, 4, 1}, - {"Full-duplex znamená:", - {"Jen jeden směr", "Oběma směry, ne současně", - "Oběma směry současně", "Jen STDM"}, 4, 2}, - {"Agregace je:", - {"Sdílení kapacity kanálu více uživateli", "Jen fázová modulace", - "Jen dvoubodový spoj", "Jen stop-bit"}, 4, 0}, -}; - -const char *net7_hints[] = { - "Multiplex dělí jeden kanál na více logických podkanálů", - "FDM: každému kanálu část frekvenčního pásma", - "TDM: každému kanálu vyhrazený časový slot", - "STDM přiděluje kapacitu dle potřeby, negarantuje 100 %", - "Simplex = jen jeden směr přenosu", - "Half-duplex = oběma směry, ale ne současně", - "Full-duplex = oběma směry současně", - "Agregace = sdílení kapacity kanálu více uživateli", -}; - -GtkWidget *build_net_unit7_exercise_page(void) { - return build_net_mcq_page(6, "netunit7", "net_ex7_title", "net_quiz7_head", - net7_qs, net7_hints, - (int)G_N_ELEMENTS(net7_qs)); -} - -const ChoiceQ net8_qs[] = { - {"Přepojování okruhů znamená:", - {"Pakety jdou vždy jinou cestou", - "Cesta se vytýčí předem a kapacita je garantována", - "Jen FDM multiplex", "Jen half-duplex"}, 4, 1}, - {"Přepojování okruhů je vhodné pro:", - {"Jen náhodné datagramy bez cesty", "Přenos v reálném čase (jako telefon)", - "Jen CRC", "Jen peer‑to‑peer tisk"}, 4, 1}, - {"Při přepojování paketů:", - {"Vždy existuje jedna pevná cesta", - "Každý paket může jít jinou cestou", - "Kapacita je vždy garantována", "Neexistují adresy"}, 4, 1}, - {"Výhoda přepojování paketů je:", - {"Garantované pořadí vždy", "Reakce na zátěž a využití kapacity", - "Jen simplex", "Jen trunking"}, 4, 1}, - {"Nevýhoda přepojování paketů je:", - {"Nereaguje na zátěž", "Negarantuje pořadí ani plynulost", - "Nelze použít adresy", "Vždy blokuje kanál jako telefon"}, 4, 1}, - {"Pro video v reálném čase je přepojování paketů:", - {"Ideální vždy", "Spíše nevhodné kvůli plynulosti", - "Jediná možná metoda", "Stejné jako AM modulace"}, 4, 1}, - {"Virtuální spoje:", - {"Nemají předem žádnou cestu", - "Mají cestu předem, prostředky jen při průchodu paketu", - "Jsou jen FDM", "Jsou jen parita"}, 4, 1}, - {"Virtuální spoje slouží hlavně k:", - {"Zrušení paketů", "Zrychlení datagramů", "Jen simplexu", - "Jen analogovému signálu"}, 4, 1}, -}; - -const char *net8_hints[] = { - "Cesta se vytýčí předem, kapacita je garantována", - "Cesta se vytýčí předem, kapacita je garantována", - "Data se dělí na pakety, každý může jít jinou cestou", - "Výhody: reakce na zátěž a lepší využití kapacity", - "Negarantuje pořadí ani plynulost – nevhodné pro živé video", - "Negarantuje pořadí ani plynulost – nevhodné pro živé video", - "Cesta je předem, prostředky se použijí jen při průchodu paketu", - "Virtuální spoje zrychlují přenos datagramů", -}; - -GtkWidget *build_net_unit8_exercise_page(void) { - return build_net_mcq_page(7, "netunit8", "net_ex8_title", "net_quiz8_head", - net8_qs, net8_hints, - (int)G_N_ELEMENTS(net8_qs)); -} - -const ChoiceQ net9_qs[] = { - {"Standardizace v sítích především:", - {"Zvyšuje nekompatibilitu", "Zajišťuje kompatibilitu mezi výrobci", - "Ruší protokoly", "Nahrazuje kabely"}, 4, 1}, - {"Dekompozice znamená:", - {"Spojení všeho do jedné vrstvy", - "Rozklad složitého přenosu na vrstvy", - "Jen FDM", "Jen CRC"}, 4, 1}, - {"Vrstvy komunikují:", - {"Se všemi vrstvami najednou", "Jen se sousedy přes rozhraní (SAP)", - "Jen přes satelit", "Jen bez protokolu"}, 4, 1}, - {"Protokol je:", - {"Fyzický kabel", "Pravidla komunikace mezi stejnými vrstvami", - "Jen amplituda signálu", "Jen tiskový server"}, 4, 1}, - {"Každá vrstva k datům typicky přidá:", - {"Jen stop-bit", "Hlavičku (header)", "Jen šířku pásma", - "Jen mainframe"}, 4, 1}, - {"Jednotka linkové vrstvy se nazývá:", - {"Segment", "Paket", "Rámec", "Baud"}, 4, 2}, - {"Jednotka síťové vrstvy se nazývá:", - {"Rámec", "Paket", "Segment", "Simplex"}, 4, 1}, - {"Jednotka transportní vrstvy se nazývá:", - {"Rámec", "Paket", "Segment", "Trunk"}, 4, 2}, -}; - -const char *net9_hints[] = { - "Standardizace zajišťuje kompatibilitu mezi výrobci", - "Dekompozice rozkládá přenos na jednotlivé vrstvy", - "Vrstvy komunikují jen se sousedy přes rozhraní SAP", - "Protokol = pravidla mezi stejnými vrstvami na různých uzlech", - "Každá vrstva přidává k datům hlavičku (header)", - "Rámec = linková, paket = síťová, segment = transportní", - "Rámec = linková, paket = síťová, segment = transportní", - "Rámec = linková, paket = síťová, segment = transportní", -}; - -GtkWidget *build_net_unit9_exercise_page(void) { - return build_net_mcq_page(8, "netunit9", "net_ex9_title", "net_quiz9_head", - net9_qs, net9_hints, - (int)G_N_ELEMENTS(net9_qs)); -} - -const ChoiceQ net10_qs[] = { - {"Model ISO/OSI má:", - {"4 vrstvy", "5 vrstev", "7 vrstev", "10 vrstev"}, 4, 2}, - {"ISO/OSI je především:", - {"Jen typ kabelu", "Univerzální referenční model", - "Jen tiskový server", "Jen FDM"}, 4, 1}, - {"Proč je ISO/OSI v praxi pomalejší?", - {"Nemá žádné vrstvy", "Každá vrstva řešila spolehlivost", - "Nepoužívá protokoly", "Nemá SAP"}, 4, 1}, - {"TCP/IP v praxi:", - {"Prohrál proti ISO/OSI", "Zvítězil jako praktická architektura", - "Je jen analogový signál", "Je jen half-duplex"}, 4, 1}, - {"TCP/IP vycházel z:", - {"Jen teoretických schémat bez praxe", "Skutečných potřeb sítí", - "Jen parity", "Jen trunkingu"}, 4, 1}, - {"V TCP/IP spolehlivost řeší:", - {"Vždy jen fyzická vrstva", "Až vyšší vrstvy", - "Jen metalické kabely", "Jen mainframe"}, 4, 1}, -}; - -const char *net10_hints[] = { - "ISO/OSI má 7 vrstev a je univerzální model", - "ISO/OSI má 7 vrstev a je univerzální model", - "V praxi je ISO/OSI pomalejší – spolehlivost řeší každá vrstva", - "TCP/IP zvítězil, protože vycházel ze skutečných potřeb", - "TCP/IP zvítězil, protože vycházel ze skutečných potřeb", - "V TCP/IP řeší spolehlivost až vyšší vrstvy", -}; - -GtkWidget *build_net_unit10_exercise_page(void) { - return build_net_mcq_page(9, "netunit10", "net_ex10_title", "net_quiz10_head", - net10_qs, net10_hints, - (int)G_N_ELEMENTS(net10_qs)); -} - -const ChoiceQ net11_qs[] = { - {"Fyzická vrstva se stará o:", - {"Přenos bitů", "Směrování paketů", "Navazování relací", - "Formátování ASCII"}, 4, 0}, - {"MAC a LLC jsou podvrstvy:", - {"Síťové vrstvy", "Spojové (linkové) vrstvy", "Transportní vrstvy", - "Aplikační vrstvy"}, 4, 1}, - {"Směrování paketů v sítích bez přímého spojení řeší:", - {"Fyzická vrstva", "Relační vrstva", "Síťová vrstva", - "Prezentační vrstva"}, 4, 2}, - {"Transportní vrstva existuje:", - {"Jen v koncových uzlech", "I v routerech", "Jen ve switchech", - "Jen na hubu"}, 4, 0}, - {"Relační vrstva především:", - {"Definuje napětí a kabely", "Navazuje, udržuje a ukončuje relace", - "Přidává MAC adresy", "Směruje pakety"}, 4, 1}, - {"Komprese a šifrování patří do vrstvy:", - {"Fyzické", "Spojové", "Prezentační", "Síťové"}, 4, 2}, - {"Aplikační vrstva poskytuje:", - {"CRC mezi sousedy", "Rozhraní pro programy (HTTP, FTP, e-mail…)", - "Jen duplex/simplex", "Jen směrování"}, 4, 1}, -}; - -const char *net11_hints[] = { - "Fyzická vrstva přenáší bity a řeší médium", - "Spojová vrstva má podvrstvy MAC a LLC", - "Síťová vrstva směruje pakety i bez přímého spojení", - "Transportní vrstva je jen v koncových uzlech, ne v routerech", - "Relační vrstva řídí relace, dialog a synchronizaci", - "Prezentační vrstva formátuje data, komprimuje a šifruje", - "Aplikační vrstva je rozhraní pro programy a služby", -}; - -GtkWidget *build_net_unit11_exercise_page(void) { - return build_net_mcq_page(10, "netunit11", "net_ex11_title", "net_quiz11_head", - net11_qs, net11_hints, - (int)G_N_ELEMENTS(net11_qs)); -} - -const ChoiceQ net12_qs[] = { - {"Aplikační vrstva TCP/IP odpovídá v ISO/OSI:", - {"Jen aplikační vrstvě", "Aplikační + prezentační + relační", - "Jen fyzické vrstvě", "Linkové + síťové"}, 4, 1}, - {"Vrstva síťového rozhraní TCP/IP odpovídá:", - {"Jen síťové ISO/OSI", "Linkové + fyzické ISO/OSI", - "Jen transportní ISO/OSI", "Jen aplikační ISO/OSI"}, 4, 1}, - {"Model TCP/IP vznikl:", - {"Nejdřív model, pak protokoly", "Nejdřív protokoly, pak model", - "Současně s Token Ring", "Jen jako náhrada za ATM"}, 4, 1}, - {"TCP je:", - {"Nespolehlivý a rychlý", "Spolehlivý a spojovaný", - "Jen směrovací protokol", "Jen fyzické kódování"}, 4, 1}, - {"UDP je:", - {"Spolehlivý a spojovaný", "Nespolehlivý a rychlý", - "Jen e-mailový protokol", "Jen ARP"}, 4, 1}, - {"HTTP, DNS a SMTP patří do vrstvy:", - {"Aplikační", "Transportní", "Síťové", "Síťového rozhraní"}, 4, 0}, - {"IP, ICMP a OSPF patří do vrstvy:", - {"Aplikační", "Transportní", "Síťové (internetové)", - "Síťového rozhraní"}, 4, 2}, - {"Ethernet a PPP patří do vrstvy:", - {"Aplikační", "Transportní", "Síťové", "Síťového rozhraní"}, 4, 3}, -}; - -const char *net12_hints[] = { - "Aplikační TCP/IP = aplikační + prezentační + relační ISO/OSI", - "Síťové rozhraní TCP/IP = linková + fyzická ISO/OSI", - "U TCP/IP vznikly nejdřív protokoly, až pak model", - "TCP je spolehlivý a spojovaný", - "UDP je nespolehlivý a rychlý", - "HTTP, DNS a SMTP jsou aplikační protokoly", - "IP, ICMP a OSPF patří na síťovou (internetovou) vrstvu", - "Ethernet a PPP patří na vrstvu síťového rozhraní", -}; - -GtkWidget *build_net_unit12_exercise_page(void) { - return build_net_mcq_page(11, "netunit12", "net_ex12_title", "net_quiz12_head", - net12_qs, net12_hints, - (int)G_N_ELEMENTS(net12_qs)); -} - -const ChoiceQ net13_qs[] = { - {"Topologie sběrnice (bus) znamená, že:", - {"Každý uzel má vlastní centrální switch", "Médium sdílí všichni", - "Kabely tvoří jen zdvojený kruh", "Používá jen OSPF"}, 4, 1}, - {"Nevýhoda sběrnice je hlavně:", - {"Že potřebuje hub u každého uzlu", - "Nízká bezpečnost a náchylnost na poruchu kabelu", - "Že nelze použít koaxiál", "Že zprávy neobíhají"}, 4, 1}, - {"Topologie hvězda propojuje uzly přes:", - {"Jen jeden společný koaxiál bez centra", - "Centrální prvek (hub nebo switch)", - "Jen Token Ring", "Jen ATM"}, 4, 1}, - {"Výhoda hvězdy je:", - {"Že přerušení jednoho kabelu k uzlu nevyřadí celou síť", - "Že všichni slyší vše", "Že nepotřebuje žádnou kabeláž", - "Že nemá aktivní prvky"}, 4, 0}, - {"Hvězda typicky používá:", - {"Jen koaxiální kabel", "Kroucenou dvoulinku nebo optiku", - "Jen simplexní rádio", "Jen FDM"}, 4, 1}, - {"V topologii kruh (ring):", - {"Zprávy obíhají, dokud nenajdou adresáta", - "Každý paket jde jen přes DNS", - "Médium sdílí hub bez kabelů", - "Neexistuje žádná kabeláž"}, 4, 0}, -}; - -const char *net13_hints[] = { - "Sběrnice: médium sdílí všichni", - "Sběrnice: nízká bezpečnost a porucha kabelu vyřadí síť", - "Hvězda: uzly jdou přes hub nebo switch", - "Hvězda: porucha kabelu k uzlu nevyřadí celou síť", - "Hvězda používá kroucenou dvoulinku nebo optiku", - "V kruhu zprávy obíhají, dokud nenajdou adresáta", -}; - -GtkWidget *build_net_unit13_exercise_page(void) { - return build_net_mcq_page(12, "netunit13", "net_ex13_title", "net_quiz13_head", - net13_qs, net13_hints, - (int)G_N_ELEMENTS(net13_qs)); -} - -const ChoiceQ net14_qs[] = { - {"Princip optiky je:", - {"Převod el. impulsů na světlo a zpět fotodiodou", - "Jen směrování paketů OSPF", "Jen sdílená sběrnice", - "Jen UDP spojení"}, 4, 0}, - {"Jedním vláknem je přenos:", - {"Vždy plně duplexní bez výjimky", "Jednosměrný (obousměrně dvě vlákna)", - "Jen poloviční kruh", "Jen Token Ring"}, 4, 1}, - {"Výhoda optiky není:", - {"Imunita vůči el.mag. rušení", "Velký dosah a šířka pásma", - "Levná a snadná montáž konektorů", "Lepší ochrana proti odposlechu"}, 4, 2}, - {"Mnohovidové vlákno (MM) má:", - {"Jádro 7–10 µm a vyžaduje laser", "Větší jádro 50/62,5 µm a více vidů", - "Jen koaxiální stínění", "Jen jednu MAC adresu"}, 4, 1}, - {"Jednovidové vlákno (SM):", - {"Má větší jádro a LED zdroj", "Má malé jádro, jeden paprsek a laser", - "Nepřenáší světlo", "Funguje jen jako hub"}, 4, 1}, - {"Levnější zdroje (LED) typicky patří k:", - {"Jednovidovým vláknům", "Mnohovidovým vláknům", - "Jen kruhové topologii", "Jen ATM"}, 4, 1}, -}; - -const char *net14_hints[] = { - "Optika: el. impulsy → světlo (LED/laser) → fotodioda", - "Jedno vlákno = jednosměrný přenos; obousměrně dvě vlákna", - "Nevýhody: náročná montáž a cena prvků/konektorů", - "MM: jádro 50/62,5 µm a více vidů", - "SM: jádro 7–10 µm, jeden paprsek, laser", - "MM typicky používá levnější LED zdroje", -}; - -GtkWidget *build_net_unit14_exercise_page(void) { - return build_net_mcq_page(13, "netunit14", "net_ex14_title", "net_quiz14_head", - net14_qs, net14_hints, - (int)G_N_ELEMENTS(net14_qs)); -} - -const ChoiceQ net15_qs[] = { - {"Primární ochrana optického vlákna má průměr:", - {"900 µm", "250 µm", "50 µm", "7–10 µm"}, 4, 1}, - {"Sekundární ochrana má průměr:", - {"250 µm", "900 µm", "62,5 µm", "1 km"}, 4, 1}, - {"Těsná sekundární ochrana je vhodná hlavně:", - {"Pro svislé instalace", "Jen pro kruhovou topologii", - "Jen pro UDP", "Jen pro hub"}, 4, 0}, - {"Volná sekundární ochrana je vhodná hlavně:", - {"Pro vodorovné instalace", "Jen pro ATM", - "Jen pro LED bez vlákna", "Jen pro sběrnici"}, 4, 0}, - {"Montáž optiky vyžaduje:", - {"Jen nůžky na koaxiál", "Precizní lámání a svářečku vláken", - "Jen hub bez konektorů", "Jen Token Ring"}, 4, 1}, - {"Při lámání se požaduje kolmost zhruba:", - {"Do 0,5°", "Do 45°", "Přesně 90° bez tolerance", "Bez významu"}, 4, 0}, -}; - -const char *net15_hints[] = { - "Primární ochrana: 250 µm", - "Sekundární ochrana: 900 µm", - "Těsná sekundární ochrana: svislé instalace", - "Volná sekundární ochrana: vodorovné instalace", - "Montáž: lámačka a svářečka optických vláken", - "Lámání vyžaduje kolmost asi 0,5°", -}; - -GtkWidget *build_net_unit15_exercise_page(void) { - return build_net_mcq_page(14, "netunit15", "net_ex15_title", "net_quiz15_head", - net15_qs, net15_hints, - (int)G_N_ELEMENTS(net15_qs)); -} - -const ChoiceQ net16_qs[] = { - {"Kolize nastane, když:", - {"Na sdíleném médiu vysílá více uzlů najednou", - "Router vypne OSPF", "Vlákno má ochranu 250 µm", - "Použijeme jen TCP"}, 4, 0}, - {"Metoda Aloha znamená především:", - {"Vysílej kdykoliv; bez potvrzení pošli znovu", - "Vždy rezervuj médium RTS/CTS", - "Nikdy nevysílej při tichu", - "Jen směrování RIP"}, 4, 0}, - {"CSMA/CD se typicky pojí s:", - {"Wi-Fi", "Ethernetem", "Jen SMTP", "Jen ATM"}, 4, 1}, - {"Při CSMA/CD uzel před vysíláním:", - {"Ignoruje médium", "Monitoruje nosnou (Carrier Sense)", - "Vždy čeká přesně 1 hodinu", "Použije jen laser"}, 4, 1}, - {"Když CSMA/CD detekuje kolizi:", - {"Pokračuje vysíláním bez změny", - "Zastaví vysílání a zkusí to po náhodném čase", - "Přepne síť na sběrnici", - "Smaže IP adresu"}, 4, 1}, - {"CSMA/CA na Wi-Fi předchází kolizím pomocí:", - {"RTS a CTS", "Jen CRC bez nosné", "Jen hubu", "Jen koaxiálu"}, 4, 0}, -}; - -const char *net16_hints[] = { - "Kolize = více uzlů vysílá na sdíleném médiu najednou", - "Aloha: vysílej kdykoliv, při chybě znovu", - "CSMA/CD patří k Ethernetu", - "CSMA/CD nejdřív poslouchá nosnou (Carrier Sense)", - "Po kolizi CSMA/CD čeká náhodný čas a zkusí znovu", - "CSMA/CA rezervuje médium přes RTS/CTS", -}; - -GtkWidget *build_net_unit16_exercise_page(void) { - return build_net_mcq_page(15, "netunit16", "net_ex16_title", "net_quiz16_head", - net16_qs, net16_hints, - (int)G_N_ELEMENTS(net16_qs)); -} - -const ChoiceQ net17_qs[] = { - {"Repeater (opakovač) hlavně:", - {"Zesiluje signál a zvyšuje dosah", "Směruje IP pakety", - "Převádí mezi protokoly vyšších vrstev", "Rezervuje médium RTS/CTS"}, 4, 0}, - {"Transceiver typicky:", - {"Převádí signál mezi různými médii", "Dělí síť jen podle DNS", - "Je vždy jen brána", "Pracuje jen s UDP"}, 4, 0}, - {"Hub (rozbočovač) je:", - {"„Hloupý“ prvek – data z jednoho portu pošle všem ostatním", - "Směrovač na síťové vrstvě", "Jen laserový zdroj", - "Jen MAC filtr bez portů"}, 4, 0}, - {"Bridge a switch pracují na vrstvě:", - {"Fyzické", "Linkové (rámce a MAC)", "Aplikační", "Jen transportní"}, 4, 1}, - {"Switch mimo jiné:", - {"Dělí síť na kolizní domény", "Nikdy nepoužívá MAC adresy", - "Funguje jen jako hub bez portů", "Převádí jen ASCII"}, 4, 0}, - {"Router pracuje s:", - {"Pakety a IP adresami a propojuje sítě", "Jen koaxiálem bez IP", - "Jen huby bez směrování", "Jen RTS/CTS"}, 4, 0}, - {"Gateway (brána) především:", - {"Převádí mezi odlišnými architekturami/protokoly", - "Jen zesiluje bitový signál", "Jen tvoří kolize", - "Jen lámání vlákna"}, 4, 0}, -}; - -const char *net17_hints[] = { - "Repeater zesiluje signál na fyzické vrstvě", - "Transceiver převádí mezi médii (např. metalika ↔ optika)", - "Hub rozešle přijatá data do všech ostatních portů", - "Bridge/switch = linková vrstva, rámce a MAC", - "Switch dělí síť na kolizní domény", - "Router = síťová vrstva, pakety a IP, propojuje sítě", - "Gateway převádí mezi odlišnými architekturami/protokoly", -}; - -GtkWidget *build_net_unit17_exercise_page(void) { - return build_net_mcq_page(16, "netunit17", "net_ex17_title", "net_quiz17_head", - net17_qs, net17_hints, - (int)G_N_ELEMENTS(net17_qs)); -} - -const ChoiceQ net18_qs[] = { - {"Switch se učí MAC adresy a ukládá je do:", - {"CAM tabulky", "Jen DNS cache", "Jen ARP bez portů", "Jen OSPF"}, 4, 0}, - {"Díky CAM tabulce switch posílá rámce:", - {"Jen na konkrétní port", "Vždy na všechny porty jako hub", - "Jen na routery", "Jen přes laser"}, 4, 0}, - {"Cut-through přepínání:", - {"Čte jen adresu příjemce a hned posílá", - "Vždy čeká na celé CRC", "Nikdy neposílá rámce", - "Pracuje jen s IP směrováním"}, 4, 0}, - {"Nevýhoda cut-through je:", - {"Že posílá i chybné rámce", "Že je nejpomalejší", - "Že nemá MAC adresy", "Že vyžaduje gateway"}, 4, 0}, - {"Store-and-forward:", - {"Přijme celý rámec, zkontroluje CRC a pak pošle", - "Čte jen první 2 byty", "Nikdy nekontroluje chyby", - "Funguje jen jako Aloha"}, 4, 0}, - {"Fragment-free (modifikovaný cut-through) čte:", - {"Prvních 64 bytů (detekce kolizí)", "Jen poslední byte", - "Celý paket IP včetně směrování", "Jen SMTP hlavičku"}, 4, 0}, -}; - -const char *net18_hints[] = { - "MAC adresy switch ukládá do CAM tabulky", - "Podle CAM tabulky posílá rámec jen na cílový port", - "Cut-through čte adresu příjemce a hned přeposílá", - "Cut-through je rychlý, ale propustí i chyby", - "Store-and-forward kontroluje celý rámec včetně CRC", - "Fragment-free čte prvních 64 bytů kvůli kolizím", -}; - -GtkWidget *build_net_unit18_exercise_page(void) { - return build_net_mcq_page(17, "netunit18", "net_ex18_title", "net_quiz18_head", - net18_qs, net18_hints, - (int)G_N_ELEMENTS(net18_qs)); -} - -const ChoiceQ net19_qs[] = { - {"Směrování probíhá na vrstvě:", - {"Fyzické", "Síťové (3. ISO/OSI)", "Jen aplikační", "Jen linkové"}, 4, 1}, - {"Adaptivní (dynamické) algoritmy:", - {"Reagují na změny a vyměňují informace mezi směrovači", - "Nikdy nemění cesty", "Fungují jen na fyzické vrstvě", - "Nepoužívají metriku"}, 4, 0}, - {"Neadaptivní (statické) směrování:", - {"Má cesty pevně nastavené správcem", "Samo opraví každý výpadek", - "Nepotřebuje směrovací tabulku", "Běží jen na Wi-Fi"}, 4, 0}, - {"Centralizované směrování v praxi:", - {"Se skoro nepoužívá – výpadek centra shodí směrování", - "Je jediný standard internetu", "Neexistuje žádné centrum", - "Pracuje jen s MAC adresami"}, 4, 0}, - {"Distribuované směrování znamená, že:", - {"Směrovače si vyměňují informace a každý má vlastní tabulku", - "Jedno centrum řídí všechny cesty", "Směrovač nezná žádné sousedy", - "Pakety jdou jen přes hub"}, 4, 0}, - {"Metrika ve směrovací tabulce:", - {"Číselně hodnotí cestu – nižší je lepší", - "Je vždy jen MAC adresa", "Nemá vliv na výběr trasy", - "Nahrazuje next hop"}, 4, 0}, - {"Distance Vector typicky:", - {"Posílá sousedům kopie tabulek a šíří informace krok za krokem", - "Počítá cesty jen v jednom centru", "Ignoruje přímé sousedy", - "Pracuje jen na aplikační vrstvě"}, 4, 0}, -}; - -const char *net19_hints[] = { - "Směrování běží na síťové (3.) vrstvě ISO/OSI", - "Adaptivní algoritmy reagují na změny a sdílí stav sítě", - "Statické cesty nastaví správce a samy se nemění", - "Centralizované směrování padá s výpadkem centra", - "Distribuované: výměna informací a vlastní tabulky", - "Nižší metrika = lepší / rychlejší trasa", - "Distance Vector: výměna tabulek se sousedy (např. každých 30 s)", -}; - -GtkWidget *build_net_unit19_exercise_page(void) { - return build_net_mcq_page(18, "netunit19", "net_ex19_title", "net_quiz19_head", - net19_qs, net19_hints, - (int)G_N_ELEMENTS(net19_qs)); -} - -const ChoiceQ net20_qs[] = { - {"Směrovač (router) pracuje na vrstvě:", - {"Fyzické", "Síťové (3.)", "Jen aplikační", "Jen prezentační"}, 4, 1}, - {"Router mimo jiné umožňuje:", - {"Segmentaci na podsítě a přístup na WAN", "Jen lámání optiky", - "Jen Aloha bez IP", "Jen cut-through bez MAC"}, 4, 0}, - {"Firewall na routeru dokáže:", - {"Filtrovat pakety a řídit služby", "Jen zesílit bitový signál", - "Jen uložit CAM bez IP", "Jen nahradit fotodiodu"}, 4, 0}, - {"Multiprotokolový router:", - {"Propojí sítě různých protokolů/standardů", "Umí jen jeden protokol", - "Nepracuje s IP adresou", "Nikdy nekonvertuje rámce"}, 4, 0}, - {"Router rozděluje síť na:", - {"Broadcastové domény", "Jen fyzické kabely bez domén", - "Jen aplikační servery", "Jen Token Ring bez Ethernetu"}, 4, 0}, - {"Brána (gateway) typicky:", - {"Připojuje LAN na odlišné prostředí (mainframe, GSM, WAN)", - "Pracuje jen jako hub", "Nikdy nemá software", - "Funguje jen na fyzické vrstvě"}, 4, 0}, - {"Poznámka k pojmu brána:", - {"Někdy se jí myslí spíše router / LAN–WAN připojení", - "Vždy znamená jen fotodiodu", "Nikdy nesouvisí s internetem", - "Nahrazuje jen lámačku vláken"}, 4, 0}, -}; - -const char *net20_hints[] = { - "Router pracuje na síťové (3.) vrstvě", - "Router segmentuje podsítě a zajišťuje WAN přístup", - "Firewall filtruje pakety a služby", - "Multiprotokolový router spojuje různé protokoly/standardy", - "Router dělí síť na broadcastové domény", - "Gateway připojuje LAN na odlišné prostředí", - "Pojem brána někdy označuje router nebo LAN–WAN připojení", -}; - -GtkWidget *build_net_unit20_exercise_page(void) { - return build_net_mcq_page(19, "netunit20", "net_ex20_title", "net_quiz20_head", - net20_qs, net20_hints, - (int)G_N_ELEMENTS(net20_qs)); -} - -const ChoiceQ net21_qs[] = { - {"Ethernetová adresa má:", - {"48 bitů (6 bytů) a je jedinečná", "Jen 16 bitů", "Jen 32 bitů IP", - "Jen 8 bitů SAP"}, 4, 0}, - {"První 3 byty MAC adresy přiděluje:", - {"IEEE výrobci", "Jen uživatel v BIOS", "Jen DNS server", - "Jen Aloha"}, 4, 0}, - {"Ethernet II v hlavičce používá:", - {"EtherType (např. IP = 0800h, hodnota > 1500)", - "Jen délku ≤ 1500 bez typu", "Jen FFFFh bez adres", - "Jen AAAAh bez MAC"}, 4, 0}, - {"IEEE 802.3 místo EtherType má:", - {"Údaj o délce (≤ 1500) a uvnitř 802.2", "Jen cut-through", - "Jen 64 B MTU bez délky", "Jen laserovou hlavičku"}, 4, 0}, - {"Raw 802.3 (Novell):", - {"Bez 802.2, jen IPX, začíná FFFFh", "Funguje jen s HTTP", - "Má vždy EtherType 0800h", "Nemá žádné adresy"}, 4, 0}, - {"Maximální rámec Ethernet II je:", - {"1518 B (1500 + 18)", "64 B", "900 µm", "250 µm"}, 4, 0}, - {"Minimální velikost rámce plyne z:", - {"Kolizního okénka (64 B)", "Jen z MTU routeru", "Jen z SNAP AAAAh", - "Jen z Token Ring"}, 4, 0}, -}; - -const char *net21_hints[] = { - "MAC adresa Ethernetu má 48 bitů a je unikátní", - "IEEE přidělí výrobci první 3 byty adresy", - "Ethernet II: EtherType > 1500 (IP = 0800h)", - "IEEE 802.3: délka ≤ 1500 a rámec 802.2", - "Raw 802.3: Novell/IPX, začíná FFFFh", - "Max. Ethernet II = 1518 B", - "Min. rámec 64 B kvůli koliznímu okénku", -}; - -GtkWidget *build_net_unit21_exercise_page(void) { - return build_net_mcq_page(20, "netunit21", "net_ex21_title", "net_quiz21_head", - net21_qs, net21_hints, - (int)G_N_ELEMENTS(net21_qs)); -} - -const ChoiceQ net22_qs[] = { - {"IP protokol je:", - {"Nespojovaný a nespolehlivý přenos datagramů", - "Spolehlivý a spojovaný jako TCP", "Jen fyzické kódování", - "Jen EtherType bez IP"}, 4, 0}, - {"Routing u IP znamená:", - {"Rozhodnutí o dalším směru datagramu", "Jen CRC na lince", - "Jen MAC učení ve switchi", "Jen lámání vlákna"}, 4, 0}, - {"Forwarding u IP znamená:", - {"Vložení do linkového rámce a odeslání", "Jen výpočet metriky OSPF", - "Jen DNS překlad", "Jen Aloha"}, 4, 0}, - {"HLEN (LENGTH) s hodnotou 5 znamená:", - {"Hlavičku dlouhou 20 B", "TTL 5", "PROTOCOL = 5", "MTU 5"}, 4, 0}, - {"TTL v IP hlavičce:", - {"Počítá průchody směrovači a brání zacyklení", - "Udává EtherType", "Nahrazuje MAC adresu", - "Je vždy 1500"}, 4, 0}, - {"Číslo protokolu 6 v IP hlavičce znamená:", - {"TCP", "UDP", "ICMP", "OSPF"}, 4, 0}, - {"Číslo protokolu 17 znamená:", - {"UDP", "TCP", "IGMP", "ARP"}, 4, 0}, - {"Ethernet MTU je typicky:", - {"1500 B", "64 kB", "576 B bez dat", "20 B hlavičky"}, 4, 0}, -}; - -const char *net22_hints[] = { - "IP je nespojovaný a nespolehlivý", - "Routing = rozhodnutí o směru datagramu", - "Forwarding = vložení do rámce a odeslání", - "HLEN 5 = 5 × 4 B = 20 B hlavičky", - "TTL snižují směrovače proti zacyklení", - "PROTOCOL 6 = TCP", - "PROTOCOL 17 = UDP", - "Ethernet MTU = 1500 B", -}; - -GtkWidget *build_net_unit22_exercise_page(void) { - return build_net_mcq_page(21, "netunit22", "net_ex22_title", "net_quiz22_head", - net22_qs, net22_hints, - (int)G_N_ELEMENTS(net22_qs)); -} - -const ChoiceQ net23_qs[] = { - {"ICMP slouží především k:", - {"Zasílání informací o chybách a stavu přenosu", - "Jen směrování OSPF tabulek", "Jen lámání optiky", - "Jen EtherType 0800h"}, 4, 0}, - {"ICMP paket se přenáší:", - {"Přímo v IP datagramu", "Jen jako Ethernet II bez IP", - "Jen v UDP bez IP", "Jen jako MAC bez datagramu"}, 4, 0}, - {"Source Quench znamená:", - {"Varování před zahlcením – zpomal odesílání", - "TTL kleslo na 0", "Cíl je nedostupný", "Echo Reply"}, 4, 0}, - {"Time Exceeded nastane, když:", - {"TTL v IP hlavičce klesne na 0", "Router nemá firewall", - "Použijeme jen SNAP", "MTU je 1500"}, 4, 0}, - {"Echo Request / Reply využívá příkaz:", - {"ping", "lámačka", "cut-through", "hub"}, 4, 0}, - {"Traceroute zjišťuje cestu tak, že:", - {"Postupně zvyšuje TTL a čeká na Time Exceeded", - "Posílá jen ARP bez IP", "Ignoruje směrovače", - "Používá jen CAM tabulku"}, 4, 0}, -}; - -const char *net23_hints[] = { - "ICMP posílá informace o chybách a stavu přenosu", - "ICMP jede uvnitř IP datagramu", - "Source Quench = zpomal odesílání kvůli zahlcení", - "Time Exceeded = TTL kleslo na 0", - "Echo Request/Reply = ping", - "Traceroute zvyšuje TTL a čte Time Exceeded", -}; - -GtkWidget *build_net_unit23_exercise_page(void) { - return build_net_mcq_page(22, "netunit23", "net_ex23_title", "net_quiz23_head", - net23_qs, net23_hints, - (int)G_N_ELEMENTS(net23_qs)); -} - -const ChoiceQ net24_qs[] = { - {"ARP převádí:", - {"IP adresu na MAC adresu", "MAC adresu na IP adresu", - "TCP na UDP", "TTL na MTU"}, 4, 0}, - {"RARP převádí:", - {"MAC adresu na IP adresu", "IP adresu na MAC adresu", - "EtherType na SAP", "OSPF na RIP"}, 4, 0}, - {"Nejčastější způsob ARP je:", - {"Dotaz a odpověď v síti", "Jen ruční tabulka bez sítě", - "Jen cut-through", "Jen ICMP Echo"}, 4, 0}, - {"ARP dotaz v Ethernetu používá:", - {"Broadcast", "Jen unicast bez broadcastu", "Jen laser", - "Jen Token Ring bez IP"}, 4, 0}, - {"ARP odpověď typicky přichází jako:", - {"Unicast s MAC adresou uzlu", "Broadcast bez MAC", - "Jen Time Exceeded", "Jen Source Quench"}, 4, 0}, - {"ARP cache slouží k tomu, aby:", - {"Se nemusely stále opakovat stejné dotazy", - "Se nahradil směrovač", "Se zrušila IP adresa", - "Se vypnul Ethernet"}, 4, 0}, -}; - -const char *net24_hints[] = { - "ARP: IP → MAC", - "RARP: MAC → IP", - "Nejčastější je dynamický dotaz a odpověď", - "ARP dotaz jde broadcastem", - "ARP odpověď je unicast s MAC", - "ARP cache ukládá výsledky dočasně (arp -a)", -}; - -GtkWidget *build_net_unit24_exercise_page(void) { - return build_net_mcq_page(23, "netunit24", "net_ex24_title", "net_quiz24_head", - net24_qs, net24_hints, - (int)G_N_ELEMENTS(net24_qs)); -} - -const ChoiceQ net25_qs[] = { - {"TCP je:", - {"Spolehlivý a spojovaný", "Nespolehlivý a nespojovaný", - "Jen fyzická vrstva", "Jen ARP cache"}, 4, 0}, - {"UDP je:", - {"Nespolehlivý a nespojovaný s malou režií", - "Spolehlivý se třícestným handshake", "Jen store-and-forward", - "Jen ICMP Time Exceeded"}, 4, 0}, - {"Porty slouží k:", - {"Rozlišení aplikací na jednom uzlu", "Jen směrování IP", - "Jen MAC učení", "Jen lámání vlákna"}, 4, 0}, - {"Navázání TCP spojení používá:", - {"Třícestné podání ruky (three-way handshake)", - "Jen broadcast ARP", "Jen Source Quench", "Jen cut-through"}, 4, 0}, - {"Hlavička TCP má typicky:", - {"20 B (UDP 8 B)", "8 B (UDP 20 B)", "1500 B", "64 B min. rámec"}, 4, 0}, - {"TCP není vhodný pro real-time média hlavně proto, že:", - {"Ztráta segmentu zastaví proud a čeká se na znovudoručení", - "Nemá žádné porty", "Nepodporuje unicast", - "Nemá hlavičku"}, 4, 0}, - {"SCTP oproti TCP nabízí:", - {"Multihoming a multistreaming", "Jen Ethernet II", - "Jen RARP", "Jen hub flooding"}, 4, 0}, -}; - -const char *net25_hints[] = { - "TCP = spolehlivý a spojovaný", - "UDP = nespolehlivý, nespojovaný, malá režie", - "Porty rozlišují aplikace na uzlu", - "TCP se navazuje three-way handshake", - "TCP hlavička 20 B, UDP 8 B", - "TCP čeká na znovudoručení – špatné pro real-time", - "SCTP: multihoming a multistreaming", -}; - -GtkWidget *build_net_unit25_exercise_page(void) { - return build_net_mcq_page(24, "netunit25", "net_ex25_title", "net_quiz25_head", - net25_qs, net25_hints, - (int)G_N_ELEMENTS(net25_qs)); -} - -const ChoiceQ net26_qs[] = { - {"Aplikační protokoly typicky posílají data přes:", - {"TCP nebo UDP", "Jen fyzickou vrstvu", "Jen ARP", - "Jen CAM tabulku"}, 4, 0}, - {"Dva běžící procesy:", - {"Nesmí používat stejný port", "Musí sdílet jeden port", - "Nesmí mít žádný port", "Používají jen MAC"}, 4, 0}, - {"Well-known porty mají rozsah:", - {"0–1023", "1024–49151", "49152–65535", "Jen 80–443"}, 4, 0}, - {"Dynamické (privátní) porty jsou:", - {"49152–65535", "0–1023", "Jen 20–21", "Jen 3306"}, 4, 0}, - {"Aplikační spojení určuje:", - {"Pětice (transport, IP1, port1, IP2, port2)", - "Jen MAC adresa", "Jen název souboru", "Jen VLAN ID"}, 4, 0}, - {"HTTP a HTTPS používají porty:", - {"80 a 443", "22 a 23", "25 a 110", "53 a 67"}, 4, 0}, - {"SSH a DNS mají porty:", - {"22 a 53", "80 a 443", "3389 a 5900", "20 a 21"}, 4, 0}, - {"MySQL a RDP jsou typicky na portech:", - {"3306 a 3389", "80 a 443", "67 a 68", "161 a 162"}, 4, 0}, -}; - -const char *net26_hints[] = { - "Aplikace posílají data přes TCP/UDP", - "Dva procesy nesmí sdílet stejný port", - "Well-known: 0–1023 (IANA)", - "Dynamické porty: 49152–65535", - "Spojení = pětice hodnot", - "HTTP 80, HTTPS 443", - "SSH 22, DNS 53", - "MySQL 3306, RDP 3389", -}; - -GtkWidget *build_net_unit26_exercise_page(void) { - return build_net_mcq_page(25, "netunit26", "net_ex26_title", "net_quiz26_head", - net26_qs, net26_hints, - (int)G_N_ELEMENTS(net26_qs)); -} - -const ChoiceQ net27_qs[] = { - {"Geostacionární družice létají asi:", - {"36 000 km nad Zemí", "16 km v troposféře", "50 km nad povrchem", - "Jen v nízké orbitě LEO"}, 4, 0}, - {"Hlavní nevýhoda družicového spoje je:", - {"Velké zpoždění (~250–300 ms)", "Žádný broadcast", - "Jen kabelové médium", "Absence portů"}, 4, 0}, - {"V síti VSAT komunikace probíhá:", - {"Jen mezi terminálem a hubem", "Přímo mezi dvěma terminály", - "Jen přes ARP", "Jen přes WEP"}, 4, 0}, - {"Mikrovlnný spoj typicky vyžaduje:", - {"Přímou viditelnost (dosah ~50 km)", "Jen metalický kabel", - "Jen port 80", "Jen WEP klíč"}, 4, 0}, - {"V infrastruktuře Wi-Fi stanice (STA):", - {"Komunikují přes AP, ne přímo mezi sebou", - "Vždy jen ad-hoc bez AP", "Nepoužívají ESSID", - "Běží jen na 36 000 km"}, 4, 0}, - {"802.11ax (Wi-Fi 6) přináší zejména:", - {"OFDMA a vysokou kapacitu", "Jen WEP", "Jen C-band 4/6 GHz", - "Jen troposférický odraz"}, 4, 0}, - {"WEP je dnes:", - {"Prolomený a nevhodný", "Nejbezpečnější volba", - "Totéž co WPA3-SAE", "Povinný od roku 2006"}, 4, 0}, - {"Doporučené zabezpečení Wi-Fi je:", - {"WPA2/WPA3 s AES (ne WEP)", "Jen Open system WEP", - "Jen Shared key WEP", "Bez hesla vždy"}, 4, 0}, -}; - -const char *net27_hints[] = { - "Geostacionární družice ~36 000 km", - "Družice: zpoždění stovky ms", - "VSAT: jen terminál ↔ hub", - "Mikrovlny: přímá viditelnost ~50 km", - "STA komunikují přes AP", - "Wi-Fi 6 (ax): OFDMA", - "WEP prolomen – nepoužívat", - "Používej WPA2/WPA3 + AES", -}; - -GtkWidget *build_net_unit27_exercise_page(void) { - return build_net_mcq_page(26, "netunit27", "net_ex27_title", "net_quiz27_head", - net27_qs, net27_hints, - (int)G_N_ELEMENTS(net27_qs)); -} - diff --git a/src/obcanka.c b/src/obcanka.c deleted file mode 100644 index 1facaa1..0000000 --- a/src/obcanka.c +++ /dev/null @@ -1,2116 +0,0 @@ -#include "graduately.h" - -/* Year 1 of Občanská nauka. - * Thematic unit "Člověk v lidském společenství" from the SOV framework - * (společenskovědní vzdělávání) and the MŠMT model syllabus, which schools - * place in the first year. Years 2, 3 and 4 are open. */ - -#define ON_ENTRY(n) \ - { .n_slides = 2, .unit_page = "onunit" #n, .ex_page = "onex" #n } - -NetLesson on_lessons[ON_LESSONS] = { - ON_ENTRY(1), ON_ENTRY(2), ON_ENTRY(3), ON_ENTRY(4), - ON_ENTRY(5), ON_ENTRY(6), ON_ENTRY(7), ON_ENTRY(8), - ON_ENTRY(9), ON_ENTRY(10), ON_ENTRY(11), ON_ENTRY(12), - ON_ENTRY(13), ON_ENTRY(14), ON_ENTRY(15), ON_ENTRY(16), - ON_ENTRY(17), -}; - -#undef ON_ENTRY - -GtkWidget *on_scroll; -GtkWidget *on_fixed; -GtkWidget *on_rail; -GtkWidget *on_nodes[ON_UNITS]; -GtkWidget *on_labels[ON_UNITS]; -double on_cx[ON_UNITS]; -double on_cy[ON_UNITS]; -int on_cols = 1; -int on_rows = 1; -int on_cw = (int)(2.0 * ROAD_MX + (ON_UNITS - 1) * PATH_SPAC); -int on_ch = (int)(2.0 * ROAD_MY); -guint on_idle; -double on_last_avail = -1.0; -int on_last_cols = -1; -int on_last_rows = -1; -int on_last_cw = -1; -int on_last_ch = -1; -cairo_surface_t *on_rail_cache; -int on_cache_w; -int on_cache_h; - -static void on_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= ON_UNITS - 1) { k = ON_UNITS - 2; u = 1.0; } - - p1x = on_cx[k]; p1y = on_cy[k]; - p2x = on_cx[k + 1]; p2y = on_cy[k + 1]; - if (k - 1 >= 0) { p0x = on_cx[k - 1]; p0y = on_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < ON_UNITS) { p3x = on_cx[k + 2]; p3y = on_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -static void on_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 24.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - on_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - on_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -static void on_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(ON_UNITS - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= ON_UNITS; rows++) { - int cols = (ON_UNITS + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > ON_UNITS) - rows = ON_UNITS; - on_rows = rows; - on_cols = (ON_UNITS + rows - 1) / rows; - if (on_cols < 1) - on_cols = 1; - on_cw = (int)(2.0 * ROAD_MX + (on_cols - 1) * PATH_SPAC); - on_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * on_cols; - int len = MIN(on_cols, ON_UNITS - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (on_cols - 1 - c); - on_cx[i] = ROAD_MX + cc * PATH_SPAC; - on_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -static void on_apply_layout(void) { - if (!on_fixed) - return; - - if (on_cols == on_last_cols && on_rows == on_last_rows && - on_cw == on_last_cw && on_ch == on_last_ch) - return; - - on_last_cols = on_cols; - on_last_rows = on_rows; - on_last_cw = on_cw; - on_last_ch = on_ch; - if (on_rail_cache) { - cairo_surface_destroy(on_rail_cache); - on_rail_cache = NULL; - } - - for (int i = 0; i < ON_UNITS; i++) { - if (!on_nodes[i] || !on_labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(on_fixed), on_nodes[i], - (int)(on_cx[i] - NODE_SIZE / 2.0), - (int)(on_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(on_fixed), on_labels[i], - (int)(on_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(on_cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(on_fixed, on_cw, on_ch); - gtk_widget_set_size_request(on_rail, on_cw, on_ch); - gtk_fixed_move(GTK_FIXED(on_fixed), on_rail, 0, 0); - gtk_widget_queue_draw(on_rail); -} - -static void on_relayout(void) { - GtkAdjustment *hadj; - double avail; - - if (!on_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(on_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - on_last_avail) < 1.0) - return; - on_last_avail = avail; - on_geometry(avail); - on_apply_layout(); -} - -static gboolean on_relayout_idle(gpointer data) { - (void)data; - on_idle = 0; - on_relayout(); - return G_SOURCE_REMOVE; -} - -static void on_relayout_later(void) { - if (on_idle == 0) - on_idle = g_idle_add(on_relayout_idle, NULL); -} - -static void on_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - (void)data; - on_relayout_later(); -} - -static void on_render_rail_to(cairo_t *cr) { - const double t_end = (double)(ON_UNITS - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - on_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - on_path(cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -static void on_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - (void)area; - (void)width; - (void)height; - (void)data; - - if (!on_rail_cache || on_cache_w != on_cw || on_cache_h != on_ch) { - cairo_t *rcr; - - if (on_rail_cache) - cairo_surface_destroy(on_rail_cache); - on_cache_w = on_cw; - on_cache_h = on_ch; - if (on_cache_w < 1) - on_cache_w = 1; - if (on_cache_h < 1) - on_cache_h = 1; - on_rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - on_cache_w, on_cache_h); - rcr = cairo_create(on_rail_cache); - on_render_rail_to(rcr); - cairo_destroy(rcr); - } - - cairo_set_source_surface(cr, on_rail_cache, 0, 0); - cairo_paint(cr); -} - -void on_rail_theme_reset(void) { - if (on_rail_cache) { - cairo_surface_destroy(on_rail_cache); - on_rail_cache = NULL; - } - if (on_rail) - gtk_widget_queue_draw(on_rail); -} - -static void on_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof(name), "on_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static void on_add_node(GtkFixed *fixed, int index) { - int num = index + 1; - gboolean locked = index >= ON_LESSONS; - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - static char unit_keys[ON_LESSONS][16]; - static gboolean unit_keys_ready = FALSE; - - if (!unit_keys_ready) { - for (int i = 0; i < ON_LESSONS; i++) - g_snprintf(unit_keys[i], sizeof unit_keys[i], "on_unit%d", i + 1); - unit_keys_ready = TRUE; - } - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_sensitive(card, !locked); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - if (locked) - gtk_widget_add_css_class(card, "locked"); - else - gtk_widget_add_css_class(card, "current"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", num); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - if (locked) { - icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 16); - gtk_box_append(GTK_BOX(vbox), icon); - } else { - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - on_lessons[index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(on_open_unit), - &on_lessons[index]); - } - - on_nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - if (index < ON_LESSONS) { - i18n_bind(name, unit_keys[index], 0); - } else { - gtk_widget_add_css_class(name, "unit-name-locked"); - } - on_labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} - -static GtkWidget *on_year_button(int year, const char *target) { - static const char *year_keys[] = { - "on_year1", "on_year2", "on_year3", "on_year4", - }; - gboolean locked = target == NULL; - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 72); - gtk_widget_set_sensitive(btn, !locked); - if (locked) - gtk_widget_add_css_class(btn, "locked"); - else - gtk_widget_add_css_class(btn, "current"); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", year); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, year_keys[year - 1], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - if (locked) { - GtkWidget *sub = gtk_label_new(NULL); - GtkWidget *icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, - 0.4392, 18); - - i18n_bind(sub, "on_year_locked_sub", 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_widget_add_css_class(sub, "unit-name-locked"); - gtk_box_append(GTK_BOX(texts), sub); - gtk_widget_set_valign(icon, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), icon); - } else { - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - } - - return btn; -} - -GtkWidget *build_onyears_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - int y; - static const char *targets[] = {"onmap", "on2map", "on3map", "on4map"}; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "Občanská nauka", "on_years_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 360, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (y = 1; y <= 4; y++) - gtk_box_append(GTK_BOX(list), on_year_button(y, targets[y - 1])); - - return page; -} - -GtkWidget *build_onmap_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - - on_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("onyears", "on_year1", "on_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - on_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, on_cw, on_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - on_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, on_cw, on_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), on_draw_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - on_rail = rail; - - for (int i = 0; i < ON_UNITS; i++) - on_add_node(GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(on_adjust_notify), NULL); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(on_adjust_notify), NULL); - - on_apply_layout(); - on_relayout_later(); - refresh_on_completion_ui(); - - return page; -} - -static void on_slide_apply(NetLesson *L); -static void on_slide_prev(GtkButton *button, gpointer data); -static void on_slide_next(GtkButton *button, gpointer data); - -static int on_note_last_w = -1; - -static void on_rescale_notes_at(int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < ON_LESSONS; i++) - net_rescale_lesson_notes(&on_lessons[i], body, head, kick); -} - -static gboolean on_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width != on_note_last_w) { - on_note_last_w = width; - on_rescale_notes_at(width); - } - return G_SOURCE_CONTINUE; -} - -static GtkWidget *build_on_unit_page(NetLesson *L, const char *title_key, - const char *sub_key, - const NetSlide *slides, guint n_slides) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar("onmap", title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "on_slide%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, on_note_tick, NULL, NULL); - on_note_last_w = -1; - on_rescale_notes_at(0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(on_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(on_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - on_slide_apply(L); - return page; -} - -static void on_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "on_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void on_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx > 0) { - L->idx--; - on_slide_apply(L); - } -} - -static void on_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - on_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -void on_lessons_apply_lang(void) { - for (int i = 0; i < ON_LESSONS; i++) - on_slide_apply(&on_lessons[i]); -} - -static void on_mcq_check(GtkButton *button, gpointer data) { - NetMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_on_done(ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -static GtkWidget *build_on_mcq_page(int lesson_id, const char *back_page, - const char *title_key, - const char *heading_key, - const ChoiceQ *qs, const char **hints, - int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - NetMcqCtx *ctx = g_new0(NetMcqCtx, 1); - int n_opts = qs[0].n_options; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(on_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - - return page; -} - -static GtkWidget *build_on_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Smysl", "Proč se učíme občanskou nauku", - "Tip: občanem se člověk stává jednáním, ne jen dokladem.", - { - "Předmět připravuje na aktivní a odpovědný život v demokratické společnosti.", - "Směřuje k tomu, aby člověk jednal slušně a nejen pro vlastní prospěch.", - "Učí kriticky myslet, nenechat se manipulovat a rozumět světu kolem sebe.", - "Navazuje na občanskou výchovu ze základní školy a prohlubuje ji.", - NULL, - }, - }, - { - "2 / 2 • Ročník", "Co patří do prvního ročníku", - "Tip: název celku je Člověk v lidském společenství.", - { - "První ročník bere osobnost, učení, vztahy, zdraví a sociální skupiny.", - "Patří sem i společnost, kultura, soužití lidí a náboženství.", - "Součástí je i hospodaření domácnosti a sociální zajištění.", - "Politický systém, právo a filozofie přicházejí v dalších ročnících.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[0], "on_unit1", "on_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaký je hlavní cíl občanské nauky?", - { - "Naučit se nazpaměť všechny zákony", - "Připravit na odpovědný život v demokratické společnosti", - "Nahradit dějepis", - "Naučit účetnictví firmy", - }, - 4, 1}, - {"Na co výuka navazuje?", - { - "Jen na odborný výcvik", - "Na občanskou výchovu ze základní školy", - "Jen na matematiku", - "Na tělesnou výchovu", - }, - 4, 1}, - {"Který tematický celek patří do 1. ročníku?", - { - "Člověk a trestní právo", - "Člověk v lidském společenství", - "Dějiny filozofie", - "Hospodářská politika státu", - }, - 4, 1}, - {"Co má žák díky předmětu umět?", - { - "Kriticky myslet a nenechat se manipulovat", - "Ignorovat názory druhých", - "Řídit se jen vlastní výhodou", - "Vyhýbat se každé diskusi", - }, - 4, 0}, - }; - static const char *hints[] = { - "Cíl je odpovědný život v demokracii", - "Navazuje na občanskou výchovu ze ZŠ", - "1. ročník = Člověk v lidském společenství", - "Kritické myšlení je součást předmětu", - }; - return build_on_mcq_page(0, "onunit1", "on_ex1_title", - "on_quiz1_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Učení", "Celoživotní vzdělávání", - "Tip: škola je začátek učení, ne jeho konec.", - { - "Vzdělání nekončí maturitou. Člověk se učí celý život.", - "Učení pomáhá zvládat změny v práci i v osobním životě.", - "Patří sem škola, samostudium i zkušenost z praxe.", - "Smyslem je rozumět světu a umět se rozhodovat.", - NULL, - }, - }, - { - "2 / 2 • Čas", "Volný čas", - "Tip: odpočinek je součást učení, ne jeho opak.", - { - "Volný čas je prostor po povinnostech, ne jen nicnedělání.", - "Dá se využít k odpočinku, koníčkům, vztahům i dalšímu učení.", - "Pasivní konzumace, třeba nekonečné scrollování, volný čas spíš spolkne.", - "Střídání učení a odpočinku chrání soustředění.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[1], "on_unit2", "on_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co znamená celoživotní vzdělávání?", - { - "Že se člověk učí i po škole", - "Že maturita stačí navždy", - "Že se učí jen ve škole", - "Že se učí až v důchodu", - }, - 4, 0}, - {"Co je volný čas?", - { - "Čas po splnění povinností", - "Jen hodiny tělocviku", - "Čas, kdy se nesmí odpočívat", - "Povinná brigáda", - }, - 4, 0}, - {"Proč nestačí trávit volný čas jen pasivně u obrazovky?", - { - "Odpočinek a vlastní aktivita tím mizí", - "Zákon to vždycky zakazuje", - "Obrazovka ruší elektřinu v domě", - "Člověk se tím automaticky naučí jazyk", - }, - 4, 0}, - {"Jak spolu souvisí učení a odpočinek?", - { - "Odpočinek učení vždycky kazí", - "Střídání učení a odpočinku pomáhá soustředění", - "Učit se má člověk jen v noci", - "Odpočinek patří jen do prázdnin", - }, - 4, 1}, - }; - static const char *hints[] = { - "Učení pokračuje i po škole", - "Volný čas je po povinnostech", - "Pasivní konzumace volný čas spolkne", - "Odpočinek soustředění podporuje", - }; - return build_on_mcq_page(1, "onunit2", "on_ex2_title", - "on_quiz2_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Složky", "Z čeho se osobnost skládá", - "Tip: osobnost není hotová nálepka, vyvíjí se.", - { - "Osobnost má tělesnou i duševní stránku a obě se ovlivňují.", - "Patří sem temperament, charakter, schopnosti a motivace.", - "Temperament je spíš vrozený styl reagování, charakter se utváří.", - "Schopnosti se dají cvičit a motivace dává jednání směr.", - NULL, - }, - }, - { - "2 / 2 • Druzí", "Socializace a empatie", - "Tip: empatie znamená představit si, jaké to je být na místě druhého.", - { - "Socializace je proces, kterým se člověk stává členem společnosti.", - "Učí se v rodině, ve škole, mezi vrstevníky i z médií.", - "Sebepoznání pomáhá jednat s druhými s empatií.", - "Porozumění sobě je základ slušného jednání s ostatními.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[2], "on_unit3", "on_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je temperament?", - { - "Naučený seznam pravidel", - "Spíše vrozený styl reagování", - "Školní známka", - "Druh povolání", - }, - 4, 1}, - {"Co je socializace?", - { - "Proces, kterým se člověk začleňuje do společnosti", - "Pouze lékařské vyšetření", - "Stěhování do jiného státu", - "Trest za přestupek", - }, - 4, 0}, - {"Čím se charakter liší od temperamentu?", - { - "Charakter se utváří, temperament je spíš vrozený", - "Jsou to přesná synonyma", - "Charakter je jen barva vlasů", - "Temperament se nedá nijak popsat", - }, - 4, 0}, - {"K čemu je empatie?", - { - "Aby člověk druhého přehlížel", - "Aby si dovedl představit situaci druhého", - "Aby vyhrál každou hádku", - "Aby se vyhnul všem vztahům", - }, - 4, 1}, - }; - static const char *hints[] = { - "Temperament je spíš vrozený styl", - "Socializace = začlenění do společnosti", - "Charakter se utváří", - "Empatie je pohled očima druhého", - }; - return build_on_mcq_page(2, "onunit3", "on_ex3_title", - "on_quiz3_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Etapy", "Od dětství ke stáří", - "Tip: etapy se překrývají, nejsou to ostré čáry.", - { - "Život má etapy: dětství, dospívání, dospělost a stáří.", - "Každá etapa má typické úkoly i možnosti.", - "Dospívání je čas hledání identity a větší samostatnosti.", - "Stáří není jen úbytek sil, přináší i zkušenost.", - NULL, - }, - }, - { - "2 / 2 • Generace", "Mezigenerační vztahy", - "Tip: respekt platí z obou stran, ne jen směrem nahoru.", - { - "Generace se navzájem potřebují, i když mají jiné zkušenosti.", - "Děti a rodiče mají vůči sobě práva i povinnosti.", - "Respekt ke starším neznamená vzdát se vlastního názoru.", - "Náročné situace, třeba nemoc nebo ztráta, se v rodině řeší společně.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[3], "on_unit4", "on_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Která etapa je typická hledáním identity?", - { - "Kojenecké období", - "Dospívání", - "Jen stáří", - "Jen předškolní věk", - }, - 4, 1}, - {"Co platí o mezigeneračních vztazích?", - { - "Mladší a starší se nepotřebují", - "Generace se mohou doplňovat zkušeností", - "Respekt znamená nemít vlastní názor", - "Povinnosti mají jen děti", - }, - 4, 1}, - {"Jak chápat etapy života?", - { - "Jako pevné přihrádky beze změn", - "Jako období s typickými úkoly, která se mohou překrývat", - "Jako trest", - "Jako jen školní ročníky", - }, - 4, 1}, - {"Co stáří přináší vedle omezení?", - { - "Jen samé ztráty", - "Zkušenost a často i nadhled", - "Povinnost odejít ze společnosti", - "Konec všech vztahů", - }, - 4, 1}, - }; - static const char *hints[] = { - "Identita se hledá hlavně v dospívání", - "Generace se doplňují", - "Etapy se překrývají", - "Stáří nese i zkušenost", - }; - return build_on_mcq_page(3, "onunit4", "on_ex4_title", - "on_quiz4_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Zátěž", "Náročné životní situace", - "Tip: říct si o pomoc není ostuda.", - { - "Patří sem stres, konflikt, nemoc, ztráta nebo velká změna.", - "Krátký stres může pomoct podat výkon, dlouhý škodí.", - "Není slabost přiznat, že situace přerůstá síly.", - "Pomoc se hledá u blízkých, ve škole i u odborníků.", - NULL, - }, - }, - { - "2 / 2 • Péče", "Psychohygiena", - "Tip: duševní zdraví je součást zdraví, ne luxus.", - { - "Psychohygiena je péče o duševní zdraví.", - "Patří sem spánek, pohyb, vztahy a umění říct ne.", - "Pomáhá režim dne a čas bez neustálých oznámení.", - "Když potíže trvají, je na místě odborná pomoc.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[4], "on_unit5", "on_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je psychohygiena?", - { - "Péče o duševní zdraví", - "Jen čištění zubů", - "Trest za stres", - "Druh diety", - }, - 4, 0}, - {"Kdy je v pořádku hledat pomoc?", - { - "Nikdy, člověk si má poradit sám", - "Když náročná situace přerůstá síly", - "Jen po dosažení plnoletosti", - "Jen když to nařídí soud", - }, - 4, 1}, - {"Co dlouhodobý stres dělá?", - { - "Vždycky zlepšuje zdraví", - "Může škodit tělu i psychice", - "Nemá žádný vliv", - "Nahrazuje spánek", - }, - 4, 1}, - {"Co do psychohygieny patří?", - { - "Spánek, pohyb a hranice", - "Jen energetické nápoje", - "Nevyspání před zkouškou", - "Izolace od všech lidí", - }, - 4, 0}, - }; - static const char *hints[] = { - "Psychohygiena = péče o duševní zdraví", - "Pomoc je na místě, když síly nestačí", - "Dlouhý stres škodí", - "Spánek, pohyb a hranice", - }; - return build_on_mcq_page(4, "onunit5", "on_ex5_title", - "on_quiz5_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Etiketa", "Pravidla slušného chování", - "Tip: slušnost se pozná tam, kde z ní nic nekápne.", - { - "Slušné chování je způsob, jak spolu lidé vycházejí bez ponižování.", - "Patří sem pozdrav, poděkování, omluva a dochvilnost.", - "Etiketa se liší situací: škola, úřad, divadlo nebo doprava.", - "Zdvořilost není slabost ani předstírání.", - NULL, - }, - }, - { - "2 / 2 • Vztahy", "Kvalita mezilidských vztahů", - "Tip: souhlas se dá kdykoli odvolat.", - { - "Vztahy potřebují respekt, důvěru a čas.", - "Patří sem rodina, přátelství i partnerský vztah.", - "Partnerský vztah stojí na souhlasu a respektu k hranicím.", - "Špatný vztah není povinnost vydržet za každou cenu.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[5], "on_unit6", "on_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je etiketa?", - { - "Seznam trestů", - "Zásady slušného chování v dané situaci", - "Jen oblečení na ples", - "Povinnost souhlasit s každým", - }, - 4, 1}, - {"Na čem stojí partnerský vztah?", - { - "Na nátlaku", - "Na respektu a souhlasu", - "Na tom, že jeden rozhoduje o všem", - "Na tajnostech před rodinou", - }, - 4, 1}, - {"Kdy se slušnost pozná nejlíp?", - { - "Když z ní člověk něco má", - "I tam, kde z ní nic nekápne", - "Jen před učitelem", - "Jen na internetu", - }, - 4, 1}, - {"Platí, že souhlas se dá vzít zpět?", - { - "Ne, jednou stačí navždy", - "Ano, souhlas se dá odvolat", - "Jen písemně u notáře", - "Jen se souhlasem skupiny", - }, - 4, 1}, - }; - static const char *hints[] = { - "Etiketa = slušné chování podle situace", - "Vztah stojí na respektu a souhlasu", - "Slušnost i tam, kde z ní nic není", - "Souhlas se dá odvolat", - }; - return build_on_mcq_page(5, "onunit6", "on_ex6_title", - "on_quiz6_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Řeč", "Verbální a neverbální komunikace", - "Tip: já-věta popisuje pocit, aniž by hned útočila.", - { - "Komunikace je verbální i neverbální: výraz, postoj a tón.", - "Aktivní naslouchání znamená opravdu slyšet, ne jen čekat na slovo.", - "Nedorozumění často vznikne z domněnky, ne ze zlého úmyslu.", - "V online textu chybí tón, proto zpráva snadno urazí.", - NULL, - }, - }, - { - "2 / 2 • Střet", "Řešení konfliktů", - "Tip: kompromis není prohra, když ho unesou obě strany.", - { - "Konflikt je střet zájmů nebo názorů, ne automaticky násilí.", - "Dá se řešit domluvou, kompromisem nebo pomocí třetí strany.", - "Vyhrát za každou cenu vztah často zničí.", - "Násilí, vydírání a ponižování nejsou řešení konfliktu.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[6], "on_unit7", "on_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je neverbální komunikace?", - { - "Jen psaný dopis", - "Výraz, postoj a tón", - "Pouze zákon", - "Školní řád", - }, - 4, 1}, - {"Co je konflikt?", - { - "Vždycky rvačka", - "Střet zájmů nebo názorů", - "Jen mezinárodní válka", - "Ticho", - }, - 4, 1}, - {"Proč online text snadno urazí?", - { - "Chybí v něm tón a výraz", - "Internet zakazuje slušnost", - "Písmo je vždycky ironické", - "Zprávy čte jen učitel", - }, - 4, 0}, - {"Co není řešení konfliktu?", - { - "Kompromis", - "Domluva", - "Násilí a ponižování", - "Pomoc třetí strany", - }, - 4, 2}, - }; - static const char *hints[] = { - "Neverbální = výraz, postoj, tón", - "Konflikt je střet, ne automaticky násilí", - "Bez tónu se text snáz urazí", - "Násilí konflikt neřeší", - }; - return build_on_mcq_page(6, "onunit7", "on_ex7_title", - "on_quiz7_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Zdraví", "Tělo i psychika", - "Tip: zdraví není jen nepřítomnost rýmy.", - { - "Zdraví je tělesná i duševní pohoda, nejen absence nemoci.", - "Ovlivňuje ho životní styl, vztahy i prostředí.", - "Člověk má odpovědnost za své návyky, ne za všechno, co ho postihne.", - "Prevence je spolehlivější než dohánět následky.", - NULL, - }, - }, - { - "2 / 2 • Návyky", "Životní styl", - "Tip: životní styl je souhrn návyků, ne jednorázové předsevzetí.", - { - "Patří sem spánek, pohyb, strava a vztahy.", - "Rizikový životní styl zdraví oslabuje postupně.", - "Odpočinek a režim dne jsou součást stylu, ne odměna na konci.", - "Když něco nejde, je v pořádku říct si o pomoc.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[7], "on_unit8", "on_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se ve škole bere zdraví?", - { - "Jen jako absence rýmy", - "Jako tělesná i duševní pohoda", - "Jen jako sportovní výkon", - "Jako školní předmět chemie", - }, - 4, 1}, - {"Co je životní styl?", - { - "Jedno předsevzetí na Nový rok", - "Souhrn návyků, kterými člověk žije", - "Jen jídelníček", - "Povinná dieta", - }, - 4, 1}, - {"K čemu je prevence?", - { - "Aby se následky doháněly později", - "Aby se problémům předcházelo", - "Aby se zrušila lékařská péče", - "Aby se k lékaři nechodilo nikdy", - }, - 4, 1}, - {"Platí, že za každou nemoc může jen vlastní styl?", - { - "Ano, vždy", - "Ne, styl zdraví ovlivňuje, ale ne všechno člověk ovlivní", - "Nemoc neexistuje", - "Styl s tím nesouvisí vůbec", - }, - 4, 1}, - }; - static const char *hints[] = { - "Zdraví je tělesné i duševní", - "Styl = souhrn návyků", - "Prevence předchází následkům", - "Styl ovlivňuje, ale neurčuje vše", - }; - return build_on_mcq_page(7, "onunit8", "on_ex8_title", - "on_quiz8_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit9_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Formy", "Co je závislost", - "Tip: závislost se týká i věcí, které nejsou zakázaná látka.", - { - "Závislost je nutkavá potřeba, která přebírá řízení života.", - "Patří sem alkohol, nikotin, jiné drogy, hazard i digitální závislost.", - "Nejde jen o slabou vůli. Mění se i odměňování v mozku.", - "Ohrožuje zdraví, vztahy, školu i peníze.", - NULL, - }, - }, - { - "2 / 2 • Pomoc", "Proč je to nebezpečné a kam se obrátit", - "Tip: první krok je pojmenovat problém, ne ho skrývat.", - { - "Pro společnost znamená závislost i náklady, násilí a zátěž rodin.", - "Prevence je informace, hranice a prostředí, kde se dá říct ne.", - "Pomoc nabízejí odborné služby, linky pomoci a školní poradenství.", - "Čím dřív se člověk ozve, tím snáz se závislost brzdí.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[8], "on_unit9", "on_unit9_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit9_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je závislost?", - { - "Občasná chuť", - "Nutkavá potřeba, která přebírá řízení života", - "Jen nelegální droga", - "Každý sportovní návyk", - }, - 4, 1}, - {"Které z uvedeného může být závislost?", - { - "Jen heroin", - "I hazard a nadužívání digitálních médií", - "Jedna káva denně", - "Čtení knih", - }, - 4, 1}, - {"Proč závislost není jen slabá vůle?", - { - "Zasahuje i odměňování v mozku", - "Protože vůle neexistuje", - "Protože ji způsobuje jen škola", - "Protože ji léčí trest", - }, - 4, 0}, - {"Kam se obrátit?", - { - "Nikam", - "Na odbornou pomoc, linku nebo školní poradenství", - "Na někoho, kdo látku taky bere a radí v tom pokračovat", - "Na náhodnou reklamu", - }, - 4, 1}, - }; - static const char *hints[] = { - "Závislost přebírá řízení života", - "I hazard a digitální nadužívání", - "Mění se odměňování v mozku", - "Pomoc je linka, odborník, škola", - }; - return build_on_mcq_page(8, "onunit9", "on_ex9_title", - "on_quiz9_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit10_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Skupiny", "Primární a sekundární skupiny", - "Tip: skupina člověka formuje, i když si to nepřizná.", - { - "Sociální skupina jsou lidé spojení vztahem a pravidly.", - "Primární skupiny, třeba rodina a blízcí přátelé, jsou osobní.", - "Sekundární, třeba třída, práce nebo spolek, jsou účelovější.", - "Člověk je zároveň členem více skupin.", - NULL, - }, - }, - { - "2 / 2 • Rodina", "Rodina a její funkce", - "Tip: důležitější než jedna šablona je, jestli rodina své funkce plní.", - { - "Rodina je základní sociální útvar a první místo socializace.", - "Má funkci citovou, výchovnou, ekonomickou i ochrannou.", - "Rodina nemusí mít jen jednu podobu, aby tyhle funkce plnila.", - "Práva a povinnosti mezi rodiči a dětmi nejsou jednosměrné.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[9], "on_unit10", "on_unit10_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit10_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je primární skupina?", - { - "Anonymní dav na koncertě", - "Blízká skupina, třeba rodina", - "Celý stát", - "Fronta v obchodě", - }, - 4, 1}, - {"Která funkce rodině patří?", - { - "Vydávat zákony", - "Citová a výchovná", - "Řídit armádu", - "Stanovit daně", - }, - 4, 1}, - {"Platí, že člověk patří jen do jedné skupiny?", - { - "Ano", - "Ne, je členem více skupin najednou", - "Patří jen do školy", - "Skupiny neexistují", - }, - 4, 1}, - {"Co je socializace v rodině?", - { - "První učení se životu mezi lidmi", - "Pouze dědické řízení", - "Stěhování", - "Školní test", - }, - 4, 0}, - }; - static const char *hints[] = { - "Rodina je typická primární skupina", - "Rodina má citovou a výchovnou funkci", - "Člověk je ve více skupinách", - "V rodině začíná socializace", - }; - return build_on_mcq_page(9, "onunit10", "on_ex10_title", - "on_quiz10_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit11_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Místo", "Komunita a sousedství", - "Tip: komunita není totéž co dav.", - { - "Komunita jsou lidé, které spojuje místo, zájem nebo sounáležitost.", - "Sousedství je každodenní soužití v místě, kde člověk žije.", - "Solidarita v komunitě pomáhá v krizi i v běžných věcech.", - "Ve velkém městě komunita být může, ale hůř se tvoří.", - NULL, - }, - }, - { - "2 / 2 • Dav", "Dav, publikum, populace a veřejnost", - "Tip: argument všichni to dělají nic nedokazuje.", - { - "Dav je dočasné seskupení, kde emoce snadno přebijí rozum.", - "Publikum sleduje program a většinou se řídí pravidly místa.", - "Populace je souhrn obyvatel.", - "Veřejnost je ta část lidí, která se vztahuje ke společným věcem.", - "V davu člověk snáz udělá to, co by sám neudělal.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[10], "on_unit11", "on_unit11_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit11_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se dav liší od komunity?", - { - "Ničím", - "Dav je dočasný a snadno v něm převáží emoce", - "Dav je vždycky rodina", - "Komunita nemá žádná pravidla", - }, - 4, 1}, - {"Co je populace?", - { - "Diváci v sále", - "Souhrn obyvatel", - "Politická strana", - "Jedna školní třída", - }, - 4, 1}, - {"Co hrozí v davu?", - { - "Že člověk udělá něco, co by sám neudělal", - "Že se automaticky zlepší morálka", - "Že emoce zmizí", - "Že se dav rozpustí rodinným právem", - }, - 4, 0}, - {"Co je veřejnost?", - { - "Jen diváci televize", - "Lidé, kteří se vztahují ke společným věcem", - "Uzavřená sekta", - "Jedna domácnost", - }, - 4, 1}, - }; - static const char *hints[] = { - "Dav je dočasný a emotivní", - "Populace = obyvatelé", - "V davu člověk snáz překročí vlastní mez", - "Veřejnost se vztahuje ke společným věcem", - }; - return build_on_mcq_page(10, "onunit11", "on_ex11_title", - "on_quiz11_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit12_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Parta", "Vrstevníci a tlak skupiny", - "Tip: parta může podržet i strhnout.", - { - "Vrstevnická skupina silně ovlivňuje dospívání.", - "Tlak skupiny může pomoct i ublížit.", - "Solidarita je ochota nést část zátěže druhého.", - "Solidarita není totéž co slepá poslušnost partě.", - NULL, - }, - }, - { - "2 / 2 • Hranice", "Migranti, azylanti a emigranti", - "Tip: azyl není totéž co turistika.", - { - "Migrant je člověk, který se stěhuje přes hranice, z různých důvodů.", - "Azylant žádá o ochranu, protože mu doma hrozí pronásledování.", - "Emigrant ze své země odchází, imigrant do země přichází.", - "Soužití má přínosy i třenice. Předsudek není argument.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[11], "on_unit12", "on_unit12_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit12_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je tlak vrstevníků?", - { - "Vliv party na rozhodování", - "Zákon parlamentu", - "Druh daně", - "Lékařská diagnóza", - }, - 4, 0}, - {"Kdo je azylant?", - { - "Turista na dovolené", - "Člověk, který žádá ochranu před pronásledováním", - "Každý, kdo má pas", - "Jen student na výměně", - }, - 4, 1}, - {"Jak se liší emigrant a imigrant?", - { - "Nijak", - "Emigrant odchází, imigrant přichází", - "Imigrant je vždycky azylant", - "Emigrant je jen z Evropské unie", - }, - 4, 1}, - {"Co je solidarita?", - { - "Slepá poslušnost", - "Ochota nést část zátěže druhého", - "Povinnost souhlasit s davem", - "Trest", - }, - 4, 1}, - }; - static const char *hints[] = { - "Tlak vrstevníků ovlivňuje rozhodování", - "Azylant žádá ochranu před pronásledováním", - "Emigrant odchází, imigrant přichází", - "Solidarita = nést část zátěže", - }; - return build_on_mcq_page(11, "onunit12", "on_ex12_title", - "on_quiz12_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit13_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Typy", "Tradiční, moderní a pozdně moderní společnost", - "Tip: moderní tu není pochvala, ale popis.", - { - "Tradiční společnost stála na zvyku, rodině a pomalém tempu změn.", - "Moderní společnost přinesla průmysl, města a větší pohyb lidí.", - "Pozdně moderní společnost je rychlá, propojená a méně přehledná.", - "Člověk v ní má víc voleb a zároveň víc nejistoty.", - NULL, - }, - }, - { - "2 / 2 • Vrstvy", "Vrstvy, elity a chudoba", - "Tip: chudoba není morální cejch.", - { - "Společenské vrstvy se liší majetkem, vzděláním, prestiží i mocí.", - "Elity jsou skupiny s velkým vlivem, ne automaticky ti lepší.", - "Sociální nerovnost a chudoba v demokracii nezmizely.", - "V tísni se člověk může obrátit na sociální služby a úřady.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[12], "on_unit13", "on_unit13_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit13_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se vyznačuje tradiční společnost?", - { - "Rychlými globálními změnami", - "Zvykem a pomalejším tempem změn", - "Jen internetem", - "Zrušením rodiny", - }, - 4, 1}, - {"Co jsou společenské elity?", - { - "Automaticky morálně nejlepší lidé", - "Skupiny s velkým vlivem", - "Jen sportovci", - "Lidé bez příjmu", - }, - 4, 1}, - {"Platí, že v demokracii chudoba neexistuje?", - { - "Ano", - "Ne, sociální nerovnost a chudoba zůstávají", - "Chudoba je jen ve středověku", - "Ústava nerovnost tím, že existuje, zruší", - }, - 4, 1}, - {"Kam se obrátit v sociální tísni?", - { - "Nikam, pomoc neexistuje", - "Na sociální služby a příslušné úřady", - "Jen na lichváře", - "Na náhodnou reklamu", - }, - 4, 1}, - }; - static const char *hints[] = { - "Tradiční společnost stojí na zvyku", - "Elity = skupiny s vlivem", - "Chudoba v demokracii nemizí", - "Tíseň řeší sociální služby a úřady", - }; - return build_on_mcq_page(12, "onunit13", "on_ex13_title", - "on_quiz13_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit14_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Pojmy", "Pohlaví a gender", - "Tip: rovnost neznamená, že jsou všichni ve všem stejní.", - { - "Pohlaví je biologická danost.", - "Gender jsou společenské role a očekávání spojená s muži a ženami.", - "Tahle očekávání se v čase a mezi kulturami liší.", - "Rovnost znamená stejnou důstojnost a šanci, ne stejný životopis.", - NULL, - }, - }, - { - "2 / 2 • Praxe", "Kde se nerovnost ukazuje", - "Tip: pozná se na konkrétním jednání, ne na heslu.", - { - "Nerovnost se může ukázat v odměňování, v péči o domácnost i v násilí.", - "Porušení rovnosti se soudí podle skutků, ne podle názvu.", - "Diskuse má stát na faktech, ne na posměchu.", - "Respekt k druhému nezávisí na tom, jestli s ním ve všem souhlasím.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[13], "on_unit14", "on_unit14_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit14_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se ve výuce rozlišuje pohlaví a gender?", - { - "Jsou to přesná synonyma", - "Pohlaví je biologické, gender jsou společenské role a očekávání", - "Gender je jen lékařská diagnóza", - "Pohlaví je krevní skupina", - }, - 4, 1}, - {"Co rovnost pohlaví znamená?", - { - "Že jsou všichni ve všem stejní", - "Stejnou důstojnost a šanci", - "Že nesmějí existovat žádné záliby", - "Že jeden rozhoduje za druhé", - }, - 4, 1}, - {"Kde se nerovnost může projevit?", - { - "Nikde", - "Třeba v odměňování nebo v dělbě péče", - "Jen v barvě očí", - "Jen ve sportovním rekordu", - }, - 4, 1}, - {"Čím se má taková diskuse řídit?", - { - "Posměchem", - "Fakty a respektem", - "Tím, kdo křičí víc", - "Zákazem otázek", - }, - 4, 1}, - }; - static const char *hints[] = { - "Gender = společenské role a očekávání", - "Rovnost = stejná důstojnost a šance", - "Ukazuje se třeba v odměně a péči", - "Diskuse stojí na faktech", - }; - return build_on_mcq_page(13, "onunit14", "on_ex14_title", - "on_quiz14_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit15_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Dvě vrstvy", "Hmotná a duchovní kultura", - "Tip: mobil je hmotná kultura, jazyk v něm je duchovní.", - { - "Kultura je to, co lidé vytvářejí a předávají, ne jen vysoké umění.", - "Hmotná kultura jsou věci: stavby, nástroje, oděv.", - "Duchovní kultura jsou myšlenky, jazyk, věda, umění a normy.", - "Obě vrstvy se prolínají.", - NULL, - }, - }, - { - "2 / 2 • Péče", "Věda, umění a kulturní hodnoty", - "Tip: kulturní hodnota není jen to, co se líbí mně.", - { - "Věda a umění jsou významné části duchovní kultury.", - "Péče o kulturní hodnoty znamená neničit je a rozumět jim.", - "Kultura se mění, proto není jeden seznam správných věcí navždy.", - "Bez kultury by společnost neměla společnou řeč ani paměť.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[14], "on_unit15", "on_unit15_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit15_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je hmotná kultura?", - { - "Jen city", - "Věci, které lidé vytvořili", - "Pouze náboženství", - "Jen zákony", - }, - 4, 1}, - {"Kam patří jazyk a věda?", - { - "Do hmotné kultury", - "Do duchovní kultury", - "Mimo kulturu", - "Jen do matematiky", - }, - 4, 1}, - {"Proč se o kulturní hodnoty pečuje?", - { - "Aby zmizely", - "Aby se neničily a zůstaly srozumitelné", - "Protože se nesmějí nikdy měnit", - "Protože kultura je jen soukromý vkus", - }, - 4, 1}, - {"Platí, že kultura je jen opera a galerie?", - { - "Ano", - "Ne, kultura je širší způsob, jak lidé žijí a tvoří", - "Kultura je jen jídlo", - "Kultura je jen sport", - }, - 4, 1}, - }; - static const char *hints[] = { - "Hmotná kultura = vytvořené věci", - "Jazyk a věda jsou duchovní kultura", - "Hodnoty se chrání a vykládají", - "Kultura je širší než vysoké umění", - }; - return build_on_mcq_page(14, "onunit15", "on_ex15_title", - "on_quiz15_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit16_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Víra", "Víra, ateismus a církve", - "Tip: ateismus není urážka a víra není diagnóza.", - { - "Věřící člověk vztahuje život k tomu, co ho přesahuje.", - "Ateista takový náboženský vztah nesdílí.", - "V České republice žijí věřící i ateisté a obojí má v demokracii místo.", - "Církev je organizované společenství věřících, ne totéž co víra sama.", - "Mezi velká náboženství patří křesťanství, islám, hinduismus, buddhismus a judaismus.", - NULL, - }, - }, - { - "2 / 2 • Riziko", "Sekty a náboženský fundamentalismus", - "Tip: varovné je, když skupina zakazuje otázky a kontakt s blízkými.", - { - "Sekta v tomto významu je uzavřená skupina, která člena izoluje a kontroluje.", - "Nebezpečí je manipulace, tlak na peníze a odříznutí od rodiny.", - "Fundamentalismus bere vlastní výklad jako jediný a často útočí na druhé.", - "Svoboda víry neznamená právo ubližovat.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[15], "on_unit16", "on_unit16_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit16_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je ateismus?", - { - "Zakázaný názor", - "Postoj, který nesdílí náboženskou víru", - "Druh církve", - "Povinnost státu", - }, - 4, 1}, - {"Co je církev?", - { - "Každá budova s věží", - "Organizované společenství věřících", - "Totéž co ateismus", - "Státní úřad", - }, - 4, 1}, - {"Čím je nebezpečná manipulativní sekta?", - { - "Tím, že má jiný svátek", - "Izolací, kontrolou a tlakem", - "Tím, že lidé věří", - "Tím, že se schází legálně", - }, - 4, 1}, - {"Co náboženský fundamentalismus často dělá?", - { - "Vede k dialogu za každou cenu", - "Bere vlastní výklad jako jediný přípustný", - "Ruší náboženství", - "Je totéž co ateismus", - }, - 4, 1}, - }; - static const char *hints[] = { - "Ateismus nesdílí náboženskou víru", - "Církev je organizované společenství", - "Sekta izoluje a kontroluje", - "Fundamentalismus trvá na jediném výkladu", - }; - return build_on_mcq_page(15, "onunit16", "on_ex16_title", - "on_quiz16_head", qs, hints, 4); -} - - -static GtkWidget *build_on_unit17_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Rozpočet", "Příjmy, výdaje a majetek", - "Tip: nejdřív povinné výdaje, pak zbytek.", - { - "Majetek člověk nabývá prací, darem, dědictvím nebo podnikáním.", - "Rozpočet domácnosti porovnává příjmy a výdaje.", - "Příjmy i výdaje jsou pravidelné a nepravidelné.", - "Schodkový rozpočet se musí řešit, přebytek se dá odložit i na stáří.", - NULL, - }, - }, - { - "2 / 2 • Tíseň", "Krize, zajištění a úvěr", - "Tip: kdo smlouvě nerozumí, ještě nepodepisuje.", - { - "Zodpovědné hospodaření znamená neutrácet to, co domácnost nemá.", - "Krize je ztráta příjmu, nemoc nebo dluh, který nejde splatit.", - "Pomoc nabízí sociální zabezpečení, dávky a poradenství, ne lichva.", - "Úvěr je nástroj, ne dar: splácí se i s navýšením.", - NULL, - }, - }, - }; - - return build_on_unit_page(&on_lessons[16], "on_unit17", "on_unit17_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on_unit17_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co porovnává rozpočet domácnosti?", - { - "Jen sny", - "Příjmy a výdaje", - "Počasí", - "Školní známky", - }, - 4, 1}, - {"Co je schodkový rozpočet?", - { - "Výdaje jsou vyšší než příjmy", - "Příjmy jsou vyšší než výdaje", - "Rozpočet bez čísel", - "Rozpočet státu", - }, - 4, 0}, - {"Jak se má řešit finanční tíseň?", - { - "Další lichvou", - "Poradenstvím a legální sociální pomocí, ne drahým dluhem", - "Tím, že se smlouvy nečtou", - "Ignorováním splátek", - }, - 4, 1}, - {"Co platí o úvěru?", - { - "Je to dar", - "Splácí se i s navýšením", - "Nemusí se vracet", - "Je totéž co mzda", - }, - 4, 1}, - }; - static const char *hints[] = { - "Rozpočet porovnává příjmy a výdaje", - "Schodek = výdaje nad příjmy", - "Tíseň se neřeší lichvou", - "Úvěr se vrací i s navýšením", - }; - return build_on_mcq_page(16, "onunit17", "on_ex17_title", - "on_quiz17_head", qs, hints, 4); -} - - -void add_on_pages(GtkStack *stack) { - typedef GtkWidget *(*OnBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - OnBuilder build_unit; - OnBuilder build_ex; - } pages[] = { - {"onunit1", "onex1", build_on_unit1_page, build_on_unit1_exercise_page}, - {"onunit2", "onex2", build_on_unit2_page, build_on_unit2_exercise_page}, - {"onunit3", "onex3", build_on_unit3_page, build_on_unit3_exercise_page}, - {"onunit4", "onex4", build_on_unit4_page, build_on_unit4_exercise_page}, - {"onunit5", "onex5", build_on_unit5_page, build_on_unit5_exercise_page}, - {"onunit6", "onex6", build_on_unit6_page, build_on_unit6_exercise_page}, - {"onunit7", "onex7", build_on_unit7_page, build_on_unit7_exercise_page}, - {"onunit8", "onex8", build_on_unit8_page, build_on_unit8_exercise_page}, - {"onunit9", "onex9", build_on_unit9_page, build_on_unit9_exercise_page}, - {"onunit10", "onex10", build_on_unit10_page, build_on_unit10_exercise_page}, - {"onunit11", "onex11", build_on_unit11_page, build_on_unit11_exercise_page}, - {"onunit12", "onex12", build_on_unit12_page, build_on_unit12_exercise_page}, - {"onunit13", "onex13", build_on_unit13_page, build_on_unit13_exercise_page}, - {"onunit14", "onex14", build_on_unit14_page, build_on_unit14_exercise_page}, - {"onunit15", "onex15", build_on_unit15_page, build_on_unit15_exercise_page}, - {"onunit16", "onex16", build_on_unit16_page, build_on_unit16_exercise_page}, - {"onunit17", "onex17", build_on_unit17_page, build_on_unit17_exercise_page}, - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/obcanka2.c b/src/obcanka2.c deleted file mode 100644 index 7f58525..0000000 --- a/src/obcanka2.c +++ /dev/null @@ -1,1911 +0,0 @@ -#include "graduately.h" - -/* Year 2 of Občanská nauka. - * Thematic unit "Člověk jako občan v demokratickém státě" from the MŠMT - * model syllabus (č.j. 18 396/2002-23) and the SOV civic framework, which - * schools place in the second year. Law is year 3. The economy, the - * world and philosophy are year 4. */ - -#define ON2_ENTRY(n) \ - { .n_slides = 2, .unit_page = "on2unit" #n, .ex_page = "on2ex" #n } - -NetLesson on2_lessons[ON2_LESSONS] = { - ON2_ENTRY(1), - ON2_ENTRY(2), - ON2_ENTRY(3), - ON2_ENTRY(4), - ON2_ENTRY(5), - ON2_ENTRY(6), - ON2_ENTRY(7), - ON2_ENTRY(8), - ON2_ENTRY(9), - ON2_ENTRY(10), - ON2_ENTRY(11), - ON2_ENTRY(12), - ON2_ENTRY(13), - ON2_ENTRY(14), - ON2_ENTRY(15), - ON2_ENTRY(16), -}; - -#undef ON2_ENTRY - -GtkWidget *on2_scroll; -GtkWidget *on2_fixed; -GtkWidget *on2_rail; -GtkWidget *on2_nodes[ON2_UNITS]; -GtkWidget *on2_labels[ON2_UNITS]; -double on2_cx[ON2_UNITS]; -double on2_cy[ON2_UNITS]; -int on2_cols = 1; -int on2_rows = 1; -int on2_cw = (int)(2.0 * ROAD_MX + (ON2_UNITS - 1) * PATH_SPAC); -int on2_ch = (int)(2.0 * ROAD_MY); -guint on2_idle; -double on2_last_avail = -1.0; -int on2_last_cols = -1; -int on2_last_rows = -1; -int on2_last_cw = -1; -int on2_last_ch = -1; -cairo_surface_t *on2_rail_cache; -int on2_cache_w; -int on2_cache_h; - -static void on2_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= ON2_UNITS - 1) { k = ON2_UNITS - 2; u = 1.0; } - - p1x = on2_cx[k]; p1y = on2_cy[k]; - p2x = on2_cx[k + 1]; p2y = on2_cy[k + 1]; - if (k - 1 >= 0) { p0x = on2_cx[k - 1]; p0y = on2_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < ON2_UNITS) { p3x = on2_cx[k + 2]; p3y = on2_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -static void on2_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 24.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - on2_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - on2_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -static void on2_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(ON2_UNITS - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= ON2_UNITS; rows++) { - int cols = (ON2_UNITS + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > ON2_UNITS) - rows = ON2_UNITS; - on2_rows = rows; - on2_cols = (ON2_UNITS + rows - 1) / rows; - if (on2_cols < 1) - on2_cols = 1; - on2_cw = (int)(2.0 * ROAD_MX + (on2_cols - 1) * PATH_SPAC); - on2_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * on2_cols; - int len = MIN(on2_cols, ON2_UNITS - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (on2_cols - 1 - c); - on2_cx[i] = ROAD_MX + cc * PATH_SPAC; - on2_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -static void on2_apply_layout(void) { - if (!on2_fixed) - return; - - if (on2_cols == on2_last_cols && on2_rows == on2_last_rows && - on2_cw == on2_last_cw && on2_ch == on2_last_ch) - return; - - on2_last_cols = on2_cols; - on2_last_rows = on2_rows; - on2_last_cw = on2_cw; - on2_last_ch = on2_ch; - if (on2_rail_cache) { - cairo_surface_destroy(on2_rail_cache); - on2_rail_cache = NULL; - } - - for (int i = 0; i < ON2_UNITS; i++) { - if (!on2_nodes[i] || !on2_labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(on2_fixed), on2_nodes[i], - (int)(on2_cx[i] - NODE_SIZE / 2.0), - (int)(on2_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(on2_fixed), on2_labels[i], - (int)(on2_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(on2_cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(on2_fixed, on2_cw, on2_ch); - gtk_widget_set_size_request(on2_rail, on2_cw, on2_ch); - gtk_fixed_move(GTK_FIXED(on2_fixed), on2_rail, 0, 0); - gtk_widget_queue_draw(on2_rail); -} - -static void on2_relayout(void) { - GtkAdjustment *hadj; - double avail; - - if (!on2_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(on2_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - on2_last_avail) < 1.0) - return; - on2_last_avail = avail; - on2_geometry(avail); - on2_apply_layout(); -} - -static gboolean on2_relayout_idle(gpointer data) { - (void)data; - on2_idle = 0; - on2_relayout(); - return G_SOURCE_REMOVE; -} - -static void on2_relayout_later(void) { - if (on2_idle == 0) - on2_idle = g_idle_add(on2_relayout_idle, NULL); -} - -static void on2_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - (void)data; - on2_relayout_later(); -} - -static void on2_render_rail_to(cairo_t *cr) { - const double t_end = (double)(ON2_UNITS - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - on2_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - on2_path(cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -static void on2_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - (void)area; - (void)width; - (void)height; - (void)data; - - if (!on2_rail_cache || on2_cache_w != on2_cw || on2_cache_h != on2_ch) { - cairo_t *rcr; - - if (on2_rail_cache) - cairo_surface_destroy(on2_rail_cache); - on2_cache_w = on2_cw; - on2_cache_h = on2_ch; - if (on2_cache_w < 1) - on2_cache_w = 1; - if (on2_cache_h < 1) - on2_cache_h = 1; - on2_rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - on2_cache_w, on2_cache_h); - rcr = cairo_create(on2_rail_cache); - on2_render_rail_to(rcr); - cairo_destroy(rcr); - } - - cairo_set_source_surface(cr, on2_rail_cache, 0, 0); - cairo_paint(cr); -} - -void on2_rail_theme_reset(void) { - if (on2_rail_cache) { - cairo_surface_destroy(on2_rail_cache); - on2_rail_cache = NULL; - } - if (on2_rail) - gtk_widget_queue_draw(on2_rail); -} - -static void on2_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof(name), "on2_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static void on2_add_node(GtkFixed *fixed, int index) { - int num = index + 1; - gboolean locked = index >= ON2_LESSONS; - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - static char unit_keys[ON2_LESSONS][16]; - static gboolean unit_keys_ready = FALSE; - - if (!unit_keys_ready) { - for (int i = 0; i < ON2_LESSONS; i++) - g_snprintf(unit_keys[i], sizeof unit_keys[i], "on2_unit%d", i + 1); - unit_keys_ready = TRUE; - } - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_sensitive(card, !locked); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - if (locked) - gtk_widget_add_css_class(card, "locked"); - else - gtk_widget_add_css_class(card, "current"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", num); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - if (locked) { - icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 16); - gtk_box_append(GTK_BOX(vbox), icon); - } else { - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - on2_lessons[index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(on2_open_unit), - &on2_lessons[index]); - } - - on2_nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - if (index < ON2_LESSONS) { - i18n_bind(name, unit_keys[index], 0); - } else { - gtk_widget_add_css_class(name, "unit-name-locked"); - } - on2_labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} -GtkWidget *build_on2map_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - - on2_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("onyears", "on_year2", "on2_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - on2_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, on2_cw, on2_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - on2_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, on2_cw, on2_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), on2_draw_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - on2_rail = rail; - - for (int i = 0; i < ON2_UNITS; i++) - on2_add_node(GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(on2_adjust_notify), NULL); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(on2_adjust_notify), NULL); - - on2_apply_layout(); - on2_relayout_later(); - refresh_on2_completion_ui(); - - return page; -} - -static void on2_slide_apply(NetLesson *L); -static void on2_slide_prev(GtkButton *button, gpointer data); -static void on2_slide_next(GtkButton *button, gpointer data); - -static int on2_note_last_w = -1; - -static void on2_rescale_notes_at(int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < ON2_LESSONS; i++) - net_rescale_lesson_notes(&on2_lessons[i], body, head, kick); -} - -static gboolean on2_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width != on2_note_last_w) { - on2_note_last_w = width; - on2_rescale_notes_at(width); - } - return G_SOURCE_CONTINUE; -} - -static GtkWidget *build_on2_unit_page(NetLesson *L, const char *title_key, - const char *sub_key, - const NetSlide *slides, guint n_slides) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar("on2map", title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "on2_slide%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, on2_note_tick, NULL, NULL); - on2_note_last_w = -1; - on2_rescale_notes_at(0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(on2_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(on2_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - on2_slide_apply(L); - return page; -} - -static void on2_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "on2_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void on2_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx > 0) { - L->idx--; - on2_slide_apply(L); - } -} - -static void on2_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - on2_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -void on2_lessons_apply_lang(void) { - for (int i = 0; i < ON2_LESSONS; i++) - on2_slide_apply(&on2_lessons[i]); -} - -static void on2_mcq_check(GtkButton *button, gpointer data) { - NetMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_on2_done(ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -static GtkWidget *build_on2_mcq_page(int lesson_id, const char *back_page, - const char *title_key, - const char *heading_key, - const ChoiceQ *qs, const char **hints, - int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - NetMcqCtx *ctx = g_new0(NetMcqCtx, 1); - int n_opts = qs[0].n_options; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(on2_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - - return page; -} -static GtkWidget *build_on2_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Stát", "Co dělá stát státem", - "Tip: bydliště ještě není občanství.", - { - "Stát je organizace veřejné moci na určitém území a nad lidmi, kteří tam žijí.", - "Má území, obyvatelstvo, veřejnou moc a právní řád.", - "Občan má ke státu trvalý právní svazek, kterému se říká státní občanství.", - "Cizinec může na území žít, občanem se tím sám nestává.", - NULL, - }, - }, - { - "2 / 2 • Podíl", "Práva a povinnosti občana", - "Tip: demokratický stát má občanovi sloužit.", - { - "Z občanství plynou práva, třeba volit do Parlamentu, a také povinnosti.", - "Povinností je dodržovat zákony, platit daně a respektovat práva druhých.", - "Moc ve státě má být kontrolovatelná, ne neomezená.", - "Občan se podílí volbami, kontrolou moci a slušným jednáním.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[0], "on2_unit1", "on2_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je stát?", - { - "Jen mapa a hymna", - "Organizace veřejné moci na území s obyvatelstvem a právním řádem", - "Každá skupina lidí", - "Pouze vláda", - }, - 4, 1}, - {"Čím se občan liší od cizince?", - { - "Má trvalý právní svazek se státem", - "Bydlí v hlavním městě", - "Mluví úředním jazykem", - "Platí jízdné", - }, - 4, 0}, - {"Co z občanství plyne?", - { - "Jen povinnost volit", - "Jen právo na pas", - "Práva i povinnosti", - "Nic, dokud člověk nepracuje", - }, - 4, 2}, - {"Jak se občan na demokratickém státě podílí?", - { - "Jen poslušností bez ptaní", - "Volbami, kontrolou moci a dodržováním zákonů", - "Tím, že moc nechá bez dozoru", - "Jen placením pokut", - }, - 4, 1}, - }; - static const char *hints[] = { - "Stát má území, obyvatele, moc a právo", - "Občanství je právní svazek, ne jen pobyt", - "Občan má práva a také povinnosti", - "Podíl je volba, kontrola i respekt k právu", - }; - return build_on2_mcq_page(0, "on2unit1", "on2_ex1_title", - "on2_quiz1_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Nabytí", "Jak se české občanství získává", - "Tip: narození na území ČR samo o sobě občanství nedává.", - { - "Dítě ho nabývá narozením, je-li alespoň jeden rodič občanem České republiky.", - "Dále ho lze nabýt určením otcovství, osvojením nebo nalezením dítěte, jehož totožnost se nezjistí.", - "Dospělý cizinec ho může získat udělením, v některých případech prohlášením.", - "Podrobnosti určuje zákon o státním občanství.", - NULL, - }, - }, - { - "2 / 2 • Udělení", "Když o občanství žádá cizinec", - "Tip: na udělení není právní nárok.", - { - "Udělení je rozhodnutí státu, ne automatický nárok žadatele.", - "Žadatel musí splnit podmínky, mimo jiné pobyt, bezúhonnost a znalost češtiny.", - "Patří sem i základní znalost ústavního systému a plnění povinností vůči státu.", - "Občan České republiky může mít i jiné občanství, dovoluje-li to zákon.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[1], "on2_unit2", "on2_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy dítě nabývá české občanství narozením?", - { - "Když se narodí v Praze", - "Když je alespoň jeden rodič občanem ČR", - "Když chodí do české školy", - "Když mu je osmnáct", - }, - 4, 1}, - {"Dává samotné narození v ČR občanství?", - { - "Ano, každému", - "Ne, kromě zvláštních případů, třeba nalezeného dítěte", - "Ano, pokud rodiče platí daň", - "Ano, po roce pobytu", - }, - 4, 1}, - {"Je na udělení občanství právní nárok?", - { - "Ano, po týdnu pobytu", - "Ne, stát ho uděluje po splnění podmínek", - "Ano, každému obyvateli EU", - "Ano, kdo složí maturitu", - }, - 4, 1}, - {"Co se při udělení obvykle požaduje?", - { - "Jen fotografii", - "Pobyt, bezúhonnost a znalost češtiny", - "Vlastnictví bytu", - "Členství v politické straně", - }, - 4, 1}, - }; - static const char *hints[] = { - "Rozhoduje občanství rodiče, ne samo místo narození", - "Platí původ po rodičích, ne místo narození", - "Udělení je rozhodnutí státu", - "Podmínky chrání, aby šlo o skutečný vztah ke státu", - }; - return build_on2_mcq_page(1, "on2unit2", "on2_ex2_title", - "on2_quiz2_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Výčet", "Které symboly Česká republika má", - "Tip: hymnou je oficiálně jen první sloka.", - { - "Zákon uvádí velký a malý státní znak, státní barvy, vlajku a vlajku prezidenta.", - "Patří k nim také státní pečeť a státní hymna.", - "Státní barvy jsou bílá, červená a modrá.", - "Hymnou je první sloka písně Kde domov můj.", - NULL, - }, - }, - { - "2 / 2 • Úcta", "K čemu symboly jsou", - "Tip: velký znak spojuje Čechy, Moravu a Slezsko.", - { - "Symboly představují stát a lidé jim mají prokazovat úctu.", - "Velký znak nese českého lva a moravskou a slezskou orlici.", - "Vlajka je bílá a červená s modrým klínem u žerdi.", - "Užívají se podle zákona, ne jako libovolná ozdoba.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[2], "on2_unit3", "on2_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Která píseň je státní hymna?", - { - "První sloka Kde domov můj", - "Celá píseň včetně druhé sloky jako povinný text", - "Hej, Slované", - "Ódu na radost", - }, - 4, 0}, - {"Jaké jsou státní barvy?", - { - "Červená, bílá a zelená", - "Bílá, červená a modrá", - "Modrá a žlutá", - "Černá a zlatá", - }, - 4, 1}, - {"Co spojuje velký státní znak?", - { - "Jen Prahu a Brno", - "Znaky Čech, Moravy a Slezska", - "Vlajky sousedních států", - "Znak Evropské unie", - }, - 4, 1}, - {"Patří státní pečeť mezi státní symboly?", - { - "Ne, je to jen razítko úřadu", - "Ano", - "Jen když ji použije obec", - "Ne, zrušila ji ústava", - }, - 4, 1}, - }; - static const char *hints[] = { - "Zákon stanoví první sloku", - "Bílá, červená a modrá", - "Lev a dvě orlice", - "Pečeť je v zákonném výčtu symbolů", - }; - return build_on2_mcq_page(2, "on2unit3", "on2_ex3_title", - "on2_quiz3_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Pořádek", "Nejvyšší pravidla státu", - "Tip: Listina je součást ústavního pořádku, ne obyčejný zákon.", - { - "Ústava je základní zákon a běžný zákon jí nesmí odporovat.", - "Ústavní pořádek tvoří Ústava, Listina základních práv a svobod a další ústavní zákony.", - "Ústava České republiky platí od 1. ledna 1993.", - "Popisuje území, moc a základní pravidla politického systému.", - NULL, - }, - }, - { - "2 / 2 • Změna", "Proč se ústava mění obtížně", - "Tip: rigidní ústava chrání pravidla před chvilkovou většinou.", - { - "Ústava se mění obtížněji než obyčejný zákon.", - "Ústavní zákon potřebuje tři pětiny všech poslanců.", - "V Senátu potřebuje tři pětiny přítomných senátorů.", - "Listina vedle ústavy chrání práva člověka a občana.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[3], "on2_unit4", "on2_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je ústava?", - { - "Volební program vlády", - "Základní zákon, kterému nesmí odporovat běžné zákony", - "Jednací řád školy", - "Rozpočet na jeden rok", - }, - 4, 1}, - {"Je Listina základních práv a svobod součást ústavního pořádku?", - { - "Ne, je to doporučení", - "Ano", - "Jen pro cizince", - "Jen do roku 1993", - }, - 4, 1}, - {"Jaká většina je potřeba k ústavnímu zákonu?", - { - "Nadpoloviční většina přítomných poslanců", - "Tři pětiny všech poslanců a tři pětiny přítomných senátorů", - "Souhlas prezidenta stačí", - "Jednomyslnost vlády", - }, - 4, 1}, - {"Od kdy ústava České republiky platí?", - { - "Od roku 1918", - "Od 1. ledna 1993", - "Od vstupu do Evropské unie", - "Od roku 1960", - }, - 4, 1}, - }; - static const char *hints[] = { - "Ústava stojí nad obyčejnými zákony", - "Listina má sílu ústavního zákona", - "Ústava je rigidní", - "Platí od vzniku samostatné České republiky", - }; - return build_on2_mcq_page(3, "on2unit4", "on2_ex4_title", - "on2_quiz4_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Složky", "Tři moci vedle sebe", - "Tip: soudce nemá být podřízený ministrovi.", - { - "Moc se dělí, aby ji jeden orgán nemohl užívat bez kontroly.", - "Zákonodárná moc dává zákony a v České republice ji má Parlament.", - "Výkonná moc zákony provádí: patří k ní vláda a prezident.", - "Soudní moc rozhoduje spory a je na ostatních složkách nezávislá.", - NULL, - }, - }, - { - "2 / 2 • Rovnováha", "Brzdy mezi složkami", - "Tip: kontrola moci je součást demokracie, ne překážka.", - { - "Složky se navzájem omezují, tomu se říká brzdy a rovnováhy.", - "Prezident může zákon vrátit a Sněmovna může vyslovit vládě nedůvěru.", - "Ústavní soud hlídá, aby právo drželo ústavní pořádek.", - "Nejvyšší kontrolní úřad kontroluje hospodaření se státním majetkem a Česká národní banka pečuje o cenovou stabilitu.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[4], "on2_unit5", "on2_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč se státní moc dělí?", - { - "Aby bylo více ministerstev", - "Aby ji nikdo neužíval bez kontroly", - "Aby soudil prezident", - "Aby zákony psala armáda", - }, - 4, 1}, - {"Kdo vykonává zákonodárnou moc?", - { - "Vláda", - "Parlament", - "Ústavní soud", - "Hejtmani", - }, - 4, 1}, - {"Kdo patří k výkonné moci?", - { - "Jen Senát", - "Vláda a prezident", - "Jen obecní zastupitelstva", - "Jen advokáti", - }, - 4, 1}, - {"Co dělá Ústavní soud?", - { - "Schvaluje státní rozpočet", - "Hlídá soulad s ústavním pořádkem", - "Řídí policii", - "Jmenuje starosty", - }, - 4, 1}, - }; - static const char *hints[] = { - "Dělba brání soustředění moci", - "Zákony dává Parlament", - "Výkonná moc zákony provádí", - "Ústavní soud není další komora Parlamentu", - }; - return build_on2_mcq_page(4, "on2unit5", "on2_ex5_title", - "on2_quiz5_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Komory", "Sněmovna a Senát", - "Tip: senátor má delší mandát než poslanec.", - { - "Parlament tvoří Poslanecká sněmovna a Senát.", - "Sněmovna má 200 poslanců volených na čtyři roky.", - "Senát má 81 senátorů volených na šest let a každé dva roky se obmění třetina.", - "Poslancem lze být od 21 let, senátorem od 40 let.", - NULL, - }, - }, - { - "2 / 2 • Zákon", "Jak vzniká obyčejný zákon", - "Tip: kraj smí podat návrh zákona.", - { - "Návrh může podat poslanec, Senát, vláda nebo zastupitelstvo kraje.", - "Návrh schvaluje Poslanecká sněmovna.", - "Senát ho může vrátit nebo zamítnout, Sněmovna může senátní nesouhlas přehlasovat.", - "Prezident zákon podepíše, nebo ho vrátí; i jeho veto může Sněmovna přehlasovat.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[5], "on2_unit6", "on2_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kolik poslanců má Poslanecká sněmovna?", - { - "81", - "200", - "150", - "26", - }, - 4, 1}, - {"Jak dlouhý je mandát senátora?", - { - "Dva roky", - "Čtyři roky", - "Šest let", - "Do odvolání vládou", - }, - 4, 2}, - {"Od kolika let lze být zvolen poslancem?", - { - "Od 18 let", - "Od 21 let", - "Od 40 let", - "Od 35 let", - }, - 4, 1}, - {"Kdo smí podat návrh zákona?", - { - "Jen prezident", - "Poslanec, Senát, vláda nebo kraj", - "Jen Ústavní soud", - "Každý občan přímo do Sbírky", - }, - 4, 1}, - }; - static const char *hints[] = { - "Sněmovna má dvě stě poslanců", - "Senát se obměňuje po třetinách", - "Do Sněmovny od 21, do Senátu od 40", - "Návrh zákona je v ústavě vyhrazen určeným subjektům", - }; - return build_on2_mcq_page(5, "on2unit6", "on2_ex6_title", - "on2_quiz6_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Hlava státu", "Prezident republiky", - "Tip: prezident se volí přímo.", - { - "Prezident je hlava státu a volí se přímo na pět let.", - "Stejný člověk může úřad vykonávat nejvýše dvě období po sobě.", - "Kandidát musí mít nejméně 40 let.", - "Zastupuje stát navenek, jmenuje vládu, je vrchním velitelem ozbrojených sil a může udělit milost.", - NULL, - }, - }, - { - "2 / 2 • Vláda", "Vrchol výkonné moci", - "Tip: vládě předsedá premiér, ne prezident.", - { - "Vládu tvoří předseda, místopředsedové a ministři.", - "Je vrcholným orgánem výkonné moci.", - "Odpovídá Poslanecké sněmovně, která jí může vyslovit nedůvěru.", - "Po jmenování žádá Sněmovnu o důvěru a řídí ministerstva.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[6], "on2_unit7", "on2_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se volí prezident republiky?", - { - "Parlamentem na doživotí", - "Přímo občany, na pět let", - "Vládou na dva roky", - "Senátem na deset let", - }, - 4, 1}, - {"Kolikrát za sebou může být člověk prezidentem?", - { - "Jen jednou", - "Nejvýše dvakrát", - "Bez omezení", - "Třikrát", - }, - 4, 1}, - {"Komu je odpovědná vláda?", - { - "Senátu", - "Poslanecké sněmovně", - "Ústavnímu soudu", - "Hejtmanům", - }, - 4, 1}, - {"Kdo vládě předsedá?", - { - "Prezident", - "Předseda vlády", - "Předseda Senátu", - "Guvernér České národní banky", - }, - 4, 1}, - }; - static const char *hints[] = { - "Přímá volba od roku 2013, mandát pět let", - "Ústava zakazuje třetí období v řadě", - "Sněmovna může vyslovit nedůvěru", - "Premiér není totéž co hlava státu", - }; - return build_on2_mcq_page(6, "on2unit7", "on2_ex7_title", - "on2_quiz7_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Správa", "Stát a územní celky", - "Tip: samospráva není totéž co ministerstvo.", - { - "Veřejná správa je správa veřejných záležitostí.", - "Státní správu vykonávají jménem státu třeba ministerstva a další úřady.", - "Samospráva patří obcím a krajům: rozhodují o svých věcech.", - "Obec a kraj mají vlastní působnost a plní i úkoly, které jim svěří stát.", - NULL, - }, - }, - { - "2 / 2 • Obec a kraj", "Kdo stojí v čele", - "Tip: hejtman stojí v čele kraje, starosta v čele obce.", - { - "V obci je volené zastupitelstvo, rada a starosta.", - "V kraji je zastupitelstvo, rada a hejtman.", - "Zastupitelstvo je nejvyšší orgán územní samosprávy.", - "Praha je hlavní město a má postavení obce i kraje.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[7], "on2_unit8", "on2_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je územní samospráva?", - { - "Řízení ministerstva z Prahy", - "Rozhodování obce a kraje o vlastních záležitostech", - "Jen práce policie", - "Jen soudní řízení", - }, - 4, 1}, - {"Kdo stojí v čele obce?", - { - "Hejtman", - "Starosta", - "Ministr vnitra", - "Senátor za okres", - }, - 4, 1}, - {"Kdo stojí v čele kraje?", - { - "Starosta", - "Hejtman", - "Prezident", - "Ředitel školy", - }, - 4, 1}, - {"Jaké postavení má Praha?", - { - "Je jen městská část", - "Je obec a zároveň kraj", - "Není samospráva", - "Řídí ji přímo vláda bez zastupitelstva", - }, - 4, 1}, - }; - static const char *hints[] = { - "Samospráva patří obci a kraji", - "Obec vede starosta", - "Kraj vede hejtman", - "Hlavní město je obec i kraj", - }; - return build_on2_mcq_page(7, "on2unit8", "on2_ex8_title", - "on2_quiz8_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit9_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Hodnoty", "Od čeho se demokracie pozná", - "Tip: většina nesmí menšině vzít základní práva.", - { - "V demokracii veřejná moc pochází od lidu.", - "Patří k ní svobodné volby, vláda většiny a ochrana menšiny.", - "Dál právní stát, dělba moci a soutěž více politických stran.", - "Svoboda člověka jde ruku v ruce s odpovědností vůči druhým.", - NULL, - }, - }, - { - "2 / 2 • Ohrožení", "Co demokracii podrývá", - "Tip: korupce je zneužití postavení k soukromému prospěchu.", - { - "Škodí jí korupce, násilí a neodpovědnost.", - "Škodí i snaha zrušit kontrolu moci a pravidla soutěže.", - "Demokracie není vláda bez pravidel.", - "Občan ji chrání účastí, ne lhostejností.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[8], "on2_unit9", "on2_unit9_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit9_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Od koho pochází veřejná moc v demokracii?", - { - "Od armády", - "Od lidu", - "Od nejbohatších firem", - "Od jednoho vůdce", - }, - 4, 1}, - {"Chrání demokracie jen vítěznou většinu?", - { - "Ano, menšina nemá práva", - "Ne, chrání i základní práva menšiny", - "Menšinu chrání jen v obci", - "Práva platí jen ve volební den", - }, - 4, 1}, - {"Co je korupce?", - { - "Svobodná volba", - "Zneužití postavení k soukromému prospěchu", - "Kritika vlády", - "Práce zastupitelstva", - }, - 4, 1}, - {"Co k demokracii patří?", - { - "Jedna povolená strana", - "Svobodné volby a právní stát", - "Moc bez soudů", - "Zákaz menšinových názorů", - }, - 4, 1}, - }; - static const char *hints[] = { - "Lid je zdroj moci", - "Vláda většiny má mez v právech menšiny", - "Korupce demokracii ohrožuje", - "Volby a právo drží demokracii pohromadě", - }; - return build_on2_mcq_page(8, "on2unit9", "on2_ex9_title", - "on2_quiz9_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit10_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Listina", "Práva člověka a občana", - "Tip: stát práva nedaruje podle nálady.", - { - "Lidská práva má člověk proto, že je člověk.", - "Listina chrání základní svobody, politická práva, práva menšin i hospodářská, sociální a kulturní práva.", - "Patří sem třeba život, osobní svoboda, vlastnictví, volební právo a vzdělání.", - "Samostatná hlava chrání právo domáhat se svých práv u nezávislého soudu.", - NULL, - }, - }, - { - "2 / 2 • Meze", "Ochrana a hranice svobody", - "Tip: svoboda projevu nechrání pomluvu ani navádění k násilí.", - { - "Práva lze omezit jen zákonem a jen z vážných důvodů, třeba ochrany druhých.", - "Ohrožená práva se hájí u soudu a lze se obrátit i na Ústavní soud.", - "Ve světě je připomíná Všeobecná deklarace lidských práv a evropská úmluva.", - "Právo jednoho končí tam, kde začíná stejně vážené právo druhého.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[9], "on2_unit10", "on2_unit10_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit10_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Proč má člověk lidská práva?", - { - "Protože je člověk", - "Jen když vyhraje volby", - "Jen jako odměnu státu", - "Jen do 18 let", - }, - 4, 0}, - {"Kde jsou v České republice ústavně zakotvena?", - { - "Jen v jednacím řádu Sněmovny", - "V Listině základních práv a svobod", - "Jen v občanském zákoníku", - "V obecní vyhlášce", - }, - 4, 1}, - {"Lze lidská práva omezit libovolně?", - { - "Ano, rozhodnutím starosty", - "Ne, jen zákonem a z vážných důvodů", - "Ano, většinou v anketě", - "Ne, nelze je omezit nikdy a v ničem", - }, - 4, 1}, - {"Kam se obrátit, jsou-li práva ohrožena?", - { - "Na nikoho, práva se nehájí", - "Třeba k soudu", - "Jen na politickou stranu", - "Jen do novin", - }, - 4, 1}, - }; - static const char *hints[] = { - "Práva nejsou milost úřadu", - "Listina je součást ústavního pořádku", - "Omezení má zákonný důvod", - "Soudní ochrana je součást Listiny", - }; - return build_on2_mcq_page(9, "on2unit10", "on2_ex10_title", - "on2_quiz10_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit11_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Dítě", "Úmluva o právech dítěte", - "Tip: dítětem je člověk mladší 18 let.", - { - "Dítě má stejnou důstojnost jako dospělý.", - "Úmluva zdůrazňuje zájem dítěte, právo na život, vzdělání a ochranu před násilím.", - "Dítě má právo být slyšeno ve věcech, které se ho týkají.", - "Rodiče i stát mají dítě chránit.", - NULL, - }, - }, - { - "2 / 2 • Ochránce", "Veřejný ochránce práv", - "Tip: ombudsman není soudce a neruší rozsudky.", - { - "Ombudsman chrání lidi před pochybením a nečinností úřadů.", - "Může věc prošetřit a žádat nápravu.", - "Nerozhoduje místo soudu a neukládá tresty.", - "Obrátit se na něj může člověk, který si neví rady s úřadem.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[10], "on2_unit11", "on2_unit11_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit11_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je podle Úmluvy o právech dítěte dítě?", - { - "Každý žák střední školy do maturity", - "Člověk mladší 18 let", - "Jen občan České republiky", - "Jen ten, kdo žije s rodiči", - }, - 4, 1}, - {"Co úmluva zvlášť zdůrazňuje?", - { - "Povinnost dítěte volit", - "Život, vzdělání a ochranu před násilím", - "Právo řídit obec", - "Povinnou práci od 14 let", - }, - 4, 1}, - {"Co dělá veřejný ochránce práv?", - { - "Prošetřuje pochybení úřadů", - "Ruší rozsudky trestních soudů", - "Jmenuje ministry", - "Schvaluje zákony", - }, - 4, 0}, - {"Může ombudsman uložit trest?", - { - "Ano, jako soudce", - "Ne", - "Ano, pokutu do milionu", - "Ano, pokud jde o dítě", - }, - 4, 1}, - }; - static const char *hints[] = { - "Hranicí je 18 let", - "Zájem dítěte a ochrana", - "Ombudsman není soud", - "Tresty ukládají soudy a správní orgány, ne ombudsman", - }; - return build_on2_mcq_page(10, "on2unit11", "on2_ex11_title", - "on2_quiz11_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit12_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Směry", "Čtyři klasické postoje", - "Tip: ideologie není totéž co jedna konkrétní strana.", - { - "Ideologie je soustava názorů na to, jak má vypadat společnost a stát.", - "Liberalismus staví na svobodě jednotlivce a na omezené moci státu.", - "Konzervatismus brání osvědčené pořádky a změny chce postupné.", - "Socialismus zdůrazňuje rovnost a silnější roli státu v hospodářství.", - NULL, - }, - }, - { - "2 / 2 • Mez", "Další směry a co demokracie nepřipouští", - "Tip: fašismus a nacismus jsou s ústavním pořádkem neslučitelné.", - { - "Nacionalismus staví národ na první místo a může být umírněný, nebo nepřátelský k jiným.", - "Environmentalismus klade důraz na ochranu přírody, feminismus na rovnost žen a mužů.", - "Anarchismus odmítá stát jako takový.", - "Fašismus a nacismus popírají demokracii a rovnost lidí.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[11], "on2_unit12", "on2_unit12_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit12_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co zdůrazňuje liberalismus?", - { - "Vládu jednoho vůdce", - "Svobodu jednotlivce", - "Zrušení voleb", - "Národ jako jedinou hodnotu", - }, - 4, 1}, - {"Co je typické pro konzervatismus?", - { - "Změna za každou cenu", - "Postupná změna a úcta k osvědčeným pořádkům", - "Odmítnutí státu", - "Zákaz tradice", - }, - 4, 1}, - {"Jsou fašismus a nacismus slučitelné s demokracií?", - { - "Ano, jsou jen další strany", - "Ne, popírají rovnost a demokratická pravidla", - "Ano, pokud vyhrají volby", - "Záleží na vlajce", - }, - 4, 1}, - {"Co je politická ideologie?", - { - "Jednací řád úřadu", - "Soustava názorů na uspořádání společnosti", - "Státní symbol", - "Druh daně", - }, - 4, 1}, - }; - static const char *hints[] = { - "Liberalismus hlídá svobodu a meze státu", - "Konzervatismus nespěchá se zlomy", - "Ústavní pořádek je nepřipouští", - "Ideologie je názorový celek, ne úřad", - }; - return build_on2_mcq_page(11, "on2unit12", "on2_ex12_title", - "on2_quiz12_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit13_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Strany", "K čemu je politická strana", - "Tip: občan se dívá na program, ne jen na heslo.", - { - "Strana sdružuje lidi s podobným programem a uchází se o hlasy.", - "V demokracii soutěží více stran a žádná nemá moc natrvalo zaručenou.", - "Strany se v čase mění, proto je důležitější program než naučený seznam názvů.", - "Jedna strana potřebuje ke vstupu do Sněmovny alespoň 5 procent hlasů.", - NULL, - }, - }, - { - "2 / 2 • Volby", "Právo volit a být volen", - "Tip: kdo nevolí, nechává rozhodnutí na ostatních.", - { - "Aktivní volební právo je právo volit, pasivní je právo být volen.", - "Do Sněmovny se volí poměrným systémem, do Senátu většinovým ve dvou kolech.", - "Prezident se volí přímo, nejvýše ve dvou kolech.", - "Do Parlamentu volí občané České republiky od 18 let; do obecního zastupitelstva mohou volit i občané EU s trvalým pobytem v obci.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[12], "on2_unit13", "on2_unit13_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit13_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu je politická strana?", - { - "Nahrazuje soud", - "Sdružuje lidi s programem a uchází se o hlasy", - "Vybírá daně", - "Jmenuje soudce", - }, - 4, 1}, - {"Jak se volí Poslanecká sněmovna?", - { - "Losem", - "Poměrným systémem", - "Jen většinově v jednom kole jako Senát", - "Vládou", - }, - 4, 1}, - {"Jak se volí Senát?", - { - "Poměrně jednou kandidátkou", - "Většinově ve dvou kolech", - "Prezidentem", - "Stejně jako evropský parlament", - }, - 4, 1}, - {"Od kolika let smí občan ČR volit do Parlamentu?", - { - "Od 15 let", - "Od 18 let", - "Od 21 let", - "Od 40 let", - }, - 4, 1}, - }; - static const char *hints[] = { - "Strana soutěží ve volbách", - "Hlasy se ve Sněmovně rozdělují poměrně", - "Senátní obvody jsou většinové", - "Aktivní právo je od 18 let", - }; - return build_on2_mcq_page(12, "on2unit13", "on2_ex13_title", - "on2_quiz13_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit14_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Spolky", "Lidé vedle státu", - "Tip: spolek není úřad.", - { - "Občanská společnost jsou lidé, kteří se sdružují nezávisle na státu.", - "Patří sem spolky, odbory, nadační organizace i místní iniciativy.", - "Není to úřad a není to totéž co politická strana, i když s nimi může jednat.", - "Hlídá moc, pomáhá a přináší témata, která stát sám nevidí.", - NULL, - }, - }, - { - "2 / 2 • Ctnosti", "Co demokracie potřebuje od lidí", - "Tip: ctnost není slepá poslušnost.", - { - "Patří sem odpovědnost, tolerance a respekt k právu.", - "Patří sem i ochota domluvit se a solidarita.", - "Občanská ctnost demokracii nepodrývá.", - "Angažovat se lze ve spolku, v obci i tím, že člověk neničí společné věci.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[13], "on2_unit14", "on2_unit14_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit14_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je občanská společnost?", - { - "Soubor ministerstev", - "Sdružování lidí nezávisle na státu", - "Jen Poslanecká sněmovna", - "Armáda", - }, - 4, 1}, - {"Je spolek státní úřad?", - { - "Ano", - "Ne", - "Ano, pokud má stanovy", - "Jen v kraji", - }, - 4, 1}, - {"Která vlastnost demokracii pomáhá?", - { - "Lhostejnost", - "Odpovědnost a tolerance", - "Pohrdání právem", - "Nenávist k menšině", - }, - 4, 1}, - {"Je slepá poslušnost občanská ctnost?", - { - "Ano, občan se neptá", - "Ne", - "Ano, pokud to řekne úřad", - "Jen ve škole", - }, - 4, 1}, - }; - static const char *hints[] = { - "Žije vedle státu, ne místo úřadů", - "Spolek je soukromé sdružení", - "Ctnosti drží soužití", - "Ctnost zahrnuje úsudek a respekt k právu", - }; - return build_on2_mcq_page(13, "on2unit14", "on2_ex14_title", - "on2_quiz14_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit15_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Pojmy", "Není to totéž", - "Tip: kritika vlády ještě není extremismus.", - { - "Radikální názor chce výraznou změnu a sám o sobě ještě nemusí rušit demokracii.", - "Extremismus popírá rovnost lidí nebo demokratická pravidla a často sahá k nenávisti.", - "Terorismus je násilí proti nezúčastněným, aby společnost dostala strach a politicky ustoupila.", - "Nesouhlas s vládou se v demokracii řeší argumentem a volbami.", - NULL, - }, - }, - { - "2 / 2 • Mez", "Proč to demokracii ohrožuje", - "Tip: symbol nenávistného hnutí není nevinný vtip.", - { - "Extremismus bere části lidí bezpečí a rovné postavení.", - "Propagace hnutí, které směřuje k potlačení práv a svobod, je nepřijatelná a může být trestná.", - "Extremistická symbolika na takové hnutí odkazuje.", - "Když parta tlačí k nenávisti, pomoc je u dospělého, ve škole nebo u policie.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[14], "on2_unit15", "on2_unit15_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit15_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Je každá ostrá kritika vlády extremismus?", - { - "Ano", - "Ne", - "Ano, pokud je v novinách", - "Ano, pokud kritik nevolil", - }, - 4, 1}, - {"Co je terorismus?", - { - "Pokojná demonstrace", - "Násilí proti nezúčastněným s cílem nahnat strach", - "Volební kampaň", - "Žaloba k soudu", - }, - 4, 1}, - {"Proč není extremistická symbolika nevinná?", - { - "Protože je drahá", - "Odkazuje na hnutí, která popírají práva a demokracii", - "Protože ji zakazuje škola bez zákona", - "Protože nepatří do módy", - }, - 4, 1}, - {"Kam se obrátit, když skupina tlačí k nenávisti?", - { - "Hlouběji do té skupiny", - "Na dospělého, školu nebo policii", - "Nikam, je to soukromá věc strany", - "Na autora symbolu s prosbou o radu", - }, - 4, 1}, - }; - static const char *hints[] = { - "Kritika patří k demokracii", - "Teror cílí na strach veřejnosti", - "Symbol nese program nenávisti", - "Pomoc je mimo tu skupinu", - }; - return build_on2_mcq_page(14, "on2unit15", "on2_ex15_title", - "on2_quiz15_head", qs, hints, 4); -} -static GtkWidget *build_on2_unit16_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Úloha", "Tisk, vysílání a internet", - "Tip: bez informací se moc špatně kontroluje.", - { - "Média jsou tisk, televize, rozhlas i internet.", - "Mají informovat, kontrolovat moc, komentovat a také bavit.", - "Svobodný přístup k informacím je pro demokracii nutný.", - "Veřejnoprávní médium má sloužit veřejnosti, soukromé žije i z reklamy a rozhodnutí vlastníků.", - NULL, - }, - }, - { - "2 / 2 • Kritika", "Jak se nenechat zmást", - "Tip: jedna sdílená zpráva ještě není důkaz.", - { - "Zpráva, komentář a reklama nejsou totéž.", - "Ptáme se, kdo informaci vydal a jaký k ní má zájem.", - "Ověření znamená podívat se i do dalšího zdroje.", - "Svoboda projevu má meze: pomluvu a navádění k násilí nechrání.", - NULL, - }, - }, - }; - - return build_on2_unit_page(&on2_lessons[15], "on2_unit16", "on2_unit16_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on2_unit16_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu jsou média v demokracii?", - { - "Jen k reklamě", - "Informovat a pomáhat kontrolovat moc", - "Nahrazovat soudy", - "Schvalovat zákony", - }, - 4, 1}, - {"Je komentář totéž co zpráva?", - { - "Ano", - "Ne, komentář je názor", - "Ano, pokud má titulek", - "Zpráva je vždy reklama", - }, - 4, 1}, - {"Jak si ověřit informaci?", - { - "Stačí počet sdílení", - "Podívat se na zdroj, zájem autora a další zdroj", - "Věřit nejhlasitějšímu titulku", - "Zeptat se jen toho, kdo ji poslal", - }, - 4, 1}, - {"Chrání svoboda projevu navádění k násilí?", - { - "Ano, bez výjimky", - "Ne", - "Ano, na internetu", - "Ano, pokud jde o politiku", - }, - 4, 1}, - }; - static const char *hints[] = { - "Informace a kontrola", - "Fakt a názor se rozlišují", - "Kritický přístup srovnává zdroje", - "Svoboda projevu má zákonné meze", - }; - return build_on2_mcq_page(15, "on2unit16", "on2_ex16_title", - "on2_quiz16_head", qs, hints, 4); -} - -void add_on2_pages(GtkStack *stack) { - typedef GtkWidget *(*OnBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - OnBuilder build_unit; - OnBuilder build_ex; - } pages[] = { - {"on2unit1", "on2ex1", build_on2_unit1_page, build_on2_unit1_exercise_page}, - {"on2unit2", "on2ex2", build_on2_unit2_page, build_on2_unit2_exercise_page}, - {"on2unit3", "on2ex3", build_on2_unit3_page, build_on2_unit3_exercise_page}, - {"on2unit4", "on2ex4", build_on2_unit4_page, build_on2_unit4_exercise_page}, - {"on2unit5", "on2ex5", build_on2_unit5_page, build_on2_unit5_exercise_page}, - {"on2unit6", "on2ex6", build_on2_unit6_page, build_on2_unit6_exercise_page}, - {"on2unit7", "on2ex7", build_on2_unit7_page, build_on2_unit7_exercise_page}, - {"on2unit8", "on2ex8", build_on2_unit8_page, build_on2_unit8_exercise_page}, - {"on2unit9", "on2ex9", build_on2_unit9_page, build_on2_unit9_exercise_page}, - {"on2unit10", "on2ex10", build_on2_unit10_page, build_on2_unit10_exercise_page}, - {"on2unit11", "on2ex11", build_on2_unit11_page, build_on2_unit11_exercise_page}, - {"on2unit12", "on2ex12", build_on2_unit12_page, build_on2_unit12_exercise_page}, - {"on2unit13", "on2ex13", build_on2_unit13_page, build_on2_unit13_exercise_page}, - {"on2unit14", "on2ex14", build_on2_unit14_page, build_on2_unit14_exercise_page}, - {"on2unit15", "on2ex15", build_on2_unit15_page, build_on2_unit15_exercise_page}, - {"on2unit16", "on2ex16", build_on2_unit16_page, build_on2_unit16_exercise_page} - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/obcanka3.c b/src/obcanka3.c deleted file mode 100644 index 431460a..0000000 --- a/src/obcanka3.c +++ /dev/null @@ -1,1910 +0,0 @@ -#include "graduately.h" - -/* Year 3 of Občanská nauka. - * Thematic unit "Člověk a právo" from the MŠMT model syllabus - * (č.j. 18 396/2002-23) and the SOV civic framework, which schools place - * in the third year. The economy, the world and philosophy are year 4. */ - -#define ON3_ENTRY(n) \ - { .n_slides = 2, .unit_page = "on3unit" #n, .ex_page = "on3ex" #n } - -NetLesson on3_lessons[ON3_LESSONS] = { - ON3_ENTRY(1), - ON3_ENTRY(2), - ON3_ENTRY(3), - ON3_ENTRY(4), - ON3_ENTRY(5), - ON3_ENTRY(6), - ON3_ENTRY(7), - ON3_ENTRY(8), - ON3_ENTRY(9), - ON3_ENTRY(10), - ON3_ENTRY(11), - ON3_ENTRY(12), - ON3_ENTRY(13), - ON3_ENTRY(14), - ON3_ENTRY(15), - ON3_ENTRY(16), -}; - -#undef ON3_ENTRY - -GtkWidget *on3_scroll; -GtkWidget *on3_fixed; -GtkWidget *on3_rail; -GtkWidget *on3_nodes[ON3_UNITS]; -GtkWidget *on3_labels[ON3_UNITS]; -double on3_cx[ON3_UNITS]; -double on3_cy[ON3_UNITS]; -int on3_cols = 1; -int on3_rows = 1; -int on3_cw = (int)(2.0 * ROAD_MX + (ON3_UNITS - 1) * PATH_SPAC); -int on3_ch = (int)(2.0 * ROAD_MY); -guint on3_idle; -double on3_last_avail = -1.0; -int on3_last_cols = -1; -int on3_last_rows = -1; -int on3_last_cw = -1; -int on3_last_ch = -1; -cairo_surface_t *on3_rail_cache; -int on3_cache_w; -int on3_cache_h; - -static void on3_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= ON3_UNITS - 1) { k = ON3_UNITS - 2; u = 1.0; } - - p1x = on3_cx[k]; p1y = on3_cy[k]; - p2x = on3_cx[k + 1]; p2y = on3_cy[k + 1]; - if (k - 1 >= 0) { p0x = on3_cx[k - 1]; p0y = on3_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < ON3_UNITS) { p3x = on3_cx[k + 2]; p3y = on3_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -static void on3_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 24.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - on3_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - on3_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -static void on3_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(ON3_UNITS - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= ON3_UNITS; rows++) { - int cols = (ON3_UNITS + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > ON3_UNITS) - rows = ON3_UNITS; - on3_rows = rows; - on3_cols = (ON3_UNITS + rows - 1) / rows; - if (on3_cols < 1) - on3_cols = 1; - on3_cw = (int)(2.0 * ROAD_MX + (on3_cols - 1) * PATH_SPAC); - on3_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * on3_cols; - int len = MIN(on3_cols, ON3_UNITS - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (on3_cols - 1 - c); - on3_cx[i] = ROAD_MX + cc * PATH_SPAC; - on3_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -static void on3_apply_layout(void) { - if (!on3_fixed) - return; - - if (on3_cols == on3_last_cols && on3_rows == on3_last_rows && - on3_cw == on3_last_cw && on3_ch == on3_last_ch) - return; - - on3_last_cols = on3_cols; - on3_last_rows = on3_rows; - on3_last_cw = on3_cw; - on3_last_ch = on3_ch; - if (on3_rail_cache) { - cairo_surface_destroy(on3_rail_cache); - on3_rail_cache = NULL; - } - - for (int i = 0; i < ON3_UNITS; i++) { - if (!on3_nodes[i] || !on3_labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(on3_fixed), on3_nodes[i], - (int)(on3_cx[i] - NODE_SIZE / 2.0), - (int)(on3_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(on3_fixed), on3_labels[i], - (int)(on3_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(on3_cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(on3_fixed, on3_cw, on3_ch); - gtk_widget_set_size_request(on3_rail, on3_cw, on3_ch); - gtk_fixed_move(GTK_FIXED(on3_fixed), on3_rail, 0, 0); - gtk_widget_queue_draw(on3_rail); -} - -static void on3_relayout(void) { - GtkAdjustment *hadj; - double avail; - - if (!on3_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(on3_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - on3_last_avail) < 1.0) - return; - on3_last_avail = avail; - on3_geometry(avail); - on3_apply_layout(); -} - -static gboolean on3_relayout_idle(gpointer data) { - (void)data; - on3_idle = 0; - on3_relayout(); - return G_SOURCE_REMOVE; -} - -static void on3_relayout_later(void) { - if (on3_idle == 0) - on3_idle = g_idle_add(on3_relayout_idle, NULL); -} - -static void on3_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - (void)data; - on3_relayout_later(); -} - -static void on3_render_rail_to(cairo_t *cr) { - const double t_end = (double)(ON3_UNITS - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - on3_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - on3_path(cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -static void on3_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - (void)area; - (void)width; - (void)height; - (void)data; - - if (!on3_rail_cache || on3_cache_w != on3_cw || on3_cache_h != on3_ch) { - cairo_t *rcr; - - if (on3_rail_cache) - cairo_surface_destroy(on3_rail_cache); - on3_cache_w = on3_cw; - on3_cache_h = on3_ch; - if (on3_cache_w < 1) - on3_cache_w = 1; - if (on3_cache_h < 1) - on3_cache_h = 1; - on3_rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - on3_cache_w, on3_cache_h); - rcr = cairo_create(on3_rail_cache); - on3_render_rail_to(rcr); - cairo_destroy(rcr); - } - - cairo_set_source_surface(cr, on3_rail_cache, 0, 0); - cairo_paint(cr); -} - -void on3_rail_theme_reset(void) { - if (on3_rail_cache) { - cairo_surface_destroy(on3_rail_cache); - on3_rail_cache = NULL; - } - if (on3_rail) - gtk_widget_queue_draw(on3_rail); -} - -static void on3_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof(name), "on3_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static void on3_add_node(GtkFixed *fixed, int index) { - int num = index + 1; - gboolean locked = index >= ON3_LESSONS; - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - static char unit_keys[ON3_LESSONS][16]; - static gboolean unit_keys_ready = FALSE; - - if (!unit_keys_ready) { - for (int i = 0; i < ON3_LESSONS; i++) - g_snprintf(unit_keys[i], sizeof unit_keys[i], "on3_unit%d", i + 1); - unit_keys_ready = TRUE; - } - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_sensitive(card, !locked); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - if (locked) - gtk_widget_add_css_class(card, "locked"); - else - gtk_widget_add_css_class(card, "current"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", num); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - if (locked) { - icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 16); - gtk_box_append(GTK_BOX(vbox), icon); - } else { - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - on3_lessons[index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(on3_open_unit), - &on3_lessons[index]); - } - - on3_nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - if (index < ON3_LESSONS) { - i18n_bind(name, unit_keys[index], 0); - } else { - gtk_widget_add_css_class(name, "unit-name-locked"); - } - on3_labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} -GtkWidget *build_on3map_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - - on3_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("onyears", "on_year3", "on3_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - on3_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, on3_cw, on3_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - on3_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, on3_cw, on3_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), on3_draw_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - on3_rail = rail; - - for (int i = 0; i < ON3_UNITS; i++) - on3_add_node(GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(on3_adjust_notify), NULL); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(on3_adjust_notify), NULL); - - on3_apply_layout(); - on3_relayout_later(); - refresh_on3_completion_ui(); - - return page; -} - -static void on3_slide_apply(NetLesson *L); -static void on3_slide_prev(GtkButton *button, gpointer data); -static void on3_slide_next(GtkButton *button, gpointer data); - -static int on3_note_last_w = -1; - -static void on3_rescale_notes_at(int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < ON3_LESSONS; i++) - net_rescale_lesson_notes(&on3_lessons[i], body, head, kick); -} - -static gboolean on3_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width != on3_note_last_w) { - on3_note_last_w = width; - on3_rescale_notes_at(width); - } - return G_SOURCE_CONTINUE; -} - -static GtkWidget *build_on3_unit_page(NetLesson *L, const char *title_key, - const char *sub_key, - const NetSlide *slides, guint n_slides) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar("on3map", title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "on3_slide%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, on3_note_tick, NULL, NULL); - on3_note_last_w = -1; - on3_rescale_notes_at(0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(on3_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(on3_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - on3_slide_apply(L); - return page; -} - -static void on3_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "on3_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void on3_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx > 0) { - L->idx--; - on3_slide_apply(L); - } -} - -static void on3_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - on3_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -void on3_lessons_apply_lang(void) { - for (int i = 0; i < ON3_LESSONS; i++) - on3_slide_apply(&on3_lessons[i]); -} - -static void on3_mcq_check(GtkButton *button, gpointer data) { - NetMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_on3_done(ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -static GtkWidget *build_on3_mcq_page(int lesson_id, const char *back_page, - const char *title_key, - const char *heading_key, - const ChoiceQ *qs, const char **hints, - int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - NetMcqCtx *ctx = g_new0(NetMcqCtx, 1); - int n_opts = qs[0].n_options; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(on3_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - - return page; -} -static GtkWidget *build_on3_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Právo", "Pravidla, která stát vynutí", - "Tip: ne každé neslušné jednání je nezákonné.", - { - "Právo je soubor pravidel, která může stát vynutit.", - "Morálka říká, co je slušné. Právo říká, co je závazné.", - "Obojí se často kryje, ale není to totéž.", - "Bez vynutitelného práva by rozhodovala síla, ne pravidlo.", - NULL, - }, - }, - { - "2 / 2 • Spravedlnost", "Podobné případy podobně", - "Tip: spravedlnost je cíl práva, ne jeho automatický výsledek.", - { - "Spravedlnost chce, aby se podobné případy posuzovaly podobně.", - "Právo má chránit slabšího před svévolí silnějšího.", - "Sankce následuje, když někdo pravidlo poruší.", - "Třetí ročník bere právní řád, soudy, smlouvy, rodinu, práci a tresty.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[0], "on3_unit1", "on3_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je právo?", - { - "Jen dobré mravy", - "Soubor pravidel, která může stát vynutit", - "Názor většiny na sociálních sítích", - "Zvyk jedné rodiny", - }, - 4, 1}, - {"Je morálka totéž co právo?", - { - "Ano", - "Ne, často se kryjí, ale nejsou totéž", - "Morálka je vždy přísnější zákon", - "Právo je jen náboženství", - }, - 4, 1}, - {"K čemu spravedlnost v právu směřuje?", - { - "Aby vyhrál hlasitější", - "Aby se podobné případy posuzovaly podobně", - "Aby trest byl vždy nejvyšší", - "Aby soudil ten, kdo je u moci", - }, - 4, 1}, - {"Co by bez vynutitelného práva rozhodovalo?", - { - "Síla", - "Los", - "Školní řád", - "Anketa", - }, - 4, 0}, - }; - static const char *hints[] = { - "Právo je vynutitelné státní mocí", - "Slušnost a zákon se nemusí krýt", - "Stejné se má měřit stejným metrem", - "Právo má nahradit právo silnějšího", - }; - return build_on3_mcq_page(0, "on3unit1", "on3_ex1_title", - "on3_quiz1_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Vázanost", "I stát má meze", - "Tip: úřad smí jen to, co mu dovoluje zákon.", - { - "V právním státě je právem vázán i stát, ne jen občan.", - "Úřad smí zasahovat do práv člověka jen tam, kde mu to zákon dovolí.", - "Moc se dělí, aby ji nikdo neužíval bez kontroly.", - "Soudy mají být nezávislé na vládě a na politicích.", - NULL, - }, - }, - { - "2 / 2 • Ochrana", "Kam se člověk obrátí", - "Tip: právní stát stojí na tom, že se práva dá dovolat.", - { - "Člověk se může domáhat ochrany u nezávislého soudu.", - "Rozhodnutí úřadu má být přezkoumatelné.", - "Nikdo nesmí být trestán bez zákona, který čin už předtím zakazoval.", - "Právní stát není stát bez pravidel. Je to stát, který svá pravidla sám dodržuje.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[1], "on3_unit2", "on3_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je v právním státě vázán právem?", - { - "Jen občané", - "I stát", - "Jen cizinci", - "Jen firmy", - }, - 4, 1}, - {"Kdy smí úřad zasáhnout do práv člověka?", - { - "Kdykoli se mu to hodí", - "Jen když mu to dovoluje zákon", - "Když o to požádá soused", - "Když to schválí starosta ústně", - }, - 4, 1}, - {"Jakou roli mají soudy?", - { - "Plnit pokyny ministra", - "Rozhodovat nezávisle", - "Psát zákony místo Parlamentu", - "Vybírat daně", - }, - 4, 1}, - {"Lze trestat čin, který v době spáchání zákon nezakazoval?", - { - "Ano, zpětně", - "Ne", - "Ano, pokud šlo o přestupek školy", - "Ano, rozhodnutím vlády", - }, - 4, 1}, - }; - static const char *hints[] = { - "Právo váže i veřejnou moc", - "Veřejná moc jedná podle zákona", - "Nezávislost soudů je součást právního státu", - "Nullum crimen sine lege", - }; - return build_on3_mcq_page(1, "on3unit2", "on3_ex2_title", - "on3_quiz2_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Pyramida", "Co stojí nad čím", - "Tip: nižší předpis nesmí odporovat vyššímu.", - { - "Nejvýš stojí ústavní zákony, včetně Ústavy a Listiny.", - "Pod nimi jsou zákony, pak nařízení vlády a vyhlášky ministerstev.", - "Obec a kraj mohou vydávat vyhlášky jen v mezích zákona.", - "Platné předpisy se vyhlašují ve Sbírce zákonů.", - NULL, - }, - }, - { - "2 / 2 • Odvětví", "Veřejné a soukromé právo", - "Tip: trestní právo je veřejné, kupní smlouva je soukromé.", - { - "Veřejné právo chrání zájem celku. Patří sem třeba trestní a správní právo.", - "Soukromé právo upravuje vztahy mezi lidmi. Patří sem občanské, rodinné a pracovní právo.", - "Když si předpisy odporují, použije se ten vyšší.", - "Neznalost zákona neomlouvá, proto se předpisy zveřejňují.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[2], "on3_unit3", "on3_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co stojí v právním řádu nejvýš?", - { - "Obecní vyhláška", - "Ústavní zákony", - "Nařízení vlády", - "Vnitřní pokyn úřadu", - }, - 4, 1}, - {"Smí vyhláška ministerstva zrušit zákon?", - { - "Ano", - "Ne, nižší předpis nesmí odporovat vyššímu", - "Ano, pokud ji podepíše ministr", - "Ano, na jeden rok", - }, - 4, 1}, - {"Kam patří trestní právo?", - { - "Do soukromého práva", - "Do veřejného práva", - "Mimo právní řád", - "Jen do školního řádu", - }, - 4, 1}, - {"Kde se právní předpisy vyhlašují?", - { - "Ve Sbírce zákonů", - "Jen na nástěnce obce", - "Jen v televizi", - "V notářském zápisu", - }, - 4, 0}, - }; - static const char *hints[] = { - "Ústava a Listina jsou nad zákony", - "Pyramida předpisů se nepřeskakuje", - "Trestní právo chrání společnost", - "Bez vyhlášení předpis nezavazuje", - }; - return build_on3_mcq_page(2, "on3unit3", "on3_ex3_title", - "on3_quiz3_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Osoby", "Kdo může mít práva", - "Tip: právnická osoba není člověk, ale právo s ní jedná.", - { - "Fyzická osoba je člověk.", - "Právnická osoba je třeba firma, spolek, obec nebo stát.", - "Právní osobnost má člověk od narození: může mít práva a povinnosti.", - "Právní vztah spojuje subjekty právy a povinnostmi.", - NULL, - }, - }, - { - "2 / 2 • Věk", "Svéprávnost a trestní odpovědnost", - "Tip: patnáct let ještě není plná svéprávnost.", - { - "Svéprávnost je způsobilost sám právně jednat.", - "Plná svéprávnost přichází zletilostí v 18 letech.", - "Soud může svéprávnost z vážných důvodů omezit.", - "Trestně odpovědný je člověk od 15 let, je-li příčetný.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[3], "on3_unit4", "on3_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je fyzická osoba?", - { - "Firma", - "Člověk", - "Úřad", - "Smlouva", - }, - 4, 1}, - {"Od kdy má člověk právní osobnost?", - { - "Od 18 let", - "Od narození", - "Od 15 let", - "Od první smlouvy", - }, - 4, 1}, - {"Kdy nastává plná svéprávnost?", - { - "V 15 letech", - "Zletilostí v 18 letech", - "Nástupem do práce", - "Zápisem do občanského průkazu", - }, - 4, 1}, - {"Od kolika let je člověk trestně odpovědný?", - { - "Od 18 let", - "Od 15 let, je-li příčetný", - "Od 10 let", - "Až od první výplaty", - }, - 4, 1}, - }; - static const char *hints[] = { - "Fyzická osoba je člověk", - "Práva může mít i dítě", - "Svéprávnost je způsobilost jednat", - "Pod 15 let trestní odpovědnost není", - }; - return build_on3_mcq_page(3, "on3unit4", "on3_ex4_title", - "on3_quiz4_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Věc", "Co vlastník smí", - "Tip: vlastnictví není bez mezí.", - { - "Vlastník věc drží, užívá a může s ní nakládat.", - "Zákon ho omezuje, třeba kvůli sousedům.", - "Vyvlastnit lze jen ve veřejném zájmu, na základě zákona a za náhradu.", - "Duševní vlastnictví chrání třeba autorské dílo nebo ochrannou známku.", - NULL, - }, - }, - { - "2 / 2 • Škoda", "Kdo ji nahradí", - "Tip: cizí dílo se nesmí jen tak zkopírovat.", - { - "Kdo způsobí škodu, má ji zpravidla nahradit.", - "Škoda může být na věci, na zdraví i v penězích, o které člověk přišel.", - "Náhrada má uvést stav co nejblíž tomu, jaký byl před škodou.", - "U autora se bere i to, že dílo někdo užije bez svolení.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[4], "on3_unit5", "on3_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co vlastník se svou věcí smí?", - { - "Jen se na ni dívat", - "Držet ji, užívat ji a nakládat s ní", - "Jen ji půjčovat státu", - "Nic, dokud ji nepojistí", - }, - 4, 1}, - {"Lze v České republice vyvlastnit bez náhrady?", - { - "Ano, kdykoli", - "Ne, jen ve veřejném zájmu, podle zákona a za náhradu", - "Ano, rozhodnutím souseda", - "Ano, pokud jde o auto", - }, - 4, 1}, - {"Co chrání duševní vlastnictví?", - { - "Jen pozemky", - "Třeba autorské dílo", - "Jen hotovost", - "Jen nemovitosti v katastru", - }, - 4, 1}, - {"Kdo má zpravidla nahradit způsobenou škodu?", - { - "Stát vždy", - "Ten, kdo ji způsobil", - "Poškozený sám", - "Soused", - }, - 4, 1}, - }; - static const char *hints[] = { - "Vlastnictví zahrnuje držbu, užívání i nakládání", - "Vyvlastnění má přísné podmínky", - "Dílo není totéž co hmotná věc", - "Škůdce škodu nahrazuje", - }; - return build_on3_mcq_page(4, "on3unit5", "on3_ex5_title", - "on3_quiz5_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Vůle", "Smlouva zavazuje", - "Tip: ústní smlouva může platit, ale hůř se dokazuje.", - { - "Smlouva je souhlasný projev vůle dvou nebo více stran.", - "Strany si sjednají, kdo, co a za jakých podmínek plní.", - "Platná smlouva zavazuje. Nelze od ní odejít jen proto, že se to přestalo hodit.", - "Zákon u některých smluv žádá písemnou formu.", - NULL, - }, - }, - { - "2 / 2 • Druhy", "Koupě, nájem, dar a dílo", - "Tip: dům se nepřevede jen podáním ruky.", - { - "Kupní smlouvou přechází věc za kupní cenu.", - "Nájem přenechává věc k dočasnému užívání za nájemné.", - "Darování je bezúplatné. Smlouvou o dílo se zhotoví, opraví nebo upraví věc.", - "Vlastnictví k nemovitosti se zapisuje do katastru.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[5], "on3_unit6", "on3_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je smlouva?", - { - "Jednostranný rozkaz úřadu", - "Souhlasný projev vůle, který strany zavazuje", - "Reklama", - "Ústní slib bez obsahu", - }, - 4, 1}, - {"Lze od každé smlouvy odejít, když se to přestane hodit?", - { - "Ano", - "Ne, platná smlouva zavazuje", - "Ano, do hodiny", - "Ano, pokud druhá strana nesouhlasí", - }, - 4, 1}, - {"Co je nájem?", - { - "Darování věci", - "Dočasné užívání věci za nájemné", - "Trest za škodu", - "Převod nemovitosti darem", - }, - 4, 1}, - {"Kam se zapisuje vlastnictví k nemovitosti?", - { - "Do občanského průkazu", - "Do katastru nemovitostí", - "Jen do smlouvy v šuplíku", - "Na finanční úřad", - }, - 4, 1}, - }; - static const char *hints[] = { - "Smlouva stojí na shodě stran", - "Závazek se plní", - "Nájem není převod vlastnictví", - "U nemovitosti rozhoduje vklad do katastru", - }; - return build_on3_mcq_page(5, "on3unit6", "on3_ex6_title", - "on3_quiz6_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Ochrana", "Slabší strana smlouvy", - "Tip: spotřebitel je člověk, který nejedná jako podnikatel.", - { - "Spotřebitel uzavírá smlouvu s podnikatelem mimo své podnikání.", - "Zákon ho chrání, protože podnikatel zná podmínky líp.", - "Nekalé obchodní praktiky a klamavá reklama jsou zakázané.", - "Smlouva nemá schovávat podstatné podmínky do nečitelného textu.", - NULL, - }, - }, - { - "2 / 2 • Reklamace", "Vada a čtrnáct dnů", - "Tip: účtenka pomáhá, ale není jediný důkaz koupě.", - { - "Vadu zboží nebo služby lze reklamovat u prodávajícího.", - "Smlouvu sjednanou po internetu nebo po telefonu lze často zrušit do 14 dnů.", - "Výjimkou je třeba zboží vyrobené na míru nebo rychle se kazící věc.", - "Když obchodník neplní, pomáhá Česká obchodní inspekce.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[6], "on3_unit7", "on3_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je spotřebitel?", - { - "Každá firma", - "Člověk, který s podnikatelem nejedná ve svém podnikání", - "Jen nezletilý", - "Jen vlastník obchodu", - }, - 4, 1}, - {"Co je reklamace?", - { - "Darování věci", - "Uplatnění vady zboží nebo služby", - "Výpověď z práce", - "Žaloba na souseda", - }, - 4, 1}, - {"Dokdy lze často odstoupit od smlouvy uzavřené po internetu?", - { - "Do 14 dnů", - "Do druhého dne", - "Do jednoho roku vždy", - "Nelze nikdy", - }, - 4, 0}, - {"Kdo pomáhá, když obchodník spotřebiteli neplní?", - { - "Česká obchodní inspekce", - "Jen školní parlament", - "Katastr nemovitostí", - "Česká národní banka u každého nákupu", - }, - 4, 0}, - }; - static const char *hints[] = { - "Spotřebitel je slabší strana", - "Reklamace se obrací na prodávajícího", - "U smluv na dálku běží čtrnáctidenní lhůta", - "ČOI dohlíží na ochranu spotřebitele", - }; - return build_on3_mcq_page(6, "on3unit7", "on3_ex7_title", - "on3_quiz7_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Nabytí", "Zákon, nebo závěť", - "Tip: dědictví lze odmítnout.", - { - "Dědí se podle závěti, a kde závěť není, podle zákona.", - "Ze zákona dědí především děti, manžel nebo partner a další blízcí.", - "Pozůstalost projednává notář jako soudní komisař.", - "Dědic může dědictví odmítnout. Odmítnutí se nedá jen tak vzít zpět.", - NULL, - }, - }, - { - "2 / 2 • Dluhy", "Soupis pozůstalosti", - "Tip: dědictví nejsou jen věci, ale i dluhy.", - { - "S majetkem mohou přejít i dluhy zůstavitele.", - "Bez soupisu může dědic ručit i nad hodnotu toho, co nabyl.", - "Požádá-li o soupis pozůstalosti, hradí dluhy jen do výše nabytého majetku.", - "Proto se před přijetím vyplatí vědět, co v pozůstalosti je.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[7], "on3_unit8", "on3_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Podle čeho se dědí, když není závěť?", - { - "Podle losu", - "Podle zákona", - "Podle přání sousedů", - "Majetek propadá vždy obci", - }, - 4, 1}, - {"Kdo projednává pozůstalost?", - { - "Notář", - "Starosta", - "Zaměstnavatel", - "Škola", - }, - 4, 0}, - {"Lze dědictví odmítnout?", - { - "Ne", - "Ano", - "Jen nemovitost", - "Jen se souhlasem věřitele", - }, - 4, 1}, - {"K čemu je soupis pozůstalosti?", - { - "Aby se dluhy hradily jen do výše nabytého majetku", - "Aby dědic přišel o všechno", - "Aby se závěť zrušila", - "Aby se dědictví nedalo odmítnout", - }, - 4, 0}, - }; - static const char *hints[] = { - "Zákon určuje okruh dědiců", - "Notář jedná jako soudní komisař", - "Odmítnutí je právo dědice", - "Soupis omezuje rozsah dluhů", - }; - return build_on3_mcq_page(7, "on3unit8", "on3_ex8_title", - "on3_quiz8_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit9_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Svazek", "Manželství a partnerství", - "Tip: partnerství z roku 2025 není totéž co staré registrované partnerství.", - { - "Manželství je trvalý svazek muže a ženy.", - "Uzavírá se svobodně, zpravidla od 18 let. Výjimečně od 16 let se souhlasem soudu.", - "Dva lidé stejného pohlaví mohou od roku 2025 uzavřít partnerství.", - "Partnerství se v řadě práv podobá manželství. Dřívější registrovaná partnerství zůstávají v platnosti.", - NULL, - }, - }, - { - "2 / 2 • Dítě", "Péče, výživa a náhradní výchova", - "Tip: pěstoun není totéž co osvojitel.", - { - "Rodiče mají o dítě pečovat, zastupovat je a živit je.", - "Dítě má právo být slyšeno ve věcech, které se ho týkají.", - "Osvojením se dítě přijímá za vlastní. Pěstoun o něj pečuje, když nemůže být u rodičů.", - "Poručník dítě zastupuje, když to rodiče nemohou.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[8], "on3_unit9", "on3_unit9_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit9_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je manželství podle občanského zákoníku?", - { - "Jakýkoli společný byt", - "Trvalý svazek muže a ženy", - "Pracovní smlouva", - "Smlouva o nájmu", - }, - 4, 1}, - {"Co mohou od roku 2025 uzavřít dva lidé stejného pohlaví?", - { - "Nic", - "Partnerství", - "Jen pracovní poměr", - "Už jen registrované partnerství jako dřív", - }, - 4, 1}, - {"Od kolika let lze zpravidla uzavřít manželství?", - { - "Od 15 let", - "Od 18 let", - "Od 21 let", - "Od 16 let bez další podmínky", - }, - 4, 1}, - {"Čím se liší pěstoun od osvojitele?", - { - "Pěstoun o dítě pečuje, osvojení je přijímá za vlastní", - "Ničím", - "Pěstoun je vždy poručník soudu", - "Osvojitel jen platí nájem", - }, - 4, 0}, - }; - static const char *hints[] = { - "Manželství je svazek muže a ženy", - "Nové registrované partnerství se už neuzavírá", - "Šestnáct let jen výjimečně se souhlasem soudu", - "Osvojení mění právní vztah rodiče a dítěte", - }; - return build_on3_mcq_page(8, "on3unit9", "on3_ex9_title", - "on3_quiz9_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit10_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Smlouva", "Vznik pracovního poměru", - "Tip: zkušební doba musí být písemná.", - { - "Pracovní smlouva určí druh práce, místo výkonu a den nástupu.", - "Uzavírá se písemně.", - "Zkušební doba smí trvat nejvýše 4 měsíce, u vedoucího zaměstnance 8 měsíců.", - "Ve zkušební době lze poměr zrušit i bez důvodu, ne však v prvních 14 dnech neschopnosti.", - NULL, - }, - }, - { - "2 / 2 • Konec", "Výpověď a bezpečná práce", - "Tip: zaměstnavatel si důvod výpovědi nesmí vymyslet.", - { - "Zaměstnanec může dát výpověď z jakéhokoli důvodu.", - "Zaměstnavatel jen ze zákonných důvodů, třeba organizačních nebo pro porušení povinností.", - "Výpovědní doba trvá nejméně dva měsíce a začíná dnem doručení.", - "Zaměstnanec má právo na mzdu, odpočinek, dovolenou a bezpečnou práci.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[9], "on3_unit10", "on3_unit10_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit10_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co musí pracovní smlouva určit?", - { - "Jen výši prémií", - "Druh práce, místo a den nástupu", - "Jméno manžela", - "Číslo občanského průkazu rodičů", - }, - 4, 1}, - {"Jak dlouhá smí být zkušební doba řadového zaměstnance?", - { - "Nejvýše 4 měsíce", - "Nejvýše jeden rok", - "Bez omezení", - "Jen jeden týden", - }, - 4, 0}, - {"Kdy smí zaměstnavatel dát výpověď?", - { - "Z jakéhokoli důvodu", - "Jen ze zákonných důvodů", - "Jen ústně na chodbě", - "Nikdy", - }, - 4, 1}, - {"Jak dlouhá je základní výpovědní doba?", - { - "Jeden týden", - "Nejméně dva měsíce", - "Půl roku vždy", - "Do konce směny", - }, - 4, 1}, - }; - static const char *hints[] = { - "To jsou podstatné náležitosti", - "U vedoucího je mez osm měsíců", - "Důvody výpovědi stanoví zákoník práce", - "Běží ode dne doručení výpovědi", - }; - return build_on3_mcq_page(9, "on3unit10", "on3_ex10_title", - "on3_quiz10_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit11_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Stupně", "Od okresního soudu výš", - "Tip: Ústavní soud není další odvolací stupeň.", - { - "Nejblíž lidem jsou okresní soudy. V Praze se jim říká obvodní.", - "Nad nimi jsou krajské soudy. V Praze je to Městský soud.", - "Vrchní soudy sídlí v Praze a v Olomouci.", - "Nejvyšší soud sjednocuje rozhodování obecných soudů.", - NULL, - }, - }, - { - "2 / 2 • Mimo řadu", "Správní a ústavní soudnictví", - "Tip: každý soudce je nezávislý.", - { - "Žaloby proti rozhodnutím úřadů řeší správní soudy.", - "Na vrcholu správního soudnictví je Nejvyšší správní soud.", - "Ústavní soud stojí mimo tuto soustavu a hlídá ústavní pořádek.", - "Soudce není podřízený ministrovi ani politikovi.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[10], "on3_unit11", "on3_unit11_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit11_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jak se jmenuje první stupeň soudů v Praze?", - { - "Krajský soud", - "Obvodní soudy", - "Vrchní soud", - "Ústavní soud", - }, - 4, 1}, - {"Kde sídlí vrchní soudy?", - { - "V Brně a Ostravě", - "V Praze a Olomouci", - "Jen v Praze", - "V každém kraji", - }, - 4, 1}, - {"Kdo završuje správní soudnictví?", - { - "Nejvyšší správní soud", - "Obecní úřad", - "Poslanecká sněmovna", - "Notářská komora", - }, - 4, 0}, - {"Je Ústavní soud běžný odvolací soud?", - { - "Ano, je nad každým rozsudkem automaticky", - "Ne, stojí mimo soustavu obecných soudů", - "Ano, nahrazuje okresní soud", - "Ano, rozhoduje každou pokutu", - }, - 4, 1}, - }; - static const char *hints[] = { - "Mimo Prahu jsou to okresní soudy", - "Vrchní soudy jsou dva", - "Správní soudy přezkoumávají úřady", - "Ústavní soud hlídá ústavní pořádek", - }; - return build_on3_mcq_page(10, "on3unit11", "on3_ex11_title", - "on3_quiz11_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit12_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Žaloba", "Občanské soudní řízení", - "Tip: kdo žaluje, je žalobce. Koho žaluje, je žalovaný.", - { - "Občanské soudní řízení začíná zpravidla žalobou.", - "Žalobce se domáhá svého práva proti žalovanému.", - "Soud vyslechne obě strany a rozhodne rozsudkem, nebo řízení jinak skončí.", - "Proti rozsudku je odvolání. Dovolání k Nejvyššímu soudu je výjimečné.", - NULL, - }, - }, - { - "2 / 2 • Úřad", "Správní řízení", - "Tip: odvolání je řádný opravný prostředek.", - { - "Správní řízení vede úřad, třeba když vydává povolení nebo ukládá povinnost.", - "Řídí se správním řádem.", - "Proti rozhodnutí se lze odvolat k nadřízenému úřadu.", - "Když to nepomůže, zbývá žaloba ke správnímu soudu.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[11], "on3_unit12", "on3_unit12_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit12_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je žalobce?", - { - "Soudce", - "Ten, kdo se žalobou domáhá svého práva", - "Svědek", - "Každý, kdo sedí v síni", - }, - 4, 1}, - {"Čím občanské soudní řízení zpravidla začíná?", - { - "Výpovědí", - "Žalobou", - "Závětí", - "Reklamací v obchodě", - }, - 4, 1}, - {"Co je odvolání?", - { - "Nová pracovní smlouva", - "Řádný opravný prostředek proti rozhodnutí", - "Odmítnutí dědictví", - "Stížnost na počasí", - }, - 4, 1}, - {"Kam se lze obrátit, když neuspěje odvolání proti úřadu?", - { - "Ke správnímu soudu", - "Do katastru", - "K zaměstnavateli", - "Na obecnou nástěnku", - }, - 4, 0}, - }; - static const char *hints[] = { - "Žalovaný je ten, proti komu žaloba míří", - "Žaloba otevírá spor", - "Odvolání přezkoumá vyšší stupeň", - "Správní soud přezkoumává rozhodnutí úřadu", - }; - return build_on3_mcq_page(11, "on3unit12", "on3_ex12_title", - "on3_quiz12_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit13_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Soud a žaloba", "Kdo rozhoduje a kdo žaluje", - "Tip: advokát není soudce.", - { - "Soudce je nezávislý, nestranný a spor rozhoduje.", - "Státní zástupce podává obžalobu a ve veřejném zájmu hlídá zákonnost trestního řízení.", - "Advokát zastupuje klienta a váže ho povinnost mlčenlivosti.", - "Kdo si advokáta nemůže dovolit, může v zákonem daných případech dostat právní pomoc.", - NULL, - }, - }, - { - "2 / 2 • Listiny", "Notář a exekutor", - "Tip: exekutor nevymýšlí dluh, vymáhá už uloženou povinnost.", - { - "Notář sepisuje veřejné listiny a projednává dědictví.", - "Veřejná listina má silnější důkazní váhu než obyčejné potvrzení.", - "Exekutor vymáhá splnění rozhodnutí, když je dlužník sám neplní.", - "Veřejný ochránce práv není soudce a rozsudky neruší.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[12], "on3_unit13", "on3_unit13_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit13_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo v trestním řízení podává obžalobu?", - { - "Advokát obžalovaného", - "Státní zástupce", - "Notář", - "Starosta", - }, - 4, 1}, - {"Čím je vázán advokát?", - { - "Pokyny protistrany", - "Povinností mlčenlivosti vůči klientovi", - "Příkazem ministra v každém sporu", - "Ničím", - }, - 4, 1}, - {"Kdo projednává dědictví?", - { - "Exekutor", - "Notář", - "Policie vždy", - "Zaměstnavatel", - }, - 4, 1}, - {"Co dělá exekutor?", - { - "Ruší zákony", - "Vymáhá splnění uložené povinnosti", - "Uzavírá manželství", - "Rozhoduje o vině v trestním řízení", - }, - 4, 1}, - }; - static const char *hints[] = { - "Státní zástupce žaluje ve veřejném zájmu", - "Advokát hájí klienta, ne úřad", - "Notář je soudní komisař", - "Exekuce není nový soud o vině", - }; - return build_on3_mcq_page(12, "on3unit13", "on3_ex13_title", - "on3_quiz13_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit14_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Rozdíl", "Závažnost rozhoduje", - "Tip: přestupek není malý trestný čin.", - { - "Trestný čin je závažný protiprávní čin, který tak označuje trestní zákoník.", - "Přestupek je mírnější protiprávní čin a trestným činem není.", - "Rušení nočního klidu bývá přestupek. Úmyslné těžké ublížení na zdraví je trestný čin.", - "Za každý z nich odpovídá jiný zákon a jiné řízení.", - NULL, - }, - }, - { - "2 / 2 • Vina", "Věk, příčetnost a presumpce", - "Tip: obviněný není odsouzený.", - { - "Trestní odpovědnost vyžaduje věk aspoň 15 let, příčetnost a zavinění.", - "Bez zavinění, tedy úmyslu nebo nedbalosti, o trestný čin nejde.", - "Dokud soud pravomocně nerozhodne, hledí se na člověka jako na nevinného.", - "Tomu se říká presumpce neviny.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[13], "on3_unit14", "on3_unit14_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit14_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se trestný čin liší od přestupku?", - { - "Ničím", - "Trestný čin je závažnější a popisuje ho trestní zákoník", - "Přestupek řeší jen Ústavní soud", - "Trestný čin nemá oběť", - }, - 4, 1}, - {"Kam spíš patří rušení nočního klidu?", - { - "Mezi přestupky", - "Vždy mezi zločiny", - "Mimo právo", - "Jen do pracovní smlouvy", - }, - 4, 0}, - {"Co presumpce neviny znamená?", - { - "Policie nesmí nikoho vyslechnout", - "Dokud soud nerozhodne, hledí se na člověka jako na nevinného", - "Trest se ukládá před soudem", - "Obviněný se nesmí hájit", - }, - 4, 1}, - {"Stačí ke trestnému činu samotný následek bez zavinění?", - { - "Ano", - "Ne, trestní právo vyžaduje zavinění", - "Ano u každého přestupku školy", - "Ano, pokud o tom napíší noviny", - }, - 4, 1}, - }; - static const char *hints[] = { - "Závažnost a zákon, který čin upravuje", - "Jde o mírnější protiprávní čin", - "Vinu vyslovuje až soud", - "Úmysl nebo nedbalost jsou podmínkou", - }; - return build_on3_mcq_page(13, "on3unit14", "on3_ex14_title", - "on3_quiz14_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit15_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Trest", "Ne jen vězení", - "Tip: trest smrti se v České republice neukládá.", - { - "Trest má chránit společnost a vést pachatele k nápravě, ne být pomstou.", - "Vedle odnětí svobody je třeba podmíněné odsouzení, obecně prospěšné práce nebo peněžitý trest.", - "Patří sem i domácí vězení nebo zákaz činnosti.", - "Tomuto posunu od pouhého zavírání se říká humanizace trestání.", - NULL, - }, - }, - { - "2 / 2 • Řízení", "Policie, žalobce, soud", - "Tip: obhájce má obviněný právo mít.", - { - "Policie věc prověřuje a vyšetřuje.", - "Státní zástupce rozhoduje, zda podá obžalobu.", - "O vině a trestu rozhoduje soud.", - "Obviněný se může hájit a v zákonem daných případech musí mít obhájce.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[14], "on3_unit15", "on3_unit15_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit15_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Jaký má být smysl trestu?", - { - "Pomsta", - "Ochrana společnosti a náprava pachatele", - "Zisk pro soudce", - "Veřejné ponížení", - }, - 4, 1}, - {"Ukládá Česká republika trest smrti?", - { - "Ano", - "Ne", - "Ano u mladistvých", - "Ano, pokud o to oběť požádá", - }, - 4, 1}, - {"Kdo rozhoduje o vině a trestu?", - { - "Policie", - "Soud", - "Noviny", - "Poškozený sám", - }, - 4, 1}, - {"Co je podmíněné odsouzení?", - { - "Trest smrti s odkladem", - "Odklad výkonu trestu, pokud se odsouzený osvědčí", - "Zproštění obžaloby", - "Přestupek", - }, - 4, 1}, - }; - static const char *hints[] = { - "Humanizace odmítá pomstu jako účel", - "Trest smrti byl zrušen", - "Policie vyšetřuje, soud rozhoduje", - "Je to alternativa k nástupu do vězení", - }; - return build_on3_mcq_page(14, "on3unit15", "on3_ex15_title", - "on3_quiz15_head", qs, hints, 4); -} -static GtkWidget *build_on3_unit16_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Věk", "Děti a mladiství", - "Tip: patnáct let je hranice trestní odpovědnosti, ne dospělosti.", - { - "Dítě mladší 15 let není trestně odpovědné.", - "Mladistvý je člověk od 15 do 18 let.", - "U mladistvého zákon hledí i na výchovu, ne jen na potrestání.", - "I čin dítěte pod 15 let se řeší, třeba opatřeními na ochranu dítěte a okolí.", - NULL, - }, - }, - { - "2 / 2 • Pomoc", "Když se stanete obětí nebo svědkem", - "Tip: linky 158 a 112 jsou pro přivolání pomoci.", - { - "Šikanu, násilí, vydírání, lichvu nebo korupci si nenechávejte pro sebe.", - "Řekněte to důvěryhodnému dospělému, škole nebo policii.", - "Při ohrožení odejděte do bezpečí a zavolejte 158 nebo 112. Do střetu se nepouštějte.", - "Svědek má mluvit pravdu. Lichva je půjčka, která zneužívá cizí tísně, a patří na policii, ne do další půjčky.", - NULL, - }, - }, - }; - - return build_on3_unit_page(&on3_lessons[15], "on3_unit16", "on3_unit16_sub", - slides, G_N_ELEMENTS(slides)); -} - -static GtkWidget *build_on3_unit16_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Je dítě mladší 15 let trestně odpovědné?", - { - "Ano, jako dospělý", - "Ne", - "Ano, od 10 let", - "Jen když chodí do školy", - }, - 4, 1}, - {"Kdo je mladistvý?", - { - "Každý student", - "Člověk od 15 do 18 let", - "Člověk do 15 let", - "Jen pachatel přestupku", - }, - 4, 1}, - {"Co udělat při šikaně nebo vydírání?", - { - "Nechat si to pro sebe", - "Říct dospělému, škole nebo policii", - "Vrátit to stejnou silou", - "Půjčit si peníze na vyplacení", - }, - 4, 1}, - {"Co má udělat svědek u policie?", - { - "Mlčet", - "Mluvit pravdu", - "Domyslet si, co policie chce slyšet", - "Oznámit jen to, co se hodí kamarádovi", - }, - 4, 1}, - }; - static const char *hints[] = { - "Trestní odpovědnost začíná v 15 letech", - "Mladistvý už je trestně odpovědný, ale jinak než dospělý", - "Pomoc je mimo tu situaci", - "Křivá výpověď věc zhoršuje", - }; - return build_on3_mcq_page(15, "on3unit16", "on3_ex16_title", - "on3_quiz16_head", qs, hints, 4); -} - -void add_on3_pages(GtkStack *stack) { - typedef GtkWidget *(*OnBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - OnBuilder build_unit; - OnBuilder build_ex; - } pages[] = { - {"on3unit1", "on3ex1", build_on3_unit1_page, build_on3_unit1_exercise_page}, - {"on3unit2", "on3ex2", build_on3_unit2_page, build_on3_unit2_exercise_page}, - {"on3unit3", "on3ex3", build_on3_unit3_page, build_on3_unit3_exercise_page}, - {"on3unit4", "on3ex4", build_on3_unit4_page, build_on3_unit4_exercise_page}, - {"on3unit5", "on3ex5", build_on3_unit5_page, build_on3_unit5_exercise_page}, - {"on3unit6", "on3ex6", build_on3_unit6_page, build_on3_unit6_exercise_page}, - {"on3unit7", "on3ex7", build_on3_unit7_page, build_on3_unit7_exercise_page}, - {"on3unit8", "on3ex8", build_on3_unit8_page, build_on3_unit8_exercise_page}, - {"on3unit9", "on3ex9", build_on3_unit9_page, build_on3_unit9_exercise_page}, - {"on3unit10", "on3ex10", build_on3_unit10_page, build_on3_unit10_exercise_page}, - {"on3unit11", "on3ex11", build_on3_unit11_page, build_on3_unit11_exercise_page}, - {"on3unit12", "on3ex12", build_on3_unit12_page, build_on3_unit12_exercise_page}, - {"on3unit13", "on3ex13", build_on3_unit13_page, build_on3_unit13_exercise_page}, - {"on3unit14", "on3ex14", build_on3_unit14_page, build_on3_unit14_exercise_page}, - {"on3unit15", "on3ex15", build_on3_unit15_page, build_on3_unit15_exercise_page}, - {"on3unit16", "on3ex16", build_on3_unit16_page, build_on3_unit16_exercise_page} - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/obcanka4.c b/src/obcanka4.c deleted file mode 100644 index 1005aea..0000000 --- a/src/obcanka4.c +++ /dev/null @@ -1,1909 +0,0 @@ -#include "graduately.h" - -/* Year 4 of Občanská nauka. - * The remaining units of the MŠMT model syllabus - * (č.j. 18 396/2002-23) and the SOV civic framework: the economy, - * Czechia in Europe and the world, and practical philosophy. - * Schools place them in the fourth year. */ - -#define ON4_ENTRY(n) \ - { .n_slides = 2, .unit_page = "on4unit" #n, .ex_page = "on4ex" #n } - -NetLesson on4_lessons[ON4_LESSONS] = { - ON4_ENTRY(1), - ON4_ENTRY(2), - ON4_ENTRY(3), - ON4_ENTRY(4), - ON4_ENTRY(5), - ON4_ENTRY(6), - ON4_ENTRY(7), - ON4_ENTRY(8), - ON4_ENTRY(9), - ON4_ENTRY(10), - ON4_ENTRY(11), - ON4_ENTRY(12), - ON4_ENTRY(13), - ON4_ENTRY(14), - ON4_ENTRY(15), - ON4_ENTRY(16), -}; - -#undef ON4_ENTRY - -GtkWidget *on4_scroll; -GtkWidget *on4_fixed; -GtkWidget *on4_rail; -GtkWidget *on4_nodes[ON4_UNITS]; -GtkWidget *on4_labels[ON4_UNITS]; -double on4_cx[ON4_UNITS]; -double on4_cy[ON4_UNITS]; -int on4_cols = 1; -int on4_rows = 1; -int on4_cw = (int)(2.0 * ROAD_MX + (ON4_UNITS - 1) * PATH_SPAC); -int on4_ch = (int)(2.0 * ROAD_MY); -guint on4_idle; -double on4_last_avail = -1.0; -int on4_last_cols = -1; -int on4_last_rows = -1; -int on4_last_cw = -1; -int on4_last_ch = -1; -cairo_surface_t *on4_rail_cache; -int on4_cache_w; -int on4_cache_h; - -static void on4_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= ON4_UNITS - 1) { k = ON4_UNITS - 2; u = 1.0; } - - p1x = on4_cx[k]; p1y = on4_cy[k]; - p2x = on4_cx[k + 1]; p2y = on4_cy[k + 1]; - if (k - 1 >= 0) { p0x = on4_cx[k - 1]; p0y = on4_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < ON4_UNITS) { p3x = on4_cx[k + 2]; p3y = on4_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -static void on4_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 24.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - on4_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - on4_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -static void on4_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(ON4_UNITS - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= ON4_UNITS; rows++) { - int cols = (ON4_UNITS + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > ON4_UNITS) - rows = ON4_UNITS; - on4_rows = rows; - on4_cols = (ON4_UNITS + rows - 1) / rows; - if (on4_cols < 1) - on4_cols = 1; - on4_cw = (int)(2.0 * ROAD_MX + (on4_cols - 1) * PATH_SPAC); - on4_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * on4_cols; - int len = MIN(on4_cols, ON4_UNITS - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (on4_cols - 1 - c); - on4_cx[i] = ROAD_MX + cc * PATH_SPAC; - on4_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -static void on4_apply_layout(void) { - if (!on4_fixed) - return; - - if (on4_cols == on4_last_cols && on4_rows == on4_last_rows && - on4_cw == on4_last_cw && on4_ch == on4_last_ch) - return; - - on4_last_cols = on4_cols; - on4_last_rows = on4_rows; - on4_last_cw = on4_cw; - on4_last_ch = on4_ch; - if (on4_rail_cache) { - cairo_surface_destroy(on4_rail_cache); - on4_rail_cache = NULL; - } - - for (int i = 0; i < ON4_UNITS; i++) { - if (!on4_nodes[i] || !on4_labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(on4_fixed), on4_nodes[i], - (int)(on4_cx[i] - NODE_SIZE / 2.0), - (int)(on4_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(on4_fixed), on4_labels[i], - (int)(on4_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(on4_cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(on4_fixed, on4_cw, on4_ch); - gtk_widget_set_size_request(on4_rail, on4_cw, on4_ch); - gtk_fixed_move(GTK_FIXED(on4_fixed), on4_rail, 0, 0); - gtk_widget_queue_draw(on4_rail); -} - -static void on4_relayout(void) { - GtkAdjustment *hadj; - double avail; - - if (!on4_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(on4_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - if (fabs(avail - on4_last_avail) < 1.0) - return; - on4_last_avail = avail; - on4_geometry(avail); - on4_apply_layout(); -} - -static gboolean on4_relayout_idle(gpointer data) { - (void)data; - on4_idle = 0; - on4_relayout(); - return G_SOURCE_REMOVE; -} - -static void on4_relayout_later(void) { - if (on4_idle == 0) - on4_idle = g_idle_add(on4_relayout_idle, NULL); -} - -static void on4_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - (void)data; - on4_relayout_later(); -} - -static void on4_render_rail_to(cairo_t *cr) { - const double t_end = (double)(ON4_UNITS - 1); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - on4_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){2.0, 40.0}, 2, 0.0); - cairo_new_path(cr); - on4_path(cr, 0.0, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); -} - -static void on4_draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - (void)area; - (void)width; - (void)height; - (void)data; - - if (!on4_rail_cache || on4_cache_w != on4_cw || on4_cache_h != on4_ch) { - cairo_t *rcr; - - if (on4_rail_cache) - cairo_surface_destroy(on4_rail_cache); - on4_cache_w = on4_cw; - on4_cache_h = on4_ch; - if (on4_cache_w < 1) - on4_cache_w = 1; - if (on4_cache_h < 1) - on4_cache_h = 1; - on4_rail_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - on4_cache_w, on4_cache_h); - rcr = cairo_create(on4_rail_cache); - on4_render_rail_to(rcr); - cairo_destroy(rcr); - } - - cairo_set_source_surface(cr, on4_rail_cache, 0, 0); - cairo_paint(cr); -} - -void on4_rail_theme_reset(void) { - if (on4_rail_cache) { - cairo_surface_destroy(on4_rail_cache); - on4_rail_cache = NULL; - } - if (on4_rail) - gtk_widget_queue_draw(on4_rail); -} - -static void on4_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof(name), "on4_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static void on4_add_node(GtkFixed *fixed, int index) { - int num = index + 1; - gboolean locked = index >= ON4_LESSONS; - GtkWidget *card; - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - GtkWidget *name; - char *text; - static char unit_keys[ON4_LESSONS][16]; - static gboolean unit_keys_ready = FALSE; - - if (!unit_keys_ready) { - for (int i = 0; i < ON4_LESSONS; i++) - g_snprintf(unit_keys[i], sizeof unit_keys[i], "on4_unit%d", i + 1); - unit_keys_ready = TRUE; - } - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_sensitive(card, !locked); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - if (locked) - gtk_widget_add_css_class(card, "locked"); - else - gtk_widget_add_css_class(card, "current"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", num); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - if (locked) { - icon = icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 16); - gtk_box_append(GTK_BOX(vbox), icon); - } else { - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_box_append(GTK_BOX(vbox), icon); - on4_lessons[index].done_icon = icon; - g_signal_connect(card, "clicked", G_CALLBACK(on4_open_unit), - &on4_lessons[index]); - } - - on4_nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(NULL); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - if (index < ON4_LESSONS) { - i18n_bind(name, unit_keys[index], 0); - } else { - gtk_widget_add_css_class(name, "unit-name-locked"); - } - on4_labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} -GtkWidget *build_on4map_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - - on4_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("onyears", "on_year4", "on4_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - on4_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, on4_cw, on4_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - on4_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, on4_cw, on4_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), on4_draw_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - on4_rail = rail; - - for (int i = 0; i < ON4_UNITS; i++) - on4_add_node(GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(on4_adjust_notify), NULL); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(on4_adjust_notify), NULL); - - on4_apply_layout(); - on4_relayout_later(); - refresh_on4_completion_ui(); - - return page; -} - -static void on4_slide_apply(NetLesson *L); -static void on4_slide_prev(GtkButton *button, gpointer data); -static void on4_slide_next(GtkButton *button, gpointer data); - -static int on4_note_last_w = -1; - -static void on4_rescale_notes_at(int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < ON4_LESSONS; i++) - net_rescale_lesson_notes(&on4_lessons[i], body, head, kick); -} - -static gboolean on4_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - (void)data; - if (width != on4_note_last_w) { - on4_note_last_w = width; - on4_rescale_notes_at(width); - } - return G_SOURCE_CONTINUE; -} - -static GtkWidget *build_on4_unit_page(NetLesson *L, const char *title_key, - const char *sub_key, - const NetSlide *slides, guint n_slides) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar("on4map", title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "on4_slide%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, on4_note_tick, NULL, NULL); - on4_note_last_w = -1; - on4_rescale_notes_at(0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(on4_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(on4_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - on4_slide_apply(L); - return page; -} - -static void on4_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "on4_slide%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void on4_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx > 0) { - L->idx--; - on4_slide_apply(L); - } -} - -static void on4_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - (void)button; - if (!L) return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - on4_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -void on4_lessons_apply_lang(void) { - for (int i = 0; i < ON4_LESSONS; i++) - on4_slide_apply(&on4_lessons[i]); -} - -static void on4_mcq_check(GtkButton *button, gpointer data) { - NetMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - mark_on4_done(ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -static GtkWidget *build_on4_mcq_page(int lesson_id, const char *back_page, - const char *title_key, - const char *heading_key, - const ChoiceQ *qs, const char **hints, - int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - NetMcqCtx *ctx = g_new0(NetMcqCtx, 1); - int n_opts = qs[0].n_options; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(on4_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - - return page; -} -static GtkWidget *build_on4_unit1_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Cena", "Nabídka a poptávka", - "Tip: cena není rozkaz, je to signál.", - { - "Trh je místo, kde se potkává nabídka s poptávkou.", - "Poptávka je ochota kupujících vzít zboží za určitou cenu.", - "Nabídka je ochota prodávajících zboží prodat.", - "Když cena roste, poptávka obvykle klesá a nabídka obvykle roste.", - NULL, - }, - }, - { - "2 / 2 • Soutěž", "Konkurence a monopol", - "Tip: čtvrtý ročník bere hospodářství, svět a filozofii.", - { - "Rovnovážná cena je tam, kde se nabídka s poptávkou potkají.", - "Konkurence nutí prodávající hlídat cenu i kvalitu.", - "Monopol má na trhu jediný prodávající a cenu si snáze diktuje.", - "Česko má tržní hospodářství. Stát stanoví pravidla, nenahrazuje každý obchod.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[0], "on4_unit1", "on4_unit1_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit1_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kde se potkává nabídka s poptávkou?", - { - "Jen v parlamentu", - "Na trhu", - "Jen u notáře", - "Jen v jedné rodině", - }, - 4, 1}, - {"Co se s poptávkou obvykle stane, když cena roste?", - { - "Vždycky roste", - "Obvykle klesá", - "Zruší se zákon", - "Zůstane vždy stejná", - }, - 4, 1}, - {"Kdo je monopol?", - { - "Jediný prodávající s velkou mocí nad cenou", - "Každý malý obchod", - "Stát, který vybírá daně", - "Kupující, který srovnává ceny", - }, - 4, 0}, - {"K čemu konkurence prodávající tlačí?", - { - "K libovolně vysoké ceně", - "Aby trh zavřeli", - "Aby hlídali cenu i kvalitu", - "Aby přestali prodávat", - }, - 4, 2}, - }; - static const char *hints[] = { - "Trh není jen kamenný krám", - "Vyšší cena část kupujících odradí", - "Konkurence monopolu chybí", - "Kupující si může vybrat jinde", - }; - return build_on4_mcq_page(0, "on4unit1", "on4_ex1_title", - "on4_quiz1_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit2_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Měřítko", "Co HDP počítá", - "Tip: HDP není vysvědčení štěstí.", - { - "Hrubý domácí produkt je tržní hodnota konečných statků a služeb.", - "Počítá se, co se na území státu vytvoří za určité období.", - "Meziprodukt, který už je v ceně hotového výrobku, se znovu nepřičítá.", - "HDP neříká, jak jsou lidé šťastní, a nepočítá neplacenou péči.", - NULL, - }, - }, - { - "2 / 2 • Vlny", "Růst a recese", - "Tip: pokles výroby se lidí dotkne dřív než tabulka.", - { - "Růst znamená, že se za období vytvoří víc.", - "Recese je období, kdy hospodářství klesá.", - "V poklesu obvykle roste nezaměstnanost a firmy odkládají investice.", - "HDP na osobu pomáhá státy srovnat, ale nezměří spravedlnost.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[1], "on4_unit2", "on4_unit2_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit2_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je hrubý domácí produkt?", - { - "Tržní hodnota konečných statků a služeb vytvořených na území státu", - "Součet poslaneckých platů", - "Počet nezaměstnaných", - "Státní dluh", - }, - 4, 0}, - {"Počítá se meziprodukt do HDP znovu?", - { - "Ano, čím víckrát, tím líp", - "Ne, aby se výroba nepočítala dvakrát", - "Jen o víkendu", - "Jen když jde o dovoz", - }, - 4, 1}, - {"Co je recese?", - { - "Nejrychlejší růst hospodářství", - "Den, kdy se platí daně", - "Období poklesu hospodářství", - "Růst všech mezd ze zákona", - }, - 4, 2}, - {"Měří HDP štěstí lidí?", - { - "Ano, je to měřítko štěstí", - "Ano, počítá i neplacenou péči", - "Ne, měří výrobu, ne štěstí", - "Ano, vyšší HDP znamená spravedlivější stát", - }, - 4, 2}, - }; - static const char *hints[] = { - "Jde o výrobu za určité období", - "V ceně hotového výrobku už je", - "Opak růstu", - "Neplacená péče v něm není", - }; - return build_on4_mcq_page(1, "on4unit2", "on4_ex2_title", - "on4_quiz2_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit3_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Směna", "K čemu jsou peníze", - "Tip: eurozóna není totéž co Evropská unie.", - { - "Peníze jsou prostředek směny a společné měřítko cen.", - "Dá se v nich také uložit hodnota na později.", - "Měnou České republiky je koruna.", - "Česko je v Evropské unii, ale eurem se zde neplatí.", - NULL, - }, - }, - { - "2 / 2 • Ceny", "Inflace", - "Tip: zdražení jedné věci ještě není inflace.", - { - "Inflace je všeobecný růst cenové hladiny.", - "Měří ji Český statistický úřad jako růst spotřebitelských cen.", - "Česká národní banka usiluje o inflaci poblíž 2 procent.", - "Vysoká inflace znehodnocuje úspory a pevný příjem koupí míň.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[2], "on4_unit3", "on4_unit3_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit3_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu peníze slouží?", - { - "Jsou prostředek směny a společné měřítko cen", - "Nahrazují zákon", - "Jsou totéž co státní dluh", - "Platí jen v jednom obchodě", - }, - 4, 0}, - {"Jaká je měna České republiky?", - { - "Euro", - "Koruna", - "Dolar", - "Měna celé eurozóny", - }, - 4, 1}, - {"Co je inflace?", - { - "Zdražení jedné značky", - "Pokles všech mezd ze zákona", - "Všeobecný růst cenové hladiny", - "Schodek státního rozpočtu", - }, - 4, 2}, - {"O jakou inflaci usiluje Česká národní banka?", - { - "Poblíž nuly za každou cenu", - "Poblíž 10 procent", - "Poblíž 20 procent", - "Poblíž 2 procent", - }, - 4, 3}, - }; - static const char *hints[] = { - "Bez nich se směna srovnává hůř", - "Euro se v Česku nepoužívá", - "Nejde o jednu věc v regálu", - "Cíl je nízká a stabilní inflace", - }; - return build_on4_mcq_page(2, "on4unit3", "on4_ex3_title", - "on4_quiz3_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit4_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Stát", "Česká národní banka", - "Tip: ČNB není obchodní banka s pobočkami na náměstí.", - { - "Česká národní banka je ústřední banka a vydává korunu.", - "Je nezávislá. Vláda jí nesmí diktovat úrokové sazby.", - "Hlavním nástrojem měnové politiky jsou právě úrokové sazby.", - "Dohlíží na banky a na další části finančního trhu.", - NULL, - }, - }, - { - "2 / 2 • Pobočka", "Obchodní banka a vklady", - "Tip: limit ochrany vkladů se počítá na osobu a jednu banku.", - { - "Obchodní banka přijímá vklady a poskytuje úvěry.", - "Peníze na účtu nejsou totéž co hotovost v trezoru banky.", - "Vklady chrání garanční systém.", - "Ochrana je zpravidla do ekvivalentu 100 000 eur na osobu a banku.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[3], "on4_unit4", "on4_unit4_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit4_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je Česká národní banka?", - { - "Obchodní banka s nejvíce pobočkami", - "Ústřední banka, která vydává korunu", - "Úřad práce", - "Ministerstvo financí", - }, - 4, 1}, - {"Čím ČNB hlavně řídí měnovou politiku?", - { - "Školním řádem", - "Počtem poslanců", - "Úrokovými sazbami", - "Sazbou DPH", - }, - 4, 2}, - {"Co dělá obchodní banka?", - { - "Schvaluje zákony", - "Přijímá vklady a poskytuje úvěry", - "Ukládá tresty", - "Stanovuje inflační cíl", - }, - 4, 1}, - {"Jak jsou vklady v bance chráněné?", - { - "Nejsou chráněné vůbec", - "Zpravidla do ekvivalentu 100 000 eur na osobu a banku", - "Jen do 1 000 korun", - "Bez limitu u všech bank dohromady", - }, - 4, 1}, - }; - static const char *hints[] = { - "Neslouží jako běžný účet pro veřejnost", - "Sazby ovlivňují cenu peněz", - "Inflační cíl je věc ČNB", - "Limit se nepočítá na celou zemi najednou", - }; - return build_on4_mcq_page(3, "on4unit4", "on4_ex4_title", - "on4_quiz4_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit5_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Výběr", "Přímé a nepřímé daně", - "Tip: DPH je v ceně nákupu, i když ji odvádí prodejce.", - { - "Přímá daň se platí z příjmu nebo z majetku.", - "Nepřímou daň člověk platí v ceně. Taková je daň z přidané hodnoty.", - "Základní sazba DPH je 21 procent, snížená 12 procent.", - "Vybrané knihy jsou od DPH osvobozené. Není to třetí sazba.", - NULL, - }, - }, - { - "2 / 2 • Rok", "Rozpočet, schodek a dluh", - "Tip: schodek je jeden rok, dluh se táhne dál.", - { - "Daně financují školy, zdravotnictví, obranu a další veřejné výdaje.", - "Státní rozpočet srovnává příjmy a výdaje státu na jeden rok.", - "Schodek vznikne, když stát v tom roce utratí víc, než vybere.", - "Dluh je to, co z minulých schodků ještě není splacené. Rozpočet schvaluje Poslanecká sněmovna.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[4], "on4_unit5", "on4_unit5_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit5_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Čím se DPH liší od daně z příjmu?", - { - "DPH je v ceně nákupu, daň z příjmu se platí z příjmu", - "Jsou totéž", - "DPH lidé v ceně nikdy neplatí", - "Daň z příjmu je přirážka na rohlíku", - }, - 4, 0}, - {"Jaká je základní sazba DPH?", - { - "12 procent", - "21 procent", - "5 procent", - "10 procent", - }, - 4, 1}, - {"Co je schodek státního rozpočtu?", - { - "Přebytek na účtu domácnosti", - "Počet bank", - "Výdaje státu v daném roce převýší příjmy", - "Inflační cíl ČNB", - }, - 4, 2}, - {"Kdo schvaluje státní rozpočet?", - { - "Česká národní banka", - "Obecní úřad", - "Každý živnostník", - "Poslanecká sněmovna", - }, - 4, 3}, - }; - static const char *hints[] = { - "Jedna je nepřímá, druhá přímá", - "Snížená sazba je 12 procent", - "Jde o jeden rozpočtový rok", - "Rozpočet je zákon", - }; - return build_on4_mcq_page(4, "on4unit5", "on4_ex5_title", - "on4_quiz5_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit6_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Účet", "Kdo je podnikatel", - "Tip: ne každá výdělečná činnost je živnost.", - { - "Podnikatel jedná soustavně, na vlastní účet a odpovědnost a za účelem zisku.", - "Častou cestou drobného podnikání je živnost.", - "Ohlašovací živnost se ohlásí. Koncesovaná navíc potřebuje povolení.", - "OSVČ podniká jako fyzická osoba. Společnost s ručením omezeným je osoba právnická.", - NULL, - }, - }, - { - "2 / 2 • Ručení", "s.r.o. a akciová společnost", - "Tip: společnost ručí svým majetkem, společník jen omezeně.", - { - "Společník s.r.o. ručí jen do výše nesplaceného vkladu.", - "Minimální vklad společníka s.r.o. je 1 koruna.", - "Akciová společnost má akcie a základní kapitál nejméně 2 miliony korun.", - "Podnikatel platí daně a odvody. Ohlášení živnosti není návod, jak se povinnostem vyhnout.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[5], "on4_unit6", "on4_unit6_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit6_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co vystihuje podnikání?", - { - "Soustavná činnost na vlastní účet a odpovědnost za účelem zisku", - "Jakákoli brigáda bez jakékoli povinnosti", - "Jen práce pro stát", - "Povinná školní docházka", - }, - 4, 0}, - {"Čím se liší koncesovaná živnost?", - { - "Ničím, stačí stejné ohlášení", - "Potřebuje povolení, nestačí jen ohlášení", - "Smí ji mít jen akciová společnost", - "Je vždy bez podmínek", - }, - 4, 1}, - {"Jaký je minimální vklad společníka s.r.o.?", - { - "2 miliony korun", - "100 000 eur", - "1 koruna", - "Kapitál se skládat nesmí", - }, - 4, 2}, - {"Čím ručí společník s.r.o. za dluhy společnosti?", - { - "Celým osobním majetkem bez omezení", - "Jen do výše nesplaceného vkladu", - "Za dluhy státu", - "Společnost svým majetkem neručí vůbec", - }, - 4, 1}, - }; - static const char *hints[] = { - "Zisk je záměr, ne záruka", - "Ohlašovací živnost se jen ohlašuje", - "Akciová společnost má hranici mnohem výš", - "Majetkem ručí samotná společnost", - }; - return build_on4_mcq_page(5, "on4unit6", "on4_ex6_title", - "on4_quiz6_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit7_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Mzda", "Kdo práci hledá", - "Tip: nezaměstnaný není každý, kdo zrovna nesedí v práci.", - { - "Trh práce spojuje zaměstnavatele a lidi, kteří práci hledají.", - "Mzda závisí na tom, co člověk umí, na poptávce a na dohodě.", - "Nezaměstnaný je, kdo práci nemá, chce pracovat a hledá ji.", - "Kdo práci nehledá, není v tomto smyslu nezaměstnaný.", - NULL, - }, - }, - { - "2 / 2 • Úřad", "Pomoc při ztrátě práce", - "Tip: smlouvu a výpověď bere třetí ročník.", - { - "Úřad práce eviduje uchazeče o zaměstnání a pomáhá místo hledat.", - "Podporu v nezaměstnanosti lze dostat jen při splnění zákonných podmínek.", - "Vzdělání a dovednosti šanci na práci zvyšují.", - "Pracovní smlouva, výpověď a zkušební doba jsou učivo třetího ročníku.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[6], "on4_unit7", "on4_unit7_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit7_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdo je nezaměstnaný?", - { - "Každý, kdo zrovna nemá směnu", - "Kdo práci nemá, chce ji a hledá ji", - "Každý student", - "Kdo práci má, ale nelíbí se mu", - }, - 4, 1}, - {"Kdo eviduje uchazeče o zaměstnání?", - { - "Česká národní banka", - "Úřad práce", - "Ústavní soud", - "Notář", - }, - 4, 1}, - {"Dostane podporu v nezaměstnanosti každý bez práce?", - { - "Ano, hned a bez podmínek", - "Ano, vyplácí ji škola", - "Ne, jen při splnění zákonných podmínek", - "Ano, je to totéž co mzda", - }, - 4, 2}, - {"Kde se bere pracovní smlouva a výpověď?", - { - "U daní ve čtvrtém ročníku", - "U voleb ve druhém ročníku", - "U rodiny v prvním ročníku", - "U pracovního práva ve třetím ročníku", - }, - 4, 3}, - }; - static const char *hints[] = { - "Patří k tomu aktivní hledání", - "Není to banka ani soud", - "Podpora není automatická", - "Čtvrtý ročník smlouvu neopakuje", - }; - return build_on4_mcq_page(6, "on4unit7", "on4_ex7_title", - "on4_quiz7_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit8_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Měsíc", "Příjmy a výdaje", - "Tip: rozpočet je porovnání, ne přání.", - { - "Rozpočet domácnosti srovnává, co přijde a co odejde.", - "Příjem je mzda, dávka, kapesné nebo jiný pravidelný přísun.", - "Nejdřív patří bydlení, jídlo, doprava a další nutné výdaje.", - "Až potom zbývá místo na věci, bez kterých se domácnost obejde.", - NULL, - }, - }, - { - "2 / 2 • Zásoba", "Rezerva a schodek", - "Tip: rezerva není totéž co půjčka.", - { - "Rezerva kryje nečekaný výdaj, třeba opravu nebo výpadek příjmu.", - "Krátký schodek se dá vyrovnat z rezervy.", - "Dlouhý schodek znamená škrtat, nebo se zadlužovat.", - "Rozpočet má smysl, jen když se podle něj domácnost opravdu řídí.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[7], "on4_unit8", "on4_unit8_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit8_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co srovnává rozpočet domácnosti?", - { - "Jen přání", - "Příjmy a výdaje", - "Počet poslanců", - "Inflaci a státní dluh", - }, - 4, 1}, - {"Co má v rozpočtu přednost?", - { - "Nejdřív bydlení, jídlo a další nutné výdaje", - "Nejdřív všechno z reklamy", - "Nejdřív půjčka na dovolenou", - "Rozpočet se nesestavuje", - }, - 4, 0}, - {"K čemu je rezerva?", - { - "Aby smazala státní dluh", - "Na nečekaný výdaj", - "Nahrazuje zdravotní pojištění", - "Je totéž co daň", - }, - 4, 1}, - {"Co znamená dlouhý schodek domácnosti?", - { - "Domácnost šetří víc, než musí", - "Příjmy jsou vyšší než výdaje", - "Výdaje převyšují příjmy a je třeba škrtat, nebo se domácnost zadluží", - "Inflace je nulová", - }, - 4, 2}, - }; - static const char *hints[] = { - "Obě strany musí být vidět", - "Nutné výdaje jsou dřív než přání", - "Patří na výpadek, ne na stát", - "Schodek není přebytek", - }; - return build_on4_mcq_page(7, "on4unit8", "on4_ex8_title", - "on4_quiz8_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit9_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Cena", "Spoření a úvěr", - "Tip: vyšší slíbený výnos obvykle znamená vyšší riziko.", - { - "Úspora je odložená spotřeba. Úvěr jsou půjčené peníze.", - "Úrok je cena půjčených peněz a úvěr se vrací i s ním.", - "RPSN ukazuje roční náklady spotřebitelského úvěru včetně poplatků.", - "Nabídky se porovnávají. Půjčit si lze jen tolik, kolik se dá vracet.", - NULL, - }, - }, - { - "2 / 2 • Krytí", "Pojištění a tíseň", - "Tip: nabídku, která těží z tísně, nepodepisujte.", - { - "Veřejné zdravotní pojištění je v České republice povinné.", - "Sociální pojištění se týká důchodu, nemoci a ztráty zaměstnání, vždy podle zákona.", - "Pojištění bytu nebo odpovědnosti je dobrovolné a kryje jen dohodnuté riziko.", - "Nabídku, která těží z něčí tísně, odmítněte a řekněte o ní dospělému.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[8], "on4_unit9", "on4_unit9_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit9_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je úrok?", - { - "Cena půjčených peněz", - "Daň z přidané hodnoty", - "Pokuta za hluk", - "Státní dluh", - }, - 4, 0}, - {"Co ukazuje RPSN?", - { - "Jen barvu platební karty", - "Roční náklady spotřebitelského úvěru včetně poplatků", - "Výši HDP", - "Počet poboček banky", - }, - 4, 1}, - {"Kolik si má domácnost půjčit?", - { - "Co nejvíc, výnos je jistý", - "Tolik, kolik slíbí první reklama", - "Jen tolik, kolik zvládne vracet", - "Libovolně, úvěr se vracet nemusí", - }, - 4, 2}, - {"Jaké pojištění je v České republice povinné?", - { - "Pojištění dovolené", - "Pojištění mobilu", - "Pojištění bytu", - "Veřejné zdravotní pojištění", - }, - 4, 3}, - }; - static const char *hints[] = { - "Úvěr není zdarma", - "Poplatky do ní patří", - "Jistý vysoký zisk nikdo seriózní neslíbí", - "Pojištění bytu je dobrovolné", - }; - return build_on4_mcq_page(8, "on4unit9", "on4_ex9_title", - "on4_quiz9_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit10_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Členství", "Unie, Schengen a euro", - "Tip: členství v Unii ještě neznamená euro.", - { - "Česká republika je členským státem Evropské unie od 1. května 2004.", - "Unie má 27 států. Společný trh je volný pohyb zboží, služeb, kapitálu a osob.", - "Česko je v Schengenu. Ne každý stát Unie v něm je a některé státy Schengenu v Unii nejsou.", - "Eurozóna je jen část Unie. V Česku se platí korunou.", - NULL, - }, - }, - { - "2 / 2 • Orgány", "Kdo v Unii rozhoduje", - "Tip: Evropská rada není Rada Evropské unie.", - { - "Evropský parlament volí občané přímo.", - "Evropská komise navrhuje unijní předpisy a dohlíží, jak se provádějí.", - "Rada Evropské unie sdružuje ministry členských států.", - "Evropská rada je setkání hlav států a vlád a určuje směr.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[9], "on4_unit10", "on4_unit10_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit10_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Od kdy je Česká republika v Evropské unii?", - { - "Od roku 1993", - "Od 1. května 2004", - "Od 12. března 1999", - "Od roku 1989", - }, - 4, 1}, - {"Platí Česko eurem?", - { - "Ano, od vstupu do Unie", - "Ano, koruna zanikla", - "Ne, je v Unii, ale ne v eurozóně", - "Euro je měna Severoatlantické aliance", - }, - 4, 2}, - {"Je každý stát Evropské unie v Schengenu?", - { - "Ano, je to totéž", - "Ne", - "Ano, a Schengen je totéž co euro", - "Ne, a Česko v něm také není", - }, - 4, 1}, - {"Kterou unijní instituci volí občané přímo?", - { - "Evropskou komisi", - "Evropskou radu", - "Radu Evropské unie", - "Evropský parlament", - }, - 4, 3}, - }; - static const char *hints[] = { - "Rok 1999 patří k NATO", - "Eurozóna je užší než Unie", - "Česko v Schengenu je", - "Ministři v Radě EU voleni přímo nejsou", - }; - return build_on4_mcq_page(9, "on4unit10", "on4_ex10_title", - "on4_quiz10_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit11_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Aliance", "Česko v NATO", - "Tip: společná obrana neruší suverenitu státu.", - { - "Česká republika je svrchovaný stát.", - "NATO je obranná aliance. Česko do něj vstoupilo 12. března 1999.", - "Smlouva bere ozbrojený útok na jednoho člena jako útok na všechny.", - "Ostatní členové pak poskytnou pomoc. Aliance není obchodní smlouva ani soud.", - NULL, - }, - }, - { - "2 / 2 • Mír", "Organizace spojených národů", - "Tip: OSN není totéž co Evropská unie.", - { - "OSN vznikla roku 1945, aby státy chránily mír a řešily spory jednáním.", - "Valné shromáždění sdružuje členské státy.", - "Rada bezpečnosti se zabývá ohrožením míru.", - "Česká republika je členem OSN, stejně jako je členem Evropské unie a NATO.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[10], "on4_unit11", "on4_unit11_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit11_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Kdy Česko vstoupilo do NATO?", - { - "1. května 2004", - "12. března 1999", - "Roku 1945", - "Roku 1918", - }, - 4, 1}, - {"Co znamená zásada společné obrany?", - { - "Ozbrojený útok na jednoho člena se bere jako útok na všechny", - "Aliance ruší suverenitu členů", - "Členové si nesmějí pomáhat", - "Jde o smlouvu o sazbě DPH", - }, - 4, 0}, - {"K čemu vznikla OSN?", - { - "Aby vydávala korunu", - "Aby státy chránily mír a řešily spory jednáním", - "Aby vedla živnostenský rejstřík", - "Aby stanovila českou DPH", - }, - 4, 1}, - {"Je Česká republika členem OSN?", - { - "Ne", - "Jen jako pozorovatel bez členství", - "Ano", - "Byla, ale roku 2004 vystoupila", - }, - 4, 2}, - }; - static const char *hints[] = { - "Rok 2004 je vstup do Evropské unie", - "Pomoc není daňový předpis", - "Vznikla roku 1945", - "Členství v Unii členství v OSN neruší", - }; - return build_on4_mcq_page(10, "on4unit11", "on4_ex11_title", - "on4_quiz11_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit12_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Hranice", "Propojený svět", - "Tip: propojení není jen výhoda.", - { - "Globalizace je rostoucí propojení ekonomik, informací a kultur přes hranice.", - "Přináší obchod, cestování a rychlejší šíření poznatků.", - "Nese i závislost na jiných státech, nerovnost a tlak na životní prostředí.", - "Globální problém, třeba změna klimatu nebo pandemie, se na hranici nezastaví.", - NULL, - }, - }, - { - "2 / 2 • Odpověď", "Spolupráce a vlastní volba", - "Tip: sledovat původ zboží je taky rozhodnutí.", - { - "Krize v jedné zemi se může přelít do jiných.", - "Státy proto spolupracují v organizacích a ve smlouvách.", - "Člověk může sledovat, odkud zboží je, a rozhodovat se s rozmyslem.", - "Hlas ve volbách je způsob, jak se k těm otázkám postavit.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[11], "on4_unit12", "on4_unit12_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit12_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co je globalizace?", - { - "Zákaz obchodu přes hranice", - "Rostoucí propojení ekonomik, informací a kultur", - "Totéž co státní rozpočet", - "Zánik všech států", - }, - 4, 1}, - {"Co globalizace může přinést?", - { - "Obchod, cestování a rychlejší šíření poznatků", - "Jen izolaci", - "Zrušení všech měn", - "Konec odpovědnosti", - }, - 4, 0}, - {"Co je globální problém?", - { - "Jen hádka dvou sousedů", - "Problém, který se nezastaví na hranici jednoho státu", - "Schodek jedné domácnosti", - "Místní školní řád", - }, - 4, 1}, - {"Proč státy u takových otázek spolupracují?", - { - "Protože krize se může přelít přes hranice", - "Protože hranice už neexistují", - "Protože OSN vybírá české daně", - "Spolupráce není k ničemu", - }, - 4, 0}, - }; - static const char *hints[] = { - "Státy globalizací nemizejí", - "Přínos nevylučuje riziko", - "Klima a pandemie jsou příklady", - "Jedna země to sama neuzavře", - }; - return build_on4_mcq_page(11, "on4unit12", "on4_ex12_title", - "on4_quiz12_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit13_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Otázka", "Co filozofie dělá", - "Tip: filozofie není seznam hotových odpovědí.", - { - "Filozofie se ptá, co je skutečné, co můžeme poznat a jak máme žít.", - "Nestačí jí příkaz ani pouhý zvyk. Chce důvody.", - "Rozlišuje pojmy, aby se lidé nebavili o různých věcech stejným slovem.", - "Nemá jeden školní klíč, který by disputaci ukončil.", - NULL, - }, - }, - { - "2 / 2 • Antika", "Sókratés, Platón a Aristotelés", - "Tip: Sókratés se nevydával za majitele hotových pravd.", - { - "Sókratés zkoumal, co lidé pokládají za jisté.", - "Sám se za vlastníka hotových pravd nevydával.", - "Platón hledal trvalé ideje za proměnlivým světem.", - "Aristotelés vycházel ze zkušenosti a třídil, co lze poznat.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[12], "on4_unit13", "on4_unit13_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit13_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Na co se filozofie ptá?", - { - "Jen na výši DPH", - "Co je skutečné, co lze poznat a jak žít", - "Kolik je poslanců", - "Jak se vyplní daňové přiznání", - }, - 4, 1}, - {"Stačí filozofii pouhý příkaz?", - { - "Ano, příkaz je důkaz", - "Ne, chce důvody", - "Ano, zvyk se nezkoumá", - "Je totéž co zákoník", - }, - 4, 1}, - {"Co Sókratés odmítal o sobě tvrdit?", - { - "Že už vlastní hotové pravdy", - "Že se má ptát", - "Že rozhovor má smysl", - "Že člověk může nevědět", - }, - 4, 0}, - {"Čím se Aristotelés ve škole často liší od Platóna?", - { - "Popíral, že lze cokoli poznat", - "Sepsal zákoník práce", - "Vycházel ze zkušenosti", - "Odmítal třídit pojmy", - }, - 4, 2}, - }; - static const char *hints[] = { - "Jde o otázky, které tabulka neuzavře", - "Bez důvodů to není zkoumání", - "Zkoumal jistoty druhých", - "Platón hledal trvalé ideje", - }; - return build_on4_mcq_page(12, "on4unit13", "on4_ex13_title", - "on4_quiz13_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit14_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Správné", "Norma a svědomí", - "Tip: svědomí může mýlit, proto patří i důvody.", - { - "Etika se ptá, co je správné dělat a proč.", - "Mravní norma není totéž co zákon. Zákon bere třetí ročník.", - "Svědomí je vnitřní smysl pro správné a špatné.", - "Může se mýlit. Proto nestačí pocit bez důvodu.", - NULL, - }, - }, - { - "2 / 2 • Volba", "Svoboda a důstojnost", - "Tip: výhodné jednání ještě nemusí být správné.", - { - "Svoboda znamená, že člověk volí. Odpovědnost znamená, že za volbu stojí.", - "Svoboda bez odpovědnosti je svévole.", - "Lidská důstojnost patří každému, ne jen úspěšným nebo užitečným.", - "Dobré jednání se nepozná jen podle toho, že se vyplatí.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[13], "on4_unit14", "on4_unit14_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit14_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Co zkoumá etika?", - { - "Výši úrokových sazeb", - "Co je správné dělat a proč", - "Soustavu soudů", - "Sazbu DPH", - }, - 4, 1}, - {"Je mravní norma totéž co zákon?", - { - "Ano", - "Ne", - "Každá neslušnost je hned trestný čin", - "Morálku vynucuje jen soud", - }, - 4, 1}, - {"Je svědomí neomylné?", - { - "Ano, proto důvody nepotřebujeme", - "Ano, nahrazuje zákon", - "Ne, může se mýlit", - "Svědomí mají jen věřící", - }, - 4, 2}, - {"Komu patří lidská důstojnost?", - { - "Jen úspěšným", - "Jen užitečným", - "Každému člověku", - "Jen těm, kdo se nikdy nezmýlí", - }, - 4, 2}, - }; - static const char *hints[] = { - "Ptá se po důvodech jednání", - "Zákon a mrav se často kryjí, ale nejsou totéž", - "Pocit se má zkoumat", - "Důstojnost se nekupuje výkonem", - }; - return build_on4_mcq_page(13, "on4unit14", "on4_ex14_title", - "on4_quiz14_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit15_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Smysl", "Víra i její odmítnutí", - "Tip: stát nesmí víru vnutit ani zakázat.", - { - "Lidé hledají smysl ve víře, ve filozofii i v pohledu bez náboženství.", - "Křesťanství dlouho utvářelo českou a evropskou kulturu.", - "Vedle něj studenti potkávají judaismus, islám a další tradice.", - "Ateismus a agnosticismus jsou postoje, které svoboda svědomí taky chrání.", - NULL, - }, - }, - { - "2 / 2 • Hranice", "Respekt není totéž co pravda", - "Tip: nesouhlasit lze bez pohrdání.", - { - "Člověk smí věřit, víru změnit, nebo nevěřit.", - "Respekt k člověku neznamená, že každý názor je pravdivý.", - "Náboženství a věda odpovídají na jiný druh otázek.", - "Svoboda svědomí chrání i toho, kdo se víry zřekl.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[14], "on4_unit15", "on4_unit15_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit15_exercise_page(void) { - static const ChoiceQ qs[] = { - {"Smí stát vnutit víru?", - { - "Ano, tu většinovou", - "Ne", - "Ano, ve škole povinně jednu", - "Ano, nevěřící ztrácí práva", - }, - 4, 1}, - {"Chrání svoboda svědomí i ateismus?", - { - "Ne", - "Ano, člověk smí nevěřit", - "Jen mimo Evropu", - "Ateismus je státní náboženství", - }, - 4, 1}, - {"Znamená respekt, že každý názor je pravdivý?", - { - "Ano", - "Ne, nesouhlasit lze slušně", - "Pravda je to, co říká hlasitější", - "Názory se nesmějí vůbec porovnávat", - }, - 4, 1}, - {"Je náboženství totéž co věda?", - { - "Ano", - "Ano, obojí měří inflaci", - "Ne, odpovídají na jiný druh otázek", - "Věda ukládá povinnou víru", - }, - 4, 2}, - }; - static const char *hints[] = { - "Svoboda svědomí nutit nedovolí", - "Patří k ní i odmítnutí víry", - "Respekt patří člověku", - "Každé se ptá jinak", - }; - return build_on4_mcq_page(14, "on4unit15", "on4_ex15_title", - "on4_quiz15_head", qs, hints, 4); -} - -static GtkWidget *build_on4_unit16_page(void) { - static const NetSlide slides[] = { - { - "1 / 2 • Měřítko", "Podle čeho volíme", - "Tip: praktická filozofie chce důvody, ne heslo.", - { - "Hodnoty jsou měřítka volby: důstojnost, pravda, spravedlnost, svoboda, solidarita.", - "Dobrý život není totéž co pohodlí nebo vysoký příjem.", - "Člověk má zkoumat vlastní důvody, ne jen opakovat větu.", - "Společenství, občan, právo a hospodářství k sobě v občance patří.", - NULL, - }, - }, - { - "2 / 2 • Druzí", "Pravda, solidarita, svoboda", - "Tip: svoboda druhého je hranice mé svobody.", - { - "Pravda se nepozná podle toho, kdo křičí hlasitěji.", - "Spravedlnost chce podobným případům podobný přístup.", - "Solidarita je ochota nést část nákladu s druhými, ne jen brát výhody.", - "Svoboda druhého je hranice mé svobody.", - NULL, - }, - }, - }; - - return build_on4_unit_page(&on4_lessons[15], "on4_unit16", "on4_unit16_sub", - slides, G_N_ELEMENTS(slides)); -} -static GtkWidget *build_on4_unit16_exercise_page(void) { - static const ChoiceQ qs[] = { - {"K čemu jsou hodnoty?", - { - "Nahrazují domácí rozpočet", - "Jsou měřítka, podle kterých volíme", - "Ruší odpovědnost", - "Jsou totéž co sazba DPH", - }, - 4, 1}, - {"Je dobrý život totéž co vysoký příjem?", - { - "Ano", - "Ne", - "Ano, HDP ho měří přímo", - "Ano, důstojnost se kupuje", - }, - 4, 1}, - {"Co praktická filozofie od člověka chce?", - { - "Aby opakoval heslo", - "Aby zkoumal vlastní důvody", - "Aby se vzdal svobody", - "Aby nečetl námitky", - }, - 4, 1}, - {"Co ohraničuje mou svobodu?", - { - "Nic", - "Jen výše mzdy", - "Svoboda druhého", - "Počet bank v ulici", - }, - 4, 2}, - }; - static const char *hints[] = { - "Bez nich je volba nahodilá", - "Příjem je prostředek, ne celý život", - "Heslo bez důvodu nestačí", - "Svoboda není svévole", - }; - return build_on4_mcq_page(15, "on4unit16", "on4_ex16_title", - "on4_quiz16_head", qs, hints, 4); -} -void add_on4_pages(GtkStack *stack) { - typedef GtkWidget *(*OnBuilder)(void); - static const struct { - const char *unit_name; - const char *ex_name; - OnBuilder build_unit; - OnBuilder build_ex; - } pages[] = { - {"on4unit1", "on4ex1", build_on4_unit1_page, build_on4_unit1_exercise_page}, - {"on4unit2", "on4ex2", build_on4_unit2_page, build_on4_unit2_exercise_page}, - {"on4unit3", "on4ex3", build_on4_unit3_page, build_on4_unit3_exercise_page}, - {"on4unit4", "on4ex4", build_on4_unit4_page, build_on4_unit4_exercise_page}, - {"on4unit5", "on4ex5", build_on4_unit5_page, build_on4_unit5_exercise_page}, - {"on4unit6", "on4ex6", build_on4_unit6_page, build_on4_unit6_exercise_page}, - {"on4unit7", "on4ex7", build_on4_unit7_page, build_on4_unit7_exercise_page}, - {"on4unit8", "on4ex8", build_on4_unit8_page, build_on4_unit8_exercise_page}, - {"on4unit9", "on4ex9", build_on4_unit9_page, build_on4_unit9_exercise_page}, - {"on4unit10", "on4ex10", build_on4_unit10_page, build_on4_unit10_exercise_page}, - {"on4unit11", "on4ex11", build_on4_unit11_page, build_on4_unit11_exercise_page}, - {"on4unit12", "on4ex12", build_on4_unit12_page, build_on4_unit12_exercise_page}, - {"on4unit13", "on4ex13", build_on4_unit13_page, build_on4_unit13_exercise_page}, - {"on4unit14", "on4ex14", build_on4_unit14_page, build_on4_unit14_exercise_page}, - {"on4unit15", "on4ex15", build_on4_unit15_page, build_on4_unit15_exercise_page}, - {"on4unit16", "on4ex16", build_on4_unit16_page, build_on4_unit16_exercise_page} - }; - - for (guint i = 0; i < G_N_ELEMENTS(pages); i++) { - gtk_stack_add_named(stack, pages[i].build_unit(), pages[i].unit_name); - gtk_stack_add_named(stack, pages[i].build_ex(), pages[i].ex_name); - } -} diff --git a/src/priroda.c b/src/priroda.c deleted file mode 100644 index 1078036..0000000 --- a/src/priroda.c +++ /dev/null @@ -1,720 +0,0 @@ -#include "graduately.h" - -/* Základy přírodopisných věd: chemistry and biology share one subject. - * Each area is a vertical list of lessons, then slides and a quiz. */ - -typedef struct { - const char *map_page; - const char *back_page; - const char *title_key; - const char *sub_key; - char **progress_path; - NetLesson *lessons; - const char *unit_keys[SCI_N]; - const char *sub_keys[SCI_N]; - GtkWidget *nodes[SCI_N]; - int note_last_w; -} SciTrack; - -static SciTrack sci_tracks[2]; -static GtkWidget *sci_rail; -static gboolean sci_ready; - -static void sci_ensure(void) { - static const char *chem_units[] = { - "chem_unit1", "chem_unit2", "chem_unit3", "chem_unit4", - "chem_unit5", "chem_unit6", "chem_unit7", "chem_unit8", - }; - static const char *chem_subs[] = { - "chem_unit1_sub", "chem_unit2_sub", "chem_unit3_sub", "chem_unit4_sub", - "chem_unit5_sub", "chem_unit6_sub", "chem_unit7_sub", "chem_unit8_sub", - }; - static const char *bio_units[] = { - "bio_unit1", "bio_unit2", "bio_unit3", "bio_unit4", - "bio_unit5", "bio_unit6", "bio_unit7", "bio_unit8", - }; - static const char *bio_subs[] = { - "bio_unit1_sub", "bio_unit2_sub", "bio_unit3_sub", "bio_unit4_sub", - "bio_unit5_sub", "bio_unit6_sub", "bio_unit7_sub", "bio_unit8_sub", - }; - - if (sci_ready) - return; - sci_tracks[0].map_page = "chemmap"; - sci_tracks[0].back_page = "scimap"; - sci_tracks[0].title_key = "Chemie"; - sci_tracks[0].sub_key = "chem_sub"; - sci_tracks[0].progress_path = &app_progress_chem; - sci_tracks[0].lessons = chem_lessons; - sci_tracks[0].note_last_w = -1; - sci_tracks[1].map_page = "biomap"; - sci_tracks[1].back_page = "scimap"; - sci_tracks[1].title_key = "Biologie"; - sci_tracks[1].sub_key = "bio_sub"; - sci_tracks[1].progress_path = &app_progress_bio; - sci_tracks[1].lessons = bio_lessons; - sci_tracks[1].note_last_w = -1; - for (int i = 0; i < SCI_N; i++) { - sci_tracks[0].unit_keys[i] = chem_units[i]; - sci_tracks[0].sub_keys[i] = chem_subs[i]; - sci_tracks[1].unit_keys[i] = bio_units[i]; - sci_tracks[1].sub_keys[i] = bio_subs[i]; - } - sci_ready = TRUE; -} - -static void sci_save(SciTrack *T) { - GKeyFile *kf; - char *path; - gchar *data; - - if (!T->progress_path || !*T->progress_path) - return; - path = *T->progress_path; - kf = g_key_file_new(); - for (int i = 0; i < SCI_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, T->lessons[i].done); - } - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - if (data) { - GError *err = NULL; - - g_file_set_contents(path, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -static void sci_load_one(SciTrack *T) { - GKeyFile *kf; - GError *err = NULL; - const char *path; - - if (!T->progress_path || !*T->progress_path) - return; - path = *T->progress_path; - kf = g_key_file_new(); - if (!g_key_file_load_from_file(kf, path, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - for (int i = 0; i < SCI_N; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - T->lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - g_key_file_free(kf); -} - -void sci_load_progress(void) { - sci_ensure(); - sci_load_one(&sci_tracks[0]); - sci_load_one(&sci_tracks[1]); -} - -static void sci_refresh(SciTrack *T) { - for (int i = 0; i < SCI_N; i++) { - GtkWidget *node = T->nodes[i]; - GtkWidget *icon = T->lessons[i].done_icon; - - if (!node) - continue; - if (T->lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -static void sci_mark_done(SciTrack *T, int lesson_id) { - if (lesson_id < 0 || lesson_id >= SCI_N) - return; - if (T->lessons[lesson_id].done) - return; - T->lessons[lesson_id].done = TRUE; - sci_save(T); - sci_refresh(T); - refresh_stats_ui(); -} - -void progress_for_sci(ProgressSum *out) { - if (!out) - return; - sci_ensure(); - for (int a = 0; a < 2; a++) { - SciTrack *T = &sci_tracks[a]; - - out->total_ex += SCI_N; - out->open_units += SCI_N; - for (int i = 0; i < SCI_N; i++) { - if (T->lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - } -} - -static void sci_open_unit(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - L->idx = 0; - if (L->stack) { - char name[16]; - - g_snprintf(name, sizeof(name), "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) - gtk_widget_set_sensitive(L->prev_btn, FALSE); - if (L->next_btn) - gtk_button_set_label(GTK_BUTTON(L->next_btn), tr("net_slide_next")); - } - show_page(L->unit_page, 1); -} - -static GtkWidget *sci_lesson_button(SciTrack *T, int index) { - GtkWidget *btn; - GtkWidget *row; - GtkWidget *num; - GtkWidget *texts; - GtkWidget *title; - GtkWidget *sub; - GtkWidget *icon; - char *num_text; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_size_request(btn, -1, 84); - - row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - gtk_widget_set_halign(row, GTK_ALIGN_START); - gtk_widget_set_valign(row, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_button_set_child(GTK_BUTTON(btn), row); - - num_text = g_strdup_printf("%d", index + 1); - num = gtk_label_new(num_text); - g_free(num_text); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - - texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(texts, GTK_ALIGN_START); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - - title = gtk_label_new(NULL); - i18n_bind(title, T->unit_keys[index], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - - sub = gtk_label_new(NULL); - i18n_bind(sub, T->sub_keys[index], 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0.0); - gtk_widget_add_css_class(sub, "hint"); - gtk_box_append(GTK_BOX(texts), sub); - - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - gtk_widget_set_valign(icon, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), icon); - T->lessons[index].done_icon = icon; - T->nodes[index] = btn; - g_signal_connect(btn, "clicked", G_CALLBACK(sci_open_unit), - &T->lessons[index]); - return btn; -} - -static GtkWidget *sci_build_list(SciTrack *T) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *list; - - sci_ensure(); - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar(T->back_page, T->title_key, T->sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_valign(list, GTK_ALIGN_START); - gtk_widget_set_size_request(list, 520, -1); - gtk_widget_set_margin_bottom(list, 12); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - - for (int i = 0; i < SCI_N; i++) - gtk_box_append(GTK_BOX(list), sci_lesson_button(T, i)); - sci_refresh(T); - return page; -} - -GtkWidget *build_chemmap_page(void) { return sci_build_list(&sci_tracks[0]); } -GtkWidget *build_biomap_page(void) { return sci_build_list(&sci_tracks[1]); } - -#define SCI_BUBBLE SUB_BUBBLE -#define SCI_LABEL_W 180.0 -#define SCI_CW 560 -#define SCI_CH 280 - -static double sci_cx[2]; -static double sci_cy[2]; - -static void draw_sci_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb slate = color_from_hex(app_theme.surface1); - - (void)area; - (void)width; - (void)height; - (void)data; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - - cairo_move_to(cr, sci_cx[0], sci_cy[0]); - cairo_line_to(cr, sci_cx[1], sci_cy[1]); - cairo_set_line_width(cr, 14); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_move_to(cr, sci_cx[0], sci_cy[0]); - cairo_line_to(cr, sci_cx[1], sci_cy[1]); - cairo_set_line_width(cr, 9); - cairo_set_source_rgb(cr, slate.r, slate.g, slate.b); - cairo_stroke(cr); -} - -void sci_rail_theme_reset(void) { - if (sci_rail) - gtk_widget_queue_draw(sci_rail); -} - -GtkWidget *build_scimap_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - static const char *keys[] = {"Chemie", "Biologie"}; - static const char *initials[] = {"C", "B"}; - static const char *targets[] = {"chemmap", "biomap"}; - - sci_cx[0] = 160.0; - sci_cy[0] = 110.0; - sci_cx[1] = 400.0; - sci_cy[1] = 110.0; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("subjects", "Základy Přírodopisných věd", "sci_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, SCI_CW, SCI_CH); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, SCI_CW, SCI_CH); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), draw_sci_rail, - NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - sci_rail = rail; - - for (int i = 0; i < 2; i++) { - GtkWidget *btn = gtk_button_new(); - GtkWidget *letter = gtk_label_new(initials[i]); - GtkWidget *name = gtk_label_new(NULL); - - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_can_focus(btn, FALSE); - gtk_widget_set_size_request(btn, (int)SCI_BUBBLE, (int)SCI_BUBBLE); - gtk_widget_add_css_class(letter, "unit-number"); - gtk_button_set_child(GTK_BUTTON(btn), letter); - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(targets[i]), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - - i18n_bind(name, keys[i], 0); - gtk_widget_set_size_request(name, (int)SCI_LABEL_W, -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - - gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0); - gtk_fixed_put(GTK_FIXED(fixed), name, 0, 0); - gtk_fixed_move(GTK_FIXED(fixed), btn, - (int)(sci_cx[i] - SCI_BUBBLE / 2.0), - (int)(sci_cy[i] - SCI_BUBBLE / 2.0)); - gtk_fixed_move(GTK_FIXED(fixed), name, - (int)(sci_cx[i] - SCI_LABEL_W / 2.0), - (int)(sci_cy[i] + SCI_BUBBLE / 2.0 + 10.0)); - } - return page; -} - -static void sci_slide_apply(NetLesson *L) { - char name[16]; - - if (!L || !L->stack) - return; - g_snprintf(name, sizeof(name), "s%u", L->idx); - gtk_stack_set_visible_child_name(GTK_STACK(L->stack), name); - if (L->prev_btn) { - gtk_button_set_label(GTK_BUTTON(L->prev_btn), tr("net_slide_prev")); - gtk_widget_set_sensitive(L->prev_btn, L->idx > 0); - } - if (L->next_btn) { - gtk_button_set_label( - GTK_BUTTON(L->next_btn), - L->idx + 1 >= L->n_slides ? tr("net_slide_start") - : tr("net_slide_next")); - } -} - -static void sci_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L || L->idx == 0) - return; - L->idx--; - sci_slide_apply(L); -} - -static void sci_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - sci_slide_apply(L); - } else { - show_page(L->ex_page, 1); - } -} - -static void sci_rescale(SciTrack *T, int w) { - int body, head, kick; - - if (w < 160) - w = 160; - body = w / 46; - if (body < 14) body = 14; - if (body > 26) body = 26; - head = body + 14; - if (head > 46) head = 46; - kick = body - 3; - if (kick < 11) kick = 11; - for (int i = 0; i < SCI_N; i++) - net_rescale_lesson_notes(&T->lessons[i], body, head, kick); -} - -static gboolean sci_note_tick(GtkWidget *w, GdkFrameClock *clock, - gpointer data) { - SciTrack *T = data; - int width = gtk_widget_get_allocated_width(w); - - (void)clock; - if (width != T->note_last_w) { - T->note_last_w = width; - sci_rescale(T, width); - } - return G_SOURCE_CONTINUE; -} - -GtkWidget *sci_unit_page(int area, NetLesson *L, const char *title_key, - const char *sub_key, const NetSlide *slides, - guint n_slides) { - SciTrack *T; - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *nav; - - sci_ensure(); - if (area < 0 || area > 1) - area = 0; - T = &sci_tracks[area]; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = n_slides; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - - gtk_box_append(GTK_BOX(page), top_bar(T->map_page, title_key, sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - - for (guint s = 0; s < n_slides; s++) { - GtkWidget *stage = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *card; - char name[16]; - - gtk_widget_set_vexpand(stage, TRUE); - g_snprintf(name, sizeof(name), "s%u", s); - gtk_stack_add_named(GTK_STACK(L->stack), stage, name); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 16); - gtk_widget_add_css_class(card, "notes-card"); - gtk_widget_set_valign(card, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(stage), card); - - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - } - - gtk_widget_add_tick_callback(L->stack, sci_note_tick, T, NULL); - T->note_last_w = -1; - sci_rescale(T, 0); - net_notes_target = NULL; - - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(sci_slide_prev), L); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(sci_slide_next), L); - gtk_box_append(GTK_BOX(nav), L->next_btn); - - L->idx = 0; - sci_slide_apply(L); - return page; -} - -void sci_lessons_apply_lang(void) { - sci_ensure(); - for (int a = 0; a < 2; a++) { - for (int i = 0; i < SCI_N; i++) - sci_slide_apply(&sci_tracks[a].lessons[i]); - } -} - -typedef struct { - const ChoiceQ *qs; - int n; - int n_opts; - SciTrack *track; - int lesson_id; - GtkWidget *feedback; - GtkToggleButton **toggles; - GtkWidget **hints; -} SciMcqCtx; - -static void sci_mcq_check(GtkButton *button, gpointer data) { - SciMcqCtx *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - sci_mark_done(ctx->track, ctx->lesson_id); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -GtkWidget *sci_mcq_page(int area, int lesson_id, const char *back_page, - const char *title_key, const char *heading_key, - const ChoiceQ *qs, const char **hints, int n) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *body; - GtkWidget *check; - GtkWidget *btns; - GtkWidget *head; - GtkWidget *intro; - SciMcqCtx *ctx = g_new0(SciMcqCtx, 1); - int n_opts = qs[0].n_options; - - sci_ensure(); - if (area < 0 || area > 1) - area = 0; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), top_bar(back_page, title_key, NULL)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - - body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_set_halign(body, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(body, TRUE); - gtk_widget_set_margin_start(body, 4); - gtk_widget_set_margin_end(body, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - - head = gtk_label_new(NULL); - i18n_bind(head, heading_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_set_margin_top(head, 4); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - - intro = gtk_label_new(NULL); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_widget_set_margin_bottom(intro, 4); - gtk_box_append(GTK_BOX(body), intro); - - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->track = &sci_tracks[area]; - ctx->lesson_id = lesson_id; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints[i]); - } - - btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_margin_top(btns, 8); - gtk_widget_set_margin_bottom(btns, 8); - gtk_box_append(GTK_BOX(body), btns); - - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(btns), check); - g_signal_connect(check, "clicked", G_CALLBACK(sci_mcq_check), ctx); - - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_box_append(GTK_BOX(body), ctx->feedback); - return page; -} diff --git a/src/progress.c b/src/progress.c deleted file mode 100644 index 9d62b71..0000000 --- a/src/progress.c +++ /dev/null @@ -1,705 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Progress */ -/* ------------------------------------------------------------------ */ - -void unit_save_progress(UnitCtx *u) { - GKeyFile *kf = g_key_file_new(); - for (int i = 1; i <= MAX_UNIT_EX; i++) { - gchar key[8]; - g_snprintf(key, sizeof(key), "%d", i); - g_key_file_set_boolean(kf, "done", key, u->done[i]); - } - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - gchar *data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - - if (data) { - GError *err = NULL; - g_file_set_contents(u->progress_file, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void unit_load_progress(UnitCtx *u) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, u->progress_file, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - for (int i = 1; i <= MAX_UNIT_EX; i++) { - gchar key[8]; - g_snprintf(key, sizeof(key), "%d", i); - u->done[i] = g_key_file_get_boolean(kf, "done", key, NULL); - } - - g_key_file_free(kf); -} - -void load_progress(void) { - for (int i = 0; i < NUM_UNLOCKED; i++) - unit_load_progress(&units[i]); - net_load_progress(); - hw_load_progress(); - on_load_progress(); - on2_load_progress(); - on3_load_progress(); - on4_load_progress(); - en_load_progress(); - de_load_progress(); - quizyear_load_all(); - lit_load_progress(); - sci_load_progress(); - fyz_load_progress(); - math_load_progress(); -} - -/* Redraw the exercise rails of every unit that already has a page. */ -void all_rails_redraw(void) { - for (int i = 0; i < NUM_UNLOCKED; i++) { - if (units[i].ex_rail) - gtk_widget_queue_draw(units[i].ex_rail); - } -} - -/* Index of the unit the student should work on next: the first unlocked one - * that is not finished yet. -1 once every open unit is complete. */ -static int current_unit_index(void) { - for (int uidx = 0; uidx < NUM_UNLOCKED; uidx++) { - UnitCtx *u = &units[uidx]; - - if (u->n_ex <= 0) - continue; - for (int i = 1; i <= u->n_ex; i++) - if (!u->done[i]) - return uidx; - } - return -1; -} - -void refresh_completion_ui(void) { - int current = current_unit_index(); - - for (int uidx = 0; uidx < NUM_UNLOCKED; uidx++) { - UnitCtx *u = &units[uidx]; - gboolean all = TRUE; - - for (int i = 1; i <= u->n_ex; i++) { - if (!u->done[i]) { - all = FALSE; - break; - } - } - - /* per-bubble markers */ - if (u->ex_cells[0] != NULL) { - for (int i = 1; i <= u->n_ex; i++) { - GtkWidget *btn = u->ex_cells[i - 1]; - if (!btn) - continue; - if (u->done[i]) { - gtk_widget_add_css_class(btn, "done"); - if (u->ex_icons[i]) - gtk_widget_set_visible(u->ex_icons[i], TRUE); - } else { - gtk_widget_remove_css_class(btn, "done"); - if (u->ex_icons[i]) - gtk_widget_set_visible(u->ex_icons[i], FALSE); - } - } - } - - /* off-path branch marker */ - if (u->has_branch && u->branch_cell) { - if (u->done[u->branch_ex]) { - gtk_widget_add_css_class(u->branch_cell, "done"); - if (u->branch_icon) - gtk_widget_set_visible(u->branch_icon, TRUE); - } else { - gtk_widget_remove_css_class(u->branch_cell, "done"); - if (u->branch_icon) - gtk_widget_set_visible(u->branch_icon, FALSE); - } - } - - /* Roadmap node: finished, the one step to take next, or simply open. - * Highlighting every unlocked unit made three of them look equally - * "current" and told the student nothing. */ - if (u->node) { - gboolean done = all && u->n_ex > 0; - - if (done) - gtk_widget_add_css_class(u->node, "done"); - else - gtk_widget_remove_css_class(u->node, "done"); - - if (!done && uidx == current) - gtk_widget_add_css_class(u->node, "current"); - else - gtk_widget_remove_css_class(u->node, "current"); - - if (u->node_done_icon) - gtk_widget_set_visible(u->node_done_icon, done); - } - } - - all_rails_redraw(); - refresh_net_completion_ui(); - refresh_hw_completion_ui(); - mluvnice_refresh_ui(); - refresh_stats_ui(); -} - -void mark_done(UnitCtx *u, int n) { - if (!u || n < 1 || n > MAX_UNIT_EX) - return; - u->done[n] = TRUE; - refresh_completion_ui(); - unit_save_progress(u); -} - -void net_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, PROGRESS_NET, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - for (int i = 0; i < NET_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - net_lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - - g_key_file_free(kf); -} - -void net_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - - for (int i = 0; i < NET_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, net_lessons[i].done); - } - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - gchar *data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - - if (data) { - GError *err = NULL; - g_file_set_contents(PROGRESS_NET, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void refresh_net_completion_ui(void) { - for (int i = 0; i < NET_LESSONS; i++) { - GtkWidget *node = net_nodes[i]; - GtkWidget *icon = net_lessons[i].done_icon; - - if (!node) - continue; - if (net_lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -void mark_net_done(int lesson_id) { - if (lesson_id < 0 || lesson_id >= NET_LESSONS) - return; - if (net_lessons[lesson_id].done) - return; - net_lessons[lesson_id].done = TRUE; - net_save_progress(); - refresh_net_completion_ui(); - refresh_stats_ui(); -} - -void progress_for_net(ProgressSum *out) { - out->total_ex += NET_LESSONS; - out->open_units += NET_LESSONS; - for (int i = 0; i < NET_LESSONS; i++) { - if (net_lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - progress_for_net_years(out); -} - -void hw_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, PROGRESS_HW, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - for (int i = 0; i < HW_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - hw_lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - - g_key_file_free(kf); -} - -void hw_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - - for (int i = 0; i < HW_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, hw_lessons[i].done); - } - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - gchar *data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - - if (data) { - GError *err = NULL; - g_file_set_contents(PROGRESS_HW, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void refresh_hw_completion_ui(void) { - for (int i = 0; i < HW_LESSONS; i++) { - GtkWidget *node = hw_nodes[i]; - GtkWidget *icon = hw_lessons[i].done_icon; - - if (!node) - continue; - if (hw_lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -void mark_hw_done(int lesson_id) { - if (lesson_id < 0 || lesson_id >= HW_LESSONS) - return; - if (hw_lessons[lesson_id].done) - return; - hw_lessons[lesson_id].done = TRUE; - hw_save_progress(); - refresh_hw_completion_ui(); - refresh_stats_ui(); -} - -void progress_for_hw(ProgressSum *out) { - out->total_ex += HW_LESSONS; - out->open_units += HW_LESSONS; - for (int i = 0; i < HW_LESSONS; i++) { - if (hw_lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - progress_for_hw_years(out); -} - -void on_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, PROGRESS_ON, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - for (int i = 0; i < ON_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - on_lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - - g_key_file_free(kf); -} - -void on_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - - for (int i = 0; i < ON_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, on_lessons[i].done); - } - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - gchar *data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - - if (data) { - GError *err = NULL; - g_file_set_contents(PROGRESS_ON, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void refresh_on_completion_ui(void) { - for (int i = 0; i < ON_LESSONS; i++) { - GtkWidget *node = on_nodes[i]; - GtkWidget *icon = on_lessons[i].done_icon; - - if (!node) - continue; - if (on_lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -void mark_on_done(int lesson_id) { - if (lesson_id < 0 || lesson_id >= ON_LESSONS) - return; - if (on_lessons[lesson_id].done) - return; - on_lessons[lesson_id].done = TRUE; - on_save_progress(); - refresh_on_completion_ui(); - refresh_stats_ui(); -} - -void progress_for_on(ProgressSum *out) { - out->total_ex += ON_LESSONS + ON2_LESSONS + ON3_LESSONS + ON4_LESSONS; - out->open_units += ON_LESSONS + ON2_LESSONS + ON3_LESSONS + ON4_LESSONS; - for (int i = 0; i < ON_LESSONS; i++) { - if (on_lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - for (int i = 0; i < ON2_LESSONS; i++) { - if (on2_lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - for (int i = 0; i < ON3_LESSONS; i++) { - if (on3_lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - for (int i = 0; i < ON4_LESSONS; i++) { - if (on4_lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } -} - -void on2_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, PROGRESS_ON2, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - for (int i = 0; i < ON2_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - on2_lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - - g_key_file_free(kf); -} - -void on2_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - - for (int i = 0; i < ON2_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, on2_lessons[i].done); - } - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - gchar *data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - - if (data) { - GError *err = NULL; - g_file_set_contents(PROGRESS_ON2, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void refresh_on2_completion_ui(void) { - for (int i = 0; i < ON2_LESSONS; i++) { - GtkWidget *node = on2_nodes[i]; - GtkWidget *icon = on2_lessons[i].done_icon; - - if (!node) - continue; - if (on2_lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -void mark_on2_done(int lesson_id) { - if (lesson_id < 0 || lesson_id >= ON2_LESSONS) - return; - if (on2_lessons[lesson_id].done) - return; - on2_lessons[lesson_id].done = TRUE; - on2_save_progress(); - refresh_on2_completion_ui(); - refresh_stats_ui(); -} - -void on3_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, PROGRESS_ON3, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - for (int i = 0; i < ON3_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - on3_lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - - g_key_file_free(kf); -} - -void on3_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - - for (int i = 0; i < ON3_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, on3_lessons[i].done); - } - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - gchar *data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - - if (data) { - GError *err = NULL; - g_file_set_contents(PROGRESS_ON3, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void refresh_on3_completion_ui(void) { - for (int i = 0; i < ON3_LESSONS; i++) { - GtkWidget *node = on3_nodes[i]; - GtkWidget *icon = on3_lessons[i].done_icon; - - if (!node) - continue; - if (on3_lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -void mark_on3_done(int lesson_id) { - if (lesson_id < 0 || lesson_id >= ON3_LESSONS) - return; - if (on3_lessons[lesson_id].done) - return; - on3_lessons[lesson_id].done = TRUE; - on3_save_progress(); - refresh_on3_completion_ui(); - refresh_stats_ui(); -} - -void on4_load_progress(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, PROGRESS_ON4, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - for (int i = 0; i < ON4_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - on4_lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - - g_key_file_free(kf); -} - -void on4_save_progress(void) { - GKeyFile *kf = g_key_file_new(); - - for (int i = 0; i < ON4_LESSONS; i++) { - gchar key[8]; - - g_snprintf(key, sizeof(key), "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, on4_lessons[i].done); - } - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - gchar *data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - - if (data) { - GError *err = NULL; - g_file_set_contents(PROGRESS_ON4, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void refresh_on4_completion_ui(void) { - for (int i = 0; i < ON4_LESSONS; i++) { - GtkWidget *node = on4_nodes[i]; - GtkWidget *icon = on4_lessons[i].done_icon; - - if (!node) - continue; - if (on4_lessons[i].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - if (icon) - gtk_widget_set_visible(icon, TRUE); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - if (icon) - gtk_widget_set_visible(icon, FALSE); - } - } -} - -void mark_on4_done(int lesson_id) { - if (lesson_id < 0 || lesson_id >= ON4_LESSONS) - return; - if (on4_lessons[lesson_id].done) - return; - on4_lessons[lesson_id].done = TRUE; - on4_save_progress(); - refresh_on4_completion_ui(); - refresh_stats_ui(); -} diff --git a/src/quizyear.c b/src/quizyear.c deleted file mode 100644 index 98b8540..0000000 --- a/src/quizyear.c +++ /dev/null @@ -1,451 +0,0 @@ -#include "graduately.h" - -/* Later years of networks and hardware. Year 1 keeps its own path. - * These years are a list of lessons, slides and a four-question quiz. */ - -#define QY_N 8 -#define QY_COUNT 6 - -struct QuizYear { - const char *prefix; - const char *map_page; - const char *back_page; - const char *title_key; - const char *sub_key; - const char *file; - NetLesson lessons[QY_N]; - char unit_page[QY_N][16]; - char ex_page[QY_N][16]; - char unit_key[QY_N][20]; - char sub_keybuf[QY_N][24]; - GtkWidget *nodes[QY_N]; -}; - -static QuizYear years[QY_COUNT]; -static gboolean qy_ready; - -QuizYear *qy_net2; -QuizYear *qy_net3; -QuizYear *qy_net4; -QuizYear *qy_hw2; -QuizYear *qy_hw3; -QuizYear *qy_hw4; - -static char map_store[QY_COUNT][16]; -static char file_store[QY_COUNT][16]; - -void quizyear_boot(void) { - static const char *prefix[] = { - "net2", "net3", "net4", "hw2", "hw3", "hw4", - }; - static const char *back[] = { - "netyears", "netyears", "netyears", - "hwyears", "hwyears", "hwyears", - }; - static const char *title[] = { - "net_year2", "net_year3", "net_year4", - "hw_year2", "hw_year3", "hw_year4", - }; - static const char *sub[] = { - "net2_sub", "net3_sub", "net4_sub", - "hw2_sub", "hw3_sub", "hw4_sub", - }; - QuizYear **slot[] = { - &qy_net2, &qy_net3, &qy_net4, &qy_hw2, &qy_hw3, &qy_hw4, - }; - - if (qy_ready) - return; - for (int y = 0; y < QY_COUNT; y++) { - QuizYear *Y = &years[y]; - - Y->prefix = prefix[y]; - Y->back_page = back[y]; - Y->title_key = title[y]; - Y->sub_key = sub[y]; - g_snprintf(map_store[y], sizeof map_store[y], "%smap", prefix[y]); - g_snprintf(file_store[y], sizeof file_store[y], "%s.conf", prefix[y]); - Y->map_page = map_store[y]; - Y->file = file_store[y]; - for (int i = 0; i < QY_N; i++) { - g_snprintf(Y->unit_page[i], sizeof Y->unit_page[i], - "%sunit%d", prefix[y], i + 1); - g_snprintf(Y->ex_page[i], sizeof Y->ex_page[i], - "%sex%d", prefix[y], i + 1); - g_snprintf(Y->unit_key[i], sizeof Y->unit_key[i], - "%s_unit%d", prefix[y], i + 1); - g_snprintf(Y->sub_keybuf[i], sizeof Y->sub_keybuf[i], - "%s_unit%d_sub", prefix[y], i + 1); - Y->lessons[i].unit_page = Y->unit_page[i]; - Y->lessons[i].ex_page = Y->ex_page[i]; - Y->lessons[i].n_slides = 3; - } - *slot[y] = Y; - } - qy_ready = TRUE; -} - -static char *qy_path(QuizYear *Y) { - return g_build_filename(app_progress_dir, Y->file, NULL); -} - -static void qy_save(QuizYear *Y) { - GKeyFile *kf = g_key_file_new(); - char *path = qy_path(Y); - gchar *data; - GError *err = NULL; - - for (int i = 0; i < QY_N; i++) { - char key[8]; - - g_snprintf(key, sizeof key, "%d", i + 1); - g_key_file_set_boolean(kf, "done", key, Y->lessons[i].done); - } - data = g_key_file_to_data(kf, NULL, NULL); - if (!g_file_set_contents(path, data, -1, &err)) { - g_warning("quiz year: %s", err->message); - g_error_free(err); - } - g_free(data); - g_free(path); - g_key_file_free(kf); -} - -static void qy_load_one(QuizYear *Y) { - GKeyFile *kf = g_key_file_new(); - char *path = qy_path(Y); - GError *err = NULL; - - if (!g_key_file_load_from_file(kf, path, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - g_free(path); - return; - } - for (int i = 0; i < QY_N; i++) { - char key[8]; - - g_snprintf(key, sizeof key, "%d", i + 1); - Y->lessons[i].done = g_key_file_get_boolean(kf, "done", key, NULL); - } - g_key_file_free(kf); - g_free(path); -} - -void quizyear_load_all(void) { - quizyear_boot(); - for (int y = 0; y < QY_COUNT; y++) - qy_load_one(&years[y]); -} - -static void qy_refresh_node(QuizYear *Y, int index) { - GtkWidget *node = Y->nodes[index]; - - if (!node) - return; - if (Y->lessons[index].done) { - gtk_widget_remove_css_class(node, "current"); - gtk_widget_add_css_class(node, "done"); - } else { - gtk_widget_remove_css_class(node, "done"); - gtk_widget_add_css_class(node, "current"); - } -} - -static void qy_mark(QuizYear *Y, int index) { - if (index < 0 || index >= QY_N || Y->lessons[index].done) - return; - Y->lessons[index].done = TRUE; - qy_save(Y); - qy_refresh_node(Y, index); - refresh_stats_ui(); -} - -static void qy_add(ProgressSum *out, int first, int n) { - for (int y = first; y < first + n; y++) { - out->total_ex += QY_N; - out->open_units += QY_N; - for (int i = 0; i < QY_N; i++) { - if (years[y].lessons[i].done) { - out->done_ex++; - out->done_units++; - } - } - } -} - -void progress_for_net_years(ProgressSum *out) { - quizyear_boot(); - qy_add(out, 0, 3); -} - -void progress_for_hw_years(ProgressSum *out) { - quizyear_boot(); - qy_add(out, 3, 3); -} - -static void qy_slide_prev(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (L && L->idx > 0) { - L->idx--; - skill_slide_apply(L); - } -} - -static void qy_slide_next(GtkButton *button, gpointer data) { - NetLesson *L = data; - - (void)button; - if (!L) - return; - if (L->idx + 1 < L->n_slides) { - L->idx++; - skill_slide_apply(L); - } else if (L->ex_page) { - show_page(L->ex_page, 1); - } -} - -void quizyear_apply_lang(void) { - if (!qy_ready) - return; - for (int y = 0; y < QY_COUNT; y++) - for (int i = 0; i < QY_N; i++) - skill_slide_apply(&years[y].lessons[i]); -} - -GtkWidget *quizyear_unit(QuizYear *Y, int index, const char *title_key, - const char *sub_key, const NetSlide *slides, - int n_slides) { - NetLesson *L = &Y->lessons[index]; - GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *scroll = gtk_scrolled_window_new(); - GtkWidget *nav; - - net_lesson_notes_ensure(L); - net_notes_target = L; - L->n_slides = (guint)n_slides; - gtk_widget_set_margin_start(page, 28); - gtk_widget_set_margin_end(page, 28); - gtk_widget_set_margin_top(page, 20); - gtk_widget_set_margin_bottom(page, 20); - gtk_box_append(GTK_BOX(page), top_bar(Y->map_page, title_key, sub_key)); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 10); - gtk_box_append(GTK_BOX(page), scroll); - L->stack = gtk_stack_new(); - gtk_stack_set_transition_type(GTK_STACK(L->stack), - GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), L->stack); - for (int s = 0; s < n_slides; s++) { - GtkWidget *card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - char name[16]; - - g_snprintf(name, sizeof name, "slide%d", s); - gtk_widget_set_margin_top(card, 8); - gtk_widget_set_margin_bottom(card, 8); - net_note_kicker(card, slides[s].kicker); - net_note_title(card, slides[s].title); - for (int i = 0; i < 8 && slides[s].line[i]; i++) - net_note_line(card, slides[s].line[i], FALSE); - if (slides[s].tip) - net_note_line(card, slides[s].tip, TRUE); - gtk_stack_add_named(GTK_STACK(L->stack), card, name); - } - nav = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_set_homogeneous(GTK_BOX(nav), TRUE); - gtk_widget_set_margin_top(nav, 10); - gtk_box_append(GTK_BOX(page), nav); - L->prev_btn = gtk_button_new_with_label(tr("net_slide_prev")); - gtk_widget_add_css_class(L->prev_btn, "btn-primary"); - gtk_box_append(GTK_BOX(nav), L->prev_btn); - g_signal_connect(L->prev_btn, "clicked", G_CALLBACK(qy_slide_prev), L); - L->next_btn = gtk_button_new_with_label(tr("net_slide_next")); - gtk_widget_add_css_class(L->next_btn, "btn-primary"); - gtk_box_append(GTK_BOX(nav), L->next_btn); - g_signal_connect(L->next_btn, "clicked", G_CALLBACK(qy_slide_next), L); - net_rescale_lesson_notes(L, 18, 32, 15); - net_notes_target = NULL; - L->idx = 0; - skill_slide_apply(L); - return page; -} - -typedef struct { - QuizYear *year; - int index; - const ChoiceQ *qs; - int n; - int n_opts; - GtkWidget *feedback; - GtkToggleButton **toggles; - GtkWidget **hints; -} QyQuiz; - -static void qy_check(GtkButton *button, gpointer data) { - QyQuiz *ctx = data; - int ok = 0; - - (void)button; - for (int i = 0; i < ctx->n; i++) { - int active = -1; - - for (int o = 0; o < ctx->n_opts; o++) { - GtkToggleButton *tb = ctx->toggles[i * ctx->n_opts + o]; - - gtk_widget_remove_css_class(GTK_WIDGET(tb), "ok"); - gtk_widget_remove_css_class(GTK_WIDGET(tb), "wrong"); - if (gtk_toggle_button_get_active(tb)) - active = o; - } - if (active == ctx->qs[i].correct) { - ok++; - if (active >= 0) - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "ok"); - } else if (active >= 0) { - gtk_widget_add_css_class( - GTK_WIDGET(ctx->toggles[i * ctx->n_opts + active]), "wrong"); - } - if (ctx->hints && ctx->hints[i]) - gtk_widget_set_visible(ctx->hints[i], TRUE); - } - if (ok == ctx->n) { - set_feedback(ctx->feedback, TRUE, tr("feedback_ok")); - qy_mark(ctx->year, ctx->index); - } else { - set_feedback(ctx->feedback, FALSE, tr("feedback_retry_short")); - } -} - -GtkWidget *quizyear_quiz(QuizYear *Y, int index, const char *title_key, - const char *head_key, const ChoiceQ *qs, - const char **hints, int n) { - QyQuiz *ctx = g_new0(QyQuiz, 1); - GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *scroll = gtk_scrolled_window_new(); - GtkWidget *body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - GtkWidget *head = gtk_label_new(NULL); - GtkWidget *intro = gtk_label_new(NULL); - GtkWidget *check; - int n_opts = qs[0].n_options; - - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), - top_bar(Y->lessons[index].unit_page, title_key, NULL)); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 12); - gtk_box_append(GTK_BOX(page), scroll); - gtk_widget_set_hexpand(body, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); - i18n_bind(head, head_key, 0); - gtk_widget_set_halign(head, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(head), TRUE); - gtk_widget_add_css_class(head, "quiz-heading"); - gtk_box_append(GTK_BOX(body), head); - i18n_bind(intro, "net_quiz_intro", 0); - gtk_widget_set_halign(intro, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(intro), TRUE); - gtk_widget_add_css_class(intro, "quiz-intro"); - gtk_box_append(GTK_BOX(body), intro); - - ctx->year = Y; - ctx->index = index; - ctx->qs = qs; - ctx->n = n; - ctx->n_opts = n_opts; - ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); - ctx->hints = g_new0(GtkWidget *, n); - for (int i = 0; i < n; i++) { - GtkWidget *card = mcq_append_question(body, i + 1, &qs[i], - &ctx->toggles[i * n_opts]); - - ctx->hints[i] = meaning_add(card, hints ? hints[i] : NULL); - } - check = gtk_button_new(); - i18n_bind(check, "check", 1); - gtk_widget_add_css_class(check, "btn-primary"); - gtk_widget_set_halign(check, GTK_ALIGN_START); - gtk_widget_set_margin_top(check, 8); - gtk_box_append(GTK_BOX(body), check); - g_signal_connect(check, "clicked", G_CALLBACK(qy_check), ctx); - ctx->feedback = gtk_label_new(""); - gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(ctx->feedback), TRUE); - gtk_box_append(GTK_BOX(body), ctx->feedback); - return page; -} - -GtkWidget *quizyear_map(QuizYear *Y) { - GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *scroll = gtk_scrolled_window_new(); - GtkWidget *list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); - - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - gtk_box_append(GTK_BOX(page), top_bar(Y->back_page, Y->title_key, Y->sub_key)); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 18); - gtk_box_append(GTK_BOX(page), scroll); - gtk_widget_set_halign(list, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(list, 520, -1); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), list); - for (int i = 0; i < QY_N; i++) { - GtkWidget *btn = gtk_button_new(); - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 14); - GtkWidget *texts = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - GtkWidget *title = gtk_label_new(NULL); - GtkWidget *sub = gtk_label_new(NULL); - char badge[8]; - GtkWidget *num; - - g_snprintf(badge, sizeof badge, "%d", i + 1); - num = gtk_label_new(badge); - gtk_widget_add_css_class(btn, "unit-node"); - gtk_widget_add_css_class(btn, "current"); - gtk_widget_set_hexpand(btn, TRUE); - gtk_widget_set_margin_start(row, 18); - gtk_widget_set_margin_end(row, 18); - gtk_widget_set_margin_top(row, 10); - gtk_widget_set_margin_bottom(row, 10); - gtk_button_set_child(GTK_BUTTON(btn), row); - gtk_widget_add_css_class(num, "unit-number"); - gtk_widget_set_valign(num, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(row), num); - gtk_widget_set_hexpand(texts, TRUE); - gtk_box_append(GTK_BOX(row), texts); - i18n_bind(title, Y->unit_key[i], 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "unit-name"); - gtk_box_append(GTK_BOX(texts), title); - i18n_bind(sub, Y->sub_keybuf[i], 0); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_label_set_xalign(GTK_LABEL(sub), 0); - gtk_widget_add_css_class(sub, "quiz-intro"); - gtk_box_append(GTK_BOX(texts), sub); - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(Y->unit_page[i]), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - Y->nodes[i] = btn; - qy_refresh_node(Y, i); - gtk_box_append(GTK_BOX(list), btn); - } - return page; -} diff --git a/src/roadmap.c b/src/roadmap.c deleted file mode 100644 index 13f0ba2..0000000 --- a/src/roadmap.c +++ /dev/null @@ -1,409 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Roadmap page */ -/* ------------------------------------------------------------------ */ - -/* Draw the "finish line" node: a locked-looking circle with the unit number - * and a small chequered flag. The chequers used to fill the whole circle, - * which read as the placeholder pattern for a missing image rather than as a - * flag, so they are now a badge sitting on a plain node face. */ -void draw_finish_cell(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - const double cell = 6.0; /* chequer square */ - const int flag_cols = 3; - const int flag_rows = 2; - const Rgb gray = color_from_hex(app_theme.overlay); - const Rgb fin_dark = color_from_hex(app_theme.finish_dark); - const Rgb fin_light = color_from_hex(app_theme.finish_light); - const Rgb fin_stroke = color_from_hex(app_theme.finish_stroke); - int n = GPOINTER_TO_INT(data); - double cx = width / 2.0; - double cy = height / 2.0; - double r = MIN(width, height) / 2.0 - 2.0; - char buf[8]; - PangoLayout *layout; - PangoFontDescription *fd; - PangoRectangle ink; - double num_cy; - double flag_x, flag_y; - int ix, iy; - - (void)area; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - cairo_save(cr); - cairo_new_path(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_clip(cr); - - cairo_rectangle(cr, cx - r, cy - r, 2.0 * r, 2.0 * r); - cairo_set_source_rgb(cr, fin_dark.r, fin_dark.g, fin_dark.b); - cairo_fill(cr); - - /* unit number, styled like the other locked nodes */ - g_snprintf(buf, sizeof(buf), "%d", n); - layout = pango_cairo_create_layout(cr); - fd = pango_font_description_new(); - pango_font_description_set_family(fd, "sans"); - pango_font_description_set_weight(fd, PANGO_WEIGHT_ULTRABOLD); - pango_font_description_set_size(fd, 22 * PANGO_SCALE); - pango_layout_set_font_description(layout, fd); - pango_layout_set_text(layout, buf, -1); - pango_layout_get_pixel_extents(layout, &ink, NULL); - - cairo_set_source_rgb(cr, gray.r, gray.g, gray.b); - num_cy = cy - 3.0; - cairo_move_to(cr, cx - ink.width / 2.0 - ink.x, - num_cy - ink.height / 2.0 - ink.y); - pango_cairo_show_layout(cr, layout); - - /* chequered flag below the number, where locked units show a padlock */ - flag_x = cx - (flag_cols * cell) / 2.0; - flag_y = num_cy + ink.height / 2.0 + 6.0; - for (iy = 0; iy < flag_rows; iy++) { - for (ix = 0; ix < flag_cols; ix++) { - const Rgb *c = ((ix + iy) & 1) ? &fin_light : &fin_stroke; - - cairo_rectangle(cr, flag_x + ix * cell, flag_y + iy * cell, - cell, cell); - cairo_set_source_rgb(cr, c->r, c->g, c->b); - cairo_fill(cr); - } - } - - g_object_unref(layout); - pango_font_description_free(fd); - cairo_restore(cr); - - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_set_source_rgb(cr, fin_stroke.r, fin_stroke.g, fin_stroke.b); - cairo_set_line_width(cr, 2.0); - cairo_stroke(cr); -} - -void road_point(double t, double *ox, double *oy) { - int k = (int)t; - double u = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (k < 0) { k = 0; u = 0.0; } - if (k >= NUM_UNITS - 1) { k = NUM_UNITS - 2; u = 1.0; } - - p1x = road_cx[k]; p1y = road_cy[k]; - p2x = road_cx[k + 1]; p2y = road_cy[k + 1]; - if (k - 1 >= 0) { p0x = road_cx[k - 1]; p0y = road_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < NUM_UNITS) { p3x = road_cx[k + 2]; p3y = road_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = u * u; - u3 = u2 * u; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * u - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * u - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -void road_path(cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 48.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - road_point(t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - road_point(t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -/* Compute the serpentine node layout for the given available width. */ -void roadmap_geometry(double avail) { - const double phase = 2.0 * G_PI * 1.7 / (double)(NUM_UNITS - 1); - int rows; - int r, c, i; - - for (rows = 1; rows <= NUM_UNITS; rows++) { - int cols = (NUM_UNITS + rows - 1) / rows; - if (2.0 * ROAD_MX + (cols - 1) * PATH_SPAC <= avail + 1.0) - break; - } - if (rows > NUM_UNITS) - rows = NUM_UNITS; - road_rows = rows; - road_cols = (NUM_UNITS + rows - 1) / rows; - if (road_cols < 1) - road_cols = 1; - road_cw = (int)(2.0 * ROAD_MX + (road_cols - 1) * PATH_SPAC); - road_ch = (int)(2.0 * ROAD_MY + (rows - 1) * ROAD_GAP); - - for (r = 0; r < rows; r++) { - int base = r * road_cols; - int len = MIN(road_cols, NUM_UNITS - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (road_cols - 1 - c); - road_cx[i] = ROAD_MX + cc * PATH_SPAC; - road_cy[i] = ROAD_MY + r * ROAD_GAP - + ROAD_WAVE * sin((double)i * phase); - } - } -} - -void road_apply_layout(void) { - int i; - - if (!road_fixed) - return; - - for (i = 0; i < NUM_UNITS; i++) { - if (!road_nodes[i] || !road_labels[i]) - continue; - gtk_fixed_move(GTK_FIXED(road_fixed), road_nodes[i], - (int)(road_cx[i] - NODE_SIZE / 2.0), - (int)(road_cy[i] - NODE_SIZE / 2.0)); - gtk_fixed_move(GTK_FIXED(road_fixed), road_labels[i], - (int)(road_cx[i] - (PATH_SPAC - 20.0) / 2.0), - (int)(road_cy[i] + NODE_SIZE / 2.0 + 10.0)); - } - - gtk_widget_set_size_request(road_fixed, road_cw, road_ch); - gtk_widget_set_size_request(road_rail, road_cw, road_ch); - gtk_fixed_move(GTK_FIXED(road_fixed), road_rail, 0, 0); - gtk_widget_queue_draw(road_rail); -} - -void road_relayout(void) { - GtkAdjustment *hadj; - double avail; - - if (!road_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(road_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - roadmap_geometry(avail); - road_apply_layout(); -} - -guint road_idle; - -gboolean road_relayout_idle(gpointer data) { - (void)data; - road_idle = 0; - road_relayout(); - return G_SOURCE_REMOVE; -} - -void road_relayout_later(void) { - if (road_idle == 0) - road_idle = g_idle_add(road_relayout_idle, NULL); -} - -void road_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - (void)data; - road_relayout_later(); -} - -void draw_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer user_data) { - const double t_lit = (double)(NUM_UNLOCKED - 1); - const double t_end = (double)(NUM_UNITS - 1); - const Rgb accent = color_from_hex(app_theme.accent); - const Rgb rail = color_from_hex(app_theme.rail); - const Rgb muted = color_from_hex(app_theme.subtext); - - (void)area; - (void)width; - (void)height; - (void)user_data; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - road_path(cr, 0.0, t_end); - cairo_set_line_width(cr, 12); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - if (t_lit > 0.0) { - cairo_new_path(cr); - road_path(cr, 0.0, t_lit); - cairo_set_source_rgb(cr, accent.r, accent.g, accent.b); - cairo_set_line_width(cr, 12); - cairo_stroke(cr); - } - - { - double start_t = t_lit > 0.0 ? t_lit : 0.0; - - cairo_set_source_rgba(cr, muted.r, muted.g, muted.b, 0.17); - cairo_set_dash(cr, (double[]){1.0, 26.0}, 2, 0.0); - cairo_new_path(cr); - road_path(cr, start_t, t_end); - cairo_stroke(cr); - cairo_set_dash(cr, NULL, 0, 0.0); - } -} - -void add_path_node(GtkFixed *fixed, int index) { - int num = index + 1; - UnitCtx *u = &units[index]; - gboolean locked = !u->unlocked; - GtkWidget *card; - GtkWidget *name; - char *text; - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "unit-node"); - gtk_widget_set_can_focus(card, FALSE); - gtk_widget_set_sensitive(card, !locked); - gtk_widget_set_size_request(card, (int)NODE_SIZE, (int)NODE_SIZE); - - if (index == NUM_UNITS - 1) { - GtkWidget *fin = gtk_drawing_area_new(); - - gtk_widget_add_css_class(card, "finish"); - gtk_widget_add_css_class(card, "locked"); - gtk_widget_set_size_request(fin, (int)NODE_SIZE, (int)NODE_SIZE); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(fin), - draw_finish_cell, - GINT_TO_POINTER(num), NULL); - gtk_button_set_child(GTK_BUTTON(card), fin); - } else { - GtkWidget *vbox; - GtkWidget *number; - GtkWidget *icon; - - /* Unlocked units start out plain; refresh_completion_ui() decides - * which single one is the current step. */ - if (locked) - gtk_widget_add_css_class(card, "locked"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), vbox); - - text = g_strdup_printf("%d", num); - number = gtk_label_new(text); - g_free(text); - gtk_widget_add_css_class(number, "unit-number"); - gtk_box_append(GTK_BOX(vbox), number); - - if (locked) { - icon = icon_area_new(draw_lock_icon, - 0.3451, 0.3569, 0.4392, 16); - } else { - icon = icon_area_new(draw_check_icon, - 0.1176, 0.1176, 0.1804, 18); - gtk_widget_set_visible(icon, FALSE); - u->node = card; - u->node_done_icon = icon; - g_object_set_data_full(G_OBJECT(card), "target", - g_strdup(u->page), g_free); - g_signal_connect(card, "clicked", G_CALLBACK(on_nav_clicked), NULL); - } - gtk_box_append(GTK_BOX(vbox), icon); - } - - road_nodes[index] = card; - gtk_fixed_put(fixed, card, 0, 0); - - name = gtk_label_new(u->title); - gtk_widget_set_size_request(name, (int)(PATH_SPAC - 20.0), -1); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(name), TRUE); - gtk_widget_add_css_class(name, "unit-name"); - if (locked) - gtk_widget_add_css_class(name, "unit-name-locked"); - road_labels[index] = name; - gtk_fixed_put(fixed, name, 0, 0); -} - -GtkWidget *build_roadmap_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - int i; - - roadmap_geometry(1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar("dehome", "roadmap_title", "roadmap_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - road_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, road_cw, road_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - road_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, road_cw, road_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), draw_rail, NULL, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - road_rail = rail; - - for (i = 0; i < NUM_UNITS; i++) - add_path_node(GTK_FIXED(fixed), i); - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(road_adjust_notify), NULL); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(road_adjust_notify), NULL); - - road_apply_layout(); - road_relayout_later(); - - return page; -} - diff --git a/src/search.c b/src/search.c deleted file mode 100644 index 7b3d149..0000000 --- a/src/search.c +++ /dev/null @@ -1,800 +0,0 @@ -#include "graduately.h" - -#include -#include - -#define SEARCH_MAX 24 - -typedef struct { - char *title; - char *subtitle; - char *hay; - char *target; - gboolean locked; - int rank; - int score; -} SearchItem; - -static GtkWidget *search_layer; -static GtkWidget *search_reveal; -static gboolean search_want_open; -static GtkWidget *search_entry; -static GtkWidget *search_list; -static GtkWidget *search_empty; -static GPtrArray *search_items; - -static gboolean subject_open(int i) { - return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ - || i == ON_SUBJ || i == EN_SUBJ || i == MATH_SUBJ || i == PHY_SUBJ - || i == SCI_SUBJ; -} - -static const char *subject_page(int i) { - if (i == 0) - return "dehome"; - if (i == NET_SUBJ) - return "netyears"; - if (i == HW_SUBJ) - return "hwyears"; - if (i == CZ_SUBJ) - return "czechmap"; - if (i == ON_SUBJ) - return "onyears"; - if (i == EN_SUBJ) - return "enyears"; - if (i == MATH_SUBJ) - return "matyears"; - if (i == PHY_SUBJ) - return "fyzyears"; - if (i == SCI_SUBJ) - return "scimap"; - return "subjects"; -} - -static void hay_add(GString *h, const char *text) { - if (text && *text) { - g_string_append(h, text); - g_string_append_c(h, ' '); - } -} - -static void hay_add_key(GString *h, const char *key) { - int i; - - hay_add(h, key); - for (i = 0; tr_ui[i].key; i++) { - if (g_strcmp0(tr_ui[i].key, key) == 0) { - hay_add(h, tr_ui[i].cs); - hay_add(h, tr_ui[i].en); - return; - } - } -} - -static SearchItem *item_new(const char *title, const char *subtitle, - const char *target, gboolean locked, int rank, - const char *extra) { - SearchItem *it = g_new0(SearchItem, 1); - GString *h = g_string_new(NULL); - char *norm; - - it->title = g_strdup(title ? title : ""); - it->subtitle = g_strdup(subtitle ? subtitle : ""); - it->target = g_strdup(target ? target : ""); - it->locked = locked; - it->rank = rank; - hay_add(h, title); - hay_add(h, subtitle); - hay_add(h, extra); - hay_add(h, target); - norm = normalize_answer(h->str); - it->hay = norm ? norm : g_strdup(""); - g_string_free(h, TRUE); - return it; -} - -static void item_free(gpointer p) { - SearchItem *it = p; - - if (!it) - return; - g_free(it->title); - g_free(it->subtitle); - g_free(it->hay); - g_free(it->target); - g_free(it); -} - -static void catalog_add(const char *title, const char *subtitle, - const char *target, gboolean locked, int rank, - const char *extra); - -void search_catalog_add(const char *title, const char *subtitle, - const char *target, gboolean locked, int rank, - const char *extra) { - catalog_add(title, subtitle, target, locked, rank, extra); -} - -static void catalog_add(const char *title, const char *subtitle, - const char *target, gboolean locked, int rank, - const char *extra) { - if (!title || !target) - return; - if (main_stack && !gtk_stack_get_child_by_name(main_stack, target) - && strncmp(target, "cetbastub:", 10) != 0) - return; - g_ptr_array_add(search_items, - item_new(title, subtitle, target, locked, rank, extra)); -} - -static void catalog_add_key(const char *title_key, const char *sub_key, - const char *target, gboolean locked, int rank, - const char *extra) { - GString *h = g_string_new(NULL); - SearchItem *it; - - if (!title_key || !target) - return; - if (main_stack && !gtk_stack_get_child_by_name(main_stack, target)) - return; - hay_add_key(h, title_key); - if (sub_key) - hay_add_key(h, sub_key); - hay_add(h, extra); - it = item_new(tr(title_key), sub_key ? tr(sub_key) : "", - target, locked, rank, h->str); - g_string_free(h, TRUE); - g_ptr_array_add(search_items, it); -} - -static void catalog_rebuild(void) { - int i, n; - char key[32]; - char page[32]; - - if (!search_items) - search_items = g_ptr_array_new_with_free_func(item_free); - else - g_ptr_array_set_size(search_items, 0); - - catalog_add_key("subjects_title", "search_page", "subjects", FALSE, 0, - "predmety subjects mapa"); - catalog_add_key("stats", "search_page", "stats", FALSE, 0, "progress"); - catalog_add_key("search_home", "search_page", "welcome", FALSE, 0, - "uvod welcome uvodni"); - - for (i = 0; i < NUM_SUBJECTS; i++) { - gboolean open = subject_open(i); - - catalog_add_key(sub_keys[i], "search_subject", - open ? subject_page(i) : "subjects", !open, 0, NULL); - } - - for (i = 0; i < NUM_UNITS; i++) { - UnitCtx *u = &units[i]; - const char *target = (u->unlocked && u->page) ? u->page : "roadmap"; - - catalog_add(u->title, tr("search_unit"), target, !u->unlocked, 1, - "deutsch nemcina german"); - if (!u->unlocked || !u->ex_tag) - continue; - if (u->has_branch && u->branch_target) - catalog_add(u->branch_name, u->title, u->branch_target, FALSE, 2, - "vokabel slovicka vocabulary"); - for (n = 1; n <= u->n_ex; n++) { - g_snprintf(page, sizeof(page), "%se%d", u->ex_tag, n); - catalog_add(u->ex_names[n], u->title, page, FALSE, 3, NULL); - } - } - - catalog_add_key("net_years_title", "search_subject", "netyears", FALSE, 0, - "site network ip"); - catalog_add_key("net_year1", "search_lesson", "netmap", FALSE, 1, "rocnik"); - catalog_add_key("net_year2", "search_lesson", "net2map", FALSE, 1, "rocnik"); - catalog_add_key("net_year3", "search_lesson", "net3map", FALSE, 1, "rocnik"); - catalog_add_key("net_year4", "search_lesson", "net4map", FALSE, 1, "rocnik"); - for (i = 1; i <= NET_LESSONS; i++) { - g_snprintf(key, sizeof(key), "net_unit%d", i); - g_snprintf(page, sizeof(page), "netunit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "site sit"); - g_snprintf(page, sizeof(page), "netex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 2; i <= 4; i++) { - for (n = 1; n <= 8; n++) { - g_snprintf(key, sizeof key, "net%d_unit%d", i, n); - g_snprintf(page, sizeof page, "net%dunit%d", i, n); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "site sit"); - } - } - - catalog_add_key("hw_year1", "search_lesson", "hwmap", FALSE, 1, "rocnik"); - catalog_add_key("hw_year2", "search_lesson", "hw2map", FALSE, 1, "rocnik"); - catalog_add_key("hw_year3", "search_lesson", "hw3map", FALSE, 1, "rocnik"); - catalog_add_key("hw_year4", "search_lesson", "hw4map", FALSE, 1, "rocnik"); - for (i = 1; i <= HW_LESSONS; i++) { - g_snprintf(key, sizeof(key), "hw_unit%d", i); - g_snprintf(page, sizeof(page), "hwunit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "hardware hw"); - g_snprintf(page, sizeof(page), "hwex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 2; i <= 4; i++) { - for (n = 1; n <= 8; n++) { - g_snprintf(key, sizeof key, "hw%d_unit%d", i, n); - g_snprintf(page, sizeof page, "hw%dunit%d", i, n); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "hardware hw"); - } - } - - catalog_add_key("on_year1", "search_lesson", "onmap", FALSE, 1, "rocnik"); - catalog_add_key("on_year2", "search_lesson", "on2map", FALSE, 1, "rocnik"); - catalog_add_key("on_year3", "search_lesson", "on3map", FALSE, 1, "rocnik"); - catalog_add_key("on_year4", "search_lesson", "on4map", FALSE, 1, "rocnik"); - for (i = 1; i <= ON_LESSONS; i++) { - g_snprintf(key, sizeof(key), "on_unit%d", i); - g_snprintf(page, sizeof(page), "onunit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "obcanka"); - g_snprintf(page, sizeof(page), "onex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= ON2_LESSONS; i++) { - g_snprintf(key, sizeof(key), "on2_unit%d", i); - g_snprintf(page, sizeof(page), "on2unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "obcanka"); - g_snprintf(page, sizeof(page), "on2ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= ON3_LESSONS; i++) { - g_snprintf(key, sizeof(key), "on3_unit%d", i); - g_snprintf(page, sizeof(page), "on3unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "obcanka"); - g_snprintf(page, sizeof(page), "on3ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= ON4_LESSONS; i++) { - g_snprintf(key, sizeof(key), "on4_unit%d", i); - g_snprintf(page, sizeof(page), "on4unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "obcanka"); - g_snprintf(page, sizeof(page), "on4ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - - catalog_add_key("en_year1", "search_lesson", "en1map", FALSE, 1, "anglictina english"); - catalog_add_key("en_year2", "search_lesson", "en2map", FALSE, 1, "anglictina english"); - catalog_add_key("en_year3", "search_lesson", "en3map", FALSE, 1, "anglictina english"); - catalog_add_key("en_year4", "search_lesson", "en4map", FALSE, 1, "anglictina english"); - catalog_add_key("de_book_title", "search_unit", "roadmap", FALSE, 1, "nemcina deutsch ucebnice"); - for (i = 1; i <= 4; i++) { - g_snprintf(key, sizeof key, "de_year%d", i); - g_snprintf(page, sizeof page, "de%dmap", i); - catalog_add_key(key, "search_lesson", page, FALSE, 1, "nemcina deutsch rocnik"); - for (n = 1; n <= 6; n++) { - g_snprintf(key, sizeof key, "de_y%d_u%d", i, n); - g_snprintf(page, sizeof page, "de%dunit%d", i, n); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "nemcina deutsch"); - } - } - for (int y = 1; y <= 4; y++) { - for (i = 1; i <= 8; i++) { - g_snprintf(key, sizeof(key), "en_y%d_u%d", y, i); - g_snprintf(page, sizeof(page), "en%dunit%d", y, i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "anglictina english"); - g_snprintf(page, sizeof(page), "en%dex%d", y, i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, - "poslech cteni psani kviz"); - } - } - - catalog_add_key("Český jazyk a literatura", "search_subject", - "czechmap", FALSE, 0, "cestina czech"); - catalog_add_key("Literatura", "search_lesson", "lityears", FALSE, 1, - "literatura"); - catalog_add_key("lit_year1", "search_lesson", "litmap", FALSE, 1, "rocnik"); - catalog_add_key("lit_year2", "search_lesson", "lit2map", FALSE, 1, "rocnik"); - catalog_add_key("lit_year3", "search_lesson", "lit3map", FALSE, 1, "rocnik"); - catalog_add_key("lit_year4", "search_lesson", "lit4map", FALSE, 1, "rocnik"); - for (i = 1; i <= LIT_N; i++) { - g_snprintf(key, sizeof(key), "lit_unit%d", i); - g_snprintf(page, sizeof(page), "litunit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); - g_snprintf(page, sizeof(page), "litex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= LIT_N; i++) { - g_snprintf(key, sizeof(key), "lit2_unit%d", i); - g_snprintf(page, sizeof(page), "lit2unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); - g_snprintf(page, sizeof(page), "lit2ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= LIT_N; i++) { - g_snprintf(key, sizeof(key), "lit3_unit%d", i); - g_snprintf(page, sizeof(page), "lit3unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); - g_snprintf(page, sizeof(page), "lit3ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= LIT_N; i++) { - g_snprintf(key, sizeof(key), "lit4_unit%d", i); - g_snprintf(page, sizeof(page), "lit4unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "literatura"); - g_snprintf(page, sizeof(page), "lit4ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - catalog_add_key("Matematika", "search_lesson", "matyears", FALSE, 1, "matematika"); - catalog_add_key("mat0_year", "search_lesson", "mat0map", FALSE, 1, "matematika zakladka"); - catalog_add_key("mat_year1", "search_lesson", "matmap", FALSE, 1, "matematika rocnik"); - catalog_add_key("mat_year2", "search_lesson", "mat2map", FALSE, 1, "matematika rocnik"); - catalog_add_key("mat_year3", "search_lesson", "mat3map", FALSE, 1, "matematika rocnik"); - catalog_add_key("mat_year4", "search_lesson", "mat4map", FALSE, 1, "matematika rocnik"); - for (i = 1; i <= MATH_N; i++) { - g_snprintf(key, sizeof(key), "mat0_unit%d", i); - g_snprintf(page, sizeof(page), "mat0unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "matematika"); - g_snprintf(page, sizeof(page), "mat0ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "priklady"); - } - for (i = 1; i <= MATH_N; i++) { - g_snprintf(key, sizeof(key), "mat_unit%d", i); - g_snprintf(page, sizeof(page), "matunit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "matematika"); - g_snprintf(page, sizeof(page), "matex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "priklady"); - } - for (i = 1; i <= MATH_N; i++) { - g_snprintf(key, sizeof(key), "mat2_unit%d", i); - g_snprintf(page, sizeof(page), "mat2unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "matematika"); - g_snprintf(page, sizeof(page), "mat2ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "priklady"); - } - for (i = 1; i <= MATH_N; i++) { - g_snprintf(key, sizeof(key), "mat3_unit%d", i); - g_snprintf(page, sizeof(page), "mat3unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "matematika"); - g_snprintf(page, sizeof(page), "mat3ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "priklady"); - } - for (i = 1; i <= MATH_N; i++) { - g_snprintf(key, sizeof(key), "mat4_unit%d", i); - g_snprintf(page, sizeof(page), "mat4unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "matematika"); - g_snprintf(page, sizeof(page), "mat4ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "priklady"); - } - catalog_add_key("fyz_year1", "search_lesson", "fyzmap", FALSE, 1, "fyzika rocnik"); - catalog_add_key("fyz_year2", "search_lesson", "fyz2map", FALSE, 1, "fyzika rocnik"); - catalog_add_key("fyz_year3", "search_lesson", "fyz3map", FALSE, 1, "fyzika rocnik"); - catalog_add_key("fyz_year4", "search_lesson", "fyz4map", FALSE, 1, "fyzika rocnik"); - for (i = 1; i <= FYZ_N; i++) { - g_snprintf(key, sizeof(key), "fyz_unit%d", i); - g_snprintf(page, sizeof(page), "fyzunit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika"); - g_snprintf(page, sizeof(page), "fyzex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= FYZ_N; i++) { - g_snprintf(key, sizeof(key), "fyz2_unit%d", i); - g_snprintf(page, sizeof(page), "fyz2unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika"); - g_snprintf(page, sizeof(page), "fyz2ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= FYZ_N; i++) { - g_snprintf(key, sizeof(key), "fyz3_unit%d", i); - g_snprintf(page, sizeof(page), "fyz3unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika"); - g_snprintf(page, sizeof(page), "fyz3ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= FYZ_N; i++) { - g_snprintf(key, sizeof(key), "fyz4_unit%d", i); - g_snprintf(page, sizeof(page), "fyz4unit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "fyzika"); - g_snprintf(page, sizeof(page), "fyz4ex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - catalog_add_key("Chemie", "search_lesson", "chemmap", FALSE, 1, "chemie"); - catalog_add_key("Biologie", "search_lesson", "biomap", FALSE, 1, "biologie"); - for (i = 1; i <= SCI_N; i++) { - g_snprintf(key, sizeof(key), "chem_unit%d", i); - g_snprintf(page, sizeof(page), "chemunit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "chemie"); - g_snprintf(page, sizeof(page), "chemex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - for (i = 1; i <= SCI_N; i++) { - g_snprintf(key, sizeof(key), "bio_unit%d", i); - g_snprintf(page, sizeof(page), "biounit%d", i); - catalog_add_key(key, "search_lesson", page, FALSE, 2, "biologie"); - g_snprintf(page, sizeof(page), "bioex%d", i); - catalog_add(tr(key), tr("search_exercise"), page, FALSE, 3, "kviz quiz"); - } - catalog_add_key("Mluvnice", "search_lesson", "mluvnice", FALSE, 1, - "gramatika grammar"); - catalog_add_key("Maturitní četba", "search_book", "readinglist", FALSE, 1, - "knihy books"); - cetba_register_search(); - - { - static const char *mluv_names[] = { - "i/y", "Velká písmena", "Slovní druhy", "Podst. jména", "Slovesa", - "Slovotvorba", "Větné členy", "Vedlejší věty", "Synonyma", - "Antonyma", "s/z", "Najdi chybu", "Tvary", "Test A–D", - "Přímá řeč", "Rozdíly", "Interpunkce", "Obrazná pojmen.", - "Slohové útvary", "Opakování", - }; - - for (i = 0; i < (int)G_N_ELEMENTS(mluv_names); i++) { - g_snprintf(page, sizeof(page), "mluve%d", i + 1); - catalog_add(mluv_names[i], tr("Mluvnice"), page, FALSE, 3, - "mluvnice gramatika"); - } - } -} - -static int item_score(const SearchItem *it, const char *needle) { - const char *p; - - if (!needle || !*needle) - return 40 - it->rank; - if (!it->hay || !it->hay[0]) - return -1; - if (g_strcmp0(it->hay, needle) == 0) - return 200 - it->rank; - if (g_str_has_prefix(it->hay, needle)) - return 160 - it->rank; - p = strstr(it->hay, needle); - if (!p) - return -1; - if (p > it->hay && p[-1] == ' ') - return 120 - it->rank; - return 80 - it->rank; -} - -static int cmp_item(gconstpointer a, gconstpointer b) { - const SearchItem *ia = *(SearchItem * const *)a; - const SearchItem *ib = *(SearchItem * const *)b; - - if (ia->score != ib->score) - return ib->score - ia->score; - return g_strcmp0(ia->title, ib->title); -} - -static void search_go(const char *target) { - if (!target || !main_stack) - return; - if (strncmp(target, "cetbastub:", 10) == 0) { - int idx = atoi(target + 10); - search_close(); - cetba_open_stub(idx); - return; - } - if (!gtk_stack_get_child_by_name(main_stack, target)) - return; - search_close(); - show_page(target, 1); -} - -static void on_row_activated(GtkListBox *box, GtkListBoxRow *row, - gpointer data) { - const char *target; - - (void)box; - (void)data; - if (!row) - return; - target = g_object_get_data(G_OBJECT(row), "target"); - search_go(target); -} - -static void search_fill(void) { - const char *raw; - char *needle; - GPtrArray *hits; - guint i; - - if (!search_list) - return; - catalog_rebuild(); - raw = gtk_editable_get_text(GTK_EDITABLE(search_entry)); - needle = normalize_answer(raw ? raw : ""); - hits = g_ptr_array_new(); - - for (i = 0; i < search_items->len; i++) { - SearchItem *it = g_ptr_array_index(search_items, i); - int score; - - if (!needle[0] && it->rank > 1) - continue; - score = item_score(it, needle); - if (score < 0) - continue; - it->score = score; - g_ptr_array_add(hits, it); - } - g_ptr_array_sort(hits, cmp_item); - if (hits->len > SEARCH_MAX) - g_ptr_array_set_size(hits, SEARCH_MAX); - - { - GtkWidget *c = gtk_widget_get_first_child(search_list); - - while (c) { - GtkWidget *next = gtk_widget_get_next_sibling(c); - - gtk_list_box_remove(GTK_LIST_BOX(search_list), c); - c = next; - } - } - for (i = 0; i < hits->len; i++) { - SearchItem *it = g_ptr_array_index(hits, i); - GtkWidget *row; - GtkWidget *box; - GtkWidget *title; - GtkWidget *sub; - GString *sub_text; - - row = gtk_list_box_row_new(); - gtk_widget_add_css_class(row, "search-hit"); - if (it->locked) - gtk_widget_add_css_class(row, "search-hit-locked"); - g_object_set_data_full(G_OBJECT(row), "target", - g_strdup(it->target), g_free); - - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_margin_start(box, 12); - gtk_widget_set_margin_end(box, 12); - gtk_widget_set_margin_top(box, 8); - gtk_widget_set_margin_bottom(box, 8); - gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), box); - - title = gtk_label_new(it->title); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_label_set_xalign(GTK_LABEL(title), 0.0); - gtk_label_set_ellipsize(GTK_LABEL(title), PANGO_ELLIPSIZE_END); - gtk_widget_add_css_class(title, "search-hit-title"); - gtk_box_append(GTK_BOX(box), title); - - sub_text = g_string_new(it->subtitle); - if (it->locked) { - if (sub_text->len) - g_string_append(sub_text, " · "); - g_string_append(sub_text, tr("stats_locked")); - } - sub = gtk_label_new(sub_text->str); - g_string_free(sub_text, TRUE); - gtk_widget_set_halign(sub, GTK_ALIGN_START); - gtk_label_set_xalign(GTK_LABEL(sub), 0.0); - gtk_widget_add_css_class(sub, "search-hit-sub"); - gtk_box_append(GTK_BOX(box), sub); - - gtk_list_box_append(GTK_LIST_BOX(search_list), row); - } - - gtk_widget_set_visible(search_empty, hits->len == 0); - gtk_widget_set_visible(search_list, hits->len > 0); - if (hits->len > 0) - gtk_list_box_select_row(GTK_LIST_BOX(search_list), - gtk_list_box_get_row_at_index( - GTK_LIST_BOX(search_list), 0)); - if (needle[0]) - gtk_label_set_text(GTK_LABEL(search_empty), tr("search_empty")); - else - gtk_label_set_text(GTK_LABEL(search_empty), tr("search_hint")); - - g_ptr_array_unref(hits); - g_free(needle); -} - -static void on_search_changed(GtkEditable *editable, gpointer data) { - (void)editable; - (void)data; - search_fill(); -} - -static void search_activate_selected(void) { - GtkListBoxRow *row; - - if (!search_list) - return; - row = gtk_list_box_get_selected_row(GTK_LIST_BOX(search_list)); - if (!row) - row = gtk_list_box_get_row_at_index(GTK_LIST_BOX(search_list), 0); - if (row) - search_go(g_object_get_data(G_OBJECT(row), "target")); -} - -static gboolean on_entry_key(GtkEventControllerKey *controller, guint keyval, - guint keycode, GdkModifierType state, - gpointer data) { - (void)controller; - (void)keycode; - (void)state; - (void)data; - - if (keyval == GDK_KEY_Escape) { - search_close(); - return TRUE; - } - if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter) { - search_activate_selected(); - return TRUE; - } - if (keyval == GDK_KEY_Down || keyval == GDK_KEY_Tab) { - GtkListBoxRow *row = gtk_list_box_get_row_at_index( - GTK_LIST_BOX(search_list), 0); - - if (row) - gtk_widget_grab_focus(GTK_WIDGET(row)); - return TRUE; - } - return FALSE; -} - -static void on_scrim_clicked(GtkGestureClick *g, gint n_press, gdouble x, - gdouble y, gpointer data) { - (void)g; - (void)n_press; - (void)x; - (void)y; - (void)data; - search_close(); -} - -static void on_search_revealed(GObject *obj, GParamSpec *pspec, gpointer data) { - GtkRevealer *reveal = GTK_REVEALER(obj); - - (void)pspec; - (void)data; - if (!gtk_revealer_get_reveal_child(reveal) && - !gtk_revealer_get_child_revealed(reveal)) - gtk_widget_set_visible(GTK_WIDGET(reveal), FALSE); -} - -gboolean search_is_open(void) { - return search_want_open; -} - -void search_close(void) { - search_want_open = FALSE; - if (search_reveal) - gtk_revealer_set_reveal_child(GTK_REVEALER(search_reveal), FALSE); -} - -static gboolean reveal_search(gpointer data) { - (void)data; - if (search_want_open && search_reveal) - gtk_revealer_set_reveal_child(GTK_REVEALER(search_reveal), TRUE); - return G_SOURCE_REMOVE; -} - -void search_open(void) { - if (!search_reveal) - return; - search_want_open = TRUE; - gtk_widget_set_visible(search_reveal, TRUE); - /* Wait a frame so the overlay is mapped and the fade actually runs. */ - g_idle_add(reveal_search, NULL); - if (search_entry) { - gtk_editable_set_text(GTK_EDITABLE(search_entry), ""); - gtk_widget_grab_focus(search_entry); - } - search_fill(); -} - -void search_apply_lang(void) { - if (!search_layer) - return; - if (search_is_open()) - search_fill(); -} - -static void on_search_clicked(GtkButton *button, gpointer data) { - (void)button; - (void)data; - if (search_is_open()) - search_close(); - else - search_open(); -} - -GtkWidget *build_search_button(void) { - GtkWidget *btn; - GtkWidget *icon; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "settings-btn"); - gtk_widget_add_css_class(btn, "flat"); - i18n_bind(btn, "search", 2); - gtk_widget_set_valign(btn, GTK_ALIGN_CENTER); - gtk_widget_set_focus_on_click(btn, FALSE); - - icon = gtk_drawing_area_new(); - gtk_widget_set_size_request(icon, 18, 18); - gtk_widget_set_can_target(icon, FALSE); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(icon), - draw_search_icon, NULL, NULL); - gtk_button_set_child(GTK_BUTTON(btn), icon); - g_signal_connect_swapped(btn, "state-flags-changed", - G_CALLBACK(gtk_widget_queue_draw), icon); - g_signal_connect(btn, "clicked", G_CALLBACK(on_search_clicked), NULL); - return btn; -} - -void search_attach(GtkOverlay *overlay) { - GtkWidget *scrim; - GtkWidget *card; - GtkWidget *scroll; - GtkEventController *keys; - GtkGesture *click; - - search_layer = gtk_overlay_new(); - gtk_widget_add_css_class(search_layer, "search-layer"); - gtk_widget_set_hexpand(search_layer, TRUE); - gtk_widget_set_vexpand(search_layer, TRUE); - - scrim = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class(scrim, "search-scrim"); - gtk_widget_set_hexpand(scrim, TRUE); - gtk_widget_set_vexpand(scrim, TRUE); - gtk_overlay_set_child(GTK_OVERLAY(search_layer), scrim); - click = gtk_gesture_click_new(); - g_signal_connect(click, "pressed", G_CALLBACK(on_scrim_clicked), NULL); - gtk_widget_add_controller(scrim, GTK_EVENT_CONTROLLER(click)); - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_widget_add_css_class(card, "search-card"); - gtk_widget_set_halign(card, GTK_ALIGN_CENTER); - gtk_widget_set_valign(card, GTK_ALIGN_START); - gtk_widget_set_margin_top(card, 72); - gtk_widget_set_size_request(card, 560, -1); - gtk_overlay_add_overlay(GTK_OVERLAY(search_layer), card); - - search_entry = gtk_entry_new(); - gtk_widget_add_css_class(search_entry, "search-entry"); - i18n_bind(search_entry, "search_placeholder", 3); - gtk_box_append(GTK_BOX(card), search_entry); - g_signal_connect(search_entry, "changed", - G_CALLBACK(on_search_changed), NULL); - keys = gtk_event_controller_key_new(); - g_signal_connect(keys, "key-pressed", G_CALLBACK(on_entry_key), NULL); - gtk_widget_add_controller(search_entry, keys); - - search_empty = gtk_label_new(NULL); - i18n_bind(search_empty, "search_hint", 0); - gtk_widget_add_css_class(search_empty, "search-empty"); - gtk_box_append(GTK_BOX(card), search_empty); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_max_content_height(GTK_SCROLLED_WINDOW(scroll), - 420); - gtk_scrolled_window_set_propagate_natural_height( - GTK_SCROLLED_WINDOW(scroll), TRUE); - gtk_box_append(GTK_BOX(card), scroll); - - search_list = gtk_list_box_new(); - gtk_widget_add_css_class(search_list, "search-results"); - gtk_list_box_set_selection_mode(GTK_LIST_BOX(search_list), - GTK_SELECTION_SINGLE); - gtk_list_box_set_activate_on_single_click(GTK_LIST_BOX(search_list), TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), search_list); - g_signal_connect(search_list, "row-activated", - G_CALLBACK(on_row_activated), NULL); - - search_reveal = gtk_revealer_new(); - gtk_revealer_set_transition_type(GTK_REVEALER(search_reveal), - GTK_REVEALER_TRANSITION_TYPE_CROSSFADE); - gtk_revealer_set_transition_duration(GTK_REVEALER(search_reveal), 160); - gtk_revealer_set_reveal_child(GTK_REVEALER(search_reveal), FALSE); - gtk_widget_set_hexpand(search_reveal, TRUE); - gtk_widget_set_vexpand(search_reveal, TRUE); - gtk_widget_set_visible(search_reveal, FALSE); - gtk_revealer_set_child(GTK_REVEALER(search_reveal), search_layer); - g_signal_connect(search_reveal, "notify::child-revealed", - G_CALLBACK(on_search_revealed), NULL); - gtk_overlay_add_overlay(overlay, search_reveal); -} diff --git a/src/settings.c b/src/settings.c deleted file mode 100644 index b951b3d..0000000 --- a/src/settings.c +++ /dev/null @@ -1,361 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Settings */ -/* ------------------------------------------------------------------ */ - -static GtkWidget *settings_popover; - -void settings_open(void) { - if (settings_popover) - gtk_popover_popup(GTK_POPOVER(settings_popover)); -} - -void draw_theme_swatch(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - ThemeId id = (ThemeId)GPOINTER_TO_INT(data); - ThemePalette p = theme_palette(id, app_color_mode); - Rgb base = color_from_hex(p.base); - Rgb a1 = color_from_hex(p.accent); - Rgb a2 = color_from_hex(p.accent3); - Rgb ok = color_from_hex(p.success); - Rgb accent = color_from_hex(app_theme.accent); - gboolean selected = (app_theme_id == id); - double size = MIN(width, height); - double cx = width / 2.0; - double cy = height / 2.0; - double r = size / 2.0 - (selected ? 3.0 : 1.0); - double dot = MAX(3.5, r * 0.26); - double gap = dot * 2.05; - - (void)area; - - if (selected) { - cairo_new_path(cr); - cairo_arc(cr, cx, cy, size / 2.0 - 0.5, 0.0, 2.0 * G_PI); - cairo_set_source_rgb(cr, accent.r, accent.g, accent.b); - cairo_set_line_width(cr, 2.2); - cairo_stroke(cr); - } - - cairo_new_path(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_set_source_rgb(cr, base.r, base.g, base.b); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_arc(cr, cx - gap, cy, dot, 0.0, 2.0 * G_PI); - cairo_set_source_rgb(cr, a1.r, a1.g, a1.b); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_arc(cr, cx, cy, dot, 0.0, 2.0 * G_PI); - cairo_set_source_rgb(cr, a2.r, a2.g, a2.b); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_arc(cr, cx + gap, cy, dot, 0.0, 2.0 * G_PI); - cairo_set_source_rgb(cr, ok.r, ok.g, ok.b); - cairo_fill(cr); -} - -void on_mode_toggled(GtkToggleButton *btn, gpointer user_data) { - ColorMode mode = (ColorMode)GPOINTER_TO_INT(user_data); - - if (!gtk_toggle_button_get_active(btn)) - return; - if (app_color_mode == mode) - return; - app_color_mode = mode; - apply_theme(); - save_settings(); -} - -void on_theme_toggled(GtkToggleButton *btn, gpointer user_data) { - ThemeId id = (ThemeId)GPOINTER_TO_INT(user_data); - - if (!gtk_toggle_button_get_active(btn)) - return; - if (app_theme_id == id) - return; - app_theme_id = id; - apply_theme(); - save_settings(); -} - -void on_lang_toggled(GtkToggleButton *btn, gpointer user_data) { - UiLang lang = (UiLang)GPOINTER_TO_INT(user_data); - - if (!gtk_toggle_button_get_active(btn)) - return; - if (app_lang == lang) - return; - app_lang = lang; - apply_language(); - save_settings(); -} - -GtkWidget *make_lang_chip(const char *label, UiLang lang, - GtkToggleButton *group) { - GtkWidget *btn = gtk_toggle_button_new_with_label(label); - - gtk_widget_add_css_class(btn, "mode-chip"); - gtk_widget_set_hexpand(btn, TRUE); - if (group) - gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(btn), group); - g_signal_connect(btn, "toggled", G_CALLBACK(on_lang_toggled), - GINT_TO_POINTER(lang)); - return btn; -} - -GtkWidget *make_mode_chip(const char *label, ColorMode mode, - GtkToggleButton *group) { - GtkWidget *btn = gtk_toggle_button_new(); - - i18n_bind(btn, label, 1); - gtk_widget_add_css_class(btn, "mode-chip"); - gtk_widget_set_hexpand(btn, TRUE); - if (group) - gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(btn), group); - g_signal_connect(btn, "toggled", G_CALLBACK(on_mode_toggled), - GINT_TO_POINTER(mode)); - return btn; -} - -GtkWidget *make_theme_card(ThemeId id, GtkToggleButton *group) { - GtkWidget *btn; - GtkWidget *vbox; - GtkWidget *swatch; - GtkWidget *name; - - btn = gtk_toggle_button_new(); - gtk_widget_add_css_class(btn, "theme-card"); - gtk_widget_set_hexpand(btn, TRUE); - if (group) - gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(btn), group); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(btn), vbox); - - swatch = gtk_drawing_area_new(); - gtk_widget_set_size_request(swatch, 44, 44); - gtk_widget_set_halign(swatch, GTK_ALIGN_CENTER); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(swatch), - draw_theme_swatch, - GINT_TO_POINTER(id), NULL); - theme_swatch_areas[id] = swatch; - gtk_box_append(GTK_BOX(vbox), swatch); - - name = gtk_label_new(theme_names[id]); - gtk_widget_add_css_class(name, "theme-card-name"); - gtk_widget_set_halign(name, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(vbox), name); - - g_signal_connect(btn, "toggled", G_CALLBACK(on_theme_toggled), - GINT_TO_POINTER(id)); - return btn; -} - -void on_settings_clicked(GtkButton *button, gpointer user_data) { - GtkPopover *popover = GTK_POPOVER(user_data); - - (void)button; - update_on_settings_open(); - gtk_popover_popup(popover); -} - -GtkWidget *build_stats_button(void) { - GtkWidget *btn; - GtkWidget *icon; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "settings-btn"); - gtk_widget_add_css_class(btn, "flat"); - i18n_bind(btn, "stats", 2); - gtk_widget_set_valign(btn, GTK_ALIGN_CENTER); - gtk_widget_set_focus_on_click(btn, FALSE); - - icon = gtk_drawing_area_new(); - gtk_widget_set_size_request(icon, 18, 18); - gtk_widget_set_can_target(icon, FALSE); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(icon), - draw_stats_icon, NULL, NULL); - gtk_button_set_child(GTK_BUTTON(btn), icon); - g_signal_connect_swapped(btn, "state-flags-changed", - G_CALLBACK(gtk_widget_queue_draw), icon); - g_signal_connect(btn, "clicked", G_CALLBACK(on_stats_clicked), NULL); - - return btn; -} - -GtkWidget *build_settings_button(void) { - GtkWidget *btn; - GtkWidget *icon; - GtkWidget *popover; - GtkWidget *box; - GtkWidget *title; - GtkWidget *label; - GtkWidget *mode_row; - GtkWidget *lang_row; - GtkWidget *theme_grid; - GtkWidget *dark_btn; - GtkWidget *light_btn; - GtkWidget *cs_btn; - GtkWidget *en_btn; - GtkWidget *first_theme = NULL; - int i; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "settings-btn"); - gtk_widget_add_css_class(btn, "flat"); - i18n_bind(btn, "settings", 2); - gtk_widget_set_valign(btn, GTK_ALIGN_CENTER); - gtk_widget_set_focus_on_click(btn, FALSE); - - icon = gtk_drawing_area_new(); - gtk_widget_set_size_request(icon, 18, 18); - gtk_widget_set_can_target(icon, FALSE); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(icon), - draw_settings_icon, NULL, NULL); - gtk_button_set_child(GTK_BUTTON(btn), icon); - g_signal_connect_swapped(btn, "state-flags-changed", - G_CALLBACK(gtk_widget_queue_draw), icon); - - popover = gtk_popover_new(); - settings_popover = popover; - gtk_widget_add_css_class(popover, "settings-popover"); - gtk_popover_set_has_arrow(GTK_POPOVER(popover), TRUE); - gtk_popover_set_position(GTK_POPOVER(popover), GTK_POS_BOTTOM); - gtk_widget_set_parent(popover, btn); - g_signal_connect_swapped(btn, "destroy", - G_CALLBACK(gtk_widget_unparent), popover); - g_signal_connect(btn, "clicked", G_CALLBACK(on_settings_clicked), popover); - - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14); - gtk_widget_add_css_class(box, "settings-box"); - - title = gtk_label_new(NULL); - i18n_bind(title, "settings_title", 0); - gtk_widget_set_halign(title, GTK_ALIGN_START); - gtk_widget_add_css_class(title, "settings-title"); - gtk_box_append(GTK_BOX(box), title); - - label = gtk_label_new(NULL); - i18n_bind(label, "mode", 0); - gtk_widget_set_halign(label, GTK_ALIGN_START); - gtk_widget_add_css_class(label, "settings-label"); - gtk_widget_set_margin_top(label, 4); - gtk_box_append(GTK_BOX(box), label); - - mode_row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - gtk_widget_add_css_class(mode_row, "settings-seg"); - gtk_box_append(GTK_BOX(box), mode_row); - - dark_btn = make_mode_chip("mode_dark", MODE_DARK, NULL); - light_btn = make_mode_chip("mode_light", MODE_LIGHT, - GTK_TOGGLE_BUTTON(dark_btn)); - g_signal_handlers_block_matched(dark_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_mode_toggled, NULL); - g_signal_handlers_block_matched(light_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_mode_toggled, NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dark_btn), - app_color_mode == MODE_DARK); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(light_btn), - app_color_mode == MODE_LIGHT); - g_signal_handlers_unblock_matched(dark_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_mode_toggled, NULL); - g_signal_handlers_unblock_matched(light_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_mode_toggled, NULL); - gtk_box_append(GTK_BOX(mode_row), dark_btn); - gtk_box_append(GTK_BOX(mode_row), light_btn); - - label = gtk_label_new(NULL); - i18n_bind(label, "theme", 0); - gtk_widget_set_halign(label, GTK_ALIGN_START); - gtk_widget_add_css_class(label, "settings-label"); - gtk_widget_set_margin_top(label, 2); - gtk_box_append(GTK_BOX(box), label); - - theme_grid = gtk_flow_box_new(); - gtk_widget_add_css_class(theme_grid, "theme-grid"); - gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(theme_grid), - GTK_SELECTION_NONE); - gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(theme_grid), 3); - gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(theme_grid), 3); - gtk_flow_box_set_column_spacing(GTK_FLOW_BOX(theme_grid), 8); - gtk_flow_box_set_row_spacing(GTK_FLOW_BOX(theme_grid), 8); - gtk_flow_box_set_homogeneous(GTK_FLOW_BOX(theme_grid), TRUE); - gtk_widget_set_hexpand(theme_grid, TRUE); - gtk_box_append(GTK_BOX(box), theme_grid); - - for (i = 0; i < THEME_COUNT; i++) { - GtkWidget *card = make_theme_card( - (ThemeId)i, - first_theme ? GTK_TOGGLE_BUTTON(first_theme) : NULL); - if (!first_theme) - first_theme = card; - if (app_theme_id == (ThemeId)i) { - g_signal_handlers_block_matched(card, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_theme_toggled, NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(card), TRUE); - g_signal_handlers_unblock_matched(card, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_theme_toggled, NULL); - } - gtk_flow_box_insert(GTK_FLOW_BOX(theme_grid), card, -1); - } - - label = gtk_label_new(NULL); - i18n_bind(label, "language", 0); - gtk_widget_set_halign(label, GTK_ALIGN_START); - gtk_widget_add_css_class(label, "settings-label"); - gtk_widget_set_margin_top(label, 4); - gtk_box_append(GTK_BOX(box), label); - - lang_row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); - gtk_widget_add_css_class(lang_row, "settings-seg"); - gtk_box_append(GTK_BOX(box), lang_row); - - cs_btn = make_lang_chip("Čeština", LANG_CS, NULL); - en_btn = make_lang_chip("English", LANG_EN, GTK_TOGGLE_BUTTON(cs_btn)); - g_signal_handlers_block_matched(cs_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_lang_toggled, NULL); - g_signal_handlers_block_matched(en_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_lang_toggled, NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs_btn), - app_lang == LANG_CS); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(en_btn), - app_lang == LANG_EN); - g_signal_handlers_unblock_matched(cs_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_lang_toggled, NULL); - g_signal_handlers_unblock_matched(en_btn, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_lang_toggled, NULL); - gtk_box_append(GTK_BOX(lang_row), cs_btn); - gtk_box_append(GTK_BOX(lang_row), en_btn); - - label = gtk_label_new(NULL); - i18n_bind(label, "updates", 0); - gtk_widget_set_halign(label, GTK_ALIGN_START); - gtk_widget_add_css_class(label, "settings-label"); - gtk_widget_set_margin_top(label, 4); - gtk_box_append(GTK_BOX(box), label); - gtk_box_append(GTK_BOX(box), build_update_box()); - - { - GtkWidget *sw = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - /* Tall enough for every section, including updates at the bottom; GTK - * still shrinks the popover to fit the window and scrolls the rest. */ - gtk_scrolled_window_set_max_content_height(GTK_SCROLLED_WINDOW(sw), 820); - gtk_scrolled_window_set_has_frame(GTK_SCROLLED_WINDOW(sw), FALSE); - gtk_scrolled_window_set_propagate_natural_width(GTK_SCROLLED_WINDOW(sw), TRUE); - gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(sw), TRUE); - gtk_widget_set_hexpand(sw, FALSE); - gtk_widget_set_vexpand(sw, FALSE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), box); - gtk_popover_set_child(GTK_POPOVER(popover), sw); - } - - return btn; -} diff --git a/src/stats.c b/src/stats.c deleted file mode 100644 index 566f85f..0000000 --- a/src/stats.c +++ /dev/null @@ -1,471 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Statistics */ -/* ------------------------------------------------------------------ */ - -GtkWidget *make_back_button(const char *target); -void on_nav_clicked(GtkButton *button, gpointer user_data); - - -StatsUi stats_ui; -char *stats_return_page; - -int unit_done_count(const UnitCtx *u) { - int n = 0; - - if (!u) - return 0; - for (int i = 1; i <= u->n_ex; i++) { - if (u->done[i]) - n++; - } - return n; -} - - -/* Sum progress over units[first .. first+n-1]. Locked placeholder units and - * the finish node (no playable exercises) are ignored. */ -void progress_for_units(int first, int n, ProgressSum *out) { - for (int j = 0; j < n; j++) { - UnitCtx *u; - int d; - - if (first < 0 || first + j >= NUM_UNITS) - continue; - u = &units[first + j]; - if (!u->unlocked || u->n_ex <= 0) - continue; - d = unit_done_count(u); - out->done_ex += d; - out->total_ex += u->n_ex; - out->open_units++; - if (d == u->n_ex) - out->done_units++; - } -} - -/* GTK gives the progress node a minimum width, so a fraction of zero would - * still paint a short stub of accent colour. Mark those bars so the - * stylesheet can hide the fill entirely. */ -static void stats_set_fraction(GtkWidget *bar, double fraction) { - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar), fraction); - if (fraction > 0.0) - gtk_widget_remove_css_class(bar, "empty"); - else - gtk_widget_add_css_class(bar, "empty"); -} - -void refresh_stats_ui(void) { - ProgressSum all = {0}; - int pct; - char *tmp; - - if (!stats_ui.ex_value) - return; - - for (int s = 0; s < NUM_SUBJECTS; s++) { - if (s == NET_SUBJ) - progress_for_net(&all); - else if (s == HW_SUBJ) - progress_for_hw(&all); - else if (s == ON_SUBJ) - progress_for_on(&all); - else if (s == EN_SUBJ) - progress_for_en(&all); - else if (s == CZ_SUBJ) { - progress_for_mluvnice(&all); - progress_for_lit(&all); - } - else if (s == SCI_SUBJ) - progress_for_sci(&all); - else if (s == PHY_SUBJ) - progress_for_fyz(&all); - else if (s == MATH_SUBJ) - progress_for_math(&all); - else { - progress_for_units(sub_unit_start[s], sub_unit_count[s], &all); - if (s == 0) - progress_for_de(&all); - } - } - - pct = all.total_ex > 0 ? (all.done_ex * 100) / all.total_ex : 0; - - tmp = g_strdup_printf(tr("stats_ex_fmt"), all.done_ex, all.total_ex); - gtk_label_set_text(GTK_LABEL(stats_ui.ex_value), tmp); - g_free(tmp); - - tmp = g_strdup_printf(tr("stats_pct_fmt"), pct); - gtk_label_set_text(GTK_LABEL(stats_ui.pct_value), tmp); - g_free(tmp); - - tmp = g_strdup_printf(tr("stats_units_fmt"), all.done_units, - all.open_units); - gtk_label_set_text(GTK_LABEL(stats_ui.units_value), tmp); - g_free(tmp); - - stats_set_fraction(stats_ui.overall_bar, - all.total_ex > 0 - ? (double)all.done_ex / (double)all.total_ex - : 0.0); - - for (int s = 0; s < NUM_SUBJECTS; s++) { - GtkWidget *count = stats_ui.subj[s].count; - GtkWidget *bar = stats_ui.subj[s].bar; - ProgressSum sp = {0}; - gboolean has_content = (s == NET_SUBJ) || (s == HW_SUBJ) - || (s == ON_SUBJ) || (s == EN_SUBJ) - || (s == CZ_SUBJ) - || (s == SCI_SUBJ) || (s == PHY_SUBJ) - || (s == MATH_SUBJ) - || sub_unit_count[s] > 0; - - if (!count || !bar) - continue; - if (s == NET_SUBJ) - progress_for_net(&sp); - else if (s == HW_SUBJ) - progress_for_hw(&sp); - else if (s == ON_SUBJ) - progress_for_on(&sp); - else if (s == EN_SUBJ) - progress_for_en(&sp); - else if (s == CZ_SUBJ) { - progress_for_mluvnice(&sp); - progress_for_lit(&sp); - } - else if (s == SCI_SUBJ) - progress_for_sci(&sp); - else if (s == PHY_SUBJ) - progress_for_fyz(&sp); - else if (s == MATH_SUBJ) - progress_for_math(&sp); - else { - progress_for_units(sub_unit_start[s], sub_unit_count[s], &sp); - if (s == 0) - progress_for_de(&sp); - } - if (has_content) { - tmp = g_strdup_printf(tr("stats_ex_fmt"), sp.done_ex, sp.total_ex); - gtk_label_set_text(GTK_LABEL(count), tmp); - g_free(tmp); - stats_set_fraction(bar, - sp.total_ex > 0 - ? (double)sp.done_ex / (double)sp.total_ex - : 0.0); - } else { - gtk_label_set_text(GTK_LABEL(count), tr("stats_locked")); - stats_set_fraction(bar, 0.0); - } - } - - for (int i = 0; i < NUM_UNITS; i++) { - UnitCtx *u = &units[i]; - GtkWidget *count = stats_ui.unit_count[i]; - GtkWidget *badge = stats_ui.unit_badge[i]; - GtkWidget *bar = stats_ui.unit_bar[i]; - GtkWidget *row = stats_ui.unit_row[i]; - gboolean unlocked = u->unlocked && u->n_ex > 0; - int d = unlocked ? unit_done_count(u) : 0; - gboolean complete = unlocked && d == u->n_ex; - - if (!count || !bar || !row) - continue; - - gtk_widget_remove_css_class(row, "done"); - gtk_widget_remove_css_class(row, "locked"); - gtk_widget_remove_css_class(bar, "done"); - - if (!unlocked) { - gtk_widget_add_css_class(row, "locked"); - gtk_label_set_text(GTK_LABEL(count), tr("stats_locked")); - stats_set_fraction(bar, 0.0); - if (badge) - gtk_widget_set_visible(badge, FALSE); - continue; - } - - tmp = g_strdup_printf(tr("stats_ex_fmt"), d, u->n_ex); - gtk_label_set_text(GTK_LABEL(count), tmp); - g_free(tmp); - stats_set_fraction(bar, - u->n_ex > 0 ? (double)d / (double)u->n_ex : 0.0); - - if (complete) { - gtk_widget_add_css_class(row, "done"); - gtk_widget_add_css_class(bar, "done"); - if (badge) { - gtk_label_set_text(GTK_LABEL(badge), tr("stats_complete")); - gtk_widget_set_visible(badge, TRUE); - } - } else if (badge) { - gtk_widget_set_visible(badge, FALSE); - } - } -} - -void on_stats_back_clicked(GtkButton *button, gpointer user_data) { - const char *target = stats_return_page; - - (void)button; - (void)user_data; - if (!target || !target[0]) - target = "subjects"; - show_page(target, -1); -} - -void on_stats_clicked(GtkButton *button, gpointer user_data) { - const char *cur; - - (void)button; - (void)user_data; - - cur = gtk_stack_get_visible_child_name(main_stack); - if (cur && g_strcmp0(cur, "stats") != 0) { - g_free(stats_return_page); - stats_return_page = g_strdup(cur); - } - refresh_stats_ui(); - show_page("stats", 0); -} - -GtkWidget *stats_metric_card(const char *label_key, GtkWidget **value_out) { - GtkWidget *card; - GtkWidget *value; - GtkWidget *label; - - card = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class(card, "stats-metric"); - gtk_widget_set_hexpand(card, TRUE); - - value = gtk_label_new("0"); - gtk_widget_set_halign(value, GTK_ALIGN_START); - gtk_widget_add_css_class(value, "stats-metric-value"); - gtk_box_append(GTK_BOX(card), value); - - label = gtk_label_new(NULL); - i18n_bind(label, label_key, 0); - gtk_widget_set_halign(label, GTK_ALIGN_START); - gtk_widget_add_css_class(label, "stats-metric-label"); - gtk_box_append(GTK_BOX(card), label); - - *value_out = value; - return card; -} - -/* Build one unit row (index, name, badge, count, bar) for the stats list. - * `num` is the row number shown (1-based within its subject). */ -GtkWidget *make_unit_stats_row(UnitCtx *u, int num, int global) { - GtkWidget *row; - GtkWidget *head; - GtkWidget *left; - GtkWidget *idx; - GtkWidget *name; - GtkWidget *right; - GtkWidget *count; - GtkWidget *badge; - GtkWidget *bar; - char text[8]; - - row = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); - gtk_widget_add_css_class(row, "stats-unit-row"); - stats_ui.unit_row[global] = row; - - head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_append(GTK_BOX(row), head); - - left = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_hexpand(left, TRUE); - gtk_box_append(GTK_BOX(head), left); - - g_snprintf(text, sizeof(text), "%d", num); - idx = gtk_label_new(text); - gtk_widget_add_css_class(idx, "stats-unit-index"); - gtk_widget_set_valign(idx, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(left), idx); - - name = gtk_label_new(u->title); - gtk_widget_set_halign(name, GTK_ALIGN_START); - gtk_widget_set_hexpand(name, TRUE); - gtk_label_set_xalign(GTK_LABEL(name), 0.0); - gtk_label_set_ellipsize(GTK_LABEL(name), PANGO_ELLIPSIZE_END); - gtk_widget_add_css_class(name, "stats-unit-name"); - gtk_box_append(GTK_BOX(left), name); - - right = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - gtk_widget_set_valign(right, GTK_ALIGN_CENTER); - gtk_box_append(GTK_BOX(head), right); - - badge = gtk_label_new(NULL); - gtk_widget_add_css_class(badge, "stats-unit-badge"); - gtk_widget_set_visible(badge, FALSE); - gtk_box_append(GTK_BOX(right), badge); - stats_ui.unit_badge[global] = badge; - - count = gtk_label_new(""); - gtk_widget_add_css_class(count, "stats-unit-count"); - gtk_box_append(GTK_BOX(right), count); - stats_ui.unit_count[global] = count; - - bar = gtk_progress_bar_new(); - gtk_widget_add_css_class(bar, "stats-unit-bar"); - gtk_widget_set_hexpand(bar, TRUE); - gtk_box_append(GTK_BOX(row), bar); - stats_ui.unit_bar[global] = bar; - - return row; -} - -GtkWidget *build_stats_page(void) { - GtkWidget *outer; - GtkWidget *scroll; - GtkWidget *page; - GtkWidget *top; - GtkWidget *back; - GtkWidget *center; - GtkWidget *heading; - GtkWidget *sub; - GtkWidget *summary; - GtkWidget *section; - GtkWidget *list; - - outer = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class(outer, "stats-page"); - - /* Same header rhythm as the other pages (top_bar). */ - top = gtk_center_box_new(); - gtk_widget_add_css_class(top, "page-top"); - gtk_widget_set_margin_top(top, 8); - gtk_widget_set_margin_bottom(top, 18); - gtk_box_append(GTK_BOX(outer), top); - - back = make_back_button("subjects"); - g_signal_handlers_disconnect_matched(back, G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, on_nav_clicked, NULL); - g_signal_connect(back, "clicked", G_CALLBACK(on_stats_back_clicked), NULL); - gtk_center_box_set_start_widget(GTK_CENTER_BOX(top), back); - - center = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); - gtk_widget_set_valign(center, GTK_ALIGN_CENTER); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(top), center); - - heading = gtk_label_new(NULL); - i18n_bind(heading, "stats_title", 0); - gtk_widget_set_halign(heading, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(heading, "roadmap-title"); - gtk_box_append(GTK_BOX(center), heading); - - sub = gtk_label_new(NULL); - i18n_bind(sub, "stats_sub", 0); - gtk_widget_set_halign(sub, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(sub, "roadmap-sub"); - gtk_label_set_wrap(GTK_LABEL(sub), TRUE); - gtk_box_append(GTK_BOX(center), sub); - - scroll = gtk_scrolled_window_new(); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_hexpand(scroll, TRUE); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_box_append(GTK_BOX(outer), scroll); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_halign(page, GTK_ALIGN_FILL); - gtk_widget_set_margin_start(page, 4); - gtk_widget_set_margin_end(page, 4); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), page); - - summary = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_widget_add_css_class(summary, "stats-summary"); - gtk_widget_set_halign(summary, GTK_ALIGN_FILL); - /* Equal columns; hexpand alone only shares the leftover space, which - * leaves the cards at different widths. */ - gtk_box_set_homogeneous(GTK_BOX(summary), TRUE); - gtk_box_append(GTK_BOX(page), summary); - - gtk_box_append(GTK_BOX(summary), - stats_metric_card("stats_ex_label", &stats_ui.ex_value)); - gtk_box_append(GTK_BOX(summary), - stats_metric_card("stats_pct_label", &stats_ui.pct_value)); - gtk_box_append(GTK_BOX(summary), - stats_metric_card("stats_units_label", - &stats_ui.units_value)); - - stats_ui.overall_bar = gtk_progress_bar_new(); - gtk_widget_add_css_class(stats_ui.overall_bar, "stats-overall-bar"); - gtk_widget_set_hexpand(stats_ui.overall_bar, TRUE); - gtk_box_append(GTK_BOX(page), stats_ui.overall_bar); - - section = gtk_label_new(NULL); - i18n_bind(section, "stats_section", 0); - gtk_widget_set_halign(section, GTK_ALIGN_START); - gtk_widget_add_css_class(section, "stats-section"); - gtk_box_append(GTK_BOX(page), section); - - list = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_append(GTK_BOX(page), list); - - for (int s = 0; s < NUM_SUBJECTS; s++) { - GtkWidget *subject; - GtkWidget *head; - GtkWidget *name; - GtkWidget *count; - GtkWidget *bar; - gboolean has_units = (s == NET_SUBJ) || (s == HW_SUBJ) - || (s == CZ_SUBJ) || (s == ON_SUBJ) - || (s == SCI_SUBJ) || (s == PHY_SUBJ) - || (s == MATH_SUBJ) - || sub_unit_count[s] > 0; - gboolean has_deutsch_units = sub_unit_count[s] > 0; - - subject = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class(subject, "stats-subject"); - gtk_box_append(GTK_BOX(list), subject); - - head = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_append(GTK_BOX(subject), head); - - name = gtk_label_new(NULL); - i18n_bind(name, sub_keys[s], 0); - gtk_widget_set_halign(name, GTK_ALIGN_START); - gtk_widget_set_hexpand(name, TRUE); - gtk_label_set_xalign(GTK_LABEL(name), 0.0); - gtk_label_set_ellipsize(GTK_LABEL(name), PANGO_ELLIPSIZE_END); - gtk_widget_add_css_class(name, "stats-subject-name"); - if (!has_units) - gtk_widget_add_css_class(name, "unit-name-locked"); - gtk_box_append(GTK_BOX(head), name); - stats_ui.subj[s].name = name; - - count = gtk_label_new(NULL); - gtk_widget_add_css_class(count, "stats-subject-count"); - if (!has_units) - gtk_widget_add_css_class(count, "locked"); - gtk_box_append(GTK_BOX(head), count); - stats_ui.subj[s].count = count; - - bar = gtk_progress_bar_new(); - gtk_widget_add_css_class(bar, "stats-subject-bar"); - gtk_widget_set_hexpand(bar, TRUE); - gtk_box_append(GTK_BOX(subject), bar); - stats_ui.subj[s].bar = bar; - - if (has_deutsch_units) { - GtkWidget *units_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - gtk_widget_add_css_class(units_box, "stats-units"); - gtk_box_append(GTK_BOX(subject), units_box); - stats_ui.subj[s].units_box = units_box; - - for (int j = 0; j < sub_unit_count[s]; j++) { - int gi = sub_unit_start[s] + j; - - gtk_box_append(GTK_BOX(units_box), - make_unit_stats_row(&units[gi], j + 1, gi)); - } - } - } - - return outer; -} diff --git a/src/subjects.c b/src/subjects.c deleted file mode 100644 index 0c9f248..0000000 --- a/src/subjects.c +++ /dev/null @@ -1,309 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Subjects page — icon grid, one tile per subject */ -/* ------------------------------------------------------------------ */ - -/* Index 0 (Deutsch), NET_SUBJ (networks), HW_SUBJ (hardware), CZ_SUBJ - * (Czech), ON_SUBJ (civics), EN_SUBJ (English), MATH_SUBJ (mathematics), - * PHY_SUBJ (physics) and SCI_SUBJ (natural sciences) are unlocked. */ -const char *sub_keys[NUM_SUBJECTS] = { - "Deutsch", - "Správa počítačových sítí", - "Technické vybavení", - "Český jazyk a literatura", - "Občanská nauka", - "English", - "Matematika", - "Fyzika", - "Základy Přírodopisných věd", - "Technická grafika", - "Prezentační grafika", - "Programování", - "Programové vybavení", -}; - -/* Slice of the global `units[]` table that each subject owns. A start of -1 - * (or a count of 0) means the subject has no content yet; such subjects show - * as locked on the statistics page until their units are added. */ -const int sub_unit_start[NUM_SUBJECTS] = { - 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; -const int sub_unit_count[NUM_SUBJECTS] = { - NUM_UNITS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -GtkWidget *sub_scroll; -GtkWidget *sub_fixed; -GtkWidget *sub_rail; -GtkWidget *sub_cells[NUM_SUBJECTS]; -GtkWidget *sub_labels[NUM_SUBJECTS]; -double sub_cx[NUM_SUBJECTS]; -double sub_cy[NUM_SUBJECTS]; -int sub_rows = 1; -int sub_cols = NUM_SUBJECTS; -int sub_cw; -int sub_ch; -guint sub_idle; - -void sub_layout_geometry(double avail) { - (void)avail; -} - -void draw_sub_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer user_data) { - (void)area; - (void)cr; - (void)width; - (void)height; - (void)user_data; -} - -void sub_apply_layout(void) { -} - -void sub_relayout(void) { -} - -gboolean sub_relayout_idle(gpointer data) { - (void)data; - sub_idle = 0; - return G_SOURCE_REMOVE; -} - -void sub_relayout_later(void) { -} - -/* German flag (black / red / gold) drawn in a clipped circle. */ -void draw_german_flag(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - double cx = width / 2.0; - double cy = height / 2.0; - double r = MIN(width, height) / 2.0 - 2.0; - double band = (double)height / 3.0; - - (void)area; - (void)data; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - cairo_save(cr); - cairo_new_path(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_clip(cr); - - cairo_new_path(cr); - cairo_rectangle(cr, 0.0, 0.0, (double)width, band); - cairo_set_source_rgb(cr, 0.18, 0.18, 0.19); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_rectangle(cr, 0.0, band, (double)width, band); - cairo_set_source_rgb(cr, 0.72, 0.27, 0.24); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_rectangle(cr, 0.0, 2.0 * band, (double)width, band); - cairo_set_source_rgb(cr, 0.84, 0.70, 0.32); - cairo_fill(cr); - - cairo_restore(cr); -} - -/* Czech flag (white / red with a blue triangle) drawn in a clipped circle. */ -void draw_czech_flag(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer data) { - double cx = width / 2.0; - double cy = height / 2.0; - double r = MIN(width, height) / 2.0 - 2.0; - - (void)area; - (void)data; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - cairo_save(cr); - cairo_new_path(cr); - cairo_arc(cr, cx, cy, r, 0.0, 2.0 * G_PI); - cairo_clip(cr); - - cairo_new_path(cr); - cairo_rectangle(cr, 0.0, 0.0, (double)width, (double)height); - cairo_set_source_rgb(cr, 0.98, 0.98, 0.98); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_rectangle(cr, 0.0, (double)height / 2.0, - (double)width, (double)height / 2.0); - cairo_set_source_rgb(cr, 0.83, 0.16, 0.18); - cairo_fill(cr); - - cairo_new_path(cr); - cairo_move_to(cr, 0.0, 0.0); - cairo_line_to(cr, (double)width * 0.55, (double)height / 2.0); - cairo_line_to(cr, 0.0, (double)height); - cairo_close_path(cr); - cairo_set_source_rgb(cr, 0.07, 0.24, 0.55); - cairo_fill(cr); - - cairo_restore(cr); -} - -static gboolean subject_is_open(int i) { - return i == 0 || i == NET_SUBJ || i == HW_SUBJ || i == CZ_SUBJ - || i == ON_SUBJ || i == EN_SUBJ || i == MATH_SUBJ || i == PHY_SUBJ - || i == SCI_SUBJ; -} - -static GtkWidget *subject_icon(int i) { - GtkWidget *area = gtk_drawing_area_new(); - - gtk_widget_set_size_request(area, 48, 48); - gtk_widget_set_halign(area, GTK_ALIGN_CENTER); - if (i == 0) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_german_flag, NULL, NULL); - else if (i == NET_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_wifi_icon, NULL, NULL); - else if (i == HW_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_chip_icon, NULL, NULL); - else if (i == CZ_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_czech_flag, NULL, NULL); - else if (i == ON_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_civics_icon, NULL, NULL); - else if (i == EN_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_uk_flag, NULL, NULL); - else if (i == MATH_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_math_icon, NULL, NULL); - else if (i == PHY_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_physics_icon, NULL, NULL); - else if (i == SCI_SUBJ) - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), - draw_science_icon, NULL, NULL); - else - return icon_area_new(draw_lock_icon, 0.3451, 0.3569, 0.4392, 22); - return area; -} - -static const char *subject_target(int i) { - if (i == 0) - return "dehome"; - if (i == NET_SUBJ) - return "netyears"; - if (i == HW_SUBJ) - return "hwyears"; - if (i == CZ_SUBJ) - return "czechmap"; - if (i == ON_SUBJ) - return "onyears"; - if (i == EN_SUBJ) - return "enyears"; - if (i == MATH_SUBJ) - return "matyears"; - if (i == PHY_SUBJ) - return "fyzyears"; - if (i == SCI_SUBJ) - return "scimap"; - return NULL; -} - -GtkWidget *build_subjects_page(void) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *grid; - int i; - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class(page, "subjects-page"); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 40); - gtk_widget_set_margin_end(page, 40); - gtk_widget_set_margin_top(page, 16); - gtk_widget_set_margin_bottom(page, 28); - - gtk_box_append(GTK_BOX(page), - top_bar("welcome", "subjects_title", "subjects_sub")); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 8); - gtk_box_append(GTK_BOX(page), scroll); - sub_scroll = scroll; - - grid = gtk_flow_box_new(); - gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(grid), 5); - gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(grid), 3); - gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(grid), GTK_SELECTION_NONE); - gtk_flow_box_set_homogeneous(GTK_FLOW_BOX(grid), TRUE); - gtk_flow_box_set_column_spacing(GTK_FLOW_BOX(grid), 14); - gtk_flow_box_set_row_spacing(GTK_FLOW_BOX(grid), 14); - gtk_widget_set_halign(grid, GTK_ALIGN_CENTER); - gtk_widget_set_hexpand(grid, TRUE); - gtk_widget_add_css_class(grid, "subject-grid"); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), grid); - sub_fixed = grid; - - for (i = 0; i < NUM_SUBJECTS; i++) { - GtkWidget *card; - GtkWidget *inner; - GtkWidget *icon; - GtkWidget *lbl; - const char *target; - gboolean open = subject_is_open(i); - - card = gtk_button_new(); - gtk_widget_add_css_class(card, "subject-tile"); - gtk_widget_set_can_focus(card, open); - gtk_widget_set_hexpand(card, TRUE); - gtk_widget_set_size_request(card, 180, 132); - - inner = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_widget_set_halign(inner, GTK_ALIGN_CENTER); - gtk_widget_set_valign(inner, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(card), inner); - - icon = subject_icon(i); - gtk_box_append(GTK_BOX(inner), icon); - - lbl = gtk_label_new(NULL); - i18n_bind(lbl, sub_keys[i], 0); - gtk_widget_set_halign(lbl, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(lbl), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(lbl), TRUE); - gtk_label_set_max_width_chars(GTK_LABEL(lbl), 16); - gtk_widget_add_css_class(lbl, "subject-name"); - gtk_box_append(GTK_BOX(inner), lbl); - - if (open) { - gtk_widget_add_css_class(card, "open"); - target = subject_target(i); - g_object_set_data_full(G_OBJECT(card), "target", - g_strdup(target), g_free); - g_signal_connect(card, "clicked", G_CALLBACK(on_nav_clicked), NULL); - } else { - gtk_widget_add_css_class(card, "locked"); - gtk_widget_add_css_class(lbl, "unit-name-locked"); - gtk_widget_set_sensitive(card, FALSE); - } - - sub_cells[i] = card; - sub_labels[i] = lbl; - gtk_flow_box_insert(GTK_FLOW_BOX(grid), card, -1); - } - - return page; -} diff --git a/src/theme.c b/src/theme.c deleted file mode 100644 index d0d44d8..0000000 --- a/src/theme.c +++ /dev/null @@ -1,440 +0,0 @@ -#include "graduately.h" - -Rgb color_from_hex(unsigned int hex) { - Rgb c; - c.r = (double)((hex >> 16) & 0xFF) / 255.0; - c.g = (double)((hex >> 8) & 0xFF) / 255.0; - c.b = (double)(hex & 0xFF) / 255.0; - return c; -} - -/* Linear blend of two colours: t = 0 keeps a, t = 1 returns b. */ -Rgb mix_rgb(Rgb a, Rgb b, double t) { - Rgb c; - c.r = a.r + (b.r - a.r) * t; - c.g = a.g + (b.g - a.g) * t; - c.b = a.b + (b.b - a.b) * t; - return c; -} - -ThemePalette theme_palette(ThemeId id, ColorMode mode) { - /* Paper: cream page, white cards, yellow CTA, near-black type. */ - static const ThemePalette cat_dark = { - 0x000000, 0x000000, 0x111111, 0x1d1d1f, 0x2c2c2e, 0x3a3a3c, - 0x86868b, 0xf5f5f7, 0xa1a1a6, 0xffd60a, 0x2997ff, 0x64d2ff, - 0x30d158, 0x64d2ff, 0xffd60a, 0xff453a, 0x1d1d1f, - 0x1d1d1f, 0x111111, 0x3a3a3c, 0x2c2c2e, 0x000000, 0x3a3a3c, 0x86868b - }; - static const ThemePalette cat_light = { - 0xf3eee6, 0xfaf7f2, 0xffffff, 0xffffff, 0xf0ebe3, 0xe5dfd4, - 0x8a8378, 0x1a1a1a, 0x5c574f, 0xffcc00, 0x0071e3, 0x2997ff, - 0x1f8a4c, 0x1a7f4a, 0xe6a800, 0xd32f2f, 0x1a1a1a, - 0xffffff, 0xf0ebe3, 0xd5cfc4, 0xe5dfd4, 0xf3eee6, 0xd5cfc4, 0x8a8378 - }; - /* Nord */ - static const ThemePalette nord_dark = { - 0x2e3440, 0x3b4252, 0x2e3440, 0x434c5e, 0x4c566a, 0x616e88, - 0x7b88a1, 0xeceff4, 0xd8dee9, 0x88c0d0, 0x81a1c1, 0x5e81ac, - 0xa3be8c, 0x8fbcbb, 0xebcb8b, 0xbf616a, 0x2e3440, - 0x434c5e, 0x3b4252, 0x4c566a, 0x2e3440, 0x2e3440, 0x434c5e, 0x4c566a - }; - static const ThemePalette nord_light = { - 0xd8dee9, 0xeceff4, 0xe5e9f0, 0xd8dee9, 0xc7ceda, 0xb0b8c8, - 0x7b88a1, 0x2e3440, 0x4c566a, 0x5e81ac, 0x81a1c1, 0x5e81ac, - 0xa3be8c, 0x8fbcbb, 0xebcb8b, 0xbf616a, 0xeceff4, - 0xe5e9f0, 0xd8dee9, 0xc7ceda, 0xd8dee9, 0xd8dee9, 0xc7ceda, 0x7b88a1 - }; - /* Dracula / light soft */ - static const ThemePalette dra_dark = { - 0x191a21, 0x282a36, 0x21222c, 0x44475a, 0x6272a4, 0x707eb0, - 0x6272a4, 0xf8f8f2, 0xbfbfb2, 0xbd93f9, 0xff79c6, 0x8be9fd, - 0x50fa7b, 0x8be9fd, 0xf1fa8c, 0xff5555, 0x282a36, - 0x383a4a, 0x2f3240, 0x44475a, 0x21222c, 0x191a21, 0x383a4a, 0x6272a4 - }; - static const ThemePalette dra_light = { - 0xd5d7e0, 0xf8f8f2, 0xefefea, 0xe2e2d8, 0xd0d0c4, 0xbfbfb2, - 0x9a9a8c, 0x282a36, 0x44475a, 0x7c3aed, 0xd946a6, 0x0891b2, - 0x16a34a, 0x0e7490, 0xca8a04, 0xdc2626, 0xf8f8f2, - 0xefefea, 0xe2e2d8, 0xd0d0c4, 0xe2e2d8, 0xd5d7e0, 0xd0d0c4, 0x9a9a8c - }; - /* Rose Pine / Dawn */ - static const ThemePalette rose_dark = { - 0x191724, 0x1f1d2e, 0x1f1d2e, 0x26233a, 0x403d52, 0x524f67, - 0x6e6a86, 0xe0def4, 0x908caa, 0xc4a7e7, 0xebbcba, 0x9ccfd8, - 0x31748f, 0x9ccfd8, 0xf6c177, 0xeb6f92, 0x191724, - 0x26233a, 0x21202e, 0x403d52, 0x191724, 0x191724, 0x26233a, 0x524f67 - }; - static const ThemePalette rose_light = { - 0xf2e9e1, 0xfaf4ed, 0xfffaf3, 0xf2e9e1, 0xdfdad9, 0xcecacd, - 0x9893a5, 0x575279, 0x797593, 0x907aa9, 0xd7827e, 0x56949f, - 0x286983, 0x56949f, 0xea9d34, 0xb4637a, 0xfaf4ed, - 0xfffaf3, 0xf2e9e1, 0xdfdad9, 0xf2e9e1, 0xf2e9e1, 0xdfdad9, 0x9893a5 - }; - /* Ocean / Tokyo Night inspired */ - static const ThemePalette ocean_dark = { - 0x16161e, 0x1a1b26, 0x16161e, 0x24283b, 0x414868, 0x565f89, - 0x565f89, 0xc0caf5, 0xa9b1d6, 0x7aa2f7, 0xbb9af7, 0x7dcfff, - 0x9ece6a, 0x73daca, 0xe0af68, 0xf7768e, 0x1a1b26, - 0x24283b, 0x1f2335, 0x3b4261, 0x16161e, 0x16161e, 0x24283b, 0x414868 - }; - static const ThemePalette ocean_light = { - 0xd6dae8, 0xe1e2ec, 0xd5d6e2, 0xc8c9d6, 0xb4b6c5, 0x9aa0b5, - 0x7a8199, 0x2e3446, 0x4a5168, 0x2e7de9, 0x7847bd, 0x007197, - 0x387068, 0x007197, 0x8c6c3e, 0xc64343, 0xe1e2ec, - 0xd5d6e2, 0xc8c9d6, 0xb4b6c5, 0xc8c9d6, 0xd6dae8, 0xb4b6c5, 0x7a8199 - }; - - /* Gruvbox */ - static const ThemePalette gruv_dark = { - 0x1d2021, 0x282828, 0x1d2021, 0x3c3836, 0x504945, 0x665c54, - 0x928374, 0xebdbb2, 0xa89984, 0xfe8019, 0xd3869b, 0x83a598, - 0xb8bb26, 0x8ec07c, 0xfabd2f, 0xfb4934, 0x1d2021, - 0x3c3836, 0x32302f, 0x504945, 0x1d2021, 0x1d2021, 0x3c3836, 0x504945 - }; - static const ThemePalette gruv_light = { - 0xebdbb2, 0xfbf1c7, 0xf2e5bc, 0xebdbb2, 0xd5c4a1, 0xbdae93, - 0x928374, 0x3c3836, 0x504945, 0xd65d0e, 0xb16286, 0x076678, - 0x79740e, 0x427b58, 0xb57614, 0x9d0006, 0xfbf1c7, - 0xf2e5bc, 0xebdbb2, 0xd5c4a1, 0xebdbb2, 0xebdbb2, 0xd5c4a1, 0x928374 - }; - /* Solarized */ - static const ThemePalette sol_dark = { - 0x002b36, 0x073642, 0x002b36, 0x586e75, 0x657b83, 0x839496, - 0x93a1a1, 0xfdf6e3, 0x93a1a1, 0x268bd2, 0x6c71c4, 0x2aa198, - 0x859900, 0x2aa198, 0xb58900, 0xdc322f, 0x002b36, - 0x073642, 0x002b36, 0x586e75, 0x002b36, 0x002b36, 0x073642, 0x586e75 - }; - static const ThemePalette sol_light = { - 0xeee8d5, 0xfdf6e3, 0xeee8d5, 0xeee8d5, 0xe2dbc6, 0xc9c0a6, - 0x657b83, 0x586e75, 0x657b83, 0x268bd2, 0x6c71c4, 0x2aa198, - 0x859900, 0x2aa198, 0xb58900, 0xdc322f, 0xfdf6e3, - 0xeee8d5, 0xe6dfc8, 0x93a1a1, 0xeee8d5, 0xeee8d5, 0x93a1a1, 0x586e75 - }; - /* Everforest */ - static const ThemePalette ever_dark = { - 0x1e2326, 0x272e33, 0x2d353b, 0x374145, 0x4f5b58, 0x7a8478, - 0x859289, 0xd3c6aa, 0xa7c080, 0xa7c080, 0xd699b6, 0x7fbbb3, - 0xa7c080, 0x83c092, 0xdbbc7f, 0xe67e80, 0x272e33, - 0x374145, 0x2d353b, 0x4f5b58, 0x1e2326, 0x1e2326, 0x374145, 0x4f5b58 - }; - static const ThemePalette ever_light = { - 0xe6e2cc, 0xfdf6e3, 0xf4f0d9, 0xefebd4, 0xe0dcc7, 0xa6b0a0, - 0x939f91, 0x5c6a72, 0x829181, 0x8da101, 0xdf69ba, 0x35a77c, - 0x8da101, 0x35a77c, 0xdfa000, 0xf85552, 0xfdf6e3, - 0xf4f0d9, 0xefebd4, 0xe0dcc7, 0xe6e2cc, 0xe6e2cc, 0xe0dcc7, 0x939f91 - }; - /* Monokai */ - static const ThemePalette mono_dark = { - 0x1d1e19, 0x272822, 0x1e1f1a, 0x3e3d32, 0x49483e, 0x75715e, - 0x75715e, 0xf8f8f2, 0xa59f85, 0xf92672, 0xae81ff, 0x66d9ef, - 0xa6e22e, 0xa1efe4, 0xe6db74, 0xf92672, 0x272822, - 0x3e3d32, 0x2e2f29, 0x49483e, 0x1d1e19, 0x1d1e19, 0x3e3d32, 0x49483e - }; - static const ThemePalette mono_light = { - 0xe6e3d4, 0xfaf8f0, 0xf3f0e4, 0xe8e4d4, 0xd6d2c0, 0xb8b49e, - 0x8a8674, 0x2d2a2e, 0x5b5854, 0xe14775, 0x7c5cbf, 0x1c7d9b, - 0x5b8c2a, 0x1c7d9b, 0xb08900, 0xe14775, 0xfaf8f0, - 0xf3f0e4, 0xe8e4d4, 0xd6d2c0, 0xe6e3d4, 0xe6e3d4, 0xd6d2c0, 0x8a8674 - }; - /* One Dark / One Light */ - static const ThemePalette one_dark = { - 0x21252b, 0x282c34, 0x21252b, 0x3b4048, 0x4b5263, 0x5c6370, - 0x5c6370, 0xabb2bf, 0x7f848e, 0xc678dd, 0x61afef, 0x56b6c2, - 0x98c379, 0x56b6c2, 0xe5c07b, 0xe06c75, 0x282c34, - 0x3b4048, 0x2c313a, 0x4b5263, 0x21252b, 0x21252b, 0x3b4048, 0x4b5263 - }; - static const ThemePalette one_light = { - 0xe5e5e6, 0xfafafa, 0xf0f0f0, 0xe5e5e6, 0xd0d0d2, 0xa0a1a7, - 0xa0a1a7, 0x383a42, 0x696c77, 0xa626a4, 0x4078f2, 0x0184bc, - 0x50a14f, 0x0184bc, 0xc18401, 0xe45649, 0xfafafa, - 0xf0f0f0, 0xe5e5e6, 0xd0d0d2, 0xe5e5e6, 0xe5e5e6, 0xd0d0d2, 0xa0a1a7 - }; - - switch (id) { - case THEME_NORD: - return mode == MODE_LIGHT ? nord_light : nord_dark; - case THEME_DRACULA: - return mode == MODE_LIGHT ? dra_light : dra_dark; - case THEME_ROSE_PINE: - return mode == MODE_LIGHT ? rose_light : rose_dark; - case THEME_OCEAN: - return mode == MODE_LIGHT ? ocean_light : ocean_dark; - case THEME_GRUVBOX: - return mode == MODE_LIGHT ? gruv_light : gruv_dark; - case THEME_SOLARIZED: - return mode == MODE_LIGHT ? sol_light : sol_dark; - case THEME_EVERFOREST: - return mode == MODE_LIGHT ? ever_light : ever_dark; - case THEME_MONOKAI: - return mode == MODE_LIGHT ? mono_light : mono_dark; - case THEME_ONE_DARK: - return mode == MODE_LIGHT ? one_light : one_dark; - case THEME_CATPPUCCIN: - default: - return mode == MODE_LIGHT ? cat_light : cat_dark; - } -} -char *read_css_file(void) { - gchar *contents = NULL; - GError *err = NULL; - - if (!g_file_get_contents(CSS_FILE, &contents, NULL, &err)) { - g_warning("Could not load stylesheet '%s': %s", CSS_FILE, - err ? err->message : "unknown error"); - if (err) - g_error_free(err); - return g_strdup(""); - } - return contents; -} - -typedef struct { - double scale; -} FontScale; - -static gboolean scale_font_size_eval(const GMatchInfo *info, GString *result, - gpointer user_data) { - const FontScale *fs = user_data; - char *space = g_match_info_fetch(info, 1); - char *num = g_match_info_fetch(info, 2); - int px = (int)g_ascii_strtoll(num, NULL, 10); - int scaled = (int)(px * fs->scale + 0.5); - - g_string_append_printf(result, "font-size:%s%dpx", space, scaled); - g_free(space); - g_free(num); - return FALSE; -} - -/* Scale every explicit `font-size: Npx` declaration so the interface grows on - * large (e.g. maximised / high-DPI) windows. Layout metrics stay untouched. - * Rules after the no-scale marker keep their fixed size, so symbol / icon - * glyphs do not scale. */ -static char *scale_font_sizes(const char *css, double scale) { - static const char marker[] = "/* no-scale */"; - const char *pos; - char *head; - char *scaled_head; - char *out; - GRegex *re; - FontScale fs; - - if (scale <= 1.0001) - return g_strdup(css); - - pos = g_strstr_len(css, -1, marker); - head = pos ? g_strndup(css, (gsize)(pos - css)) : g_strdup(css); - - fs.scale = scale; - re = g_regex_new("font-size:([ \t]*)([0-9]+)px", 0, 0, NULL); - scaled_head = g_regex_replace_eval(re, head, -1, 0, 0, - scale_font_size_eval, &fs, NULL); - g_regex_unref(re); - g_free(head); - - if (pos) - out = g_strconcat(scaled_head, pos, NULL); - else - out = scaled_head; - g_free(scaled_head); - return out; -} - -/* The palette is data-driven, so its @define-color bindings are generated - * here and prepended to the rules loaded from the external stylesheet. */ -char *build_theme_css(const ThemePalette *p) { - char *palette = g_strdup_printf( - "@define-color bg_crust #%06x;\n" - "@define-color bg_base #%06x;\n" - "@define-color bg_mantle #%06x;\n" - "@define-color bg_surface0 #%06x;\n" - "@define-color bg_surface1 #%06x;\n" - "@define-color bg_surface2 #%06x;\n" - "@define-color fg_overlay #%06x;\n" - "@define-color fg_text #%06x;\n" - "@define-color fg_subtext #%06x;\n" - "@define-color accent #%06x;\n" - "@define-color accent2 #%06x;\n" - "@define-color accent3 #%06x;\n" - "@define-color success #%06x;\n" - "@define-color success2 #%06x;\n" - "@define-color warning #%06x;\n" - "@define-color error #%06x;\n" - "@define-color on_accent #%06x;\n" - "@define-color node_bg #%06x;\n" - "@define-color locked_bg #%06x;\n" - "@define-color locked_border #%06x;\n", - p->crust, p->base, p->mantle, p->surface0, p->surface1, p->surface2, - p->overlay, p->text, p->subtext, p->accent, p->accent2, p->accent3, - p->success, p->success2, p->warning, p->error, p->on_accent, - p->node, p->locked_bg, p->locked_border); - char *rules = read_css_file(); - char *scaled = scale_font_sizes(rules, app_ui_scale); - char *css = g_strconcat(palette, scaled, NULL); - - g_free(palette); - g_free(rules); - g_free(scaled); - return css; -} - -void save_settings(void) { - GKeyFile *kf = g_key_file_new(); - gchar *data; - - g_key_file_set_string(kf, "ui", "theme", theme_names[app_theme_id]); - g_key_file_set_string(kf, "ui", "mode", - app_color_mode == MODE_LIGHT ? "light" : "dark"); - g_key_file_set_string(kf, "ui", "lang", - app_lang == LANG_EN ? "en" : "cs"); - g_key_file_set_string(kf, "ui", "seen_commit", changelog_seen()); - - if (g_mkdir_with_parents(PROGRESS_DIR, 0755) != 0) { - g_key_file_free(kf); - return; - } - - data = g_key_file_to_data(kf, NULL, NULL); - g_key_file_free(kf); - if (data) { - GError *err = NULL; - g_file_set_contents(SETTINGS_FILE, data, -1, &err); - if (err) - g_error_free(err); - g_free(data); - } -} - -void load_settings(void) { - GKeyFile *kf = g_key_file_new(); - GError *err = NULL; - gchar *theme = NULL; - gchar *mode = NULL; - - if (!g_key_file_load_from_file(kf, SETTINGS_FILE, G_KEY_FILE_NONE, &err)) { - if (err) - g_error_free(err); - g_key_file_free(kf); - return; - } - - theme = g_key_file_get_string(kf, "ui", "theme", NULL); - mode = g_key_file_get_string(kf, "ui", "mode", NULL); - if (theme) { - for (int i = 0; i < THEME_COUNT; i++) { - if (g_ascii_strcasecmp(theme, theme_names[i]) == 0) { - app_theme_id = (ThemeId)i; - break; - } - } - g_free(theme); - } - if (mode) { - if (g_ascii_strcasecmp(mode, "light") == 0 || - g_ascii_strcasecmp(mode, "white") == 0) - app_color_mode = MODE_LIGHT; - else - app_color_mode = MODE_DARK; - g_free(mode); - } - { - gchar *lang = g_key_file_get_string(kf, "ui", "lang", NULL); - if (lang) { - if (g_ascii_strcasecmp(lang, "en") == 0 || - g_ascii_strcasecmp(lang, "english") == 0) - app_lang = LANG_EN; - else - app_lang = LANG_CS; - g_free(lang); - } - } - { - gchar *seen = g_key_file_get_string(kf, "ui", "seen_commit", NULL); - - changelog_set_seen(seen); - g_free(seen); - } - - g_key_file_free(kf); -} - -/* GTK only re-resolves the style of widgets that are actually drawn after a - * CSS provider reload. Pages that are not the current stack child keep their - * previously resolved colors, so after switching the theme any page you then - * open still shows the old palette (e.g. near-white text in light mode). - * Adding and immediately removing a dummy class forces GTK to invalidate the - * style node of every widget, including hidden pages. */ -void force_restyle_tree(GtkWidget *w) { - GtkWidget *child; - - if (!w) - return; - - gtk_widget_add_css_class(w, "m4-restyle"); - gtk_widget_remove_css_class(w, "m4-restyle"); - - for (child = gtk_widget_get_first_child(w); child; - child = gtk_widget_get_next_sibling(child)) - force_restyle_tree(child); -} - -void apply_theme(void) { - char *css; - GtkSettings *settings = gtk_settings_get_default(); - - app_theme = theme_palette(app_theme_id, app_color_mode); - - if (settings) { - g_object_set(settings, - "gtk-application-prefer-dark-theme", - app_color_mode == MODE_DARK, - NULL); - } - - css = build_theme_css(&app_theme); - - if (!theme_provider) { - theme_provider = gtk_css_provider_new(); - gtk_style_context_add_provider_for_display( - gdk_display_get_default(), - GTK_STYLE_PROVIDER(theme_provider), - GTK_STYLE_PROVIDER_PRIORITY_USER); - } - - #if GTK_CHECK_VERSION(4, 12, 0) - gtk_css_provider_load_from_string(theme_provider, css); -#else - /* GTK 4.6 (Ubuntu 22.04) — load_from_string arrived in 4.12. */ - gtk_css_provider_load_from_data(theme_provider, css, -1); -#endif - g_free(css); - - refresh_welcome_heading(); - - if (main_window) { - gtk_widget_queue_draw(GTK_WIDGET(main_window)); - force_restyle_tree(GTK_WIDGET(main_window)); - } - if (road_rail) - gtk_widget_queue_draw(road_rail); - for (int i = 0; i < NUM_UNLOCKED; i++) - if (units[i].ex_rail) - gtk_widget_queue_draw(units[i].ex_rail); - for (int i = 0; i < THEME_COUNT; i++) { - if (theme_swatch_areas[i]) - gtk_widget_queue_draw(theme_swatch_areas[i]); - } - net_rail_theme_reset(); - hw_rail_theme_reset(); - on_rail_theme_reset(); - on2_rail_theme_reset(); - on3_rail_theme_reset(); - on4_rail_theme_reset(); - en_rail_theme_reset(); - czech_rail_theme_reset(); - lit_rail_theme_reset(); - sci_rail_theme_reset(); - fyz_rail_theme_reset(); - math_rail_theme_reset(); - book_rail_theme_reset(); -} diff --git a/src/unitmap.c b/src/unitmap.c deleted file mode 100644 index 7f8498f..0000000 --- a/src/unitmap.c +++ /dev/null @@ -1,410 +0,0 @@ -#include "graduately.h" - -/* ------------------------------------------------------------------ */ -/* Unit 1 exercise path (roadmap-style serpentine) */ -/* ------------------------------------------------------------------ */ - - -/* Compute the serpentine exercise layout for the given available width. */ -void ex_layout_geometry(UnitCtx *u, double avail) { - const int n = u->n_ex; - const double phase = 2.0 * G_PI * 1.7 / (double)(n > 1 ? n - 1 : 1); - const double lift = u->has_branch ? EX_BRANCH_LIFT : 0.0; - int rows; - int r, c, i; - - if (n < 1) - return; - for (rows = 1; rows <= n; rows++) { - int cols = (n + rows - 1) / rows; - if (2.0 * EX_MX + (cols - 1) * EX_SPAC <= avail + 1.0) - break; - } - if (rows > n) - rows = n; - u->ex_rows = rows; - u->ex_cols = (n + rows - 1) / rows; - if (u->ex_cols < 1) - u->ex_cols = 1; - u->ex_cw = (int)(2.0 * EX_MX + (u->ex_cols - 1) * EX_SPAC); - u->ex_ch = (int)(2.0 * EX_MY + (rows - 1) * EX_GAP + lift); - - for (r = 0; r < rows; r++) { - int base = r * u->ex_cols; - int len = MIN(u->ex_cols, n - base); - int fwd = (r % 2) == 0; - for (c = 0; c < len; c++) { - i = base + c; - int cc = fwd ? c : (u->ex_cols - 1 - c); - u->ex_cx[i] = EX_MX + cc * EX_SPAC; - u->ex_cy[i] = EX_MY + lift + r * EX_GAP - + EX_WAVE * sin((double)i * phase); - } - } - - /* The branch hangs above exercise 2 (index 1), nudged sideways so its - * connector is a slanted link rather than a dead-straight vertical line. */ - if (u->has_branch && n > 1) { - u->branch_cx = u->ex_cx[1] + EX_BRANCH_DX; - u->branch_cy = u->ex_cy[1] - EX_BRANCH_LIFT; - } -} - -void ex_point(UnitCtx *u, double t, double *ox, double *oy) { - const int n = u->n_ex; - int k = (int)t; - double uu = t - (double)k; - double u2, u3; - double p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y; - - if (n < 2) { *ox = u->ex_cx[0]; *oy = u->ex_cy[0]; return; } - if (k < 0) { k = 0; uu = 0.0; } - if (k >= n - 1) { k = n - 2; uu = 1.0; } - - p1x = u->ex_cx[k]; p1y = u->ex_cy[k]; - p2x = u->ex_cx[k + 1]; p2y = u->ex_cy[k + 1]; - if (k - 1 >= 0) { p0x = u->ex_cx[k - 1]; p0y = u->ex_cy[k - 1]; } - else { p0x = p1x - (p2x - p1x); p0y = p1y - (p2y - p1y); } - if (k + 2 < n) { p3x = u->ex_cx[k + 2]; p3y = u->ex_cy[k + 2]; } - else { p3x = p2x + (p2x - p1x); p3y = p2y + (p2y - p1y); } - - u2 = uu * uu; - u3 = u2 * uu; - *ox = 0.5 * (2.0 * p1x + (-p0x + p2x) * uu - + (2.0 * p0x - 5.0 * p1x + 4.0 * p2x - p3x) * u2 - + (-p0x + 3.0 * p1x - 3.0 * p2x + p3x) * u3); - *oy = 0.5 * (2.0 * p1y + (-p0y + p2y) * uu - + (2.0 * p0y - 5.0 * p1y + 4.0 * p2y - p3y) * u2 - + (-p0y + 3.0 * p1y - 3.0 * p2y + p3y) * u3); -} - -void ex_path(UnitCtx *u, cairo_t *cr, double t0, double t1) { - const double steps_per_unit = 48.0; - int n = (int)((t1 - t0) * steps_per_unit); - double x, y; - int s; - - if (n < 1) - n = 1; - ex_point(u, t0, &x, &y); - cairo_move_to(cr, x, y); - for (s = 1; s <= n; s++) { - ex_point(u, t0 + (t1 - t0) * (double)s / (double)n, &x, &y); - cairo_line_to(cr, x, y); - } -} - -/* Wavy link from an exercise bubble up to the off-path branch. */ -static void branch_path(cairo_t *cr, double x0, double y0, - double x1, double y1) { - double dy = y0 - y1; - double c1x = x0 + EX_WAVE * 1.3; - double c1y = y0 - dy * 0.45; - double c2x = x1 - EX_WAVE * 1.3; - double c2y = y1 + dy * 0.45; - - cairo_move_to(cr, x0, y0); - cairo_curve_to(cr, c1x, c1y, c2x, c2y, x1, y1); -} - -void draw_ex_rail(GtkDrawingArea *area, cairo_t *cr, - int width, int height, gpointer user_data) { - UnitCtx *u = user_data; - const double t_end = (double)(u->n_ex - 1); - const Rgb slate = color_from_hex(app_theme.surface1); - const Rgb green = color_from_hex(app_theme.success); - const Rgb rail = color_from_hex(app_theme.rail); - - (void)area; - (void)width; - (void)height; - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - - cairo_new_path(cr); - ex_path(u, cr, 0.0, t_end); - cairo_set_line_width(cr, 14); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_new_path(cr); - ex_path(u, cr, 0.0, t_end); - cairo_set_line_width(cr, 9); - cairo_set_source_rgb(cr, slate.r, slate.g, slate.b); - cairo_stroke(cr); - - for (int k = 0; k < u->n_ex - 1; k++) { - if (!(u->done[k + 1] || u->done[k + 2])) - continue; - cairo_new_path(cr); - ex_path(u, cr, (double)k, (double)(k + 1)); - cairo_set_source_rgba(cr, green.r, green.g, green.b, 0.85); - cairo_set_line_width(cr, 9); - cairo_stroke(cr); - } - - /* Off-path branch connector up from exercise 2. */ - if (u->has_branch && u->n_ex > 1) { - gboolean bdone = u->done[u->branch_ex]; - - cairo_new_path(cr); - branch_path(cr, u->ex_cx[1], u->ex_cy[1], u->branch_cx, u->branch_cy); - cairo_set_line_width(cr, 14); - cairo_set_source_rgb(cr, rail.r, rail.g, rail.b); - cairo_stroke(cr); - - cairo_new_path(cr); - branch_path(cr, u->ex_cx[1], u->ex_cy[1], u->branch_cx, u->branch_cy); - cairo_set_line_width(cr, 9); - if (bdone) - cairo_set_source_rgba(cr, green.r, green.g, green.b, 0.85); - else - cairo_set_source_rgb(cr, slate.r, slate.g, slate.b); - cairo_stroke(cr); - } -} - -void ex_apply_layout(UnitCtx *u) { - int i; - - if (!u->ex_fixed) - return; - - for (i = 0; i < u->n_ex; i++) { - if (u->ex_cells[i]) - gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->ex_cells[i], - (int)(u->ex_cx[i] - EX_BUBBLE / 2.0), - (int)(u->ex_cy[i] - EX_BUBBLE / 2.0)); - if (u->ex_labels[i]) - gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->ex_labels[i], - (int)(u->ex_cx[i] - (EX_SPAC - 20.0) / 2.0), - (int)(u->ex_cy[i] + EX_BUBBLE / 2.0 + 8.0)); - } - - if (u->has_branch && u->branch_cell) { - gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->branch_cell, - (int)(u->branch_cx - EX_BUBBLE / 2.0), - (int)(u->branch_cy - EX_BUBBLE / 2.0)); - if (u->branch_label) - gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->branch_label, - (int)(u->branch_cx + EX_BUBBLE / 2.0 + 10.0), - (int)(u->branch_cy - 14.0)); - } - - gtk_widget_set_size_request(u->ex_fixed, u->ex_cw, u->ex_ch); - gtk_widget_set_size_request(u->ex_rail, u->ex_cw, u->ex_ch); - gtk_fixed_move(GTK_FIXED(u->ex_fixed), u->ex_rail, 0, 0); - gtk_widget_queue_draw(u->ex_rail); -} - -void ex_relayout(UnitCtx *u) { - GtkAdjustment *hadj; - double avail; - - if (!u->ex_scroll) - return; - hadj = gtk_scrolled_window_get_hadjustment( - GTK_SCROLLED_WINDOW(u->ex_scroll)); - avail = gtk_adjustment_get_page_size(hadj); - if (avail < 1.0) - return; - ex_layout_geometry(u, avail); - ex_apply_layout(u); -} - -gboolean ex_relayout_idle(gpointer data) { - UnitCtx *u = data; - u->ex_idle = 0; - ex_relayout(u); - return G_SOURCE_REMOVE; -} - -void ex_relayout_later(UnitCtx *u) { - if (u->ex_idle == 0) - u->ex_idle = g_idle_add(ex_relayout_idle, u); -} - -void ex_adjust_notify(GtkAdjustment *adj, GParamSpec *ps, - gpointer data) { - (void)adj; - (void)ps; - ex_relayout_later(data); -} - -GtkWidget *make_bubble(UnitCtx *u, int n) { - GtkWidget *btn; - GtkWidget *vbox; - GtkWidget *num_label; - GtkWidget *icon; - char *num; - char *target; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "ex-bubble"); - gtk_widget_set_size_request(btn, (int)EX_BUBBLE, (int)EX_BUBBLE); - gtk_widget_set_can_focus(btn, FALSE); - if (u->done[n]) - gtk_widget_add_css_class(btn, "done"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(btn), vbox); - - num = g_strdup_printf("%d", n); - num_label = gtk_label_new(num); - g_free(num); - gtk_widget_set_halign(num_label, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(num_label, "bubble-number"); - gtk_box_append(GTK_BOX(vbox), num_label); - - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 16); - gtk_widget_set_visible(icon, u->done[n]); - gtk_box_append(GTK_BOX(vbox), icon); - - u->ex_cells[n - 1] = btn; - u->ex_icons[n] = icon; - - target = g_strdup_printf("%se%d", u->ex_tag, n); - g_object_set_data_full(G_OBJECT(btn), "target", target, g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - - return btn; -} - -static GtkWidget *make_branch_bubble(UnitCtx *u) { - GtkWidget *btn; - GtkWidget *vbox; - GtkWidget *star; - GtkWidget *icon; - - btn = gtk_button_new(); - gtk_widget_add_css_class(btn, "ex-bubble"); - gtk_widget_add_css_class(btn, "ex-branch"); - gtk_widget_set_size_request(btn, (int)EX_BUBBLE, (int)EX_BUBBLE); - gtk_widget_set_can_focus(btn, FALSE); - if (u->done[u->branch_ex]) - gtk_widget_add_css_class(btn, "done"); - - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2); - gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER); - gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER); - gtk_button_set_child(GTK_BUTTON(btn), vbox); - - star = gtk_label_new("★"); - gtk_widget_set_halign(star, GTK_ALIGN_CENTER); - gtk_widget_add_css_class(star, "bubble-number"); - gtk_widget_add_css_class(star, "branch-star"); - gtk_box_append(GTK_BOX(vbox), star); - - icon = icon_area_new(draw_check_icon, 0.1176, 0.1176, 0.1804, 16); - gtk_widget_set_visible(icon, u->done[u->branch_ex]); - gtk_box_append(GTK_BOX(vbox), icon); - - u->branch_cell = btn; - u->branch_icon = icon; - - g_object_set_data_full(G_OBJECT(btn), "target", - g_strdup(u->branch_target), g_free); - g_signal_connect(btn, "clicked", G_CALLBACK(on_nav_clicked), NULL); - return btn; -} - -GtkWidget *build_unit_page(UnitCtx *u) { - GtkWidget *page; - GtkWidget *scroll; - GtkWidget *wrap; - GtkWidget *fixed; - GtkWidget *rail; - GtkAdjustment *ha; - GtkAdjustment *va; - int i; - - if (u->n_ex < 1) - return NULL; - ex_layout_geometry(u, 1000.0); - - page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_hexpand(page, TRUE); - gtk_widget_set_vexpand(page, TRUE); - gtk_widget_set_margin_start(page, 32); - gtk_widget_set_margin_end(page, 32); - gtk_widget_set_margin_top(page, 24); - gtk_widget_set_margin_bottom(page, 24); - - gtk_box_append(GTK_BOX(page), - top_bar(u->back_target ? u->back_target : "roadmap", - u->title, u->sub_key)); - - scroll = gtk_scrolled_window_new(); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_widget_set_vexpand(scroll, TRUE); - gtk_widget_set_margin_top(scroll, 14); - gtk_box_append(GTK_BOX(page), scroll); - u->ex_scroll = scroll; - - wrap = gtk_center_box_new(); - gtk_widget_set_vexpand(wrap, TRUE); - gtk_widget_set_hexpand(wrap, TRUE); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), wrap); - - fixed = gtk_fixed_new(); - gtk_widget_set_halign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_valign(fixed, GTK_ALIGN_CENTER); - gtk_widget_set_size_request(fixed, u->ex_cw, u->ex_ch); - gtk_center_box_set_center_widget(GTK_CENTER_BOX(wrap), fixed); - u->ex_fixed = fixed; - - rail = gtk_drawing_area_new(); - gtk_widget_set_size_request(rail, u->ex_cw, u->ex_ch); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(rail), draw_ex_rail, - u, NULL); - gtk_fixed_put(GTK_FIXED(fixed), rail, 0, 0); - u->ex_rail = rail; - - for (i = 0; i < u->n_ex; i++) { - GtkWidget *btn = make_bubble(u, i + 1); - GtkWidget *lbl = gtk_label_new(u->ex_names[i + 1]); - - u->ex_labels[i] = lbl; - - gtk_widget_set_size_request(lbl, (int)(EX_SPAC - 20.0), -1); - gtk_widget_set_halign(lbl, GTK_ALIGN_CENTER); - gtk_label_set_justify(GTK_LABEL(lbl), GTK_JUSTIFY_CENTER); - gtk_label_set_wrap(GTK_LABEL(lbl), TRUE); - gtk_widget_add_css_class(lbl, "ex-label"); - - gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0); - gtk_fixed_put(GTK_FIXED(fixed), lbl, 0, 0); - } - - if (u->has_branch && u->branch_target) { - GtkWidget *btn = make_branch_bubble(u); - GtkWidget *lbl = gtk_label_new(u->branch_name); - - u->branch_label = lbl; - gtk_widget_set_halign(lbl, GTK_ALIGN_START); - gtk_widget_add_css_class(lbl, "ex-label"); - gtk_widget_set_visible(lbl, TRUE); - - gtk_fixed_put(GTK_FIXED(fixed), btn, 0, 0); - gtk_fixed_put(GTK_FIXED(fixed), lbl, 0, 0); - } - - ha = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scroll)); - va = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll)); - g_signal_connect(ha, "notify::page-size", - G_CALLBACK(ex_adjust_notify), u); - g_signal_connect(va, "notify::page-size", - G_CALLBACK(ex_adjust_notify), u); - - ex_apply_layout(u); - ex_relayout_later(u); - - return page; -} diff --git a/src/update.c b/src/update.c deleted file mode 100644 index bf39b9e..0000000 --- a/src/update.c +++ /dev/null @@ -1,1127 +0,0 @@ -#include "graduately.h" - -#include - -#ifdef _WIN32 -#include -#define update_getpid() ((long)_getpid()) -#else -#include -#define update_getpid() ((long)getpid()) -#endif - -/* ------------------------------------------------------------------ */ -/* Self-update */ -/* ------------------------------------------------------------------ */ - -/* Networking runs through the `curl` command rather than a linked HTTP - * library. curl already handles TLS, redirects and proxies, it ships with - * macOS, with every desktop Linux and with Windows 10 and later, and using it - * keeps the three bundling scripts free of another shared library to ship. - * Every call is asynchronous, so a slow or unreachable network never blocks - * the interface. - * - * Packages are not published as releases. They live on the `builds` branch of - * the repository, which CI rewrites on every change to main, so an update is - * simply whatever that branch currently holds. The branch also carries a - * VERSION file naming the commit its packages were built from; comparing that - * against the commit baked into this binary is the whole check. - * - * raw.githubusercontent.com is cached by Fastly by branch name, so a URL that - * says `/builds/VERSION` can keep serving yesterday's file after CI rewrote - * the branch. The check therefore reads the branch tip from the Atom feed - * (plain curl, no API token) and then fetches VERSION and the package from - * that commit SHA. Serving files from raw.githubusercontent.com still avoids - * the REST API and its unauthenticated rate limit, and needs no JSON parser. - * - * An application cannot reliably replace its own files while it is running, so - * all three platforms follow the same shape: unpack the new version into a - * writable staging directory, write a small script that waits for this process - * to exit before swapping it in, then launch that script detached and quit. - * Staging lives in the user cache first, because /Applications is often not - * writable from a GUI app even when the installer could put a .app there. */ - -#define UPDATE_ATOM_URL "https://github.com/" UPDATE_REPO \ - "/commits/" UPDATE_BRANCH ".atom" -#define UPDATE_STAGING_DIR ".graduately-update" - -#ifdef _WIN32 -#define NULL_DEVICE "NUL" -#else -#define NULL_DEVICE "/dev/null" -#endif - -#ifdef __APPLE__ -#define CURL_BIN "/usr/bin/curl" -#else -#define CURL_BIN "curl" -#endif - -typedef enum { - UPDATE_IDLE, - UPDATE_CHECKING, - UPDATE_UP_TO_DATE, - UPDATE_AVAILABLE, - UPDATE_DOWNLOADING, - UPDATE_STAGED, - UPDATE_FAILED, -} UpdateState; - -/* How this copy is installed, which decides what the update has to replace: a - * macOS bundle, a Windows install directory, or a single AppImage file. Builds - * run straight from the source tree cannot update themselves. */ -typedef enum { - INSTALL_UNSUPPORTED, - INSTALL_MACOS_BUNDLE, - INSTALL_WINDOWS_DIR, - INSTALL_APPIMAGE, -} InstallKind; - -static struct { - UpdateState state; - gboolean interactive; /* user asked, so also report "up to date" */ - char *tip; /* current commit of the builds branch itself */ - char *latest; /* commit the published packages were built from */ - char *latest_hint; /* "Build from " parsed from the Atom title */ - char *staging; /* scratch directory beside the install */ - char *archive; /* asset downloaded into the staging directory */ - char *source; /* unpacked version the swap script moves in */ - char *script; /* swap script, run after this process exits */ - char *error; - goffset total; /* asset size, 0 when the server did not say */ - guint poll_id; - GtkWidget *banner; - GtkWidget *banner_label; - GtkWidget *banner_action; - GtkWidget *status; /* status line in the settings popover */ - GtkWidget *action; /* check / update / restart button */ - GtkWidget *progress; -} up; - -/* ------------------------------------------------------------------ */ -/* Build identity */ -/* ------------------------------------------------------------------ */ - -/* Commits are not ordered, so there is nothing to compare: the branch only - * ever holds the current build, and anything else means this copy is behind. - * Short and full forms count as the same commit, so the interface can show a - * short one without confusing the check. */ -/* First 7–40 hex digits on the line; ignores comments and CDN junk. */ -static char *parse_commit(const char *text) { - const char *p; - size_t n; - - if (!text) - return NULL; - for (p = text; *p; p++) { - if (g_ascii_isxdigit(*p)) { - n = 0; - while (g_ascii_isxdigit(p[n])) - n++; - if (n >= 7 && n <= 40) - return g_strndup(p, n); - p += n; - if (!*p) - break; - } - } - return NULL; -} - -/* First Grit::Commit/<40-hex> in a GitHub Atom feed is the branch tip. */ -static char *parse_atom_commit(const char *text) { - const char *p; - - if (!text) - return NULL; - p = strstr(text, "Commit/"); - while (p) { - const char *s = p + 7; - size_t n = 0; - - while (g_ascii_isxdigit(s[n])) - n++; - if (n == 40) - return g_strndup(s, 40); - p = strstr(s, "Commit/"); - } - return NULL; -} - -/* CI commit message on the builds branch: "Build from ". */ -static char *parse_build_from(const char *text) { - const char *p; - - if (!text) - return NULL; - p = strstr(text, "Build from "); - if (!p) - return NULL; - p += 11; - if (strlen(p) >= 40) { - size_t n = 0; - - while (n < 40 && g_ascii_isxdigit(p[n])) - n++; - if (n == 40) - return g_strndup(p, 40); - } - return parse_commit(p); -} - -/* Pin raw.githubusercontent.com to a commit so Fastly cannot serve a stale - * branch-named file. Falls back to the branch name if the tip is unknown. */ -static char *builds_raw_url(const char *name) { - const char *ref = (up.tip && up.tip[0]) ? up.tip : UPDATE_BRANCH; - - return g_strdup_printf("https://raw.githubusercontent.com/%s/%s/%s", - UPDATE_REPO, ref, name); -} - -static gboolean same_commit(const char *a, const char *b) { - char *ca = parse_commit(a); - char *cb = parse_commit(b); - size_t n; - gboolean ok; - - if (!ca || !cb) { - g_free(ca); - g_free(cb); - return FALSE; - } - n = MIN(strlen(ca), strlen(cb)); - ok = n >= 7 && g_ascii_strncasecmp(ca, cb, n) == 0; - g_free(ca); - g_free(cb); - return ok; -} - -/* Packaged builds carry a source commit; see APP_COMMIT in graduately.h. */ -static gboolean is_published_build(void) { - return g_ascii_isxdigit(APP_COMMIT[0]) && strlen(APP_COMMIT) >= 7; -} - -/* Commit hashes are unreadable at full length; seven characters is what git - * itself shows. */ -static char *short_commit(const char *sha) { - return g_strndup(sha ? sha : "", 7); -} - -/* ------------------------------------------------------------------ */ -/* Install layout */ -/* ------------------------------------------------------------------ */ - -/* The asset published for this platform, or NULL when the release carries - * none. Only arm64 macOS and x86_64 Linux / Windows are built. */ -static const char *asset_name(void) { -#if defined(_WIN32) - return "graduately-windows-x64.zip"; -#elif defined(__APPLE__) -#if defined(__aarch64__) || defined(__arm64__) - return "graduately-macos-arm64.zip"; -#else - return NULL; -#endif -#elif defined(__x86_64__) - return "graduately-linux-x86_64.AppImage"; -#else - return NULL; -#endif -} - -/* What the update replaces, plus the directory holding it. */ -static InstallKind install_target(char **target_out, char **parent_out) { - char *exe = app_executable_path(); - InstallKind kind = INSTALL_UNSUPPORTED; - char *target = NULL; - - *target_out = NULL; - *parent_out = NULL; - -#ifndef _WIN32 - { - const char *appimage = g_getenv("APPIMAGE"); - - if (appimage && appimage[0]) { - target = g_strdup(appimage); - kind = INSTALL_APPIMAGE; - } - } -#endif - -#ifdef __APPLE__ - /* .../Graduately.app/Contents/MacOS/Graduately -> .../Graduately.app */ - if (!target && exe) { - char *macos_dir = g_path_get_dirname(exe); - char *contents = g_path_get_dirname(macos_dir); - char *bundle = g_path_get_dirname(contents); - - if (g_str_has_suffix(macos_dir, "MacOS") && - g_str_has_suffix(bundle, ".app")) { - target = g_strdup(bundle); - kind = INSTALL_MACOS_BUNDLE; - } - g_free(bundle); - g_free(contents); - g_free(macos_dir); - } -#endif - -#ifdef _WIN32 - /* The Windows package is a plain directory holding the exe and the GTK - * runtime, so the directory itself is what gets refreshed. */ - if (!target && exe) { - target = g_path_get_dirname(exe); - kind = INSTALL_WINDOWS_DIR; - } -#endif - - if (target) { - *target_out = target; - *parent_out = g_path_get_dirname(target); - } - g_free(exe); - return kind; -} - -/* An update is only worth offering when a release carries an asset for this - * platform and the running copy is one this code knows how to replace. */ -static gboolean update_supported(void) { - char *target = NULL; - char *parent = NULL; - gboolean ok = install_target(&target, &parent) != INSTALL_UNSUPPORTED; - - g_free(target); - g_free(parent); - return ok && asset_name() != NULL; -} - -/* Depth-first delete; GLib has no recursive remove. */ -static void remove_tree(const char *path) { - GDir *dir; - - if (!path || !g_file_test(path, G_FILE_TEST_EXISTS)) - return; - - if (g_file_test(path, G_FILE_TEST_IS_DIR) && - !g_file_test(path, G_FILE_TEST_IS_SYMLINK)) { - const char *name; - - dir = g_dir_open(path, 0, NULL); - if (dir) { - while ((name = g_dir_read_name(dir))) { - char *child = g_build_filename(path, name, NULL); - - remove_tree(child); - g_free(child); - } - g_dir_close(dir); - } - g_rmdir(path); - } else { - g_remove(path); - } -} - -/* An interrupted swap leaves the staging directory behind; drop it so it does - * not sit next to the install forever. */ -void update_clear_staging(void) { - char *target = NULL; - char *parent = NULL; - char *cache = g_build_filename(g_get_user_cache_dir(), - "graduately-update", NULL); - - remove_tree(cache); - g_free(cache); - if (install_target(&target, &parent) != INSTALL_UNSUPPORTED) { - char *stale = g_build_filename(parent, UPDATE_STAGING_DIR, NULL); - - remove_tree(stale); - g_free(stale); - } - g_free(target); - g_free(parent); -} - -/* ------------------------------------------------------------------ */ -/* Interface state */ -/* ------------------------------------------------------------------ */ - -static void update_set_state(UpdateState state); -static void update_start_download(void); - -static void update_fail(const char *message) { - g_free(up.error); - up.error = g_strdup(message); - update_set_state(UPDATE_FAILED); -} - -static void update_refresh_ui(void) { - gboolean busy = up.state == UPDATE_CHECKING || - up.state == UPDATE_DOWNLOADING; - gboolean banner = up.state == UPDATE_AVAILABLE || - up.state == UPDATE_DOWNLOADING || - up.state == UPDATE_STAGED; - const char *status = ""; - const char *action = "update_check"; - char *owned = NULL; - - switch (up.state) { - case UPDATE_IDLE: - case UPDATE_UP_TO_DATE: { - char *mine = short_commit(APP_COMMIT); - - owned = g_strdup_printf(tr(up.state == UPDATE_IDLE - ? "update_current" - : "update_uptodate"), mine); - status = owned; - g_free(mine); - break; - } - case UPDATE_CHECKING: - status = tr("update_checking"); - break; - case UPDATE_AVAILABLE: { - char *newest = short_commit(up.latest); - - owned = g_strdup_printf(tr("update_available"), newest); - status = owned; - action = "update_install"; - g_free(newest); - break; - } - case UPDATE_DOWNLOADING: - status = tr("update_downloading"); - action = "update_install"; - break; - case UPDATE_STAGED: - status = tr("update_staged"); - action = "update_restart"; - break; - case UPDATE_FAILED: - status = up.error ? up.error : tr("update_failed"); - break; - } - - if (up.status) - gtk_label_set_text(GTK_LABEL(up.status), status); - if (up.action) { - gtk_button_set_label(GTK_BUTTON(up.action), tr(action)); - gtk_widget_set_sensitive(up.action, !busy); - } - if (up.progress) - gtk_widget_set_visible(up.progress, up.state == UPDATE_DOWNLOADING); - - if (up.banner) { - gtk_revealer_set_reveal_child(GTK_REVEALER(up.banner), banner); - if (banner) { - gtk_label_set_text(GTK_LABEL(up.banner_label), status); - gtk_button_set_label(GTK_BUTTON(up.banner_action), tr(action)); - gtk_widget_set_sensitive(up.banner_action, !busy); - } - } - - g_free(owned); -} - -static void update_set_state(UpdateState state) { - up.state = state; - update_refresh_ui(); -} - -/* Called by apply_language() so switching language relabels the banner. */ -void update_apply_lang(void) { - update_refresh_ui(); -} - -/* ------------------------------------------------------------------ */ -/* Running curl */ -/* ------------------------------------------------------------------ */ - -/* Host tools (curl, tar, ditto, the swap script) must not inherit the - * bundle's DYLD/LD library path — that is for GTK, and it can stop system - * curl from talking to the network. */ -static GSubprocess *spawn_host(const char *const *argv, GSubprocessFlags flags) { - GSubprocessLauncher *launcher = g_subprocess_launcher_new(flags); - GSubprocess *proc; - -#ifdef __APPLE__ - g_subprocess_launcher_unsetenv(launcher, "DYLD_LIBRARY_PATH"); - g_subprocess_launcher_unsetenv(launcher, "DYLD_FALLBACK_LIBRARY_PATH"); - g_subprocess_launcher_unsetenv(launcher, "DYLD_INSERT_LIBRARIES"); -#endif -#ifdef __linux__ - if (g_getenv("APPIMAGE")) - g_subprocess_launcher_unsetenv(launcher, "LD_LIBRARY_PATH"); -#endif - proc = g_subprocess_launcher_spawnv(launcher, argv, NULL); - g_object_unref(launcher); - return proc; -} - -/* Spawn curl and hand its stdout to `done`. FALSE means curl itself could not - * be started, the one failure worth its own message. */ -static gboolean curl_async(const char *const *argv, GAsyncReadyCallback done) { - GSubprocess *proc; - - proc = spawn_host(argv, G_SUBPROCESS_FLAGS_STDOUT_PIPE | - G_SUBPROCESS_FLAGS_STDERR_SILENCE); - if (!proc) - return FALSE; - g_subprocess_communicate_utf8_async(proc, NULL, NULL, done, NULL); - return TRUE; -} - -/* ------------------------------------------------------------------ */ -/* Staging and the swap script */ -/* ------------------------------------------------------------------ */ - -/* The macOS asset holds a single .app whose name we should not assume. */ -static char *find_app_bundle(const char *dir) { - GDir *d = g_dir_open(dir, 0, NULL); - const char *name; - char *found = NULL; - - if (!d) - return NULL; - while (!found && (name = g_dir_read_name(d))) { - if (g_str_has_suffix(name, ".app")) - found = g_build_filename(dir, name, NULL); - } - g_dir_close(d); - return found; -} - -/* Each script takes: pid target source staging. They all wait for this - * process to exit, swap the new version in, relaunch and clean up after - * themselves. Rolling back on a failed move keeps a broken half-update from - * leaving the user with nothing to start. */ -static const char *swap_script_body(InstallKind kind) { - switch (kind) { - case INSTALL_MACOS_BUNDLE: - /* Detach first so dropping the GSubprocess (or quitting) cannot - * take the swap down with us. /Applications is often not writable - * from a GUI app, so a failed in-place copy goes to ~/Applications. - * ditto keeps the .app layout and works across volumes. */ - return "#!/bin/sh\n" - "if [ -z \"$MATURITA_UPDATE_DETACHED\" ]; then\n" - " MATURITA_UPDATE_DETACHED=1\n" - " export MATURITA_UPDATE_DETACHED\n" - " nohup /bin/sh \"$0\" \"$@\" >/dev/null 2>&1 &\n" - " exit 0\n" - "fi\n" - "pid=$1; target=$2; source=$3; staging=$4\n" - "n=0\n" - "while kill -0 \"$pid\" 2>/dev/null && [ $n -lt 600 ]; do\n" - " sleep 0.2; n=$((n+1))\n" - "done\n" - "place=$target\n" - "if /usr/bin/ditto \"$source\" \"$target\" 2>/dev/null; then\n" - " xattr -cr \"$target\" 2>/dev/null\n" - "else\n" - " alt=\"$HOME/Applications/$(basename \"$target\")\"\n" - " mkdir -p \"$HOME/Applications\"\n" - " if /usr/bin/ditto \"$source\" \"$alt\" 2>/dev/null; then\n" - " xattr -cr \"$alt\" 2>/dev/null\n" - " place=$alt\n" - " fi\n" - "fi\n" - "open -n \"$place\"\n" - "rm -rf \"$staging\"\n" - "rm -f \"$0\"\n"; - case INSTALL_APPIMAGE: - return "#!/bin/sh\n" - "if [ -z \"$MATURITA_UPDATE_DETACHED\" ]; then\n" - " MATURITA_UPDATE_DETACHED=1\n" - " export MATURITA_UPDATE_DETACHED\n" - " nohup /bin/sh \"$0\" \"$@\" >/dev/null 2>&1 &\n" - " exit 0\n" - "fi\n" - "pid=$1; target=$2; source=$3; staging=$4\n" - "n=0\n" - "while kill -0 \"$pid\" 2>/dev/null && [ $n -lt 600 ]; do\n" - " sleep 0.2; n=$((n+1))\n" - "done\n" - "if mv \"$source\" \"$target\" 2>/dev/null; then\n" - " chmod +x \"$target\"\n" - "fi\n" - "\"$target\" >/dev/null 2>&1 &\n" - "rm -rf \"$staging\"\n" - "rm -f \"$0\"\n"; - case INSTALL_WINDOWS_DIR: - /* Copies over the install without mirroring, so the progress files - * kept inside it survive. ping is the sleep that works without a - * console window. start /b detaches so quitting this process - * cannot terminate the swap. */ - return "@echo off\r\n" - "if not defined MATURITA_UPDATE_DETACHED (\r\n" - " set MATURITA_UPDATE_DETACHED=1\r\n" - " start \"\" /b cmd /c \"%~f0\" %*\r\n" - " exit /b 0\r\n" - ")\r\n" - "set PID=%~1\r\n" - "set TARGET=%~2\r\n" - "set SOURCE=%~3\r\n" - "set STAGING=%~4\r\n" - ":wait\r\n" - "tasklist /FI \"PID eq %PID%\" 2>nul" - " | find \"%PID%\" >nul\r\n" - "if not errorlevel 1 (\r\n" - " ping -n 2 127.0.0.1 >nul\r\n" - " goto wait\r\n" - ")\r\n" - "xcopy \"%SOURCE%\\*\" \"%TARGET%\\\" /E /I /Y /Q >nul\r\n" - "start \"\" \"%TARGET%\\graduately.exe\"\r\n" - "rmdir /s /q \"%STAGING%\"\r\n" - "del \"%~f0\"\r\n"; - case INSTALL_UNSUPPORTED: - default: - return NULL; - } -} - -static gboolean write_swap_script(InstallKind kind) { - const char *body = swap_script_body(kind); - const char *name = kind == INSTALL_WINDOWS_DIR ? "graduately-update.cmd" - : "graduately-update.sh"; - - if (!body) - return FALSE; - - g_free(up.script); - up.script = g_build_filename(g_get_tmp_dir(), name, NULL); - if (!g_file_set_contents(up.script, body, -1, NULL)) - return FALSE; - g_chmod(up.script, 0755); - return TRUE; -} - -/* Unpack the asset and write the swap script. Nothing outside the staging - * directory is touched until the user restarts. */ -static void install_staged(void) { - char *target = NULL; - char *parent = NULL; - InstallKind kind = install_target(&target, &parent); - char *source = NULL; - gboolean ok; - - if (kind == INSTALL_APPIMAGE) { - /* The asset already is the executable; there is nothing to unpack. */ - source = g_strdup(up.archive); - ok = TRUE; - } else { - char *unpacked = g_build_filename(up.staging, "new", NULL); -#ifdef __APPLE__ - const char *argv[] = {"/usr/bin/ditto", "-x", "-k", up.archive, - unpacked, NULL}; -#else - const char *argv[] = {"tar", "-xf", up.archive, "-C", unpacked, NULL}; -#endif - GSubprocess *proc; - - /* macOS: ditto keeps the .app layout. Elsewhere bsdtar reads zip. */ - ok = g_mkdir_with_parents(unpacked, 0755) == 0; - if (ok) { - proc = spawn_host(argv, G_SUBPROCESS_FLAGS_STDERR_SILENCE); - ok = proc && g_subprocess_wait_check(proc, NULL, NULL); - g_clear_object(&proc); - } - if (ok && kind == INSTALL_MACOS_BUNDLE) { - source = find_app_bundle(unpacked); - ok = source != NULL; - } else if (ok) { - source = g_strdup(unpacked); - } - g_free(unpacked); - } - - if (ok) - ok = write_swap_script(kind); - - g_free(up.source); - up.source = source; - g_free(target); - g_free(parent); - - if (ok) - update_set_state(UPDATE_STAGED); - else - update_fail(tr("update_err_stage")); -} - -/* ------------------------------------------------------------------ */ -/* Download */ -/* ------------------------------------------------------------------ */ - -/* curl writes straight to disk, so the partial file's size is the progress. */ -static gboolean download_poll(gpointer data) { - GStatBuf st; - - (void)data; - if (up.state != UPDATE_DOWNLOADING) { - up.poll_id = 0; - return G_SOURCE_REMOVE; - } - if (up.progress && up.archive && g_stat(up.archive, &st) == 0) { - if (up.total > 0) - gtk_progress_bar_set_fraction( - GTK_PROGRESS_BAR(up.progress), - CLAMP((double)st.st_size / (double)up.total, 0.0, 1.0)); - else - gtk_progress_bar_pulse(GTK_PROGRESS_BAR(up.progress)); - } - return G_SOURCE_CONTINUE; -} - -static void download_done(GObject *src, GAsyncResult *res, gpointer data) { - GSubprocess *proc = G_SUBPROCESS(src); - gboolean ok; - - (void)data; - g_subprocess_communicate_utf8_finish(proc, res, NULL, NULL, NULL); - ok = g_subprocess_get_successful(proc); - g_object_unref(proc); - - if (up.poll_id) { - g_source_remove(up.poll_id); - up.poll_id = 0; - } - - if (!ok) { - update_fail(tr("update_err_download")); - return; - } - install_staged(); -} - -/* Content-Length of the asset, read from the headers of every redirect hop. - * The last one is the file itself; the hops before it report zero. curl has no - * --write-out variable for this, since a HEAD downloads no body. */ -static goffset content_length_from_headers(const char *headers) { - char **lines = g_strsplit(headers ? headers : "", "\n", -1); - goffset total = 0; - - for (guint i = 0; lines[i]; i++) { - if (g_ascii_strncasecmp(lines[i], "content-length:", 15) == 0) { - goffset v = (goffset)g_ascii_strtoll(lines[i] + 15, NULL, 10); - - if (v > 0) - total = v; - } - } - g_strfreev(lines); - return total; -} - -/* The asset size only makes the progress bar meaningful, so a failure here - * costs nothing: the bar falls back to pulsing. */ -static void size_probe_done(GObject *src, GAsyncResult *res, gpointer data) { - GSubprocess *proc = G_SUBPROCESS(src); - char *out = NULL; - char *url; - const char *argv[8]; - - (void)data; - g_subprocess_communicate_utf8_finish(proc, res, &out, NULL, NULL); - up.total = content_length_from_headers(out); - g_free(out); - g_object_unref(proc); - - if (up.state != UPDATE_DOWNLOADING) - return; - - url = builds_raw_url(asset_name()); - argv[0] = CURL_BIN; - argv[1] = "-fsSL"; - argv[2] = "--max-time"; - argv[3] = "1800"; - argv[4] = "-o"; - argv[5] = up.archive; - argv[6] = url; - argv[7] = NULL; - - if (!curl_async(argv, download_done)) - update_fail(tr("update_err_curl")); - else - up.poll_id = g_timeout_add(250, download_poll, NULL); - g_free(url); -} - -static void update_start_download(void) { - char *target = NULL; - char *parent = NULL; - char *url; - const char *argv[10]; - - if (install_target(&target, &parent) == INSTALL_UNSUPPORTED || - !asset_name()) { - g_free(target); - g_free(parent); - update_fail(tr("update_err_unsupported")); - return; - } - - /* Stage in the user cache first: /Applications is often not writable - * from a GUI app even when the installer could put a .app there. */ - g_free(up.staging); - up.staging = g_build_filename(g_get_user_cache_dir(), - "graduately-update", NULL); - remove_tree(up.staging); - if (g_mkdir_with_parents(up.staging, 0755) != 0 && parent) { - g_free(up.staging); - up.staging = g_build_filename(parent, UPDATE_STAGING_DIR, NULL); - remove_tree(up.staging); - } - g_free(target); - g_free(parent); - if (g_mkdir_with_parents(up.staging, 0755) != 0) { - update_fail(tr("update_err_readonly")); - return; - } - - g_free(up.archive); - up.archive = g_build_filename(up.staging, asset_name(), NULL); - up.total = 0; - update_set_state(UPDATE_DOWNLOADING); - - /* HEAD the asset with its headers on stdout, to size the progress bar. */ - url = builds_raw_url(asset_name()); - argv[0] = CURL_BIN; - argv[1] = "-fsSLI"; - argv[2] = "--max-time"; - argv[3] = "20"; - argv[4] = "-D"; - argv[5] = "-"; - argv[6] = "-o"; - argv[7] = NULL_DEVICE; - argv[8] = url; - argv[9] = NULL; - - if (!curl_async(argv, size_probe_done)) - update_fail(tr("update_err_curl")); - g_free(url); -} - -/* ------------------------------------------------------------------ */ -/* Check */ -/* ------------------------------------------------------------------ */ - -/* A failed background check stays silent; only an explicit one reports. */ -static void check_giveup(void) { - if (up.interactive) - update_fail(tr("update_err_network")); - else - update_set_state(UPDATE_IDLE); -} - -static void finish_check(void) { - if (!up.latest) { - check_giveup(); - return; - } - - if (same_commit(APP_COMMIT, up.latest)) - update_set_state(up.interactive ? UPDATE_UP_TO_DATE : UPDATE_IDLE); - else if (update_supported()) { - update_set_state(UPDATE_AVAILABLE); - /* Download without another click: the remaining action is Restart. */ - update_start_download(); - } else if (up.interactive) - /* A newer build exists, but this copy cannot swap itself out. */ - update_fail(tr("update_err_unsupported")); - else - update_set_state(UPDATE_IDLE); -} - -static void check_done(GObject *src, GAsyncResult *res, gpointer data) { - GSubprocess *proc = G_SUBPROCESS(src); - char *out = NULL; - gboolean ok; - - (void)data; - g_subprocess_communicate_utf8_finish(proc, res, &out, NULL, NULL); - ok = g_subprocess_get_successful(proc); - g_object_unref(proc); - - if (out) - g_strstrip(out); - g_free(up.latest); - up.latest = (ok && out) ? parse_commit(out) : NULL; - g_free(out); - if (!up.latest && up.latest_hint) - up.latest = g_strdup(up.latest_hint); - finish_check(); -} - -static void tip_done(GObject *src, GAsyncResult *res, gpointer data) { - GSubprocess *proc = G_SUBPROCESS(src); - char *out = NULL; - gboolean ok; - char *url; - const char *argv[6]; - - (void)data; - g_subprocess_communicate_utf8_finish(proc, res, &out, NULL, NULL); - ok = g_subprocess_get_successful(proc); - g_object_unref(proc); - - g_free(up.tip); - g_free(up.latest_hint); - up.tip = (ok && out) ? parse_atom_commit(out) : NULL; - up.latest_hint = (ok && out) ? parse_build_from(out) : NULL; - g_free(out); - - /* The Atom title already names the main commit; that is enough to decide - * whether we are behind, even if the VERSION file fetch fails. */ - if (up.latest_hint) { - g_free(up.latest); - up.latest = g_strdup(up.latest_hint); - finish_check(); - return; - } - - if (!up.tip) { - url = g_strdup_printf( - "https://raw.githubusercontent.com/%s/%s/VERSION?t=%ld", - UPDATE_REPO, UPDATE_BRANCH, (long)g_get_real_time()); - } else { - url = builds_raw_url("VERSION"); - } - argv[0] = CURL_BIN; - argv[1] = "-fsSL"; - argv[2] = "--max-time"; - argv[3] = "20"; - argv[4] = url; - argv[5] = NULL; - - if (!curl_async(argv, check_done)) - check_giveup(); - g_free(url); -} - -void update_check_async(gboolean interactive) { - const char *argv[6]; - - if (up.state == UPDATE_CHECKING || up.state == UPDATE_DOWNLOADING || - up.state == UPDATE_STAGED) - return; - - up.interactive = interactive; - - /* Nothing to compare against without a baked-in commit. */ - if (!is_published_build()) { - if (interactive) - update_fail(tr("update_err_devbuild")); - return; - } - - update_set_state(UPDATE_CHECKING); - - argv[0] = CURL_BIN; - argv[1] = "-fsSL"; - argv[2] = "--max-time"; - argv[3] = "20"; - argv[4] = UPDATE_ATOM_URL; - argv[5] = NULL; - - if (!curl_async(argv, tip_done)) { - if (interactive) - update_fail(tr("update_err_curl")); - else - update_set_state(UPDATE_IDLE); - } -} - -/* ------------------------------------------------------------------ */ -/* Restart into the new version */ -/* ------------------------------------------------------------------ */ - -static void update_restart(void) { - char *target = NULL; - char *parent = NULL; - InstallKind kind = install_target(&target, &parent); - char *pid = g_strdup_printf("%ld", update_getpid()); - GSubprocess *proc; - const char *argv[8]; - int i = 0; - - if (kind == INSTALL_UNSUPPORTED || !up.script || !up.source || - !up.staging) { - g_free(pid); - g_free(target); - g_free(parent); - update_fail(tr("update_err_stage")); - return; - } - -#ifdef _WIN32 - argv[i++] = "cmd"; - argv[i++] = "/c"; -#else - argv[i++] = "/bin/sh"; -#endif - argv[i++] = up.script; - argv[i++] = pid; - argv[i++] = target; - argv[i++] = up.source; - argv[i++] = up.staging; - argv[i] = NULL; - - /* The script detaches itself and exits; wait for that so we do not - * quit before the grandchild is running. */ - proc = spawn_host(argv, G_SUBPROCESS_FLAGS_NONE); - g_free(pid); - g_free(target); - g_free(parent); - - if (!proc || !g_subprocess_wait_check(proc, NULL, NULL)) { - g_clear_object(&proc); - update_fail(tr("update_err_stage")); - return; - } - g_object_unref(proc); - - if (main_window) { - GtkApplication *app = gtk_window_get_application(main_window); - - if (app) - g_application_quit(G_APPLICATION(app)); - else - gtk_window_close(main_window); - } -} - -/* ------------------------------------------------------------------ */ -/* Widgets */ -/* ------------------------------------------------------------------ */ - -static void on_update_action(GtkButton *btn, gpointer data) { - (void)btn; - (void)data; - - switch (up.state) { - case UPDATE_AVAILABLE: - update_start_download(); - break; - case UPDATE_STAGED: - update_restart(); - break; - case UPDATE_DOWNLOADING: - case UPDATE_CHECKING: - break; - default: - update_check_async(TRUE); - break; - } -} - -static void on_update_dismiss(GtkButton *btn, gpointer data) { - (void)btn; - (void)data; - if (up.banner) - gtk_revealer_set_reveal_child(GTK_REVEALER(up.banner), FALSE); -} - -/* Strip shown above the page stack once an update is waiting. */ -GtkWidget *build_update_banner(void) { - GtkWidget *bar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - GtkWidget *label = gtk_label_new(""); - GtkWidget *action = gtk_button_new_with_label(""); - GtkWidget *later = gtk_button_new(); - - gtk_widget_add_css_class(bar, "update-banner"); - - gtk_widget_set_hexpand(label, TRUE); - gtk_label_set_xalign(GTK_LABEL(label), 0.0); - gtk_widget_add_css_class(label, "update-banner-text"); - gtk_box_append(GTK_BOX(bar), label); - - gtk_widget_add_css_class(action, "update-banner-btn"); - gtk_widget_set_valign(action, GTK_ALIGN_CENTER); - g_signal_connect(action, "clicked", G_CALLBACK(on_update_action), NULL); - gtk_box_append(GTK_BOX(bar), action); - - i18n_bind(later, "update_later", 1); - gtk_widget_add_css_class(later, "update-banner-later"); - gtk_widget_set_valign(later, GTK_ALIGN_CENTER); - g_signal_connect(later, "clicked", G_CALLBACK(on_update_dismiss), NULL); - gtk_box_append(GTK_BOX(bar), later); - - up.banner_label = label; - up.banner_action = action; - { - GtkWidget *reveal = gtk_revealer_new(); - - gtk_revealer_set_transition_type(GTK_REVEALER(reveal), - GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN); - gtk_revealer_set_transition_duration(GTK_REVEALER(reveal), 180); - gtk_revealer_set_reveal_child(GTK_REVEALER(reveal), FALSE); - gtk_revealer_set_child(GTK_REVEALER(reveal), bar); - up.banner = reveal; - return reveal; - } -} - -/* "Updates" section of the settings popover. */ -GtkWidget *build_update_box(void) { - GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - GtkWidget *row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); - GtkWidget *status = gtk_label_new(""); - GtkWidget *action = gtk_button_new_with_label(""); - GtkWidget *progress = gtk_progress_bar_new(); - - gtk_widget_set_hexpand(status, TRUE); - gtk_label_set_xalign(GTK_LABEL(status), 0.0); - gtk_label_set_wrap(GTK_LABEL(status), TRUE); - gtk_label_set_max_width_chars(GTK_LABEL(status), 30); - gtk_widget_add_css_class(status, "update-status"); - gtk_box_append(GTK_BOX(row), status); - - gtk_widget_add_css_class(action, "update-btn"); - gtk_widget_set_valign(action, GTK_ALIGN_CENTER); - g_signal_connect(action, "clicked", G_CALLBACK(on_update_action), NULL); - gtk_box_append(GTK_BOX(row), action); - gtk_box_append(GTK_BOX(box), row); - - gtk_widget_add_css_class(progress, "update-progress"); - gtk_widget_set_visible(progress, FALSE); - gtk_box_append(GTK_BOX(box), progress); - - up.status = status; - up.action = action; - up.progress = progress; - update_refresh_ui(); - return box; -} - -/* ------------------------------------------------------------------ */ -/* Startup */ -/* ------------------------------------------------------------------ */ - -static gboolean update_startup_check(gpointer data) { - (void)data; - update_check_async(FALSE); - return G_SOURCE_REMOVE; -} - -/* The first check can race CI publishing a new build after launch. */ -static gboolean update_periodic_check(gpointer data) { - (void)data; - if (up.state == UPDATE_IDLE || up.state == UPDATE_UP_TO_DATE || - up.state == UPDATE_FAILED) - update_check_async(FALSE); - return G_SOURCE_CONTINUE; -} - -void update_on_settings_open(void) { - if (up.state == UPDATE_IDLE || up.state == UPDATE_UP_TO_DATE || - up.state == UPDATE_FAILED) - update_check_async(FALSE); -} - -/* Leaves the first seconds to the interface, then looks for a new release. */ -void update_init(void) { - update_clear_staging(); - g_timeout_add_seconds(3, update_startup_check, NULL); - g_timeout_add_seconds(120, update_periodic_check, NULL); -} diff --git a/src/util.c b/src/util.c deleted file mode 100644 index ec2abaf..0000000 --- a/src/util.c +++ /dev/null @@ -1,434 +0,0 @@ -#include "graduately.h" - -#ifdef _WIN32 -#include -#elif defined(__APPLE__) -#include -#include -#else -#include -#endif - -/* ------------------------------------------------------------------ */ -/* Portable data / progress paths */ -/* ------------------------------------------------------------------ */ - -char *app_progress_dir; -char *app_progress_u1; -char *app_progress_u2; -char *app_progress_u3; -char *app_settings_file; -char *app_progress_net; -char *app_progress_hw; -char *app_progress_on; -char *app_progress_on2; -char *app_progress_on3; -char *app_progress_on4; -char *app_progress_en; -char *app_progress_de; -char *app_progress_mluvnice; -char *app_progress_cetba; -char *app_progress_lit; -char *app_progress_lit2; -char *app_progress_lit3; -char *app_progress_lit4; -char *app_progress_chem; -char *app_progress_bio; -char *app_progress_fyz; -char *app_progress_fyz2; -char *app_progress_fyz3; -char *app_progress_fyz4; -char *app_progress_mat0; -char *app_progress_mat; -char *app_progress_mat2; -char *app_progress_mat3; -char *app_progress_mat4; - -static char *dup_dirname(const char *path) { - char *tmp = g_strdup(path); - char *dir; - - if (!tmp) - return NULL; - dir = g_path_get_dirname(tmp); - g_free(tmp); - return dir; -} - -/* Absolute path of this process's executable, or NULL. */ -char *app_executable_path(void) { -#ifdef _WIN32 - wchar_t wbuf[MAX_PATH]; - DWORD n = GetModuleFileNameW(NULL, wbuf, MAX_PATH); - char *out; - - if (n == 0 || n >= MAX_PATH) - return NULL; - out = g_utf16_to_utf8((const gunichar2 *)wbuf, -1, NULL, NULL, NULL); - return out; -#elif defined(__APPLE__) - char *buf; - uint32_t size = 0; - - _NSGetExecutablePath(NULL, &size); - if (size == 0) - return NULL; - buf = g_malloc(size); - if (_NSGetExecutablePath(buf, &size) != 0) { - g_free(buf); - return NULL; - } - { - char *real = g_canonicalize_filename(buf, NULL); - - g_free(buf); - return real ? real : NULL; - } -#else - return g_file_read_link("/proc/self/exe", NULL); -#endif -} - -static gboolean dir_has_stylesheet(const char *dir) { - char *css; - gboolean ok; - - if (!dir || !dir[0]) - return FALSE; - css = g_build_filename(dir, CSS_FILE, NULL); - ok = g_file_test(css, G_FILE_TEST_IS_REGULAR); - g_free(css); - return ok; -} - -/* Source tree keeps runtime files in data/; installed copies put them - * next to the binary (or in Contents/Resources on macOS). */ -static char *stylesheet_dir(const char *dir) { - char *child; - - if (!dir || !dir[0]) - return NULL; - if (dir_has_stylesheet(dir)) - return g_strdup(dir); - child = g_build_filename(dir, "data", NULL); - if (dir_has_stylesheet(child)) - return child; - g_free(child); - return NULL; -} - -static char *macos_resources_dir(const char *exe) { - char *macos_dir; - char *contents; - char *resources; - - if (!exe) - return NULL; - macos_dir = dup_dirname(exe); - if (!macos_dir) - return NULL; - if (!g_str_has_suffix(macos_dir, "MacOS")) { - g_free(macos_dir); - return NULL; - } - contents = dup_dirname(macos_dir); - g_free(macos_dir); - if (!contents) - return NULL; - resources = g_build_filename(contents, "Resources", NULL); - g_free(contents); - if (!dir_has_stylesheet(resources)) { - g_free(resources); - return NULL; - } - return resources; -} - -/* Directory next to Foo.app when exe is .../Foo.app/Contents/MacOS/Graduately. */ -static char *macos_app_parent_dir(const char *exe) { - char *macos_dir; - char *contents; - char *app_bundle; - char *parent; - - if (!exe) - return NULL; - macos_dir = dup_dirname(exe); - if (!macos_dir || !g_str_has_suffix(macos_dir, "MacOS")) { - g_free(macos_dir); - return NULL; - } - contents = dup_dirname(macos_dir); - g_free(macos_dir); - if (!contents) - return NULL; - app_bundle = dup_dirname(contents); - g_free(contents); - if (!app_bundle) - return NULL; - parent = dup_dirname(app_bundle); - g_free(app_bundle); - return parent; -} - -static void set_progress_paths(const char *write_root) { - g_free(app_progress_dir); - g_free(app_progress_u1); - g_free(app_progress_u2); - g_free(app_progress_u3); - g_free(app_settings_file); - g_free(app_progress_net); - g_free(app_progress_hw); - g_free(app_progress_on); - g_free(app_progress_on2); - g_free(app_progress_on3); - g_free(app_progress_on4); - g_free(app_progress_en); - g_free(app_progress_de); - g_free(app_progress_mluvnice); - g_free(app_progress_cetba); - g_free(app_progress_lit); - g_free(app_progress_lit2); - g_free(app_progress_lit3); - g_free(app_progress_lit4); - g_free(app_progress_chem); - g_free(app_progress_bio); - g_free(app_progress_fyz); - g_free(app_progress_fyz2); - g_free(app_progress_fyz3); - g_free(app_progress_fyz4); - g_free(app_progress_mat0); - g_free(app_progress_mat); - g_free(app_progress_mat2); - g_free(app_progress_mat3); - g_free(app_progress_mat4); - - app_progress_dir = g_build_filename(write_root, PROGRESS_DIR_NAME, NULL); - app_progress_u1 = g_build_filename(app_progress_dir, "unit1.conf", NULL); - app_progress_u2 = g_build_filename(app_progress_dir, "unit2.conf", NULL); - app_progress_u3 = g_build_filename(app_progress_dir, "unit3.conf", NULL); - app_settings_file = g_build_filename(app_progress_dir, "settings.conf", NULL); - app_progress_net = g_build_filename(app_progress_dir, "net.conf", NULL); - app_progress_hw = g_build_filename(app_progress_dir, "hw.conf", NULL); - app_progress_on = g_build_filename(app_progress_dir, "on.conf", NULL); - app_progress_on2 = g_build_filename(app_progress_dir, "on2.conf", NULL); - app_progress_on3 = g_build_filename(app_progress_dir, "on3.conf", NULL); - app_progress_on4 = g_build_filename(app_progress_dir, "on4.conf", NULL); - app_progress_en = g_build_filename(app_progress_dir, "english.conf", NULL); - app_progress_de = g_build_filename(app_progress_dir, "german-course.conf", NULL); - app_progress_mluvnice = g_build_filename(app_progress_dir, "mluvnice.conf", NULL); - app_progress_cetba = g_build_filename(app_progress_dir, "cetba.conf", NULL); - app_progress_lit = g_build_filename(app_progress_dir, "lit.conf", NULL); - app_progress_lit2 = g_build_filename(app_progress_dir, "lit2.conf", NULL); - app_progress_lit3 = g_build_filename(app_progress_dir, "lit3.conf", NULL); - app_progress_lit4 = g_build_filename(app_progress_dir, "lit4.conf", NULL); - app_progress_chem = g_build_filename(app_progress_dir, "chem.conf", NULL); - app_progress_bio = g_build_filename(app_progress_dir, "bio.conf", NULL); - app_progress_fyz = g_build_filename(app_progress_dir, "fyz.conf", NULL); - app_progress_fyz2 = g_build_filename(app_progress_dir, "fyz2.conf", NULL); - app_progress_fyz3 = g_build_filename(app_progress_dir, "fyz3.conf", NULL); - app_progress_fyz4 = g_build_filename(app_progress_dir, "fyz4.conf", NULL); - app_progress_mat0 = g_build_filename(app_progress_dir, "mat0.conf", NULL); - app_progress_mat = g_build_filename(app_progress_dir, "mat.conf", NULL); - app_progress_mat2 = g_build_filename(app_progress_dir, "mat2.conf", NULL); - app_progress_mat3 = g_build_filename(app_progress_dir, "mat3.conf", NULL); - app_progress_mat4 = g_build_filename(app_progress_dir, "mat4.conf", NULL); -} - -/* Resolve read-only asset root, chdir there, and point progress at a writable - * location (next to the AppImage / .app, or beside the binary / source tree). */ -void setup_portable_paths(void) { - const char *appdir = g_getenv("APPDIR"); - const char *appimage = g_getenv("APPIMAGE"); - char *exe = app_executable_path(); - char *exe_dir = exe ? dup_dirname(exe) : NULL; - char *data_dir = NULL; - char *write_root = NULL; - char *cwd; - - if (appdir) - data_dir = stylesheet_dir(appdir); - if (!data_dir) - data_dir = macos_resources_dir(exe); - if (!data_dir) - data_dir = stylesheet_dir(exe_dir); - if (!data_dir && exe_dir) { - char *parent = dup_dirname(exe_dir); - - data_dir = stylesheet_dir(parent); - g_free(parent); - } - - cwd = g_get_current_dir(); - if (!data_dir) - data_dir = stylesheet_dir(cwd); - if (!data_dir && cwd) - data_dir = g_strdup(cwd); - - if (appimage && appimage[0]) - write_root = dup_dirname(appimage); - if (!write_root) - write_root = macos_app_parent_dir(exe); - /* Keep progress/ at the project root when the binary lives in build/. */ - if (!write_root && exe_dir) { - char *parent = dup_dirname(exe_dir); - char *from_parent = stylesheet_dir(parent); - - if (from_parent) { - write_root = parent; - parent = NULL; - g_free(from_parent); - } - g_free(parent); - } - if (!write_root && exe_dir) - write_root = g_strdup(exe_dir); - if (!write_root && data_dir) { - if (g_str_has_suffix(data_dir, G_DIR_SEPARATOR_S "data")) - write_root = dup_dirname(data_dir); - else - write_root = g_strdup(data_dir); - } - if (!write_root) - write_root = g_strdup("."); - - set_progress_paths(write_root); - - if (data_dir && g_chdir(data_dir) != 0) - g_warning("Could not chdir to data directory '%s'", data_dir); - - g_free(cwd); - g_free(write_root); - g_free(data_dir); - g_free(exe_dir); - g_free(exe); -} - -char *normalize_answer(const char *input) { - GString *pre = g_string_new(NULL); - GString *out = g_string_new(NULL); - const gchar *down = g_utf8_strdown(input ? input : "", -1); - gchar *decomp; - const gchar *p; - gboolean prev_space = FALSE; - - /* German special letters first, so ä/ö/ü/ß keep their two-letter - * keyboard fallbacks (ae/oe/ue/ss). */ - for (p = down; *p; p = g_utf8_next_char(p)) { - gunichar ch = g_utf8_get_char(p); - - switch (ch) { - case 0x00e4: g_string_append(pre, "ae"); break; /* ä */ - case 0x00f6: g_string_append(pre, "oe"); break; /* ö */ - case 0x00fc: g_string_append(pre, "ue"); break; /* ü */ - case 0x00df: g_string_append(pre, "ss"); break; /* ß */ - default: g_string_append_unichar(pre, ch); break; - } - } - - /* Decompose and drop combining accent marks so Czech letters such as - * é/ě/ř/ů/ž/š/č are treated as their base letters. */ - decomp = g_utf8_normalize(pre->str, -1, G_NORMALIZE_NFD); - if (!decomp) - decomp = g_strdup(pre->str); - - for (p = decomp; *p; p = g_utf8_next_char(p)) { - gunichar ch = g_utf8_get_char(p); - - if (g_unichar_combining_class(ch) != 0) - continue; /* accent mark */ - - if (g_unichar_isspace(ch)) { - if (out->len > 0 && !prev_space) - g_string_append_c(out, ' '); - prev_space = TRUE; - continue; - } - - if (!g_unichar_isalnum(ch)) - continue; /* ignore punctuation and symbols */ - - prev_space = FALSE; - g_string_append_unichar(out, ch); - } - - if (out->len > 0 && out->str[out->len - 1] == ' ') - g_string_truncate(out, out->len - 1); - - g_free(decomp); - g_free((gpointer)down); - g_string_free(pre, TRUE); - return g_string_free(out, FALSE); -} - -void shuffle_indices(int *arr, int n) { - for (int i = n - 1; i > 0; i--) { - int j = g_random_int_range(0, i + 1); - int tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } -} - -void flow_clear(GtkFlowBox *fb) { - GtkWidget *c = gtk_widget_get_first_child(GTK_WIDGET(fb)); - while (c) { - GtkWidget *next = gtk_widget_get_next_sibling(c); - gtk_flow_box_remove(fb, c); - c = next; - } -} - -void answer_mark(GtkWidget *widget, gboolean ok) { - if (ok) { - gtk_widget_remove_css_class(widget, "answer-wrong"); - gtk_widget_add_css_class(widget, "answer-ok"); - } else { - gtk_widget_remove_css_class(widget, "answer-ok"); - gtk_widget_add_css_class(widget, "answer-wrong"); - } -} - -void set_feedback(GtkWidget *label, gboolean ok, const char *text) { - gtk_widget_remove_css_class(label, "feedback-ok"); - gtk_widget_remove_css_class(label, "feedback-err"); - gtk_widget_remove_css_class(label, "feedback-warn"); - gtk_widget_add_css_class(label, ok ? "feedback-ok" : "feedback-err"); - gtk_label_set_text(GTK_LABEL(label), text); -} - -/* Yellow "almost there" note: close to a correct answer but incomplete. */ -void set_feedback_warn(GtkWidget *label, const char *text) { - gtk_widget_remove_css_class(label, "feedback-ok"); - gtk_widget_remove_css_class(label, "feedback-err"); - gtk_widget_remove_css_class(label, "feedback-warn"); - gtk_widget_add_css_class(label, "feedback-warn"); - gtk_label_set_text(GTK_LABEL(label), text); -} - -/* True if `s` contains any German special letter (ä, ö, ü or ß). */ -gboolean text_has_german_umlaut(const char *s) { - const char *p = s ? s : ""; - - while (*p) { - gunichar c = g_utf8_get_char(p); - - if (c == 0x00e4 || c == 0x00f6 || c == 0x00fc || c == 0x00df) - return TRUE; - p = g_utf8_next_char(p); - } - return FALSE; -} - -/* Small bilingual note shown under the exercise title whenever the answer - * the student has to type may contain a German special letter. */ -void add_umlaut_note(GtkWidget *body) { - GtkWidget *n = gtk_label_new(NULL); - - i18n_bind(n, "hint_umlauts", 0); - gtk_widget_set_halign(n, GTK_ALIGN_START); - gtk_label_set_wrap(GTK_LABEL(n), TRUE); - gtk_widget_set_margin_bottom(n, 2); - gtk_widget_add_css_class(n, "hint"); - gtk_box_append(GTK_BOX(body), n); -}