#include "maturita.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–10 = source topics 01–09 (Základní pojmy … ISO/OSI). */ { .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" }, }; 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; static 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); gtk_stack_set_visible_child_name(main_stack, L->unit_page); } 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 { gtk_stack_set_visible_child_name(main_stack, L->ex_page); } } 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 mauve = color_from_hex(app_theme.accent); const Rgb rail = color_from_hex(app_theme.rail); const Rgb muted = color_from_hex(app_theme.subtext); double hx, hy; 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); net_point(0.0, &hx, &hy); draw_node_halo(cr, hx, hy, NODE_SIZE * 1.05, mauve.r, mauve.g, mauve.b, 0.18); cairo_new_path(cr); net_path(cr, 0.0, t_end); cairo_set_line_width(cr, 16); 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" }; 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); } 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("subjects", "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_relayout_later(); refresh_net_completion_ui(); return page; } GtkWidget *build_net_unit_page(NetLesson *L, const char *title_key, const NetSlide *slides, guint n_slides) { GtkWidget *page; GtkWidget *scroll; GtkWidget *nav; char sub_key[64]; net_lesson_notes_ensure(L); net_notes_target = L; L->n_slides = n_slides; g_snprintf(sub_key, sizeof(sub_key), "%s_sub", title_key); 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("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", 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", 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", 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", 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: f = 1/T", { "Analogový: spojitý, nabývá libovolných hodnot.", "Digitální: diskrétní, hodnoty 0 a 1.", "Parametry signálu:", "perioda T, frekvence f = 1/T,", "amplituda A, fázový posun Φ.", NULL, }, }, { "2 / 4 • Modulace", "Základní typy modulace", "Modulace = přenos v přeloženém pásmu", { "AM – amplitudová modulace.", "FM – frekvenční modulace.", "PM – fázová modulace.", NULL, }, }, { "3 / 4 • Kombinované", "QPSK a 256-QAM", NULL, { "QPSK: 2 bity v jednom prvku (symbolu).", "256-QAM: 8 bitů v jednom prvku.", NULL, }, }, { "4 / 4 • Rychlosti", "Modulační, přenosová a šířka pásma", NULL, { "Modulační rychlost: počet změn signálu za sekundu [Baud, Bd/s].", "Přenosová rychlost: velikost přenesené informace [bit/s, bps].", "Šířka pásma: rozsah frekvencí –", "určuje maximální možnou rychlost.", NULL, }, }, }; return build_net_unit_page(&net_lessons[4], "net_unit5", 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", 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", 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", 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", 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", slides, NET10_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); gtk_editable_set_width_chars(GTK_EDITABLE(e), 15); 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(); 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, 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_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, 10); 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, 6); gtk_widget_add_css_class(head, "ex-sub"); 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, "ex-prompt"); 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 *prompt; GtkWidget *row; GtkToggleButton *first = NULL; char *qtext; qtext = g_strdup_printf("%d.) %s", i + 1, qs[i].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_widget_add_css_class(prompt, "ex-prompt"); gtk_widget_set_margin_top(prompt, 8); gtk_box_append(GTK_BOX(body), prompt); row = gtk_flow_box_new(); gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(row), GTK_SELECTION_NONE); gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(row), n_opts); gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(row), n_opts); gtk_widget_set_halign(row, GTK_ALIGN_START); gtk_box_append(GTK_BOX(body), row); for (int o = 0; o < n_opts; o++) { GtkWidget *tb = gtk_toggle_button_new_with_label(qs[i].options[o]); gtk_widget_add_css_class(tb, "pill"); gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(tb), first); if (!first) first = GTK_TOGGLE_BUTTON(tb); gtk_flow_box_append(GTK_FLOW_BOX(row), tb); ctx->toggles[i * n_opts + o] = GTK_TOGGLE_BUTTON(tb); } ctx->hints[i] = meaning_add(body, hints[i]); } btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_set_margin_top(btns, 12); gtk_box_append(GTK_BOX(body), btns); 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_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)); }