From f111f23b5c287b0ab09adbe4fe6094aeb36113e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hozda?= Date: Thu, 30 Apr 2020 14:07:40 +0200 Subject: [PATCH 01/49] korektura pt.1 --- kap-generatory.tex | 22 +++++----- kap-markup.tex | 22 +++++----- kap-modelova-implementace.tex | 70 ++++++++++++++++---------------- kap-paradigmata.tex | 6 +-- kap-taxonomie-pozadavku.tex | 8 ++-- kap-vyhodnoceni-implementace.tex | 2 +- poznamky | 5 +++ 7 files changed, 70 insertions(+), 65 deletions(-) create mode 100644 poznamky diff --git a/kap-generatory.tex b/kap-generatory.tex index c10e2c6..6bab955 100644 --- a/kap-generatory.tex +++ b/kap-generatory.tex @@ -6,11 +6,11 @@ Dynamické stránky jsou generovány speciálně pro každého uživatele na zá \section{Výhody statických webových stránek}\label{kap:vyhody-statickych-webovych-stranek} -Pro sdílení statického obsahu mezi různé uživatele stačí velmi jednoduchý HTTP server bez jakýchkoliv dalších modulů typu \textit{PHP}, \textit{Python} a dalších systémů, které by obsah dynamicky generovaly například z dat vytažených z databáze, nebo z uživatelského vstupu. Na straně serveru tedy nedochází ke zpracování obsahu těsně před jeho odesláním uživateli, čímž se v komunikaci mezi klientem a serverem se drasticky snižuje \uv{Time To First Byte}\footnote{Time To First Byte --- čas mezi odesláním požadavku a přijmutím prvního bajtu dat.} a tím dochází ke snížení celkové latence. \citep{mozttfb} +Pro sdílení statického obsahu mezi různé uživatele stačí velmi jednoduchý HTTP server bez jakýchkoliv dalších modulů typu \textit{PHP}, \textit{Python} a dalších systémů, které by obsah dynamicky generovaly například z dat vytažených z databáze, nebo z uživatelského vstupu. Na straně serveru tedy nedochází ke zpracování obsahu těsně před jeho odesláním uživateli, čímž se v komunikaci mezi klientem a serverem drasticky snižuje \uv{Time To First Byte}\footnote{Time To First Byte --- čas mezi odesláním požadavku a přijmutím prvního bajtu dat.} a tím dochází ke snížení celkové latence. \citep{mozttfb} -Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z tohoto výzkumu se autoři rozhodli v následujících měsících od vydání analýzy zainvestovat více času do úprav všech aspektů jejich nové stránky FT.com s cílem jejího zrychlení.\todo{Nechat opravit překlad} +Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že z pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z tohoto výzkumu se autoři rozhodli v měsících po vydání analýzy investovat více času do úprav všech aspektů jejich nové stránky FT.com s cílem jejího zrychlení.\todo{Nechat opravit překlad} -Eliminováním dynamického obsahu se také předchází nevyžádaným vstupům od uživatele, které mohou být i cílené na prolomení bezpečnostních nedostatků webové aplikace a v některých případech mohou vést k úniku citlivých dat, převzetí kontroly útočníka nad webovou aplikací nebo celým serverem, podstrčení falešných dat uživateli a mnoho dalším běžně se stávajícím útokům. Statický web eliminuje tento problém, jelikož nemá žádný uživatelský vstup. +Eliminováním dynamického obsahu se také předchází nevyžádaným vstupům od uživatele, které mohou být i cílené na prolomení bezpečnostních nedostatků webové aplikace a v některých případech mohou vést k úniku citlivých dat, převzetí kontroly útočníka nad webovou aplikací nebo celým serverem, podstrčení falešných dat uživateli a mnoha dalším běžným útokům. Statický web eliminuje tento problém, jelikož nemá žádný uživatelský vstup. Sledování a analýze nejčastějších chyb webových aplikací a serverů se věnuje organizace OWASP\footnote{The Open Web Application Security Project --- \url{https://owasp.org/}.}, která vydává aktualizované seznamy a statistiky. Podle OWASP byly v roce 2017 nejčastější tyto chyby a bezpečnostní nedostatky: @@ -22,25 +22,25 @@ Sledování a analýze nejčastějších chyb webových aplikací a serverů se \item{Nefunkční řízení přístupu} \item{Špatná konfigurace zabezpečení} \item{Cross-Site Scripting (XSS)} - \item{Nezabezpečná deserializace} - \item{Uživání komponent se známými zranitelnostmi} + \item{Nezabezpečená deserializace} + \item{Užívání komponent se známými zranitelnostmi} \item{Nedostatečné logování a monitorování} \end{enumerate} \citep{owasp2017} -Většina těchto chyb se vztahuje právě k dynamickým webovým aplikacím. Bezpečnost tedy závisí nejen na programátorovi který aplikaci vytváří, ale také na tom, že programovací jazyk je bezpečně implementován. To nelze tvrdit o nejpoužívanějším jazyce PHP, který nejen že obsahuje spousty chyb, viz seznam nalezených bezpečnostních děr \citep{cve_php}, ale zároveň nevede programátora ke psaní bezpečného kódu a ve výsledku vzniká nebezpečná aplikace, pokud si autor nedá pozor na správné ošetření vstupů a další bezpečnostní aspekty programu. +Většina těchto chyb se vztahuje právě k dynamickým webovým aplikacím. Bezpečnost tedy závisí nejen na programátorovi který aplikaci vytváří, ale také na tom, že programovací jazyk je bezpečně implementován. To nelze tvrdit o nejpoužívanějším jazyce PHP, který nejen že obsahuje mnoho chyb, viz seznam nalezených bezpečnostních děr \citep{cve_php}, ale zároveň nevede programátora k psaní bezpečného kódu, což má za následek nebezpečené aplikace, pokud si autor nedá pozor na správné ošetření vstupů a dalších bezpečnostních aspektů programu. -Skvělým příkladem chybovosti dynamických webů je systém Wordpress, ve kterém jsou každý rok nalezeny desítky bezpečnostních chyb \citep{cve_wordpress}, přičemž mnoho dalších přibývá s instalací špatně napsaných rozšíření. Například na začátku roku 2020 byla nalezena bezpečnostní chyba v rozšíření, které bylo využíváno na více než dvě stě tisících webových stránkách a potencionálním útočníkům umožnila smazat obsah databáze \citep{thehackernews_wordpress_1}. Na konci roku 2019 umožnila chyba ve dvou nezabezpečených rozšířeních neautorizované přihlášení k účtu administrátora bez použití hesla \citep{thehackernews_wordpress_2}. +Podstatným příkladem chybovosti dynamických webů je systém Wordpress, ve kterém jsou každý rok nalezeny desítky bezpečnostních chyb \citep{cve_wordpress}, přičemž mnoho dalších přibývá s instalací rozšíření, která postrádají bezpečnostní prvky. Například na začátku roku 2020 byla nalezena bezpečnostní chyba v rozšíření, které bylo využíváno na více než dvě stě tisících webových stránkách a potencionálním útočníkům umožňovala smazat obsah databáze \citep{thehackernews_wordpress_1}. Na konci roku 2019 umožnila chyba ve dvou nezabezpečených rozšířeních neautorizované přihlášení k účtu administrátora bez použití hesla \citep{thehackernews_wordpress_2}. -Údržba velkých webových aplikací je také často problematická. Kód je nutné udržovat v návaznosti na aktualizace daného jazyka, databázového systému a dalších věcí. Těmto aktualizacím se z bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s databázemi a různými frameworky\todo{Lepši slovo?} a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. +Údržba velkých webových aplikací je často problematická. Kód je nutné udržovat v návaznosti na aktualizace daného jazyka, databázového systému a dalších aspektů. Těmto aktualizacím se z bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s databázemi a různými frameworky\todo{Lepši slovo?} a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. -Jako každý jiný systém, i statické generátory mají své nevýhody. Hlavním z problémů je to, že správa statického generátoru a tvorba obsahu je náročnější, než klasické webové rozhraní s administračním panelem, různými uživateli a jednoduchou správou pro běžné technicky nenadané uživatele. Pro přidání nebo úpravu obsahu je nutné pracovat s lokálními soubory ve stromové struktuře a při generování je často potřebný zásah do shellu\footnote{Program pro interpretování příkazů v prostředí příkazové řádky.}. Tvorba systému pro automatizované generování je také náročnější než instalace některého z běžných CMS\footnote{Content Management System}. \citep{softpedia_generators} +Jako každý jiný systém, i statické generátory mají své nevýhody. Hlavním z problémů je to, že správa statického generátoru a tvorba obsahu je náročnější, než klasické webové rozhraní s administračním panelem, různými uživateli a jednoduchou správou pro běžné, méně technicky zaměřené uživatele. Pro přidání nebo úpravu obsahu je nutné pracovat s lokálními soubory ve stromové struktuře a při generování je často potřebný zásah do shellu\footnote{Program pro interpretování příkazů v prostředí příkazové řádky.}. Tvorba systému pro automatizované generování je také náročnější než instalace některého z běžných CMS\footnote{Content Management System}. \citep{softpedia_generators} \section{Princip generátorů}\label{kap:princip-generatoru} -Generátor statického obsahu je tvořen ze tří hlavních částí. První částí jsou soubory šablon, které popisují rozložení stránky, vizuální vlastnosti, typografii, ale také vstupní a výstupní kódování a formáty. V podstatě definují jak a kam se bude obsah vkládat. Druhou částí je obsah obecně psaný v některém ze značkovacích jazyků, nejčastěji v jazyce Markdown. Obsah je strukturován do vlastních sekcí a souborů, aby bylo snadné rozlišit, do které části výsledné stránky patří. Třetí a poslední částí je samotné jádro generátoru, které zpracovává obsah, vkládá ho do šablon a renderuje statickou webovou stránku. +Ekosystém generátoru statického obsahu je tvořen ze tří hlavních složek. První částí jsou soubory šablon, které popisují rozložení stránky, vizuální vlastnosti, typografii, ale také vstupní a výstupní kódování a formáty. V podstatě definují jak a kam se bude obsah vkládat. Druhou částí je obsah samotný, napsaný v některém ze značkovacích jazyků, nejčastěji v jazyce Markdown. Obsah bývá strukturován do sekcí a souborů, aby bylo snadné rozlišit, do které části výsledné stránky patří. Třetí a poslední složkou je samotné jádro generátoru, které zpracovává obsah, vkládá ho do šablon a renderuje statickou webovou stránku. -Většina generátorů zároveň umí pracovat s konfiguračními soubory, kterými jde nastavit chování generátoru na jednom centralizovaném místě. Část z nich má také integrovaný jednoduchý web server, který umožňuje autorovi náhled výstupních stránek během tvorby obsahu. +Většina generátorů zároveň umí pracovat s konfiguračními soubory, kterými jde nastavit globální chování generátoru. Část z nich také integruje jednoduchý webserver, který umožňuje autorovi náhled výstupních stránek zatím co tvoří obsah. \citep{softpedia_generators} diff --git a/kap-markup.tex b/kap-markup.tex index d6117f3..6469f6c 100644 --- a/kap-markup.tex +++ b/kap-markup.tex @@ -2,37 +2,37 @@ \section{Principy značkovacích jazyků} -Vysvětlení principu značkovacích jazyků, nebo také takzvaně \uv{makrup jazyků}, můžeme najít například v RFC 7764\footnote{Jako \textit{RFC} se označují standardy vydané organizací IETF (Internet Engineering Task Force).}, tedy že v počítačových systémech jsou kontextuální data ukládána a zpracována několika technikami. Informaci lze kódovat jako čistý text bez speciálních formátovacích znaků. Tento přístup je jednoduchý pro implementaci i použití, ovšem neumožňuje složitější formátování textu. +Definici konceptu značkovacích jazyků, nebo-li \uv{markup jazyků}, můžeme najít například v RFC 7764\footnote{Jako \textit{RFC} se označují standardy vydané organizací IETF (Internet Engineering Task Force).}, tedy že v počítačových systémech jsou kontextuální data ukládána a zpracována několika technikami. Informaci lze kódovat jako čistý text bez speciálních formátovacích znaků. Tento přístup je jednoduchý pro implementaci i použití, ovšem neumožňuje složitější formátování textu. -Kódovat lze můžeme i do binárních dat určených ke zpracování a interpretaci specializovaným programem. Zřejmou nevýhodou je to, že zdroj není čitelný bez programu určeného pro jeho interpretaci. +Kódovat můžeme i do binárních formátů určených ke zpracování a interpretaci specializovaným programem. Zřejmou nevýhodou je to, že zdroj není čitelný bez programu určeného pro jeho interpretaci. -Markup jazyky se snaží o spojení toho nejlepšího z obou světů, tedy o obsah čitelný v čistém textu s možností formátování. To je dosaženo tím, že běžným znakům jsou přiděleny speciální významy nedefinované původní znakovou sadou. Uživatel je schopen tyto znaky psát jako čistý text a vyjádřit tím speciální význam. Například v rámci jazyka Markdown se znak \texttt{\#} změní z běžného křížku na definování nadpisu první úrovně, nebo také kombinace znaků \texttt{

} značí začátek odstavce v HTML. \citep{rfc7764} +Markup jazyky se snaží o spojení nejlepšího z obou světů, tedy o obsah s možností formátování, který je jednoduše čitelný jak pro člověka, tak pro stroj. Toho je dosaženo tím, že v je v běžných textových souborech přiřezen vybraným znakům speciální význam. Uživatel je schopen tyto znaky psát bez potřeby speciálních nástrojů a tím jednoduše vyjádřit speciální význam. Například v rámci jazyka Markdown se znak \texttt{\#} změní z běžného křížku na definování nadpisu první úrovně, nebo také kombinace znaků \texttt{

} značí začátek odstavce v HTML. \citep{rfc7764} \section{Nejběžnější jazyky} -Ke dnešnímu dni vnikl nespočet značkovacích jazyků. Nejpoužívanějším z nich jednoznačně HTML, ovšem tato práce se věnuje těm nejpoužívanějším jazykům, které mají uživateli usnadnit psaní a sázení obsahu. Uživatel tedy nemusí nutně řešit typografii a formátování obsahu při jeho psaní, tedy o věci, o které se později stará generátor pomocí šablon. U HTML je tomu naopak, kdy uživatel řeší samotný obsah i formátování v jednu chvíli skrze různé druhy formátovacích tagů. O vyplňování obsahu do HTML se v případě staticky generovaných webů stará právě samotný generátor. +V současnosti existuje nespočet značkovacích jazyků. Nejpoužívanějším z nich je jednoznačně HTML, ovšem tato práce se věnuje těm nejpoužívanějším jazykům, které mají uživateli usnadnit psaní a sázení obsahu. Uživatel se tedy nemusí při tvorbě nutně zabývat typografií a formátováním obsahu, což jsou aspekty, o které se později postará generátor pomocí šablon. U HTML je tomu naopak, uživatel řeší samotný obsah i formátování v jednu chvíli skrze různé druhy formátovacích tagů. O vyplňování obsahu do HTML se v případě staticky generovaných webů stará právě samotný generátor. -Vybrané jazyky jsou zároveň cílené na čitelnost samotného zdrojového obsahu v čistém textu bez nutnosti jeho interpretace speciálním prostředím či zpracováním do jiného formátu, například do PDF, DjVu, PostScript apod. Například podtržení textu je v nějakém pseudo-jazyce reprezentováno opravdovým podtržením pomocí spojovníků, nikoliv obalením nadpisu ve speciální deklaraci, jako je tomu například u HTML. Podtržení je poté pro čtenáře mnohem jasnější, jelikož nemusí přemýšlet, co v případě HTML daný tag vůbec způsobuje, ale podtržený vyplývá z kontextu. +Vybrané jazyky jsou zároveň cílené na čitelnost samotného zdrojového obsahu v čistém textu bez nutnosti jeho interpretace speciálním prostředím či zpracováním do jiného formátu, například do PDF, DjVu, PostScript apod. Například podtržení textu je v nějakém pseudo-jazyce reprezentováno opravdovým podtržením pomocí spojovníků, nikoliv obalením nadpisu ve speciální deklaraci, jako je tomu například u HTML. Podtržení je poté pro čtenáře mnohem jasnější, jelikož nemusí přemýšlet, co v kontextu HTML daný tag znamená, kdežto podtržení vyplývá z kontextu. Seznam nejoblíbenějších jazyků je sestaven podle aktuálních statistik ze serveru Slant, který se věnuje obecnému určení oblíbenosti na základě hodnocení ze strany uživatelů. \citep{slant} \subsection{Markdown}\label{kap:markdown} -Vznik jazyka Markdown byl 14. prosince roku 2014, když John Gruber vydal jeho první popis syntaxe a referenční implementaci. +Jazyka Markdown vznikl 19. března roku 2004, když John Gruber vydal první popis syntaxe a referenční implementaci. Hlavním z cílů syntaxe jazyka je vytvářet co možná nejčitelnější obsah v syrové podobě. Dokument psaný v Markdownu by měl být publikovatelný sám o sobě jako čistý text bez dalších úprav a zpracování. Jazyk byl ovlivněn několika již existujícími specifikacemi jiných jazyků, ovšem největším zdrojem inspirace pro jeho vznik jsou čisté emailové korespondence. \citep{daringfireball} -První specifikaci Gruber vydal společně s referenční implementací v jazyce Perl, která slouží pro konverzi Markdownu do HTML. Tento program je také pojmenován jako \uv{Markdown}, ovšem mluvíme-li o \uv{Markdownu}, máme nejčastěji na mysli samotnou syntaxi. Ta je dnes již implementována v mnoha různých jazycích a programech. Gruberova specifikace ovšem není formální standard, kvůli čemuž vznikl veliký počet alternativních a více čí méně pozměněných implementací, které nemusí být navzájem kompatibilní. Nejčastějšími z nich jsou například Github Markdown, CommonMark, R Markdown a mnoho dalších. \citep{commonmark} +První specifikaci Gruber vydal společně s referenční implementací v jazyce Perl, která prováděla konverzi Markdownu do HTML. Tento program je také pojmenován \uv{Markdown}, ovšem mluvíme-li o \uv{Markdownu}, máme nejčastěji na mysli samotnou syntaxi. Ta má dnes mnoho implementací v různých programovacích jazycích. Gruberova specifikace ovšem není formální standard, kvůli čemuž vznikl veliký počet alternativních a více či méně pozměněných implementací, které nemusí být navzájem kompatibilní. Nejčastějšími z nich jsou například Github Markdown, CommonMark, R Markdown a mnoho dalších. \citep{commonmark} Nevyužívanější formální specifikací je právě CommonMark\footnote{\url{https://commonmark.org/}}, který slouží jako pevný základ většiny rozšíření. \citep{github_formal_markdown_spec}. -Podobně jako je tomu u specifikací, existuje velké množství programů, které tyto různé specifikace překládají. Švýcarským nožem mezi nimi je program Pandoc\footnote{\url{https://pandoc.org/}}, který umí překládat Markdown do enormního výběru jiných formátů, nebo z jiných formátů zpět. Tato funkcionalita se nezvtahuje pouze na jazyk Markdown, ovšem Pandoc dokáže operovat mezi všemy podporovanými formáty, například dokáže konvertovat obsah z HTML do \TeX{}u. Na druhou stranu existují i velmi jednoduché překladače, například program smu\footnote{\url{https://github.com/Gottox/smu}}, který umí překládat Markdown do HTML nebo čistého textu a neobsahuje více než 600 SLOC\footnote{Source lines of code}, tedy řádků kódu hlavního programu. +Podobně jako je tomu u specifikací, existuje velké množství programů, které tyto různé specifikace překládají. Švýcarským nožem mezi nimi je program Pandoc\footnote{\url{https://pandoc.org/}}, který umí překládat Markdown do enormního výběru jiných formátů, nebo z jiných formátů zpět. Tato funkcionalita se nevztahuje pouze na jazyk Markdown, Pandoc dokáže operovat mezi všemi podporovanými formáty, například dokáže konvertovat obsah z HTML do \TeX{}u. Na druhou stranu existují i velmi jednoduché překladače, například program smu\footnote{\url{https://github.com/Gottox/smu}}, který umí překládat Markdown do HTML nebo čistého textu a neobsahuje více než 600 SLOC\footnote{Source lines of code}, tedy řádků kódu hlavního programu. \subsection{Org-mode} -Org-mode vznikl jako jeden z módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s možností přidání libovolného nového backendu\todo{České slovo?}. Cílem Org-mode je možnost ho používat i s minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor emacs je zároveň velmi často protován na různé druhy stsémů a je tedy možné ho využívat v podstatě kdekoliv. \citep{orgmanual} +Org-mode vznikl jako jeden z módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s možností přidání libovolného nového backendu\todo{České slovo?}. Cílem Org-mode je možnost ho používat i s minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor Emacs je zároveň velmi často portován na různé druhy systémů a je tedy možné ho využívat v podstatě kdekoliv. \citep{orgmanual} -Podporuje také \uv{literate programming} a \uv{reproducible research}, tedy že Org soubory mohou obsahovat plně funkční bloky s kódem, které lze evaluovat v rámci systému a výstup bloků lze automaticky vkládat přímo do dokumentu. \citep{environment_for_literate_programming} +Podporuje také \uv{literate programming} a \uv{reproducible research}, tedy že Org soubory mohou obsahovat plně funkční bloky s kódem, které lze hodnotit v rámci systému a výstup bloků lze automaticky vkládat přímo do dokumentu. \citep{environment_for_literate_programming} Jak popisuje Carsten Dominik ve svém krátkém technickém popisu, Org-mode umí navrhování, psaní poznámek, hypertextové odkazy, tabulky, seznamy, plánování projektů, GTD, HTML a \LaTeX{}, a to všechno v čistých textových souborech v editoru Emacs. \citep{carsten_dominik} @@ -51,7 +51,7 @@ Tento jazyk se již vzdaluje od původního konceptu čitelnosti zdroje, ovšem Většina uživatelů se setkala spíše s jazykem \LaTeX, tedy s nadstavbou původního \TeX{}u, která má uživateli zjednodušit práci svými makry a rozšířeními. Realita je ovšem taková, že \LaTeX{} dělá celou práci složitější, jak popisuje doktor Olšák: \begin{quote} -Představte si, že si nějaký uživatel přečte \LaTeX{}ovou příručku a nabyde dojmu, že mu bude stačit rozumět problematice sazby na úrovni této příručky. Pak se jednou překlepne třeba při sestavování tabulky a na terminálu na něj \TeX{} křičí: {\tt Extra alignment tab has been changed to "\verb|\cr|".} Uživatel začne znovu listovat ve své příručce a zjistí, že tam o~žádném "\verb|\cr|" není jediná zmínka. Má pak tři možnosti: (1)~Zmáčkne Enter a podobně se zachová i u~dalších chyb. Pomyslí si, že ten \LaTeX{} je něco tajemného a mystického. (2)~Propadne zoufalství a jde od toho. Dojde k~závěru, ľe je lepší zůstat u~Wordu. Vždyť stačí vzít tabulku v~Excelu a jednoduše ji přemístit do Wordu a jaképak smolení se s~nějakým podezřelým "\verb|\cr|". (3)~Pořídí si \TeX{}book a po intenzivním studiu nakonec řekne: \uv{aha}. V~tuto chvíli ale už nepotřebuje, aby mu \LaTeX{} zakrýval složitost \TeX{}u. +Představte si, že si nějaký uživatel přečte \LaTeX{}ovou příručku a nabude dojmu, že mu bude stačit rozumět problematice sazby na úrovni této příručky. Pak se jednou překlepne třeba při sestavování tabulky a na terminálu na něj \TeX{} křičí: {\tt Extra alignment tab has been changed to "\verb|\cr|".} Uživatel začne znovu listovat ve své příručce a zjistí, že tam o~žádném "\verb|\cr|" není jediná zmínka. Má pak tři možnosti: (1)~Zmáčkne Enter a podobně se zachová i u~dalších chyb. Pomyslí si, že ten \LaTeX{} je něco tajemného a mystického. (2)~Propadne zoufalství a jde od toho. Dojde k~závěru, ľe je lepší zůstat u~Wordu. Vždyť stačí vzít tabulku v~Excelu a jednoduše ji přemístit do Wordu a jaképak smolení se s~nějakým podezřelým "\verb|\cr|". (3)~Pořídí si \TeX{}book a po intenzivním studiu nakonec řekne: \uv{aha}. V~tuto chvíli ale už nepotřebuje, aby mu \LaTeX{} zakrýval složitost \TeX{}u. \end{quote} \citep{nolatex} Ve výsledku je tedy lepší, z různých důvodů popsaných doktorem Olšákem v jeho publikaci, použít samotný plain \TeX{} na úkor vyšší vstupní úrovně pro použivání jazyka. diff --git a/kap-modelova-implementace.tex b/kap-modelova-implementace.tex index 5e7d899..20deeb2 100644 --- a/kap-modelova-implementace.tex +++ b/kap-modelova-implementace.tex @@ -8,21 +8,21 @@ Modelový web se skládá ze dvou částí, a to z verzovacího systému pro spr \subsection{Verzovací systém pro správu obsahu}\label{kap:vyber-vhodneho-systemu-verzovani} -Pro správu obsahu i šablon a statických souborů byl zvolen distribuovaný verzovací systém Git, který má v porovnání s jinými verzovacími systémy spousty výhod. Hlavní jeho výhodou je rozšířené využití v praxi a snadné používání. Díky svým decentralizovaným vlastnostem ho lze využívat v mnoha odlišných pracovních postupech. S naklonovaným repozitářem lze pracovat i bez připojení k síti, což lze považovat i za druh zálohy. Git také umožňuje slučování různých změn od mnoha uživatelů a dovoluje jednoduše řešit potenciální konflikty. \citep{why_is_git_better_than_x} +Pro správu obsahu i šablon a statických souborů byl zvolen distribuovaný verzovací systém Git, který má v porovnání s jinými verzovacími systémy, zejména centralizovanými, spousty výhod. Hlavní jeho výhodou je rozšířené využití v praxi a snadné používání. Díky svým decentralizovaným vlastnostem ho lze využívat v mnoha odlišných pracovních postupech. S naklonovaným repozitářem lze pracovat i bez připojení k síti, což lze považovat i za druh zálohy. Git také umožňuje slučování různých změn od mnoha uživatelů a dovoluje jednoduše řešit potenciální konflikty. \citep{why_is_git_better_than_x} Skvěle využitelnou funkcí pro modelovou implementaci je také to, že po provedení změn v repozitáři lze pomocí Gitu spouštět skripty, které mohou provádět automatické generování obsahu a další užitečné operace. Tato funkcionalita je implementována v rámci modelové implementace v sekci \ref{kap:automaticke-generovani-obsahu}. \subsection{Generátor statického webu} -Protože forma modelového webu odpovídá paradigmatu webové prezentace ze sekce \ref{kap:paradigmata-webova-prezentace}, byl pro jeho generování použit program Zola\footnote{\url{https://www.getzola.org/}}, jehož výhody jsou v sekci \ref{kap:paradigmata-webova-prezentace} popsány. +Protože forma modelového webu odpovídá paradigmatu webové prezentace ze sekce \ref{kap:paradigmata-webova-prezentace}, byl pro jeho generování použit program Zola\footnote{\url{https://www.getzola.org/}}, jehož výhody jsou popsány v sekci \ref{kap:paradigmata-webova-prezentace}. \todo[inline]{Přesunout výběr a výhody generátoru sem.} \section{Tvorba šablony} -Jak se uvádí v dokumentaci\footnote{\url{https://www.getzola.org/documentation/content/overview/}}, Zola pracuje s několika druhy stránek, primárně s takzvanou \uv{sekcí} a \uv{stránkou}. Každá sekce může mít vlastní obsah, ovšem může obsahovat i další subsekce, díky čemuž lze dělit obsah do stromové struktury. Stránka slouží pouze k předání obsahu a nikoliv k dalšímu větvení struktury. Dá se tedy říci, že stránka značí konec dané větve. Kořenem celého stromu je speciální sekce s názvem \uv{index}. Každá tato část standardně využívá vlastní HTML šablonu, ovšem nejde o pravidlo a každá část větve může využívat jinou šablonu. To je užitečné například u stránek s různým druhem obsahu. V rámci modelového webu zůstává druh obsahu stejný a není tedy třeba odchylovat se od standardní struktury. +Jak se uvádí v dokumentaci\footnote{\url{https://www.getzola.org/documentation/content/overview/}}, Zola pracuje s několika druhy stránek, primárně s takzvanou \uv{sekcí} a \uv{stránkou}. Každá sekce může mít vlastní obsah, ovšem může obsahovat i další subsekce, díky čemuž lze dělit obsah do stromové struktury. Stránka slouží pouze k předání obsahu a nikoliv k dalšímu větvení struktury. Dá se tedy říci, že stránka reprezentuje list v rámci stromovité struktury. Kořenem celého stromu je speciální sekce s názvem \uv{index}. Každá tato část standardně využívá vlastní HTML šablonu, to není ovšem pravidlo a každá část větve může využívat jinou šablonu. To je užitečné například u stránek s různými druhy obsahu. V rámci modelového webu zůstává druh obsahu stejný a není tedy třeba odchylovat se od standardní struktury. -Soubory se šablonami se nachází ve složce \texttt{templates/}, ve které generátor vždy očekává šablonu \texttt{index.html}. Ta se využívá jak k vykreslení úvodní kořenové stránky, tak ji mohou ostatní šablony rozšiřovat. Tato kořenová šablona tedy obsahuje základní strukturu celé stránky, přičemž navazující šablony jen mění určité části obsahu a nedefinují celou strukturu znovu. +Soubory se šablonami se nachází ve složce \texttt{templates/}, ve které generátor vždy očekává šablonu \texttt{index.html}. Ta se využívá jak k vykreslení úvodní kořenové stránky, tak jako základ, kterou mohou ostatní šablony rozšiřovat. Tato kořenová šablona tedy obsahuje základní strukturu celé stránky, přičemž navazující šablony jen mění určité části obsahu a nedefinují celou strukturu znovu. Generátor v šablonách hledá vlastní řídící sekvence, které se popisují závorkami. Existují tři druhy kombinací, které lze použít: @@ -102,7 +102,7 @@ Název stránky zůstane stejný a v jejím těle přibude text \uv{Ahoj, světe {% endblock %} \end{lstlisting} -Šablona \texttt{section.html} se v rámci generátoru Zola implicitně využívá pro všechny existující sekce\footnote{\url{https://www.getzola.org/documentation/content/section/}}. Názvem stránky v této šabloně bude, stejně jako u hlavní šablony, název stránky z konstanty \texttt{config.title} definované v konfiguračním souboru, ale také spojovník a název dané sekce. Za pseudo-výstup lze považovat například \uv{UČITEL ONLINE -- základní a střední škola}, bude-li se uživatel nacházet v sekci pro základní a střední školy. +Šablona \texttt{section.html} se v rámci generátoru Zola implicitně využívá pro všechny existující sekce\footnote{\url{https://www.getzola.org/documentation/content/section/}}. Názvem stránky v této šabloně bude, podobně jako u hlavní šablony, název stránky z konstanty \texttt{config.title} definované v konfiguračním souboru, ale také spojovník a název dané sekce. Za modelový výstup lze považovat například \uv{UČITEL ONLINE -- základní a střední škola}, bude-li se uživatel nacházet v sekci pro základní a střední školy. V bloku s obsahem bude původní obsah \uv{Ahoj, světe!} nahrazen za řetězec \uv{Toto je obsah kategorie}. Ten ovšem nechceme definovat přímo v šabloně, nýbrž cílem generátoru je vyplňovat obsah ze zdrojových souborů v sázecím jazyce, viz. sekce \ref{kap:princip-generatoru}. Zola pro vkládání obsahu využívá stejný princip jako v ostatních případech, tedy vypsání obsahu proměnné, v tomto případě proměnné \texttt{section.content}, která obsahuje zkompilované HTML z daného Markdown souboru. Zároveň je dobrou praktikou provést vyčištění vstupu filtrem \texttt{safe}\footnote{\url{https://tera.netlify.com/docs/\#safe}}. @@ -119,16 +119,16 @@ Z principu by žádný obsah neměl být definován přímo v šabloně, nýbrž \section{Automatické generování vícevrstvé navigace} -Obsah modelové implementace je dělen do stromové datové struktury o potenciálně nekonečné hloubce, kdy každá část větve je v rámci generátoru vlastní kategorií, nikoliv stránkou. Pro modelovou implementaci bylo zvoleno, aby navigace byla generována v návaznosti na aktivní cestu ve stromě. Ve stránce jsou dvě různé navigace, jedna hlavní a vždy vidiětelná, která obsahuje rozdělení obsahu dle škol a druhá navigace, která zobrazuje aktivní větev stromu. +Obsah modelové implementace je dělen do stromové datové struktury o potenciálně nekonečné hloubce, kdy každá část větve je v rámci generátoru vlastní kategorií, nikoliv stránkou. Pro modelovou implementaci bylo zvoleno, aby navigace byla generována v návaznosti na aktivní cestu ve stromě. Ve stránce jsou dvě různé navigace, hlavní, která je vždy viditelná a obsahuje rozdělení obsahu dle škol a vedlejší, která zobrazuje aktivní větev stromu. \begin{figure}[h]\centering \includegraphics{img/generovani-vicevrstve-navigace} \caption{Diagram průběhu generování vícevrstvé navigace} \end{figure} -První vrstvou struktury jsou hlavní sekce, v rámci implementace pojemnované jako $L_1$, které jsou vypsány vždy ve vlastní navigaci. Pod touto navigací je zobrazen seznam všech kategorií, které vybraná položka v $L_1$ obsahuje. Pokud uživatel zvolí kteroukoliv položku v $L_2$, v navigaci se objeví další sloupec, který obsahuje všechny podkategorie vybrané položky, tedy všechny podkategorie ve vrstvě $L_3$. Takto lze stromem procházet potenciálně do nekonečna. Styly modelové šablony ovšem počítají s maximální hloubkou čtyř subkategorií. +První vrstvou struktury jsou hlavní sekce, v rámci implementace pojmenované jako $L_1$, které jsou vypsány vždy ve vlastní navigaci. Pod touto navigací je zobrazen seznam všech kategorií, které vybraná položka v $L_1$ obsahuje. Pokud uživatel zvolí kteroukoliv položku v $L_2$, v navigaci se objeví další sloupec, který obsahuje všechny podkategorie vybrané položky, tedy všechny podkategorie ve vrstvě $L_3$. Takto lze stromem procházet potenciálně do nekonečna. Styly modelové šablony ovšem počítají s maximální hloubkou čtyř subkategorií. -Tato funkcionalita je implementována pomocí tří cyklů, z níchž jeden je vložený. První cyklus (příklad \ref{lst:obsah-cyklus1}) se provádí pro všechny rodiče aktivní ktegorie vrstev $L_2,L_3,\dotsc,L_n$, kde $n$ je aktuílní vrstva. V každé iteraci se mění kontext, ve kterém generátor pracuje. Z daného kontextu generátor vypisuje pomocí vnořeného cyklem všechny subkategorie. Ve druhém cyklu (příklad \ref{lst:obsah-cyklus2}) se vypisují všichni potomci dané stránky, tedy potomci ve vrstvě $L_{n+1}$. +Tato funkcionalita je implementována pomocí tří cyklů, z nichž jeden je vložený. První cyklus (příklad \ref{lst:obsah-cyklus1}) se provádí pro všechny rodiče aktivní kategorie vrstev $L_2,L_3,\dotsc,L_n$, kde $n$ je aktuální vrstva. V každé iteraci se mění kontext, ve kterém generátor pracuje. Z daného kontextu generátor vypisuje pomocí vnořeného cyklem všechny subkategorie. Ve druhém cyklu (příklad \ref{lst:obsah-cyklus2}) se vypisují všichni potomci dané stránky, tedy potomci ve vrstvě $L_{n+1}$. \begin{lstlisting}[label=lst:obsah-cyklus1,caption=Cyklus pro vypisování všech rodičů v dané větvi navigace] {% if section.ancestors %} @@ -164,23 +164,23 @@ Tato funkcionalita je implementována pomocí tří cyklů, z níchž jeden je v \section{Rozšíření šablony} -Ve výchozím stavu generátor neumí vkládat nic jiného, než je uvedeno ve specifikaci CommonMark, viz. sekce \ref{kap:markdown}. Dle požadavků modelového webu je nutné, aby generátor uměl vkládat videa přímo do stránky. Taková funkcionalita není soušástí specifikace CommonMark a je tedy potřeba rozšířit generátor. Nejvhodnějším způsobem přidání vlastních funkcionalit je využití filtrů, které se v rámci generátoru nazývají \uv{shortcode}. +Ve výchozím stavu generátor neumí zpracovávat nic jiného, než co je uvedeno ve specifikaci CommonMark, viz. sekce \ref{kap:markdown}. Dle požadavků modelového webu je nutné, aby generátor uměl vkládat videa přímo do stránky. Taková funkcionalita není součástí specifikace CommonMark a je tedy potřeba rozšířit generátor. Nejvhodnějším způsobem přidání vlastních funkcionalit je využití filtrů, které se v rámci generátoru nazývají \uv{shortcode}. -Principem vlastních filtrů je to, že si uživatel vytvoří vlastní šablonu, kterou lze vyvolat speciální řídící sekvencí přímo z obsahu. Každý tento shortcode může pracovat s libovolným množstvím proměnných a po zpracování vloží do místa vyvolání zkompilovaný HTML kód. Lze tedy tvrdit, že shortcode je v své podstatě imperativní funkce, která umí pracovat s parametry. +Principem vlastních filtrů je to, že si uživatel vytvoří vlastní šablonu, kterou lze vyvolat pomocí speciální řídící sekvence přímo z obsahu. Každý tento shortcode může pracovat s libovolným množstvím proměnných a po zpracování vloží do místa vyvolání zkompilovaný HTML kód. Dá se tedy říci, že shortcode je v své podstatě funkce, která umí pracovat s parametry. -Pro tvorbu těchto filtrů je v generátoru Zola určena složka \texttt{templates/shortcodes}, která obsahuje jejich HTML šablony a kód pro zpracování generátorem. Název HTML souboru definuje název vlastního filtru. Vytvoříme-li uvitř této složky soubor nazvaný \texttt{video.html}, budeme v obsahu schopni využívat vlastní filtr s názvem \texttt{video}. +Pro tvorbu těchto filtrů je v generátoru Zola určena složka \texttt{templates/shortcodes}, která obsahuje jejich HTML šablony a kód pro zpracování generátorem. Název HTML souboru definuje název vlastního filtru. Vytvoříme-li uvnitř této složky soubor nazvaný \texttt{video.html}, budeme v obsahu schopni využívat vlastní filtr s názvem \texttt{video}. \begin{lstlisting}[label=lst:jednoduchy-filtr,caption=Příklad jednoduchého filtru s jedním atributem] \end{lstlisting} -V příkladu \ref{lst:jednoduchy-filtr} bude filtr očekávat atribut \texttt{src} a bude vracet jednoduchý HTML kód pro vložení videa do stránky. Tento filtr lze vyvolat kdekoliv v obsahu, tedy v kterémkoliv souboru s koncovkou \texttt{.md}. Za názvem filtru se do závorky uvádí parametry oddělené čárkou. U posledního parametru se čárky nevuvádí, což platí i v případě, kdy se uvádí pouze jeden parametr, jako je tomu v příkladu \ref{lst:vyvolani-filtru}. +V příkladu \ref{lst:jednoduchy-filtr} bude filtr očekávat atribut \texttt{src} a bude vracet jednoduchý HTML kód pro vložení videa do stránky. Tento filtr lze vyvolat kdekoliv v obsahu, tedy v kterémkoliv souboru s koncovkou \texttt{.md}. Za názvem filtru se do závorky uvádí parametry oddělené čárkou. U posledního parametru se čárky neuvádí, což platí i v případě, kdy se uvádí pouze jeden parametr, jako je tomu v příkladu \ref{lst:vyvolani-filtru}. \begin{lstlisting}[label=lst:vyvolani-filtru,caption=Vyvolání vlastního filtru s jedním parametrem] {{ video(src="video.webm") }} \end{lstlisting} -V rámci vybraného generátoru není nutné specifikovat atributy na jeden řádek a lze je pro přehlednost vypisovat na více řádků, jako tomu je například u programu \ref{lst:formatovani-atributu}, zůstane-li dodržena koncepce oddělení atributů čárkou, tedy že poslední atribut vždy zůstane bez čárky. Výstupem této direktivy bude následující HTML kód. +V rámci vybraného generátoru není nutné specifikovat atributy na jeden řádek a lze je pro přehlednost vypisovat na více řádků, jako tomu je například u programu \ref{lst:formatovani-atributu}, zůstane-li dodržen způsob oddělování atributů čárkou, tedy že poslední atribut vždy zůstane bez čárky. Výstupem této direktivy bude následující HTML kód. \begin{lstlisting}[caption=Výstup direktivy z příkladu \ref{lst:jednoduchy-filtr}] @@ -200,7 +200,7 @@ Součástí požadavků pro modelový web jsou i citace přiložených souborů {% endif %} \end{lstlisting} -Filtr je možné opět vyvolat pomocí stejné direktivy kdekoliv v obsahu, ovšem nyní lze libovolně přidat parametry pro metadata. +Filtr je opět možné vyvolat pomocí stejné direktivy kdekoliv v obsahu, ovšem nyní lze libovolně přidávat parametry pro metadata. \begin{lstlisting}[label=lst:formatovani-atributu,caption=Vyvolání filtru \ref{lst:filtr-s-podminkami} s formátováním na řádky] {{ video( @@ -211,16 +211,16 @@ Filtr je možné opět vyvolat pomocí stejné direktivy kdekoliv v obsahu, ovš ) }} \end{lstlisting} -Protože byly zadány všechny povinné i nepovinné atributy, výtupem toho filtru budou i části kódu s metadaty. +Protože byly zadány všechny povinné i nepovinné atributy, výstupem toho filtru budou i části kódu s metadaty. \begin{lstlisting}[caption=Výstup direktivy z příkladu \ref{lst:formatovani-atributu}] - +

Název videa (2020, Jméno autora)
\end{lstlisting} - Pro modelový web byla zvážena možnost vypisování obsahu automaticky, tedy že program zkontroluje složku s obsahem a pokud narazí na soubor se specifikovanou koncovkou, vypíše jej do obsahu podle daných pravidel. Generátor Zola umožňuje prohledávání složek a práci se soubory, v rámci Zoly takzvanými \uv{assety}. Tuto funkcionalitu lze tedy implementovat jednoduchým cyklem a filtem, které zpracují všechny případné soubory ve složce dané stránky. Zoubory lze filtrovat mnoha způsoby, z nichž je nejuniverzálnější funkce \texttt{matching()}, která dovoluje filtrovat vstup regulárními výrazy dle implementace regex v jazyce Rust\footnote{\url{https://docs.rs/regex/1.3.6/regex/}}. V následujícím příkladu je pro ilustraci této funkcionality implementován program vypisující obrázky s předem definovanými koncovkami. +Pro modelový web byla zvážena možnost vypisování obsahu automaticky, tedy že program projde složku s obsahem a pokud narazí na soubor se specifikovanou koncovkou, vypíše jej do obsahu podle daných pravidel. Generátor Zola umožňuje prohledávání složek a práci se soubory, pro které se v rámci Zoly používá termín \uv{assety}. Tuto funkcionalitu lze tedy implementovat jednoduchým cyklem a filtrem, které zpracují všechny případné soubory ve složce dané stránky. Soubory lze filtrovat mnoha způsoby, z nichž je nejuniverzálnější funkce \texttt{matching()}, která dovoluje filtrovat vstup regulárními výrazy dle jejich implementace v jazyce Rust\footnote{\url{https://docs.rs/regex/1.3.6/regex/}}. V následujícím příkladu je pro ilustraci této funkcionality implementován program vypisující obrázky s předem definovanými koncovkami. \begin{lstlisting}[caption=Automatický výpis obrázků s pevně definovanými koncovkami] {% if section.assets %} @@ -232,7 +232,7 @@ Protože byly zadány všechny povinné i nepovinné atributy, výtupem toho fil {% endif %} \end{lstlisting} -Toto řešení ovšem není ve výsledném modelu implemntováno, protože jedním z požadavků je možnost vkládání souborů na libovolné místo v obsahu. Na stejném principu je ovšem vytvořen filtr pro vládání souborů, který tento požadavek splňuje. Výhodou filtru je, že ho lze vyvolat kdekoliv v obsahu a není vázán na pevně dané místo v šabloně. Ten očekává alespoň jeden parametr uvádějící název souboru bez koncovky, pro dle kterého pak filtr vyhledá všechny různé formáty s tímto názvem a ty vloží do stránky. Druhým libovolným parametrem je název souboru, který se do stránky vloží místo názvu souboru. to umožňuje uivateli volně pracovat s názvy souborů v souborvé struktuře bez ovlivnění obsahu stránky. +Toto řešení ovšem není ve výsledném modelu implementováno, protože jedním z požadavků je možnost vkládání souborů na libovolné místo v obsahu. Na stejném principu je vytvořen filtr pro vkládání souborů, který tento požadavek splňuje. Výhodou filtru je, že ho lze vyvolat kdekoliv v obsahu a není vázán na pevně dané místo v šabloně. Ten očekává alespoň jeden parametr uvádějící název souboru bez koncovky, podle kterého pak filtr vyhledá všechny různé formáty s tímto názvem a ty vloží do stránky. Druhým libovolným parametrem je název souboru, který se do stránky vloží místo názvu souboru. To umožňuje uživateli volně pracovat s názvy souborů v souborové struktuře bez ovlivnění obsahu stránky. \begin{lstlisting}[label=lst:filtr-souboru,caption=Filtr pro výpis souborů s automatickým hledáním] {% if section.assets and filename %} @@ -253,9 +253,9 @@ Toto řešení ovšem není ve výsledném modelu implemntováno, protože jedn {% endif %} \end{lstlisting} -V první části filtr zkontroluje, zda byl vyplněn parametr \texttt{title} a v přípdě že ano, nastaví ho jako název souoru v obsahu. V opačném případě využije název souboru samotného. Ve druhém kroku nastává kontrola, zda se ve složce nacházejí soubory (mimo hlavní soubor \texttt{\_index.md}) a pokud ano, přes všechny soubory se iteruje kontrola, zda soubor splňuje podmínku názvu. Kontrola této podmínky je tvořena kombinací proměnných generátoru a regulárního výrazu. Každý soubor který splňuje podmínku je poté vypsán do obahu jako přímý odkaz k jeho stažení. +V první části filtr zkontroluje, zda byl vyplněn parametr \texttt{title} a v případě, že ano, nastaví ho jako název souboru v obsahu. V opačném případě využije název souboru samotného. Ve druhém kroku nastává kontrola, zda se ve složce nacházejí soubory (mimo hlavní soubor \texttt{\_index.md}) a pokud ano, tak se iterativně zkontrolují všechny soubory, zda splňují podmínku názvu. Kontrola této podmínky je tvořena kombinací proměnných generátoru a regulárního výrazu. Každý soubor, který splňuje podmínku je poté vypsán do obsahu jako přímý odkaz k jeho stažení. -Jako text v odkazu se použije koncovka souboru, která se záskává spojením několika filtrů, tedy filtru \texttt{split(pat=".")}, který rozdělí řetězec podle znaku tečka do pole a navazující filtr \texttt{last} vrátí poslední položku v poli. Tím filtr získá samotnou koncovku souboru. +Jako text v odkazu se použije koncovka souboru, která se získává spojením několika filtrů, tedy filtru \texttt{split(pat=".")}, který rozdělí řetězec podle znaku tečka do pole a navazující filtr \texttt{last} vrátí poslední položku v poli. Tím filtr získá samotnou koncovku souboru. Filtr lze vyvolat stejně, jako je tomu u filtru pro vkládání videa. Název filtru je opět definován názvem souboru \texttt{tmeplates/shortcodes/document.html} a bude jím tedy název \texttt{document()}. @@ -266,7 +266,7 @@ Filtr lze vyvolat stejně, jako je tomu u filtru pro vkládání videa. Název f ) }} \end{lstlisting} -V příkladu \ref{lst:vyvolani-filtru-souboru} je definován i nepovinný atribut \texttt{title}, který kvůli přehlednosti umožňuje nastavit název. Atribut \texttt{filename} definuje název souboru ve složce bez koncovky. Všechny soubory, které chce uživatel vypsat, musí tedy mít stejný název a musí se lišit pouze koncovkou. Jsou li ve složce soubory s názvem \texttt{pracovni-list} a koncovkami \texttt{pdf}, \texttt{odt}, \texttt{djvu} a \texttt{ps}, bute výstupem filtru následující HTML. +V příkladu \ref{lst:vyvolani-filtru-souboru} je definován i nepovinný atribut \texttt{title}, který kvůli přehlednosti umožňuje nastavit název. Atribut \texttt{filename} definuje název souboru ve složce bez koncovky. Všechny soubory, které chce uživatel vypsat, musí tedy mít stejný název a musí se lišit pouze koncovkou. Jsou li ve složce soubory s názvem \texttt{pracovni-list} a koncovkami \texttt{pdf}, \texttt{odt}, \texttt{djvu} a \texttt{ps}, bude výstupem filtru následující HTML. \begin{lstlisting}[caption=Výstup direktivy z příkladu \ref{lst:vyvolani-filtru-souboru}]
@@ -282,21 +282,21 @@ V příkladu \ref{lst:vyvolani-filtru-souboru} je definován i nepovinný atribu Optimalizace modelové implementace je provedena na základě článku ze serveru \cite{calomel_optimization}, který se věnuje sestavením užitečných rad pro optimalizaci webových stránek na serverech s omezeným připojením do sítě a pro zvýšení spokojenosti uživatelů z užívání optimalizovaného webu, jak je rozebráno v sekci \ref{kap:vyhody-statickych-webovych-stranek}. -Jak se na webu Colomel píše, provozování webserveru může být hodnotná zkušenost, ale zároveň může být i zkouškou trpělivosti. Chcete svým uživatelům předávat všechny vaše stránky a obrázky, ovšem máte jen omezenou šířku pásma, pomocí které můžete data přenášet. Pokud přetížíte své pipojení, klienti nevštěvující váš web server si budou myslet, že je pomalý a neresponzivní. Je tedy třeba webový server nastavit tím nejlepším možným způsobem s cílem získat co nejvíce návštěv a zlepšit zážitek vašim návštěvníkům. Následující rady slouží ke snížení zátěže serveru, ke zrcyhlení odesílání stránek a k zastavení nechtěnného a škodlivého provozu. +Jak se na webu Colomel píše, provozování webserveru může být hodnotná zkušenost, ale zároveň může být i zkouškou trpělivosti. Chcete svým uživatelům předávat všechny vaše stránky a obrázky, ovšem máte jen omezenou šířku pásma, pomocí které můžete data přenášet. Pokud přetížíte své připojení, klienti navštěvující váš web server si budou myslet, že je pomalý a neresponzivní. Je tedy třeba webový server nastavit tím nejlepším možným způsobem s cílem získat co nejvíce návštěv a zlepšit zážitek vašim návštěvníkům. Následující rady slouží ke snížení zátěže serveru, ke zrychlení odesílání stránek a k zastavení nechtěného a škodlivého provozu. Práce se věnuje pouze technickým optimalizacím spojených s tvorbou samotné webové stránky, nikoliv však optimalizacím sítě, web serveru a vizuálního návrhu. Nenačítá-li se stránka během několika vteřin, většina uživatelů jednoduše odejde. Cílem této sekce je provést optimalizace, které urychlí načítání modelové implementace. \subsection{Typy a kvalita obrázků} -Fotografie a grafika využívají mnohem více dat pro přenos než běžný HTML text a je tedy nutné provést optimalizaci (kompresi) obrázků na co nejmenší možnou velikost souborů. Obrázky není třeba renderovat na více než 72 dpi a pro každý druh grafiky je třeba zvolit vhodný tofmát, tj. formát JPEG pro fotografie a formáty PNG či SVG pro jednoduchou grafiku. Rastrové obrázky mají pouze potřebné rozlišení, tedy maximálně hodnotu největšího rozlišení, které se ve stránce bude zobrazovat. Klíčové je také nevyužívat obrázky v případě, kde je lze nahradit čístým HTML a CSS. +Fotografie a grafika využívají mnohem více dat pro přenos než běžný HTML text a je tedy nutné provést optimalizaci (kompresi) obrázků na co nejmenší možnou velikost souborů. Obrázky není třeba renderovat na více než 72 dpi a pro každý druh grafiky je třeba zvolit vhodný formát, tj. formát JPEG pro fotografie a formáty PNG či SVG pro jednoduchou grafiku. Rastrové obrázky mají pouze potřebné rozlišení, tedy maximálně hodnotu největšího rozlišení, které se ve stránce bude zobrazovat. Klíčové je také nevyužívat obrázky v případě, kde je lze nahradit čistým HTML a CSS. Obrázky ve formátu JPEG mají velice efektivní ztrátovou kompresi, pomocí které lze zredukovat velikost obrázku o značnou část. Autor článku tvrdí, že většinu obrázků lze komprimovat až o 50\% bez viditelné ztráty na kvalitě. Své obrázky dokonce zkomprimoval ze 27 kilobajtů na pouhých 8 kilobajtů s JPEG kompresí 60\%. \subsection{Ikona \textit{favicon.ico}} -Původně je \textit{favicon.ico} výtvorem firmy Microsoft, kdy její Internet Explorer automaticky odesílal požadavek na pevnou URL \texttt{/favicon.ico} od kořene webového serveru. Jde o malou ikonku, která se dnes zobrazuje u každé záložky s webovou stránkou. Problémem je to, že se požadavkům o ní nelze vyhnout a vždy se počítá s tím, že ikona na web serveru existuje. Odesílá se vždy s každou stránkou a některé prohlížeče se po ní dotazují z neznámých důvodu dvakrát. Autor článku uvádí, že u některých serverů bylo až 30\% přenesených dat využito jen na servírování ikony. +Původně je \textit{favicon.ico} výtvorem firmy Microsoft, kdy Internet Explorer automaticky odesílal požadavek na pevnou URL \texttt{/favicon.ico} od kořene webového serveru. Jde o malou ikonku, která se dnes zobrazuje u každé záložky s webovou stránkou. Problémem je, že se požadavkům o ní nelze vyhnout a vždy se počítá s tím, že ikona na web serveru existuje. Odesílá se vždy s každou stránkou a některé prohlížeče se po ní dotazují z neznámých důvodu dvakrát. Autor článku uvádí, že u některých serverů bylo až 30\% přenesených dat využito jen na odesílání ikony. -Principem optimalizace je udržet ikonu ji co nejmenší, v nejlepším případě tak malou, že se vejde do jednoho TCP paketu, tedy do velikosti 1460 bajtů na většině systémů. Toho lze docílit tím, že ikona nebude větší než 16x16 pixelů s nízkou barevnou hloubkou, nejlépe s pouze čtyřmi barvami. Také je možné poslat pouze 1x1 pixelů veliký prázdný obrázek, nebo vracet stavový kód 204\footnote{204 No Content -- Server úspěšně zpracoval požadavek, ale nevrací žádný obsah.} a neodesílat ikonu žádnou. +Principem optimalizace je udržet ikonu co nejmenší, v nejlepším případě tak malou, že se vejde do jednoho TCP paketu, tedy do velikosti 1460 bajtů na většině systémů. Toho lze docílit tím, že ikona nebude větší než 16x16 pixelů s nízkou barevnou hloubkou, nejlépe s pouze čtyřmi barvami. Také je možné poslat pouze 1x1 pixelů veliký prázdný obrázek, nebo vracet stavový kód 204\footnote{204 No Content -- Server úspěšně zpracoval požadavek, ale nevrací žádný obsah.} a neodesílat ikonu žádnou. \subsection{Obecné HTML optimalizace} @@ -311,13 +311,13 @@ Redukcí nepotřebných znaků v HTML lze také ušetřit značnou část přeno \item recyklování již použitých obrázků a tlačítek. \end{itemize} -K odstranění přebytečných mezer, zalomení řádků, HTML komentářů a prázdných řádků lze použít automatický filtr, který provede kompresi výstupu. \todo{Přesunout do návrhu pro rozšíření?}Generátor Zola provádí kompresi CSS, ovšem nemá zabudovanou funkcionalitu pro minifikaci výsledného HTML, která je ovšem v době psaní této práce vyvíjena\footnote{\url{https://github.com/getzola/zola/issues/542}}. +K odstranění přebytečných mezer, zalomení řádků, HTML komentářů a prázdných řádků lze použít automatický filtr, který provede kompresi výstupu. \todo{Přesunout do návrhu pro rozšíření?}Generátor Zola provádí kompresi CSS, ovšem nemá zabudovanou funkcionalitu pro minifikaci výsledného HTML, která je v době psaní této práce vyvíjena\footnote{\url{https://github.com/getzola/zola/issues/542}}. Touto redukcí lze ušetřit 2\% přenosu dat oproti ručně psanému neoptimalizovanému kódu. Je-li průměrná velikost stránky sto kilobajtů, lze touto optimalizací ušetřit dva kilobajty při každém odeslání stránky. Při odeslání sta tisíce stránek za měsíc je ve výsledku ušetřeno dvě stě megabajtů dat, které jsou jinak zbytečně odesílány uživatelům, kteří je stejně nezobrazí. Další obecné rady pro optimalizaci HTML jsou uvedeny na serveru \cite{yahoo_optimization}, kde se uvádí spousta dalších způsobů ke zrychlení načítání stránky a k nižšímu vytížení sítě. -Připojením externích CSS a JavaScript souborů je umožněno jejich ukládání do paměti cache, což snižuje HTTP požadavky vůči serveru. Je-li obsah těchto souborů přímo ve stránce, je odesílán pokaždé s novou stránkou a to vede ke zbytečnému vytěžování sítě. S tím souvísí i velikost stránek, kdy soubory větší než je daná maximální velikost se do paměti cache neukládají a je proto dobré tuto velikost nepřekračovat. +Připojením externích CSS a JavaScript souborů je umožněno jejich ukládání do paměti cache, což snižuje HTTP požadavky vůči serveru. Je-li obsah těchto souborů přímo ve stránce, je odesílán pokaždé s novou stránkou a to vede ke zbytečnému vytěžování sítě. S tím souvisí i velikost stránek, kdy soubory větší než je daná maximální velikost se do mezipaměti neukládají a je proto dobré tuto velikost nepřekračovat. \quest[inline]{U starých zařízení jsou pevně dané velikosti, například v roce 2011 byly limity 25.6K u iOS nebo 5M u Firefoxu. Mám je zde uvádět, i když se to rychle mění, nebo to stačí takhle obecně?} @@ -325,7 +325,7 @@ Připojením externího CSS přímo do hlavičky je umožněno progresivní vykr Je také důležité udržovat validní HTML, kdy například chybějící atribut \texttt{src=""} způsobuje odesílání nevyžádaných požadavků na server. -\quest[inline]{HTML5 už specifikuje, aby prohlížeče kvůli prázdnému \textit{src} neposílaly další požadavaek. Je tedy nutné uvádět tento příklad?} +\quest[inline]{HTML5 už specifikuje, aby prohlížeče kvůli prázdnému \textit{src} neposílaly další požadavek. Je tedy nutné uvádět tento příklad?} \subsection{Videa a jejich vložení do stránky} @@ -333,19 +333,19 @@ Je také důležité udržovat validní HTML, kdy například chybějící atrib \section{Správa obsahu a verzování} -Statické stránky neumožňují správu uživatelů v prámci webové aplikace, tedy že se případný editor nebo administrátor přihlásí a upravuje obsah klikáním, či psaním ve WYSIWYG\footnote{What You See Is What You Get -- Princip editoru který během psaní formátuje text tak, jak bude ve výsledku vypadat, například LibreOffice Writer atd.} editoru. Správu uživatelů lze jednoduše řešit omezením přístupu na web server, kde jen oprávnění uživatelé mohou do obsahu zasahovat. To je ovšem velmi tězkopádné řešení, protože neumožňuje práci více uživatelům najednou a neudržuje předešlé verze obsahu a historii úprav. Lepší alternativou je využití některého verzovacího systému. Pro účely modelové implementace byl vybrán distribuovaný verzovací systém Git, jak je vysvětleno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}. +Statické stránky neumožňují správu uživatelů v rámci webové aplikace, tedy, že se případný editor nebo administrátor přihlásí a upravuje obsah klikáním, či psaním ve WYSIWYG\footnote{What You See Is What You Get -- Princip editoru který během psaní formátuje text tak, jak bude ve výsledku vypadat, například LibreOffice Writer atd.} editoru. Správu uživatelů lze jednoduše řešit omezením přístupu na web server, kde jen oprávnění uživatelé mohou do obsahu zasahovat. To je ovšem velmi těžkopádné řešení, protože neumožňuje práci více uživatelům najednou a neudržuje předešlé verze obsahu a historii úprav. Lepší alternativou je využití některého verzovacího systému. Pro účely modelové implementace byl vybrán distribuovaný verzovací systém Git, jak je vysvětleno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}. -V tomto systému jsou soubory uloženy repozitářích, kde každý projekt je vlastní repozitář. V rámci repozitáře se ukládají všechny změny obsahu v takzvaných \uv{commitech}, nebo-li záznamech o provedených změnách včetně krátkého popisu a jejich autora. Tyto revize lze provádět v různých větvích repozitáře a větve je možné mezi sebou spojovat a kombinovat. Je také možné vracet se do kteréhokoliv bodu v historii v rámci každé větvě. +V tomto systému jsou soubory uloženy v repozitářích, kde každý projekt je vlastní repozitář. V rámci jednotlivých repozitářů se ukládají všechny změny obsahu prostřednictvím takzvaných \uv{commitech}, nebo-li záznamů o provedených změnách včetně jejich krátkého popisu a autora. Tyto revize lze provádět v různých větvích repozitáře a větve je možné mezi sebou spojovat a kombinovat. Je také možné vracet se do kteréhokoliv bodu v historii v rámci každé větvě. -Nastane-li konflikt při nahrávání změn, umoňujě Git jejich snadné vyřešení. Konflikt je stav, kdy například dva různí uživatelé provedli úpravy na stejném místě stejného souboru a snaží se je nahrát do repozitáře. Git v tuto chvíli druhého uživatele upozorní, že původní soubor byl změněn a je třeba tento konflikt vyřešit. Zamezuje se tedy přepsání změn prvního uživatele. +Nastane-li konflikt při nahrávání změn, umožňuje Git jejich snadné vyřešení. Konflikt je stav, kdy například dva různí uživatelé provedli úpravy na stejném místě stejného souboru a snaží se je nahrát do repozitáře. Git v tuto chvíli druhého uživatele upozorní, že původní soubor byl změněn a je třeba tento konflikt vyřešit. Zamezuje se tedy přepsání změn prvního uživatele. -K systému Git existují různé služby, které tento systém rozšiřují i webové grafické rozhraní se spoustou dalších rozšíření. Nejčastěji používanými službami jsou GitHub\footnote{\url{https://github.com/}}, GitLab\footnote{\url{https://gitlab.com/}}, nebo Bitbucket\footnote{\url{https://bitbucket.org/}}, z nichž některé lze provozovat na vlastním serveru. Snadným systémem pro vlastní provozování je také program Gitea\footnote{\url{https://gitea.com/}}, který je oproti předem zmíněným systémům zcela svobodným sotwarem a je velmi jednoduchý na instalaci a správu. Tyto systémy mají navíc integrovaný jednoduchý WYSIWYG editor pro úpravu souborů přímo z webového rozhraní a také umí renderovat soubory s obsahem napsaným v jazyce Markdown, který je popsán v sekci \ref{kap:markdown}. +K systému Git existují různé služby, které tento systém rozšiřují o webové grafické rozhraní s množstvím dalších rozšíření. Nejčastěji používanými službami jsou GitHub\footnote{\url{https://github.com/}}, GitLab\footnote{\url{https://gitlab.com/}}, nebo Bitbucket\footnote{\url{https://bitbucket.org/}}, z nichž některé lze provozovat na vlastním serveru. Snadným systémem pro vlastní provozování je také program Gitea\footnote{\url{https://gitea.com/}}, který je oproti předem zmíněným systémům zcela svobodným softwarem a je velmi jednoduchý na instalaci a správu. Tyto systémy mají navíc integrovaný jednoduchý WYSIWYG editor pro úpravu souborů přímo z webového rozhraní a také umí renderovat soubory s obsahem napsaným v jazyce Markdown, který je popsán v sekci \ref{kap:markdown}. \subsection{Automatizace generování obsahu}\label{kap:automaticke-generovani-obsahu} Tato část práce se věnuje samotné implementaci automatického generování obsahu na základě změn v repozitáři. -Jak bylo zmíněno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}, git umožňuje nastavení takzvaných \uv{hooks}, které se v určité chvíli spustí. Jak uvádí dokuemntace\footnote{\url{https://git-scm.com/docs/githooks}}, existuje spousta druhů hooků, které jsou vyvolány v různé části zpracování požadavku. V případě této implementace je nejvhodnější hook \textit{post-receive}, který je spouštěn až po nahrání a zpracování všech změn v repozitáři. +Jak bylo zmíněno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}, git umožňuje nastavení takzvaných \uv{hooks}, které se v určité chvíli spustí. Jak uvádí dokumentace\footnote{\url{https://git-scm.com/docs/githooks}}, existuje spousta druhů hooků, které jsou vyvolány v různé části zpracování požadavku. V případě této implementace je nejvhodnější hook \textit{post-receive}, který je spouštěn až po nahrání a zpracování všech změn v repozitáři. Následující skript po vyvolání Gitem provede veškeré potřebné operace ke zpracování nového obsahu na web serveru. @@ -374,11 +374,11 @@ rsync --recursive --delete --checksum \ public/ "$WEBROOT" \end{lstlisting} -Skript \ref{lst:git-hook-skript} je složen z několika částí. Jako první probíhá na řádcích 1--3 nastavení proměnných, ve kterých se ukládá odkaz na vzdálený Git repozitář, název složky, do které se obsah má klonovat a název složky do které se má kopírovat výstup, nebo-li vygenerované HTML. Dále se skript na řádku 5 přepíná do složky, ve které se sám nachází, proto aby skript fungoval vždy, ať je spuštěný ze kteréhokoliv místa v souborovém systému. +Skript \ref{lst:git-hook-skript} je složen z několika částí. Jako první probíhá na řádcích 1--3 nastavení proměnných, ve kterých se ukládá odkaz na vzdálený Git repozitář, název složky, do které se obsah má klonovat a název složky, do které se má kopírovat výstup, nebo-li vygenerované HTML. Dále se skript na řádku 5 přepíná do složky, ve které se sám nachází, proto aby skript fungoval vždy, ať je spuštěný ze kteréhokoliv místa v souborovém systému. V další části skriptu probíhá na řádku 7 kontrola, zda již existuje složka s naklonovaným Git repozitářem. Pokud složka neexistuje, provede se naklonování vzdáleného repozitáře a tím i k vytvoření složky. -Třetí část provádí generování statického obsahu. Nejprve se skript přepne do repozitáře, v němž provede příkaz \texttt{git pull}, který do složky stáhne poslední změny ze vzdáleného repozitáře, tedy synchronizuje obsah na poslední verzi. Po synchronizaci repozitáře proběhne samotné spuštění generátoru, který z obsahu vygeneruje statické HTML, jenž vloží do složky \texttt{./public}. Poté na řádcích 12--14 probíhá kopírování nově vygenerovaného obsahu do složky \texttt{/srv/www/ucitelonline}, včetně nastavení Unixových práv na bezpečné hodnoty zvlášť pro složky a soubory. +Třetí část provádí generování statického obsahu. Nejprve se skript přepne do repozitáře, v němž provede příkaz \texttt{git pull}, který do složky stáhne poslední změny ze vzdáleného repozitáře, tedy synchronizuje obsah na poslední verzi. Po synchronizaci repozitáře proběhne samotné spuštění generátoru, který z obsahu vygeneruje statické HTML, jenž vloží do složky \texttt{./public}. Poté na řádcích 12--14 probíhá kopírování nově vygenerovaného obsahu do složky \texttt{/srv/www/ucitelonline}, včetně nastavení Unixových práv souborů na bezpečné hodnoty, které se liší pro složky a pro soubory. Skript spoléhá na to, že systém má již předem správně nakonfigurované uživatele, uživatelské skupiny, web server, a že jsou nainstalované potřebné programy Git, Rsync, generátor Zola. Systémový uživatel, pod kterým je vyvolán Git hook, musí být ve skupině \textit{www-data}, nebo v jiné skupině společně s uživatelem, pod kterým je spuštěn web server. Zároveň musí mít uživatel práva pro zápis do cílové složky \texttt{/srv/www/ucitelonline}. diff --git a/kap-paradigmata.tex b/kap-paradigmata.tex index eebbd45..18ee9b0 100644 --- a/kap-paradigmata.tex +++ b/kap-paradigmata.tex @@ -1,6 +1,6 @@ \chapter{Webová paradigmata} -Ve světě webových stránek se setkáváme se spoustou forem a paradigmat, která se hodí pro obsažení různých druhů informací. Neexistují žádné formální zařazení druhů webových stránek do skupin, ovšem některé webové portály se pokouší určit základní druhy webů, které se na Internetu objevují. Na základě těchto portálů a jejich rozřazení do skupin\footnote{\url{http://www.xislegraphix.com/website-types.html}}\footnote{\url{https://www.hostgator.com/blog/popular-types-websites-create}}\footnote{\url{https://www.quora.com/What-are-the-different-types-of-websites}}\todo{Přesunout odkazy pod jednu položku.}, které jsou často mířené na specifický obsah, lze vytvořit tři základní paradigmata, do kterých lze tyto weby zařadit. Jsou jimi: +Ve světě webových stránek se setkáváme se spoustou forem a paradigmat, která se hodí pro zpracování různých druhů informací. Neexistuje žádné formální zařazení druhů webových stránek do skupin, ovšem některé webové portály se pokouší určit základní druhy webů, které se na Internetu objevují. Na základě těchto portálů a jejich rozřazení do skupin\footnote{\url{http://www.xislegraphix.com/website-types.html}}\footnote{\url{https://www.hostgator.com/blog/popular-types-websites-create}}\footnote{\url{https://www.quora.com/What-are-the-different-types-of-websites}}\todo{Přesunout odkazy pod jednu položku.}, které jsou často mířené na specifický obsah, lze vytvořit tři základní paradigmata, do kterých lze tyto weby zařadit. Jsou jimi: \begin{itemize} \item{Webová prezentace} @@ -15,11 +15,11 @@ V této práci byl ke každému z paradigmat vybrán systém vhodný pro generov Nejbližší původním webům z dob vzniku WWW jsou webové prezentace, tedy stránky s jednoduchým obsahem, které slouží k předání informací čtenáři například formou článků. Do této skupiny lze zařadit portfolia, blog, online noviny a časopisy, firemní stránky, foto alba a podobně. Tento druh stránek se skvěle hodí ke statickému generování obsahu, který se odesílá všem uživatelům stejný a nemění se často. -Jako nejvhodnější systém pro generování webových prezentací byl vybrán software Zola. Ten je oproti jiným systémům výhodný tím, že je napsaný v jazyce Rust a je tedy snadno rozšiřitelný a mnohem rychlejší, než většina jeho alternativ \citep{benchmarks_game}. I s těmito výhodami si zachovává spousty funkcí a rysů, které lze najít v ostatních složitých systémech. Také je možné generátor zkompilovat do jednoho staticky linkovaného binárního souboru, se kterým se pracuje mnohem lépe, než se složitým frameworkem. +Jako nejvhodnější systém pro generování webových prezentací byl vybrán software Zola. Ten je oproti jiným systémům výhodný tím, že je napsaný v jazyce Rust a je tedy mnohem rychlejší a bezpečnější, než většina jeho alternativ \citep{benchmarks_game}. Kromě těchto výhod si zachovává většinu funkcí a rysů, které lze najít v ostatních složitých systémech. Také je možné generátor zkompilovat do jednoho staticky linkovaného binárního souboru, se kterým se pracuje mnohem lépe, než se složitým frameworkem. \section{Index všeobecných informací} -Za obecného zástupce tohoto druhu stránek lze považovat Wikipiedii, která podnítila vznik spousty jiných takzvaných \uv{Wiki systémů} a stránek. +Za obecného zástupce tohoto druhu stránek lze považovat Wikipedii, která podnítila vznik spousty jiných takzvaných \uv{Wiki systémů} a stránek. \section{Technická dokumentace} diff --git a/kap-taxonomie-pozadavku.tex b/kap-taxonomie-pozadavku.tex index 7d63639..f2c8657 100644 --- a/kap-taxonomie-pozadavku.tex +++ b/kap-taxonomie-pozadavku.tex @@ -1,6 +1,6 @@ \chapter{Taxonomie požadavků pro modelový web}\label{kap:taxonomie-pozadavku} -Tato kapitola se věnuje určení základních požadavků pro modelovou implementaci. Jsou zde shrnuta obecná kritéria, která často platí pro většinu webových prezentací, a také kritéria specifická pro modelovou implementaci v rámci této práce. Dle těchto kritérií je poté samotná implementace tvořena v následující kapitole \ref{kap:modelova-implementace}. +Tato kapitola se věnuje určení základních požadavků pro modelovou implementaci. Jsou zde shrnuta obecná kritéria, která platí pro většinu webových prezentací, a také kritéria specifická pro modelovou implementaci v rámci této práce. Dle těchto kritérií je poté samotná implementace tvořena v následující kapitole \ref{kap:modelova-implementace}. Jako modelová implementace byl zvolen web pro distribuci výukových materiálů a odkazů užitečných pro výuku. Tvorba těchto webových stránek je zadána Ústavem výzkumu a rozvoje vzdělávání Pedagogické fakulty Univerzity Karlovy za účelem usnadnění práce již aktivních učitelů v době šíření viru COVID-19. Stránky mají učitelům pomoci s přípravou distanční výuky a úkolů v době vyhlášení stavu nouze a celostátní karantény. Modelová implementace je tedy plně využívána v praxi mnoha pedagogy z celé republiky. Tuto implementaci lze ovšem použít na distribuci jakýchkoliv jiných výukových materiálů, či ke psaní a správě dokumentace. @@ -16,12 +16,12 @@ Stránky by měly být udržovatelné i po předání jinému správci a celý s Specifická kritéria jsou vytvořena na základě požadavků autorů obsahu, tedy učitelů, ze kterých každý má své specifické požadavky na funkce a vlastnosti, které musí obsah splňovat. Následující kritéria jsou souhrnem a kompromisem mezi všemi požadavky. -Stránky musí být staticky generované a není tedy žádoucí v rámci webu řešit uživatelské účty, přihlašování apod. Hlavním požadavkem pro sturkturu stránky je možnost dělit obsah na sekce dle druhu školy (základní škola, střední škola, vysoká škola atd.) a dále pak na subsekce podle předmětů a oborů. +Stránky musí být staticky generované a není tedy žádoucí v rámci webu řešit uživatelské účty, přihlašování apod. Hlavním požadavkem pro strukturu stránky je možnost dělit obsah na sekce dle druhu školy (základní škola, střední škola, vysoká škola atd.) a dále pak na subsekce podle předmětů a oborů. -Do samotného obsahu musí být možné vkládat přílohy ke stažení v různých formátech, obrázky a videa s možností jejich ocitování, tedy uvedení autora, názvu díla apod. Všechny přiložené soubory musí být distribuovatelné přímo z webových stránek, nikoliv s externích zdrojů. Všechna videa je nutné vložit do stránky a musí je být možné přehrát v nativním přehrávači prohlížeče bez nutnosti otevírání externích webových stránek či programů. V hlavičce každé stránky musí být možné specifikovat několik metadat: autora či seznam autorů obsahu, skupinu pro kterou je obsah určen a časovou dotaci. +Do samotného obsahu musí být možné vkládat přílohy ke stažení v různých formátech, obrázky a videa s možností jejich ocitování, tedy uvedení autora, názvu díla apod. Všechny přiložené soubory musí být distribuovatelné přímo z webových stránek, nikoliv z externích zdrojů. Všechna videa je nutné vložit do stránky a musí je být možné přehrát v nativním přehrávači prohlížeče bez nutnosti otevírání externích webových stránek či programů. V hlavičce každé stránky musí být možné specifikovat metadata: autora či seznam autorů obsahu, skupinu pro kterou je obsah určen a časovou dotaci. Obsah stránek musí být možné spravovat předem pověřenými uživateli a jeho změny musí být zaznamenávány v decentralizovaném verzovacím systému. Generování statického webu na základě změn obsahu je nutné řešit automatizovaně bez dalších zásahů správce, či manuálního nahrávání nového obsahu na webserver. \section{Kritéria pro šablony a design} -Obsah musí být snadno čitelný a zobrazitelný na každém druhu zařízení, tedy jak na monitorech s nadstandardní velikostí, tak na mobilních zařízeních. Zároveň musí být snadno čitelný, v nejlepším případě vysokokontrastní černý text na bílém pozadí s dostatečnou velikostí. Navigace v obsahu musí být jednoduchá a intuitivní a vzhled celé stránky konzistentní. Na stránce nesmí přesahovat objem vizuálních elementů nad obsahem. Relevantní obsah by měl být na jednom místě, nikoliv rozdělený na několik různých stránek, mezi kterými musí uživatel přecházet. +Obsah musí být snadno čitelný a zobrazitelný na každém druhu zařízení, tedy jak na monitorech s nadstandardní velikostí, tak na mobilních zařízeních. Zároveň musí být snadno čitelný, v nejlepším případě vysoko kontrastní černý text na bílém pozadí s dostatečnou velikostí. Navigace v obsahu musí být jednoduchá a intuitivní a vzhled celé stránky konzistentní. Na stránce nesmí přesahovat objem vizuálních elementů nad obsahem. Relevantní obsah by měl být na jednom místě, nikoliv rozdělený na několik různých stránek, mezi kterými musí uživatel přecházet. diff --git a/kap-vyhodnoceni-implementace.tex b/kap-vyhodnoceni-implementace.tex index 18e5870..322fd54 100644 --- a/kap-vyhodnoceni-implementace.tex +++ b/kap-vyhodnoceni-implementace.tex @@ -1,6 +1,6 @@ \chapter{Vyhodnocení modelové implementace} -\section{Návrhy pro rozříšení systému} +\section{Návrhy pro rozšíření systému} \section{Implementace rozšíření} diff --git a/poznamky b/poznamky new file mode 100644 index 0000000..0526443 --- /dev/null +++ b/poznamky @@ -0,0 +1,5 @@ +- ocitovat financial times výzkum +- pro framework není český ekvivalent (framework znamená kostra, to nechceš lol) +- backend a frontend bys moh popsat max jako část serveru a část klienta, ale backend a frontend je lepší +- "U starých zařízení..." - řek bych, že můžeš zmínit max 4 fun nebo abys nahnal znaky lol +- "HTML5 už specifikuje" - nah vyjeb se na to lol -- 2.45.2 From 1731e7c785be64cede22e4e14d3405c1f3941154 Mon Sep 17 00:00:00 2001 From: magnusi Date: Thu, 30 Apr 2020 14:26:20 +0200 Subject: [PATCH 02/49] korektura (#6) --- kap-generatory.tex | 22 +++++------ kap-markup.tex | 22 +++++------ kap-modelova-implementace.tex | 70 +++++++++++++++++------------------ kap-paradigmata.tex | 6 +-- kap-taxonomie-pozadavku.tex | 8 ++-- poznamky | 5 +++ 6 files changed, 69 insertions(+), 64 deletions(-) create mode 100644 poznamky diff --git a/kap-generatory.tex b/kap-generatory.tex index c10e2c6..6bab955 100644 --- a/kap-generatory.tex +++ b/kap-generatory.tex @@ -6,11 +6,11 @@ Dynamické stránky jsou generovány speciálně pro každého uživatele na zá \section{Výhody statických webových stránek}\label{kap:vyhody-statickych-webovych-stranek} -Pro sdílení statického obsahu mezi různé uživatele stačí velmi jednoduchý HTTP server bez jakýchkoliv dalších modulů typu \textit{PHP}, \textit{Python} a dalších systémů, které by obsah dynamicky generovaly například z dat vytažených z databáze, nebo z uživatelského vstupu. Na straně serveru tedy nedochází ke zpracování obsahu těsně před jeho odesláním uživateli, čímž se v komunikaci mezi klientem a serverem se drasticky snižuje \uv{Time To First Byte}\footnote{Time To First Byte --- čas mezi odesláním požadavku a přijmutím prvního bajtu dat.} a tím dochází ke snížení celkové latence. \citep{mozttfb} +Pro sdílení statického obsahu mezi různé uživatele stačí velmi jednoduchý HTTP server bez jakýchkoliv dalších modulů typu \textit{PHP}, \textit{Python} a dalších systémů, které by obsah dynamicky generovaly například z dat vytažených z databáze, nebo z uživatelského vstupu. Na straně serveru tedy nedochází ke zpracování obsahu těsně před jeho odesláním uživateli, čímž se v komunikaci mezi klientem a serverem drasticky snižuje \uv{Time To First Byte}\footnote{Time To First Byte --- čas mezi odesláním požadavku a přijmutím prvního bajtu dat.} a tím dochází ke snížení celkové latence. \citep{mozttfb} -Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z tohoto výzkumu se autoři rozhodli v následujících měsících od vydání analýzy zainvestovat více času do úprav všech aspektů jejich nové stránky FT.com s cílem jejího zrychlení.\todo{Nechat opravit překlad} +Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že z pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z tohoto výzkumu se autoři rozhodli v měsících po vydání analýzy investovat více času do úprav všech aspektů jejich nové stránky FT.com s cílem jejího zrychlení.\todo{Nechat opravit překlad} -Eliminováním dynamického obsahu se také předchází nevyžádaným vstupům od uživatele, které mohou být i cílené na prolomení bezpečnostních nedostatků webové aplikace a v některých případech mohou vést k úniku citlivých dat, převzetí kontroly útočníka nad webovou aplikací nebo celým serverem, podstrčení falešných dat uživateli a mnoho dalším běžně se stávajícím útokům. Statický web eliminuje tento problém, jelikož nemá žádný uživatelský vstup. +Eliminováním dynamického obsahu se také předchází nevyžádaným vstupům od uživatele, které mohou být i cílené na prolomení bezpečnostních nedostatků webové aplikace a v některých případech mohou vést k úniku citlivých dat, převzetí kontroly útočníka nad webovou aplikací nebo celým serverem, podstrčení falešných dat uživateli a mnoha dalším běžným útokům. Statický web eliminuje tento problém, jelikož nemá žádný uživatelský vstup. Sledování a analýze nejčastějších chyb webových aplikací a serverů se věnuje organizace OWASP\footnote{The Open Web Application Security Project --- \url{https://owasp.org/}.}, která vydává aktualizované seznamy a statistiky. Podle OWASP byly v roce 2017 nejčastější tyto chyby a bezpečnostní nedostatky: @@ -22,25 +22,25 @@ Sledování a analýze nejčastějších chyb webových aplikací a serverů se \item{Nefunkční řízení přístupu} \item{Špatná konfigurace zabezpečení} \item{Cross-Site Scripting (XSS)} - \item{Nezabezpečná deserializace} - \item{Uživání komponent se známými zranitelnostmi} + \item{Nezabezpečená deserializace} + \item{Užívání komponent se známými zranitelnostmi} \item{Nedostatečné logování a monitorování} \end{enumerate} \citep{owasp2017} -Většina těchto chyb se vztahuje právě k dynamickým webovým aplikacím. Bezpečnost tedy závisí nejen na programátorovi který aplikaci vytváří, ale také na tom, že programovací jazyk je bezpečně implementován. To nelze tvrdit o nejpoužívanějším jazyce PHP, který nejen že obsahuje spousty chyb, viz seznam nalezených bezpečnostních děr \citep{cve_php}, ale zároveň nevede programátora ke psaní bezpečného kódu a ve výsledku vzniká nebezpečná aplikace, pokud si autor nedá pozor na správné ošetření vstupů a další bezpečnostní aspekty programu. +Většina těchto chyb se vztahuje právě k dynamickým webovým aplikacím. Bezpečnost tedy závisí nejen na programátorovi který aplikaci vytváří, ale také na tom, že programovací jazyk je bezpečně implementován. To nelze tvrdit o nejpoužívanějším jazyce PHP, který nejen že obsahuje mnoho chyb, viz seznam nalezených bezpečnostních děr \citep{cve_php}, ale zároveň nevede programátora k psaní bezpečného kódu, což má za následek nebezpečené aplikace, pokud si autor nedá pozor na správné ošetření vstupů a dalších bezpečnostních aspektů programu. -Skvělým příkladem chybovosti dynamických webů je systém Wordpress, ve kterém jsou každý rok nalezeny desítky bezpečnostních chyb \citep{cve_wordpress}, přičemž mnoho dalších přibývá s instalací špatně napsaných rozšíření. Například na začátku roku 2020 byla nalezena bezpečnostní chyba v rozšíření, které bylo využíváno na více než dvě stě tisících webových stránkách a potencionálním útočníkům umožnila smazat obsah databáze \citep{thehackernews_wordpress_1}. Na konci roku 2019 umožnila chyba ve dvou nezabezpečených rozšířeních neautorizované přihlášení k účtu administrátora bez použití hesla \citep{thehackernews_wordpress_2}. +Podstatným příkladem chybovosti dynamických webů je systém Wordpress, ve kterém jsou každý rok nalezeny desítky bezpečnostních chyb \citep{cve_wordpress}, přičemž mnoho dalších přibývá s instalací rozšíření, která postrádají bezpečnostní prvky. Například na začátku roku 2020 byla nalezena bezpečnostní chyba v rozšíření, které bylo využíváno na více než dvě stě tisících webových stránkách a potencionálním útočníkům umožňovala smazat obsah databáze \citep{thehackernews_wordpress_1}. Na konci roku 2019 umožnila chyba ve dvou nezabezpečených rozšířeních neautorizované přihlášení k účtu administrátora bez použití hesla \citep{thehackernews_wordpress_2}. -Údržba velkých webových aplikací je také často problematická. Kód je nutné udržovat v návaznosti na aktualizace daného jazyka, databázového systému a dalších věcí. Těmto aktualizacím se z bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s databázemi a různými frameworky\todo{Lepši slovo?} a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. +Údržba velkých webových aplikací je často problematická. Kód je nutné udržovat v návaznosti na aktualizace daného jazyka, databázového systému a dalších aspektů. Těmto aktualizacím se z bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s databázemi a různými frameworky\todo{Lepši slovo?} a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. -Jako každý jiný systém, i statické generátory mají své nevýhody. Hlavním z problémů je to, že správa statického generátoru a tvorba obsahu je náročnější, než klasické webové rozhraní s administračním panelem, různými uživateli a jednoduchou správou pro běžné technicky nenadané uživatele. Pro přidání nebo úpravu obsahu je nutné pracovat s lokálními soubory ve stromové struktuře a při generování je často potřebný zásah do shellu\footnote{Program pro interpretování příkazů v prostředí příkazové řádky.}. Tvorba systému pro automatizované generování je také náročnější než instalace některého z běžných CMS\footnote{Content Management System}. \citep{softpedia_generators} +Jako každý jiný systém, i statické generátory mají své nevýhody. Hlavním z problémů je to, že správa statického generátoru a tvorba obsahu je náročnější, než klasické webové rozhraní s administračním panelem, různými uživateli a jednoduchou správou pro běžné, méně technicky zaměřené uživatele. Pro přidání nebo úpravu obsahu je nutné pracovat s lokálními soubory ve stromové struktuře a při generování je často potřebný zásah do shellu\footnote{Program pro interpretování příkazů v prostředí příkazové řádky.}. Tvorba systému pro automatizované generování je také náročnější než instalace některého z běžných CMS\footnote{Content Management System}. \citep{softpedia_generators} \section{Princip generátorů}\label{kap:princip-generatoru} -Generátor statického obsahu je tvořen ze tří hlavních částí. První částí jsou soubory šablon, které popisují rozložení stránky, vizuální vlastnosti, typografii, ale také vstupní a výstupní kódování a formáty. V podstatě definují jak a kam se bude obsah vkládat. Druhou částí je obsah obecně psaný v některém ze značkovacích jazyků, nejčastěji v jazyce Markdown. Obsah je strukturován do vlastních sekcí a souborů, aby bylo snadné rozlišit, do které části výsledné stránky patří. Třetí a poslední částí je samotné jádro generátoru, které zpracovává obsah, vkládá ho do šablon a renderuje statickou webovou stránku. +Ekosystém generátoru statického obsahu je tvořen ze tří hlavních složek. První částí jsou soubory šablon, které popisují rozložení stránky, vizuální vlastnosti, typografii, ale také vstupní a výstupní kódování a formáty. V podstatě definují jak a kam se bude obsah vkládat. Druhou částí je obsah samotný, napsaný v některém ze značkovacích jazyků, nejčastěji v jazyce Markdown. Obsah bývá strukturován do sekcí a souborů, aby bylo snadné rozlišit, do které části výsledné stránky patří. Třetí a poslední složkou je samotné jádro generátoru, které zpracovává obsah, vkládá ho do šablon a renderuje statickou webovou stránku. -Většina generátorů zároveň umí pracovat s konfiguračními soubory, kterými jde nastavit chování generátoru na jednom centralizovaném místě. Část z nich má také integrovaný jednoduchý web server, který umožňuje autorovi náhled výstupních stránek během tvorby obsahu. +Většina generátorů zároveň umí pracovat s konfiguračními soubory, kterými jde nastavit globální chování generátoru. Část z nich také integruje jednoduchý webserver, který umožňuje autorovi náhled výstupních stránek zatím co tvoří obsah. \citep{softpedia_generators} diff --git a/kap-markup.tex b/kap-markup.tex index d6117f3..6469f6c 100644 --- a/kap-markup.tex +++ b/kap-markup.tex @@ -2,37 +2,37 @@ \section{Principy značkovacích jazyků} -Vysvětlení principu značkovacích jazyků, nebo také takzvaně \uv{makrup jazyků}, můžeme najít například v RFC 7764\footnote{Jako \textit{RFC} se označují standardy vydané organizací IETF (Internet Engineering Task Force).}, tedy že v počítačových systémech jsou kontextuální data ukládána a zpracována několika technikami. Informaci lze kódovat jako čistý text bez speciálních formátovacích znaků. Tento přístup je jednoduchý pro implementaci i použití, ovšem neumožňuje složitější formátování textu. +Definici konceptu značkovacích jazyků, nebo-li \uv{markup jazyků}, můžeme najít například v RFC 7764\footnote{Jako \textit{RFC} se označují standardy vydané organizací IETF (Internet Engineering Task Force).}, tedy že v počítačových systémech jsou kontextuální data ukládána a zpracována několika technikami. Informaci lze kódovat jako čistý text bez speciálních formátovacích znaků. Tento přístup je jednoduchý pro implementaci i použití, ovšem neumožňuje složitější formátování textu. -Kódovat lze můžeme i do binárních dat určených ke zpracování a interpretaci specializovaným programem. Zřejmou nevýhodou je to, že zdroj není čitelný bez programu určeného pro jeho interpretaci. +Kódovat můžeme i do binárních formátů určených ke zpracování a interpretaci specializovaným programem. Zřejmou nevýhodou je to, že zdroj není čitelný bez programu určeného pro jeho interpretaci. -Markup jazyky se snaží o spojení toho nejlepšího z obou světů, tedy o obsah čitelný v čistém textu s možností formátování. To je dosaženo tím, že běžným znakům jsou přiděleny speciální významy nedefinované původní znakovou sadou. Uživatel je schopen tyto znaky psát jako čistý text a vyjádřit tím speciální význam. Například v rámci jazyka Markdown se znak \texttt{\#} změní z běžného křížku na definování nadpisu první úrovně, nebo také kombinace znaků \texttt{

} značí začátek odstavce v HTML. \citep{rfc7764} +Markup jazyky se snaží o spojení nejlepšího z obou světů, tedy o obsah s možností formátování, který je jednoduše čitelný jak pro člověka, tak pro stroj. Toho je dosaženo tím, že v je v běžných textových souborech přiřezen vybraným znakům speciální význam. Uživatel je schopen tyto znaky psát bez potřeby speciálních nástrojů a tím jednoduše vyjádřit speciální význam. Například v rámci jazyka Markdown se znak \texttt{\#} změní z běžného křížku na definování nadpisu první úrovně, nebo také kombinace znaků \texttt{

} značí začátek odstavce v HTML. \citep{rfc7764} \section{Nejběžnější jazyky} -Ke dnešnímu dni vnikl nespočet značkovacích jazyků. Nejpoužívanějším z nich jednoznačně HTML, ovšem tato práce se věnuje těm nejpoužívanějším jazykům, které mají uživateli usnadnit psaní a sázení obsahu. Uživatel tedy nemusí nutně řešit typografii a formátování obsahu při jeho psaní, tedy o věci, o které se později stará generátor pomocí šablon. U HTML je tomu naopak, kdy uživatel řeší samotný obsah i formátování v jednu chvíli skrze různé druhy formátovacích tagů. O vyplňování obsahu do HTML se v případě staticky generovaných webů stará právě samotný generátor. +V současnosti existuje nespočet značkovacích jazyků. Nejpoužívanějším z nich je jednoznačně HTML, ovšem tato práce se věnuje těm nejpoužívanějším jazykům, které mají uživateli usnadnit psaní a sázení obsahu. Uživatel se tedy nemusí při tvorbě nutně zabývat typografií a formátováním obsahu, což jsou aspekty, o které se později postará generátor pomocí šablon. U HTML je tomu naopak, uživatel řeší samotný obsah i formátování v jednu chvíli skrze různé druhy formátovacích tagů. O vyplňování obsahu do HTML se v případě staticky generovaných webů stará právě samotný generátor. -Vybrané jazyky jsou zároveň cílené na čitelnost samotného zdrojového obsahu v čistém textu bez nutnosti jeho interpretace speciálním prostředím či zpracováním do jiného formátu, například do PDF, DjVu, PostScript apod. Například podtržení textu je v nějakém pseudo-jazyce reprezentováno opravdovým podtržením pomocí spojovníků, nikoliv obalením nadpisu ve speciální deklaraci, jako je tomu například u HTML. Podtržení je poté pro čtenáře mnohem jasnější, jelikož nemusí přemýšlet, co v případě HTML daný tag vůbec způsobuje, ale podtržený vyplývá z kontextu. +Vybrané jazyky jsou zároveň cílené na čitelnost samotného zdrojového obsahu v čistém textu bez nutnosti jeho interpretace speciálním prostředím či zpracováním do jiného formátu, například do PDF, DjVu, PostScript apod. Například podtržení textu je v nějakém pseudo-jazyce reprezentováno opravdovým podtržením pomocí spojovníků, nikoliv obalením nadpisu ve speciální deklaraci, jako je tomu například u HTML. Podtržení je poté pro čtenáře mnohem jasnější, jelikož nemusí přemýšlet, co v kontextu HTML daný tag znamená, kdežto podtržení vyplývá z kontextu. Seznam nejoblíbenějších jazyků je sestaven podle aktuálních statistik ze serveru Slant, který se věnuje obecnému určení oblíbenosti na základě hodnocení ze strany uživatelů. \citep{slant} \subsection{Markdown}\label{kap:markdown} -Vznik jazyka Markdown byl 14. prosince roku 2014, když John Gruber vydal jeho první popis syntaxe a referenční implementaci. +Jazyka Markdown vznikl 19. března roku 2004, když John Gruber vydal první popis syntaxe a referenční implementaci. Hlavním z cílů syntaxe jazyka je vytvářet co možná nejčitelnější obsah v syrové podobě. Dokument psaný v Markdownu by měl být publikovatelný sám o sobě jako čistý text bez dalších úprav a zpracování. Jazyk byl ovlivněn několika již existujícími specifikacemi jiných jazyků, ovšem největším zdrojem inspirace pro jeho vznik jsou čisté emailové korespondence. \citep{daringfireball} -První specifikaci Gruber vydal společně s referenční implementací v jazyce Perl, která slouží pro konverzi Markdownu do HTML. Tento program je také pojmenován jako \uv{Markdown}, ovšem mluvíme-li o \uv{Markdownu}, máme nejčastěji na mysli samotnou syntaxi. Ta je dnes již implementována v mnoha různých jazycích a programech. Gruberova specifikace ovšem není formální standard, kvůli čemuž vznikl veliký počet alternativních a více čí méně pozměněných implementací, které nemusí být navzájem kompatibilní. Nejčastějšími z nich jsou například Github Markdown, CommonMark, R Markdown a mnoho dalších. \citep{commonmark} +První specifikaci Gruber vydal společně s referenční implementací v jazyce Perl, která prováděla konverzi Markdownu do HTML. Tento program je také pojmenován \uv{Markdown}, ovšem mluvíme-li o \uv{Markdownu}, máme nejčastěji na mysli samotnou syntaxi. Ta má dnes mnoho implementací v různých programovacích jazycích. Gruberova specifikace ovšem není formální standard, kvůli čemuž vznikl veliký počet alternativních a více či méně pozměněných implementací, které nemusí být navzájem kompatibilní. Nejčastějšími z nich jsou například Github Markdown, CommonMark, R Markdown a mnoho dalších. \citep{commonmark} Nevyužívanější formální specifikací je právě CommonMark\footnote{\url{https://commonmark.org/}}, který slouží jako pevný základ většiny rozšíření. \citep{github_formal_markdown_spec}. -Podobně jako je tomu u specifikací, existuje velké množství programů, které tyto různé specifikace překládají. Švýcarským nožem mezi nimi je program Pandoc\footnote{\url{https://pandoc.org/}}, který umí překládat Markdown do enormního výběru jiných formátů, nebo z jiných formátů zpět. Tato funkcionalita se nezvtahuje pouze na jazyk Markdown, ovšem Pandoc dokáže operovat mezi všemy podporovanými formáty, například dokáže konvertovat obsah z HTML do \TeX{}u. Na druhou stranu existují i velmi jednoduché překladače, například program smu\footnote{\url{https://github.com/Gottox/smu}}, který umí překládat Markdown do HTML nebo čistého textu a neobsahuje více než 600 SLOC\footnote{Source lines of code}, tedy řádků kódu hlavního programu. +Podobně jako je tomu u specifikací, existuje velké množství programů, které tyto různé specifikace překládají. Švýcarským nožem mezi nimi je program Pandoc\footnote{\url{https://pandoc.org/}}, který umí překládat Markdown do enormního výběru jiných formátů, nebo z jiných formátů zpět. Tato funkcionalita se nevztahuje pouze na jazyk Markdown, Pandoc dokáže operovat mezi všemi podporovanými formáty, například dokáže konvertovat obsah z HTML do \TeX{}u. Na druhou stranu existují i velmi jednoduché překladače, například program smu\footnote{\url{https://github.com/Gottox/smu}}, který umí překládat Markdown do HTML nebo čistého textu a neobsahuje více než 600 SLOC\footnote{Source lines of code}, tedy řádků kódu hlavního programu. \subsection{Org-mode} -Org-mode vznikl jako jeden z módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s možností přidání libovolného nového backendu\todo{České slovo?}. Cílem Org-mode je možnost ho používat i s minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor emacs je zároveň velmi často protován na různé druhy stsémů a je tedy možné ho využívat v podstatě kdekoliv. \citep{orgmanual} +Org-mode vznikl jako jeden z módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s možností přidání libovolného nového backendu\todo{České slovo?}. Cílem Org-mode je možnost ho používat i s minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor Emacs je zároveň velmi často portován na různé druhy systémů a je tedy možné ho využívat v podstatě kdekoliv. \citep{orgmanual} -Podporuje také \uv{literate programming} a \uv{reproducible research}, tedy že Org soubory mohou obsahovat plně funkční bloky s kódem, které lze evaluovat v rámci systému a výstup bloků lze automaticky vkládat přímo do dokumentu. \citep{environment_for_literate_programming} +Podporuje také \uv{literate programming} a \uv{reproducible research}, tedy že Org soubory mohou obsahovat plně funkční bloky s kódem, které lze hodnotit v rámci systému a výstup bloků lze automaticky vkládat přímo do dokumentu. \citep{environment_for_literate_programming} Jak popisuje Carsten Dominik ve svém krátkém technickém popisu, Org-mode umí navrhování, psaní poznámek, hypertextové odkazy, tabulky, seznamy, plánování projektů, GTD, HTML a \LaTeX{}, a to všechno v čistých textových souborech v editoru Emacs. \citep{carsten_dominik} @@ -51,7 +51,7 @@ Tento jazyk se již vzdaluje od původního konceptu čitelnosti zdroje, ovšem Většina uživatelů se setkala spíše s jazykem \LaTeX, tedy s nadstavbou původního \TeX{}u, která má uživateli zjednodušit práci svými makry a rozšířeními. Realita je ovšem taková, že \LaTeX{} dělá celou práci složitější, jak popisuje doktor Olšák: \begin{quote} -Představte si, že si nějaký uživatel přečte \LaTeX{}ovou příručku a nabyde dojmu, že mu bude stačit rozumět problematice sazby na úrovni této příručky. Pak se jednou překlepne třeba při sestavování tabulky a na terminálu na něj \TeX{} křičí: {\tt Extra alignment tab has been changed to "\verb|\cr|".} Uživatel začne znovu listovat ve své příručce a zjistí, že tam o~žádném "\verb|\cr|" není jediná zmínka. Má pak tři možnosti: (1)~Zmáčkne Enter a podobně se zachová i u~dalších chyb. Pomyslí si, že ten \LaTeX{} je něco tajemného a mystického. (2)~Propadne zoufalství a jde od toho. Dojde k~závěru, ľe je lepší zůstat u~Wordu. Vždyť stačí vzít tabulku v~Excelu a jednoduše ji přemístit do Wordu a jaképak smolení se s~nějakým podezřelým "\verb|\cr|". (3)~Pořídí si \TeX{}book a po intenzivním studiu nakonec řekne: \uv{aha}. V~tuto chvíli ale už nepotřebuje, aby mu \LaTeX{} zakrýval složitost \TeX{}u. +Představte si, že si nějaký uživatel přečte \LaTeX{}ovou příručku a nabude dojmu, že mu bude stačit rozumět problematice sazby na úrovni této příručky. Pak se jednou překlepne třeba při sestavování tabulky a na terminálu na něj \TeX{} křičí: {\tt Extra alignment tab has been changed to "\verb|\cr|".} Uživatel začne znovu listovat ve své příručce a zjistí, že tam o~žádném "\verb|\cr|" není jediná zmínka. Má pak tři možnosti: (1)~Zmáčkne Enter a podobně se zachová i u~dalších chyb. Pomyslí si, že ten \LaTeX{} je něco tajemného a mystického. (2)~Propadne zoufalství a jde od toho. Dojde k~závěru, ľe je lepší zůstat u~Wordu. Vždyť stačí vzít tabulku v~Excelu a jednoduše ji přemístit do Wordu a jaképak smolení se s~nějakým podezřelým "\verb|\cr|". (3)~Pořídí si \TeX{}book a po intenzivním studiu nakonec řekne: \uv{aha}. V~tuto chvíli ale už nepotřebuje, aby mu \LaTeX{} zakrýval složitost \TeX{}u. \end{quote} \citep{nolatex} Ve výsledku je tedy lepší, z různých důvodů popsaných doktorem Olšákem v jeho publikaci, použít samotný plain \TeX{} na úkor vyšší vstupní úrovně pro použivání jazyka. diff --git a/kap-modelova-implementace.tex b/kap-modelova-implementace.tex index 432536e..6b20d7b 100644 --- a/kap-modelova-implementace.tex +++ b/kap-modelova-implementace.tex @@ -8,21 +8,21 @@ Modelový web se skládá ze dvou částí, a to z verzovacího systému pro spr \subsection{Verzovací systém pro správu obsahu}\label{kap:vyber-vhodneho-systemu-verzovani} -Pro správu obsahu i šablon a statických souborů byl zvolen distribuovaný verzovací systém Git, který má v porovnání s jinými verzovacími systémy spousty výhod. Hlavní jeho výhodou je rozšířené využití v praxi a snadné používání. Díky svým decentralizovaným vlastnostem ho lze využívat v mnoha odlišných pracovních postupech. S naklonovaným repozitářem lze pracovat i bez připojení k síti, což lze považovat i za druh zálohy. Git také umožňuje slučování různých změn od mnoha uživatelů a dovoluje jednoduše řešit potenciální konflikty. \citep{why_is_git_better_than_x} +Pro správu obsahu i šablon a statických souborů byl zvolen distribuovaný verzovací systém Git, který má v porovnání s jinými verzovacími systémy, zejména centralizovanými, spousty výhod. Hlavní jeho výhodou je rozšířené využití v praxi a snadné používání. Díky svým decentralizovaným vlastnostem ho lze využívat v mnoha odlišných pracovních postupech. S naklonovaným repozitářem lze pracovat i bez připojení k síti, což lze považovat i za druh zálohy. Git také umožňuje slučování různých změn od mnoha uživatelů a dovoluje jednoduše řešit potenciální konflikty. \citep{why_is_git_better_than_x} Skvěle využitelnou funkcí pro modelovou implementaci je také to, že po provedení změn v repozitáři lze pomocí Gitu spouštět skripty, které mohou provádět automatické generování obsahu a další užitečné operace. Tato funkcionalita je implementována v rámci modelové implementace v sekci \ref{kap:automaticke-generovani-obsahu}. \subsection{Generátor statického webu} -Protože forma modelového webu odpovídá paradigmatu webové prezentace ze sekce \ref{kap:paradigmata-webova-prezentace}, byl pro jeho generování použit program Zola\footnote{\url{https://www.getzola.org/}}, jehož výhody jsou v sekci \ref{kap:paradigmata-webova-prezentace} popsány. +Protože forma modelového webu odpovídá paradigmatu webové prezentace ze sekce \ref{kap:paradigmata-webova-prezentace}, byl pro jeho generování použit program Zola\footnote{\url{https://www.getzola.org/}}, jehož výhody jsou popsány v sekci \ref{kap:paradigmata-webova-prezentace}. \todo[inline]{Přesunout výběr a výhody generátoru sem.} \section{Tvorba šablony} -Jak se uvádí v dokumentaci\footnote{\url{https://www.getzola.org/documentation/content/overview/}}, Zola pracuje s několika druhy stránek, primárně s takzvanou \uv{sekcí} a \uv{stránkou}. Každá sekce může mít vlastní obsah, ovšem může obsahovat i další subsekce, díky čemuž lze dělit obsah do stromové struktury. Stránka slouží pouze k předání obsahu a nikoliv k dalšímu větvení struktury. Dá se tedy říci, že stránka značí konec dané větve. Kořenem celého stromu je speciální sekce s názvem \uv{index}. Každá tato část standardně využívá vlastní HTML šablonu, ovšem nejde o pravidlo a každá část větve může využívat jinou šablonu. To je užitečné například u stránek s různým druhem obsahu. V rámci modelového webu zůstává druh obsahu stejný a není tedy třeba odchylovat se od standardní struktury. +Jak se uvádí v dokumentaci\footnote{\url{https://www.getzola.org/documentation/content/overview/}}, Zola pracuje s několika druhy stránek, primárně s takzvanou \uv{sekcí} a \uv{stránkou}. Každá sekce může mít vlastní obsah, ovšem může obsahovat i další subsekce, díky čemuž lze dělit obsah do stromové struktury. Stránka slouží pouze k předání obsahu a nikoliv k dalšímu větvení struktury. Dá se tedy říci, že stránka reprezentuje list v rámci stromovité struktury. Kořenem celého stromu je speciální sekce s názvem \uv{index}. Každá tato část standardně využívá vlastní HTML šablonu, to není ovšem pravidlo a každá část větve může využívat jinou šablonu. To je užitečné například u stránek s různými druhy obsahu. V rámci modelového webu zůstává druh obsahu stejný a není tedy třeba odchylovat se od standardní struktury. -Soubory se šablonami se nachází ve složce \texttt{templates/}, ve které generátor vždy očekává šablonu \texttt{index.html}. Ta se využívá jak k vykreslení úvodní kořenové stránky, tak ji mohou ostatní šablony rozšiřovat. Tato kořenová šablona tedy obsahuje základní strukturu celé stránky, přičemž navazující šablony jen mění určité části obsahu a nedefinují celou strukturu znovu. +Soubory se šablonami se nachází ve složce \texttt{templates/}, ve které generátor vždy očekává šablonu \texttt{index.html}. Ta se využívá jak k vykreslení úvodní kořenové stránky, tak jako základ, kterou mohou ostatní šablony rozšiřovat. Tato kořenová šablona tedy obsahuje základní strukturu celé stránky, přičemž navazující šablony jen mění určité části obsahu a nedefinují celou strukturu znovu. Generátor v šablonách hledá vlastní řídící sekvence, které se popisují závorkami. Existují tři druhy kombinací, které lze použít: @@ -102,7 +102,7 @@ Název stránky zůstane stejný a v jejím těle přibude text \uv{Ahoj, světe {% endblock %} \end{lstlisting} -Šablona \texttt{section.html} se v rámci generátoru Zola implicitně využívá pro všechny existující sekce\footnote{\url{https://www.getzola.org/documentation/content/section/}}. Názvem stránky v této šabloně bude, stejně jako u hlavní šablony, název stránky z konstanty \texttt{config.title} definované v konfiguračním souboru, ale také spojovník a název dané sekce. Za pseudo-výstup lze považovat například \uv{UČITEL ONLINE -- základní a střední škola}, bude-li se uživatel nacházet v sekci pro základní a střední školy. +Šablona \texttt{section.html} se v rámci generátoru Zola implicitně využívá pro všechny existující sekce\footnote{\url{https://www.getzola.org/documentation/content/section/}}. Názvem stránky v této šabloně bude, podobně jako u hlavní šablony, název stránky z konstanty \texttt{config.title} definované v konfiguračním souboru, ale také spojovník a název dané sekce. Za modelový výstup lze považovat například \uv{UČITEL ONLINE -- základní a střední škola}, bude-li se uživatel nacházet v sekci pro základní a střední školy. V bloku s obsahem bude původní obsah \uv{Ahoj, světe!} nahrazen za řetězec \uv{Toto je obsah kategorie}. Ten ovšem nechceme definovat přímo v šabloně, nýbrž cílem generátoru je vyplňovat obsah ze zdrojových souborů v sázecím jazyce, viz. sekce \ref{kap:princip-generatoru}. Zola pro vkládání obsahu využívá stejný princip jako v ostatních případech, tedy vypsání obsahu proměnné, v tomto případě proměnné \texttt{section.content}, která obsahuje zkompilované HTML z daného Markdown souboru. Zároveň je dobrou praktikou provést vyčištění vstupu filtrem \texttt{safe}\footnote{\url{https://tera.netlify.com/docs/\#safe}}. @@ -119,16 +119,16 @@ Z principu by žádný obsah neměl být definován přímo v šabloně, nýbrž \section{Automatické generování vícevrstvé navigace} -Obsah modelové implementace je dělen do stromové datové struktury o potenciálně nekonečné hloubce, kdy každá část větve je v rámci generátoru vlastní kategorií, nikoliv stránkou. Pro modelovou implementaci bylo zvoleno, aby navigace byla generována v návaznosti na aktivní cestu ve stromě. Ve stránce jsou dvě různé navigace, jedna hlavní a vždy vidiětelná, která obsahuje rozdělení obsahu dle škol a druhá navigace, která zobrazuje aktivní větev stromu. +Obsah modelové implementace je dělen do stromové datové struktury o potenciálně nekonečné hloubce, kdy každá část větve je v rámci generátoru vlastní kategorií, nikoliv stránkou. Pro modelovou implementaci bylo zvoleno, aby navigace byla generována v návaznosti na aktivní cestu ve stromě. Ve stránce jsou dvě různé navigace, hlavní, která je vždy viditelná a obsahuje rozdělení obsahu dle škol a vedlejší, která zobrazuje aktivní větev stromu. \begin{figure}[h]\centering \includegraphics{img/generovani-vicevrstve-navigace} \caption{Diagram průběhu generování vícevrstvé navigace} \end{figure} -První vrstvou struktury jsou hlavní sekce, v rámci implementace pojemnované jako $L_1$, které jsou vypsány vždy ve vlastní navigaci. Pod touto navigací je zobrazen seznam všech kategorií, které vybraná položka v $L_1$ obsahuje. Pokud uživatel zvolí kteroukoliv položku v $L_2$, v navigaci se objeví další sloupec, který obsahuje všechny podkategorie vybrané položky, tedy všechny podkategorie ve vrstvě $L_3$. Takto lze stromem procházet potenciálně do nekonečna. Styly modelové šablony ovšem počítají s maximální hloubkou čtyř subkategorií. +První vrstvou struktury jsou hlavní sekce, v rámci implementace pojmenované jako $L_1$, které jsou vypsány vždy ve vlastní navigaci. Pod touto navigací je zobrazen seznam všech kategorií, které vybraná položka v $L_1$ obsahuje. Pokud uživatel zvolí kteroukoliv položku v $L_2$, v navigaci se objeví další sloupec, který obsahuje všechny podkategorie vybrané položky, tedy všechny podkategorie ve vrstvě $L_3$. Takto lze stromem procházet potenciálně do nekonečna. Styly modelové šablony ovšem počítají s maximální hloubkou čtyř subkategorií. -Tato funkcionalita je implementována pomocí tří cyklů, z níchž jeden je vložený. První cyklus (příklad \ref{lst:obsah-cyklus1}) se provádí pro všechny rodiče aktivní ktegorie vrstev $L_2,L_3,\dotsc,L_n$, kde $n$ je aktuílní vrstva. V každé iteraci se mění kontext, ve kterém generátor pracuje. Z daného kontextu generátor vypisuje pomocí vnořeného cyklem všechny subkategorie. Ve druhém cyklu (příklad \ref{lst:obsah-cyklus2}) se vypisují všichni potomci dané stránky, tedy potomci ve vrstvě $L_{n+1}$. +Tato funkcionalita je implementována pomocí tří cyklů, z nichž jeden je vložený. První cyklus (příklad \ref{lst:obsah-cyklus1}) se provádí pro všechny rodiče aktivní kategorie vrstev $L_2,L_3,\dotsc,L_n$, kde $n$ je aktuální vrstva. V každé iteraci se mění kontext, ve kterém generátor pracuje. Z daného kontextu generátor vypisuje pomocí vnořeného cyklem všechny subkategorie. Ve druhém cyklu (příklad \ref{lst:obsah-cyklus2}) se vypisují všichni potomci dané stránky, tedy potomci ve vrstvě $L_{n+1}$. \begin{lstlisting}[label=lst:obsah-cyklus1,caption=Cyklus pro vypisování všech rodičů v dané větvi navigace] {% if section.ancestors %} @@ -164,23 +164,23 @@ Tato funkcionalita je implementována pomocí tří cyklů, z níchž jeden je v \section{Rozšíření šablony}\label{kap:rozsireni-sablony} -Ve výchozím stavu generátor neumí vkládat nic jiného, než je uvedeno ve specifikaci CommonMark, viz. sekce \ref{kap:markdown}. Dle požadavků modelového webu je nutné, aby generátor uměl vkládat videa přímo do stránky. Taková funkcionalita není soušástí specifikace CommonMark a je tedy potřeba rozšířit generátor. Nejvhodnějším způsobem přidání vlastních funkcionalit je využití filtrů, které se v rámci generátoru nazývají \uv{shortcode}. +Ve výchozím stavu generátor neumí zpracovávat nic jiného, než co je uvedeno ve specifikaci CommonMark, viz. sekce \ref{kap:markdown}. Dle požadavků modelového webu je nutné, aby generátor uměl vkládat videa přímo do stránky. Taková funkcionalita není součástí specifikace CommonMark a je tedy potřeba rozšířit generátor. Nejvhodnějším způsobem přidání vlastních funkcionalit je využití filtrů, které se v rámci generátoru nazývají \uv{shortcode}. -Principem vlastních filtrů je to, že si uživatel vytvoří vlastní šablonu, kterou lze vyvolat speciální řídící sekvencí přímo z obsahu. Každý tento shortcode může pracovat s libovolným množstvím proměnných a po zpracování vloží do místa vyvolání zkompilovaný HTML kód. Lze tedy tvrdit, že shortcode je v své podstatě imperativní funkce, která umí pracovat s parametry. +Principem vlastních filtrů je to, že si uživatel vytvoří vlastní šablonu, kterou lze vyvolat pomocí speciální řídící sekvence přímo z obsahu. Každý tento shortcode může pracovat s libovolným množstvím proměnných a po zpracování vloží do místa vyvolání zkompilovaný HTML kód. Dá se tedy říci, že shortcode je v své podstatě funkce, která umí pracovat s parametry. -Pro tvorbu těchto filtrů je v generátoru Zola určena složka \texttt{templates/shortcodes}, která obsahuje jejich HTML šablony a kód pro zpracování generátorem. Název HTML souboru definuje název vlastního filtru. Vytvoříme-li uvitř této složky soubor nazvaný \texttt{video.html}, budeme v obsahu schopni využívat vlastní filtr s názvem \texttt{video}. +Pro tvorbu těchto filtrů je v generátoru Zola určena složka \texttt{templates/shortcodes}, která obsahuje jejich HTML šablony a kód pro zpracování generátorem. Název HTML souboru definuje název vlastního filtru. Vytvoříme-li uvnitř této složky soubor nazvaný \texttt{video.html}, budeme v obsahu schopni využívat vlastní filtr s názvem \texttt{video}. \begin{lstlisting}[label=lst:jednoduchy-filtr,caption=Příklad jednoduchého filtru s jedním atributem] \end{lstlisting} -V příkladu \ref{lst:jednoduchy-filtr} bude filtr očekávat atribut \texttt{src} a bude vracet jednoduchý HTML kód pro vložení videa do stránky. Tento filtr lze vyvolat kdekoliv v obsahu, tedy v kterémkoliv souboru s koncovkou \texttt{.md}. Za názvem filtru se do závorky uvádí parametry oddělené čárkou. U posledního parametru se čárky nevuvádí, což platí i v případě, kdy se uvádí pouze jeden parametr, jako je tomu v příkladu \ref{lst:vyvolani-filtru}. +V příkladu \ref{lst:jednoduchy-filtr} bude filtr očekávat atribut \texttt{src} a bude vracet jednoduchý HTML kód pro vložení videa do stránky. Tento filtr lze vyvolat kdekoliv v obsahu, tedy v kterémkoliv souboru s koncovkou \texttt{.md}. Za názvem filtru se do závorky uvádí parametry oddělené čárkou. U posledního parametru se čárky neuvádí, což platí i v případě, kdy se uvádí pouze jeden parametr, jako je tomu v příkladu \ref{lst:vyvolani-filtru}. \begin{lstlisting}[label=lst:vyvolani-filtru,caption=Vyvolání vlastního filtru s jedním parametrem] {{ video(src="video.webm") }} \end{lstlisting} -V rámci vybraného generátoru není nutné specifikovat atributy na jeden řádek a lze je pro přehlednost vypisovat na více řádků, jako tomu je například u programu \ref{lst:formatovani-atributu}, zůstane-li dodržena koncepce oddělení atributů čárkou, tedy že poslední atribut vždy zůstane bez čárky. Výstupem této direktivy bude následující HTML kód. +V rámci vybraného generátoru není nutné specifikovat atributy na jeden řádek a lze je pro přehlednost vypisovat na více řádků, jako tomu je například u programu \ref{lst:formatovani-atributu}, zůstane-li dodržen způsob oddělování atributů čárkou, tedy že poslední atribut vždy zůstane bez čárky. Výstupem této direktivy bude následující HTML kód. \begin{lstlisting}[caption=Výstup direktivy z příkladu \ref{lst:jednoduchy-filtr}] @@ -200,7 +200,7 @@ Součástí požadavků pro modelový web jsou i citace přiložených souborů {% endif %} \end{lstlisting} -Filtr je možné opět vyvolat pomocí stejné direktivy kdekoliv v obsahu, ovšem nyní lze libovolně přidat parametry pro metadata. +Filtr je opět možné vyvolat pomocí stejné direktivy kdekoliv v obsahu, ovšem nyní lze libovolně přidávat parametry pro metadata. \begin{lstlisting}[label=lst:formatovani-atributu,caption=Vyvolání filtru \ref{lst:filtr-s-podminkami} s formátováním na řádky] {{ video( @@ -211,16 +211,16 @@ Filtr je možné opět vyvolat pomocí stejné direktivy kdekoliv v obsahu, ovš ) }} \end{lstlisting} -Protože byly zadány všechny povinné i nepovinné atributy, výtupem toho filtru budou i části kódu s metadaty. +Protože byly zadány všechny povinné i nepovinné atributy, výstupem toho filtru budou i části kódu s metadaty. \begin{lstlisting}[caption=Výstup direktivy z příkladu \ref{lst:formatovani-atributu}] - +

\end{lstlisting} - Pro modelový web byla zvážena možnost vypisování obsahu automaticky, tedy že program zkontroluje složku s obsahem a pokud narazí na soubor se specifikovanou koncovkou, vypíše jej do obsahu podle daných pravidel. Generátor Zola umožňuje prohledávání složek a práci se soubory, v rámci Zoly takzvanými \uv{assety}. Tuto funkcionalitu lze tedy implementovat jednoduchým cyklem a filtem, které zpracují všechny případné soubory ve složce dané stránky. Zoubory lze filtrovat mnoha způsoby, z nichž je nejuniverzálnější funkce \texttt{matching()}, která dovoluje filtrovat vstup regulárními výrazy dle implementace regex v jazyce Rust\footnote{\url{https://docs.rs/regex/1.3.6/regex/}}. V následujícím příkladu je pro ilustraci této funkcionality implementován program vypisující obrázky s předem definovanými koncovkami. +Pro modelový web byla zvážena možnost vypisování obsahu automaticky, tedy že program projde složku s obsahem a pokud narazí na soubor se specifikovanou koncovkou, vypíše jej do obsahu podle daných pravidel. Generátor Zola umožňuje prohledávání složek a práci se soubory, pro které se v rámci Zoly používá termín \uv{assety}. Tuto funkcionalitu lze tedy implementovat jednoduchým cyklem a filtrem, které zpracují všechny případné soubory ve složce dané stránky. Soubory lze filtrovat mnoha způsoby, z nichž je nejuniverzálnější funkce \texttt{matching()}, která dovoluje filtrovat vstup regulárními výrazy dle jejich implementace v jazyce Rust\footnote{\url{https://docs.rs/regex/1.3.6/regex/}}. V následujícím příkladu je pro ilustraci této funkcionality implementován program vypisující obrázky s předem definovanými koncovkami. \begin{lstlisting}[caption=Automatický výpis obrázků s pevně definovanými koncovkami] {% if section.assets %} @@ -232,7 +232,7 @@ Protože byly zadány všechny povinné i nepovinné atributy, výtupem toho fil {% endif %} \end{lstlisting} -Toto řešení ovšem není ve výsledném modelu implemntováno, protože jedním z požadavků je možnost vkládání souborů na libovolné místo v obsahu. Na stejném principu je ovšem vytvořen filtr pro vládání souborů, který tento požadavek splňuje. Výhodou filtru je, že ho lze vyvolat kdekoliv v obsahu a není vázán na pevně dané místo v šabloně. Ten očekává alespoň jeden parametr uvádějící název souboru bez koncovky, pro dle kterého pak filtr vyhledá všechny různé formáty s tímto názvem a ty vloží do stránky. Druhým libovolným parametrem je název souboru, který se do stránky vloží místo názvu souboru. to umožňuje uivateli volně pracovat s názvy souborů v souborvé struktuře bez ovlivnění obsahu stránky. +Toto řešení ovšem není ve výsledném modelu implementováno, protože jedním z požadavků je možnost vkládání souborů na libovolné místo v obsahu. Na stejném principu je vytvořen filtr pro vkládání souborů, který tento požadavek splňuje. Výhodou filtru je, že ho lze vyvolat kdekoliv v obsahu a není vázán na pevně dané místo v šabloně. Ten očekává alespoň jeden parametr uvádějící název souboru bez koncovky, podle kterého pak filtr vyhledá všechny různé formáty s tímto názvem a ty vloží do stránky. Druhým libovolným parametrem je název souboru, který se do stránky vloží místo názvu souboru. To umožňuje uživateli volně pracovat s názvy souborů v souborové struktuře bez ovlivnění obsahu stránky. \begin{lstlisting}[label=lst:filtr-souboru,caption=Filtr pro výpis souborů s automatickým hledáním] {% if section.assets and filename %} @@ -253,9 +253,9 @@ Toto řešení ovšem není ve výsledném modelu implemntováno, protože jedn {% endif %} \end{lstlisting} -V první části filtr zkontroluje, zda byl vyplněn parametr \texttt{title} a v přípdě že ano, nastaví ho jako název souoru v obsahu. V opačném případě využije název souboru samotného. Ve druhém kroku nastává kontrola, zda se ve složce nacházejí soubory (mimo hlavní soubor \texttt{\_index.md}) a pokud ano, přes všechny soubory se iteruje kontrola, zda soubor splňuje podmínku názvu. Kontrola této podmínky je tvořena kombinací proměnných generátoru a regulárního výrazu. Každý soubor který splňuje podmínku je poté vypsán do obahu jako přímý odkaz k jeho stažení. +V první části filtr zkontroluje, zda byl vyplněn parametr \texttt{title} a v případě, že ano, nastaví ho jako název souboru v obsahu. V opačném případě využije název souboru samotného. Ve druhém kroku nastává kontrola, zda se ve složce nacházejí soubory (mimo hlavní soubor \texttt{\_index.md}) a pokud ano, tak se iterativně zkontrolují všechny soubory, zda splňují podmínku názvu. Kontrola této podmínky je tvořena kombinací proměnných generátoru a regulárního výrazu. Každý soubor, který splňuje podmínku je poté vypsán do obsahu jako přímý odkaz k jeho stažení. -Jako text v odkazu se použije koncovka souboru, která se záskává spojením několika filtrů, tedy filtru \texttt{split(pat=".")}, který rozdělí řetězec podle znaku tečka do pole a navazující filtr \texttt{last} vrátí poslední položku v poli. Tím filtr získá samotnou koncovku souboru. +Jako text v odkazu se použije koncovka souboru, která se získává spojením několika filtrů, tedy filtru \texttt{split(pat=".")}, který rozdělí řetězec podle znaku tečka do pole a navazující filtr \texttt{last} vrátí poslední položku v poli. Tím filtr získá samotnou koncovku souboru. Filtr lze vyvolat stejně, jako je tomu u filtru pro vkládání videa. Název filtru je opět definován názvem souboru \texttt{tmeplates/shortcodes/document.html} a bude jím tedy název \texttt{document()}. @@ -266,7 +266,7 @@ Filtr lze vyvolat stejně, jako je tomu u filtru pro vkládání videa. Název f ) }} \end{lstlisting} -V příkladu \ref{lst:vyvolani-filtru-souboru} je definován i nepovinný atribut \texttt{title}, který kvůli přehlednosti umožňuje nastavit název. Atribut \texttt{filename} definuje název souboru ve složce bez koncovky. Všechny soubory, které chce uživatel vypsat, musí tedy mít stejný název a musí se lišit pouze koncovkou. Jsou li ve složce soubory s názvem \texttt{pracovni-list} a koncovkami \texttt{pdf}, \texttt{odt}, \texttt{djvu} a \texttt{ps}, bute výstupem filtru následující HTML. +V příkladu \ref{lst:vyvolani-filtru-souboru} je definován i nepovinný atribut \texttt{title}, který kvůli přehlednosti umožňuje nastavit název. Atribut \texttt{filename} definuje název souboru ve složce bez koncovky. Všechny soubory, které chce uživatel vypsat, musí tedy mít stejný název a musí se lišit pouze koncovkou. Jsou li ve složce soubory s názvem \texttt{pracovni-list} a koncovkami \texttt{pdf}, \texttt{odt}, \texttt{djvu} a \texttt{ps}, bude výstupem filtru následující HTML. \begin{lstlisting}[caption=Výstup direktivy z příkladu \ref{lst:vyvolani-filtru-souboru}]
@@ -282,21 +282,21 @@ V příkladu \ref{lst:vyvolani-filtru-souboru} je definován i nepovinný atribu Optimalizace modelové implementace je provedena na základě článku ze serveru \cite{calomel_optimization}, který se věnuje sestavením užitečných rad pro optimalizaci webových stránek na serverech s omezeným připojením do sítě a pro zvýšení spokojenosti uživatelů z užívání optimalizovaného webu, jak je rozebráno v sekci \ref{kap:vyhody-statickych-webovych-stranek}. -Jak se na webu Colomel píše, provozování webserveru může být hodnotná zkušenost, ale zároveň může být i zkouškou trpělivosti. Chcete svým uživatelům předávat všechny vaše stránky a obrázky, ovšem máte jen omezenou šířku pásma, pomocí které můžete data přenášet. Pokud přetížíte své pipojení, klienti nevštěvující váš web server si budou myslet, že je pomalý a neresponzivní. Je tedy třeba webový server nastavit tím nejlepším možným způsobem s cílem získat co nejvíce návštěv a zlepšit zážitek vašim návštěvníkům. Následující rady slouží ke snížení zátěže serveru, ke zrcyhlení odesílání stránek a k zastavení nechtěnného a škodlivého provozu. +Jak se na webu Colomel píše, provozování webserveru může být hodnotná zkušenost, ale zároveň může být i zkouškou trpělivosti. Chcete svým uživatelům předávat všechny vaše stránky a obrázky, ovšem máte jen omezenou šířku pásma, pomocí které můžete data přenášet. Pokud přetížíte své připojení, klienti navštěvující váš web server si budou myslet, že je pomalý a neresponzivní. Je tedy třeba webový server nastavit tím nejlepším možným způsobem s cílem získat co nejvíce návštěv a zlepšit zážitek vašim návštěvníkům. Následující rady slouží ke snížení zátěže serveru, ke zrychlení odesílání stránek a k zastavení nechtěného a škodlivého provozu. Práce se věnuje pouze technickým optimalizacím spojených s tvorbou samotné webové stránky, nikoliv však optimalizacím sítě, web serveru a vizuálního návrhu. Nenačítá-li se stránka během několika vteřin, většina uživatelů jednoduše odejde. Cílem této sekce je provést optimalizace, které urychlí načítání modelové implementace. \subsection{Typy a kvalita obrázků} -Fotografie a grafika využívají mnohem více dat pro přenos než běžný HTML text a je tedy nutné provést optimalizaci (kompresi) obrázků na co nejmenší možnou velikost souborů. Obrázky není třeba renderovat na více než 72 dpi a pro každý druh grafiky je třeba zvolit vhodný tofmát, tj. formát JPEG pro fotografie a formáty PNG či SVG pro jednoduchou grafiku. Rastrové obrázky mají pouze potřebné rozlišení, tedy maximálně hodnotu největšího rozlišení, které se ve stránce bude zobrazovat. Klíčové je také nevyužívat obrázky v případě, kde je lze nahradit čístým HTML a CSS. +Fotografie a grafika využívají mnohem více dat pro přenos než běžný HTML text a je tedy nutné provést optimalizaci (kompresi) obrázků na co nejmenší možnou velikost souborů. Obrázky není třeba renderovat na více než 72 dpi a pro každý druh grafiky je třeba zvolit vhodný formát, tj. formát JPEG pro fotografie a formáty PNG či SVG pro jednoduchou grafiku. Rastrové obrázky mají pouze potřebné rozlišení, tedy maximálně hodnotu největšího rozlišení, které se ve stránce bude zobrazovat. Klíčové je také nevyužívat obrázky v případě, kde je lze nahradit čistým HTML a CSS. Obrázky ve formátu JPEG mají velice efektivní ztrátovou kompresi, pomocí které lze zredukovat velikost obrázku o značnou část. Autor článku tvrdí, že většinu obrázků lze komprimovat až o 50\% bez viditelné ztráty na kvalitě. Své obrázky dokonce zkomprimoval ze 27 kilobajtů na pouhých 8 kilobajtů s JPEG kompresí 60\%. \subsection{Ikona \textit{favicon.ico}} -Původně je \textit{favicon.ico} výtvorem firmy Microsoft, kdy její Internet Explorer automaticky odesílal požadavek na pevnou URL \texttt{/favicon.ico} od kořene webového serveru. Jde o malou ikonku, která se dnes zobrazuje u každé záložky s webovou stránkou. Problémem je to, že se požadavkům o ní nelze vyhnout a vždy se počítá s tím, že ikona na web serveru existuje. Odesílá se vždy s každou stránkou a některé prohlížeče se po ní dotazují z neznámých důvodu dvakrát. Autor článku uvádí, že u některých serverů bylo až 30\% přenesených dat využito jen na servírování ikony. +Původně je \textit{favicon.ico} výtvorem firmy Microsoft, kdy Internet Explorer automaticky odesílal požadavek na pevnou URL \texttt{/favicon.ico} od kořene webového serveru. Jde o malou ikonku, která se dnes zobrazuje u každé záložky s webovou stránkou. Problémem je, že se požadavkům o ní nelze vyhnout a vždy se počítá s tím, že ikona na web serveru existuje. Odesílá se vždy s každou stránkou a některé prohlížeče se po ní dotazují z neznámých důvodu dvakrát. Autor článku uvádí, že u některých serverů bylo až 30\% přenesených dat využito jen na odesílání ikony. -Principem optimalizace je udržet ikonu ji co nejmenší, v nejlepším případě tak malou, že se vejde do jednoho TCP paketu, tedy do velikosti 1460 bajtů na většině systémů. Toho lze docílit tím, že ikona nebude větší než 16x16 pixelů s nízkou barevnou hloubkou, nejlépe s pouze čtyřmi barvami. Také je možné poslat pouze 1x1 pixelů veliký prázdný obrázek, nebo vracet stavový kód 204\footnote{204 No Content -- Server úspěšně zpracoval požadavek, ale nevrací žádný obsah.} a neodesílat ikonu žádnou. +Principem optimalizace je udržet ikonu co nejmenší, v nejlepším případě tak malou, že se vejde do jednoho TCP paketu, tedy do velikosti 1460 bajtů na většině systémů. Toho lze docílit tím, že ikona nebude větší než 16x16 pixelů s nízkou barevnou hloubkou, nejlépe s pouze čtyřmi barvami. Také je možné poslat pouze 1x1 pixelů veliký prázdný obrázek, nebo vracet stavový kód 204\footnote{204 No Content -- Server úspěšně zpracoval požadavek, ale nevrací žádný obsah.} a neodesílat ikonu žádnou. \subsection{Obecné HTML optimalizace} @@ -311,13 +311,13 @@ Redukcí nepotřebných znaků v HTML lze také ušetřit značnou část přeno \item recyklování již použitých obrázků a tlačítek. \end{itemize} -K odstranění přebytečných mezer, zalomení řádků, HTML komentářů a prázdných řádků lze použít automatický filtr, který provede kompresi výstupu. \todo{Přesunout do návrhu pro rozšíření?}Generátor Zola provádí kompresi CSS, ovšem nemá zabudovanou funkcionalitu pro minifikaci výsledného HTML, která je ovšem v době psaní této práce vyvíjena\footnote{\url{https://github.com/getzola/zola/issues/542}}. +K odstranění přebytečných mezer, zalomení řádků, HTML komentářů a prázdných řádků lze použít automatický filtr, který provede kompresi výstupu. \todo{Přesunout do návrhu pro rozšíření?}Generátor Zola provádí kompresi CSS, ovšem nemá zabudovanou funkcionalitu pro minifikaci výsledného HTML, která je v době psaní této práce vyvíjena\footnote{\url{https://github.com/getzola/zola/issues/542}}. Touto redukcí lze ušetřit 2\% přenosu dat oproti ručně psanému neoptimalizovanému kódu. Je-li průměrná velikost stránky sto kilobajtů, lze touto optimalizací ušetřit dva kilobajty při každém odeslání stránky. Při odeslání sta tisíce stránek za měsíc je ve výsledku ušetřeno dvě stě megabajtů dat, které jsou jinak zbytečně odesílány uživatelům, kteří je stejně nezobrazí. Další obecné rady pro optimalizaci HTML jsou uvedeny na serveru \cite{yahoo_optimization}, kde se uvádí spousta dalších způsobů ke zrychlení načítání stránky a k nižšímu vytížení sítě. -Připojením externích CSS a JavaScript souborů je umožněno jejich ukládání do paměti cache, což snižuje HTTP požadavky vůči serveru. Je-li obsah těchto souborů přímo ve stránce, je odesílán pokaždé s novou stránkou a to vede ke zbytečnému vytěžování sítě. S tím souvísí i velikost stránek, kdy soubory větší než je daná maximální velikost se do paměti cache neukládají a je proto dobré tuto velikost nepřekračovat. +Připojením externích CSS a JavaScript souborů je umožněno jejich ukládání do paměti cache, což snižuje HTTP požadavky vůči serveru. Je-li obsah těchto souborů přímo ve stránce, je odesílán pokaždé s novou stránkou a to vede ke zbytečnému vytěžování sítě. S tím souvisí i velikost stránek, kdy soubory větší než je daná maximální velikost se do mezipaměti neukládají a je proto dobré tuto velikost nepřekračovat. \quest[inline]{U starých zařízení jsou pevně dané velikosti, například v roce 2011 byly limity 25.6K u iOS nebo 5M u Firefoxu. Mám je zde uvádět, i když se to rychle mění, nebo to stačí takhle obecně?} @@ -325,7 +325,7 @@ Připojením externího CSS přímo do hlavičky je umožněno progresivní vykr Je také důležité udržovat validní HTML, kdy například chybějící atribut \texttt{src=""} způsobuje odesílání nevyžádaných požadavků na server. -\quest[inline]{HTML5 už specifikuje, aby prohlížeče kvůli prázdnému \textit{src} neposílaly další požadavaek. Je tedy nutné uvádět tento příklad?} +\quest[inline]{HTML5 už specifikuje, aby prohlížeče kvůli prázdnému \textit{src} neposílaly další požadavek. Je tedy nutné uvádět tento příklad?} \subsection{Videa a jejich vložení do stránky} @@ -333,19 +333,19 @@ Je také důležité udržovat validní HTML, kdy například chybějící atrib \section{Správa obsahu a verzování} -Statické stránky neumožňují správu uživatelů v prámci webové aplikace, tedy že se případný editor nebo administrátor přihlásí a upravuje obsah klikáním, či psaním ve WYSIWYG\footnote{What You See Is What You Get -- Princip editoru který během psaní formátuje text tak, jak bude ve výsledku vypadat, například LibreOffice Writer atd.} editoru. Správu uživatelů lze jednoduše řešit omezením přístupu na web server, kde jen oprávnění uživatelé mohou do obsahu zasahovat. To je ovšem velmi tězkopádné řešení, protože neumožňuje práci více uživatelům najednou a neudržuje předešlé verze obsahu a historii úprav. Lepší alternativou je využití některého verzovacího systému. Pro účely modelové implementace byl vybrán distribuovaný verzovací systém Git, jak je vysvětleno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}. +Statické stránky neumožňují správu uživatelů v rámci webové aplikace, tedy, že se případný editor nebo administrátor přihlásí a upravuje obsah klikáním, či psaním ve WYSIWYG\footnote{What You See Is What You Get -- Princip editoru který během psaní formátuje text tak, jak bude ve výsledku vypadat, například LibreOffice Writer atd.} editoru. Správu uživatelů lze jednoduše řešit omezením přístupu na web server, kde jen oprávnění uživatelé mohou do obsahu zasahovat. To je ovšem velmi těžkopádné řešení, protože neumožňuje práci více uživatelům najednou a neudržuje předešlé verze obsahu a historii úprav. Lepší alternativou je využití některého verzovacího systému. Pro účely modelové implementace byl vybrán distribuovaný verzovací systém Git, jak je vysvětleno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}. -V tomto systému jsou soubory uloženy repozitářích, kde každý projekt je vlastní repozitář. V rámci repozitáře se ukládají všechny změny obsahu v takzvaných \uv{commitech}, nebo-li záznamech o provedených změnách včetně krátkého popisu a jejich autora. Tyto revize lze provádět v různých větvích repozitáře a větve je možné mezi sebou spojovat a kombinovat. Je také možné vracet se do kteréhokoliv bodu v historii v rámci každé větvě. +V tomto systému jsou soubory uloženy v repozitářích, kde každý projekt je vlastní repozitář. V rámci jednotlivých repozitářů se ukládají všechny změny obsahu prostřednictvím takzvaných \uv{commitech}, nebo-li záznamů o provedených změnách včetně jejich krátkého popisu a autora. Tyto revize lze provádět v různých větvích repozitáře a větve je možné mezi sebou spojovat a kombinovat. Je také možné vracet se do kteréhokoliv bodu v historii v rámci každé větvě. -Nastane-li konflikt při nahrávání změn, umoňujě Git jejich snadné vyřešení. Konflikt je stav, kdy například dva různí uživatelé provedli úpravy na stejném místě stejného souboru a snaží se je nahrát do repozitáře. Git v tuto chvíli druhého uživatele upozorní, že původní soubor byl změněn a je třeba tento konflikt vyřešit. Zamezuje se tedy přepsání změn prvního uživatele. +Nastane-li konflikt při nahrávání změn, umožňuje Git jejich snadné vyřešení. Konflikt je stav, kdy například dva různí uživatelé provedli úpravy na stejném místě stejného souboru a snaží se je nahrát do repozitáře. Git v tuto chvíli druhého uživatele upozorní, že původní soubor byl změněn a je třeba tento konflikt vyřešit. Zamezuje se tedy přepsání změn prvního uživatele. -K systému Git existují různé služby, které tento systém rozšiřují i webové grafické rozhraní se spoustou dalších rozšíření. Nejčastěji používanými službami jsou GitHub\footnote{\url{https://github.com/}}, GitLab\footnote{\url{https://gitlab.com/}}, nebo Bitbucket\footnote{\url{https://bitbucket.org/}}, z nichž některé lze provozovat na vlastním serveru. Snadným systémem pro vlastní provozování je také program Gitea\footnote{\url{https://gitea.com/}}, který je oproti předem zmíněným systémům zcela svobodným sotwarem a je velmi jednoduchý na instalaci a správu. Tyto systémy mají navíc integrovaný jednoduchý WYSIWYG editor pro úpravu souborů přímo z webového rozhraní a také umí renderovat soubory s obsahem napsaným v jazyce Markdown, který je popsán v sekci \ref{kap:markdown}. +K systému Git existují různé služby, které tento systém rozšiřují o webové grafické rozhraní s množstvím dalších rozšíření. Nejčastěji používanými službami jsou GitHub\footnote{\url{https://github.com/}}, GitLab\footnote{\url{https://gitlab.com/}}, nebo Bitbucket\footnote{\url{https://bitbucket.org/}}, z nichž některé lze provozovat na vlastním serveru. Snadným systémem pro vlastní provozování je také program Gitea\footnote{\url{https://gitea.com/}}, který je oproti předem zmíněným systémům zcela svobodným softwarem a je velmi jednoduchý na instalaci a správu. Tyto systémy mají navíc integrovaný jednoduchý WYSIWYG editor pro úpravu souborů přímo z webového rozhraní a také umí renderovat soubory s obsahem napsaným v jazyce Markdown, který je popsán v sekci \ref{kap:markdown}. \subsection{Automatizace generování obsahu}\label{kap:automaticke-generovani-obsahu} Tato část práce se věnuje samotné implementaci automatického generování obsahu na základě změn v repozitáři. -Jak bylo zmíněno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}, git umožňuje nastavení takzvaných \uv{hooks}, které se v určité chvíli spustí. Jak uvádí dokuemntace\footnote{\url{https://git-scm.com/docs/githooks}}, existuje spousta druhů hooků, které jsou vyvolány v různé části zpracování požadavku. V případě této implementace je nejvhodnější hook \textit{post-receive}, který je spouštěn až po nahrání a zpracování všech změn v repozitáři. +Jak bylo zmíněno v sekci \ref{kap:vyber-vhodneho-systemu-verzovani}, git umožňuje nastavení takzvaných \uv{hooks}, které se v určité chvíli spustí. Jak uvádí dokumentace\footnote{\url{https://git-scm.com/docs/githooks}}, existuje spousta druhů hooků, které jsou vyvolány v různé části zpracování požadavku. V případě této implementace je nejvhodnější hook \textit{post-receive}, který je spouštěn až po nahrání a zpracování všech změn v repozitáři. Následující skript po vyvolání Gitem provede veškeré potřebné operace ke zpracování nového obsahu na web serveru. @@ -374,11 +374,11 @@ rsync --recursive --delete --checksum \ public/ "$WEBROOT" \end{lstlisting} -Skript \ref{lst:git-hook-skript} je složen z několika částí. Jako první probíhá na řádcích 1--3 nastavení proměnných, ve kterých se ukládá odkaz na vzdálený Git repozitář, název složky, do které se obsah má klonovat a název složky do které se má kopírovat výstup, nebo-li vygenerované HTML. Dále se skript na řádku 5 přepíná do složky, ve které se sám nachází, proto aby skript fungoval vždy, ať je spuštěný ze kteréhokoliv místa v souborovém systému. +Skript \ref{lst:git-hook-skript} je složen z několika částí. Jako první probíhá na řádcích 1--3 nastavení proměnných, ve kterých se ukládá odkaz na vzdálený Git repozitář, název složky, do které se obsah má klonovat a název složky, do které se má kopírovat výstup, nebo-li vygenerované HTML. Dále se skript na řádku 5 přepíná do složky, ve které se sám nachází, proto aby skript fungoval vždy, ať je spuštěný ze kteréhokoliv místa v souborovém systému. V další části skriptu probíhá na řádku 7 kontrola, zda již existuje složka s naklonovaným Git repozitářem. Pokud složka neexistuje, provede se naklonování vzdáleného repozitáře a tím i k vytvoření složky. -Třetí část provádí generování statického obsahu. Nejprve se skript přepne do repozitáře, v němž provede příkaz \texttt{git pull}, který do složky stáhne poslední změny ze vzdáleného repozitáře, tedy synchronizuje obsah na poslední verzi. Po synchronizaci repozitáře proběhne samotné spuštění generátoru, který z obsahu vygeneruje statické HTML, jenž vloží do složky \texttt{./public}. Poté na řádcích 12--14 probíhá kopírování nově vygenerovaného obsahu do složky \texttt{/srv/www/ucitelonline}, včetně nastavení Unixových práv na bezpečné hodnoty zvlášť pro složky a soubory. +Třetí část provádí generování statického obsahu. Nejprve se skript přepne do repozitáře, v němž provede příkaz \texttt{git pull}, který do složky stáhne poslední změny ze vzdáleného repozitáře, tedy synchronizuje obsah na poslední verzi. Po synchronizaci repozitáře proběhne samotné spuštění generátoru, který z obsahu vygeneruje statické HTML, jenž vloží do složky \texttt{./public}. Poté na řádcích 12--14 probíhá kopírování nově vygenerovaného obsahu do složky \texttt{/srv/www/ucitelonline}, včetně nastavení Unixových práv souborů na bezpečné hodnoty, které se liší pro složky a pro soubory. Skript spoléhá na to, že systém má již předem správně nakonfigurované uživatele, uživatelské skupiny, web server, a že jsou nainstalované potřebné programy Git, Rsync, generátor Zola. Systémový uživatel, pod kterým je vyvolán Git hook, musí být ve skupině \textit{www-data}, nebo v jiné skupině společně s uživatelem, pod kterým je spuštěn web server. Zároveň musí mít uživatel práva pro zápis do cílové složky \texttt{/srv/www/ucitelonline}. diff --git a/kap-paradigmata.tex b/kap-paradigmata.tex index eebbd45..18ee9b0 100644 --- a/kap-paradigmata.tex +++ b/kap-paradigmata.tex @@ -1,6 +1,6 @@ \chapter{Webová paradigmata} -Ve světě webových stránek se setkáváme se spoustou forem a paradigmat, která se hodí pro obsažení různých druhů informací. Neexistují žádné formální zařazení druhů webových stránek do skupin, ovšem některé webové portály se pokouší určit základní druhy webů, které se na Internetu objevují. Na základě těchto portálů a jejich rozřazení do skupin\footnote{\url{http://www.xislegraphix.com/website-types.html}}\footnote{\url{https://www.hostgator.com/blog/popular-types-websites-create}}\footnote{\url{https://www.quora.com/What-are-the-different-types-of-websites}}\todo{Přesunout odkazy pod jednu položku.}, které jsou často mířené na specifický obsah, lze vytvořit tři základní paradigmata, do kterých lze tyto weby zařadit. Jsou jimi: +Ve světě webových stránek se setkáváme se spoustou forem a paradigmat, která se hodí pro zpracování různých druhů informací. Neexistuje žádné formální zařazení druhů webových stránek do skupin, ovšem některé webové portály se pokouší určit základní druhy webů, které se na Internetu objevují. Na základě těchto portálů a jejich rozřazení do skupin\footnote{\url{http://www.xislegraphix.com/website-types.html}}\footnote{\url{https://www.hostgator.com/blog/popular-types-websites-create}}\footnote{\url{https://www.quora.com/What-are-the-different-types-of-websites}}\todo{Přesunout odkazy pod jednu položku.}, které jsou často mířené na specifický obsah, lze vytvořit tři základní paradigmata, do kterých lze tyto weby zařadit. Jsou jimi: \begin{itemize} \item{Webová prezentace} @@ -15,11 +15,11 @@ V této práci byl ke každému z paradigmat vybrán systém vhodný pro generov Nejbližší původním webům z dob vzniku WWW jsou webové prezentace, tedy stránky s jednoduchým obsahem, které slouží k předání informací čtenáři například formou článků. Do této skupiny lze zařadit portfolia, blog, online noviny a časopisy, firemní stránky, foto alba a podobně. Tento druh stránek se skvěle hodí ke statickému generování obsahu, který se odesílá všem uživatelům stejný a nemění se často. -Jako nejvhodnější systém pro generování webových prezentací byl vybrán software Zola. Ten je oproti jiným systémům výhodný tím, že je napsaný v jazyce Rust a je tedy snadno rozšiřitelný a mnohem rychlejší, než většina jeho alternativ \citep{benchmarks_game}. I s těmito výhodami si zachovává spousty funkcí a rysů, které lze najít v ostatních složitých systémech. Také je možné generátor zkompilovat do jednoho staticky linkovaného binárního souboru, se kterým se pracuje mnohem lépe, než se složitým frameworkem. +Jako nejvhodnější systém pro generování webových prezentací byl vybrán software Zola. Ten je oproti jiným systémům výhodný tím, že je napsaný v jazyce Rust a je tedy mnohem rychlejší a bezpečnější, než většina jeho alternativ \citep{benchmarks_game}. Kromě těchto výhod si zachovává většinu funkcí a rysů, které lze najít v ostatních složitých systémech. Také je možné generátor zkompilovat do jednoho staticky linkovaného binárního souboru, se kterým se pracuje mnohem lépe, než se složitým frameworkem. \section{Index všeobecných informací} -Za obecného zástupce tohoto druhu stránek lze považovat Wikipiedii, která podnítila vznik spousty jiných takzvaných \uv{Wiki systémů} a stránek. +Za obecného zástupce tohoto druhu stránek lze považovat Wikipedii, která podnítila vznik spousty jiných takzvaných \uv{Wiki systémů} a stránek. \section{Technická dokumentace} diff --git a/kap-taxonomie-pozadavku.tex b/kap-taxonomie-pozadavku.tex index 7d63639..f2c8657 100644 --- a/kap-taxonomie-pozadavku.tex +++ b/kap-taxonomie-pozadavku.tex @@ -1,6 +1,6 @@ \chapter{Taxonomie požadavků pro modelový web}\label{kap:taxonomie-pozadavku} -Tato kapitola se věnuje určení základních požadavků pro modelovou implementaci. Jsou zde shrnuta obecná kritéria, která často platí pro většinu webových prezentací, a také kritéria specifická pro modelovou implementaci v rámci této práce. Dle těchto kritérií je poté samotná implementace tvořena v následující kapitole \ref{kap:modelova-implementace}. +Tato kapitola se věnuje určení základních požadavků pro modelovou implementaci. Jsou zde shrnuta obecná kritéria, která platí pro většinu webových prezentací, a také kritéria specifická pro modelovou implementaci v rámci této práce. Dle těchto kritérií je poté samotná implementace tvořena v následující kapitole \ref{kap:modelova-implementace}. Jako modelová implementace byl zvolen web pro distribuci výukových materiálů a odkazů užitečných pro výuku. Tvorba těchto webových stránek je zadána Ústavem výzkumu a rozvoje vzdělávání Pedagogické fakulty Univerzity Karlovy za účelem usnadnění práce již aktivních učitelů v době šíření viru COVID-19. Stránky mají učitelům pomoci s přípravou distanční výuky a úkolů v době vyhlášení stavu nouze a celostátní karantény. Modelová implementace je tedy plně využívána v praxi mnoha pedagogy z celé republiky. Tuto implementaci lze ovšem použít na distribuci jakýchkoliv jiných výukových materiálů, či ke psaní a správě dokumentace. @@ -16,12 +16,12 @@ Stránky by měly být udržovatelné i po předání jinému správci a celý s Specifická kritéria jsou vytvořena na základě požadavků autorů obsahu, tedy učitelů, ze kterých každý má své specifické požadavky na funkce a vlastnosti, které musí obsah splňovat. Následující kritéria jsou souhrnem a kompromisem mezi všemi požadavky. -Stránky musí být staticky generované a není tedy žádoucí v rámci webu řešit uživatelské účty, přihlašování apod. Hlavním požadavkem pro sturkturu stránky je možnost dělit obsah na sekce dle druhu školy (základní škola, střední škola, vysoká škola atd.) a dále pak na subsekce podle předmětů a oborů. +Stránky musí být staticky generované a není tedy žádoucí v rámci webu řešit uživatelské účty, přihlašování apod. Hlavním požadavkem pro strukturu stránky je možnost dělit obsah na sekce dle druhu školy (základní škola, střední škola, vysoká škola atd.) a dále pak na subsekce podle předmětů a oborů. -Do samotného obsahu musí být možné vkládat přílohy ke stažení v různých formátech, obrázky a videa s možností jejich ocitování, tedy uvedení autora, názvu díla apod. Všechny přiložené soubory musí být distribuovatelné přímo z webových stránek, nikoliv s externích zdrojů. Všechna videa je nutné vložit do stránky a musí je být možné přehrát v nativním přehrávači prohlížeče bez nutnosti otevírání externích webových stránek či programů. V hlavičce každé stránky musí být možné specifikovat několik metadat: autora či seznam autorů obsahu, skupinu pro kterou je obsah určen a časovou dotaci. +Do samotného obsahu musí být možné vkládat přílohy ke stažení v různých formátech, obrázky a videa s možností jejich ocitování, tedy uvedení autora, názvu díla apod. Všechny přiložené soubory musí být distribuovatelné přímo z webových stránek, nikoliv z externích zdrojů. Všechna videa je nutné vložit do stránky a musí je být možné přehrát v nativním přehrávači prohlížeče bez nutnosti otevírání externích webových stránek či programů. V hlavičce každé stránky musí být možné specifikovat metadata: autora či seznam autorů obsahu, skupinu pro kterou je obsah určen a časovou dotaci. Obsah stránek musí být možné spravovat předem pověřenými uživateli a jeho změny musí být zaznamenávány v decentralizovaném verzovacím systému. Generování statického webu na základě změn obsahu je nutné řešit automatizovaně bez dalších zásahů správce, či manuálního nahrávání nového obsahu na webserver. \section{Kritéria pro šablony a design} -Obsah musí být snadno čitelný a zobrazitelný na každém druhu zařízení, tedy jak na monitorech s nadstandardní velikostí, tak na mobilních zařízeních. Zároveň musí být snadno čitelný, v nejlepším případě vysokokontrastní černý text na bílém pozadí s dostatečnou velikostí. Navigace v obsahu musí být jednoduchá a intuitivní a vzhled celé stránky konzistentní. Na stránce nesmí přesahovat objem vizuálních elementů nad obsahem. Relevantní obsah by měl být na jednom místě, nikoliv rozdělený na několik různých stránek, mezi kterými musí uživatel přecházet. +Obsah musí být snadno čitelný a zobrazitelný na každém druhu zařízení, tedy jak na monitorech s nadstandardní velikostí, tak na mobilních zařízeních. Zároveň musí být snadno čitelný, v nejlepším případě vysoko kontrastní černý text na bílém pozadí s dostatečnou velikostí. Navigace v obsahu musí být jednoduchá a intuitivní a vzhled celé stránky konzistentní. Na stránce nesmí přesahovat objem vizuálních elementů nad obsahem. Relevantní obsah by měl být na jednom místě, nikoliv rozdělený na několik různých stránek, mezi kterými musí uživatel přecházet. diff --git a/poznamky b/poznamky new file mode 100644 index 0000000..0526443 --- /dev/null +++ b/poznamky @@ -0,0 +1,5 @@ +- ocitovat financial times výzkum +- pro framework není český ekvivalent (framework znamená kostra, to nechceš lol) +- backend a frontend bys moh popsat max jako část serveru a část klienta, ale backend a frontend je lepší +- "U starých zařízení..." - řek bych, že můžeš zmínit max 4 fun nebo abys nahnal znaky lol +- "HTML5 už specifikuje" - nah vyjeb se na to lol -- 2.45.2 From e1d08ccbfc03bd8fbb05e270ea1bba4d62d16e24 Mon Sep 17 00:00:00 2001 From: Emil Miler Date: Thu, 30 Apr 2020 14:33:17 +0200 Subject: [PATCH 03/49] =?UTF-8?q?Opravy=20podle=20pozn=C3=A1mek=20od=20Luk?= =?UTF-8?q?=C3=A1=C5=A1e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kap-generatory.tex | 4 ++-- kap-markup.tex | 2 +- kap-modelova-implementace.tex | 4 ---- poznamky | 5 ----- prace.pdf | Bin 537467 -> 536127 bytes 5 files changed, 3 insertions(+), 12 deletions(-) delete mode 100644 poznamky diff --git a/kap-generatory.tex b/kap-generatory.tex index 6bab955..e101236 100644 --- a/kap-generatory.tex +++ b/kap-generatory.tex @@ -8,7 +8,7 @@ Dynamické stránky jsou generovány speciálně pro každého uživatele na zá Pro sdílení statického obsahu mezi různé uživatele stačí velmi jednoduchý HTTP server bez jakýchkoliv dalších modulů typu \textit{PHP}, \textit{Python} a dalších systémů, které by obsah dynamicky generovaly například z dat vytažených z databáze, nebo z uživatelského vstupu. Na straně serveru tedy nedochází ke zpracování obsahu těsně před jeho odesláním uživateli, čímž se v komunikaci mezi klientem a serverem drasticky snižuje \uv{Time To First Byte}\footnote{Time To First Byte --- čas mezi odesláním požadavku a přijmutím prvního bajtu dat.} a tím dochází ke snížení celkové latence. \citep{mozttfb} -Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že z pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z tohoto výzkumu se autoři rozhodli v měsících po vydání analýzy investovat více času do úprav všech aspektů jejich nové stránky FT.com s cílem jejího zrychlení.\todo{Nechat opravit překlad} +Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že z pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z tohoto výzkumu se autoři rozhodli v měsících po vydání analýzy investovat více času do úprav všech aspektů jejich nové stránky FT.com s cílem jejího zrychlení. \citep{financialtimes} Eliminováním dynamického obsahu se také předchází nevyžádaným vstupům od uživatele, které mohou být i cílené na prolomení bezpečnostních nedostatků webové aplikace a v některých případech mohou vést k úniku citlivých dat, převzetí kontroly útočníka nad webovou aplikací nebo celým serverem, podstrčení falešných dat uživateli a mnoha dalším běžným útokům. Statický web eliminuje tento problém, jelikož nemá žádný uživatelský vstup. @@ -33,7 +33,7 @@ Většina těchto chyb se vztahuje právě k dynamickým webovým aplikacím. Be Podstatným příkladem chybovosti dynamických webů je systém Wordpress, ve kterém jsou každý rok nalezeny desítky bezpečnostních chyb \citep{cve_wordpress}, přičemž mnoho dalších přibývá s instalací rozšíření, která postrádají bezpečnostní prvky. Například na začátku roku 2020 byla nalezena bezpečnostní chyba v rozšíření, které bylo využíváno na více než dvě stě tisících webových stránkách a potencionálním útočníkům umožňovala smazat obsah databáze \citep{thehackernews_wordpress_1}. Na konci roku 2019 umožnila chyba ve dvou nezabezpečených rozšířeních neautorizované přihlášení k účtu administrátora bez použití hesla \citep{thehackernews_wordpress_2}. -Údržba velkých webových aplikací je často problematická. Kód je nutné udržovat v návaznosti na aktualizace daného jazyka, databázového systému a dalších aspektů. Těmto aktualizacím se z bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s databázemi a různými frameworky\todo{Lepši slovo?} a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. +Údržba velkých webových aplikací je často problematická. Kód je nutné udržovat v návaznosti na aktualizace daného jazyka, databázového systému a dalších aspektů. Těmto aktualizacím se z bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s databázemi a různými frameworky a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. Jako každý jiný systém, i statické generátory mají své nevýhody. Hlavním z problémů je to, že správa statického generátoru a tvorba obsahu je náročnější, než klasické webové rozhraní s administračním panelem, různými uživateli a jednoduchou správou pro běžné, méně technicky zaměřené uživatele. Pro přidání nebo úpravu obsahu je nutné pracovat s lokálními soubory ve stromové struktuře a při generování je často potřebný zásah do shellu\footnote{Program pro interpretování příkazů v prostředí příkazové řádky.}. Tvorba systému pro automatizované generování je také náročnější než instalace některého z běžných CMS\footnote{Content Management System}. \citep{softpedia_generators} diff --git a/kap-markup.tex b/kap-markup.tex index 6469f6c..804bb5b 100644 --- a/kap-markup.tex +++ b/kap-markup.tex @@ -30,7 +30,7 @@ Podobně jako je tomu u specifikací, existuje velké množství programů, kter \subsection{Org-mode} -Org-mode vznikl jako jeden z módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s možností přidání libovolného nového backendu\todo{České slovo?}. Cílem Org-mode je možnost ho používat i s minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor Emacs je zároveň velmi často portován na různé druhy systémů a je tedy možné ho využívat v podstatě kdekoliv. \citep{orgmanual} +Org-mode vznikl jako jeden z módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s možností přidání libovolného nového backendu. Cílem Org-mode je možnost ho používat i s minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor Emacs je zároveň velmi často portován na různé druhy systémů a je tedy možné ho využívat v podstatě kdekoliv. \citep{orgmanual} Podporuje také \uv{literate programming} a \uv{reproducible research}, tedy že Org soubory mohou obsahovat plně funkční bloky s kódem, které lze hodnotit v rámci systému a výstup bloků lze automaticky vkládat přímo do dokumentu. \citep{environment_for_literate_programming} diff --git a/kap-modelova-implementace.tex b/kap-modelova-implementace.tex index 6b20d7b..2cd0f1a 100644 --- a/kap-modelova-implementace.tex +++ b/kap-modelova-implementace.tex @@ -323,10 +323,6 @@ Připojením externích CSS a JavaScript souborů je umožněno jejich ukládán Připojením externího CSS přímo do hlavičky je umožněno progresivní vykreslování webové stránky, které urychluje \uv{Time To First Byte}, viz sekce \ref{kap:vyhody-statickych-webovych-stranek}. Naopak umístěním případných JavaScript souborů až na konec celé stránky se prioritizuje načítání viditelného obsahu před méně důležitými skripty. -Je také důležité udržovat validní HTML, kdy například chybějící atribut \texttt{src=""} způsobuje odesílání nevyžádaných požadavků na server. - -\quest[inline]{HTML5 už specifikuje, aby prohlížeče kvůli prázdnému \textit{src} neposílaly další požadavek. Je tedy nutné uvádět tento příklad?} - \subsection{Videa a jejich vložení do stránky} \todo[inline]{Výhody CDN a problematika sledování uživatelů.} diff --git a/poznamky b/poznamky deleted file mode 100644 index 0526443..0000000 --- a/poznamky +++ /dev/null @@ -1,5 +0,0 @@ -- ocitovat financial times výzkum -- pro framework není český ekvivalent (framework znamená kostra, to nechceš lol) -- backend a frontend bys moh popsat max jako část serveru a část klienta, ale backend a frontend je lepší -- "U starých zařízení..." - řek bych, že můžeš zmínit max 4 fun nebo abys nahnal znaky lol -- "HTML5 už specifikuje" - nah vyjeb se na to lol diff --git a/prace.pdf b/prace.pdf index e26b6b08c2535741869b2b378218328ff6f1247f..8215d66489a47631cc130f59760c93de4e2a45ab 100644 GIT binary patch delta 100551 zcmX_{Q*@w#vZZ6&>ab(mwr#6pn}5);ZQJVDwr$&1Cq3ufxij@p>wBr!T5Ipx^?5?v zyG2~@LIBOi!^+IV#+>9$!1e#Roq*^6anlEZ0q9R|HWnsvZdP%65pGs?dM+jwZh8qZ zQ89X9VHQ>{W=>XaaS`q&U&0%5Q0AlrWvZqmv2{?uT#5P1-`%YYful)5FZ02x6@KUU=5oyoMF z^;ajEoiJ_YT+CYuaUPm6-sjjEg?}!-j&H1*tvg3W#u{etXWJ;EjZt(tb4?x&yK_%R zXU{IcEpZN3RN!dRU(!y6h=c*koz8i210+=f+Gmlc45Wo9Gk1NIlX>Fa84L8x*d$>Y zMy$p$Ug=)5MU#gwKj$QYPP)i@#oX8H%~ttdq)29negj=t&v~ebUzk)PIU ziYppFw4?68w{a_K0<4)PVe4dX=y&aCHp|V;K{@))oP{sFus}ukJL4M~w0E*wiHE(GnyoMpNPn!BKg!IU^ z9PSaZsoa|oqm3y(E1~R#?ubp8%DS3R^P^ohEp<5$#7-$#M{ek6W;%>s}k zszzLa$_lKv-nn3h3E-xAb|ZMo|7M2)%Cn|;(j5$29|(fNsIH>FbYaI&wvHLmQLYcI zJyeEve4iMWA;1^xh9G1h(`h^R(Fv394tf6U^n2NfQo5*#ZU#5P)cyoPPn!4NInGnY zllaWRu@(xA*DW|a`shVxuLn-vW0%D-D;<`VQw~-@AIn4gbEDp&V?9r1s&4|YZkTne z@R6x;XvD#3gr8aFQPhRuZ)s$qwKQTJ)pb(VR@P#a;{;49I)jUbQvtWb1|=nJmX-iT zTN}$5hU+dTZs`tVR6Ef6ENXP#kD1}}*l4sx*BngxfUc&XP>q}G#+P@n(-7&3=BK7^ z0=C2=TvhgaY@|S093(8XVm;tgXwG$Siv4K8+WIIw>S7L0WhYnL#yzkl@()(0f2&C% zns8o;dW(v7_2uM?UvulNt+XXpU4w2-_RUrcOV;XgK;~e@vZ@H@WvHNK)B%0sCiB}( zU_F~@C47Etp_0#hBIGUoy&Dsh<+w<@gqwE2FRO|@cPmYGyDRK0{QUzB?NZF1mAZAwd}Ty}yxvKV(L7?B zGmBGqDRmi#IqdRfdKggXEUu@26LhU(x99G4zEpC`OS^KXyj*HM8WU_u+E^2a(T`%C zdDvy{WqSmbUGHd8{}6cBfP_9UDY z3}@c%^x50Bvvuo{=5AP}2wh|@!GPb-(mbYs|99J!{@(39(FP#Yy!d+CZrMzaS+Rxr zs_>~Zv9YK93U+6!?WB(Y{%i)1*(2NNPu1{MPp^a|pJ@@D)avJHvf4xy>y@?Gbmz6F zZ`p?QAt~<7sGeCzPvhecFS#q~X`I-7NZy!eVQ0}VcAD1+G@R@(c_fgs9(nt>LHH%|WKC%Ga{r(8LDO#fd`k zCclkEE*(Ft-Q)L#wdqNDEOz7%S*6Bpw55m%-|NPWa&G|NQpIk(&CbsNF=DiOu9I$N z*o+8WCo<6-xIh1@wc zFclnoFyGR3(_iG7@+w7WC^HlB-G)TIM|Mb%>*S+_`Ar`v8&@QFmOs+r%{29vJx&4j zk2}WUAp2hf0dDB9??OMn;kB+Oc$)a-@nDmfgD}8ZIJwg1(ZOf{ZI{ClRR7hwJu)@& z{%D+u!aBI5Tv6(@mm$%2~A5Lk*V>_o` zdpok91pszbWp@P>n2+5H!2VdgyUSn_0uC$u+W(n;-FH$7>c977jXL%Db}gGGcQCV> zW91>4H&Gkj5`pW?qvrYSl4uBDT)m%iNBiydY(wKZyi4V!j*i;+t`g-Ajyb&j7Cz(7 zS$`mqdL$?Y-D|9YeBF_1XX0MJ}ZoeQ`Pub;d~m zk!8aCDxLun+!1UMrA&uSLVxI!LzSDJm$b7I(i%)IJrRLYqZ!ft6p~0(Hrt|GfJ%jxNJ3llyb>8s}O5>N4b=nK<{4 zT)BwCZ9wKMmk6F*GxYfVQj~t{pPi=Z--=q)B%Kn#>ggRSF5GXK57L!yj(9?ZSFa2|E2f&Hp4aY9PB&-t>)a%v)GZ#A{~g%0F68%!40R53>*d!iLusQ=v|MDlf8)!D3sR z-p&nfei=GJ3Fc%AJ9p%%kj9ZsH#;5tI!~S+NB0#B&oSh-U{!5c>Z4|>y2OMjG>!oh z_g;94k`@S#{7PUbB4ar`PJ(-rJ}NrG8$D&dY_XZ8Yf&H-_Zh;2FNpE?{)fQH)6BhYG1;CD5Cc?CLAsvU2G0v}~EPV^A96?uk||6}@GA0wf7jF`~;Y zCDD+rGU?8%Ph_jewwg!#5#D~)VBi76N>&^sTC;D9mmu#F>m|Nle2z_gWiCQJL<00y zfz|?q)boQ264caIJI6~7o4>4z#$1}XGR~$J)KU0gwsPXzPIQhy@BC(+3`N-V6)F?a znUq+go|&ag7*y*@boC&-bx*#2g%JL(Vpc1_h;eG;rPYwXcU|_`6b>DyrKwwGTawkMr$ru3O!YY{S^qFvr@@2f~VJXRO=5{9XB^?>meQ$lYge{jFIGN;

v0P|M4ubZt#0X$w#@E|)~BC4FYY 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

NurPZ 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 PGcz+VGYTaoMNdWwE>ds6 delta 101965 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�SOHRU=*83@$Ee{%L*34G2`k2Ub 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 GPeuxLC`rQr -- 2.45.2 From 41146d41817a4068498bbda6dbba163242264b39 Mon Sep 17 00:00:00 2001 From: Emil Miler Date: Thu, 30 Apr 2020 22:58:43 +0200 Subject: [PATCH 04/49] =?UTF-8?q?Vlna=20pro=20pevn=C3=A9=20mezery?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #2 --- Makefile | 5 +- kap-generatory.tex | 24 ++--- kap-markup.tex | 26 +++--- kap-modelova-implementace.tex | 146 +++++++++++++++---------------- kap-paradigmata.tex | 6 +- kap-taxonomie-pozadavku.tex | 18 ++-- kap-vyhodnoceni-implementace.tex | 8 +- prace.pdf | Bin 536127 -> 536138 bytes prace.tex | 4 +- titulka.tex | 2 +- 10 files changed, 121 insertions(+), 118 deletions(-) diff --git a/Makefile b/Makefile index 5ca8f3d..1efe2a3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ export TEXINPUTS=../tex//: -all: prace.pdf sighup +all: vlna prace.pdf sighup # LaTeX je potreba spustit nekolikrat, aby spravne spocital odkazy prace.pdf: prace.tex $(wildcard *.tex) literatura.bib prace.xmpdata @@ -9,6 +9,9 @@ prace.pdf: prace.tex $(wildcard *.tex) literatura.bib prace.xmpdata pdflatex $< pdflatex $< +vlna: $(wildcard *.tex) + -vlna -l $^ + clean: rm -f *.log *.dvi *.aux *.toc *.lof *.lot *.out *.bbl *.blg *.xmpi *.lol rm -f prace.pdf diff --git a/kap-generatory.tex b/kap-generatory.tex index e101236..f2c2281 100644 --- a/kap-generatory.tex +++ b/kap-generatory.tex @@ -1,18 +1,18 @@ \chapter{Staticky generovaný web} -Princip statické webové stránky sahá až ke vzniku WWW, kdy existovaly pouze stránky statické, tedy stejné pro každého uživatele. Jejich obsah může být průběžně aktualizován, ovšem negenerují se zvlášť pro každého uživatele na základě různých proměnných. U statických webů tedy dochází k vytvoření čistého HTML ve chvíli, kdy je změněn zdrojový obsah, nebo kdy autor ručně spustí generátor. \citep{pcmag_static} +Princip statické webové stránky sahá až ke vzniku WWW, kdy existovaly pouze stránky statické, tedy stejné pro každého uživatele. Jejich obsah může být průběžně aktualizován, ovšem negenerují se zvlášť pro každého uživatele na základě různých proměnných. U~statických webů tedy dochází k~vytvoření čistého HTML ve chvíli, kdy je změněn zdrojový obsah, nebo kdy autor ručně spustí generátor. \citep{pcmag_static} -Dynamické stránky jsou generovány speciálně pro každého uživatele na základě jeho nastavení, různých vstupů, proměnných a dalších vlastností. Ke generování dochází ve chvíli, kdy si uživatel stránku vyžádá, nikoliv předem, jako je tomu u staticky generovaných stránek. \citep{pcmag_dynamic} +Dynamické stránky jsou generovány speciálně pro každého uživatele na základě jeho nastavení, různých vstupů, proměnných a dalších vlastností. Ke generování dochází ve chvíli, kdy si uživatel stránku vyžádá, nikoliv předem, jako je tomu u~staticky generovaných stránek. \citep{pcmag_dynamic} \section{Výhody statických webových stránek}\label{kap:vyhody-statickych-webovych-stranek} -Pro sdílení statického obsahu mezi různé uživatele stačí velmi jednoduchý HTTP server bez jakýchkoliv dalších modulů typu \textit{PHP}, \textit{Python} a dalších systémů, které by obsah dynamicky generovaly například z dat vytažených z databáze, nebo z uživatelského vstupu. Na straně serveru tedy nedochází ke zpracování obsahu těsně před jeho odesláním uživateli, čímž se v komunikaci mezi klientem a serverem drasticky snižuje \uv{Time To First Byte}\footnote{Time To First Byte --- čas mezi odesláním požadavku a přijmutím prvního bajtu dat.} a tím dochází ke snížení celkové latence. \citep{mozttfb} +Pro sdílení statického obsahu mezi různé uživatele stačí velmi jednoduchý HTTP server bez jakýchkoliv dalších modulů typu \textit{PHP}, \textit{Python} a dalších systémů, které by obsah dynamicky generovaly například z~dat vytažených z~databáze, nebo z~uživatelského vstupu. Na straně serveru tedy nedochází ke zpracování obsahu těsně před jeho odesláním uživateli, čímž se v~komunikaci mezi klientem a serverem drasticky snižuje \uv{Time To First Byte}\footnote{Time To First Byte --- čas mezi odesláním požadavku a přijmutím prvního bajtu dat.} a tím dochází ke snížení celkové latence. \citep{mozttfb} -Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že z pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z tohoto výzkumu se autoři rozhodli v měsících po vydání analýzy investovat více času do úprav všech aspektů jejich nové stránky FT.com s cílem jejího zrychlení. \citep{financialtimes} +Snížení samotné latence může pozitivně přispět ke spokojenosti uživatelů, což dokazuje nespočet výzkumů na toto téma, například analýza z~webového portálu Financial Times, kde se uvádí, že rychlost webové stránky negativně ovlivňuje hloubku jejího užívání, ať už je odezva sebemenší. Jak je zde rovněž uvedeno, data ukazují, že z~pohledu uživatelské spokojenosti a finančního dopadu existují jasné a důležité výhody při zrychlení webové stránky. Z~tohoto výzkumu se autoři rozhodli v~měsících po vydání analýzy investovat více času do úprav všech aspektů jejich nové stránky FT.com s~cílem jejího zrychlení. \citep{financialtimes} -Eliminováním dynamického obsahu se také předchází nevyžádaným vstupům od uživatele, které mohou být i cílené na prolomení bezpečnostních nedostatků webové aplikace a v některých případech mohou vést k úniku citlivých dat, převzetí kontroly útočníka nad webovou aplikací nebo celým serverem, podstrčení falešných dat uživateli a mnoha dalším běžným útokům. Statický web eliminuje tento problém, jelikož nemá žádný uživatelský vstup. +Eliminováním dynamického obsahu se také předchází nevyžádaným vstupům od uživatele, které mohou být i cílené na prolomení bezpečnostních nedostatků webové aplikace a v~některých případech mohou vést k~úniku citlivých dat, převzetí kontroly útočníka nad webovou aplikací nebo celým serverem, podstrčení falešných dat uživateli a mnoha dalším běžným útokům. Statický web eliminuje tento problém, jelikož nemá žádný uživatelský vstup. -Sledování a analýze nejčastějších chyb webových aplikací a serverů se věnuje organizace OWASP\footnote{The Open Web Application Security Project --- \url{https://owasp.org/}.}, která vydává aktualizované seznamy a statistiky. Podle OWASP byly v roce 2017 nejčastější tyto chyby a bezpečnostní nedostatky: +Sledování a analýze nejčastějších chyb webových aplikací a serverů se věnuje organizace OWASP\footnote{The Open Web Application Security Project --- \url{https://owasp.org/}.}, která vydává aktualizované seznamy a statistiky. Podle OWASP byly v~roce 2017 nejčastější tyto chyby a bezpečnostní nedostatky: \begin{enumerate} \item{Injekce} @@ -29,18 +29,18 @@ Sledování a analýze nejčastějších chyb webových aplikací a serverů se \citep{owasp2017} -Většina těchto chyb se vztahuje právě k dynamickým webovým aplikacím. Bezpečnost tedy závisí nejen na programátorovi který aplikaci vytváří, ale také na tom, že programovací jazyk je bezpečně implementován. To nelze tvrdit o nejpoužívanějším jazyce PHP, který nejen že obsahuje mnoho chyb, viz seznam nalezených bezpečnostních děr \citep{cve_php}, ale zároveň nevede programátora k psaní bezpečného kódu, což má za následek nebezpečené aplikace, pokud si autor nedá pozor na správné ošetření vstupů a dalších bezpečnostních aspektů programu. +Většina těchto chyb se vztahuje právě k~dynamickým webovým aplikacím. Bezpečnost tedy závisí nejen na programátorovi který aplikaci vytváří, ale také na tom, že programovací jazyk je bezpečně implementován. To nelze tvrdit o~nejpoužívanějším jazyce PHP, který nejen že obsahuje mnoho chyb, viz seznam nalezených bezpečnostních děr \citep{cve_php}, ale zároveň nevede programátora k~psaní bezpečného kódu, což má za následek nebezpečené aplikace, pokud si autor nedá pozor na správné ošetření vstupů a dalších bezpečnostních aspektů programu. -Podstatným příkladem chybovosti dynamických webů je systém Wordpress, ve kterém jsou každý rok nalezeny desítky bezpečnostních chyb \citep{cve_wordpress}, přičemž mnoho dalších přibývá s instalací rozšíření, která postrádají bezpečnostní prvky. Například na začátku roku 2020 byla nalezena bezpečnostní chyba v rozšíření, které bylo využíváno na více než dvě stě tisících webových stránkách a potencionálním útočníkům umožňovala smazat obsah databáze \citep{thehackernews_wordpress_1}. Na konci roku 2019 umožnila chyba ve dvou nezabezpečených rozšířeních neautorizované přihlášení k účtu administrátora bez použití hesla \citep{thehackernews_wordpress_2}. +Podstatným příkladem chybovosti dynamických webů je systém Wordpress, ve kterém jsou každý rok nalezeny desítky bezpečnostních chyb \citep{cve_wordpress}, přičemž mnoho dalších přibývá s~instalací rozšíření, která postrádají bezpečnostní prvky. Například na začátku roku 2020 byla nalezena bezpečnostní chyba v~rozšíření, které bylo využíváno na více než dvě stě tisících webových stránkách a potencionálním útočníkům umožňovala smazat obsah databáze \citep{thehackernews_wordpress_1}. Na konci roku 2019 umožnila chyba ve dvou nezabezpečených rozšířeních neautorizované přihlášení k~účtu administrátora bez použití hesla \citep{thehackernews_wordpress_2}. -Údržba velkých webových aplikací je často problematická. Kód je nutné udržovat v návaznosti na aktualizace daného jazyka, databázového systému a dalších aspektů. Těmto aktualizacím se z bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s databázemi a různými frameworky a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. +Údržba velkých webových aplikací je často problematická. Kód je nutné udržovat v~návaznosti na aktualizace daného jazyka, databázového systému a dalších aspektů. Těmto aktualizacím se z~bezpečnostních důvodů nelze vyhýbat. Statický web nemusí udržovat funkční propojení s~databázemi a různými frameworky a je tedy mnohem méně náročný na dlouhodobou údržbu. Při zvolení správného generátoru není nutná ani údržba šablon a celý systém při zachování stejného prostředí nepřestane fungovat. Protože statický generátor nepracuje s~uživatelským vstupem, vyhýbá se bezpečnostním chybám a tím i nutným aktualizacím. -Jako každý jiný systém, i statické generátory mají své nevýhody. Hlavním z problémů je to, že správa statického generátoru a tvorba obsahu je náročnější, než klasické webové rozhraní s administračním panelem, různými uživateli a jednoduchou správou pro běžné, méně technicky zaměřené uživatele. Pro přidání nebo úpravu obsahu je nutné pracovat s lokálními soubory ve stromové struktuře a při generování je často potřebný zásah do shellu\footnote{Program pro interpretování příkazů v prostředí příkazové řádky.}. Tvorba systému pro automatizované generování je také náročnější než instalace některého z běžných CMS\footnote{Content Management System}. \citep{softpedia_generators} +Jako každý jiný systém, i statické generátory mají své nevýhody. Hlavním z~problémů je to, že správa statického generátoru a tvorba obsahu je náročnější, než klasické webové rozhraní s~administračním panelem, různými uživateli a jednoduchou správou pro běžné, méně technicky zaměřené uživatele. Pro přidání nebo úpravu obsahu je nutné pracovat s~lokálními soubory ve stromové struktuře a při generování je často potřebný zásah do shellu\footnote{Program pro interpretování příkazů v~prostředí příkazové řádky.}. Tvorba systému pro automatizované generování je také náročnější než instalace některého z~běžných CMS\footnote{Content Management System}. \citep{softpedia_generators} \section{Princip generátorů}\label{kap:princip-generatoru} -Ekosystém generátoru statického obsahu je tvořen ze tří hlavních složek. První částí jsou soubory šablon, které popisují rozložení stránky, vizuální vlastnosti, typografii, ale také vstupní a výstupní kódování a formáty. V podstatě definují jak a kam se bude obsah vkládat. Druhou částí je obsah samotný, napsaný v některém ze značkovacích jazyků, nejčastěji v jazyce Markdown. Obsah bývá strukturován do sekcí a souborů, aby bylo snadné rozlišit, do které části výsledné stránky patří. Třetí a poslední složkou je samotné jádro generátoru, které zpracovává obsah, vkládá ho do šablon a renderuje statickou webovou stránku. +Ekosystém generátoru statického obsahu je tvořen ze tří hlavních složek. První částí jsou soubory šablon, které popisují rozložení stránky, vizuální vlastnosti, typografii, ale také vstupní a výstupní kódování a formáty. V~podstatě definují jak a kam se bude obsah vkládat. Druhou částí je obsah samotný, napsaný v~některém ze značkovacích jazyků, nejčastěji v~jazyce Markdown. Obsah bývá strukturován do sekcí a souborů, aby bylo snadné rozlišit, do které části výsledné stránky patří. Třetí a poslední složkou je samotné jádro generátoru, které zpracovává obsah, vkládá ho do šablon a renderuje statickou webovou stránku. -Většina generátorů zároveň umí pracovat s konfiguračními soubory, kterými jde nastavit globální chování generátoru. Část z nich také integruje jednoduchý webserver, který umožňuje autorovi náhled výstupních stránek zatím co tvoří obsah. +Většina generátorů zároveň umí pracovat s~konfiguračními soubory, kterými jde nastavit globální chování generátoru. Část z~nich také integruje jednoduchý webserver, který umožňuje autorovi náhled výstupních stránek zatím co tvoří obsah. \citep{softpedia_generators} diff --git a/kap-markup.tex b/kap-markup.tex index 804bb5b..09a3192 100644 --- a/kap-markup.tex +++ b/kap-markup.tex @@ -2,17 +2,17 @@ \section{Principy značkovacích jazyků} -Definici konceptu značkovacích jazyků, nebo-li \uv{markup jazyků}, můžeme najít například v RFC 7764\footnote{Jako \textit{RFC} se označují standardy vydané organizací IETF (Internet Engineering Task Force).}, tedy že v počítačových systémech jsou kontextuální data ukládána a zpracována několika technikami. Informaci lze kódovat jako čistý text bez speciálních formátovacích znaků. Tento přístup je jednoduchý pro implementaci i použití, ovšem neumožňuje složitější formátování textu. +Definici konceptu značkovacích jazyků, nebo-li \uv{markup jazyků}, můžeme najít například v~RFC 7764\footnote{Jako \textit{RFC} se označují standardy vydané organizací IETF (Internet Engineering Task Force).}, tedy že v~počítačových systémech jsou kontextuální data ukládána a zpracována několika technikami. Informaci lze kódovat jako čistý text bez speciálních formátovacích znaků. Tento přístup je jednoduchý pro implementaci i použití, ovšem neumožňuje složitější formátování textu. Kódovat můžeme i do binárních formátů určených ke zpracování a interpretaci specializovaným programem. Zřejmou nevýhodou je to, že zdroj není čitelný bez programu určeného pro jeho interpretaci. -Markup jazyky se snaží o spojení nejlepšího z obou světů, tedy o obsah s možností formátování, který je jednoduše čitelný jak pro člověka, tak pro stroj. Toho je dosaženo tím, že v je v běžných textových souborech přiřezen vybraným znakům speciální význam. Uživatel je schopen tyto znaky psát bez potřeby speciálních nástrojů a tím jednoduše vyjádřit speciální význam. Například v rámci jazyka Markdown se znak \texttt{\#} změní z běžného křížku na definování nadpisu první úrovně, nebo také kombinace znaků \texttt{

} značí začátek odstavce v HTML. \citep{rfc7764} +Markup jazyky se snaží o~spojení nejlepšího z~obou světů, tedy o~obsah s~možností formátování, který je jednoduše čitelný jak pro člověka, tak pro stroj. Toho je dosaženo tím, že v~je v~běžných textových souborech přiřezen vybraným znakům speciální význam. Uživatel je schopen tyto znaky psát bez potřeby speciálních nástrojů a tím jednoduše vyjádřit speciální význam. Například v~rámci jazyka Markdown se znak \texttt{\#} změní z~běžného křížku na definování nadpisu první úrovně, nebo také kombinace znaků \texttt{

} značí začátek odstavce v~HTML. \citep{rfc7764} \section{Nejběžnější jazyky} -V současnosti existuje nespočet značkovacích jazyků. Nejpoužívanějším z nich je jednoznačně HTML, ovšem tato práce se věnuje těm nejpoužívanějším jazykům, které mají uživateli usnadnit psaní a sázení obsahu. Uživatel se tedy nemusí při tvorbě nutně zabývat typografií a formátováním obsahu, což jsou aspekty, o které se později postará generátor pomocí šablon. U HTML je tomu naopak, uživatel řeší samotný obsah i formátování v jednu chvíli skrze různé druhy formátovacích tagů. O vyplňování obsahu do HTML se v případě staticky generovaných webů stará právě samotný generátor. +V~současnosti existuje nespočet značkovacích jazyků. Nejpoužívanějším z~nich je jednoznačně HTML, ovšem tato práce se věnuje těm nejpoužívanějším jazykům, které mají uživateli usnadnit psaní a sázení obsahu. Uživatel se tedy nemusí při tvorbě nutně zabývat typografií a formátováním obsahu, což jsou aspekty, o~které se později postará generátor pomocí šablon. U~HTML je tomu naopak, uživatel řeší samotný obsah i formátování v~jednu chvíli skrze různé druhy formátovacích tagů. O~vyplňování obsahu do HTML se v~případě staticky generovaných webů stará právě samotný generátor. -Vybrané jazyky jsou zároveň cílené na čitelnost samotného zdrojového obsahu v čistém textu bez nutnosti jeho interpretace speciálním prostředím či zpracováním do jiného formátu, například do PDF, DjVu, PostScript apod. Například podtržení textu je v nějakém pseudo-jazyce reprezentováno opravdovým podtržením pomocí spojovníků, nikoliv obalením nadpisu ve speciální deklaraci, jako je tomu například u HTML. Podtržení je poté pro čtenáře mnohem jasnější, jelikož nemusí přemýšlet, co v kontextu HTML daný tag znamená, kdežto podtržení vyplývá z kontextu. +Vybrané jazyky jsou zároveň cílené na čitelnost samotného zdrojového obsahu v~čistém textu bez nutnosti jeho interpretace speciálním prostředím či zpracováním do jiného formátu, například do PDF, DjVu, PostScript apod. Například podtržení textu je v~nějakém pseudo-jazyce reprezentováno opravdovým podtržením pomocí spojovníků, nikoliv obalením nadpisu ve speciální deklaraci, jako je tomu například u~HTML. Podtržení je poté pro čtenáře mnohem jasnější, jelikož nemusí přemýšlet, co v~kontextu HTML daný tag znamená, kdežto podtržení vyplývá z~kontextu. Seznam nejoblíbenějších jazyků je sestaven podle aktuálních statistik ze serveru Slant, který se věnuje obecnému určení oblíbenosti na základě hodnocení ze strany uživatelů. \citep{slant} @@ -20,21 +20,21 @@ Seznam nejoblíbenějších jazyků je sestaven podle aktuálních statistik ze Jazyka Markdown vznikl 19. března roku 2004, když John Gruber vydal první popis syntaxe a referenční implementaci. -Hlavním z cílů syntaxe jazyka je vytvářet co možná nejčitelnější obsah v syrové podobě. Dokument psaný v Markdownu by měl být publikovatelný sám o sobě jako čistý text bez dalších úprav a zpracování. Jazyk byl ovlivněn několika již existujícími specifikacemi jiných jazyků, ovšem největším zdrojem inspirace pro jeho vznik jsou čisté emailové korespondence. \citep{daringfireball} +Hlavním z~cílů syntaxe jazyka je vytvářet co možná nejčitelnější obsah v~syrové podobě. Dokument psaný v~Markdownu by měl být publikovatelný sám o~sobě jako čistý text bez dalších úprav a zpracování. Jazyk byl ovlivněn několika již existujícími specifikacemi jiných jazyků, ovšem největším zdrojem inspirace pro jeho vznik jsou čisté emailové korespondence. \citep{daringfireball} -První specifikaci Gruber vydal společně s referenční implementací v jazyce Perl, která prováděla konverzi Markdownu do HTML. Tento program je také pojmenován \uv{Markdown}, ovšem mluvíme-li o \uv{Markdownu}, máme nejčastěji na mysli samotnou syntaxi. Ta má dnes mnoho implementací v různých programovacích jazycích. Gruberova specifikace ovšem není formální standard, kvůli čemuž vznikl veliký počet alternativních a více či méně pozměněných implementací, které nemusí být navzájem kompatibilní. Nejčastějšími z nich jsou například Github Markdown, CommonMark, R Markdown a mnoho dalších. \citep{commonmark} +První specifikaci Gruber vydal společně s~referenční implementací v~jazyce Perl, která prováděla konverzi Markdownu do HTML. Tento program je také pojmenován \uv{Markdown}, ovšem mluvíme-li o~\uv{Markdownu}, máme nejčastěji na mysli samotnou syntaxi. Ta má dnes mnoho implementací v~různých programovacích jazycích. Gruberova specifikace ovšem není formální standard, kvůli čemuž vznikl veliký počet alternativních a více či méně pozměněných implementací, které nemusí být navzájem kompatibilní. Nejčastějšími z~nich jsou například Github Markdown, CommonMark, R Markdown a mnoho dalších. \citep{commonmark} Nevyužívanější formální specifikací je právě CommonMark\footnote{\url{https://commonmark.org/}}, který slouží jako pevný základ většiny rozšíření. \citep{github_formal_markdown_spec}. -Podobně jako je tomu u specifikací, existuje velké množství programů, které tyto různé specifikace překládají. Švýcarským nožem mezi nimi je program Pandoc\footnote{\url{https://pandoc.org/}}, který umí překládat Markdown do enormního výběru jiných formátů, nebo z jiných formátů zpět. Tato funkcionalita se nevztahuje pouze na jazyk Markdown, Pandoc dokáže operovat mezi všemi podporovanými formáty, například dokáže konvertovat obsah z HTML do \TeX{}u. Na druhou stranu existují i velmi jednoduché překladače, například program smu\footnote{\url{https://github.com/Gottox/smu}}, který umí překládat Markdown do HTML nebo čistého textu a neobsahuje více než 600 SLOC\footnote{Source lines of code}, tedy řádků kódu hlavního programu. +Podobně jako je tomu u~specifikací, existuje velké množství programů, které tyto různé specifikace překládají. Švýcarským nožem mezi nimi je program Pandoc\footnote{\url{https://pandoc.org/}}, který umí překládat Markdown do enormního výběru jiných formátů, nebo z~jiných formátů zpět. Tato funkcionalita se nevztahuje pouze na jazyk Markdown, Pandoc dokáže operovat mezi všemi podporovanými formáty, například dokáže konvertovat obsah z~HTML do \TeX{}u. Na druhou stranu existují i velmi jednoduché překladače, například program smu\footnote{\url{https://github.com/Gottox/smu}}, který umí překládat Markdown do HTML nebo čistého textu a neobsahuje více než 600 SLOC\footnote{Source lines of code}, tedy řádků kódu hlavního programu. \subsection{Org-mode} -Org-mode vznikl jako jeden z módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s možností přidání libovolného nového backendu. Cílem Org-mode je možnost ho používat i s minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor Emacs je zároveň velmi často portován na různé druhy systémů a je tedy možné ho využívat v podstatě kdekoliv. \citep{orgmanual} +Org-mode vznikl jako jeden z~módů pro editor Emacs\footnote{\url{https://www.gnu.org/software/emacs/}}. Funguje podobně jako ostatní markup jazyky, tedy jako jeden centrální systém pro správu obsahu, ze kterého lze vytvářet jiné formáty, například HTML, \LaTeX, Open Document, Markdown, PDF a podobně s~možností přidání libovolného nového backendu. Cílem Org-mode je možnost ho používat i s~minimální úrovní jeho znalosti, ovšem jeho funkcionalita je vždy přístupná. Vše je realizováno pouze na čistých textových souborech, nejlépe přenositelným typem souboru. Editor Emacs je zároveň velmi často portován na různé druhy systémů a je tedy možné ho využívat v~podstatě kdekoliv. \citep{orgmanual} -Podporuje také \uv{literate programming} a \uv{reproducible research}, tedy že Org soubory mohou obsahovat plně funkční bloky s kódem, které lze hodnotit v rámci systému a výstup bloků lze automaticky vkládat přímo do dokumentu. \citep{environment_for_literate_programming} +Podporuje také \uv{literate programming} a \uv{reproducible research}, tedy že Org soubory mohou obsahovat plně funkční bloky s~kódem, které lze hodnotit v~rámci systému a výstup bloků lze automaticky vkládat přímo do dokumentu. \citep{environment_for_literate_programming} -Jak popisuje Carsten Dominik ve svém krátkém technickém popisu, Org-mode umí navrhování, psaní poznámek, hypertextové odkazy, tabulky, seznamy, plánování projektů, GTD, HTML a \LaTeX{}, a to všechno v čistých textových souborech v editoru Emacs. \citep{carsten_dominik} +Jak popisuje Carsten Dominik ve svém krátkém technickém popisu, Org-mode umí navrhování, psaní poznámek, hypertextové odkazy, tabulky, seznamy, plánování projektů, GTD, HTML a \LaTeX{}, a to všechno v~čistých textových souborech v~editoru Emacs. \citep{carsten_dominik} \subsection{AsciiDoc} @@ -46,15 +46,15 @@ Jak popisuje Carsten Dominik ve svém krátkém technickém popisu, Org-mode um \subsection{\TeX} -Tento jazyk se již vzdaluje od původního konceptu čitelnosti zdroje, ovšem ve statických generátorech ho lze stále efektivně využít a jeho části se velmi často objevují jako rozšíření dříve zmíněných jazyků. Jedním z hlavních rozšíření jsou zápisy matematických rovnic, které z \TeX{}u vychází.\todo{Rozšířit o popis TeXu a matiky.} +Tento jazyk se již vzdaluje od původního konceptu čitelnosti zdroje, ovšem ve statických generátorech ho lze stále efektivně využít a jeho části se velmi často objevují jako rozšíření dříve zmíněných jazyků. Jedním z~hlavních rozšíření jsou zápisy matematických rovnic, které z~\TeX{}u vychází.\todo{Rozšířit o~popis TeXu a matiky.} -Většina uživatelů se setkala spíše s jazykem \LaTeX, tedy s nadstavbou původního \TeX{}u, která má uživateli zjednodušit práci svými makry a rozšířeními. Realita je ovšem taková, že \LaTeX{} dělá celou práci složitější, jak popisuje doktor Olšák: +Většina uživatelů se setkala spíše s~jazykem \LaTeX, tedy s~nadstavbou původního \TeX{}u, která má uživateli zjednodušit práci svými makry a rozšířeními. Realita je ovšem taková, že \LaTeX{} dělá celou práci složitější, jak popisuje doktor Olšák: \begin{quote} Představte si, že si nějaký uživatel přečte \LaTeX{}ovou příručku a nabude dojmu, že mu bude stačit rozumět problematice sazby na úrovni této příručky. Pak se jednou překlepne třeba při sestavování tabulky a na terminálu na něj \TeX{} křičí: {\tt Extra alignment tab has been changed to "\verb|\cr|".} Uživatel začne znovu listovat ve své příručce a zjistí, že tam o~žádném "\verb|\cr|" není jediná zmínka. Má pak tři možnosti: (1)~Zmáčkne Enter a podobně se zachová i u~dalších chyb. Pomyslí si, že ten \LaTeX{} je něco tajemného a mystického. (2)~Propadne zoufalství a jde od toho. Dojde k~závěru, ľe je lepší zůstat u~Wordu. Vždyť stačí vzít tabulku v~Excelu a jednoduše ji přemístit do Wordu a jaképak smolení se s~nějakým podezřelým "\verb|\cr|". (3)~Pořídí si \TeX{}book a po intenzivním studiu nakonec řekne: \uv{aha}. V~tuto chvíli ale už nepotřebuje, aby mu \LaTeX{} zakrýval složitost \TeX{}u. \end{quote} \citep{nolatex} -Ve výsledku je tedy lepší, z různých důvodů popsaných doktorem Olšákem v jeho publikaci, použít samotný plain \TeX{} na úkor vyšší vstupní úrovně pro použivání jazyka. +Ve výsledku je tedy lepší, z~různých důvodů popsaných doktorem Olšákem v~jeho publikaci, použít samotný plain \TeX{} na úkor vyšší vstupní úrovně pro použivání jazyka. \subsection{Troff} diff --git a/kap-modelova-implementace.tex b/kap-modelova-implementace.tex index 2cd0f1a..9ba75ce 100644 --- a/kap-modelova-implementace.tex +++ b/kap-modelova-implementace.tex @@ -1,40 +1,40 @@ \chapter{Modelová implementace}\label{kap:modelova-implementace} -Tato část práce se věnuje tvorbě modelové implementace systému pro generování statického webu dle definovaných požadavků v kapitole \ref{kap:taxonomie-pozadavku}. Jsou zde vybrány vhodné součásti, ze kterých je modelová implementace složena. Systém je vytvářen na základě poznatků z předchozích částí práce. +Tato část práce se věnuje tvorbě modelové implementace systému pro generování statického webu dle definovaných požadavků v~kapitole \ref{kap:taxonomie-pozadavku}. Jsou zde vybrány vhodné součásti, ze kterých je modelová implementace složena. Systém je vytvářen na základě poznatků z~předchozích částí práce. \section{Výběr vhodného systému}\label{kap:vyber-vhodneho-systemu} -Modelový web se skládá ze dvou částí, a to z verzovacího systému pro správu obsahu a generátoru statického HTML. +Modelový web se skládá ze dvou částí, a to z~verzovacího systému pro správu obsahu a generátoru statického HTML. \subsection{Verzovací systém pro správu obsahu}\label{kap:vyber-vhodneho-systemu-verzovani} -Pro správu obsahu i šablon a statických souborů byl zvolen distribuovaný verzovací systém Git, který má v porovnání s jinými verzovacími systémy, zejména centralizovanými, spousty výhod. Hlavní jeho výhodou je rozšířené využití v praxi a snadné používání. Díky svým decentralizovaným vlastnostem ho lze využívat v mnoha odlišných pracovních postupech. S naklonovaným repozitářem lze pracovat i bez připojení k síti, což lze považovat i za druh zálohy. Git také umožňuje slučování různých změn od mnoha uživatelů a dovoluje jednoduše řešit potenciální konflikty. \citep{why_is_git_better_than_x} +Pro správu obsahu i šablon a statických souborů byl zvolen distribuovaný verzovací systém Git, který má v~porovnání s~jinými verzovacími systémy, zejména centralizovanými, spousty výhod. Hlavní jeho výhodou je rozšířené využití v~praxi a snadné používání. Díky svým decentralizovaným vlastnostem ho lze využívat v~mnoha odlišných pracovních postupech. S~naklonovaným repozitářem lze pracovat i bez připojení k~síti, což lze považovat i za druh zálohy. Git také umožňuje slučování různých změn od mnoha uživatelů a dovoluje jednoduše řešit potenciální konflikty. \citep{why_is_git_better_than_x} -Skvěle využitelnou funkcí pro modelovou implementaci je také to, že po provedení změn v repozitáři lze pomocí Gitu spouštět skripty, které mohou provádět automatické generování obsahu a další užitečné operace. Tato funkcionalita je implementována v rámci modelové implementace v sekci \ref{kap:automaticke-generovani-obsahu}. +Skvěle využitelnou funkcí pro modelovou implementaci je také to, že po provedení změn v~repozitáři lze pomocí Gitu spouštět skripty, které mohou provádět automatické generování obsahu a další užitečné operace. Tato funkcionalita je implementována v~rámci modelové implementace v~sekci \ref{kap:automaticke-generovani-obsahu}. \subsection{Generátor statického webu} -Protože forma modelového webu odpovídá paradigmatu webové prezentace ze sekce \ref{kap:paradigmata-webova-prezentace}, byl pro jeho generování použit program Zola\footnote{\url{https://www.getzola.org/}}, jehož výhody jsou popsány v sekci \ref{kap:paradigmata-webova-prezentace}. +Protože forma modelového webu odpovídá paradigmatu webové prezentace ze sekce \ref{kap:paradigmata-webova-prezentace}, byl pro jeho generování použit program Zola\footnote{\url{https://www.getzola.org/}}, jehož výhody jsou popsány v~sekci \ref{kap:paradigmata-webova-prezentace}. \todo[inline]{Přesunout výběr a výhody generátoru sem.} \section{Tvorba šablony} -Jak se uvádí v dokumentaci\footnote{\url{https://www.getzola.org/documentation/content/overview/}}, Zola pracuje s několika druhy stránek, primárně s takzvanou \uv{sekcí} a \uv{stránkou}. Každá sekce může mít vlastní obsah, ovšem může obsahovat i další subsekce, díky čemuž lze dělit obsah do stromové struktury. Stránka slouží pouze k předání obsahu a nikoliv k dalšímu větvení struktury. Dá se tedy říci, že stránka reprezentuje list v rámci stromovité struktury. Kořenem celého stromu je speciální sekce s názvem \uv{index}. Každá tato část standardně využívá vlastní HTML šablonu, to není ovšem pravidlo a každá část větve může využívat jinou šablonu. To je užitečné například u stránek s různými druhy obsahu. V rámci modelového webu zůstává druh obsahu stejný a není tedy třeba odchylovat se od standardní struktury. +Jak se uvádí v~dokumentaci\footnote{\url{https://www.getzola.org/documentation/content/overview/}}, Zola pracuje s~několika druhy stránek, primárně s~takzvanou \uv{sekcí} a \uv{stránkou}. Každá sekce může mít vlastní obsah, ovšem může obsahovat i další subsekce, díky čemuž lze dělit obsah do stromové struktury. Stránka slouží pouze k~předání obsahu a nikoliv k~dalšímu větvení struktury. Dá se tedy říci, že stránka reprezentuje list v~rámci stromovité struktury. Kořenem celého stromu je speciální sekce s~názvem \uv{index}. Každá tato část standardně využívá vlastní HTML šablonu, to není ovšem pravidlo a každá část větve může využívat jinou šablonu. To je užitečné například u~stránek s~různými druhy obsahu. V~rámci modelového webu zůstává druh obsahu stejný a není tedy třeba odchylovat se od standardní struktury. -Soubory se šablonami se nachází ve složce \texttt{templates/}, ve které generátor vždy očekává šablonu \texttt{index.html}. Ta se využívá jak k vykreslení úvodní kořenové stránky, tak jako základ, kterou mohou ostatní šablony rozšiřovat. Tato kořenová šablona tedy obsahuje základní strukturu celé stránky, přičemž navazující šablony jen mění určité části obsahu a nedefinují celou strukturu znovu. +Soubory se šablonami se nachází ve složce \texttt{templates/}, ve které generátor vždy očekává šablonu \texttt{index.html}. Ta se využívá jak k~vykreslení úvodní kořenové stránky, tak jako základ, kterou mohou ostatní šablony rozšiřovat. Tato kořenová šablona tedy obsahuje základní strukturu celé stránky, přičemž navazující šablony jen mění určité části obsahu a nedefinují celou strukturu znovu. -Generátor v šablonách hledá vlastní řídící sekvence, které se popisují závorkami. Existují tři druhy kombinací, které lze použít: +Generátor v~šablonách hledá vlastní řídící sekvence, které se popisují závorkami. Existují tři druhy kombinací, které lze použít: \begin{itemize} - \item \texttt{\{\% \%\}} -- Metoda, funkce, cykly, podmínky, práce s proměnnou atd. + \item \texttt{\{\% \%\}} -- Metoda, funkce, cykly, podmínky, práce s~proměnnou atd. \item \texttt{\{\{ \}\}} -- Výpis do HTML \item \texttt{\{\# \#\}} -- Komentář \end{itemize} -Generátor také vyžaduje konfigurační soubor \texttt{config.toml} v kořenové složce projektu, který obsahuje různé nastavení stránky, globální proměnné a chování generátoru. +Generátor také vyžaduje konfigurační soubor \texttt{config.toml} v~kořenové složce projektu, který obsahuje různé nastavení stránky, globální proměnné a chování generátoru. -\begin{lstlisting}[label=lst:jednoducha-konfigurace,caption=Příklad jednoduché konfigurace v souboru \texttt{config.toml}] +\begin{lstlisting}[label=lst:jednoducha-konfigurace,caption=Příklad jednoduché konfigurace v~souboru \texttt{config.toml}] # Adresa ze které se generují odkazy base_url = "https://ucitelonline.pedf.cuni.cz" # Název stránky @@ -45,7 +45,7 @@ description = "Web pro ditstribuci užitečných materiálů" compile_sass = true \end{lstlisting} -Systém vždy zpracuje úvodní šablonu \texttt{index.html}, ze které pak lze odvíjet ostatní šablony. Tato hlavní šablona obsahuje strukturu celé webové stránky a nesmí v ní tedy chybět validní HTML struktura, tedy hlavička, tělo, metadata, kódování a podobně. Do struktury lze vkládat libovolné řídící sekvence pro generátor, které ovlivňují výsledný výstup. +Systém vždy zpracuje úvodní šablonu \texttt{index.html}, ze které pak lze odvíjet ostatní šablony. Tato hlavní šablona obsahuje strukturu celé webové stránky a nesmí v~ní tedy chybět validní HTML struktura, tedy hlavička, tělo, metadata, kódování a podobně. Do struktury lze vkládat libovolné řídící sekvence pro generátor, které ovlivňují výsledný výstup. \begin{lstlisting}[label=lst:zakladni-sablona,caption=Základní šablona \texttt{index.html}] @@ -59,11 +59,11 @@ Systém vždy zpracuje úvodní šablonu \texttt{index.html}, ze které pak lze \end{lstlisting} -V příkladu \ref{lst:zakladni-sablona} je název stránky mezi tagy \texttt{} vyplněn generátorem. Ten do šablony vloží hodnotu konstanty \texttt{config.title}, která je nastavena v konfiguračním souboru \texttt{config.toml} z příkladu \ref{lst:jednoducha-konfigurace}. Názvem stránky bude tedy řetězec \uv{Učitel online}. Generátor dokáže převzít kteroukoliv konstantu z kontextu konfiguračního souboru. +V~příkladu \ref{lst:zakladni-sablona} je název stránky mezi tagy \texttt{} vyplněn generátorem. Ten do šablony vloží hodnotu konstanty \texttt{config.title}, která je nastavena v~konfiguračním souboru \texttt{config.toml} z~příkladu \ref{lst:jednoducha-konfigurace}. Názvem stránky bude tedy řetězec \uv{Učitel online}. Generátor dokáže převzít kteroukoliv konstantu z~kontextu konfiguračního souboru. -Všechny direktivy lze v rámci generátoru navazovat na sebe, podobně jako je tomu v Unixových systémech. Spojování funkcí a filtrů se provádí znakem \texttt{|}, stejně jako v POSIX\footnote{Portable Operating System Interface -- Rodina standardů Unixových systémů} shellu, kde výstup jednoho příkazu se stane vstupem příkazu navazujícího. Například je možné název stránky vypsat ve velkých písmenech i přesto, že v konfiguračním souboru je formátován pouze s velkým písmenem na začátku. K převedení na velká písmena slouží filtr \texttt{upper}. Názvem stránky bude po zpracování programem \ref{lst:filtr-upper} řetězec \uv{UČITEL ONLINE}. +Všechny direktivy lze v~rámci generátoru navazovat na sebe, podobně jako je tomu v~Unixových systémech. Spojování funkcí a filtrů se provádí znakem \texttt{|}, stejně jako v~POSIX\footnote{Portable Operating System Interface -- Rodina standardů Unixových systémů} shellu, kde výstup jednoho příkazu se stane vstupem příkazu navazujícího. Například je možné název stránky vypsat ve velkých písmenech i přesto, že v~konfiguračním souboru je formátován pouze s~velkým písmenem na začátku. K~převedení na velká písmena slouží filtr \texttt{upper}. Názvem stránky bude po zpracování programem \ref{lst:filtr-upper} řetězec \uv{UČITEL ONLINE}. -\begin{lstlisting}[label=lst:filtr-upper,caption=Základní šablona s filtrem pro přepsání názvu na velká písmena] +\begin{lstlisting}[label=lst:filtr-upper,caption=Základní šablona s~filtrem pro přepsání názvu na velká písmena] @@ -75,9 +75,9 @@ Všechny direktivy lze v rámci generátoru navazovat na sebe, podobně jako je \end{lstlisting} -V šabloně je také možnost vytvořit bloky, které lze v navazujících šablonách měnit. K vysvětlení principu fungování bloků je možné název stránky z příkladu \ref{lst:filtr-upper} obalit blokem \texttt{title} a těla vložit blok \texttt{content}. +V~šabloně je také možnost vytvořit bloky, které lze v~navazujících šablonách měnit. K~vysvětlení principu fungování bloků je možné název stránky z~příkladu \ref{lst:filtr-upper} obalit blokem \texttt{title} a těla vložit blok \texttt{content}. -\begin{lstlisting}[label=lst:bloky,caption=Využití bloků v šabloně z příkladu \ref{lst:filtr-upper}] +\begin{lstlisting}[label=lst:bloky,caption=Využití bloků v~šabloně z~příkladu \ref{lst:filtr-upper}] @@ -92,9 +92,9 @@ V šabloně je také možnost vytvořit bloky, které lze v navazujících šabl \end{lstlisting} -Název stránky zůstane stejný a v jejím těle přibude text \uv{Ahoj, světe!}. Vytvoříme-li novou šablonu s názvem \texttt{section.html}, generátor nám umožní rozšířit ji o původní šablonu \texttt{index.html} a měnit pouze definované bloky. Není tedy nutné znovu definovat celou strukturu stránky. Pro importování, nebo-li rozšíření šablony, slouží direktiva \texttt{extends}. +Název stránky zůstane stejný a v~jejím těle přibude text \uv{Ahoj, světe!}. Vytvoříme-li novou šablonu s~názvem \texttt{section.html}, generátor nám umožní rozšířit ji o~původní šablonu \texttt{index.html} a měnit pouze definované bloky. Není tedy nutné znovu definovat celou strukturu stránky. Pro importování, nebo-li rozšíření šablony, slouží direktiva \texttt{extends}. -\begin{lstlisting}[label=lst:sablona-section,caption=Definice nové šablony \texttt{section.html} rozšiřující šablonu z příkladu \ref{lst:bloky}] +\begin{lstlisting}[label=lst:sablona-section,caption=Definice nové šablony \texttt{section.html} rozšiřující šablonu z~příkladu \ref{lst:bloky}] {% extends "index.html" %} {% block title %}{{ config.title | upper }} – {{ section.title }}{% endblock %} {% block content %} @@ -102,9 +102,9 @@ Název stránky zůstane stejný a v jejím těle přibude text \uv{Ahoj, světe {% endblock %} \end{lstlisting} -Šablona \texttt{section.html} se v rámci generátoru Zola implicitně využívá pro všechny existující sekce\footnote{\url{https://www.getzola.org/documentation/content/section/}}. Názvem stránky v této šabloně bude, podobně jako u hlavní šablony, název stránky z konstanty \texttt{config.title} definované v konfiguračním souboru, ale také spojovník a název dané sekce. Za modelový výstup lze považovat například \uv{UČITEL ONLINE -- základní a střední škola}, bude-li se uživatel nacházet v sekci pro základní a střední školy. +Šablona \texttt{section.html} se v~rámci generátoru Zola implicitně využívá pro všechny existující sekce\footnote{\url{https://www.getzola.org/documentation/content/section/}}. Názvem stránky v~této šabloně bude, podobně jako u~hlavní šablony, název stránky z~konstanty \texttt{config.title} definované v~konfiguračním souboru, ale také spojovník a název dané sekce. Za modelový výstup lze považovat například \uv{UČITEL ONLINE -- základní a střední škola}, bude-li se uživatel nacházet v~sekci pro základní a střední školy. -V bloku s obsahem bude původní obsah \uv{Ahoj, světe!} nahrazen za řetězec \uv{Toto je obsah kategorie}. Ten ovšem nechceme definovat přímo v šabloně, nýbrž cílem generátoru je vyplňovat obsah ze zdrojových souborů v sázecím jazyce, viz. sekce \ref{kap:princip-generatoru}. Zola pro vkládání obsahu využívá stejný princip jako v ostatních případech, tedy vypsání obsahu proměnné, v tomto případě proměnné \texttt{section.content}, která obsahuje zkompilované HTML z daného Markdown souboru. Zároveň je dobrou praktikou provést vyčištění vstupu filtrem \texttt{safe}\footnote{\url{https://tera.netlify.com/docs/\#safe}}. +V~bloku s~obsahem bude původní obsah \uv{Ahoj, světe!} nahrazen za řetězec \uv{Toto je obsah kategorie}. Ten ovšem nechceme definovat přímo v~šabloně, nýbrž cílem generátoru je vyplňovat obsah ze zdrojových souborů v~sázecím jazyce, viz. sekce \ref{kap:princip-generatoru}. Zola pro vkládání obsahu využívá stejný princip jako v~ostatních případech, tedy vypsání obsahu proměnné, v~tomto případě proměnné \texttt{section.content}, která obsahuje zkompilované HTML z~daného Markdown souboru. Zároveň je dobrou praktikou provést vyčištění vstupu filtrem \texttt{safe}\footnote{\url{https://tera.netlify.com/docs/\#safe}}. \begin{lstlisting}[label=lst:sablona-section-vlozeni-obsahu,caption=Vkládání obsahu ze zdrojového Markdown souboru] @@ -115,22 +115,22 @@ V bloku s obsahem bude původní obsah \uv{Ahoj, světe!} nahrazen za řetězec {% endblock %} \end{lstlisting} -Z principu by žádný obsah neměl být definován přímo v šabloně, nýbrž by měl být do stránky vkládán generátorem z proměnných, nebo ze sázeného obsahu. V rámci modelové implementace je toto nepsané pravidlo dodržováno. +Z~principu by žádný obsah neměl být definován přímo v~šabloně, nýbrž by měl být do stránky vkládán generátorem z~proměnných, nebo ze sázeného obsahu. V~rámci modelové implementace je toto nepsané pravidlo dodržováno. \section{Automatické generování vícevrstvé navigace} -Obsah modelové implementace je dělen do stromové datové struktury o potenciálně nekonečné hloubce, kdy každá část větve je v rámci generátoru vlastní kategorií, nikoliv stránkou. Pro modelovou implementaci bylo zvoleno, aby navigace byla generována v návaznosti na aktivní cestu ve stromě. Ve stránce jsou dvě různé navigace, hlavní, která je vždy viditelná a obsahuje rozdělení obsahu dle škol a vedlejší, která zobrazuje aktivní větev stromu. +Obsah modelové implementace je dělen do stromové datové struktury o~potenciálně nekonečné hloubce, kdy každá část větve je v~rámci generátoru vlastní kategorií, nikoliv stránkou. Pro modelovou implementaci bylo zvoleno, aby navigace byla generována v~návaznosti na aktivní cestu ve stromě. Ve stránce jsou dvě různé navigace, hlavní, která je vždy viditelná a obsahuje rozdělení obsahu dle škol a vedlejší, která zobrazuje aktivní větev stromu. \begin{figure}[h]\centering \includegraphics{img/generovani-vicevrstve-navigace} \caption{Diagram průběhu generování vícevrstvé navigace} \end{figure} -První vrstvou struktury jsou hlavní sekce, v rámci implementace pojmenované jako $L_1$, které jsou vypsány vždy ve vlastní navigaci. Pod touto navigací je zobrazen seznam všech kategorií, které vybraná položka v $L_1$ obsahuje. Pokud uživatel zvolí kteroukoliv položku v $L_2$, v navigaci se objeví další sloupec, který obsahuje všechny podkategorie vybrané položky, tedy všechny podkategorie ve vrstvě $L_3$. Takto lze stromem procházet potenciálně do nekonečna. Styly modelové šablony ovšem počítají s maximální hloubkou čtyř subkategorií. +První vrstvou struktury jsou hlavní sekce, v~rámci implementace pojmenované jako $L_1$, které jsou vypsány vždy ve vlastní navigaci. Pod touto navigací je zobrazen seznam všech kategorií, které vybraná položka v~$L_1$ obsahuje. Pokud uživatel zvolí kteroukoliv položku v~$L_2$, v~navigaci se objeví další sloupec, který obsahuje všechny podkategorie vybrané položky, tedy všechny podkategorie ve vrstvě $L_3$. Takto lze stromem procházet potenciálně do nekonečna. Styly modelové šablony ovšem počítají s~maximální hloubkou čtyř subkategorií. -Tato funkcionalita je implementována pomocí tří cyklů, z nichž jeden je vložený. První cyklus (příklad \ref{lst:obsah-cyklus1}) se provádí pro všechny rodiče aktivní kategorie vrstev $L_2,L_3,\dotsc,L_n$, kde $n$ je aktuální vrstva. V každé iteraci se mění kontext, ve kterém generátor pracuje. Z daného kontextu generátor vypisuje pomocí vnořeného cyklem všechny subkategorie. Ve druhém cyklu (příklad \ref{lst:obsah-cyklus2}) se vypisují všichni potomci dané stránky, tedy potomci ve vrstvě $L_{n+1}$. +Tato funkcionalita je implementována pomocí tří cyklů, z~nichž jeden je vložený. První cyklus (příklad \ref{lst:obsah-cyklus1}) se provádí pro všechny rodiče aktivní kategorie vrstev $L_2,L_3,\dotsc,L_n$, kde $n$ je aktuální vrstva. V~každé iteraci se mění kontext, ve kterém generátor pracuje. Z~daného kontextu generátor vypisuje pomocí vnořeného cyklem všechny subkategorie. Ve druhém cyklu (příklad \ref{lst:obsah-cyklus2}) se vypisují všichni potomci dané stránky, tedy potomci ve vrstvě $L_{n+1}$. -\begin{lstlisting}[label=lst:obsah-cyklus1,caption=Cyklus pro vypisování všech rodičů v dané větvi navigace] +\begin{lstlisting}[label=lst:obsah-cyklus1,caption=Cyklus pro vypisování všech rodičů v~dané větvi navigace] {% if section.ancestors %} {% for s in section.ancestors %} {% if loop.index < 2 %}{% continue %}{% endif %} @@ -164,31 +164,31 @@ Tato funkcionalita je implementována pomocí tří cyklů, z nichž jeden je vl \section{Rozšíření šablony}\label{kap:rozsireni-sablony} -Ve výchozím stavu generátor neumí zpracovávat nic jiného, než co je uvedeno ve specifikaci CommonMark, viz. sekce \ref{kap:markdown}. Dle požadavků modelového webu je nutné, aby generátor uměl vkládat videa přímo do stránky. Taková funkcionalita není součástí specifikace CommonMark a je tedy potřeba rozšířit generátor. Nejvhodnějším způsobem přidání vlastních funkcionalit je využití filtrů, které se v rámci generátoru nazývají \uv{shortcode}. +Ve výchozím stavu generátor neumí zpracovávat nic jiného, než co je uvedeno ve specifikaci CommonMark, viz. sekce \ref{kap:markdown}. Dle požadavků modelového webu je nutné, aby generátor uměl vkládat videa přímo do stránky. Taková funkcionalita není součástí specifikace CommonMark a je tedy potřeba rozšířit generátor. Nejvhodnějším způsobem přidání vlastních funkcionalit je využití filtrů, které se v~rámci generátoru nazývají \uv{shortcode}. -Principem vlastních filtrů je to, že si uživatel vytvoří vlastní šablonu, kterou lze vyvolat pomocí speciální řídící sekvence přímo z obsahu. Každý tento shortcode může pracovat s libovolným množstvím proměnných a po zpracování vloží do místa vyvolání zkompilovaný HTML kód. Dá se tedy říci, že shortcode je v své podstatě funkce, která umí pracovat s parametry. +Principem vlastních filtrů je to, že si uživatel vytvoří vlastní šablonu, kterou lze vyvolat pomocí speciální řídící sekvence přímo z~obsahu. Každý tento shortcode může pracovat s~libovolným množstvím proměnných a po zpracování vloží do místa vyvolání zkompilovaný HTML kód. Dá se tedy říci, že shortcode je v~své podstatě funkce, která umí pracovat s~parametry. -Pro tvorbu těchto filtrů je v generátoru Zola určena složka \texttt{templates/shortcodes}, která obsahuje jejich HTML šablony a kód pro zpracování generátorem. Název HTML souboru definuje název vlastního filtru. Vytvoříme-li uvnitř této složky soubor nazvaný \texttt{video.html}, budeme v obsahu schopni využívat vlastní filtr s názvem \texttt{video}. +Pro tvorbu těchto filtrů je v~generátoru Zola určena složka \texttt{templates/shortcodes}, která obsahuje jejich HTML šablony a kód pro zpracování generátorem. Název HTML souboru definuje název vlastního filtru. Vytvoříme-li uvnitř této složky soubor nazvaný \texttt{video.html}, budeme v~obsahu schopni využívat vlastní filtr s~názvem \texttt{video}. -\begin{lstlisting}[label=lst:jednoduchy-filtr,caption=Příklad jednoduchého filtru s jedním atributem] +\begin{lstlisting}[label=lst:jednoduchy-filtr,caption=Příklad jednoduchého filtru s~jedním atributem] \end{lstlisting} -V příkladu \ref{lst:jednoduchy-filtr} bude filtr očekávat atribut \texttt{src} a bude vracet jednoduchý HTML kód pro vložení videa do stránky. Tento filtr lze vyvolat kdekoliv v obsahu, tedy v kterémkoliv souboru s koncovkou \texttt{.md}. Za názvem filtru se do závorky uvádí parametry oddělené čárkou. U posledního parametru se čárky neuvádí, což platí i v případě, kdy se uvádí pouze jeden parametr, jako je tomu v příkladu \ref{lst:vyvolani-filtru}. +V~příkladu \ref{lst:jednoduchy-filtr} bude filtr očekávat atribut \texttt{src} a bude vracet jednoduchý HTML kód pro vložení videa do stránky. Tento filtr lze vyvolat kdekoliv v~obsahu, tedy v~kterémkoliv souboru s~koncovkou \texttt{.md}. Za názvem filtru se do závorky uvádí parametry oddělené čárkou. U~posledního parametru se čárky neuvádí, což platí i v~případě, kdy se uvádí pouze jeden parametr, jako je tomu v~příkladu \ref{lst:vyvolani-filtru}. -\begin{lstlisting}[label=lst:vyvolani-filtru,caption=Vyvolání vlastního filtru s jedním parametrem] +\begin{lstlisting}[label=lst:vyvolani-filtru,caption=Vyvolání vlastního filtru s~jedním parametrem] {{ video(src="video.webm") }} \end{lstlisting} -V rámci vybraného generátoru není nutné specifikovat atributy na jeden řádek a lze je pro přehlednost vypisovat na více řádků, jako tomu je například u programu \ref{lst:formatovani-atributu}, zůstane-li dodržen způsob oddělování atributů čárkou, tedy že poslední atribut vždy zůstane bez čárky. Výstupem této direktivy bude následující HTML kód. +V~rámci vybraného generátoru není nutné specifikovat atributy na jeden řádek a lze je pro přehlednost vypisovat na více řádků, jako tomu je například u~programu \ref{lst:formatovani-atributu}, zůstane-li dodržen způsob oddělování atributů čárkou, tedy že poslední atribut vždy zůstane bez čárky. Výstupem této direktivy bude následující HTML kód. -\begin{lstlisting}[caption=Výstup direktivy z příkladu \ref{lst:jednoduchy-filtr}] +\begin{lstlisting}[caption=Výstup direktivy z~příkladu \ref{lst:jednoduchy-filtr}] \end{lstlisting} -Součástí požadavků pro modelový web jsou i citace přiložených souborů a videí. Existující filtr je tedy třeba rozšířit o možnost přiložení různých metadat. Tato metadata ovšem nejsou pro vložení videa povinná. Ve specifikaci vlastních filtrů lze využívat všechny operátory, které generátor nabízí. Nejlepším přístupem k tomuto problému je tedy využití jednoduchých podmínek, které kontrolují, zda je každá z hodnot zadána jako parametr a v případě že ano, vepíše se do obsahu. Atributy ošetřené podmínkami tedy nejsou povinné, zatímco nevyplněný atribut \texttt{src} by při generování vyvolal chybu. V následujícím příkladu jsou přidány podmínky pro kontrolu a případné vložení, jimiž jsou název videa (\texttt{title}), jméno autora (\texttt{author}) a rok vytvoření (\texttt{year}). +Součástí požadavků pro modelový web jsou i citace přiložených souborů a videí. Existující filtr je tedy třeba rozšířit o~možnost přiložení různých metadat. Tato metadata ovšem nejsou pro vložení videa povinná. Ve specifikaci vlastních filtrů lze využívat všechny operátory, které generátor nabízí. Nejlepším přístupem k~tomuto problému je tedy využití jednoduchých podmínek, které kontrolují, zda je každá z~hodnot zadána jako parametr a v~případě že ano, vepíše se do obsahu. Atributy ošetřené podmínkami tedy nejsou povinné, zatímco nevyplněný atribut \texttt{src} by při generování vyvolal chybu. V~následujícím příkladu jsou přidány podmínky pro kontrolu a případné vložení, jimiž jsou název videa (\texttt{title}), jméno autora (\texttt{author}) a rok vytvoření (\texttt{year}). -\begin{lstlisting}[label=lst:filtr-s-podminkami,caption=Filtr pro vkládání videa s využitím podmínek] +\begin{lstlisting}[label=lst:filtr-s-podminkami,caption=Filtr pro vkládání videa s~využitím podmínek] {% if title or year and author %}