From baa03a69d495f3d030806133ca0f6111e9e81021 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sun, 5 Aug 2018 12:05:45 +0200 Subject: [PATCH 01/30] Add the Snake workshop course --- courses/snake/info.yml | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 courses/snake/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml new file mode 100644 index 0000000000..af4471729e --- /dev/null +++ b/courses/snake/info.yml @@ -0,0 +1,57 @@ +title: Hadí workshop +description: Hravá ochutnávka programování +long_description: | + + Chceš se naučit programovat, ale nevíš kde začít? + Máme tu workshop právě pro tebe! + + Pod vedením instruktora vytvoříš variantu klasické videohry Had, + kterou můžeš znát třeba ze starších mobilů Nokia. + Na vlastní kůži si vyzkoušíš jak se píše kód, + jaké jsou základní programovací koncepty, a jaké to je, + když počítač přestane trucovat a začne poslouchat tvoje příkazy. + + (Přijde-li ti projekt málo praktický, nezoufej! Spíš než o hru jde + o základní programovací principy, které dál využiješ např. při tvorbě + webových aplikací, analýze dat, strojovém učení, + programování robotů nebo návrhu systémových nástrojů.) + + Workshop je pro úplné začátečníky. + Není potřeba vědět nic o programování, stačí mít počítač a umět ho používat + (např. otevřít/uložit soubor, nainstalovat program). + + Workshop je v češtině a zdarma. + + Zalíbí-li se ti tahle ochutnávka, je možnost pokračovat jedním + z podzimních začátečnických kurzů PyLadies, které začnou nedlouho + po workshopu. + + --- + + Materiály níže jsou zatím poznámky pro lektora, často psané pro + pokročilejší studenty; na workshopu budou podány v jednodušší podobě. + +vars: + coach-present: true + +plan: +- title: Workshop + slug: workshop + date: 2018-09-01 + materials: + - title: Úvod + url: null + - lesson: beginners/cmdline + title: Příkazová řádka (*) + - title: Instalalce Pygletu + url: null + - title: Základy Pythonu (podle Django Girls) + url: https://tutorial.djangogirls.org/cs/python_introduction/ + - title: "Doplnění: list slicing, del, n-tice, zip()" + url: null + - lesson: intro/pyglet + title: Úvod do Pygletu (*) + - lesson: snake/drawing + - lesson: snake/logic + - title: Zabalení spustitelného souboru (bonus) + url: null From be3754337452349e68a2c7eb2cfeafc0be6b3db0 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sun, 19 Aug 2018 20:22:37 +0200 Subject: [PATCH 02/30] Copy python-basics from DjangoGirls --- courses/snake/info.yml | 2 +- lessons/fast-track/python-basics/index.md | 847 ++++++++++++++++++++++ lessons/fast-track/python-basics/info.yml | 12 + 3 files changed, 860 insertions(+), 1 deletion(-) create mode 100644 lessons/fast-track/python-basics/index.md create mode 100644 lessons/fast-track/python-basics/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml index af4471729e..5050a9233e 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -46,7 +46,7 @@ plan: - title: Instalalce Pygletu url: null - title: Základy Pythonu (podle Django Girls) - url: https://tutorial.djangogirls.org/cs/python_introduction/ + lesson: fast-track/python-basics - title: "Doplnění: list slicing, del, n-tice, zip()" url: null - lesson: intro/pyglet diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md new file mode 100644 index 0000000000..6a197344f9 --- /dev/null +++ b/lessons/fast-track/python-basics/index.md @@ -0,0 +1,847 @@ +# Úvod do Pythonu + +> Část této kapitoly je založena na kurzu Geek Girls Carrots (https://github.com/ggcarrots/django-carrots). + +Pojďme napsat nějaký kód! + +## Interaktivní režim Pythonu + +Chceš-li si začít hrát s Pythonem, musíme otevřít *příkazový řádek* v počítači. Již bys měla vědět jak na to – naučily jsme se to v kapitole [Úvod do příkazového řádku][1]. + + [1]: ../intro_to_command_line/README.md + +Jakmile budeš připravena, postupuj podle níže uvedených pokynů. + +Chceme otevřít Python konzoli, takže napiš `python` na Windows nebo `python3` na Mac a OS/Linuxu a zmáčkni `enter`. + +``` +$ python3 +Python 3.4.3 (...) +Type "help", "copyright", "credits" or "license" for more information. +>>> +``` + +## Tvůj první příkaz v Pythonu! + +Po spuštění interaktivního režimu Python se výzva na řádku změní na `>>>`. Pro nás to znamená, že pro tuto chvíli můžeme používat pouze příkazy v jazyce Python. Není nutné zadávat `>>>` - Python to udělá za tebe. + +Pokud chceš ukončit Python konzoli, kdykoliv stačí zadat `exit()` nebo použít zkratku `Ctrl + Z` na Windows a `Ctrl + D` pro Mac/Linux. Pak již neuvidíš `>>>`. + +Pro tuto chvíli nechceme Python konzoli opustit. Chceme se o ní naučit více. Začněme s něčím opravdu jednoduchým. Například zkusme napsat nějakou matematiku. Napiš třeba `2 + 3` a zmáčkni `enter`. + +``` +>>> 2 + 3 +5 +``` + +Hezké! Vidíš, jak se zobrazila odpověď? Python umí matematiku! Můžeš zkusit jiné příkazy typu: `4 * 5` ; `5-1` ; `40 / 2` + +Chvíli si s tím hraj a pak se sem vrať zpátky :). + +Jak vidíš, Python je skvělá kalkulačka. Pokud tě zajímá, co jiného můžeš dělat... + +## Řetězce + +A co tvé jméno? Zadej své jméno do uvozovek, jak vidíš níže: + +``` +>>> "Ola" +"Ola" +``` + +Nyní jsi vytvořila svůj první řetězec! Je to posloupnost znaků, které mohou být zpracovány počítačem. Řetězec musí vždy začínat a končit stejným znakem. To může být jednoduchá (`'`) nebo dvojitá (`"`) uvozovka (neexistuje žádný rozdíl!) Uvozovkami Pythonu říkáš, že co je uvnitř, je řetězec. + +Řetězce mohou být spojovány. Zkus toto: + +``` +>>> "Ahoj " + "Ola" +'Ahoj Ola' +``` + +Také můžeš násobit řetězce s číslem: + +``` +>>> "Ola" * 3 +'OlaOlaOla' +``` + +Pokud budeš chtít dát apostrof dovnitř svého řetězce, máš dvě možnosti, jak to udělat. + +Pomocí dvojité uvozovky: + +``` +>>> "Runnin' down the hill" +"Runnin' down the hill" +``` + +nebo použít escape sekvenci - před apostrof napsat zpětné lomítko (\`): + +``` +>>> 'Runnin\' down the hill' +"Runnin' down the hill" +``` + +Pěkné, co? Chceš-li vidět své jméno velkými písmeny, jednoduše zadej: + +``` +>>> "Ola".upper() +'OLA' +``` + +Právě jsi použila `upper` **funkci** na svém řetězci! Funkce (jako `upper()`) je sled instrukcí, které Python provádí na daném objektu (`"Ola"`) poté, co ji zavoláš. + +Pokud chceš znát počet písmen ve svém jméně, tak pro to má Python také funkci! + +``` +>>> len("Ola") +3 +``` + +Zajímá tě, proč někdy voláš funkce s `.` na konci řetězce (jako `"Ola".upper()`) a někdy nejprve zavoláš funkci a vložíš řetězec do závorek? V některých případech funkce patří do objektů, jako `upper()`, což lze provést pouze u řetězců. V tomto případě nazýváme funkci **metodou**. Jindy, funkce nepatří k ničemu konkrétnímu a lze ji použít na různé typy objektů, stejně jako `len()`. To je důvod, proč předáváme `"Ola"` jako parametr pro funkci `len`. + +### Shrnutí + +OK, dost bylo řetězců. Co ses zatím naučila: + +* **interaktivní režim Pythonu** - zadávání příkazů (kódu) do Pythonového interaktivního režimu a zobrazení výsledku/odpovědi v Pythonu +* **čísla a řetězce** - v Pythonu se čísla používají pro matematiku a řetězce pro textové objekty +* **operátor** - jako + a * kombinuje hodnoty a vytvoří nové +* **funkce** - jako upper() a len() provádí akce u objektů. + +To jsou základy každého programovacího jazyka. Připravena na něco dalšího? Vsadíme se, že ano! + +## Chyby + +Pojďme zkusit něco nového. Můžeme zkusit zjistit délku čísla stejným způsobem, jakým jsme zjišťovali délku našeho jména? Zadej `len(304023)` a stiskni klávesu `Enter`: + +``` +>>> len(304023) +Traceback (most recent call last): +File "", +line 1, in +TypeError: object of type 'int' has no len() +``` + +Zobrazila se ti naše první chyba! Ta říká, že objekty typu "int" (integers, celá čísla) nemají délku. Tak co můžeme udělat teď? Možná můžeme zkusit napsat naše číslo jako řetězec? Řetězce mají délky, že? + +``` +>>> len(str(304023)) +6 +``` + +Funguje to! Použili jsme funkci `str` uvnitř funkce `len`. `str()` vše převádí na řetězec. + +* Funkce `str`převede věci do **řetězců** +* Funkce `int` převede věci na **celá čísla** + +> Důležité upozornění: můžeme převést čísla na text, ale nemůžeme jen tak převést text na čísla - co by se stalo, kdybychom se pokusily o toto: `int('hello')`? + +## Proměnné + +Důležitým konceptem v programování jsou proměnné. Proměnná není nic jiného než pojmenování něčeho, co budeme chtít použít později. Programátoři proměnné používají k ukládání dat, aby byl jejich kód čitelnější a nemuseli si pamatovat, co dané věci jsou. + +Řekněme, že chceme vytvořit novou proměnnou s názvem `name`: + +``` +>>> name = "Ola" +``` + +Vidíš? Je to snadné! Jednoduše napíšeš: name se rovná Ola. + +Jak sis jistě všimla, tvůj program nevrátil nic jako předtím. Jak tedy víme, že proměnná skutečně existuje? Jednoduše zadejte `name` a stiskni klávesu `Enter`: + +``` +>>> name +'Ola' +``` + +Hurá! První proměnná :)! Kdykoli můžeš změnit to, na co daná proměnná ukazuje: + +``` +>>> name = "Sonja" +>>> name +'Sonja' +``` + +Můžeš ji také použít ve funkcích: + +``` +>>> len(name) +5 +``` + +Super, ne? Samozřejmě proměnná může obsahovat cokoliv, například také čísla! Zkus tohle: + +``` +>>> a = 4 +>>> b = 6 +>>> a * b +24 +``` + +Ale co když použijeme nesprávné jméno? Dokážeš odhadnout, co se stane? Pojďme to zkusit! + +``` +>>> city = "Tokyo" +>>> ctiy +Traceback (most recent call last): File "", line 1, in +NameError: name 'ctiy' is not defined +``` + +Chyba! Jak vidíš, Python má různé typy chyb a tato se nazývá **NameError**. Python ti vrátí tuto chybu, pokud se pokusíš použít proměnnou, která nebyla dosud definována. Pokud někdy dojde k této chybě, zkontroluj svůj kód, abys zjistila, jestli jsi nezadala nějaké jméno nesprávně. + +Chvilku si s tím, ať vidíš, co se s tím dá dělat! + +## Funkce print + +Zkus toto: + +``` +>>> name = 'Maria' +>>> name +'Maria' +>>> print(name) +Maria +``` + +Zadáš-li jen `name`, interpretr Pythonu reaguje na řetězcovou *reprezentaci* proměnné "name", což jsou písmena M-a-r-i-a, obklopená jednoduchými uvozovkami ''. Když napíšeš `print(name)`, Python vypíše obsah proměnné na obrazovku bez uvozovek, což vypadá lépe. + +Jak uvidíme později, funkce `print()` je také užitečná, když chceme vypsat věci uvnitř funkce nebo na více řádcích. + +## Seznamy + +Vedle řetězců a celých čísel má Python další druhy různých typů objektů. Teď se podíváme na jeden, který se nazývá **list**. Seznamy jsou přesně to, co si myslíš, že jsou: jsou to objekty, které obsahují seznam ostatních objektů :) + +Nestyď se a vytvoř seznam: + +``` +>>> [] +[] +``` + +Ano, tento seznam je prázdný. Není moc užitečný, že? Pojďme vytvořit seznam čísel z loterie. Nechceme se stále opakovat, takže seznam uložíme také do proměnné: + +``` +>>> lottery = [3, 42, 12, 19, 30, 59] +``` + +Dobrá máme seznam! Co s ním můžeme dělat? Uvidíme, kolik čísel loterie je v seznamu. Máš nějakou představu, jakou funkci bys měla použít? Už to přeci víš! + +``` +>>> len(lottery) +6 +``` + +Ano! Funkce `len()` ti zjistí počet objektů v seznamu. Šikovné, že? Možná bychom je teď měli zkusit seřadit: + +``` +>>> lottery.sort() +``` + +Tato funkce nic nevrátí, jen změní pořadí čísel v seznamu. Pojďme ho znovu vypsat a uvidíme co se stalo: + +``` +>>> print(lottery) +[3, 12, 19, 30, 42, 59] +``` + +Jak můžeš vidět, čísla v seznamu jsou nyní seřazena od nejnižší k nejvyšší hodnotě. Gratulujeme! + +Můžeme také zkusit obrátit pořadí? Udělejme to! + +``` +>>> lottery.reverse() +>>> print(lottery) +[59, 42, 30, 19, 12, 3] +``` + +Snadné, že? Pokud chceš něco přidat do svého seznamu, můžeš to provést zadáním tohoto příkazu: + +``` +>>> lottery.append(199) +>>> print(lottery) +[59, 42, 30, 19, 12, 3, 199] +``` + +Pokud chceš zobrazit pouze první číslo, můžeš to udělat pomocí **indexů**. Index je číslo, které říká, kde se v seznamu položka najde. Programátoři preferují počítání od 0, takže první objekt v seznamu je v indexu 0, druhý je v indexu 1 a tak dále. Zkus toto: + +``` +>>> print(lottery[0]) +59 +>>> print(lottery[1]) +42 +``` + +Jak vidíš, pro přístup k různým objektům ve tvém seznamu použiješ jméno seznamu a index objektu uvnitř hranatých závorek. + +Chceš-li odstranit něco ze svého seznamu, budeš muset použít **indexy**, jak jsme se dozvěděli výše, a příkaz `pop()`. Zkusme to, co jsme se naučily dříve; budeme odstraňovat první číslo našeho seznamu. + +``` +>>> print(lottery) +[59, 42, 30, 19, 12, 3, 199] +>>> print(lottery[0]) +59 +>>> lottery.pop(0) +>>> print(lottery) +[42, 30, 19, 12, 3, 199] +``` + +Funguje to všechno skvěle! + +Pro další zábavu zkus nějaké jiné indexy: 6, 7, 1000, -1, -6 nebo -1000. Pokus se předpovědět výsledek před zadáním příkazu. Jsou výsledky správné? + +Seznam všech dostupných metod pro seznam nalezneš v této kapitole Python dokumentace: https://docs.python.org/3/tutorial/datastructures.html + +## Slovníky + +Slovník je podobný seznamu, ale pro přístup k hodnotám se používá klíč místo indexu. Klíč může být jakýkoli řetězec nebo číslo. Syntaxe pro definování prázdného slovníku je: + +``` +>>> {} +{} +``` + +Vidíš, že jsi právě vytvořila prázdný slovník. Hurá! + +A teď zkus napsat následující příkaz (zkus nahradit vlastními informacemi): + +``` +>>> participant = {'name': 'Ola', 'country': 'Poland', 'favorite_numbers': [7, 42, 92]} +``` + +Tímto příkazem jsi právě vytvořila proměnnou s názvem `participant` s třemi dvojicemi klíčů hodnot: + +* Klíč `name` odkazuje na hodnotu `"Ola"` (`string/řetězcový` objekt), +* klíč`country`, ukazuje na `"Polsko"` (další `řetězec`)), +* a `favorite_numbers` ukazuje `[7, 42, 92]` (`list/seznam` obsahující 3 čísla). + +Můžeš zkontrolovat obsah jednotlivých klíčů následující syntaxí: + +``` +>>> print(participant['name']) +Ola +``` + +Je to podobné seznamu. Ale není nutné si pamatovat index - jen jméno. + +Co se stane, když se zeptáme Pythonu na hodnotu klíče, který neexistuje? Zkus hádat! Pojďme to vyzkoušet a uvidíš! + +``` +>>> participant['age'] +Traceback (most recent call last): +File "", line 1, in +KeyError: 'age' +``` + +Podívej, další chyba! Toto je **KeyError**. Python ti napomáhá a řekne ti, že klíč `"věk"` v tomto slovníku neexistuje. + +Kdy použít slovník a kdy seznam? To je dobrý postřeh k zamyšlení. Kdy použít jakou variantu pochopíš, až si přečteš následující řádky. + +* Potřebuješ jen seřazenou sekvenci položek? Použij seznam. +* Pokud potřebuješ přiřadit hodnotám klíče, abys je mohla později efektivně vyhledávat (klíčem)? Používej slovník. + +Slovníky stejně jako seznamy jsou *mutable/proměnlivé*, což znamená, že je lze změnit po jejich vytvoření. Do slovníku můžeš přidat nové páry klíč/hodnota po jeho vytvoření: + +``` +>>> participant['favorite_language'] = 'Python' +``` + +Stejně jako u seznamů můžeš použít metodu `len()` na slovníky, vrací počet párů klíč/hodnota ve slovníku. Nestyď se a zadej příkaz: + +``` +>>> len(participant) +4 +``` + +Doufám, že ti to nyní dává větší smysl. :) Připravena na více zábavy se slovníky? Pojďme na další řádek a další úžasné věci. + +Příkazem `pop()` odstraníš položky ve slovníku. Například pokud chceš odstranit záznam, kterému odpovídá klíč `"favorite_numbers"`, zadej následující příkaz: + +``` +>>> participant.pop('favorite_numbers') +>>> participant +{'country': 'Poland', 'favorite_language': 'Python', 'name': 'Ola'} +``` + +Jak vidíš, z výstupu byla odstraněna odpovídající dvojice klíč hodnota 'favorite_numbers'. + +Kromě toho můžeš také změnit hodnotu přidruženou k již vytvořenému klíči ve slovníku. Napiš: + +``` +>>> participant['country'] = 'Germany' +>>> participant +{'country': 'Germany', 'favorite_language': 'Python', 'name': 'Ola'} +``` + +Jak můžeš vidět, hodnota klíče `'country'` se změnila z `"Poland"` na `"Germany"`. :) Úžasné? Hurá! Právě jsi se naučila další úžasnou věc. + +### Shrnutí + +Skvělé! Nyní víš o programování hodně. V této poslední části jsi se naučila o: + +* **errors/chyby** - nyní víš jak číst a pochopit chyby, které ti Python zobrazí, pokud nerozumí příkazu, který jsi zadala +* **proměnné/variables** - názvy pro objekty, které umožňují psát kód snadněji tak, aby byl čitelnější +* **seznamy/lists** - seznamy objektů uložených v určitém pořadí +* **slovníky/dictionaries** - objekty, které jsou uloženy jako dvojice klíč–hodnota + +Jsi připravena na další část? + +## Porovnávání věcí + +Velká část programování zahrnuje porovnání věci. Co je nejjednodušší věc k porovnání? Čísla, samozřejmě. Podívejme se, jak to funguje: + +``` +>>> 5 > 2 +True +>>> 3 < 1 +False >>> 5 > 2 * 2 +True +>>> 1 == 1 +True +>>> 5 != 2 +True +``` + +Dali jsme Pythonu nějaká čísla na porovnání. Jak vidíš, Python může porovnávat nejen čísla, ale může také porovnat výsledky metod. Pěkný, co? + +Zajímá tě, proč jsme daly dva symboly rovná se `==` vedle sebe pro porovnání, zda jsou čísla stejná? Jedno rovnítko `=` používáme pro přiřazení hodnoty do proměnné. Vždy, **vždy** musíte dát dvě rovnítka `==`, pokud chcete zkontrolovat, jestli se věci navzájem rovnají. Můžeme také zjišťovat, že se věci navzájem nerovnají. Pro takové porovnání můžeme použít symbol `!=`, jak je uvedeno v příkladu výše. + +Dejme Pythonu dva další úkoly: + +``` +>>> 6 >= 12 / 2 +True +>>> 3 <= 2 +False +``` + +`>` a `<` jsou pro použití snadné, ale co `> =` a `< =` - víš, co se tím myslí? Podívejme se na to: + +* x `>` y znamená: x je větší než y +* x `<` y znamená: x je menší než y +* x `<=` y znamená: x je menší nebo rovno y +* x `>=` y znamená: x je větší nebo rovno y + +Úžasné! Chceš zkusit ještě něco? Zkuste tohle: + +``` +>>> 6 > 2 and 2 < 3 +True +>>> 3 > 2 and 2 < 1 +False +>>> 3 > 2 or 2 < 1 +True +``` + +Pythonu můžeš dát porovnat tolik čísel kolik chceš a na vše ti dá odpověď! Je docela chytrý, že? + +* **and** - Pokud použiješ operátor `and`, obě strany musí být pravdivé, aby celý příkaz byl pravdivý +* **or** - Pokud použiješ operátor `or`, stačí, aby jen jedna strana z porovnání byla pravdivá, aby celý příkaz byl pravdivý + +Už jsi někdy slyšela výraz "srovnávat jablka a hrušky"? Zkusme v Pythonu ekvivalent: + +``` +>>> 1 > 'django' +Traceback (most recent call last): +File "", line 1, in +TypeError: '>' not supported between instances of 'int' and 'str' +``` + +Zde vidíš, že stejně jako nelze srovnávat "jablka a hrušky", Python není schopen porovnávat řetězce (`str`) a čísla (`int`). Místo toho zobrazí **TypeError** a říká nám, že tyto dva typy nelze srovnávat společně. + +## Logic hodnoty/Booleany + +Mimochodem právě jste se dozvěděly o novém typu objektu v Pythonu. Říká se mu **boolean** a je to asi nejjednodušší typ. + +Existují pouze dva logické objekty: - True - False + +Aby Python pochopil, že se jedná o tento typ, je potřeba vždy psát jako True (první písmeno velké, zbytek malý). **true, TRUE, tRUE nebude fungovat – jedině True je správně.** (Totéž samozřejmě platí pro False.) + +Pravdivostní hodnoty mohou být také v proměnné! Viz zde: + +``` +>>> a = True +>>> a +True +``` + +Rovněž to můžete provést takto: + +``` +>>> a = 2 > 5 +>>> a +False +``` + +Zkoušej a bav se s logickými hodnotami. Zkus spustit následující příkazy: + +* `True and True` +* `False and True` +* `True or 1 == 1` +* `1 != 2` + +Gratulujeme! Logické hodnoty jsou jedny z nejbezvadnějších vlastností v programování a vy jste se je právě naučily používat! + +# Ulož to! + +Zatím jsme psaly všechny naše programy v konzoli v interaktivním režimu Pythonu, který nás omezuje na jeden řádek kódu v jednu chvíli. Normální programy jsou uloženy v souborech a spouští je **konzole** nebo **překladač** programovacího jazyku. Zatím jsme spouštěly naše programy po jednom řádku v **konzoli, v interaktivním režimu** Python. Pro příštích několik úkolů budeme potřebovat více než jeden řádek kódu, takže rychle musíme: + +* Ukončit interaktivní režim Pythonu +* Otevřít náš zvolený editor kódu +* Uložit nějaký kód do nového pythonovského souboru +* Spustit ho! + +Chceš-li opustit interaktivní režim Pythonu, který jsme dosud používaly, jednoduše zadejte ~ ~ ~ exit() ~ ~ ~ funkci: + +``` +>>> exit() +$ +``` + +Tak se dostaneš zpět do příkazové řádky. + +Dříve sis vybrala editor kódu v části [editor kódu][2]. Nyní potřebujeme editor otevřít a napsat vlastní kód do nového souboru: + + [2]: ../code_editor/README.md + +```python +print('Hello, Django girls!') +``` + +> **Poznámka:** Měla bys objevit jednu z nejúžasnější věcí na editorech kódu: barvy! V interaktivním režimu Pythonu mělo vše stejnou barvu, ale nyní bys měla vidět, že funkce `print` je jinou barvou než řetězec uvnitř. To se nazývá "zvýrazňování syntaxe" a je to opravdu užitečná funkce při kódování. Barvy ti napoví, že máš neuzavřený řetězce nebo překlep v názvu slova (jako `def` ve funkci, kterou uvidíš níže). To je jeden z důvodů, proč používáme editory kódu :) + +Samozřejmě teď jsi již pěkně ostřílená python programátorka, tak neváhej napsat nějaký kód, který ses dnes naučila. + +Teď potřebujeme uložit vytvořený soubor a dát mu popisný název. Pojďme ho nazvat **python_intro.py** a uložit jej na plochu. Soubor můžeš pojmenovat jakkoliv chceš, ale důležitá věc je, aby ses ujistila, že soubor končí na **.py**. Přípona **.py** říká našemu operačnímu systému, že jde o **spustitelný soubor Pythonu** a Python ho může spustit. + +Pokud máš soubor uložen, je čas jej spustit! Pomocí dovedností, které jsi se naučila v sekci příkazová řádka, **změň adresář** pomocí terminálu na plochu. + +Na Macu bude příkaz vypadat přibližně takto: + +``` +$ cd ~/Desktop +``` + +Na Linuxu to bude vypadat takto (slovo "Desktop" (Plocha) může být přeloženo do tvého jazyka): + +``` +$ cd ~/Desktop +``` + +A na Windows to bude vypadat takto: + +``` +> cd %HomePath%\Desktop +``` + +Pokud nevíš jak dál, stačí požádat o pomoc kouče. + +Nyní pomocí Pythonu spustíš kód v souboru takto: + +``` +$ python3 python_intro.py +Hello, Django girls! +``` + +V pořádku! Právě jsi spustila svůj první program v Pythonu, který byl uložen do souboru. Cítíš se úžasně? + +Nyní můžeme přejít k základním nástrojům pro programování: + +## If...elif...else + +Spousty věcí v kódu chceme provádět, jen pokud jsou splněny určité podmínky. To je důvod, proč Python má něco, čemu se říká **if statements**. + +Nahraďte kód v souboru **python_intro.py** tímto: + +```python +if 3 > 2: +``` + +Pokud jsi soubor uložila a spustila, pravděpodobně uvidíš následující chybu: + +``` +$ python3 python_intro.py +File "python_intro.py", line 2 + ^ +SyntaxError: unexpected EOF while parsing +``` + +Python očekává, že mu dáš další pokyny, které mají být provedeny, pokud bude podmínka `3 > 2` splněna (`True`). Řekněme tedy Pythonu, ať vypíše "Funguje to!". Změň svůj kód v souboru **python_intro.py** na tento: + +```python +if 3 > 2: + print('It works!') +``` + +Všimla sis, jak jsme odsadily poslední řádek kódu o 4 mezery? Musíme to udělat, podle toho Python pozná, jakou část kódu má spustit, pokud vyhodnotí předchozí výraz jako pravdivý. Můžete udělat jen jednu mezeru, ale téměř všichni programátoři v Pythonu dělají 4, aby kód vypadal upraveně a čitelně. Jeden `Tab` bude také počítán jako 4 mezery. + +Ulož a spusť: + +``` +$ python3 python_intro.py +It works! +``` + +### Co když podmínka není pravdivá? + +V předchozích příkladech byl kód proveden pouze v případě, že podmínky byly splněny. Python má také příkazy `elif` a `else`: + +```python +if 5 > 2: + print('5 is indeed greater than 2') +else: + print('5 is not greater than 2') +``` + +Pokud je výraz pravdivý, po spuštění se vytiskne: + +``` +$ python3 python_intro.py +5 is not greater than 2 +``` + +Kdyby 2 bylo větší než 5, spustil by se první příkaz. Jak snadné! Podívejme se, jak funguje `elif`: + +```python +name = 'Sonja' +if name == 'Ola': + print('Hey Ola!') +elif name == 'Sonja': + print('Hey Sonja!') +else: + print('Hey anonymous!') +``` + +a spusť: + +``` +$ python3 python_intro.py +Hey Sonja! +``` + +Viděla jsi co se tam stalo? `elif` umožňuje přidat další podmínky, které se spustí, pokud se předchozí podmínky nezdaří. + +Můžeš po počátečním `if` přidat tolik `elif` příkazů, kolik se ti zlíbí. Například: + +```python +volume = 57 +if volume < 20: + print("Je to dost potichu.") +elif 20 <= volume < 40: + print("Jako hudba v pozadí dobré.") +elif 40 <= volume < 60: + print("Skvělé, slyším všechny detaily.") +elif 60 <= volume < 80: + print("Dobré na party.") +elif 80 <= volume < 100: + print("Trochu moc nahlas!") +else: + print("Krvácí mi uši!") +``` + +Python prochází a testuje každou položku v posloupnosti a vypíše: + +``` +$ python3 python_intro.py + Skvělé, slyším všechny detaily. +``` + +### Shrnutí + +V posledních třech cvičeních ses dozvěděla o: + +* **Porovnání věcí** - v Pythonu můžeš porovnat věci pomocí operátorů `>`, `> =`, `==` `< =`, `<` a `and`, `or` +* **Logické hodnoty / Booleany** - typy, které mohou mít pouze jednu ze dvou hodnot: `True` nebo `False` +* **Ukládání do souborů** - pokud uložíme kód do souboru, můžeme spouštět velké programy +* **if...elif...else** - příkazy, které umožňují spouštět kód pouze v případě, kdy jsou splněny určité podmínky. + +Čas na poslední část této kapitoly! + +## Vlastní funkce! + +Pamatuješ na funkci `len()`, kterou jsi spouštěla v Pythonu? Máme pro tebe dobrou zprávu. Nyní se dozvíš, jak napsat své vlastní funkce! + +Funkce je sled instrukcí, které by měl Python provést. Každá funkce v Pythonu začíná klíčovým slovem `def`, dále je uveden název a funkce může mít také nějaké parametry. Začněme u té nejlehčí. Nahraď kód v **python_intro.py** následujícím: + +```python +def hi(): + print('Hi there!') + print('How are you?') + +hi() +``` + +Naše první funkce je připravena! + +Asi se divíš, proč jsme napsaly název funkce v dolní části souboru. To je proto, že Python přečte soubor a spustí ho od shora dolů. Pokud chceš využívat svou funkci, musíš její název znovu napsat dole (tím ji zavoláš/spustíš). + +Tak to teď zkus a uvidíš, co se stane: + +``` +$ python3 python_intro.py +Hi there! +How are you? +``` + +To bylo snadné! Napišme naši první funkci s parametry. Použijeme předchozí příklad - napíšeme funkci, která nás pozdraví podle toho, jaké zadáme jméno při jejím spuštění: + +```python +def hi(name): +``` + +Jak vidíš, nyní jsme přidaly naší funkci parametr, `name`: + +```python +def hi(name): + if name == 'Ola': + print('Hi Ola!') + elif name == 'Sonja': + print('Hi Sonja!') + else: + print('Hi anonymous!') + +hi() +``` + +Pamatuj si: Funkce `print` je odsazená čtyři mezery v příkazu `if`. To je proto, aby se funkce spustila, pokud je splněna podmínka. Podívej se, jak to funguje nyní: + +``` +$ python3 python_intro.py +Traceback (most recent call last): +File "python_intro.py", line 10, in + hi() +TypeError: hi() missing 1 required positional argument: 'name' +``` + +Jejda, chyba. Naštěstí nám Python vypsal docela užitečnou chybovou zprávu. Jak vidíš, funkce `hi()` (kterou jsme definovaly) má jeden povinný parametr `(s názvem name)`, který jsme zapomněly při volání funkce předat. Pojďme to opravit v následující části: + +```python +hi("Ola") +``` + +A znovu jej spusť: + +``` +$ python3 python_intro.py +Hi Ola! +``` + +A co když změníme jméno? + +```python +hi("Sonja") +``` + +Spustíme: + +``` +$ python3 python_intro.py +Hi Sonja! +``` + +C myslíš, že se stane, když tam napíšeš jiné jméno než Ola nebo Sonja? Zkus to a uvidíme, jestli máš pravdu. Mělo by to vypsat toto: + +``` +Hi anonymous! +``` + +To je paráda, co? Nemusíš se opakovat a měnit takto jméno pokaždé, když chceš, aby funkce pozdravila jinou osobu. To je přesně důvod, proč potřebujeme funkce: abychom nikdy neopakovaly náš kód! + +Udělejme to ještě chytřeji – existuje více jmen než dvě a psaní podmínky pro každé jméno by bylo těžké, že? + +```python +def hi(name): + print('Hi ' + name + '!') + +hi("Rachel") +``` + +Pojďme zavolat náš nový kód: + +``` +$ python3 python_intro.py +Hi Rachel! +``` + +Blahopřejeme! Právě ses naučila, jak psát funkce :) + +## Smyčky/Loops + +Nyní pojďme na poslední část. To bylo rychlé, co? :) + +Programátoři se neradi opakují. Programování je o automatizaci věci, takže nechceme zdravit každého člověka podle jeho jména manuálně, že? Zde se budou smyčky hodit. + +Ještě si vzpomínáš na seznamy? Udělejme seznam dívek: + +```python +girls = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'You'] +``` + +Chceme pozdravit všechny s použitím jejich jména. Máme funkci `hi`, která to umí udělat. Tak ji použijeme ve smyčce: + +```python +for name in girls: +``` + +Příkaz ~ ~ ~ for ~ ~ ~ se chová podobně jako příkaz ~ ~ ~ if ~ ~ ~, v následujícím kódu musíme oba řádky odsadit o čtyři mezery. + +Zde je celý kód, který umístíme do souboru: + +```python +def hi(name): + print('Hi ' + name + '!') + +girls = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'You'] +for name in girls: + hi(name) + print('Next girl') +``` + +A když ho spustíme: + +``` +$ python3 python_intro.py +Hi Rachel! +Next girl +Hi Monica! +Next girl +Hi Phoebe! +Next girl +Hi Ola! +Next girl +Hi You! +Next girl +``` + +Jak vidíš, vše, co jsi vložila dovnitř příkazu `for` s odsazením, se zopakuje pro každý prvek seznamu `girls`. + +Ve funkci `for` můžeš také použít čísla pomocí funkce `range`: + +```python +for i in range(1, 6): + print(i) +``` + +Což ti vypíše: + +``` +1 +2 +3 +4 +5 +``` + +`range` je funkce, která vytvoří seznam s posloupností čísel (tato čísla zadáváš jako parametry funkce). + +Všimni si, že druhé z těchto dvou čísel není zahrnuto v seznamu, který je výstupem Pythonu (`range (1, 6)` počítá od 1 do 5, ale nezahrnuje číslo 6). To je proto, že "range" je z poloviny otevřený, čímž myslíme, že obsahuje první hodnotu, ale ne poslední. + +## Shrnutí + +A je to. **Jsi naprosto skvělá!** To byla složitá kapitola, takže bys na sebe měla být hrdá. My jsme na tebe velmi hrdí za to, že ses dostala tak daleko! + +Můžeš si jít krátce odpočinout - protáhnout se, projít se, zavřít oči - než se pustíme do další kapitoly. :) + +![Hrnek][3] + + [3]: images/cupcake.png diff --git a/lessons/fast-track/python-basics/info.yml b/lessons/fast-track/python-basics/info.yml new file mode 100644 index 0000000000..322c0d5f95 --- /dev/null +++ b/lessons/fast-track/python-basics/info.yml @@ -0,0 +1,12 @@ +title: Úvod do Pythonu +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/) +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 From adee4eef2ad821a3e7e9c9aea9bc66bce3629105 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sun, 19 Aug 2018 20:33:29 +0200 Subject: [PATCH 03/30] Some rewriting of python-basics --- lessons/fast-track/python-basics/index.md | 413 ++++++++++++++++------ 1 file changed, 313 insertions(+), 100 deletions(-) diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md index 6a197344f9..aa83a3183b 100644 --- a/lessons/fast-track/python-basics/index.md +++ b/lessons/fast-track/python-basics/index.md @@ -1,216 +1,422 @@ # Úvod do Pythonu -> Část této kapitoly je založena na kurzu Geek Girls Carrots (https://github.com/ggcarrots/django-carrots). +> Tento text je založen na materiálech [Django Girls](https://tutorial.djangogirls.org/cs/python_introduction/) a [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). -Pojďme napsat nějaký kód! +Pojď napsat nějaký kód! ## Interaktivní režim Pythonu -Chceš-li si začít hrát s Pythonem, musíme otevřít *příkazový řádek* v počítači. Již bys měla vědět jak na to – naučily jsme se to v kapitole [Úvod do příkazového řádku][1]. +Chceš-li si začít hrát s Pythonem, otevři *příkazový řádek* a aktivuj virtuální prostředí. Zkontroluj si, že na začátku příkazové řádky ti svítí `(venv)`. - [1]: ../intro_to_command_line/README.md +Je-li tomu tak, nezbývá než – konečně – pustit Python. K tomu použij příkaz `python`: -Jakmile budeš připravena, postupuj podle níže uvedených pokynů. - -Chceme otevřít Python konzoli, takže napiš `python` na Windows nebo `python3` na Mac a OS/Linuxu a zmáčkni `enter`. - -``` +``` console $ python3 -Python 3.4.3 (...) +Python 3.6.6 (...) Type "help", "copyright", "credits" or "license" for more information. >>> ``` -## Tvůj první příkaz v Pythonu! +Příkaz vypíše několik informací. Z prvního řádku se můžeš ujistit, že používáš Python 3. (Vidíš-li číslo jako `2.7.11`, něco je špatně – popros o radu kouče.) -Po spuštění interaktivního režimu Python se výzva na řádku změní na `>>>`. Pro nás to znamená, že pro tuto chvíli můžeme používat pouze příkazy v jazyce Python. Není nutné zadávat `>>>` - Python to udělá za tebe. +Třemi „zobáčky“ ``>>>` pak Python poprosí o instrukce. Je to jako v příkazové řádce, ale místo příkazů jako `cd` a `mkdir` sem budeš psát příkazy Pythonu. -Pokud chceš ukončit Python konzoli, kdykoliv stačí zadat `exit()` nebo použít zkratku `Ctrl + Z` na Windows a `Ctrl + D` pro Mac/Linux. Pak již neuvidíš `>>>`. +Jako první instrukci použijeme Pythonu jako kalkulačku. +Za tři zobáčky napiš třeba `2 + 3` a zmáčkni Enter. -Pro tuto chvíli nechceme Python konzoli opustit. Chceme se o ní naučit více. Začněme s něčím opravdu jednoduchým. Například zkusme napsat nějakou matematiku. Napiš třeba `2 + 3` a zmáčkni `enter`. - -``` +``` pycon >>> 2 + 3 5 ``` -Hezké! Vidíš, jak se zobrazila odpověď? Python umí matematiku! Můžeš zkusit jiné příkazy typu: `4 * 5` ; `5-1` ; `40 / 2` +Zobrazila se ti správná odpověď? +Pokud ano, gratuluji! První příkaz v Pythonu máš za sebou. -Chvíli si s tím hraj a pak se sem vrať zpátky :). +Zkusíš i odečítání? + +A jak je to s násobením? +{# XXX: Jak zapsat násobení? `4 x 5` `4 . 5` `4 × 5` `4 * 5` -#} +Na kalkulačce bys zadala `4 × 5`, což se na klávesnici píše špatně. +Python proto používá symbol `*` a pro dělení `/`. +Tyhle symboly se odborně nazývají *operátory*. + +``` pycon +>>> 4 * 5 +20 +>>> 40 / 2 +20.0 +``` + +{# XXX: +Kolik je +123 + 456789? +#} + +> [style-note] +> Mezery mezi čísly a znamínkem nejsou nutné: `4*5` nebo `4 * 5` dělá +> to samé. +> Je ale zvykem používat jednu mezeru – tak jako to vidíš v materiálech. +> Kód je tak čitelnější. -Jak vidíš, Python je skvělá kalkulačka. Pokud tě zajímá, co jiného můžeš dělat... ## Řetězce -A co tvé jméno? Zadej své jméno do uvozovek, jak vidíš níže: +Čísla jsou pro počítače dost užitečná (ostatně slovo *počítač* to naznačuje), +ale Python umí pracovat i s jinými druhy informací. +Třeba s textem. -``` ->>> "Ola" -"Ola" +Zkus si to: zadej své jméno do uvozovek, jak vidíš níže: + +``` pycon +>>> 'Ola' +'Ola' ``` -Nyní jsi vytvořila svůj první řetězec! Je to posloupnost znaků, které mohou být zpracovány počítačem. Řetězec musí vždy začínat a končit stejným znakem. To může být jednoduchá (`'`) nebo dvojitá (`"`) uvozovka (neexistuje žádný rozdíl!) Uvozovkami Pythonu říkáš, že co je uvnitř, je řetězec. +Nyní jsi vytvořil{{a}} svůj první *řetězec*! +Řetězec je programátorský termín pro *text* – posloupnost znaků (písmenek), které mohou být zpracovány počítačem. -Řetězce mohou být spojovány. Zkus toto: +Když řetězec zadáváš, musíš ho vždy uzavřít do uvozovek (apostrofů). +Jinak by Python nepoznal, co je text a co jsou instrukce. -``` ->>> "Ahoj " + "Ola" -'Ahoj Ola' -``` +{# XXX: Assessment here: adding strings together #} -Také můžeš násobit řetězce s číslem: +Řetězce se dají spojovat – „sečítat“ – pomocí `+`. Zkus toto: +``` pycon +>>> 'Já jsem ' + 'Ola' +'Já jsem Ola' ``` ->>> "Ola" * 3 + +> [note] +> Pozor na mezeru! Když zadáš `'Já jsem'+'Ola'`, spojí se ti dvě slova +> dohromady. +> Počítač považuje mezeru za znak, a chová se k ní stejně jako k jakémukoli +> písmenku. +> Když nedáš mezeru do uvozovek, nebude součástí řetězce. +> Zkus si: +> +> ``` pycon +> >>> 'Já jsem' + ' ' + 'Ola' +> 'Já jsem Ola' +> ``` + +Také můžeš řetězce opakovat – násobit číslem: + +``` pycon +>>> 'Ola' * 3 'OlaOlaOla' ``` -Pokud budeš chtít dát apostrof dovnitř svého řetězce, máš dvě možnosti, jak to udělat. +### Uvozování -Pomocí dvojité uvozovky: +A co když budeš chtít dát dovnitř do svého řetězce apostrof? +Můžeš kolem řetězce použít dvojité uvozovky: -``` ->>> "Runnin' down the hill" -"Runnin' down the hill" +``` pycon +>>> "To bych řek', že jsou pořádně praštěný!" +"To bych řek', že jsou pořádně praštěný!" ``` -nebo použít escape sekvenci - před apostrof napsat zpětné lomítko (\`): +Pythonu je jedno, se kterým druhem uvozovek řetězec zadáš. +Podstatná jsou jen písmenka uvnitř. +Když Python řetězec vypisuje, může si vybrat jiný druh uvozovek +než jsi použil{{a}} ty: +``` pycon +>>> "Ola" +'Ola' ``` ->>> 'Runnin\' down the hill' -"Runnin' down the hill" -``` -Pěkné, co? Chceš-li vidět své jméno velkými písmeny, jednoduše zadej: +### Funkce a metody + +Už umíš řetězce „sčítat“ pomocí `+` (`'Ahoj ' + 'Olo!'`) +a „násobit“ pomocí `*` (`'la' * 3`). +Na všechny ostatní věci, které se s textem dají dělat, +ale na klávesnici není dost symbolů. +Proto jsou některé operace pojmenované slovně – třeba takzvané *funkce*. + +Chceš-li znát počet písmen ve svém jméně, zavolej funkci `len`. +Napiš `len` (bez uvozovek), pak kulaté závorky, a do těch závorek +své jméno (jako řetězec – v uvozovkách): +``` pycon +>>> len('Ola') +3 ``` ->>> "Ola".upper() + +{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} + +Kromě funkcí existují *metody*, které se zapisují trochu jinak. + +Chceš-li vidět své jméno velkými písmeny, zavolej metody `upper`. +Napiš řetězec, pak tečku, jméno metody `upper` (bez uvozovek) a prázdné +závorky: + +``` pycon +>>> 'Ola'.upper() 'OLA' ``` -Právě jsi použila `upper` **funkci** na svém řetězci! Funkce (jako `upper()`) je sled instrukcí, které Python provádí na daném objektu (`"Ola"`) poté, co ji zavoláš. +Zkus si zavolat metodu `lower`. + +{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} -Pokud chceš znát počet písmen ve svém jméně, tak pro to má Python také funkci! +Co je metoda (které voláš s `.`, jako `'Ola'.upper()`) a co je funkce +(kde vložíš informaci do závorek jako (`len('Ola')`) + +### Shrnutí +OK, dost bylo řetězců. Co ses zatím naučil{{a}}: + +* **Interaktivní režim Pythonu** umožňuje zadávat příkazy (kód) pro + Python a zobrazuje výsledky/odpovědi. +* **Čísla a řetězce** se používají na matematiku a práci s textem. +* **Operátor** jako `+` a `*` kombinuje hodnoty a vytvoří výsledek. +* **Funkce** a **metody** jako `len()` a `upper()` provádí na hodnotách + nějaké akce. + +Čísla, řetězce a operátory a funkce jsou základy většiny programovacích jazyků. + +Připraven{{a}} na něco dalšího? Vsadíme se, že ano! + + +## Skládání + +Volání funkce nebo metody můžeš použít jako jinou hodnotu. + +Nech Python spočítat matematický výraz `(1 + 3) / 2`: + +```pycon +>>> (1 + 3) / 2 +2.0 ``` ->>> len("Ola") -3 + +Python napřed sečte `1 + 3` a vyjde mu 4. +Čtverku doplní místo `1 + 3` do původního příkladu, a dostane `4 / 2`. +To vydělí a dostane `2`. + +Neboli: `(1 + 3) / 2` = `4 / 2` = `2` + +Zkus se zamyslet, jak Python zpracuje tyto výrazy: + +```pycon +>>> len('Ola') + 1 +4 ``` -Zajímá tě, proč někdy voláš funkce s `.` na konci řetězce (jako `"Ola".upper()`) a někdy nejprve zavoláš funkci a vložíš řetězec do závorek? V některých případech funkce patří do objektů, jako `upper()`, což lze provést pouze u řetězců. V tomto případě nazýváme funkci **metodou**. Jindy, funkce nepatří k ničemu konkrétnímu a lze ji použít na různé typy objektů, stejně jako `len()`. To je důvod, proč předáváme `"Ola"` jako parametr pro funkci `len`. +```pycon +>>> 'Já jsem ' + 'Ola'.upper() +'Já jsem OLA' +``` -### Shrnutí +```pycon +>>> len('Ola'.upper()) +4 +``` + +```pycon +>>> len('Ola' * 3) +9 +``` + +{% filter solution() %} +`'Já jsem ' + 'Ola'.upper()` → `'Já jsem ' + 'OLA'` → `'Já jsem OLA'` -OK, dost bylo řetězců. Co ses zatím naučila: +`len('Ola') + 1` → `3 + 1` → `4` -* **interaktivní režim Pythonu** - zadávání příkazů (kódu) do Pythonového interaktivního režimu a zobrazení výsledku/odpovědi v Pythonu -* **čísla a řetězce** - v Pythonu se čísla používají pro matematiku a řetězce pro textové objekty -* **operátor** - jako + a * kombinuje hodnoty a vytvoří nové -* **funkce** - jako upper() a len() provádí akce u objektů. +`len('Ola'.upper())` → `len('OLA')` → `3` + +`len('Ola' * 3)` → `len('OlaOlaOla')` → `9` +{% endfilter %} + + +Podobné skládání je v programování velice časté. +Většinu základních stavebních bloků se začátečník naučí za pár +týdnů – a pak je po celou svou progrmátorskou kariéru skládá do +složitějších a složitějších konstrukcí. -To jsou základy každého programovacího jazyka. Připravena na něco dalšího? Vsadíme se, že ano! ## Chyby -Pojďme zkusit něco nového. Můžeme zkusit zjistit délku čísla stejným způsobem, jakým jsme zjišťovali délku našeho jména? Zadej `len(304023)` a stiskni klávesu `Enter`: +Pojď zkusit něco nového: zjistit délku čísla stejným způsobem, +jakým jsme zjišťovali délku našeho jména. +Zadej `len(304023)` a stiskni Enter: -``` +``` pycon >>> len(304023) Traceback (most recent call last): -File "", -line 1, in + File "", line 1, in TypeError: object of type 'int' has no len() ``` -Zobrazila se ti naše první chyba! Ta říká, že objekty typu "int" (integers, celá čísla) nemají délku. Tak co můžeme udělat teď? Možná můžeme zkusit napsat naše číslo jako řetězec? Řetězce mají délky, že? +{# XXX: tohle nebude první chyba... #} +Zobrazila se ti naše první chyba! +Ta říká, že objekty typu `int` (zkratka anglického *integer*, celé číslo) +nemají délku. +Tak co můžeme udělat teď? +Možná můžeme zkusit napsat naše číslo jako řetězec? +Řetězce mají délky, že? +```pycon +>>> len("304023") +6 ``` + +Existuje i funkce, která *převede* číslo na řetězec. Jmenuje se `str`: + +```pycon +>>> str(304023) +"304023" >>> len(str(304023)) 6 ``` -Funguje to! Použili jsme funkci `str` uvnitř funkce `len`. `str()` vše převádí na řetězec. +Podobně funkce `int` převádí věci na celá čísla: -* Funkce `str`převede věci do **řetězců** -* Funkce `int` převede věci na **celá čísla** +```pycon +>>> int("304023") +``` -> Důležité upozornění: můžeme převést čísla na text, ale nemůžeme jen tak převést text na čísla - co by se stalo, kdybychom se pokusily o toto: `int('hello')`? +Můžeš převést čísla na text, ale nemůžeš jen tak převést text na čísla. +Co by se stalo, kdyby ses pokusil{{a}} na číslo převést řetězec, ve kterém +nejsou číslice? + +{% filter solution() %} +``` pycon +>>> int('hello') +Traceback (most recent call last): + File "", line 1, in +ValueError: invalid literal for int() with base 10: 'ahoj' +``` +{% endfilter %} ## Proměnné -Důležitým konceptem v programování jsou proměnné. Proměnná není nic jiného než pojmenování něčeho, co budeme chtít použít později. Programátoři proměnné používají k ukládání dat, aby byl jejich kód čitelnější a nemuseli si pamatovat, co dané věci jsou. +Důležitým konceptem v programování jsou *proměnné*. +Proměnná není nic jiného než *pojmenování* něčeho, +co budeme chtít použít později. +Programátoři proměnné používají k ukládání dat, +aby byl jejich kód čitelnější a nemuseli si pamatovat konkrétní hodnoty. -Řekněme, že chceme vytvořit novou proměnnou s názvem `name`: +Řekněme, že chceš vytvořit novou proměnnou s názvem `jmeno`. +To se zapíše takto: -``` ->>> name = "Ola" +``` pycon +>>> jmeno = 'Ola' ``` -Vidíš? Je to snadné! Jednoduše napíšeš: name se rovná Ola. +Proměnná `jmeno` teď bude mít hodnotu `'Ola'`. -Jak sis jistě všimla, tvůj program nevrátil nic jako předtím. Jak tedy víme, že proměnná skutečně existuje? Jednoduše zadejte `name` a stiskni klávesu `Enter`: +Jak sis mohl{{a}} všimnout, tenhle příkaz nic nevrátil – Python nevypsal +žádný výslede. +Jak tedy víme, že proměnná skutečně existuje? -``` ->>> name +Zadej samotné jméno proměnné (tedy `jmeno`) a stiskni Enter: + +``` pycon +>>> jmeno 'Ola' ``` -Hurá! První proměnná :)! Kdykoli můžeš změnit to, na co daná proměnná ukazuje: +Zkus si nastavit i jinou proměnnou – třeba svoji oblíbenou barvu: +``` pycon +>>> barva = 'modrá' +>>> barva +'modrá' ``` ->>> name = "Sonja" ->>> name -'Sonja' + +Kdykoli můžeš do proměnné přiřadit znovu, a změnit tak co se pod +daným jménem skrývá: + +``` pycon +>>> jmeno +'Ola' +>>> jmeno = "Soňa" +>>> jmeno +'Soňa' ``` Můžeš ji také použít ve funkcích: -``` ->>> len(name) -5 +``` pycon +>>> len(jmeno) +4 ``` -Super, ne? Samozřejmě proměnná může obsahovat cokoliv, například také čísla! Zkus tohle: +Super, ne? +Proměnná může obsahovat cokoliv, například také čísla! +Zkus tohle: -``` ->>> a = 4 ->>> b = 6 ->>> a * b +``` pycon +>>> sirka = 4 +>>> delka = 6 +>>> sirka * delka 24 ``` -Ale co když použijeme nesprávné jméno? Dokážeš odhadnout, co se stane? Pojďme to zkusit! +Ale co když použiješ nesprávné jméno? Dokážeš odhadnout, co se stane? +{% filter solution %} +``` pycon +>>> mesto = "Tokyo" +>>> mmesto +Traceback (most recent call last): + File "", line 1, in +NameError: name 'mmesto' is not defined ``` ->>> city = "Tokyo" ->>> ctiy -Traceback (most recent call last): File "", line 1, in -NameError: name 'ctiy' is not defined -``` +{% endfilter %} + +Chyba! -Chyba! Jak vidíš, Python má různé typy chyb a tato se nazývá **NameError**. Python ti vrátí tuto chybu, pokud se pokusíš použít proměnnou, která nebyla dosud definována. Pokud někdy dojde k této chybě, zkontroluj svůj kód, abys zjistila, jestli jsi nezadala nějaké jméno nesprávně. +Python má různé typy chyb. Tato se nazývá `NameError`. +Python ti vrátí tuto chybu, pokud se pokusíš použít proměnnou, +která dosud nebyla nastavena. +Pokud někdy dojde k této chybě, zkontroluj svůj kód, abys zjistil{{a}}, +jestli jsi někde neudělal{{a}} překlep. + +> [note] Jména proměnných +> Profesionální programátoři pojmenovávají proměnné anglicky, +> aby jim rozuměli co nejvíc kolegů po celém světě. +> Ze začátku ale doporučujeme češtinu – je tak jasnější, která jména +> si můžeš zvolit {{gnd('sám', 'sama')}} (např. `barva`) a která jsou +> z Pythonu (např. `upper`). +> +> Je ovšem dobré se nepoužívat diakritiku a vyhnout se velkým pímenům: +> místo `Jméno` použij jen `jmeno`. -Chvilku si s tím, ať vidíš, co se s tím dá dělat! ## Funkce print Zkus toto: -``` ->>> name = 'Maria' ->>> name -'Maria' ->>> print(name) -Maria +``` pycon +>>> jmeno = 'Marie' +>>> jmeno +'Marie' +>>> print(jmeno) +Marie ``` -Zadáš-li jen `name`, interpretr Pythonu reaguje na řetězcovou *reprezentaci* proměnné "name", což jsou písmena M-a-r-i-a, obklopená jednoduchými uvozovkami ''. Když napíšeš `print(name)`, Python vypíše obsah proměnné na obrazovku bez uvozovek, což vypadá lépe. +Zadáš-li jen `name`, Python vypíše řetězec obklopený jednoduchými uvozovkami. +To je *reprezentace* řetězce `'Marie'` – způsob, jak tuhle hodnotu +zadat v Pythonu. -Jak uvidíme později, funkce `print()` je také užitečná, když chceme vypsat věci uvnitř funkce nebo na více řádcích. +Funkce `print`, místo toho vypíše hodnotu bez uvozovek, což vypadá lépe +(i když pro progrmátora to může být méně užitečné). + +Jak uvidíme později, vypisování pomocí funkce `print()` je také užitečná, +když chceme vypsat věci uvnitř funkce nebo na více řádcích. + +{# XXX: why is print here??? #} ## Seznamy -Vedle řetězců a celých čísel má Python další druhy různých typů objektů. Teď se podíváme na jeden, který se nazývá **list**. Seznamy jsou přesně to, co si myslíš, že jsou: jsou to objekty, které obsahují seznam ostatních objektů :) +Vedle řetězců a celých čísel má Python další druhy různých typů hodnot. +Teď se podíváme na jeden, který se nazývá *seznam* (anglicky *list*). +Seznamy jsou přesně to, co si myslíš, že jsou: jsou to objekty, které obsahují seznam ostatních objektů :) + +{# Anglické termíny všude! #} Nestyď se a vytvoř seznam: @@ -498,6 +704,13 @@ Chceš-li opustit interaktivní režim Pythonu, který jsme dosud používaly, j $ ``` +{# (((((((( XXX )))))))) #} +> [Note] +> Pokud budeš chtít Python konzoli ukončit, zadej `exit()` nebo použíj +> zkratku `Ctrl + D` (pro Mac/Linux) nebo `Ctrl + Z` (na Windows). +> Pak již neuvidíš `>>>`. + + Tak se dostaneš zpět do příkazové řádky. Dříve sis vybrala editor kódu v části [editor kódu][2]. Nyní potřebujeme editor otevřít a napsat vlastní kód do nového souboru: From 95514d0c6e6b2fe0f2a1c96402f176240bb24df9 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sun, 19 Aug 2018 21:40:17 +0200 Subject: [PATCH 04/30] More intro rewriting, mainly on lists --- lessons/fast-track/python-basics/index.md | 243 ++++++++++++++++++---- 1 file changed, 197 insertions(+), 46 deletions(-) diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md index aa83a3183b..ccf0b32ce6 100644 --- a/lessons/fast-track/python-basics/index.md +++ b/lessons/fast-track/python-basics/index.md @@ -43,20 +43,32 @@ Tyhle symboly se odborně nazývají *operátory*. ``` pycon >>> 4 * 5 20 ->>> 40 / 2 -20.0 +>>> 5 / 2 +2.5 ``` +> [note] +> V tomto úvodu budeme zadávat jen celá čísla. +> Dělením ale může vzniknout třeba dva a půl +> (tedy `2.5` – Python používá desetinnou *tečku*). +> Z důvodů, do kterých teď nebudeme zabíhat, se desetinné pozice po dělení +> objeví i když vyjde celé číslo: +> ``` pycon +> >>> 4 / 2 +> 2.0 +> ``` + {# XXX: Kolik je 123 + 456789? #} > [style-note] -> Mezery mezi čísly a znamínkem nejsou nutné: `4*5` nebo `4 * 5` dělá -> to samé. -> Je ale zvykem používat jednu mezeru – tak jako to vidíš v materiálech. -> Kód je tak čitelnější. +> Mezery mezi čísly a znamínkem nejsou nutné: `4*5` i `4 * 5` dělá +> to samé co `4 * 5`. +> Je ale zvykem psát kolem operátoru jednu mezeru z každé strany – tak jako +> v těchto materiálech. +> Kód je pak čitelnější. ## Řetězce @@ -90,9 +102,10 @@ Jinak by Python nepoznal, co je text a co jsou instrukce. > [note] > Pozor na mezeru! Když zadáš `'Já jsem'+'Ola'`, spojí se ti dvě slova > dohromady. -> Počítač považuje mezeru za znak, a chová se k ní stejně jako k jakémukoli +> Počítač považuje i mezeru za *znak*; chová se k ní stejně jako k jakémukoli > písmenku. > Když nedáš mezeru do uvozovek, nebude součástí řetězce. +> > Zkus si: > > ``` pycon @@ -412,91 +425,229 @@ když chceme vypsat věci uvnitř funkce nebo na více řádcích. ## Seznamy -Vedle řetězců a celých čísel má Python další druhy různých typů hodnot. +Vedle řetězců a celých čísel má Python další druhy hodnot. + Teď se podíváme na jeden, který se nazývá *seznam* (anglicky *list*). -Seznamy jsou přesně to, co si myslíš, že jsou: jsou to objekty, které obsahují seznam ostatních objektů :) +To je hodnota, která v sobě obsahuje jiné hodnoty. {# Anglické termíny všude! #} -Nestyď se a vytvoř seznam: +Seznamy se zadávají tak, že dáš několik hodnot, oddělených čárkami, +do hranatých závorek. +Zkus si vytvořit třeba seznam čísel z loterie: +``` pycon +>>> [3, 42, 12, 19, 30, 59] +[3, 42, 12, 19, 30, 59] ``` ->>> [] -[] + +Abys s takovým seznamem mohl{{a}} pracovat, +ulož si ho do proměnné: + +``` pycon +>>> loterie = [3, 42, 12, 19, 30, 59] ``` -Ano, tento seznam je prázdný. Není moc užitečný, že? Pojďme vytvořit seznam čísel z loterie. Nechceme se stále opakovat, takže seznam uložíme také do proměnné: +Dobrá, máme seznam! Co s ním můžeme dělat? +Podíváme se, kolik čísel v seznamu je. +Dá se na to použít funkce, kterou už znáš. +Tipneš si, která to je? +{% filter solution %} +``` pycon +>>> len(loterie) +6 ``` ->>> lottery = [3, 42, 12, 19, 30, 59] + +Funkce `len()` umí zjistit nejen délku řetězce, ale i délku seznamu – tedy +počet jeho prvků. +{% endfilter %} + +Teď si zkus seznam seřadit. Na to existuje metoda `sort`: + +``` pycon +>>> loterie.sort() ``` -Dobrá máme seznam! Co s ním můžeme dělat? Uvidíme, kolik čísel loterie je v seznamu. Máš nějakou představu, jakou funkci bys měla použít? Už to přeci víš! +Tato funkce nic nevrátí, jen změní pořadí čísel v seznamu. +Znovu si ho vypiš, ať vidíš co se stalo: +``` pycon +>>> print(loterie) +[3, 12, 19, 30, 42, 59] ``` ->>> len(lottery) -6 + +Čísla v seznamu jsou nyní seřazena od nejnižší k nejvyšší hodnotě. + +Podobně funguje metoda `reverse`, která obrátí pořadí prvků. +Vyzkoušej si ji! + +``` pycon +>>> loterie.reverse() +>>> print(loterie) +[59, 42, 30, 19, 12, 3] ``` -Ano! Funkce `len()` ti zjistí počet objektů v seznamu. Šikovné, že? Možná bychom je teď měli zkusit seřadit: +Pokud chceš do svého něco přidat seznamu, můžeš to provést pomocí metody +`append`. +Ale pozor! Tahle metoda potřebuje vědět co má do seznamu přidat +Nová hodnota se zadává do závorek: +``` pycon +>>> loterie.append(199) ``` ->>> lottery.sort() + +Metoda opět nic nevrací, takže je potřeba seznam pro kontrolu vypsat: + +``` pycon +>>> print(loterie) +[59, 42, 30, 19, 12, 3, 199] ``` -Tato funkce nic nevrátí, jen změní pořadí čísel v seznamu. Pojďme ho znovu vypsat a uvidíme co se stalo: +### Vybírání prvků + +Když se budeš chtít na jednu věc ze seznamu podívat podrobněji, +přijde vhod možnost vybrat si konkrétní prvek. +Na to se v Pythonu používají hranaté závorky. +{# XXX: MCQ #} + +Chceš-li vybrat prvek, zadej jméno seznamu a hned za ním hranaté závorky +s pořadovým číslem prvku, který chceš: + +``` pycon +>>> loterie[1] ``` ->>> print(lottery) -[3, 12, 19, 30, 42, 59] + +Dostaneš první prvek? + +{% filter solution %} +``` pycon +>>> loterie +[59, 42, 30, 19, 12, 3, 199] +>>> loterie[1] +42 ``` -Jak můžeš vidět, čísla v seznamu jsou nyní seřazena od nejnižší k nejvyšší hodnotě. Gratulujeme! +Ne, dostaneš druhý prvek. -Můžeme také zkusit obrátit pořadí? Udělejme to! +Programátoři počítají od nuly. +Chceš li tedy první prvek, popros Python o prvek číslo nula: +``` pycon +>>> loterie[0] +42 ``` ->>> lottery.reverse() ->>> print(lottery) -[59, 42, 30, 19, 12, 3] + +Je to zpočátku divné, ale dá se na to zvyknout. +{% endfilter %} + +Číslu prvku se také říká *index* a procesu vybírání prvků *indexování*. + +Zkus si indexování s dalšími indexy: 3, 100, 7, -1, -2, -6 nebo -100. +Pokus se předpovědět výsledek před zadáním příkazu. +Jak ti to půjde? + +{% filter solution %} +``` pycon +>>> loterie +[59, 42, 30, 19, 12, 3, 199] + +>>> loterie[3] +19 ``` +Index 3 označuje čtvrtý prvek. -Snadné, že? Pokud chceš něco přidat do svého seznamu, můžeš to provést zadáním tohoto příkazu: +``` pycon +>>> loterie[7] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range ``` ->>> lottery.append(199) ->>> print(lottery) -[59, 42, 30, 19, 12, 3, 199] +Prvek s indexem 100 v seznamu není – nastane chyba. + +``` pycon +>>> loterie[1000] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range ``` +Prvek s indexem 7 v seznamu taky není. -Pokud chceš zobrazit pouze první číslo, můžeš to udělat pomocí **indexů**. Index je číslo, které říká, kde se v seznamu položka najde. Programátoři preferují počítání od 0, takže první objekt v seznamu je v indexu 0, druhý je v indexu 1 a tak dále. Zkus toto: +``` pycon +>>> loterie[-1] +199 +``` +Index -1 označuje *poslední* prvek. +``` pycon +>>> loterie[-2] +3 ``` ->>> print(lottery[0]) -59 ->>> print(lottery[1]) +Index -2 označuje předposlední prvek. + +``` pycon +>>> loterie[-6] 42 ``` +Index -6 označuje šestý prvek od konce. -Jak vidíš, pro přístup k různým objektům ve tvém seznamu použiješ jméno seznamu a index objektu uvnitř hranatých závorek. +``` pycon +>>> loterie[-100] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range +``` +Stý prvek od konce v seznamu není. Nastane chyba. +{% endfilter %} + +### Řezání + +XXX Slicing -Chceš-li odstranit něco ze svého seznamu, budeš muset použít **indexy**, jak jsme se dozvěděli výše, a příkaz `pop()`. Zkusme to, co jsme se naučily dříve; budeme odstraňovat první číslo našeho seznamu. +### Odstraňování +Chceš-li ze seznamu něco odstranit, můžeš opět použít indexy. +Tentokrát s příkazem `del`. +Následující kód odstraní počáteční číslo seznamu, tedy prvek číslo 0: + +``` pycon +>>> del loterie[0] ``` ->>> print(lottery) -[59, 42, 30, 19, 12, 3, 199] ->>> print(lottery[0]) -59 ->>> lottery.pop(0) ->>> print(lottery) + +Pak si seznam opět vypiš. Kousek chybí! + +``` pycon +>>> loterie [42, 30, 19, 12, 3, 199] ``` -Funguje to všechno skvěle! +Zkusíš odstranit poslední prvek? + +{% filter solution %} +``` pycon +>>> del loterie[-1] +>>> loterie +[42, 30, 19, 12, 3] +``` +{% endfilter %} -Pro další zábavu zkus nějaké jiné indexy: 6, 7, 1000, -1, -6 nebo -1000. Pokus se předpovědět výsledek před zadáním příkazu. Jsou výsledky správné? +A co prostřední tři? +Zkus si nejdřív vypsat, které to jsou, a pak teprve použít `del`. + +{% filter solution %} +``` pycon +>>> loterie +[42, 30, 19, 12, 3] +>>> loterie[1:-1] +[30, 19, 12] +>>> del loterie[1:-1] +>>> loterie +[42, 3] +``` +{% endfilter %} -Seznam všech dostupných metod pro seznam nalezneš v této kapitole Python dokumentace: https://docs.python.org/3/tutorial/datastructures.html ## Slovníky From 506e0ee1d2b573416360b23a3a457bc137db8697 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 28 Aug 2018 14:38:54 +0200 Subject: [PATCH 05/30] Rewrite intro to dicts --- courses/snake/info.yml | 2 +- lessons/fast-track/python-basics/index.md | 154 ++++++++++++++-------- 2 files changed, 102 insertions(+), 54 deletions(-) diff --git a/courses/snake/info.yml b/courses/snake/info.yml index 5050a9233e..9079c789d3 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -45,7 +45,7 @@ plan: title: Příkazová řádka (*) - title: Instalalce Pygletu url: null - - title: Základy Pythonu (podle Django Girls) + - title: Základy Pythonu lesson: fast-track/python-basics - title: "Doplnění: list slicing, del, n-tice, zip()" url: null diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md index ccf0b32ce6..b2883855a8 100644 --- a/lessons/fast-track/python-basics/index.md +++ b/lessons/fast-track/python-basics/index.md @@ -651,97 +651,145 @@ Zkus si nejdřív vypsat, které to jsou, a pak teprve použít `del`. ## Slovníky -Slovník je podobný seznamu, ale pro přístup k hodnotám se používá klíč místo indexu. Klíč může být jakýkoli řetězec nebo číslo. Syntaxe pro definování prázdného slovníku je: +Jiný typ hodnot, které v sobě mohou obsahovat další hodnoty, je *slovník*. +Pro příklad si představ překladový slovník, třeba česko-anglický: -``` ->>> {} -{} -``` +* **Jablko**: Apple +* **Knoflík**: Button +* **Myš**: Mouse -Vidíš, že jsi právě vytvořila prázdný slovník. Hurá! +Slovník v Pythonu obsahuje záznamy, a každý záznam přiřazuje +nějakému *klíči* nějakou *hodnotu*. +V našem příkladu je klíči *Jablko* přiřazena hodnota *Apple*, +klíči *Knoflík* náleží hodnota *Button* +a klič *Myš* ukazuje na *Mouse*. -A teď zkus napsat následující příkaz (zkus nahradit vlastními informacemi): +V Pythonu by se takový slovník napsal následovně: -``` ->>> participant = {'name': 'Ola', 'country': 'Poland', 'favorite_numbers': [7, 42, 92]} +``` pycon +>>> slovnik = {'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'} ``` -Tímto příkazem jsi právě vytvořila proměnnou s názvem `participant` s třemi dvojicemi klíčů hodnot: +Naše klíče a hodnoty jsou slova – krátké texty, tedy řetězce, +které je potřeba dát do uvozovek. +Klíč a hodnota jsou oddělené dvojtečkou, +jednotlivé dvojice se od sebe oddělují čárkou, +a celý slovník je uzavřený ve složených závorkách. -* Klíč `name` odkazuje na hodnotu `"Ola"` (`string/řetězcový` objekt), -* klíč`country`, ukazuje na `"Polsko"` (další `řetězec`)), -* a `favorite_numbers` ukazuje `[7, 42, 92]` (`list/seznam` obsahující 3 čísla). +Když budeš chtít v takovém slovníku něco najít, potřebuješ vědět, co hledat. +Konkrétně *klíč*. +Pomocí hranatých závorek můžeš zjistit hodnotu, která odpovídá danému klíči: -Můžeš zkontrolovat obsah jednotlivých klíčů následující syntaxí: +``` pycon +>>> slovnik['Jablko'] +'Apple' ``` ->>> print(participant['name']) -Ola -``` -Je to podobné seznamu. Ale není nutné si pamatovat index - jen jméno. +Je to podobné jako u seznamů, jen v hranatých závorkách není pořadí prvku, +ale klíč. +{# XXX: Slicing taky nejde #} + +> [note] +> Naopak to nejde – slovník neumožňuje podle hodnoty přímo zjistit klíč. +> Na překlad z angličtiny do češtiny bys potřeboval{{a}} druhý slovník. -Co se stane, když se zeptáme Pythonu na hodnotu klíče, který neexistuje? Zkus hádat! Pojďme to vyzkoušet a uvidíš! +### Měnění slovníků -``` ->>> participant['age'] +Co se stane, když klíč ve slovníku není? + +``` pycon +>>> slovnik['Pes'] Traceback (most recent call last): -File "", line 1, in -KeyError: 'age' + File "", line 1, in +KeyError: 'Pes' ``` -Podívej, další chyba! Toto je **KeyError**. Python ti napomáhá a řekne ti, že klíč `"věk"` v tomto slovníku neexistuje. +Python si postěžuje na `KeyError` – chybu klíče. -Kdy použít slovník a kdy seznam? To je dobrý postřeh k zamyšlení. Kdy použít jakou variantu pochopíš, až si přečteš následující řádky. +Podobně jako seznamy se ale slovníky dají měnit. +Nový záznam vytvoříš takhle: -* Potřebuješ jen seřazenou sekvenci položek? Použij seznam. -* Pokud potřebuješ přiřadit hodnotám klíče, abys je mohla později efektivně vyhledávat (klíčem)? Používej slovník. +``` pycon +>>> slovnik['Pes'] = 'Dog' +>>> slovnik +{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Dog'} +``` + +> [note] +> Na rozdíl od překladového slovníku nemusí být Pythonní slovník seřazený +> podle abecedy. +> Není to potřeba, počítač umí rychle vyhledávat i bez seřazení. -Slovníky stejně jako seznamy jsou *mutable/proměnlivé*, což znamená, že je lze změnit po jejich vytvoření. Do slovníku můžeš přidat nové páry klíč/hodnota po jeho vytvoření: +Kdybys potřebovala{{a}} změnit už existující záznam, použij stejný příkaz. +K jednomu klíči může patřit jen jedna hodnota. +``` pycon +>>> slovnik['Pes'] = 'Extension cord' +>>> slovnik +{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Extension cord'} ``` ->>> participant['favorite_language'] = 'Python' -``` -Stejně jako u seznamů můžeš použít metodu `len()` na slovníky, vrací počet párů klíč/hodnota ve slovníku. Nestyď se a zadej příkaz: +{# XXX: Zmínit se o nehomogenních slovnících? #} + +Chceš-li ze zlovníku nějaký záznam smazat, dělá se to podobně jako +u seznamů příkazem `del`: +``` pycon +>>> del slovnik['Pes'] +>>> slovnik +{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'} ``` ->>> len(participant) -4 + +A když budeš chtít zjistit, kolik je ve slovníku záznamů, +zeptáš se podobně jako na počet znaků řetězce nebo prvků seznamu. +Použiješ funkci `len()`. + +``` pycon +>>> len(slovnik) +3 ``` -Doufám, že ti to nyní dává větší smysl. :) Připravena na více zábavy se slovníky? Pojďme na další řádek a další úžasné věci. +{# XXX -Příkazem `pop()` odstraníš položky ve slovníku. Například pokud chceš odstranit záznam, kterému odpovídá klíč `"favorite_numbers"`, zadej následující příkaz: +### K zamyšlení -``` ->>> participant.pop('favorite_numbers') ->>> participant -{'country': 'Poland', 'favorite_language': 'Python', 'name': 'Ola'} -``` +Ke každému klíči může patřit jen jedna hodnota. +Jak bys zařídil{{a}}, aby hodnot víc? -Jak vidíš, z výstupu byla odstraněna odpovídající dvojice klíč hodnota 'favorite_numbers'. +Zkus do Pythonní proměnné uložit tyto kontakty: -Kromě toho můžeš také změnit hodnotu přidruženou k již vytvořenému klíči ve slovníku. Napiš: +* Katka: + * 4925219 +* Jirka: + * 7477058 + * 3251156 +* Verča: + * 1019103 +{% filter solution %} +Více hodnot se dá uložit do seznamu. +Hodnoty budou seznamy čísel: + +```pycon +>>> kontakty = {'Katka': ['4925219'], 'Jirka': ['7477058', '3251156'], 'Verča': ['1019103']} ``` ->>> participant['country'] = 'Germany' ->>> participant -{'country': 'Germany', 'favorite_language': 'Python', 'name': 'Ola'} -``` +{% endfilter %} -Jak můžeš vidět, hodnota klíče `'country'` se změnila z `"Poland"` na `"Germany"`. :) Úžasné? Hurá! Právě jsi se naučila další úžasnou věc. +Verča se přestěhovala do zahraničí a má nové číslo: `+897 3788509`. + +#} ### Shrnutí -Skvělé! Nyní víš o programování hodně. V této poslední části jsi se naučila o: +Skvělé! Nyní víš o programování hodně. V této poslední části jsi poznal{{a}}: -* **errors/chyby** - nyní víš jak číst a pochopit chyby, které ti Python zobrazí, pokud nerozumí příkazu, který jsi zadala -* **proměnné/variables** - názvy pro objekty, které umožňují psát kód snadněji tak, aby byl čitelnější -* **seznamy/lists** - seznamy objektů uložených v určitém pořadí -* **slovníky/dictionaries** - objekty, které jsou uloženy jako dvojice klíč–hodnota +* **chyby** - hlášky které Python zobrazí když nerozumí příkazu který jsi zadal{{a}} nebo ho neumí splnit +* **proměnné** - názvy pro objekty, které umožňují psát čitelnější kód +* **seznam** - sekvence objektů uložených v určitém pořadí +* **slovník** - sbírka záznamů klíč–hodnota -Jsi připravena na další část? +Jsi připraven{{a}} na další část? ## Porovnávání věcí From 704f0a7af6ccb6839930f8a6f53a47b729415179 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 28 Aug 2018 16:25:13 +0200 Subject: [PATCH 06/30] Work on logic & saving --- courses/snake/info.yml | 10 +- lessons/fast-track/python-basics/index.md | 408 +++++++++++++--------- 2 files changed, 254 insertions(+), 164 deletions(-) diff --git a/courses/snake/info.yml b/courses/snake/info.yml index 9079c789d3..1c9663af10 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -35,9 +35,13 @@ vars: coach-present: true plan: -- title: Workshop - slug: workshop - date: 2018-09-01 +- title: Příprava + slug: preparation + materials: + - lesson: beginners/cmdline + - lesson: beginners/install +- title: Úvod do Pythonu + slug: intro materials: - title: Úvod url: null diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md index b2883855a8..f1170dd751 100644 --- a/lessons/fast-track/python-basics/index.md +++ b/lessons/fast-track/python-basics/index.md @@ -398,31 +398,6 @@ jestli jsi někde neudělal{{a}} překlep. > Je ovšem dobré se nepoužívat diakritiku a vyhnout se velkým pímenům: > místo `Jméno` použij jen `jmeno`. - -## Funkce print - -Zkus toto: - -``` pycon ->>> jmeno = 'Marie' ->>> jmeno -'Marie' ->>> print(jmeno) -Marie -``` - -Zadáš-li jen `name`, Python vypíše řetězec obklopený jednoduchými uvozovkami. -To je *reprezentace* řetězce `'Marie'` – způsob, jak tuhle hodnotu -zadat v Pythonu. - -Funkce `print`, místo toho vypíše hodnotu bez uvozovek, což vypadá lépe -(i když pro progrmátora to může být méně užitečné). - -Jak uvidíme později, vypisování pomocí funkce `print()` je také užitečná, -když chceme vypsat věci uvnitř funkce nebo na více řádcích. - -{# XXX: why is print here??? #} - ## Seznamy Vedle řetězců a celých čísel má Python další druhy hodnot. @@ -473,7 +448,7 @@ Tato funkce nic nevrátí, jen změní pořadí čísel v seznamu. Znovu si ho vypiš, ať vidíš co se stalo: ``` pycon ->>> print(loterie) +>>> loterie [3, 12, 19, 30, 42, 59] ``` @@ -484,7 +459,7 @@ Vyzkoušej si ji! ``` pycon >>> loterie.reverse() ->>> print(loterie) +>>> loterie [59, 42, 30, 19, 12, 3] ``` @@ -500,7 +475,7 @@ Nová hodnota se zadává do závorek: Metoda opět nic nevrací, takže je potřeba seznam pro kontrolu vypsat: ``` pycon ->>> print(loterie) +>>> loterie [59, 42, 30, 19, 12, 3, 199] ``` @@ -752,6 +727,10 @@ Použiješ funkci `len()`. {# XXX +* Kontakty +* Když číslo není číslo +* Více čísel + ### K zamyšlení Ke každému klíči může patřit jen jedna hodnota. @@ -793,43 +772,56 @@ Jsi připraven{{a}} na další část? ## Porovnávání věcí -Velká část programování zahrnuje porovnání věci. Co je nejjednodušší věc k porovnání? Čísla, samozřejmě. Podívejme se, jak to funguje: +Programátoři často porovnávají různé hodnoty. Pojďme se podívat, jak na to. -``` +``` pycon >>> 5 > 2 True ->>> 3 < 1 -False >>> 5 > 2 * 2 -True ->>> 1 == 1 -True ->>> 5 != 2 +>>> 5 > 8 +False +>>> 5 < 8 True ``` -Dali jsme Pythonu nějaká čísla na porovnání. Jak vidíš, Python může porovnávat nejen čísla, ale může také porovnat výsledky metod. Pěkný, co? +Když se Pythonu zeptáš, jestli je jedno číslo větší než druhé, odpoví ti +`True` (pravda) nebo `False` (nepravda). + +Funguje to i se složitějšími výrazy: -Zajímá tě, proč jsme daly dva symboly rovná se `==` vedle sebe pro porovnání, zda jsou čísla stejná? Jedno rovnítko `=` používáme pro přiřazení hodnoty do proměnné. Vždy, **vždy** musíte dát dvě rovnítka `==`, pokud chcete zkontrolovat, jestli se věci navzájem rovnají. Můžeme také zjišťovat, že se věci navzájem nerovnají. Pro takové porovnání můžeme použít symbol `!=`, jak je uvedeno v příkladu výše. +``` pycon +>>> 5 > 2 * 2 +True +``` -Dejme Pythonu dva další úkoly: +„Větší než“ a „menší než“ používají značky známé z matematiky. +Chceš-li se ale zeptat, jestli jsou dvě čísla stejná, je to trochu jiné: +``` pycon +>>> 1 == 1 +True ``` ->>> 6 >= 12 / 2 + +Jedno rovnítko `=` používáme pro přiřazení hodnoty do proměnné. +Když chceš zkontrolovat, jestli se věci navzájem rovnají, vždy, **vždy** musíš dát dvě rovnítka `==`. + +Další možnosti porovnávání jsou nerovnost (≠), větší než (≤) a meší než (≥). +Většina lidí tyhle symboly nemá na klávesnici, a tak se používá `!=`, `<=` +a `>=`. + +``` pycon +>>> 5 != 2 True >>> 3 <= 2 False +>>> 6 >= 12 / 2 +True ``` -`>` a `<` jsou pro použití snadné, ale co `> =` a `< =` - víš, co se tím myslí? Podívejme se na to: - -* x `>` y znamená: x je větší než y -* x `<` y znamená: x je menší než y -* x `<=` y znamená: x je menší nebo rovno y -* x `>=` y znamená: x je větší nebo rovno y +### Logika -Úžasné! Chceš zkusit ještě něco? Zkuste tohle: +Chceš zkusit ještě něco? Zkus tohle: -``` +``` pycon >>> 6 > 2 and 2 < 3 True >>> 3 > 2 and 2 < 1 @@ -838,39 +830,45 @@ False True ``` -Pythonu můžeš dát porovnat tolik čísel kolik chceš a na vše ti dá odpověď! Je docela chytrý, že? +V Pythonu můžeš zkombinovat několik porovnání do jednoho! -* **and** - Pokud použiješ operátor `and`, obě strany musí být pravdivé, aby celý příkaz byl pravdivý -* **or** - Pokud použiješ operátor `or`, stačí, aby jen jedna strana z porovnání byla pravdivá, aby celý příkaz byl pravdivý +* Pokud použiješ operátor `and`, obě strany musí být pravdivé, aby byl celý výraz pravdivý. +* Pokud použiješ operátor `or`, stačí aby jen jedna strana z porovnání byla pravdivá. -Už jsi někdy slyšela výraz "srovnávat jablka a hrušky"? Zkusme v Pythonu ekvivalent: +Už jsi někdy slyšel{{a}} výraz „srovnávat jablka a hrušky“? Zkusme v Pythonu ekvivalent: -``` ->>> 1 > 'django' +``` pycon +>>> 1 > 'krajta' Traceback (most recent call last): -File "", line 1, in + File "", line 1, in TypeError: '>' not supported between instances of 'int' and 'str' ``` -Zde vidíš, že stejně jako nelze srovnávat "jablka a hrušky", Python není schopen porovnávat řetězce (`str`) a čísla (`int`). Místo toho zobrazí **TypeError** a říká nám, že tyto dva typy nelze srovnávat společně. +Stejně jako nelze srovnávat „jablka a hrušky“, +Python není schopen porovnávat řetězce (`str`) a čísla (`int`). +Místo toho zobrazí `TypeError` a říká nám, že tyto dva typy nelze porovnat. -## Logic hodnoty/Booleany -Mimochodem právě jste se dozvěděly o novém typu objektu v Pythonu. Říká se mu **boolean** a je to asi nejjednodušší typ. +### Logické hodnoty -Existují pouze dva logické objekty: - True - False +Mimochodem právě ses dozvěděl{{a}} o novém typu objektu v Pythonu. +Říká se mu *pravdivostní hodnota*, nebo častěji anglicky *boolean*. -Aby Python pochopil, že se jedná o tento typ, je potřeba vždy psát jako True (první písmeno velké, zbytek malý). **true, TRUE, tRUE nebude fungovat – jedině True je správně.** (Totéž samozřejmě platí pro False.) +Může mít jednu z dvou hodnot: `True` a `False`. -Pravdivostní hodnoty mohou být také v proměnné! Viz zde: +Aby Python pochopil, že se jedná o tento typ, +je potřeba dávat pozor na velikost písmen. +`true`, `TRUE`, `tRUE` nebude fungovat – jedině `True` je správně. -``` +Jako kažtou hodnotu, i pravdivostní hodnotu můžeš uložit do proměnné: + +``` pycon >>> a = True >>> a True ``` -Rovněž to můžete provést takto: +Stejně tak můžeš uložit i výsledek porovnání: ``` >>> a = 2 > 5 @@ -878,31 +876,36 @@ Rovněž to můžete provést takto: False ``` -Zkoušej a bav se s logickými hodnotami. Zkus spustit následující příkazy: +# Ulož to! -* `True and True` -* `False and True` -* `True or 1 == 1` -* `1 != 2` +Zatím jsi psal{{a}} všechny programy v konzoli v interaktivním režimu Pythonu, +který nás omezuje na jeden řádek kódu. +Když Python opustíš (nebo vypneš počítač), +všechno co jsi zatím naprogramoval{{a}}, se ztratí. -Gratulujeme! Logické hodnoty jsou jedny z nejbezvadnějších vlastností v programování a vy jste se je právě naučily používat! +Větší programy jsou trvanlivější: ukládají se do souborů a dají se kdykoli +spustit znovu. -# Ulož to! - -Zatím jsme psaly všechny naše programy v konzoli v interaktivním režimu Pythonu, který nás omezuje na jeden řádek kódu v jednu chvíli. Normální programy jsou uloženy v souborech a spouští je **konzole** nebo **překladač** programovacího jazyku. Zatím jsme spouštěly naše programy po jednom řádku v **konzoli, v interaktivním režimu** Python. Pro příštích několik úkolů budeme potřebovat více než jeden řádek kódu, takže rychle musíme: +Vyzkoušejme si to. Budeme potřebovat: * Ukončit interaktivní režim Pythonu -* Otevřít náš zvolený editor kódu -* Uložit nějaký kód do nového pythonovského souboru +* Otevřít editor kódu +* Uložit kód do nového souboru * Spustit ho! -Chceš-li opustit interaktivní režim Pythonu, který jsme dosud používaly, jednoduše zadejte ~ ~ ~ exit() ~ ~ ~ funkci: +Zkus vypnout Python. Existuje na to funkce `exit()`: -``` +``` pycon >>> exit() -$ ``` +Tak se dostaneš zpět do příkazové řádky. +Budou tu fungovat příkazy jako `cd` a `mkdir`, +ale ne příkazy Pythonu, jako `1 + 1`. + +Chceš-li opustit interaktivní režim Pythonu, který jsme dosud používaly, jednoduše zadejte ~ ~ ~ exit() ~ ~ ~ funkci: + + {# (((((((( XXX )))))))) #} > [Note] > Pokud budeš chtít Python konzoli ukončit, zadej `exit()` nebo použíj @@ -912,162 +915,245 @@ $ Tak se dostaneš zpět do příkazové řádky. -Dříve sis vybrala editor kódu v části [editor kódu][2]. Nyní potřebujeme editor otevřít a napsat vlastní kód do nového souboru: - - [2]: ../code_editor/README.md +Doufám, že máš nainstalovaný textový editor. +Ten teď otevři a napiš do nového souboru tento příkaz: ```python -print('Hello, Django girls!') -``` - -> **Poznámka:** Měla bys objevit jednu z nejúžasnější věcí na editorech kódu: barvy! V interaktivním režimu Pythonu mělo vše stejnou barvu, ale nyní bys měla vidět, že funkce `print` je jinou barvou než řetězec uvnitř. To se nazývá "zvýrazňování syntaxe" a je to opravdu užitečná funkce při kódování. Barvy ti napoví, že máš neuzavřený řetězce nebo překlep v názvu slova (jako `def` ve funkci, kterou uvidíš níže). To je jeden z důvodů, proč používáme editory kódu :) - -Samozřejmě teď jsi již pěkně ostřílená python programátorka, tak neváhej napsat nějaký kód, který ses dnes naučila. - -Teď potřebujeme uložit vytvořený soubor a dát mu popisný název. Pojďme ho nazvat **python_intro.py** a uložit jej na plochu. Soubor můžeš pojmenovat jakkoliv chceš, ale důležitá věc je, aby ses ujistila, že soubor končí na **.py**. Přípona **.py** říká našemu operačnímu systému, že jde o **spustitelný soubor Pythonu** a Python ho může spustit. +print('Hello, PyLadies!') +``` + +Teď vytvořený soubor ulož pod nějakým popisným názvem. +Pojďme ho nazvat `python_intro.py` a ulož si jej na plochu. +Soubor můžeš pojmenovat jakkoliv chceš, ale jméno musí končit na `.py` +Tahle přípona říká editoru nebo i operačnímu systému, +že jde o program v Pythonu a Python ho může spustit. + +> [note] Obarvování +> Po uložení by se text měl obarvit. +> V interaktivním režimu Pythonu mělo vše stejnou barvu, +> ale nyní bys měla vidět, že jméno funkce `print` je jinou barvou než +> řetězec v závorkách. +> Barvy nevolíš {{gnd('sám', 'sama')}}, vybírá je editor na základě toho, +> jak potom Python kódu porozumí. +> +> Nazývá se to "zvýrazňování syntaxe" a je to užitečná funkce. +> Chce to trochu praxe, ale barvy můžou napovědět +> že ti chybí uvozovka za řetězcem +> nebo máš překlep v klíčovém slovu jako `del`. +> To je jeden z důvodů, proč používáme editory kódu :) -Pokud máš soubor uložen, je čas jej spustit! Pomocí dovedností, které jsi se naučila v sekci příkazová řádka, **změň adresář** pomocí terminálu na plochu. +Pokud máš soubor uložen, je čas jej spustit! +Pomocí dovedností, které jsi se naučil{{a}} v sekci příkazová řádka, +*změň adresář* terminálu na plochu. Na Macu bude příkaz vypadat přibližně takto: -``` -$ cd ~/Desktop +``` console +(venv) $ cd ~/Desktop ``` -Na Linuxu to bude vypadat takto (slovo "Desktop" (Plocha) může být přeloženo do tvého jazyka): +Na Linuxu to bude vypadat takto (slovo "Desktop" (Plocha) může být +přeloženo třeba do češtiny): -``` -$ cd ~/Desktop +``` console +(venv) $ cd ~/Desktop ``` A na Windows to bude vypadat takto: -``` -> cd %HomePath%\Desktop +``` doscon +(venv) > cd Desktop ``` -Pokud nevíš jak dál, stačí požádat o pomoc kouče. +Pokud nevíš jak dál, požádej o pomoc kouče. -Nyní pomocí Pythonu spustíš kód v souboru takto: +Nyní pomocí Pythonu spusť kód v souboru: -``` -$ python3 python_intro.py -Hello, Django girls! +``` console +(venv) $ python python_intro.py +Hello, PyLadies! ``` -V pořádku! Právě jsi spustila svůj první program v Pythonu, který byl uložen do souboru. Cítíš se úžasně? +Funguje? Vidíš text? +Jesli ano, právě jsi spustil{{a}} svůj první opravdový program v Pythonu! +Cítíš se úžasně? -Nyní můžeme přejít k základním nástrojům pro programování: +### Vstup a výstup -## If...elif...else +Funkce `print()`, kterou jsi použila, umí něco *vypsat* na obrazovku. +V konzoli se hodnoty výrazů vypisovaly automaticky, abys je mohl{{a}} +průběžně kontrolovat, ale programy v souborech bývají složitější a výpis +každého kroku by byl nepřehledný. +Proto na vypsání potřebuješ `print()`. +Zkus si to: -Spousty věcí v kódu chceme provádět, jen pokud jsou splněny určité podmínky. To je důvod, proč Python má něco, čemu se říká **if statements**. +``` python +jmeno = 'Ola' -Nahraďte kód v souboru **python_intro.py** tímto: +'Já jsem ' + jmeno # Tohle Python nevypíše -```python -if 3 > 2: +print(jmeno * 8) # Tohle jo! ``` -Pokud jsi soubor uložila a spustila, pravděpodobně uvidíš následující chybu: +Do závorek funkce `print()` můěš dát i víc hodnot oddělených čárkami. +``` python +jmeno = 'Amálka' +vek = 5 +print('Já jsem', jmeno, 'a je mi', vek) + +print('Za rok mi bude', vek + 1) ``` -$ python3 python_intro.py -File "python_intro.py", line 2 - ^ -SyntaxError: unexpected EOF while parsing + +Další užitečná funkce je `input()`, která se umí zeptat na otázku. +Odpověď pak vrátí jako řetězec, který si můžeš uložit do proměnné: + +``` python +jmeno = input('Jak se jmenuješ? ') +print(jmeno, 'umí programovat!') ``` -Python očekává, že mu dáš další pokyny, které mají být provedeny, pokud bude podmínka `3 > 2` splněna (`True`). Řekněme tedy Pythonu, ať vypíše "Funguje to!". Změň svůj kód v souboru **python_intro.py** na tento: +A co když budeš chtít spíš číslo než text? +Pamatuješ si na funkci, která umí převést řetězec na číslo? -```python -if 3 > 2: - print('It works!') +``` python +letopocet = int(input('Jaký je letos rok? ')) +print('Loni byl rok', letopocet - 1) ``` -Všimla sis, jak jsme odsadily poslední řádek kódu o 4 mezery? Musíme to udělat, podle toho Python pozná, jakou část kódu má spustit, pokud vyhodnotí předchozí výraz jako pravdivý. Můžete udělat jen jednu mezeru, ale téměř všichni programátoři v Pythonu dělají 4, aby kód vypadal upraveně a čitelně. Jeden `Tab` bude také počítán jako 4 mezery. -Ulož a spusť: +## Když – tak -``` -$ python3 python_intro.py -It works! +Spoustu věcí v kódu chceme provádět, jen pokud jsou splněny určité podmínky. +Proto má Python *podmíněné příkazy*. + +Zkusíme napsat program, který ověřuje tajné heslo. +Tenhle program napíše `True`, když zadáš slovo `čokoláda`: + +```python +heslo = input('Zadej heslo: ') +print(heslo == 'čokoláda') ``` -### Co když podmínka není pravdivá? +Vypsání `True` ale není moc zajímavé. +Lepší program by dělal tohle: -V předchozích příkladech byl kód proveden pouze v případě, že podmínky byly splněny. Python má také příkazy `elif` a `else`: +* Zeptá se na tajné heslo +* Když je heslo správné: + * Pustí uživatele dovnitř + +V Pythonu se „když“ řekne `if`. Používá se takhle: ```python -if 5 > 2: - print('5 is indeed greater than 2') -else: - print('5 is not greater than 2') +heslo = input('Zadej heslo: ') +if heslo == 'čokoláda': + print('Správně! Račte vstoupit.') ``` -Pokud je výraz pravdivý, po spuštění se vytiskne: +Podmíněný příkaz začíná `if`, pokračuje podmínkou (třeba porovnáním) +a končí dvojtečkou. +Po řádkem s `if` je příkaz *odsazený* – na začátku řádku jsou 4 mezery. + +Podle toho Python pozná, že tuhle část programu má provést, +jen když je podmínka pravdivá. + +Ulož a spusť: + +``` console +(venv) $ python python_intro.py +Zadej heslo: čokoláda +Správně! Můžeš vstoupit. ``` -$ python3 python_intro.py -5 is not greater than 2 + +``` console +(venv) $ python python_intro.py +Zadej heslo: sezam ``` -Kdyby 2 bylo větší než 5, spustil by se první příkaz. Jak snadné! Podívejme se, jak funguje `elif`: +### Jinak + +V předchozím příkladu byl kód proveden pouze v případě, že podmínka byla splněna. +Ještě lepší program by ale: + +* Zeptá se na tajné heslo +* Když je heslo správné: + * Pustí uživatele dovnitř +* Jinak: + * Spustí alarm + +Python má také příkazy `elif` a `else`: ```python -name = 'Sonja' -if name == 'Ola': - print('Hey Ola!') -elif name == 'Sonja': - print('Hey Sonja!') +heslo = input('Zadej heslo: ') +if heslo == 'čokoláda': + print('Správně! Račte vstoupit.') else: - print('Hey anonymous!') + print('POZOR! POZOR! NEOPRÁVNĚNÝ VSTUP!') ``` -a spusť: +Funuje to? -``` -$ python3 python_intro.py -Hey Sonja! -``` +### Více možností + +Občas se stane, že se program musí rozhodnout mezi více možnostmi. +K tomu slouží příkaz `elif`, zkratka znglického *else if* – „jinak, pokud“. + +Napišme program, který okomentuje hlasitost hudby: -Viděla jsi co se tam stalo? `elif` umožňuje přidat další podmínky, které se spustí, pokud se předchozí podmínky nezdaří. +* Zeptá se na hlasitost, a odpověď uloží jako číslo. +* Když je hlasitost do 20: + * vypíše „Je to dost potichu.“ +* Jinak, když je hlasitost do 40: + * vypíše „Jako hudba v pozadí dobré.“ +* Jinak, když je hlasitost do 60: + * vypíše „Skvělé, slyším všechny detaily.“ +* Jinak, když je hlasitost do 80: + * vypíše „Dobré na párty.“ +* Jinak, když je hlasitost do 100: + * vypíše „Trochu moc nahlas!“ +* Jinak: + * vypíše „Krvácí mi uši!“ -Můžeš po počátečním `if` přidat tolik `elif` příkazů, kolik se ti zlíbí. Například: +V Pythonu: ```python -volume = 57 -if volume < 20: +hlasitost = int(input('Jaká je nastavená hlasitost rádia? ')) +if hlasitost < 20: print("Je to dost potichu.") -elif 20 <= volume < 40: +elif hlasitost < 40: print("Jako hudba v pozadí dobré.") -elif 40 <= volume < 60: +elif hlasitost < 60: print("Skvělé, slyším všechny detaily.") -elif 60 <= volume < 80: +elif hlasitost < 80: print("Dobré na party.") -elif 80 <= volume < 100: +elif hlasitost < 100: print("Trochu moc nahlas!") else: print("Krvácí mi uši!") ``` -Python prochází a testuje každou položku v posloupnosti a vypíše: - -``` -$ python3 python_intro.py - Skvělé, slyším všechny detaily. +``` console +(venv) $ python python_intro.py +Jaká je nastavená hlasitost rádia? 28 +Jako hudba v pozadí dobré. ``` +Všimni si, že se vybere vždycky jedna alternativa. +Když zadáš `28`, Python se dostane k `hlasitost < 40`, vypíše +příslušnou hlášku a další možnosti přeskočí. + + ### Shrnutí V posledních třech cvičeních ses dozvěděla o: -* **Porovnání věcí** - v Pythonu můžeš porovnat věci pomocí operátorů `>`, `> =`, `==` `< =`, `<` a `and`, `or` -* **Logické hodnoty / Booleany** - typy, které mohou mít pouze jednu ze dvou hodnot: `True` nebo `False` -* **Ukládání do souborů** - pokud uložíme kód do souboru, můžeme spouštět velké programy -* **if...elif...else** - příkazy, které umožňují spouštět kód pouze v případě, kdy jsou splněny určité podmínky. +* **Porovnání věcí** - v Pythonu můžeš porovnávat věci pomocí operátorů `>`, `>=`, `==` `<=`, `<`, `!=` a `and`, `or` +* **Pravdivostní hodnoty / Boolean** - typ, který může mít pouze jednu ze dvou hodnot: `True` nebo `False` +* **Ukládání do souborů** - pokud uložíš kód do souboru, můžeš spouštět větší programy +* **if – elif – else** - příkazy, které umožňují spouštět kód pouze v případě, kdy jsou splněny určité podmínky. -Čas na poslední část této kapitoly! +Čas na předposlední část této kapitoly! ## Vlastní funkce! From 05f3c2681beef6bb23883022bfba682d43de227c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 28 Aug 2018 17:38:11 +0200 Subject: [PATCH 07/30] Work on function definitions --- lessons/fast-track/python-basics/index.md | 169 +++++++++++++--------- 1 file changed, 102 insertions(+), 67 deletions(-) diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md index f1170dd751..47a4d75108 100644 --- a/lessons/fast-track/python-basics/index.md +++ b/lessons/fast-track/python-basics/index.md @@ -1042,7 +1042,8 @@ Lepší program by dělal tohle: * Když je heslo správné: * Pustí uživatele dovnitř -V Pythonu se „když“ řekne `if`. Používá se takhle: +Anglicky se „když“ řekne *if*. A to je i jméno Pythoního příkazu. +Používá se takhle: ```python heslo = input('Zadej heslo: ') @@ -1082,14 +1083,15 @@ Ještě lepší program by ale: * Jinak: * Spustí alarm -Python má také příkazy `elif` a `else`: +K tomu má Python příkaz `else` – „jinak“: ```python heslo = input('Zadej heslo: ') if heslo == 'čokoláda': print('Správně! Račte vstoupit.') else: - print('POZOR! POZOR! NEOPRÁVNĚNÝ VSTUP!') + print('POZOR! POZOR!') + print('NEOPRÁVNĚNÝ VSTUP!') ``` Funuje to? @@ -1155,113 +1157,146 @@ V posledních třech cvičeních ses dozvěděla o: Čas na předposlední část této kapitoly! -## Vlastní funkce! -Pamatuješ na funkci `len()`, kterou jsi spouštěla v Pythonu? Máme pro tebe dobrou zprávu. Nyní se dozvíš, jak napsat své vlastní funkce! +## Vlastní funkce -Funkce je sled instrukcí, které by měl Python provést. Každá funkce v Pythonu začíná klíčovým slovem `def`, dále je uveden název a funkce může mít také nějaké parametry. Začněme u té nejlehčí. Nahraď kód v **python_intro.py** následujícím: +Pamatuješ na funkce `len()` a `print()`? +Jsou jako kouzelná zaříkadla z knihy vázané v kůži: když víš jak se jmenují +a umíš je správně {# XXX: vyslovit #}napsat, něco pro tebe udělají. -```python -def hi(): - print('Hi there!') - print('How are you?') +Teď postoupíme na další úroveň: vymyslíme si vlastní zaříkadla! +Jak? Budeme kombinovat příkazy, které už známe. + +Třeba funkce, která tě pozdraví, by měla: + +* Vypsat „ahoj!“ +* Vypsat „jak se máš?“ -hi() +Definice funkce v Pythonu začíná klíčovým slovem `def`, +dále je uveden název a závorky (zatím prázdné). +Pak jako po `if` dvojtečka, a odsazené příkazy, +které má funkce provést. + +```python +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') ``` Naše první funkce je připravena! -Asi se divíš, proč jsme napsaly název funkce v dolní části souboru. To je proto, že Python přečte soubor a spustí ho od shora dolů. Pokud chceš využívat svou funkci, musíš její název znovu napsat dole (tím ji zavoláš/spustíš). +Když ale tenhle program spustíš, nic neudělá. +To proto, že tohle je jen *definice* funkce. +Python teď ví jak pozdravit – ale neřeklo se, že to má udělat! -Tak to teď zkus a uvidíš, co se stane: +Na konec programu přidej volání. +To už není součást funkce, ale pokračování samotného programu. +Proto nesmí být odsazené: -``` -$ python3 python_intro.py -Hi there! -How are you? +```python +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') + +pozdrav() ``` -To bylo snadné! Napišme naši první funkci s parametry. Použijeme předchozí příklad - napíšeme funkci, která nás pozdraví podle toho, jaké zadáme jméno při jejím spuštění: +Co se stane, když funkci zavoláš několikrát po sobě? ```python -def hi(name): +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') + +pozdrav() +pozdrav() +pozdrav() ``` -Jak vidíš, nyní jsme přidaly naší funkci parametr, `name`: +Co se stane, když volání dáš *nad* definici funkce, místo na konec programu? ```python -def hi(name): - if name == 'Ola': - print('Hi Ola!') - elif name == 'Sonja': - print('Hi Sonja!') - else: - print('Hi anonymous!') +pozdrav() -hi() +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') ``` -Pamatuj si: Funkce `print` je odsazená čtyři mezery v příkazu `if`. To je proto, aby se funkce spustila, pokud je splněna podmínka. Podívej se, jak to funguje nyní: - -``` -$ python3 python_intro.py +{% filter solution %} +``` pycon Traceback (most recent call last): -File "python_intro.py", line 10, in - hi() -TypeError: hi() missing 1 required positional argument: 'name' + File "", line 1, in +NameError: name 'pozdrav' is not defined ``` -Jejda, chyba. Naštěstí nám Python vypsal docela užitečnou chybovou zprávu. Jak vidíš, funkce `hi()` (kterou jsme definovaly) má jeden povinný parametr `(s názvem name)`, který jsme zapomněly při volání funkce předat. Pojďme to opravit v následující části: +Python si stěžuje na `NameError` – nezná nic jménem `pozdrav`. -```python -hi("Ola") -``` +Python totiž program čte odzhora dolů. +Až příkazem `def` se „naučí" jak zdravit – +Předtím, než se k příkazu `def` dostane, funkce neexistuje. +{% endfilter %} -A znovu jej spusť: +# Parametry -``` -$ python3 python_intro.py -Hi Ola! -``` +Funkce jako `len('slovo')` a `print(1 + 2)` umí navíc pracovat s hodnotou. -A co když změníme jméno? +Pojďme napisať funkciu, ktorá ťa pozdraví menom. +(Uľahčíme si to použitím jazyka, ktorý nepoužíva piaty pád.) ```python -hi("Sonja") +def pozdrav(meno): + print('Vitam ťa,', meno) + +pozdrav('Ola') +pozdrav('Soňa') +pozdrav('Hubert') +pozdrav('Anička') ``` -Spustíme: +Jak to funguje? +V definici funkce uvedeš závorkách *parametr* – jméno proměnné se kterou bude +funkce pracovat. +Hodnotu pro tenhle parametr pak zadáš při volání funkce. -``` -$ python3 python_intro.py -Hi Sonja! -``` +Zvládneš napsat program, který se zeptá na jméno a pak tě pozdraví? -C myslíš, že se stane, když tam napíšeš jiné jméno než Ola nebo Sonja? Zkus to a uvidíme, jestli máš pravdu. Mělo by to vypsat toto: +{% filter solution %} +```python +def pozdrav(meno): + print('Vitam ťa,', meno) +pozdrav(input('Jak se jmenuješ? ')) ``` -Hi anonymous! -``` +{% endfilter %} -To je paráda, co? Nemusíš se opakovat a měnit takto jméno pokaždé, když chceš, aby funkce pozdravila jinou osobu. To je přesně důvod, proč potřebujeme funkce: abychom nikdy neopakovaly náš kód! +Co se stane, když funkci zavoláš bez hodnoty pro parametr? -Udělejme to ještě chytřeji – existuje více jmen než dvě a psaní podmínky pro každé jméno by bylo těžké, že? +{% filter solution %} +``` pycon +Traceback (most recent call last): + File "", line 9, in +TypeError: pozdrav() missing 1 required positional argument: 'meno' +``` -```python -def hi(name): - print('Hi ' + name + '!') +Python si stěžuje na `TypeError` – funkce `pozdrav` nedostala povinný +argument `meno`. +{% endfilter %} -hi("Rachel") -``` +Funkce může obsahovat jakýkoli kód. +Třeba podmíněný příkaz, `if`. +Příkazy po `if` je pak potřeba odsatit o *další* čtyři mezery: -Pojďme zavolat náš nový kód: +```python +def pozdrav(meno): + print('Vitam ťa,', meno) + if meno == 'Ola': + print('Ty umíš programovať!') +pozdrav('Hubert') +pozdrav('Ola') +pozdrav('Soňa') ``` -$ python3 python_intro.py -Hi Rachel! -``` - -Blahopřejeme! Právě ses naučila, jak psát funkce :) ## Smyčky/Loops From 5ae599ccf261c7ec39923a7e3cc80c66932388bf Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 28 Aug 2018 18:12:07 +0200 Subject: [PATCH 08/30] Rewrite functions & loops --- lessons/fast-track/python-basics/index.md | 105 ++++++++++++++-------- lessons/fast-track/python-basics/info.yml | 2 +- 2 files changed, 68 insertions(+), 39 deletions(-) diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md index 47a4d75108..d7fa0dcc50 100644 --- a/lessons/fast-track/python-basics/index.md +++ b/lessons/fast-track/python-basics/index.md @@ -1298,71 +1298,91 @@ pozdrav('Ola') pozdrav('Soňa') ``` -## Smyčky/Loops -Nyní pojďme na poslední část. To bylo rychlé, co? :) +## Cykly -Programátoři se neradi opakují. Programování je o automatizaci věci, takže nechceme zdravit každého člověka podle jeho jména manuálně, že? Zde se budou smyčky hodit. +Programátoři se neradi opakují. +Programování je o automatizaci: nebudeme zdravit každého člověka zvlášť, +vezměme seznam padesáti lidí a pozdravíme je všechny najednou! -Ještě si vzpomínáš na seznamy? Udělejme seznam dívek: +(Hm, někteří programátoři nejsou moc sociálně nadaní. +Ale jinde se ta automatizace fakt hodí!) + +Ještě si vzpomínáš na seznamy? +Udělej si seznam jmen: ```python -girls = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'You'] +jmena = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'Ty'] ``` -Chceme pozdravit všechny s použitím jejich jména. Máme funkci `hi`, která to umí udělat. Tak ji použijeme ve smyčce: +Udělejme program, který: -```python -for name in girls: -``` +* Pro každé jméno ze seznamu jmen: + * pozdraví daným jménem -Příkaz ~ ~ ~ for ~ ~ ~ se chová podobně jako příkaz ~ ~ ~ if ~ ~ ~, v následujícím kódu musíme oba řádky odsadit o čtyři mezery. +V Pythonu se takový *cyklus* – opakování „pro každý prvek seznamu“ – píše +pomocí příkazu `for`: + +``` python +for jmeno in jmena: + pozdrav(jmeno) +``` -Zde je celý kód, který umístíme do souboru: +Celý program bude tedy vypadat takto: ```python -def hi(name): - print('Hi ' + name + '!') +def pozdrav(meno): + print('Vitam ťa,', meno) -girls = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'You'] -for name in girls: - hi(name) - print('Next girl') +jmena = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'Ty'] +for jmeno in jmena: + pozdrav(jmeno) ``` A když ho spustíme: -``` +``` console $ python3 python_intro.py -Hi Rachel! -Next girl -Hi Monica! -Next girl -Hi Phoebe! -Next girl -Hi Ola! -Next girl -Hi You! -Next girl +Vitam ťa, Rachel +Vitam ťa, Monica +Vitam ťa, Phoebe +Vitam ťa, Ola +Vitam ťa, Ty ``` -Jak vidíš, vše, co jsi vložila dovnitř příkazu `for` s odsazením, se zopakuje pro každý prvek seznamu `girls`. +Jak vidíš, vše, co jsi vložila dovnitř příkazu `for` s odsazením, +se zopakuje pro každý prvek seznamu `jmena`. + +{# XXX: exercise? #} -Ve funkci `for` můžeš také použít čísla pomocí funkce `range`: +## Opakuj n-krát + +Cyklus `for` můžeš použít i s jinými hodnotami než se seznamy. + +Často se používá s funkcí `range()`. +Když chceš něco 200-krát zopakovat, napiš: ```python -for i in range(1, 6): - print(i) +for i in range(200): + print("Nebudu házet igelit do táboráku!") ``` -Což ti vypíše: +Jak to funguje? +`for i in range(X)` se dá přeložit jako „pro každé číslo +od nuly do X“. +Do proměnné `i` Python uloží, pokolikáté cyklem prochází – počínaje, +v programátorském stylu, od nuly: +```python +for i in range(5): + print(i) +``` ``` +0 1 2 3 4 -5 ``` `range` je funkce, která vytvoří seznam s posloupností čísel (tato čísla zadáváš jako parametry funkce). @@ -1371,10 +1391,19 @@ Všimni si, že druhé z těchto dvou čísel není zahrnuto v seznamu, který j ## Shrnutí -A je to. **Jsi naprosto skvělá!** To byla složitá kapitola, takže bys na sebe měla být hrdá. My jsme na tebe velmi hrdí za to, že ses dostala tak daleko! +A je to. +*Jsi naprosto skvěl{{gnd('ý', 'á')}}!* +Tohle byla složitá kapitola, takže bys na sebe měl{{a}} být hrd{{gnd('ý', 'á')}}. +My jsme na tebe velmi hrdí za to, že ses dostal{{a}} tak daleko! + +Naučil{{a}} ses: + +* **Definice funkcí** – jak pojmenovat pár příkazů +* **Cykly** – jak opakovat nějaký postup několikrát po sobě -Můžeš si jít krátce odpočinout - protáhnout se, projít se, zavřít oči - než se pustíme do další kapitoly. :) +Můžeš si jít krátce odpočinout – protáhnout se, projít se, +zavřít oči – než se pustíme do další kapitoly. :) -![Hrnek][3] +🧁 - [3]: images/cupcake.png + {# XXX: range #} diff --git a/lessons/fast-track/python-basics/info.yml b/lessons/fast-track/python-basics/info.yml index 322c0d5f95..09314e9b91 100644 --- a/lessons/fast-track/python-basics/info.yml +++ b/lessons/fast-track/python-basics/info.yml @@ -1,7 +1,7 @@ title: Úvod do Pythonu style: md attribution: -- Založeno na materiálech [DjangoGirls](https://djangogirls.org/) +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). - Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). - | Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. From 5bae2fa70d6ac457cc8fa179f815d963f1b1de2a Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 28 Aug 2018 19:01:19 +0200 Subject: [PATCH 09/30] Split the fast-track/python-basics into manymany small chapters --- courses/snake/info.yml | 20 +- lessons/fast-track/bool/index.md | 105 ++ lessons/fast-track/bool/info.yml | 12 + lessons/fast-track/conversion/index.md | 53 + lessons/fast-track/conversion/info.yml | 12 + lessons/fast-track/def/index.md | 140 ++ .../{python-basics => def}/info.yml | 2 +- lessons/fast-track/dict/index.md | 145 ++ lessons/fast-track/dict/info.yml | 12 + lessons/fast-track/for/index.md | 108 ++ lessons/fast-track/for/info.yml | 12 + lessons/fast-track/if/index.md | 136 ++ lessons/fast-track/if/info.yml | 12 + lessons/fast-track/list/index.md | 224 +++ lessons/fast-track/list/info.yml | 12 + lessons/fast-track/python-basics/index.md | 1409 ----------------- lessons/fast-track/repl/index.md | 65 + lessons/fast-track/repl/info.yml | 12 + lessons/fast-track/script/index.md | 144 ++ lessons/fast-track/script/info.yml | 12 + lessons/fast-track/str/index.md | 177 +++ lessons/fast-track/str/info.yml | 12 + lessons/fast-track/variables/index.md | 94 ++ lessons/fast-track/variables/info.yml | 12 + 24 files changed, 1525 insertions(+), 1417 deletions(-) create mode 100644 lessons/fast-track/bool/index.md create mode 100644 lessons/fast-track/bool/info.yml create mode 100644 lessons/fast-track/conversion/index.md create mode 100644 lessons/fast-track/conversion/info.yml create mode 100644 lessons/fast-track/def/index.md rename lessons/fast-track/{python-basics => def}/info.yml (96%) create mode 100644 lessons/fast-track/dict/index.md create mode 100644 lessons/fast-track/dict/info.yml create mode 100644 lessons/fast-track/for/index.md create mode 100644 lessons/fast-track/for/info.yml create mode 100644 lessons/fast-track/if/index.md create mode 100644 lessons/fast-track/if/info.yml create mode 100644 lessons/fast-track/list/index.md create mode 100644 lessons/fast-track/list/info.yml delete mode 100644 lessons/fast-track/python-basics/index.md create mode 100644 lessons/fast-track/repl/index.md create mode 100644 lessons/fast-track/repl/info.yml create mode 100644 lessons/fast-track/script/index.md create mode 100644 lessons/fast-track/script/info.yml create mode 100644 lessons/fast-track/str/index.md create mode 100644 lessons/fast-track/str/info.yml create mode 100644 lessons/fast-track/variables/index.md create mode 100644 lessons/fast-track/variables/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml index 1c9663af10..bcfb6f21cb 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -40,17 +40,23 @@ plan: materials: - lesson: beginners/cmdline - lesson: beginners/install -- title: Úvod do Pythonu + - lesson: beginners/install-editor +- title: Workshop slug: intro materials: - title: Úvod url: null - - lesson: beginners/cmdline - title: Příkazová řádka (*) - - title: Instalalce Pygletu - url: null - - title: Základy Pythonu - lesson: fast-track/python-basics + - lesson: fast-track/repl + - lesson: fast-track/str + - lesson: fast-track/conversion + - lesson: fast-track/variables + - lesson: fast-track/list + - lesson: fast-track/dict + - lesson: fast-track/bool + - lesson: fast-track/script + - lesson: fast-track/if + - lesson: fast-track/def + - lesson: fast-track/for - title: "Doplnění: list slicing, del, n-tice, zip()" url: null - lesson: intro/pyglet diff --git a/lessons/fast-track/bool/index.md b/lessons/fast-track/bool/index.md new file mode 100644 index 0000000000..855775aa96 --- /dev/null +++ b/lessons/fast-track/bool/index.md @@ -0,0 +1,105 @@ +# Porovnávání věcí + +Programátoři často porovnávají různé hodnoty. Pojďme se podívat, jak na to. + +``` pycon +>>> 5 > 2 +True +>>> 5 > 8 +False +>>> 5 < 8 +True +``` + +Když se Pythonu zeptáš, jestli je jedno číslo větší než druhé, odpoví ti +`True` (pravda) nebo `False` (nepravda). + +Funguje to i se složitějšími výrazy: + +``` pycon +>>> 5 > 2 * 2 +True +``` + +„Větší než“ a „menší než“ používají značky známé z matematiky. +Chceš-li se ale zeptat, jestli jsou dvě čísla stejná, je to trochu jiné: + +``` pycon +>>> 1 == 1 +True +``` + +Jedno rovnítko `=` používáme pro přiřazení hodnoty do proměnné. +Když chceš zkontrolovat, jestli se věci navzájem rovnají, vždy, **vždy** musíš dát dvě rovnítka `==`. + +Další možnosti porovnávání jsou nerovnost (≠), větší než (≤) a meší než (≥). +Většina lidí tyhle symboly nemá na klávesnici, a tak se používá `!=`, `<=` +a `>=`. + +``` pycon +>>> 5 != 2 +True +>>> 3 <= 2 +False +>>> 6 >= 12 / 2 +True +``` + +## Logika + +Chceš zkusit ještě něco? Zkus tohle: + +``` pycon +>>> 6 > 2 and 2 < 3 +True +>>> 3 > 2 and 2 < 1 +False +>>> 3 > 2 or 2 < 1 +True +``` + +V Pythonu můžeš zkombinovat několik porovnání do jednoho! + +* Pokud použiješ operátor `and`, obě strany musí být pravdivé, aby byl celý výraz pravdivý. +* Pokud použiješ operátor `or`, stačí aby jen jedna strana z porovnání byla pravdivá. + +Už jsi někdy slyšel{{a}} výraz „srovnávat jablka a hrušky“? Zkusme v Pythonu ekvivalent: + +``` pycon +>>> 1 > 'krajta' +Traceback (most recent call last): + File "", line 1, in +TypeError: '>' not supported between instances of 'int' and 'str' +``` + +Stejně jako nelze srovnávat „jablka a hrušky“, +Python není schopen porovnávat řetězce (`str`) a čísla (`int`). +Místo toho zobrazí `TypeError` a říká nám, že tyto dva typy nelze porovnat. + + +## Pravdivostní hodnoty + +Mimochodem, právě ses dozvěděl{{a}} o novém typu objektu v Pythonu. +Říká se mu *pravdivostní hodnota*, nebo častěji anglicky *boolean*. + +Může mít jednu z dvou hodnot: `True` a `False`. + +Aby Python pochopil, že se jedná o tento typ, +je potřeba dávat pozor na velikost písmen. +`true`, `TRUE`, `tRUE` nebude fungovat – jedině `True` je správně. + +Jako každou hodnotu, i pravdivostní hodnotu můžeš uložit do proměnné: + +``` pycon +>>> a = True +>>> a +True +``` + +Stejně tak můžeš uložit i výsledek porovnání: + +``` +>>> a = 2 > 5 +>>> a +False +``` diff --git a/lessons/fast-track/bool/info.yml b/lessons/fast-track/bool/info.yml new file mode 100644 index 0000000000..f6696deb81 --- /dev/null +++ b/lessons/fast-track/bool/info.yml @@ -0,0 +1,12 @@ +title: Porovnávání a logika +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/conversion/index.md b/lessons/fast-track/conversion/index.md new file mode 100644 index 0000000000..f2201965ff --- /dev/null +++ b/lessons/fast-track/conversion/index.md @@ -0,0 +1,53 @@ +# Převádění typů + +Pojď zkusit něco nového: zjistit délku čísla stejným způsobem, +jakým jsme zjišťovali délku našeho jména. +Zadej `len(304023)` a stiskni Enter: + +``` pycon +>>> len(304023) +Traceback (most recent call last): + File "", line 1, in +TypeError: object of type 'int' has no len() +``` + +{# XXX: tohle nebude první chyba... #} +Zobrazila se ti naše první chyba! +Ta říká, že objekty typu `int` (zkratka anglického *integer*, celé číslo) +nemají délku. +Tak co můžeme udělat teď? +Možná můžeme zkusit napsat naše číslo jako řetězec? +Řetězce mají délky, že? + +```pycon +>>> len("304023") +6 +``` + +Existuje i funkce, která *převede* číslo na řetězec. Jmenuje se `str`: + +```pycon +>>> str(304023) +"304023" +>>> len(str(304023)) +6 +``` + +Podobně funkce `int` převádí věci na celá čísla: + +```pycon +>>> int("304023") +``` + +Můžeš převést čísla na text, ale nemůžeš jen tak převést text na čísla. +Co by se stalo, kdyby ses pokusil{{a}} na číslo převést řetězec, ve kterém +nejsou číslice? + +{% filter solution() %} +``` pycon +>>> int('hello') +Traceback (most recent call last): + File "", line 1, in +ValueError: invalid literal for int() with base 10: 'ahoj' +``` +{% endfilter %} diff --git a/lessons/fast-track/conversion/info.yml b/lessons/fast-track/conversion/info.yml new file mode 100644 index 0000000000..32b55093de --- /dev/null +++ b/lessons/fast-track/conversion/info.yml @@ -0,0 +1,12 @@ +title: Převádění typů +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/def/index.md b/lessons/fast-track/def/index.md new file mode 100644 index 0000000000..2616dc51ea --- /dev/null +++ b/lessons/fast-track/def/index.md @@ -0,0 +1,140 @@ +# Vlastní funkce + +Pamatuješ na funkce `len()` a `print()`? +Jsou jako kouzelná zaříkadla z knihy vázané v kůži: když víš jak se jmenují +a umíš je správně {# XXX: vyslovit #}napsat, něco pro tebe udělají. + +Teď postoupíme na další úroveň: vymyslíme si vlastní zaříkadla! +Jak? Budeme kombinovat příkazy, které už známe. + +Třeba funkce, která tě pozdraví, by měla: + +* Vypsat „ahoj!“ +* Vypsat „jak se máš?“ + +Definice funkce v Pythonu začíná klíčovým slovem `def`, +dále je uveden název a závorky (zatím prázdné). +Pak jako po `if` dvojtečka, a odsazené příkazy, +které má funkce provést. + +```python +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') +``` + +Naše první funkce je připravena! + +Když ale tenhle program spustíš, nic neudělá. +To proto, že tohle je jen *definice* funkce. +Python teď ví jak pozdravit – ale neřeklo se, že to má udělat! + +Na konec programu přidej volání. +To už není součást funkce, ale pokračování samotného programu. +Proto nesmí být odsazené: + +```python +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') + +pozdrav() +``` + +Co se stane, když funkci zavoláš několikrát po sobě? + +```python +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') + +pozdrav() +pozdrav() +pozdrav() +``` + +Co se stane, když volání dáš *nad* definici funkce, místo na konec programu? + +```python +pozdrav() + +def pozdrav(): + print('Ahoj!') + print('Jak se máš?') +``` + +{% filter solution %} +``` pycon +Traceback (most recent call last): + File "", line 1, in +NameError: name 'pozdrav' is not defined +``` + +Python si stěžuje na `NameError` – nezná nic jménem `pozdrav`. + +Python totiž program čte odzhora dolů. +Až příkazem `def` se „naučí" jak zdravit – +Předtím, než se k příkazu `def` dostane, funkce neexistuje. +{% endfilter %} + +## Parametry + +Funkce jako `len('slovo')` a `print(1 + 2)` umí navíc pracovat s hodnotou. + +Pojďme napisať funkciu, ktorá ťa pozdraví menom. +(Uľahčíme si to použitím jazyka, ktorý nepoužíva piaty pád.) + +```python +def pozdrav(meno): + print('Vitam ťa,', meno) + +pozdrav('Ola') +pozdrav('Soňa') +pozdrav('Hubert') +pozdrav('Anička') +``` + +Jak to funguje? +V definici funkce uvedeš závorkách *parametr* – jméno proměnné se kterou bude +funkce pracovat. +Hodnotu pro tenhle parametr pak zadáš při volání funkce. + +Zvládneš napsat program, který se zeptá na jméno a pak tě pozdraví? + +{% filter solution %} +```python +def pozdrav(meno): + print('Vitam ťa,', meno) + +pozdrav(input('Jak se jmenuješ? ')) +``` +{% endfilter %} + +Co se stane, když funkci zavoláš bez hodnoty pro parametr? + +{% filter solution %} +``` pycon +Traceback (most recent call last): + File "", line 9, in +TypeError: pozdrav() missing 1 required positional argument: 'meno' +``` + +Python si stěžuje na `TypeError` – funkce `pozdrav` nedostala povinný +argument `meno`. +{% endfilter %} + +Funkce může obsahovat jakýkoli kód. +Třeba podmíněný příkaz, `if`. +Příkazy po `if` je pak potřeba odsatit o *další* čtyři mezery: + +```python +def pozdrav(meno): + print('Vitam ťa,', meno) + if meno == 'Ola': + print('Ty umíš programovať!') + +pozdrav('Hubert') +pozdrav('Ola') +pozdrav('Soňa') +``` + diff --git a/lessons/fast-track/python-basics/info.yml b/lessons/fast-track/def/info.yml similarity index 96% rename from lessons/fast-track/python-basics/info.yml rename to lessons/fast-track/def/info.yml index 09314e9b91..c8a5b5efa0 100644 --- a/lessons/fast-track/python-basics/info.yml +++ b/lessons/fast-track/def/info.yml @@ -1,4 +1,4 @@ -title: Úvod do Pythonu +title: Vlastní funkce style: md attribution: - Založeno na materiálech [DjangoGirls](https://djangogirls.org/). diff --git a/lessons/fast-track/dict/index.md b/lessons/fast-track/dict/index.md new file mode 100644 index 0000000000..de756eadee --- /dev/null +++ b/lessons/fast-track/dict/index.md @@ -0,0 +1,145 @@ +# Slovníky + +Jiný typ hodnot, které v sobě mohou obsahovat další hodnoty, je *slovník*. +Pro příklad si představ překladový slovník, třeba česko-anglický: + +* **Jablko**: Apple +* **Knoflík**: Button +* **Myš**: Mouse + +Slovník v Pythonu obsahuje záznamy, a každý záznam přiřazuje +nějakému *klíči* nějakou *hodnotu*. +V našem příkladu je klíči *Jablko* přiřazena hodnota *Apple*, +klíči *Knoflík* náleží hodnota *Button* +a klič *Myš* ukazuje na *Mouse*. + +V Pythonu by se takový slovník napsal následovně: + +``` pycon +>>> slovnik = {'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'} +``` + +Naše klíče a hodnoty jsou slova – krátké texty, tedy řetězce, +které je potřeba dát do uvozovek. +Klíč a hodnota jsou oddělené dvojtečkou, +jednotlivé dvojice se od sebe oddělují čárkou, +a celý slovník je uzavřený ve složených závorkách. + +Když budeš chtít v takovém slovníku něco najít, potřebuješ vědět, co hledat. +Konkrétně *klíč*. +Pomocí hranatých závorek můžeš zjistit hodnotu, která odpovídá danému klíči: + + +``` pycon +>>> slovnik['Jablko'] +'Apple' +``` + +Je to podobné jako u seznamů, jen v hranatých závorkách není pořadí prvku, +ale klíč. +{# XXX: Slicing taky nejde #} + +> [note] +> Naopak to nejde – slovník neumožňuje podle hodnoty přímo zjistit klíč. +> Na překlad z angličtiny do češtiny bys potřeboval{{a}} druhý slovník. + +## Měnění slovníků + +Co se stane, když klíč ve slovníku není? + +``` pycon +>>> slovnik['Pes'] +Traceback (most recent call last): + File "", line 1, in +KeyError: 'Pes' +``` + +Python si postěžuje na `KeyError` – chybu klíče. + +Podobně jako seznamy se ale slovníky dají měnit. +Nový záznam vytvoříš takhle: + +``` pycon +>>> slovnik['Pes'] = 'Dog' +>>> slovnik +{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Dog'} +``` + +> [note] +> Na rozdíl od překladového slovníku nemusí být Pythonní slovník seřazený +> podle abecedy. +> Není to potřeba, počítač umí rychle vyhledávat i bez seřazení. + +Kdybys potřebovala{{a}} změnit už existující záznam, použij stejný příkaz. +K jednomu klíči může patřit jen jedna hodnota. + +``` pycon +>>> slovnik['Pes'] = 'Extension cord' +>>> slovnik +{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Extension cord'} +``` + +{# XXX: Zmínit se o nehomogenních slovnících? #} + +Chceš-li ze zlovníku nějaký záznam smazat, dělá se to podobně jako +u seznamů příkazem `del`: + +``` pycon +>>> del slovnik['Pes'] +>>> slovnik +{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'} +``` + +A když budeš chtít zjistit, kolik je ve slovníku záznamů, +zeptáš se podobně jako na počet znaků řetězce nebo prvků seznamu. +Použiješ funkci `len()`. + +``` pycon +>>> len(slovnik) +3 +``` + +{# XXX + +* Kontakty +* Když číslo není číslo +* Více čísel + +## K zamyšlení + +Ke každému klíči může patřit jen jedna hodnota. +Jak bys zařídil{{a}}, aby hodnot víc? + +Zkus do Pythonní proměnné uložit tyto kontakty: + +* Katka: + * 4925219 +* Jirka: + * 7477058 + * 3251156 +* Verča: + * 1019103 + +{% filter solution %} +Více hodnot se dá uložit do seznamu. +Hodnoty budou seznamy čísel: + +```pycon +>>> kontakty = {'Katka': ['4925219'], 'Jirka': ['7477058', '3251156'], 'Verča': ['1019103']} +``` +{% endfilter %} + +Verča se přestěhovala do zahraničí a má nové číslo: `+897 3788509`. + +#} + +## Shrnutí + +Skvělé! Nyní víš o programování hodně. V této poslední části jsi poznal{{a}}: + +* **chyby** - hlášky které Python zobrazí když nerozumí příkazu který jsi zadal{{a}} nebo ho neumí splnit +* **proměnné** - názvy pro objekty, které umožňují psát čitelnější kód +* **seznam** - sekvence objektů uložených v určitém pořadí +* **slovník** - sbírka záznamů klíč–hodnota + +Jsi připraven{{a}} na další část? diff --git a/lessons/fast-track/dict/info.yml b/lessons/fast-track/dict/info.yml new file mode 100644 index 0000000000..c58c5373cd --- /dev/null +++ b/lessons/fast-track/dict/info.yml @@ -0,0 +1,12 @@ +title: Slovníky +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/for/index.md b/lessons/fast-track/for/index.md new file mode 100644 index 0000000000..50d5c947d4 --- /dev/null +++ b/lessons/fast-track/for/index.md @@ -0,0 +1,108 @@ +# Cykly + +Programátoři se neradi opakují. +Programování je o automatizaci: nebudeme zdravit každého člověka zvlášť, +vezměme seznam padesáti lidí a pozdravíme je všechny najednou! + +(Hm, někteří programátoři nejsou moc sociálně nadaní. +Ale jinde se ta automatizace fakt hodí!) + +Ještě si vzpomínáš na seznamy? +Udělej si seznam jmen: + +```python +jmena = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'Ty'] +``` + +Udělejme program, který: + +* Pro každé jméno ze seznamu jmen: + * pozdraví daným jménem + +V Pythonu se takový *cyklus* – opakování „pro každý prvek seznamu“ – píše +pomocí příkazu `for`: + +``` python +for jmeno in jmena: + pozdrav(jmeno) +``` + +Celý program bude tedy vypadat takto: + +```python +def pozdrav(meno): + print('Vitam ťa,', meno) + +jmena = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'Ty'] +for jmeno in jmena: + pozdrav(jmeno) +``` + +A když ho spustíme: + +``` console +$ python3 python_intro.py +Vitam ťa, Rachel +Vitam ťa, Monica +Vitam ťa, Phoebe +Vitam ťa, Ola +Vitam ťa, Ty +``` + +Jak vidíš, vše, co jsi vložila dovnitř příkazu `for` s odsazením, +se zopakuje pro každý prvek seznamu `jmena`. + +{# XXX: exercise? #} + +## Opakuj n-krát + +Cyklus `for` můžeš použít i s jinými hodnotami než se seznamy. + +Často se používá s funkcí `range()`. +Když chceš něco 200-krát zopakovat, napiš: + +```python +for i in range(200): + print("Nebudu házet igelit do táboráku!") +``` + +Jak to funguje? +`for i in range(X)` se dá přeložit jako „pro každé číslo +od nuly do X“. +Do proměnné `i` Python uloží, pokolikáté cyklem prochází – počínaje, +v programátorském stylu, od nuly: + +```python +for i in range(5): + print(i) +``` +``` +0 +1 +2 +3 +4 +``` + +`range` je funkce, která vytvoří seznam s posloupností čísel (tato čísla zadáváš jako parametry funkce). + +Všimni si, že druhé z těchto dvou čísel není zahrnuto v seznamu, který je výstupem Pythonu (`range (1, 6)` počítá od 1 do 5, ale nezahrnuje číslo 6). To je proto, že "range" je z poloviny otevřený, čímž myslíme, že obsahuje první hodnotu, ale ne poslední. + +## Shrnutí + +A je to. +*Jsi naprosto skvěl{{gnd('ý', 'á')}}!* +Tohle byla složitá kapitola, takže bys na sebe měl{{a}} být hrd{{gnd('ý', 'á')}}. +My jsme na tebe velmi hrdí za to, že ses dostal{{a}} tak daleko! + +Naučil{{a}} ses: + +* **Definice funkcí** – jak pojmenovat pár příkazů +* **Cykly** – jak opakovat nějaký postup několikrát po sobě + +Můžeš si jít krátce odpočinout – protáhnout se, projít se, +zavřít oči – než se pustíme do další kapitoly. :) + +🧁 + + {# XXX: range #} diff --git a/lessons/fast-track/for/info.yml b/lessons/fast-track/for/info.yml new file mode 100644 index 0000000000..ca95e6f8f7 --- /dev/null +++ b/lessons/fast-track/for/info.yml @@ -0,0 +1,12 @@ +title: Cykly +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/if/index.md b/lessons/fast-track/if/index.md new file mode 100644 index 0000000000..bcb6498d8e --- /dev/null +++ b/lessons/fast-track/if/index.md @@ -0,0 +1,136 @@ +# Podmínky + +Spoustu věcí v kódu chceme provádět, jen pokud jsou splněny určité podmínky. +Proto má Python *podmíněné příkazy*. + +Zkusíme napsat program, který ověřuje tajné heslo. +Tenhle program napíše `True`, když zadáš slovo `čokoláda`: + +```python +heslo = input('Zadej heslo: ') +print(heslo == 'čokoláda') +``` + +## Když – tak + +Vypsání `True` ale není moc zajímavé. +Lepší program by dělal tohle: + +* Zeptá se na tajné heslo +* Když je heslo správné: + * Pustí uživatele dovnitř + +Anglicky se „když“ řekne *if*. A to je i jméno Pythoního příkazu. +Používá se takhle: + +```python +heslo = input('Zadej heslo: ') +if heslo == 'čokoláda': + print('Správně! Račte vstoupit.') +``` + +Podmíněný příkaz začíná `if`, pokračuje podmínkou (třeba porovnáním) +a končí dvojtečkou. + +Po řádkem s `if` je příkaz *odsazený* – na začátku řádku jsou 4 mezery. + +Podle toho Python pozná, že tuhle část programu má provést, +jen když je podmínka pravdivá. + +Ulož a spusť: + +``` console +(venv) $ python python_intro.py +Zadej heslo: čokoláda +Správně! Můžeš vstoupit. +``` + +``` console +(venv) $ python python_intro.py +Zadej heslo: sezam +``` + +## Jinak + +V předchozím příkladu byl kód proveden pouze v případě, že podmínka byla splněna. +Ještě lepší program by ale: + +* Zeptá se na tajné heslo +* Když je heslo správné: + * Pustí uživatele dovnitř +* Jinak: + * Spustí alarm + +K tomu má Python příkaz `else` – „jinak“: + +```python +heslo = input('Zadej heslo: ') +if heslo == 'čokoláda': + print('Správně! Račte vstoupit.') +else: + print('POZOR! POZOR!') + print('NEOPRÁVNĚNÝ VSTUP!') +``` + +Funuje to? + +## Více možností + +Občas se stane, že se program musí rozhodnout mezi více možnostmi. +K tomu slouží příkaz `elif`, zkratka znglického *else if* – „jinak, pokud“. + +Napišme program, který okomentuje hlasitost hudby: + +* Zeptá se na hlasitost, a odpověď uloží jako číslo. +* Když je hlasitost do 20: + * vypíše „Je to dost potichu.“ +* Jinak, když je hlasitost do 40: + * vypíše „Jako hudba v pozadí dobré.“ +* Jinak, když je hlasitost do 60: + * vypíše „Skvělé, slyším všechny detaily.“ +* Jinak, když je hlasitost do 80: + * vypíše „Dobré na párty.“ +* Jinak, když je hlasitost do 100: + * vypíše „Trochu moc nahlas!“ +* Jinak: + * vypíše „Krvácí mi uši!“ + +V Pythonu: + +```python +hlasitost = int(input('Jaká je nastavená hlasitost rádia? ')) +if hlasitost < 20: + print("Je to dost potichu.") +elif hlasitost < 40: + print("Jako hudba v pozadí dobré.") +elif hlasitost < 60: + print("Skvělé, slyším všechny detaily.") +elif hlasitost < 80: + print("Dobré na party.") +elif hlasitost < 100: + print("Trochu moc nahlas!") +else: + print("Krvácí mi uši!") +``` + +``` console +(venv) $ python python_intro.py +Jaká je nastavená hlasitost rádia? 28 +Jako hudba v pozadí dobré. +``` + +Všimni si, že se vybere vždycky jedna alternativa. +Když zadáš `28`, Python se dostane k `hlasitost < 40`, vypíše +příslušnou hlášku a další možnosti přeskočí. + + +## Shrnutí + +V posledních třech cvičeních ses dozvěděl{{a}} o: + +* **Porovnání věcí** - v Pythonu můžeš porovnávat věci pomocí operátorů `>`, `>=`, `==` `<=`, `<`, `!=` a `and`, `or` +* **Pravdivostní hodnoty / Boolean** - typ, který může mít pouze jednu ze dvou hodnot: `True` nebo `False` +* **Ukládání do souborů** - pokud uložíš kód do souboru, můžeš spouštět větší programy +* **if – elif – else** - příkazy, které umožňují spouštět kód pouze v případě, kdy jsou splněny určité podmínky. + +Čas na předposlední část této kapitoly! diff --git a/lessons/fast-track/if/info.yml b/lessons/fast-track/if/info.yml new file mode 100644 index 0000000000..3aac54ef9f --- /dev/null +++ b/lessons/fast-track/if/info.yml @@ -0,0 +1,12 @@ +title: Podmínky +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/list/index.md b/lessons/fast-track/list/index.md new file mode 100644 index 0000000000..4c3e04c497 --- /dev/null +++ b/lessons/fast-track/list/index.md @@ -0,0 +1,224 @@ +# Seznamy + +Vedle řetězců a celých čísel má Python další druhy hodnot. + +Teď se podíváme na jeden, který se nazývá *seznam* (anglicky *list*). +To je hodnota, která v sobě obsahuje jiné hodnoty. + +{# Anglické termíny všude! #} + +Seznamy se zadávají tak, že dáš několik hodnot, oddělených čárkami, +do hranatých závorek. +Zkus si vytvořit třeba seznam čísel z loterie: + +``` pycon +>>> [3, 42, 12, 19, 30, 59] +[3, 42, 12, 19, 30, 59] +``` + +Abys s takovým seznamem mohl{{a}} pracovat, +ulož si ho do proměnné: + +``` pycon +>>> loterie = [3, 42, 12, 19, 30, 59] +``` + +Dobrá, máme seznam! Co s ním můžeme dělat? +Podíváme se, kolik čísel v seznamu je. +Dá se na to použít funkce, kterou už znáš. +Tipneš si, která to je? + +{% filter solution %} +``` pycon +>>> len(loterie) +6 +``` + +Funkce `len()` umí zjistit nejen délku řetězce, ale i délku seznamu – tedy +počet jeho prvků. +{% endfilter %} + +Teď si zkus seznam seřadit. Na to existuje metoda `sort`: + +``` pycon +>>> loterie.sort() +``` + +Tato funkce nic nevrátí, jen změní pořadí čísel v seznamu. +Znovu si ho vypiš, ať vidíš co se stalo: + +``` pycon +>>> loterie +[3, 12, 19, 30, 42, 59] +``` + +Čísla v seznamu jsou nyní seřazena od nejnižší k nejvyšší hodnotě. + +Podobně funguje metoda `reverse`, která obrátí pořadí prvků. +Vyzkoušej si ji! + +``` pycon +>>> loterie.reverse() +>>> loterie +[59, 42, 30, 19, 12, 3] +``` + +Pokud chceš do svého něco přidat seznamu, můžeš to provést pomocí metody +`append`. +Ale pozor! Tahle metoda potřebuje vědět co má do seznamu přidat +Nová hodnota se zadává do závorek: + +``` pycon +>>> loterie.append(199) +``` + +Metoda opět nic nevrací, takže je potřeba seznam pro kontrolu vypsat: + +``` pycon +>>> loterie +[59, 42, 30, 19, 12, 3, 199] +``` + +## Vybírání prvků + +Když se budeš chtít na jednu věc ze seznamu podívat podrobněji, +přijde vhod možnost vybrat si konkrétní prvek. +Na to se v Pythonu používají hranaté závorky. + +{# XXX: MCQ #} + +Chceš-li vybrat prvek, zadej jméno seznamu a hned za ním hranaté závorky +s pořadovým číslem prvku, který chceš: + +``` pycon +>>> loterie[1] +``` + +Dostaneš první prvek? + +{% filter solution %} +``` pycon +>>> loterie +[59, 42, 30, 19, 12, 3, 199] +>>> loterie[1] +42 +``` + +Ne, dostaneš druhý prvek. + +Programátoři počítají od nuly. +Chceš li tedy první prvek, popros Python o prvek číslo nula: + +``` pycon +>>> loterie[0] +42 +``` + +Je to zpočátku divné, ale dá se na to zvyknout. +{% endfilter %} + +Číslu prvku se také říká *index* a procesu vybírání prvků *indexování*. + +Zkus si indexování s dalšími indexy: 3, 100, 7, -1, -2, -6 nebo -100. +Pokus se předpovědět výsledek před zadáním příkazu. +Jak ti to půjde? + +{% filter solution %} +``` pycon +>>> loterie +[59, 42, 30, 19, 12, 3, 199] + +>>> loterie[3] +19 +``` +Index 3 označuje čtvrtý prvek. + +``` pycon +>>> loterie[7] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range + +``` +Prvek s indexem 100 v seznamu není – nastane chyba. + +``` pycon +>>> loterie[1000] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range +``` +Prvek s indexem 7 v seznamu taky není. + +``` pycon +>>> loterie[-1] +199 +``` +Index -1 označuje *poslední* prvek. + +``` pycon +>>> loterie[-2] +3 +``` +Index -2 označuje předposlední prvek. + +``` pycon +>>> loterie[-6] +42 +``` +Index -6 označuje šestý prvek od konce. + +``` pycon +>>> loterie[-100] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range +``` +Stý prvek od konce v seznamu není. Nastane chyba. +{% endfilter %} + +## Řezání + +XXX Slicing + +## Odstraňování + +Chceš-li ze seznamu něco odstranit, můžeš opět použít indexy. +Tentokrát s příkazem `del`. +Následující kód odstraní počáteční číslo seznamu, tedy prvek číslo 0: + +``` pycon +>>> del loterie[0] +``` + +Pak si seznam opět vypiš. Kousek chybí! + +``` pycon +>>> loterie +[42, 30, 19, 12, 3, 199] +``` + +Zkusíš odstranit poslední prvek? + +{% filter solution %} +``` pycon +>>> del loterie[-1] +>>> loterie +[42, 30, 19, 12, 3] +``` +{% endfilter %} + +A co prostřední tři? +Zkus si nejdřív vypsat, které to jsou, a pak teprve použít `del`. + +{% filter solution %} +``` pycon +>>> loterie +[42, 30, 19, 12, 3] +>>> loterie[1:-1] +[30, 19, 12] +>>> del loterie[1:-1] +>>> loterie +[42, 3] +``` +{% endfilter %} diff --git a/lessons/fast-track/list/info.yml b/lessons/fast-track/list/info.yml new file mode 100644 index 0000000000..b540485bdd --- /dev/null +++ b/lessons/fast-track/list/info.yml @@ -0,0 +1,12 @@ +title: Seznamy +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/python-basics/index.md b/lessons/fast-track/python-basics/index.md deleted file mode 100644 index d7fa0dcc50..0000000000 --- a/lessons/fast-track/python-basics/index.md +++ /dev/null @@ -1,1409 +0,0 @@ -# Úvod do Pythonu - -> Tento text je založen na materiálech [Django Girls](https://tutorial.djangogirls.org/cs/python_introduction/) a [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). - -Pojď napsat nějaký kód! - -## Interaktivní režim Pythonu - -Chceš-li si začít hrát s Pythonem, otevři *příkazový řádek* a aktivuj virtuální prostředí. Zkontroluj si, že na začátku příkazové řádky ti svítí `(venv)`. - -Je-li tomu tak, nezbývá než – konečně – pustit Python. K tomu použij příkaz `python`: - -``` console -$ python3 -Python 3.6.6 (...) -Type "help", "copyright", "credits" or "license" for more information. ->>> -``` - -Příkaz vypíše několik informací. Z prvního řádku se můžeš ujistit, že používáš Python 3. (Vidíš-li číslo jako `2.7.11`, něco je špatně – popros o radu kouče.) - -Třemi „zobáčky“ ``>>>` pak Python poprosí o instrukce. Je to jako v příkazové řádce, ale místo příkazů jako `cd` a `mkdir` sem budeš psát příkazy Pythonu. - -Jako první instrukci použijeme Pythonu jako kalkulačku. -Za tři zobáčky napiš třeba `2 + 3` a zmáčkni Enter. - -``` pycon ->>> 2 + 3 -5 -``` - -Zobrazila se ti správná odpověď? -Pokud ano, gratuluji! První příkaz v Pythonu máš za sebou. - -Zkusíš i odečítání? - -A jak je to s násobením? -{# XXX: Jak zapsat násobení? `4 x 5` `4 . 5` `4 × 5` `4 * 5` -#} -Na kalkulačce bys zadala `4 × 5`, což se na klávesnici píše špatně. -Python proto používá symbol `*` a pro dělení `/`. -Tyhle symboly se odborně nazývají *operátory*. - -``` pycon ->>> 4 * 5 -20 ->>> 5 / 2 -2.5 -``` - -> [note] -> V tomto úvodu budeme zadávat jen celá čísla. -> Dělením ale může vzniknout třeba dva a půl -> (tedy `2.5` – Python používá desetinnou *tečku*). -> Z důvodů, do kterých teď nebudeme zabíhat, se desetinné pozice po dělení -> objeví i když vyjde celé číslo: -> ``` pycon -> >>> 4 / 2 -> 2.0 -> ``` - -{# XXX: -Kolik je -123 + 456789? -#} - -> [style-note] -> Mezery mezi čísly a znamínkem nejsou nutné: `4*5` i `4 * 5` dělá -> to samé co `4 * 5`. -> Je ale zvykem psát kolem operátoru jednu mezeru z každé strany – tak jako -> v těchto materiálech. -> Kód je pak čitelnější. - - -## Řetězce - -Čísla jsou pro počítače dost užitečná (ostatně slovo *počítač* to naznačuje), -ale Python umí pracovat i s jinými druhy informací. -Třeba s textem. - -Zkus si to: zadej své jméno do uvozovek, jak vidíš níže: - -``` pycon ->>> 'Ola' -'Ola' -``` - -Nyní jsi vytvořil{{a}} svůj první *řetězec*! -Řetězec je programátorský termín pro *text* – posloupnost znaků (písmenek), které mohou být zpracovány počítačem. - -Když řetězec zadáváš, musíš ho vždy uzavřít do uvozovek (apostrofů). -Jinak by Python nepoznal, co je text a co jsou instrukce. - -{# XXX: Assessment here: adding strings together #} - -Řetězce se dají spojovat – „sečítat“ – pomocí `+`. Zkus toto: - -``` pycon ->>> 'Já jsem ' + 'Ola' -'Já jsem Ola' -``` - -> [note] -> Pozor na mezeru! Když zadáš `'Já jsem'+'Ola'`, spojí se ti dvě slova -> dohromady. -> Počítač považuje i mezeru za *znak*; chová se k ní stejně jako k jakémukoli -> písmenku. -> Když nedáš mezeru do uvozovek, nebude součástí řetězce. -> -> Zkus si: -> -> ``` pycon -> >>> 'Já jsem' + ' ' + 'Ola' -> 'Já jsem Ola' -> ``` - -Také můžeš řetězce opakovat – násobit číslem: - -``` pycon ->>> 'Ola' * 3 -'OlaOlaOla' -``` - -### Uvozování - -A co když budeš chtít dát dovnitř do svého řetězce apostrof? -Můžeš kolem řetězce použít dvojité uvozovky: - -``` pycon ->>> "To bych řek', že jsou pořádně praštěný!" -"To bych řek', že jsou pořádně praštěný!" -``` - -Pythonu je jedno, se kterým druhem uvozovek řetězec zadáš. -Podstatná jsou jen písmenka uvnitř. -Když Python řetězec vypisuje, může si vybrat jiný druh uvozovek -než jsi použil{{a}} ty: - -``` pycon ->>> "Ola" -'Ola' -``` - -### Funkce a metody - -Už umíš řetězce „sčítat“ pomocí `+` (`'Ahoj ' + 'Olo!'`) -a „násobit“ pomocí `*` (`'la' * 3`). -Na všechny ostatní věci, které se s textem dají dělat, -ale na klávesnici není dost symbolů. -Proto jsou některé operace pojmenované slovně – třeba takzvané *funkce*. - -Chceš-li znát počet písmen ve svém jméně, zavolej funkci `len`. -Napiš `len` (bez uvozovek), pak kulaté závorky, a do těch závorek -své jméno (jako řetězec – v uvozovkách): - -``` pycon ->>> len('Ola') -3 -``` - -{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} - -Kromě funkcí existují *metody*, které se zapisují trochu jinak. - -Chceš-li vidět své jméno velkými písmeny, zavolej metody `upper`. -Napiš řetězec, pak tečku, jméno metody `upper` (bez uvozovek) a prázdné -závorky: - -``` pycon ->>> 'Ola'.upper() -'OLA' -``` - -Zkus si zavolat metodu `lower`. - -{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} - -Co je metoda (které voláš s `.`, jako `'Ola'.upper()`) a co je funkce -(kde vložíš informaci do závorek jako (`len('Ola')`) - -### Shrnutí - -OK, dost bylo řetězců. Co ses zatím naučil{{a}}: - -* **Interaktivní režim Pythonu** umožňuje zadávat příkazy (kód) pro - Python a zobrazuje výsledky/odpovědi. -* **Čísla a řetězce** se používají na matematiku a práci s textem. -* **Operátor** jako `+` a `*` kombinuje hodnoty a vytvoří výsledek. -* **Funkce** a **metody** jako `len()` a `upper()` provádí na hodnotách - nějaké akce. - -Čísla, řetězce a operátory a funkce jsou základy většiny programovacích jazyků. - -Připraven{{a}} na něco dalšího? Vsadíme se, že ano! - - -## Skládání - -Volání funkce nebo metody můžeš použít jako jinou hodnotu. - -Nech Python spočítat matematický výraz `(1 + 3) / 2`: - -```pycon ->>> (1 + 3) / 2 -2.0 -``` - -Python napřed sečte `1 + 3` a vyjde mu 4. -Čtverku doplní místo `1 + 3` do původního příkladu, a dostane `4 / 2`. -To vydělí a dostane `2`. - -Neboli: `(1 + 3) / 2` = `4 / 2` = `2` - -Zkus se zamyslet, jak Python zpracuje tyto výrazy: - -```pycon ->>> len('Ola') + 1 -4 -``` - -```pycon ->>> 'Já jsem ' + 'Ola'.upper() -'Já jsem OLA' -``` - -```pycon ->>> len('Ola'.upper()) -4 -``` - -```pycon ->>> len('Ola' * 3) -9 -``` - -{% filter solution() %} -`'Já jsem ' + 'Ola'.upper()` → `'Já jsem ' + 'OLA'` → `'Já jsem OLA'` - -`len('Ola') + 1` → `3 + 1` → `4` - -`len('Ola'.upper())` → `len('OLA')` → `3` - -`len('Ola' * 3)` → `len('OlaOlaOla')` → `9` -{% endfilter %} - - -Podobné skládání je v programování velice časté. -Většinu základních stavebních bloků se začátečník naučí za pár -týdnů – a pak je po celou svou progrmátorskou kariéru skládá do -složitějších a složitějších konstrukcí. - - -## Chyby - -Pojď zkusit něco nového: zjistit délku čísla stejným způsobem, -jakým jsme zjišťovali délku našeho jména. -Zadej `len(304023)` a stiskni Enter: - -``` pycon ->>> len(304023) -Traceback (most recent call last): - File "", line 1, in -TypeError: object of type 'int' has no len() -``` - -{# XXX: tohle nebude první chyba... #} -Zobrazila se ti naše první chyba! -Ta říká, že objekty typu `int` (zkratka anglického *integer*, celé číslo) -nemají délku. -Tak co můžeme udělat teď? -Možná můžeme zkusit napsat naše číslo jako řetězec? -Řetězce mají délky, že? - -```pycon ->>> len("304023") -6 -``` - -Existuje i funkce, která *převede* číslo na řetězec. Jmenuje se `str`: - -```pycon ->>> str(304023) -"304023" ->>> len(str(304023)) -6 -``` - -Podobně funkce `int` převádí věci na celá čísla: - -```pycon ->>> int("304023") -``` - -Můžeš převést čísla na text, ale nemůžeš jen tak převést text na čísla. -Co by se stalo, kdyby ses pokusil{{a}} na číslo převést řetězec, ve kterém -nejsou číslice? - -{% filter solution() %} -``` pycon ->>> int('hello') -Traceback (most recent call last): - File "", line 1, in -ValueError: invalid literal for int() with base 10: 'ahoj' -``` -{% endfilter %} - -## Proměnné - -Důležitým konceptem v programování jsou *proměnné*. -Proměnná není nic jiného než *pojmenování* něčeho, -co budeme chtít použít později. -Programátoři proměnné používají k ukládání dat, -aby byl jejich kód čitelnější a nemuseli si pamatovat konkrétní hodnoty. - -Řekněme, že chceš vytvořit novou proměnnou s názvem `jmeno`. -To se zapíše takto: - -``` pycon ->>> jmeno = 'Ola' -``` - -Proměnná `jmeno` teď bude mít hodnotu `'Ola'`. - -Jak sis mohl{{a}} všimnout, tenhle příkaz nic nevrátil – Python nevypsal -žádný výslede. -Jak tedy víme, že proměnná skutečně existuje? - -Zadej samotné jméno proměnné (tedy `jmeno`) a stiskni Enter: - -``` pycon ->>> jmeno -'Ola' -``` - -Zkus si nastavit i jinou proměnnou – třeba svoji oblíbenou barvu: - -``` pycon ->>> barva = 'modrá' ->>> barva -'modrá' -``` - -Kdykoli můžeš do proměnné přiřadit znovu, a změnit tak co se pod -daným jménem skrývá: - -``` pycon ->>> jmeno -'Ola' ->>> jmeno = "Soňa" ->>> jmeno -'Soňa' -``` - -Můžeš ji také použít ve funkcích: - -``` pycon ->>> len(jmeno) -4 -``` - -Super, ne? -Proměnná může obsahovat cokoliv, například také čísla! -Zkus tohle: - -``` pycon ->>> sirka = 4 ->>> delka = 6 ->>> sirka * delka -24 -``` - -Ale co když použiješ nesprávné jméno? Dokážeš odhadnout, co se stane? - -{% filter solution %} -``` pycon ->>> mesto = "Tokyo" ->>> mmesto -Traceback (most recent call last): - File "", line 1, in -NameError: name 'mmesto' is not defined -``` -{% endfilter %} - -Chyba! - -Python má různé typy chyb. Tato se nazývá `NameError`. -Python ti vrátí tuto chybu, pokud se pokusíš použít proměnnou, -která dosud nebyla nastavena. -Pokud někdy dojde k této chybě, zkontroluj svůj kód, abys zjistil{{a}}, -jestli jsi někde neudělal{{a}} překlep. - -> [note] Jména proměnných -> Profesionální programátoři pojmenovávají proměnné anglicky, -> aby jim rozuměli co nejvíc kolegů po celém světě. -> Ze začátku ale doporučujeme češtinu – je tak jasnější, která jména -> si můžeš zvolit {{gnd('sám', 'sama')}} (např. `barva`) a která jsou -> z Pythonu (např. `upper`). -> -> Je ovšem dobré se nepoužívat diakritiku a vyhnout se velkým pímenům: -> místo `Jméno` použij jen `jmeno`. - -## Seznamy - -Vedle řetězců a celých čísel má Python další druhy hodnot. - -Teď se podíváme na jeden, který se nazývá *seznam* (anglicky *list*). -To je hodnota, která v sobě obsahuje jiné hodnoty. - -{# Anglické termíny všude! #} - -Seznamy se zadávají tak, že dáš několik hodnot, oddělených čárkami, -do hranatých závorek. -Zkus si vytvořit třeba seznam čísel z loterie: - -``` pycon ->>> [3, 42, 12, 19, 30, 59] -[3, 42, 12, 19, 30, 59] -``` - -Abys s takovým seznamem mohl{{a}} pracovat, -ulož si ho do proměnné: - -``` pycon ->>> loterie = [3, 42, 12, 19, 30, 59] -``` - -Dobrá, máme seznam! Co s ním můžeme dělat? -Podíváme se, kolik čísel v seznamu je. -Dá se na to použít funkce, kterou už znáš. -Tipneš si, která to je? - -{% filter solution %} -``` pycon ->>> len(loterie) -6 -``` - -Funkce `len()` umí zjistit nejen délku řetězce, ale i délku seznamu – tedy -počet jeho prvků. -{% endfilter %} - -Teď si zkus seznam seřadit. Na to existuje metoda `sort`: - -``` pycon ->>> loterie.sort() -``` - -Tato funkce nic nevrátí, jen změní pořadí čísel v seznamu. -Znovu si ho vypiš, ať vidíš co se stalo: - -``` pycon ->>> loterie -[3, 12, 19, 30, 42, 59] -``` - -Čísla v seznamu jsou nyní seřazena od nejnižší k nejvyšší hodnotě. - -Podobně funguje metoda `reverse`, která obrátí pořadí prvků. -Vyzkoušej si ji! - -``` pycon ->>> loterie.reverse() ->>> loterie -[59, 42, 30, 19, 12, 3] -``` - -Pokud chceš do svého něco přidat seznamu, můžeš to provést pomocí metody -`append`. -Ale pozor! Tahle metoda potřebuje vědět co má do seznamu přidat -Nová hodnota se zadává do závorek: - -``` pycon ->>> loterie.append(199) -``` - -Metoda opět nic nevrací, takže je potřeba seznam pro kontrolu vypsat: - -``` pycon ->>> loterie -[59, 42, 30, 19, 12, 3, 199] -``` - -### Vybírání prvků - -Když se budeš chtít na jednu věc ze seznamu podívat podrobněji, -přijde vhod možnost vybrat si konkrétní prvek. -Na to se v Pythonu používají hranaté závorky. - -{# XXX: MCQ #} - -Chceš-li vybrat prvek, zadej jméno seznamu a hned za ním hranaté závorky -s pořadovým číslem prvku, který chceš: - -``` pycon ->>> loterie[1] -``` - -Dostaneš první prvek? - -{% filter solution %} -``` pycon ->>> loterie -[59, 42, 30, 19, 12, 3, 199] ->>> loterie[1] -42 -``` - -Ne, dostaneš druhý prvek. - -Programátoři počítají od nuly. -Chceš li tedy první prvek, popros Python o prvek číslo nula: - -``` pycon ->>> loterie[0] -42 -``` - -Je to zpočátku divné, ale dá se na to zvyknout. -{% endfilter %} - -Číslu prvku se také říká *index* a procesu vybírání prvků *indexování*. - -Zkus si indexování s dalšími indexy: 3, 100, 7, -1, -2, -6 nebo -100. -Pokus se předpovědět výsledek před zadáním příkazu. -Jak ti to půjde? - -{% filter solution %} -``` pycon ->>> loterie -[59, 42, 30, 19, 12, 3, 199] - ->>> loterie[3] -19 -``` -Index 3 označuje čtvrtý prvek. - -``` pycon ->>> loterie[7] -Traceback (most recent call last): - File "", line 1, in -IndexError: list index out of range - -``` -Prvek s indexem 100 v seznamu není – nastane chyba. - -``` pycon ->>> loterie[1000] -Traceback (most recent call last): - File "", line 1, in -IndexError: list index out of range -``` -Prvek s indexem 7 v seznamu taky není. - -``` pycon ->>> loterie[-1] -199 -``` -Index -1 označuje *poslední* prvek. - -``` pycon ->>> loterie[-2] -3 -``` -Index -2 označuje předposlední prvek. - -``` pycon ->>> loterie[-6] -42 -``` -Index -6 označuje šestý prvek od konce. - -``` pycon ->>> loterie[-100] -Traceback (most recent call last): - File "", line 1, in -IndexError: list index out of range -``` -Stý prvek od konce v seznamu není. Nastane chyba. -{% endfilter %} - -### Řezání - -XXX Slicing - -### Odstraňování - -Chceš-li ze seznamu něco odstranit, můžeš opět použít indexy. -Tentokrát s příkazem `del`. -Následující kód odstraní počáteční číslo seznamu, tedy prvek číslo 0: - -``` pycon ->>> del loterie[0] -``` - -Pak si seznam opět vypiš. Kousek chybí! - -``` pycon ->>> loterie -[42, 30, 19, 12, 3, 199] -``` - -Zkusíš odstranit poslední prvek? - -{% filter solution %} -``` pycon ->>> del loterie[-1] ->>> loterie -[42, 30, 19, 12, 3] -``` -{% endfilter %} - -A co prostřední tři? -Zkus si nejdřív vypsat, které to jsou, a pak teprve použít `del`. - -{% filter solution %} -``` pycon ->>> loterie -[42, 30, 19, 12, 3] ->>> loterie[1:-1] -[30, 19, 12] ->>> del loterie[1:-1] ->>> loterie -[42, 3] -``` -{% endfilter %} - - -## Slovníky - -Jiný typ hodnot, které v sobě mohou obsahovat další hodnoty, je *slovník*. -Pro příklad si představ překladový slovník, třeba česko-anglický: - -* **Jablko**: Apple -* **Knoflík**: Button -* **Myš**: Mouse - -Slovník v Pythonu obsahuje záznamy, a každý záznam přiřazuje -nějakému *klíči* nějakou *hodnotu*. -V našem příkladu je klíči *Jablko* přiřazena hodnota *Apple*, -klíči *Knoflík* náleží hodnota *Button* -a klič *Myš* ukazuje na *Mouse*. - -V Pythonu by se takový slovník napsal následovně: - -``` pycon ->>> slovnik = {'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'} -``` - -Naše klíče a hodnoty jsou slova – krátké texty, tedy řetězce, -které je potřeba dát do uvozovek. -Klíč a hodnota jsou oddělené dvojtečkou, -jednotlivé dvojice se od sebe oddělují čárkou, -a celý slovník je uzavřený ve složených závorkách. - -Když budeš chtít v takovém slovníku něco najít, potřebuješ vědět, co hledat. -Konkrétně *klíč*. -Pomocí hranatých závorek můžeš zjistit hodnotu, která odpovídá danému klíči: - - -``` pycon ->>> slovnik['Jablko'] -'Apple' -``` - -Je to podobné jako u seznamů, jen v hranatých závorkách není pořadí prvku, -ale klíč. -{# XXX: Slicing taky nejde #} - -> [note] -> Naopak to nejde – slovník neumožňuje podle hodnoty přímo zjistit klíč. -> Na překlad z angličtiny do češtiny bys potřeboval{{a}} druhý slovník. - -### Měnění slovníků - -Co se stane, když klíč ve slovníku není? - -``` pycon ->>> slovnik['Pes'] -Traceback (most recent call last): - File "", line 1, in -KeyError: 'Pes' -``` - -Python si postěžuje na `KeyError` – chybu klíče. - -Podobně jako seznamy se ale slovníky dají měnit. -Nový záznam vytvoříš takhle: - -``` pycon ->>> slovnik['Pes'] = 'Dog' ->>> slovnik -{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Dog'} -``` - -> [note] -> Na rozdíl od překladového slovníku nemusí být Pythonní slovník seřazený -> podle abecedy. -> Není to potřeba, počítač umí rychle vyhledávat i bez seřazení. - -Kdybys potřebovala{{a}} změnit už existující záznam, použij stejný příkaz. -K jednomu klíči může patřit jen jedna hodnota. - -``` pycon ->>> slovnik['Pes'] = 'Extension cord' ->>> slovnik -{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse', 'Pes': 'Extension cord'} -``` - -{# XXX: Zmínit se o nehomogenních slovnících? #} - -Chceš-li ze zlovníku nějaký záznam smazat, dělá se to podobně jako -u seznamů příkazem `del`: - -``` pycon ->>> del slovnik['Pes'] ->>> slovnik -{'Jablko': 'Apple', 'Knoflík': 'Button', 'Myš': 'Mouse'} -``` - -A když budeš chtít zjistit, kolik je ve slovníku záznamů, -zeptáš se podobně jako na počet znaků řetězce nebo prvků seznamu. -Použiješ funkci `len()`. - -``` pycon ->>> len(slovnik) -3 -``` - -{# XXX - -* Kontakty -* Když číslo není číslo -* Více čísel - -### K zamyšlení - -Ke každému klíči může patřit jen jedna hodnota. -Jak bys zařídil{{a}}, aby hodnot víc? - -Zkus do Pythonní proměnné uložit tyto kontakty: - -* Katka: - * 4925219 -* Jirka: - * 7477058 - * 3251156 -* Verča: - * 1019103 - -{% filter solution %} -Více hodnot se dá uložit do seznamu. -Hodnoty budou seznamy čísel: - -```pycon ->>> kontakty = {'Katka': ['4925219'], 'Jirka': ['7477058', '3251156'], 'Verča': ['1019103']} -``` -{% endfilter %} - -Verča se přestěhovala do zahraničí a má nové číslo: `+897 3788509`. - -#} - -### Shrnutí - -Skvělé! Nyní víš o programování hodně. V této poslední části jsi poznal{{a}}: - -* **chyby** - hlášky které Python zobrazí když nerozumí příkazu který jsi zadal{{a}} nebo ho neumí splnit -* **proměnné** - názvy pro objekty, které umožňují psát čitelnější kód -* **seznam** - sekvence objektů uložených v určitém pořadí -* **slovník** - sbírka záznamů klíč–hodnota - -Jsi připraven{{a}} na další část? - -## Porovnávání věcí - -Programátoři často porovnávají různé hodnoty. Pojďme se podívat, jak na to. - -``` pycon ->>> 5 > 2 -True ->>> 5 > 8 -False ->>> 5 < 8 -True -``` - -Když se Pythonu zeptáš, jestli je jedno číslo větší než druhé, odpoví ti -`True` (pravda) nebo `False` (nepravda). - -Funguje to i se složitějšími výrazy: - -``` pycon ->>> 5 > 2 * 2 -True -``` - -„Větší než“ a „menší než“ používají značky známé z matematiky. -Chceš-li se ale zeptat, jestli jsou dvě čísla stejná, je to trochu jiné: - -``` pycon ->>> 1 == 1 -True -``` - -Jedno rovnítko `=` používáme pro přiřazení hodnoty do proměnné. -Když chceš zkontrolovat, jestli se věci navzájem rovnají, vždy, **vždy** musíš dát dvě rovnítka `==`. - -Další možnosti porovnávání jsou nerovnost (≠), větší než (≤) a meší než (≥). -Většina lidí tyhle symboly nemá na klávesnici, a tak se používá `!=`, `<=` -a `>=`. - -``` pycon ->>> 5 != 2 -True ->>> 3 <= 2 -False ->>> 6 >= 12 / 2 -True -``` - -### Logika - -Chceš zkusit ještě něco? Zkus tohle: - -``` pycon ->>> 6 > 2 and 2 < 3 -True ->>> 3 > 2 and 2 < 1 -False ->>> 3 > 2 or 2 < 1 -True -``` - -V Pythonu můžeš zkombinovat několik porovnání do jednoho! - -* Pokud použiješ operátor `and`, obě strany musí být pravdivé, aby byl celý výraz pravdivý. -* Pokud použiješ operátor `or`, stačí aby jen jedna strana z porovnání byla pravdivá. - -Už jsi někdy slyšel{{a}} výraz „srovnávat jablka a hrušky“? Zkusme v Pythonu ekvivalent: - -``` pycon ->>> 1 > 'krajta' -Traceback (most recent call last): - File "", line 1, in -TypeError: '>' not supported between instances of 'int' and 'str' -``` - -Stejně jako nelze srovnávat „jablka a hrušky“, -Python není schopen porovnávat řetězce (`str`) a čísla (`int`). -Místo toho zobrazí `TypeError` a říká nám, že tyto dva typy nelze porovnat. - - -### Logické hodnoty - -Mimochodem právě ses dozvěděl{{a}} o novém typu objektu v Pythonu. -Říká se mu *pravdivostní hodnota*, nebo častěji anglicky *boolean*. - -Může mít jednu z dvou hodnot: `True` a `False`. - -Aby Python pochopil, že se jedná o tento typ, -je potřeba dávat pozor na velikost písmen. -`true`, `TRUE`, `tRUE` nebude fungovat – jedině `True` je správně. - -Jako kažtou hodnotu, i pravdivostní hodnotu můžeš uložit do proměnné: - -``` pycon ->>> a = True ->>> a -True -``` - -Stejně tak můžeš uložit i výsledek porovnání: - -``` ->>> a = 2 > 5 ->>> a -False -``` - -# Ulož to! - -Zatím jsi psal{{a}} všechny programy v konzoli v interaktivním režimu Pythonu, -který nás omezuje na jeden řádek kódu. -Když Python opustíš (nebo vypneš počítač), -všechno co jsi zatím naprogramoval{{a}}, se ztratí. - -Větší programy jsou trvanlivější: ukládají se do souborů a dají se kdykoli -spustit znovu. - -Vyzkoušejme si to. Budeme potřebovat: - -* Ukončit interaktivní režim Pythonu -* Otevřít editor kódu -* Uložit kód do nového souboru -* Spustit ho! - -Zkus vypnout Python. Existuje na to funkce `exit()`: - -``` pycon ->>> exit() -``` - -Tak se dostaneš zpět do příkazové řádky. -Budou tu fungovat příkazy jako `cd` a `mkdir`, -ale ne příkazy Pythonu, jako `1 + 1`. - -Chceš-li opustit interaktivní režim Pythonu, který jsme dosud používaly, jednoduše zadejte ~ ~ ~ exit() ~ ~ ~ funkci: - - -{# (((((((( XXX )))))))) #} -> [Note] -> Pokud budeš chtít Python konzoli ukončit, zadej `exit()` nebo použíj -> zkratku `Ctrl + D` (pro Mac/Linux) nebo `Ctrl + Z` (na Windows). -> Pak již neuvidíš `>>>`. - - -Tak se dostaneš zpět do příkazové řádky. - -Doufám, že máš nainstalovaný textový editor. -Ten teď otevři a napiš do nového souboru tento příkaz: - -```python -print('Hello, PyLadies!') -``` - -Teď vytvořený soubor ulož pod nějakým popisným názvem. -Pojďme ho nazvat `python_intro.py` a ulož si jej na plochu. -Soubor můžeš pojmenovat jakkoliv chceš, ale jméno musí končit na `.py` -Tahle přípona říká editoru nebo i operačnímu systému, -že jde o program v Pythonu a Python ho může spustit. - -> [note] Obarvování -> Po uložení by se text měl obarvit. -> V interaktivním režimu Pythonu mělo vše stejnou barvu, -> ale nyní bys měla vidět, že jméno funkce `print` je jinou barvou než -> řetězec v závorkách. -> Barvy nevolíš {{gnd('sám', 'sama')}}, vybírá je editor na základě toho, -> jak potom Python kódu porozumí. -> -> Nazývá se to "zvýrazňování syntaxe" a je to užitečná funkce. -> Chce to trochu praxe, ale barvy můžou napovědět -> že ti chybí uvozovka za řetězcem -> nebo máš překlep v klíčovém slovu jako `del`. -> To je jeden z důvodů, proč používáme editory kódu :) - -Pokud máš soubor uložen, je čas jej spustit! -Pomocí dovedností, které jsi se naučil{{a}} v sekci příkazová řádka, -*změň adresář* terminálu na plochu. - -Na Macu bude příkaz vypadat přibližně takto: - -``` console -(venv) $ cd ~/Desktop -``` - -Na Linuxu to bude vypadat takto (slovo "Desktop" (Plocha) může být -přeloženo třeba do češtiny): - -``` console -(venv) $ cd ~/Desktop -``` - -A na Windows to bude vypadat takto: - -``` doscon -(venv) > cd Desktop -``` - -Pokud nevíš jak dál, požádej o pomoc kouče. - -Nyní pomocí Pythonu spusť kód v souboru: - -``` console -(venv) $ python python_intro.py -Hello, PyLadies! -``` - -Funguje? Vidíš text? -Jesli ano, právě jsi spustil{{a}} svůj první opravdový program v Pythonu! -Cítíš se úžasně? - -### Vstup a výstup - -Funkce `print()`, kterou jsi použila, umí něco *vypsat* na obrazovku. -V konzoli se hodnoty výrazů vypisovaly automaticky, abys je mohl{{a}} -průběžně kontrolovat, ale programy v souborech bývají složitější a výpis -každého kroku by byl nepřehledný. -Proto na vypsání potřebuješ `print()`. -Zkus si to: - -``` python -jmeno = 'Ola' - -'Já jsem ' + jmeno # Tohle Python nevypíše - -print(jmeno * 8) # Tohle jo! -``` - -Do závorek funkce `print()` můěš dát i víc hodnot oddělených čárkami. - -``` python -jmeno = 'Amálka' -vek = 5 -print('Já jsem', jmeno, 'a je mi', vek) - -print('Za rok mi bude', vek + 1) -``` - -Další užitečná funkce je `input()`, která se umí zeptat na otázku. -Odpověď pak vrátí jako řetězec, který si můžeš uložit do proměnné: - -``` python -jmeno = input('Jak se jmenuješ? ') -print(jmeno, 'umí programovat!') -``` - -A co když budeš chtít spíš číslo než text? -Pamatuješ si na funkci, která umí převést řetězec na číslo? - -``` python -letopocet = int(input('Jaký je letos rok? ')) -print('Loni byl rok', letopocet - 1) -``` - - -## Když – tak - -Spoustu věcí v kódu chceme provádět, jen pokud jsou splněny určité podmínky. -Proto má Python *podmíněné příkazy*. - -Zkusíme napsat program, který ověřuje tajné heslo. -Tenhle program napíše `True`, když zadáš slovo `čokoláda`: - -```python -heslo = input('Zadej heslo: ') -print(heslo == 'čokoláda') -``` - -Vypsání `True` ale není moc zajímavé. -Lepší program by dělal tohle: - -* Zeptá se na tajné heslo -* Když je heslo správné: - * Pustí uživatele dovnitř - -Anglicky se „když“ řekne *if*. A to je i jméno Pythoního příkazu. -Používá se takhle: - -```python -heslo = input('Zadej heslo: ') -if heslo == 'čokoláda': - print('Správně! Račte vstoupit.') -``` - -Podmíněný příkaz začíná `if`, pokračuje podmínkou (třeba porovnáním) -a končí dvojtečkou. - -Po řádkem s `if` je příkaz *odsazený* – na začátku řádku jsou 4 mezery. - -Podle toho Python pozná, že tuhle část programu má provést, -jen když je podmínka pravdivá. - -Ulož a spusť: - -``` console -(venv) $ python python_intro.py -Zadej heslo: čokoláda -Správně! Můžeš vstoupit. -``` - -``` console -(venv) $ python python_intro.py -Zadej heslo: sezam -``` - -### Jinak - -V předchozím příkladu byl kód proveden pouze v případě, že podmínka byla splněna. -Ještě lepší program by ale: - -* Zeptá se na tajné heslo -* Když je heslo správné: - * Pustí uživatele dovnitř -* Jinak: - * Spustí alarm - -K tomu má Python příkaz `else` – „jinak“: - -```python -heslo = input('Zadej heslo: ') -if heslo == 'čokoláda': - print('Správně! Račte vstoupit.') -else: - print('POZOR! POZOR!') - print('NEOPRÁVNĚNÝ VSTUP!') -``` - -Funuje to? - -### Více možností - -Občas se stane, že se program musí rozhodnout mezi více možnostmi. -K tomu slouží příkaz `elif`, zkratka znglického *else if* – „jinak, pokud“. - -Napišme program, který okomentuje hlasitost hudby: - -* Zeptá se na hlasitost, a odpověď uloží jako číslo. -* Když je hlasitost do 20: - * vypíše „Je to dost potichu.“ -* Jinak, když je hlasitost do 40: - * vypíše „Jako hudba v pozadí dobré.“ -* Jinak, když je hlasitost do 60: - * vypíše „Skvělé, slyším všechny detaily.“ -* Jinak, když je hlasitost do 80: - * vypíše „Dobré na párty.“ -* Jinak, když je hlasitost do 100: - * vypíše „Trochu moc nahlas!“ -* Jinak: - * vypíše „Krvácí mi uši!“ - -V Pythonu: - -```python -hlasitost = int(input('Jaká je nastavená hlasitost rádia? ')) -if hlasitost < 20: - print("Je to dost potichu.") -elif hlasitost < 40: - print("Jako hudba v pozadí dobré.") -elif hlasitost < 60: - print("Skvělé, slyším všechny detaily.") -elif hlasitost < 80: - print("Dobré na party.") -elif hlasitost < 100: - print("Trochu moc nahlas!") -else: - print("Krvácí mi uši!") -``` - -``` console -(venv) $ python python_intro.py -Jaká je nastavená hlasitost rádia? 28 -Jako hudba v pozadí dobré. -``` - -Všimni si, že se vybere vždycky jedna alternativa. -Když zadáš `28`, Python se dostane k `hlasitost < 40`, vypíše -příslušnou hlášku a další možnosti přeskočí. - - -### Shrnutí - -V posledních třech cvičeních ses dozvěděla o: - -* **Porovnání věcí** - v Pythonu můžeš porovnávat věci pomocí operátorů `>`, `>=`, `==` `<=`, `<`, `!=` a `and`, `or` -* **Pravdivostní hodnoty / Boolean** - typ, který může mít pouze jednu ze dvou hodnot: `True` nebo `False` -* **Ukládání do souborů** - pokud uložíš kód do souboru, můžeš spouštět větší programy -* **if – elif – else** - příkazy, které umožňují spouštět kód pouze v případě, kdy jsou splněny určité podmínky. - -Čas na předposlední část této kapitoly! - - -## Vlastní funkce - -Pamatuješ na funkce `len()` a `print()`? -Jsou jako kouzelná zaříkadla z knihy vázané v kůži: když víš jak se jmenují -a umíš je správně {# XXX: vyslovit #}napsat, něco pro tebe udělají. - -Teď postoupíme na další úroveň: vymyslíme si vlastní zaříkadla! -Jak? Budeme kombinovat příkazy, které už známe. - -Třeba funkce, která tě pozdraví, by měla: - -* Vypsat „ahoj!“ -* Vypsat „jak se máš?“ - -Definice funkce v Pythonu začíná klíčovým slovem `def`, -dále je uveden název a závorky (zatím prázdné). -Pak jako po `if` dvojtečka, a odsazené příkazy, -které má funkce provést. - -```python -def pozdrav(): - print('Ahoj!') - print('Jak se máš?') -``` - -Naše první funkce je připravena! - -Když ale tenhle program spustíš, nic neudělá. -To proto, že tohle je jen *definice* funkce. -Python teď ví jak pozdravit – ale neřeklo se, že to má udělat! - -Na konec programu přidej volání. -To už není součást funkce, ale pokračování samotného programu. -Proto nesmí být odsazené: - -```python -def pozdrav(): - print('Ahoj!') - print('Jak se máš?') - -pozdrav() -``` - -Co se stane, když funkci zavoláš několikrát po sobě? - -```python -def pozdrav(): - print('Ahoj!') - print('Jak se máš?') - -pozdrav() -pozdrav() -pozdrav() -``` - -Co se stane, když volání dáš *nad* definici funkce, místo na konec programu? - -```python -pozdrav() - -def pozdrav(): - print('Ahoj!') - print('Jak se máš?') -``` - -{% filter solution %} -``` pycon -Traceback (most recent call last): - File "", line 1, in -NameError: name 'pozdrav' is not defined -``` - -Python si stěžuje na `NameError` – nezná nic jménem `pozdrav`. - -Python totiž program čte odzhora dolů. -Až příkazem `def` se „naučí" jak zdravit – -Předtím, než se k příkazu `def` dostane, funkce neexistuje. -{% endfilter %} - -# Parametry - -Funkce jako `len('slovo')` a `print(1 + 2)` umí navíc pracovat s hodnotou. - -Pojďme napisať funkciu, ktorá ťa pozdraví menom. -(Uľahčíme si to použitím jazyka, ktorý nepoužíva piaty pád.) - -```python -def pozdrav(meno): - print('Vitam ťa,', meno) - -pozdrav('Ola') -pozdrav('Soňa') -pozdrav('Hubert') -pozdrav('Anička') -``` - -Jak to funguje? -V definici funkce uvedeš závorkách *parametr* – jméno proměnné se kterou bude -funkce pracovat. -Hodnotu pro tenhle parametr pak zadáš při volání funkce. - -Zvládneš napsat program, který se zeptá na jméno a pak tě pozdraví? - -{% filter solution %} -```python -def pozdrav(meno): - print('Vitam ťa,', meno) - -pozdrav(input('Jak se jmenuješ? ')) -``` -{% endfilter %} - -Co se stane, když funkci zavoláš bez hodnoty pro parametr? - -{% filter solution %} -``` pycon -Traceback (most recent call last): - File "", line 9, in -TypeError: pozdrav() missing 1 required positional argument: 'meno' -``` - -Python si stěžuje na `TypeError` – funkce `pozdrav` nedostala povinný -argument `meno`. -{% endfilter %} - -Funkce může obsahovat jakýkoli kód. -Třeba podmíněný příkaz, `if`. -Příkazy po `if` je pak potřeba odsatit o *další* čtyři mezery: - -```python -def pozdrav(meno): - print('Vitam ťa,', meno) - if meno == 'Ola': - print('Ty umíš programovať!') - -pozdrav('Hubert') -pozdrav('Ola') -pozdrav('Soňa') -``` - - -## Cykly - -Programátoři se neradi opakují. -Programování je o automatizaci: nebudeme zdravit každého člověka zvlášť, -vezměme seznam padesáti lidí a pozdravíme je všechny najednou! - -(Hm, někteří programátoři nejsou moc sociálně nadaní. -Ale jinde se ta automatizace fakt hodí!) - -Ještě si vzpomínáš na seznamy? -Udělej si seznam jmen: - -```python -jmena = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'Ty'] -``` - -Udělejme program, který: - -* Pro každé jméno ze seznamu jmen: - * pozdraví daným jménem - -V Pythonu se takový *cyklus* – opakování „pro každý prvek seznamu“ – píše -pomocí příkazu `for`: - -``` python -for jmeno in jmena: - pozdrav(jmeno) -``` - -Celý program bude tedy vypadat takto: - -```python -def pozdrav(meno): - print('Vitam ťa,', meno) - -jmena = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'Ty'] -for jmeno in jmena: - pozdrav(jmeno) -``` - -A když ho spustíme: - -``` console -$ python3 python_intro.py -Vitam ťa, Rachel -Vitam ťa, Monica -Vitam ťa, Phoebe -Vitam ťa, Ola -Vitam ťa, Ty -``` - -Jak vidíš, vše, co jsi vložila dovnitř příkazu `for` s odsazením, -se zopakuje pro každý prvek seznamu `jmena`. - -{# XXX: exercise? #} - -## Opakuj n-krát - -Cyklus `for` můžeš použít i s jinými hodnotami než se seznamy. - -Často se používá s funkcí `range()`. -Když chceš něco 200-krát zopakovat, napiš: - -```python -for i in range(200): - print("Nebudu házet igelit do táboráku!") -``` - -Jak to funguje? -`for i in range(X)` se dá přeložit jako „pro každé číslo -od nuly do X“. -Do proměnné `i` Python uloží, pokolikáté cyklem prochází – počínaje, -v programátorském stylu, od nuly: - -```python -for i in range(5): - print(i) -``` -``` -0 -1 -2 -3 -4 -``` - -`range` je funkce, která vytvoří seznam s posloupností čísel (tato čísla zadáváš jako parametry funkce). - -Všimni si, že druhé z těchto dvou čísel není zahrnuto v seznamu, který je výstupem Pythonu (`range (1, 6)` počítá od 1 do 5, ale nezahrnuje číslo 6). To je proto, že "range" je z poloviny otevřený, čímž myslíme, že obsahuje první hodnotu, ale ne poslední. - -## Shrnutí - -A je to. -*Jsi naprosto skvěl{{gnd('ý', 'á')}}!* -Tohle byla složitá kapitola, takže bys na sebe měl{{a}} být hrd{{gnd('ý', 'á')}}. -My jsme na tebe velmi hrdí za to, že ses dostal{{a}} tak daleko! - -Naučil{{a}} ses: - -* **Definice funkcí** – jak pojmenovat pár příkazů -* **Cykly** – jak opakovat nějaký postup několikrát po sobě - -Můžeš si jít krátce odpočinout – protáhnout se, projít se, -zavřít oči – než se pustíme do další kapitoly. :) - -🧁 - - {# XXX: range #} diff --git a/lessons/fast-track/repl/index.md b/lessons/fast-track/repl/index.md new file mode 100644 index 0000000000..3f92c2f963 --- /dev/null +++ b/lessons/fast-track/repl/index.md @@ -0,0 +1,65 @@ +# Interaktivní režim Pythonu + +Chceš-li si začít hrát s Pythonem, otevři *příkazový řádek* a aktivuj virtuální prostředí. Zkontroluj si, že na začátku příkazové řádky ti svítí `(venv)`. + +Je-li tomu tak, nezbývá než – konečně – pustit Python. K tomu použij příkaz `python`: + +``` console +$ python3 +Python 3.6.6 (...) +Type "help", "copyright", "credits" or "license" for more information. +>>> +``` + +Příkaz vypíše několik informací. Z prvního řádku se můžeš ujistit, že používáš Python 3. (Vidíš-li číslo jako `2.7.11`, něco je špatně – popros o radu kouče.) + +Třemi „zobáčky“ ``>>>` pak Python poprosí o instrukce. Je to jako v příkazové řádce, ale místo příkazů jako `cd` a `mkdir` sem budeš psát příkazy Pythonu. + +Jako první instrukci použijeme Pythonu jako kalkulačku. +Za tři zobáčky napiš třeba `2 + 3` a zmáčkni Enter. + +``` pycon +>>> 2 + 3 +5 +``` + +Zobrazila se ti správná odpověď? +Pokud ano, gratuluji! První příkaz v Pythonu máš za sebou. + +Zkusíš i odečítání? + +A jak je to s násobením? +{# XXX: Jak zapsat násobení? `4 x 5` `4 . 5` `4 × 5` `4 * 5` -#} +Na kalkulačce bys zadala `4 × 5`, což se na klávesnici píše špatně. +Python proto používá symbol `*` a pro dělení `/`. +Tyhle symboly se odborně nazývají *operátory*. + +``` pycon +>>> 4 * 5 +20 +>>> 5 / 2 +2.5 +``` + +> [note] +> V tomto úvodu budeme zadávat jen celá čísla. +> Dělením ale může vzniknout třeba dva a půl +> (tedy `2.5` – Python používá desetinnou *tečku*). +> Z důvodů, do kterých teď nebudeme zabíhat, se desetinné pozice po dělení +> objeví i když vyjde celé číslo: +> ``` pycon +> >>> 4 / 2 +> 2.0 +> ``` + +{# XXX: +Kolik je +123 + 456789? +#} + +> [style-note] +> Mezery mezi čísly a znamínkem nejsou nutné: `4*5` i `4 * 5` dělá +> to samé co `4 * 5`. +> Je ale zvykem psát kolem operátoru jednu mezeru z každé strany – tak jako +> v těchto materiálech. +> Kód je pak čitelnější. diff --git a/lessons/fast-track/repl/info.yml b/lessons/fast-track/repl/info.yml new file mode 100644 index 0000000000..31c415c76a --- /dev/null +++ b/lessons/fast-track/repl/info.yml @@ -0,0 +1,12 @@ +title: Interaktivní režim Pythonu +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/script/index.md b/lessons/fast-track/script/index.md new file mode 100644 index 0000000000..c480a740b7 --- /dev/null +++ b/lessons/fast-track/script/index.md @@ -0,0 +1,144 @@ +# Ulož to! + +Zatím jsi psal{{a}} všechny programy v konzoli v interaktivním režimu Pythonu, +který nás omezuje na jeden řádek kódu. +Když Python opustíš (nebo vypneš počítač), +všechno co jsi zatím naprogramoval{{a}}, se ztratí. + +Větší programy jsou trvanlivější: ukládají se do souborů a dají se kdykoli +spustit znovu. + +Vyzkoušejme si to. Budeme potřebovat: + +* Ukončit interaktivní režim Pythonu +* Otevřít editor kódu +* Uložit kód do nového souboru +* Spustit ho! + +Zkus vypnout Python. Existuje na to funkce `exit()`: + +``` pycon +>>> exit() +``` + +Tak se dostaneš zpět do příkazové řádky. +Budou tu fungovat příkazy jako `cd` a `mkdir`, +ale ne příkazy Pythonu, jako `1 + 1`. + +Chceš-li opustit interaktivní režim Pythonu, který jsme dosud používaly, jednoduše zadejte ~ ~ ~ exit() ~ ~ ~ funkci: + + +{# (((((((( XXX )))))))) #} +> [Note] +> Pokud budeš chtít Python konzoli ukončit, zadej `exit()` nebo použíj +> zkratku `Ctrl + D` (pro Mac/Linux) nebo `Ctrl + Z` (na Windows). +> Pak již neuvidíš `>>>`. + + +Tak se dostaneš zpět do příkazové řádky. + +Doufám, že máš nainstalovaný textový editor. +Ten teď otevři a napiš do nového souboru tento příkaz: + +```python +print('Hello, PyLadies!') +``` + +Teď vytvořený soubor ulož pod nějakým popisným názvem. +Pojďme ho nazvat `python_intro.py` a ulož si jej na plochu. +Soubor můžeš pojmenovat jakkoliv chceš, ale jméno musí končit na `.py` +Tahle přípona říká editoru nebo i operačnímu systému, +že jde o program v Pythonu a Python ho může spustit. + +> [note] Obarvování +> Po uložení by se text měl obarvit. +> V interaktivním režimu Pythonu mělo vše stejnou barvu, +> ale nyní bys měla vidět, že jméno funkce `print` je jinou barvou než +> řetězec v závorkách. +> Barvy nevolíš {{gnd('sám', 'sama')}}, vybírá je editor na základě toho, +> jak potom Python kódu porozumí. +> +> Nazývá se to "zvýrazňování syntaxe" a je to užitečná funkce. +> Chce to trochu praxe, ale barvy můžou napovědět +> že ti chybí uvozovka za řetězcem +> nebo máš překlep v klíčovém slovu jako `del`. +> To je jeden z důvodů, proč používáme editory kódu :) + +Pokud máš soubor uložen, je čas jej spustit! +Pomocí dovedností, které jsi se naučil{{a}} v sekci příkazová řádka, +*změň adresář* terminálu na plochu. + +Na Macu bude příkaz vypadat přibližně takto: + +``` console +(venv) $ cd ~/Desktop +``` + +Na Linuxu to bude vypadat takto (slovo "Desktop" (Plocha) může být +přeloženo třeba do češtiny): + +``` console +(venv) $ cd ~/Desktop +``` + +A na Windows to bude vypadat takto: + +``` doscon +(venv) > cd Desktop +``` + +Pokud nevíš jak dál, požádej o pomoc kouče. + +Nyní pomocí Pythonu spusť kód v souboru: + +``` console +(venv) $ python python_intro.py +Hello, PyLadies! +``` + +Funguje? Vidíš text? +Jesli ano, právě jsi spustil{{a}} svůj první opravdový program v Pythonu! +Cítíš se úžasně? + +## Vstup a výstup + +Funkce `print()`, kterou jsi použila, umí něco *vypsat* na obrazovku. +V konzoli se hodnoty výrazů vypisovaly automaticky, abys je mohl{{a}} +průběžně kontrolovat, ale programy v souborech bývají složitější a výpis +každého kroku by byl nepřehledný. +Proto na vypsání potřebuješ `print()`. +Zkus si to: + +``` python +jmeno = 'Ola' + +'Já jsem ' + jmeno # Tohle Python nevypíše + +print(jmeno * 8) # Tohle jo! +``` + +Do závorek funkce `print()` můěš dát i víc hodnot oddělených čárkami. + +``` python +jmeno = 'Amálka' +vek = 5 +print('Já jsem', jmeno, 'a je mi', vek) + +print('Za rok mi bude', vek + 1) +``` + +Další užitečná funkce je `input()`, která se umí zeptat na otázku. +Odpověď pak vrátí jako řetězec, který si můžeš uložit do proměnné: + +``` python +jmeno = input('Jak se jmenuješ? ') +print(jmeno, 'umí programovat!') +``` + +A co když budeš chtít spíš číslo než text? +Pamatuješ si na funkci, která umí převést řetězec na číslo? + +``` python +letopocet = int(input('Jaký je letos rok? ')) +print('Loni byl rok', letopocet - 1) +``` diff --git a/lessons/fast-track/script/info.yml b/lessons/fast-track/script/info.yml new file mode 100644 index 0000000000..94b7f371ab --- /dev/null +++ b/lessons/fast-track/script/info.yml @@ -0,0 +1,12 @@ +title: Ulož to! +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/str/index.md b/lessons/fast-track/str/index.md new file mode 100644 index 0000000000..009a546f20 --- /dev/null +++ b/lessons/fast-track/str/index.md @@ -0,0 +1,177 @@ +# Řetězce + +Čísla jsou pro počítače dost užitečná (ostatně slovo *počítač* to naznačuje), +ale Python umí pracovat i s jinými druhy informací. +Třeba s textem. + +Zkus si to: zadej své jméno do uvozovek, jak vidíš níže: + +``` pycon +>>> 'Ola' +'Ola' +``` + +Nyní jsi vytvořil{{a}} svůj první *řetězec*! +Řetězec je programátorský termín pro *text* – posloupnost znaků (písmenek), které mohou být zpracovány počítačem. + +Když řetězec zadáváš, musíš ho vždy uzavřít do uvozovek (apostrofů). +Jinak by Python nepoznal, co je text a co jsou instrukce. + +{# XXX: Assessment here: adding strings together #} + +Řetězce se dají spojovat – „sečítat“ – pomocí `+`. Zkus toto: + +``` pycon +>>> 'Já jsem ' + 'Ola' +'Já jsem Ola' +``` + +> [note] +> Pozor na mezeru! Když zadáš `'Já jsem'+'Ola'`, spojí se ti dvě slova +> dohromady. +> Počítač považuje i mezeru za *znak*; chová se k ní stejně jako k jakémukoli +> písmenku. +> Když nedáš mezeru do uvozovek, nebude součástí řetězce. +> +> Zkus si: +> +> ``` pycon +> >>> 'Já jsem' + ' ' + 'Ola' +> 'Já jsem Ola' +> ``` + +Také můžeš řetězce opakovat – násobit číslem: + +``` pycon +>>> 'Ola' * 3 +'OlaOlaOla' +``` + +## Uvozování + +A co když budeš chtít dát dovnitř do svého řetězce apostrof? +Můžeš kolem řetězce použít dvojité uvozovky: + +``` pycon +>>> "To bych řek', že jsou pořádně praštěný!" +"To bych řek', že jsou pořádně praštěný!" +``` + +Pythonu je jedno, se kterým druhem uvozovek řetězec zadáš. +Podstatná jsou jen písmenka uvnitř. +Když Python řetězec vypisuje, může si vybrat jiný druh uvozovek +než jsi použil{{a}} ty: + +``` pycon +>>> "Ola" +'Ola' +``` + +## Funkce a metody + +Už umíš řetězce „sčítat“ pomocí `+` (`'Ahoj ' + 'Olo!'`) +a „násobit“ pomocí `*` (`'la' * 3`). +Na všechny ostatní věci, které se s textem dají dělat, +ale na klávesnici není dost symbolů. +Proto jsou některé operace pojmenované slovně – třeba takzvané *funkce*. + +Chceš-li znát počet písmen ve svém jméně, zavolej funkci `len`. +Napiš `len` (bez uvozovek), pak kulaté závorky, a do těch závorek +své jméno (jako řetězec – v uvozovkách): + +``` pycon +>>> len('Ola') +3 +``` + +{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} + +Kromě funkcí existují *metody*, které se zapisují trochu jinak. + +Chceš-li vidět své jméno velkými písmeny, zavolej metody `upper`. +Napiš řetězec, pak tečku, jméno metody `upper` (bez uvozovek) a prázdné +závorky: + +``` pycon +>>> 'Ola'.upper() +'OLA' +``` + +Zkus si zavolat metodu `lower`. + +{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} + +Co je metoda (které voláš s `.`, jako `'Ola'.upper()`) a co je funkce +(kde vložíš informaci do závorek jako (`len('Ola')`) + + +{# XXX: Move elsewhere? #} +## Skládání + +Volání funkce nebo metody můžeš použít jako jinou hodnotu. + +Nech Python spočítat matematický výraz `(1 + 3) / 2`: + +```pycon +>>> (1 + 3) / 2 +2.0 +``` + +Python napřed sečte `1 + 3` a vyjde mu 4. +Čtverku doplní místo `1 + 3` do původního příkladu, a dostane `4 / 2`. +To vydělí a dostane `2`. + +Neboli: `(1 + 3) / 2` = `4 / 2` = `2` + +Zkus se zamyslet, jak Python zpracuje tyto výrazy: + +```pycon +>>> len('Ola') + 1 +4 +``` + +```pycon +>>> 'Já jsem ' + 'Ola'.upper() +'Já jsem OLA' +``` + +```pycon +>>> len('Ola'.upper()) +4 +``` + +```pycon +>>> len('Ola' * 3) +9 +``` + +{% filter solution() %} +`'Já jsem ' + 'Ola'.upper()` → `'Já jsem ' + 'OLA'` → `'Já jsem OLA'` + +`len('Ola') + 1` → `3 + 1` → `4` + +`len('Ola'.upper())` → `len('OLA')` → `3` + +`len('Ola' * 3)` → `len('OlaOlaOla')` → `9` +{% endfilter %} + + +Podobné skládání je v programování velice časté. +Většinu základních stavebních bloků se začátečník naučí za pár +týdnů – a pak je po celou svou progrmátorskou kariéru skládá do +složitějších a složitějších konstrukcí. + +### Shrnutí + +OK, dost bylo řetězců. Co ses zatím naučil{{a}}: + +* **Interaktivní režim Pythonu** umožňuje zadávat příkazy (kód) pro + Python a zobrazuje výsledky/odpovědi. +* **Čísla a řetězce** se používají na matematiku a práci s textem. +* **Operátor** jako `+` a `*` kombinuje hodnoty a vytvoří výsledek. +* **Funkce** a **metody** jako `len()` a `upper()` provádí na hodnotách + nějaké akce. + +Čísla, řetězce a operátory a funkce jsou základy většiny programovacích jazyků. + +Připraven{{a}} na něco dalšího? Vsadíme se, že ano! diff --git a/lessons/fast-track/str/info.yml b/lessons/fast-track/str/info.yml new file mode 100644 index 0000000000..2356c8de7b --- /dev/null +++ b/lessons/fast-track/str/info.yml @@ -0,0 +1,12 @@ +title: Řetězce +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 diff --git a/lessons/fast-track/variables/index.md b/lessons/fast-track/variables/index.md new file mode 100644 index 0000000000..b03ceaed36 --- /dev/null +++ b/lessons/fast-track/variables/index.md @@ -0,0 +1,94 @@ +# Proměnné + +Důležitým konceptem v programování jsou *proměnné*. +Proměnná není nic jiného než *pojmenování* něčeho, +co budeme chtít použít později. +Programátoři proměnné používají k ukládání dat, +aby byl jejich kód čitelnější a nemuseli si pamatovat konkrétní hodnoty. + +Řekněme, že chceš vytvořit novou proměnnou s názvem `jmeno`. +To se zapíše takto: + +``` pycon +>>> jmeno = 'Ola' +``` + +Proměnná `jmeno` teď bude mít hodnotu `'Ola'`. + +Jak sis mohl{{a}} všimnout, tenhle příkaz nic nevrátil – Python nevypsal +žádný výslede. +Jak tedy víme, že proměnná skutečně existuje? + +Zadej samotné jméno proměnné (tedy `jmeno`) a stiskni Enter: + +``` pycon +>>> jmeno +'Ola' +``` + +Zkus si nastavit i jinou proměnnou – třeba svoji oblíbenou barvu: + +``` pycon +>>> barva = 'modrá' +>>> barva +'modrá' +``` + +Kdykoli můžeš do proměnné přiřadit znovu, a změnit tak co se pod +daným jménem skrývá: + +``` pycon +>>> jmeno +'Ola' +>>> jmeno = "Soňa" +>>> jmeno +'Soňa' +``` + +Můžeš ji také použít ve funkcích: + +``` pycon +>>> len(jmeno) +4 +``` + +Super, ne? +Proměnná může obsahovat cokoliv, například také čísla! +Zkus tohle: + +``` pycon +>>> sirka = 4 +>>> delka = 6 +>>> sirka * delka +24 +``` + +Ale co když použiješ nesprávné jméno? Dokážeš odhadnout, co se stane? + +{% filter solution %} +``` pycon +>>> mesto = "Tokyo" +>>> mmesto +Traceback (most recent call last): + File "", line 1, in +NameError: name 'mmesto' is not defined +``` +{% endfilter %} + +Chyba! + +Python má různé typy chyb. Tato se nazývá `NameError`. +Python ti vrátí tuto chybu, pokud se pokusíš použít proměnnou, +která dosud nebyla nastavena. +Pokud někdy dojde k této chybě, zkontroluj svůj kód, abys zjistil{{a}}, +jestli jsi někde neudělal{{a}} překlep. + +> [note] Jména proměnných +> Profesionální programátoři pojmenovávají proměnné anglicky, +> aby jim rozuměli co nejvíc kolegů po celém světě. +> Ze začátku ale doporučujeme češtinu – je tak jasnější, která jména +> si můžeš zvolit {{gnd('sám', 'sama')}} (např. `barva`) a která jsou +> z Pythonu (např. `upper`). +> +> Je ovšem dobré se nepoužívat diakritiku a vyhnout se velkým pímenům: +> místo `Jméno` použij jen `jmeno`. diff --git a/lessons/fast-track/variables/info.yml b/lessons/fast-track/variables/info.yml new file mode 100644 index 0000000000..1177b57aed --- /dev/null +++ b/lessons/fast-track/variables/info.yml @@ -0,0 +1,12 @@ +title: Proměnné +style: md +attribution: +- Založeno na materiálech [DjangoGirls](https://djangogirls.org/). +- Část této kapitoly je založena na kurzu [Geek Girls Carrots](https://github.com/ggcarrots/django-carrots). +- | + Původní DjangoGirls tutoriál přeložila do češtiny skupina dobrovolníků. + Poděkování patří hlavně: Davidovi (dakf), Kristýně Kumpánové, + Veronice Gabrielové, Tomáši Ehrlichovi, Aničce Jaegerové, + Matějovi Stuchlíkovi, Filipovi Sivákovi a Juraji M. Bezručkovi. +- Pro PyLadies CZ upravil Petr Viktorin, 2018. +license: cc-by-sa-40 From 434e995057ad23ca41368b0aabb08463eec3744c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 29 Aug 2018 23:27:54 +0200 Subject: [PATCH 10/30] Add installation instructions and venv setup to snake workshop --- courses/snake/info.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/courses/snake/info.yml b/courses/snake/info.yml index bcfb6f21cb..5b0d930b58 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -40,6 +40,7 @@ plan: materials: - lesson: beginners/cmdline - lesson: beginners/install + - lesson: beginners/venv-setup - lesson: beginners/install-editor - title: Workshop slug: intro From 679c7368e8857b185e5081b3e5be7e03b0d6e45f Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 31 Aug 2018 10:22:45 +0200 Subject: [PATCH 11/30] Snake: Put entire game in one file, move toroid topo into extension --- courses/snake/info.yml | 8 + lessons/snake/drawing/index.md | 59 ++- lessons/snake/logic/index.md | 399 ++++++++----------- lessons/snake/logic/info.yml | 2 +- lessons/snake/logic/static/coord-vectors.svg | 269 +++++++++++++ lessons/snake/toroid/index.md | 101 +++++ lessons/snake/toroid/info.yml | 4 + 7 files changed, 589 insertions(+), 253 deletions(-) create mode 100644 lessons/snake/logic/static/coord-vectors.svg create mode 100644 lessons/snake/toroid/index.md create mode 100644 lessons/snake/toroid/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml index 5b0d930b58..44bc9ae319 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -66,3 +66,11 @@ plan: - lesson: snake/logic - title: Zabalení spustitelného souboru (bonus) url: null +- title: Rozšíření + slug: extensions + date: 2018-09-01 + time: + start: '18:00' + end: '18:30' + materials: + - lesson: snake/toroid diff --git a/lessons/snake/drawing/index.md b/lessons/snake/drawing/index.md index 31350daa95..7ddab81066 100644 --- a/lessons/snake/drawing/index.md +++ b/lessons/snake/drawing/index.md @@ -14,7 +14,7 @@ musí o hře „pamatovat“, aby mohl aktuální stav zobrazit? Bude potřebovat například aktuální polohu všech částí hada: kde má začátek? Kroutí se doprava nebo doleva? Jak je dlouhý? -Naopak barvu hada se stavu ukložit nepotřebuješ – každý had v téhle hře bude +Naopak barvu hada ve stavu uložit nepotřebuješ – každý had v téhle hře bude stejný. Napadne tě, jak polohu hada zapsat pomocí čísel, seznamů a dalších základních @@ -35,7 +35,7 @@ Každý bod v rovině (třeba na obrazovce!) je možné popsat dvěmi čísly: x-ovou a y-ovou souřadnicí. Ta x-ová říká, jak moc vlevo je bod od nějakého počátku, ta y-ová udává jak moc je nahoře. -My za onen „počátek“ zvolíme roh okýnka, ve kterém se bude plazit náš had. +My za onen „počátek“ zvolíme roh okýnka, ve kterém se bude náš had plazit. Na rozdíl od školní geometrie se had bude plazit po čtverečkové mřížce. Je to jako na šachovnici – když jde pěšec na D5, D značí, jak moc je to @@ -100,10 +100,6 @@ se souřadnicemi (10, 20). Na to, abychom hada vykreslili, použijeme okýnko z Pygletu. Tady je základní kostra programu Pyglet, které už bys měl{{a}} rozumět. -Udělej si nový, prázdný adresář na hadí hru, a kostru si -zkopíruj do souboru `ui.py`. -Budeme ji dál rozvíjet. - ```python import pyglet @@ -116,6 +112,10 @@ def on_draw(): pyglet.app.run() ``` +Udělej si nový, prázdný adresář na hadí hru, a kostru si +zkopíruj do souboru `had.py`. +Budeme ji dál rozvíjet. + Stáhni si soubor [green.png]({{ static('green.png') }}) – zelený čtvereček – a dej ho do adresáře, kam píšeš kód. @@ -133,7 +133,7 @@ Potom zkus dovnitř do funkce `on_draw` přidat vykreslení obrázku na souřadn green_image.blit(40, 50, width=10, height=10) ``` -Program spusť (`cd` do nového adresáře; `python ui.py`). Funguje? +Program spusť (`cd` do nového adresáře; `python had.py`). Funguje? (Je docela důležité, aby fungoval – nevidíš-li zelený čtvereček, nečti dál a program radši oprav.) @@ -201,8 +201,7 @@ for x, y in snake: ... ``` -Funguje to? Vidíš v tom – aspoň zhruba – hada -(i když je poskládaný ze čtverečků)? +Funguje to? Vidíš v tom – aspoň zhruba – hada poskládaného ze čtverečků? {{ figure( img=static('coords-blocks.svg'), @@ -210,8 +209,8 @@ Funguje to? Vidíš v tom – aspoň zhruba – hada ) }} Jestli ne, nezoufej, zkontroluj si to znovu, poptej se na radu. -Řešení využij až jako krajní možnost, jak pokračovat dál – nebo na kontrolu -správného řešení. +Ukázkové řešení využij až jako krajní možnost, jak pokračovat dál. +Nebo pro kontrolu. {% filter solution %} ```python @@ -239,12 +238,11 @@ pyglet.app.run() ## Krmení - Aby bylo ve hře co dělat, budeme potřebovat pro hada krmení. -Stáhni si do adresáře s projektem obrázek `apple.png` (ať už jednoduchý -čtvereček nebo detailnější obrázek), a zkus vykreslit jídlo třeba -na následující souřadnice: +Stáhni si do adresáře s projektem obrázek +[apple.png](({{ static('apple.png') }}) a zkus vykreslit +jablíčka na následující souřadnice: ```python food = [(2, 0), (5, 1), (1, 4)] @@ -278,12 +276,13 @@ pyglet.app.run() ``` {% endfilter %} -Používáš-li detailnější obrázek, možná si všimneš, že má trošičku „zubaté“ hrany. -To je dáno způsobem, jakým v Pygletu obrázek vykreslujeme. -Úplné vysvětlení by zabralo příliš času, proto ukážu jen řešení. -Až se naučíš grafiku víc do hloubky, pochopíš co se tu děje :) +Možná si všimneš, že obrázek má ve hře trošičku „zubaté“ hrany. +To je dáno způsobem, jakým v Pygletu vykreslujeme. +Úplné vysvětlení by se do tohoto návodu nevešlo, potřebuje trochu hlubší +znalosti počítačové grafiky. +Proto uvedu jen řešení. -Do funkce `on_draw`, hned za `clear`, dej následující dva řádky: +Do funkce `on_draw`, hned za `clear`, dej následující tři řádky: ```python # Lepší vykreslování (pro nás zatím kouzelné zaříkadlo) @@ -319,7 +318,8 @@ Obrázek se jmenuje odkud-kam.png. > [note] > Co jsou taková ta divná „hadí vajíčka”? -> To je pro přímad, že by had byl jen jedno políčko dlouhý – a tedy měl hlavu +> +> To je pro případ, že by had byl jen jedno políčko dlouhý – a tedy měl hlavu > i ocas na stejném políčku. > V naší hře se do takového stavu nedostaneme (had bude začínat s délkou 2), > ale může se stát, že se do něj dostaneš omylem při vývoji hry. @@ -372,7 +372,7 @@ právě vypsal{{a}}. Začni s prázdným slovníkem, `{}`, a v cyklu `for` do něj postupně přidávej záznamy. -Pak slovník vypiš. +Pak celý slovník vypiš. Až to budeš mít, měl by výpis vypadat asi takhle: @@ -458,9 +458,9 @@ Místo toho, aby byl všude stejný kousek hada, ale budeme chtít vybrat vždycky ten správný. Jak na to? - Podle čeho ho vybrat? +Pojďme si to vyzkoušet vedle. Vytvoř soubor `smery.py` a napiš do něj: ```python @@ -533,16 +533,15 @@ vrať se k materiálům k předchozím lekcím (hlavně k úvodu do Pythonu), zkoušej a objevuj… A časem na to přijdeš. Až se to stane, zkus své řešení co nejvíc *zjednodušit* a pak ho zakomponovat -do vykreslovací funkce. -To by už nemělo být příliš složité: +do vykreslovací funkce místo existujícího cyklu `for x, y in snake`. ```python - for ??? in ???snake???: + for ... in ...: ... - x = ??? - y = ??? - odkud = ??? - kam = ??? + x = ... + y = ... + odkud = ... + kam = ... ... snake_tiles[odkud + '-' + kam].blit( diff --git a/lessons/snake/logic/index.md b/lessons/snake/logic/index.md index 94951ad568..9a106c771e 100644 --- a/lessons/snake/logic/index.md +++ b/lessons/snake/logic/index.md @@ -1,8 +1,8 @@ # Logika hry -Už umíš vykreslit „fotku“ hada. -Hadí videohra ale nebude jen statický obrázek. -Had se bude hýbat! +Už umíš vykreslit hada ze seznamu souřadnic. +Hadí videohra ale nebude jen „fotka“. +Seznam se bude měnit a had se bude hýbat! + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + y + x + + + + + + + + + + + + + + + + + + + + diff --git a/lessons/snake/toroid/index.md b/lessons/snake/toroid/index.md new file mode 100644 index 0000000000..f0aabda06d --- /dev/null +++ b/lessons/snake/toroid/index.md @@ -0,0 +1,101 @@ +# Nekonečná klec + +Místo konce hry při naražení do zdi můžeme nechat hada „projít“ a objevit se na +druhé straně. + +Z pohledu logiky hry to není tak složité, jak to může znít. +Stačí v `move` místo ukončení hry správně nastavit příslušnou hodnotu. +Je ale potřeba si dát pozor kde použít `new_x` a kde `new_y`, kde `width` a kde +`height`, a kde přičíst nebo odečíst jedničku, aby při číslování od nuly +všechno sedělo. +Zkus to! + +{% filter solution %} +```python + # Kontrola vylezení z hrací plochy + if new_x < 0: + new_x = self.width - 1 + if new_y < 0: + new_y = self.height - 1 + if new_x >= self.width: + new_x = 0 + if new_y >= self.height: + new_y = 0 +``` +{% endfilter %} + +> [note] +> Jestli už vykresluješ hada místo housenky, možná teď narazíš na problém +> s vybíráním správných dílků – okraj herní plochy hada vizuálně rozdělí +> na dva menší. +> Zatím tenhle vizuální problém ignoruj. + + +## Zbytkové řešení + +Jde to jednodušeji? Jde! +Matematikové vymysleli operaci, která se jmenuje *zbytek po dělení*. +Ta dělá přesně to, co potřebujeme – zbytek po dělení nové souřadnice velikostí +hřiště dá souřadnici, která leží v hřišti. +Když byla předchozí souřadnice o jedna větší než maximum, +zbytek po dělení bude nula; když byla -1, dostaneme maximum. + +Python moužívá pro zbytek po dělení ooperátor `%`. Zkus si to: + +``` pycon +>>> 6 % 10 # Zbytek po dělení šesti desíti +6 +>>> 10 % 10 +0 +>>> -1 % 10 +9 +``` + +Celý kód pro kontrolu a ošetření vylézání z hrací plochy tak jde +nahradit dvěma řádky: + +```python + new_x = new_x % self.width + new_y = new_y % self.height +``` + +Podobné matematické „zkratky“ umí programátorům často usnadnit život. +Jen přijít na ně nebývá jednoduché. +Ale nevěš hlavu: neláká-li tě studovat informatiku na škole, věz, že to jde +i bez „zkratek“. Jen občas trochu krkoloměji. + +> [note] +> To, že existuje přesně operace kterou potřebujeme, není až tak úplně náhoda. +> Ona matematická jednoduchost je spíš *důvod*, proč se hrací plocha +> u spousty starých her chová právě takhle. +> Odborně se tomu „takhle“ říká +> [toroidální topologie](https://en.wikipedia.org/wiki/Torus#Topology). + +> [note] Pro matematiky +> Zkušení matematici si teď možná stěžují na nutnost definovat zbytek po +> dělení záporných čísel. Proto dodám, že ho Python schválně +> [definuje vhodně](https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations) +> pro tento účel; `a % b` má vždy stejné znaménko jako `b`. + + +{# XXX + +## Vykreslování + +> Volné chvilce se pokus problém opravit. +> Doporučuji se vrátit k „abstraktní“ funkci, která jen vypisuje souřadnice +> a směry: +> +> ``` +> 1 2 tail right +> 2 2 left right +> 3 2 left top +> 3 3 bottom top +> 3 4 bottom top +> 3 5 bottom right +> 4 5 left head +> ``` +> Jdeš-li podle návodu, tuhle funkci máš uloženou v souboru `smery.py` +> Oprav nejdřív tu, a řešení „transplantuj“ do hry. +#} + diff --git a/lessons/snake/toroid/info.yml b/lessons/snake/toroid/info.yml new file mode 100644 index 0000000000..c22d27aa61 --- /dev/null +++ b/lessons/snake/toroid/info.yml @@ -0,0 +1,4 @@ +title: Rozšíření Hada – Nekonečná klec +style: md +attribution: Pro PyLadies CZ napsal Petr Viktorin, 2018. +license: cc-by-sa-40 From a6f2cc1b4016cb85b7529b3a4da99e48e19849f1 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 31 Aug 2018 15:01:20 +0200 Subject: [PATCH 12/30] Snake: Add Pyglet fast-track, some more rewriting --- courses/snake/info.yml | 12 +- lessons/fast-track/pyglet/index.md | 297 ++++++++++++++++++ lessons/fast-track/pyglet/info.yml | 5 + lessons/snake/drawing/index.md | 27 +- .../snake/drawing/static/screenshot-dir.png | Bin 18904 -> 19255 bytes lessons/snake/logic/index.md | 105 +++---- 6 files changed, 373 insertions(+), 73 deletions(-) create mode 100644 lessons/fast-track/pyglet/index.md create mode 100644 lessons/fast-track/pyglet/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml index 44bc9ae319..6c2298074d 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -60,17 +60,17 @@ plan: - lesson: fast-track/for - title: "Doplnění: list slicing, del, n-tice, zip()" url: null - - lesson: intro/pyglet - title: Úvod do Pygletu (*) +- title: Had + slug: workshop + materials: + - title: Instalalce Pygletu + url: null + - lesson: fast-track/pyglet - lesson: snake/drawing - lesson: snake/logic - title: Zabalení spustitelného souboru (bonus) url: null - title: Rozšíření slug: extensions - date: 2018-09-01 - time: - start: '18:00' - end: '18:30' materials: - lesson: snake/toroid diff --git a/lessons/fast-track/pyglet/index.md b/lessons/fast-track/pyglet/index.md new file mode 100644 index 0000000000..e2bdce0b92 --- /dev/null +++ b/lessons/fast-track/pyglet/index.md @@ -0,0 +1,297 @@ +# Grafika + +Teď si ukážeme, jak napsat grafickou aplikaci. + +Python obsahuje nástroje na kreslení obrázků, +ale pro tvorbu her nejsou příliš vhodné. +Použijeme proto *knihovnu* (nadstavbu) jménem Pyglet, která je přímo stavěná +na interaktivní grafiku. + +Musíme si ji ale nejdřív zvlášť nainstalovat. +Nejjistější je do příkazové řádky se zapnutým virtuálním prostředím +zadat následující dva příkazy. +(Existují i jednodušší způsoby, které ovšem vyžadují „správně“ +nastavený systém.) + +* Aktualizace nástroje `pip`, který umí instalovat knihovny pro Python: + ``` console + (venv)$ python -m pip install --upgrade pip + ``` + (V překladu: **Python**e, spusť **m**odul **pip** a řekni mu, + ať na**instal**uje a kdyžtak aktualizuje (*upgrade*) knihovnu **pip**.) +* Samotné nainstalování Pygletu: + ``` console + (venv)$ python -m pip install pyglet + ``` + (V překladu: **Python**e, spusť **m**odul **pip** a řekni mu, + ať na**instal**uje knihovnu **pyglet**.) + +U mě vypadá instalace nějak takto: + +```console +(venv)$ python -m pip install --upgrade pip +Requirement already satisfied: pip in ./venv/lib/python3.6/site-packages (18.0) +(venv)$ python -m pip install pyglet +Collecting pyglet + Downloading pyglet-1.2.4-py3-none-any.whl (964kB) +Installing collected packages: pyglet +Successfully installed pyglet-1.2.4 +``` + +Důležité je `Successfully installed`, resp. `Requirement already satisfied` +na konci. +To znamená že je knihovna připravená k použití! + + +## Kostra programu + +Teď zkus v editoru vytvořit nový soubor, uložit ho jako `grafika.py` +a napsat do něj následující program: + +```python +import pyglet +window = pyglet.window.Window() +pyglet.app.run() +print('Hotovo!') +``` + +Spusť ho. Mělo by se objevit černé okýnko. + +> [note] Okýnko není černé? +> Na některých počítačích (často s macOS a některými druhy Linuxu) se stává, +> že okýnko není černé, ale je v něm nějaký „nepořádek“. +> To nevadí. +> Než do okýnka začneme kreslit, nepořádek uklidíme. + +> [note] AttributeError? +> Jestli dostaneš chybu +> `AttributeError: module 'pyglet' has no attribute 'window'`, zkontroluj si, +> zě jsi soubor pojmenoval{{a}} `grafika.py` a ne `pyglet.py`. +> Soubor v editoru„ulož jako `grafika.py`, případný soubor `pyglet.py` smaž, +> a zkus to znovu. + +Hotovo? Pojďme si vysvětlit, co se v tomhle programu děje. + +Příkaz `import pyglet` ti zpřístupní grafickou knihovnu, tak jako třeba +`import random` ti zpřístupní funkce okolo náhodných čísel. + +Zavolání `pyglet.window.Window()` vytvoří nové *okýnko* na obrazovce. +Vrátí objekt, kterým pak tohle okýnko můžeš ovládat; ten si uložíme +do proměnné `window`. + +Zavolání `pyglet.app.run()` pak spustí aplikaci. +Co to znamená? + +Jednoduché programy, které jsi zatím psal{{a}}, jsou popisy procesu – podobně +jako třeba recepty k vaření. +Sled kroků, které Python postupně vykoná od prvního po poslední. +Občas se něco opakuje a některé kroky se dají „zabalit“ do funkce, +ale vždycky jsme zatím popisovali jeden postup od začátku po konec. + +Programy pro složitější aplikace spíš než jako recept vypadají jako příručka +automechanika. +Popisují, co se má stát v jaké situaci. +Třeba program pro textový editor by mohl vypadat takhle: + +* Když uživatel zmáčkne písmenko na klávesnici, přidej ho do dokumentu. +*

Když uživatel zmáčkne ⌫ Backspace, poslední písmenko umaž.

+* Když uživatel zmáčkne tlačítko Uložit, zapiš soubor na disk. + +I takový program se dá napsat i jako „recept“ – ale ten recept je pro všechny +aplikace stejný: + +* Pořád dokola: + * Počkej, než se něco zajímavého stane + * Zareaguj na nastalou situaci + +A to je přesně to, co dělá `pyglet.app.run()`. +Zpracovává *události*, situace na které je potřeba zareagovat. +V tvém programu reaguje zavírací tlačítko okýnka a na klávesu Esc +tím, že okno zavře a ukončí se. + +Tvůj úkol teď bude popsat, jaké další události jsou zajímavé +a jak na ně reagovat. + + +## Obsluha událostí + +Nejjednodušší událost, kterou můžeme obsloužit, je psaní textu na klávesnici. + +Zkus do programu těsně nad řádek `pyglet.app.run()` dát následující kód: + +``` python +@window.event +def on_text(text): + print(text) +``` + +Co to je? +Je to definice funkce, ale na začátku má *dekorátor* – tu řádku začínající +zavináčem. + +Dekorátor `window.event` je způsob, jak Pygletu říct, že má tuto funkci +spustit, když se něco zajímavého stane. + +Co zajímavého? +To Pyglet zjistí podle jména funkce: `on_text` reaguje na text. +Vždycky, když uživatel zmáčkne klávesu, Pyglet zavolá tvoji funkci! + +A co udělá tvoje funkce? Zavolá `print`. To už znáš. +Zadaný text se vypíše na konzoli, ze které program spouštíš. +To, že je otevřené okýnko, neznamená že `print` začne automaticky psát do něj! + + +## Kreslení + +Jak psát do okýnka? +To je trochu složitější než do konzole. +Text tu může mít různé barvy, velikosti, druhy písma, +může být všelijak posunutý nebo natočený… + +Všechny tyhle *atributy* písma můžeme (i se samotným textem) uložit do objektu +`Label` („popisek“). +Zkus to – dej následující kód pod řádek s `window = `: + +```python +label = pyglet.text.Label("Ahoj!", x=10, y=20) +``` + +V proměnné `label` teď budeš mít máš popisek s textem `"Ahoj"`, který patří +na pozici (10, 20) – 10 bodů od pravého okraje okna, 20 od spodního. + +To je ale jen informace. +Podobně jako pro vypsání textu do konzole je potřeba zavolat `print`, +pro nakreslení textu je potřeba reagovat na událost +*vykreslení okna* – `on_draw`. + +Dej pod funkci `on_text` tento kód: + +```python +@window.event +def on_draw(): + window.clear() + label.draw() +``` + +Tuhle funkci Pyglet zavolá vždycky, když je potřeba nakreslit obsah okýnka. +U animací (filmů nebo her) to často bývá třeba 60× za sekundu +(„[60 FPS](https://cs.wikipedia.org/wiki/Sn%C3%ADmkov%C3%A1_frekvence)“). + +Funkce dělá dvě věci: +* Smaže celé okýnko (nabarví ho na černo) +* Vykreslí text + +V okně teď bude vidět pozdrav! + + +Zkus ještě změnit `on_text` tak, aby se zadaný text místo na konzoli +ukázal v okýnku. +To se dělá přiřazením do *atributu* `label.text`: + +```python +@window.event +def on_text(text): + print('Starý text:', label.text) + label.text = text + print('Nový text:', label.text) +``` + +Zvládneš v této funkci nový text přidat ke starému, +aby program fungoval jako jednoduchý textový editor? + +{% filter solution %} +```python +@window.event +def on_text(text): + label.text = label.text + text +``` +{% endfilter %} + + +## Další událostí + +Na jaké další události se dá reagovat? +Všechny jsou popsané v [dokumentaci Pygletu](https://pyglet.readthedocs.io/en/latest/modules/window.html#pyglet.window.Window.on_activate). +Tady uvádím pár zajímavých. + +### Stisk klávesy + +Klávesy, které nezadávají text (šipky, Backspace nebo +Enter, atp.) se dají rozpoznat v události `on_key_press`. + +Funkce `on_key_press` má dva argumenty: první je kód klávesy, +který můžeš porovnat s konstantou z [pyglet.window.key](https://pyglet.readthedocs.io/en/latest/modules/window_key.html#key-constants). +Druhý určuje stisknuté modifikátory jako Shift nebo Ctrl. + +``` python +@window.event +def on_key_press(key_code, modifier): + if key_code == pyglet.window.key.BACKSPACE: + label.text = label.text[:-1] + + if key_code == pyglet.window.key.ENTER: + print('Zadaná zpráva:', label.text) + window.close() +``` + +Na macOS budeš možná muset zaměňit `BACKSPACE` za `DELETE`. {# XXX: je to tak? #} +(Nebo si doma nastuduj [způsob](https://pyglet.readthedocs.io/en/latest/programming_guide/keyboard.html#motion-events), jak to dělat automaticky a správně.) + + +### Kliknutí myši + +Při obsluze události `on_mouse_press` dostaneš informace o pozici +kliknutí (x-ovou a x-ovou souřadnici) +a navíc informaci o stisknutém tlačítku myši a modifikátoru. + +Takhle se třeba popisek přesune na místo kliknutí: + +```python +@window.event +def on_mouse_press(x, y, button, modifier): + label.x = x + label.y = y +``` + + +## Celý program + +Pro případ, že by ses ztratil{{a}} nebo nevěděla, +kam který kousek kódu patří, uvádím výsledný ukázkový program. + +```python +import pyglet +window = pyglet.window.Window() +label = pyglet.text.Label("Ahoj!", x=10, y=20) + + +@window.event +def on_draw(): + window.clear() + label.draw() + + +@window.event +def on_text(text): + label.text = label.text + text + + +@window.event +def on_key_press(key_code, modifier): + if key_code == pyglet.window.key.BACKSPACE: + label.text = label.text[:-1] + + if key_code == pyglet.window.key.ENTER: + print('Zadaná zpráva:', label.text) + window.close() + + +@window.event +def on_mouse_press(x, y, button, modifier): + label.x = x + label.y = y + + +pyglet.app.run() +``` + diff --git a/lessons/fast-track/pyglet/info.yml b/lessons/fast-track/pyglet/info.yml new file mode 100644 index 0000000000..75daef2403 --- /dev/null +++ b/lessons/fast-track/pyglet/info.yml @@ -0,0 +1,5 @@ +title: Úvod do Pygletu +style: md +attribution: +- Pro PyLadies Brno napsal Petr Viktorin, 2015-2018. +license: cc-by-sa-40 diff --git a/lessons/snake/drawing/index.md b/lessons/snake/drawing/index.md index 7ddab81066..c399bb43a6 100644 --- a/lessons/snake/drawing/index.md +++ b/lessons/snake/drawing/index.md @@ -1,7 +1,7 @@ # Nakresli mi hada -Většina videoher má vlastní svět – spoustu čísel, textů, seznamů a jiných -datových objektů, které popisují všechno, co ve hře je – celý *stav* hry. +Většina videoher má celý herní svět uložený jako spoustu čísel, textů, seznamů +a jiných datových objektů, které popisují všechno, co ve hře je. Tenhle stav se časem mění, ať už automaticky nebo podle akcí hráče. A docela často – většinou zhruba šedesátkrát za vteřinu – se stav hry převede na obrázek, který se hráčovi ukáže. @@ -98,7 +98,7 @@ se souřadnicemi (10, 20). ## Sázení čtverečku Na to, abychom hada vykreslili, použijeme okýnko z Pygletu. -Tady je základní kostra programu Pyglet, které už bys měl{{a}} rozumět. +Tady je základní kostra Pygletí aplikace, které už bys měl{{a}} rozumět: ```python import pyglet @@ -112,8 +112,8 @@ def on_draw(): pyglet.app.run() ``` -Udělej si nový, prázdný adresář na hadí hru, a kostru si -zkopíruj do souboru `had.py`. +V editoru si otevři nový soubor, ulož ho jako `had.py` a kostru programu +do něj zkopíruj. Budeme ji dál rozvíjet. @@ -142,8 +142,8 @@ Budeme radši používat čtverečky větší, řekněme 64 pixelů. To číslo je „střelené od boku“. V programu ho použijeme několikrát, a možná ho později budeš chtít upravit. -Uložíme si ho proto do *konstanty* – proměnné, kterou nebudeme měnit. -Konstanty se tradičně pojmenovávají velkými písmeny, a píšou se hned za řádek +Uložíme si ho proto do *konstanty* (proměnné, kterou nebudeme měnit). +Konstanty se tradičně pojmenovávají velkými písmeny a píšou se hned za řádek `import` (i když to není technicky nutné). Přidej tedy za `import` řádek: @@ -281,7 +281,6 @@ To je dáno způsobem, jakým v Pygletu vykreslujeme. Úplné vysvětlení by se do tohoto návodu nevešlo, potřebuje trochu hlubší znalosti počítačové grafiky. Proto uvedu jen řešení. - Do funkce `on_draw`, hned za `clear`, dej následující tři řádky: ```python @@ -321,9 +320,8 @@ Obrázek se jmenuje odkud-kam.png. > > To je pro případ, že by had byl jen jedno políčko dlouhý – a tedy měl hlavu > i ocas na stejném políčku. -> V naší hře se do takového stavu nedostaneme (had bude začínat s délkou 2), -> ale může se stát, že se do něj dostaneš omylem při vývoji hry. -> Když jsou obrázky k dispozici, lépe pak zjišťuješ, co je špatně. +> V dodělané hře se do takového stavu nedostaneme (had bude začínat s délkou 2), +> ale než hru dokončíme, budou tyhle obrázky užitečné. Pojďme si teď tyhle obrázky *načíst*. Šlo by to dělat postupně, třeba takhle: @@ -341,7 +339,7 @@ na některý zapomněl{{a}}. Proto Pythonu řekneme, aby nám dal všechny soubory s koncovkou `.png` v daném adresáři. Na to se dá použít třída `Path` z modulu [`pathlib`](https://docs.python.org/3/library/pathlib.html). -Zkus si napsat (do nového souboru, třeba `experiment.py`) tento kód +Zkus si do nového souboru, třeba `experiment.py`, napsat následující kód a spustit ho. Dokážeš vysvětlit, co dělá? @@ -406,8 +404,9 @@ print(snake_tiles) A teď zkus načtení obrázků začlenit do programu s hadem! Všechny importy patří nahoru, konstanty pod ně, a dál pak zbytek kódu. -Vypisovat načtený slovník ve hře nemusíš, zato místo `green_image` -pak ve vykreslovací funkci použij třeba `snake_tiles['tail-head']`. +Vypisovat načtený slovník ve hře nemusíš. +Zato ve vykreslovací funkci použij místo `green_image` +třeba `snake_tiles['tail-head']`. Místo čtverečků se teď objeví kuličky – místo hada budeš mít „housenku“. diff --git a/lessons/snake/drawing/static/screenshot-dir.png b/lessons/snake/drawing/static/screenshot-dir.png index 62382a32847242d7246e004f8bd68c0de4054951..ca4f16946453039ca9965040e4f48a3825b97014 100644 GIT binary patch literal 19255 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 diff --git a/lessons/snake/logic/index.md b/lessons/snake/logic/index.md index 9a106c771e..f450377353 100644 --- a/lessons/snake/logic/index.md +++ b/lessons/snake/logic/index.md @@ -51,7 +51,7 @@ pyglet.app.run() ``` Zkus těsně nad řádek `pyglet.app.run` doplnit funkci, -která se bude volat každou šestinu vteřiny, +která se bude volat každou šestinu vteřiny a přidá hadovi políčko navíc: ``` python @@ -78,27 +78,33 @@ Zvývá směr hada ovládat šipkami na klávesnici, a většina hry bude hotov ## Ven se stavem Než uděláme interaktivního hada, zkusíme trošku uklidit. -Program se nám rozrůstá, a za chvíli bude složité se v něm vyznat. +Program se nám rozrůstá a za chvíli bude složité se v něm vyznat. Stav hry máme zatím ve dvou seznamech: `snake` a `food`. Časem ale bude podobných proměnných víc. -Abychom je měli všechny pohromadě, vytvoříme pro stav *třídu* – typ objektu, -který obsahuje celý stav hry. - -Všechno, co je potřeba o hře vědět – v našem případně zatím souřadnice hada -a jídla – bude tato třída obsahovat jako *atributy*. +Abychom je měli všechny pohromadě, vytvoříme pro stav *třídu*. {# XXX: More about classes #} -Třída bude obsahovat dvě *metody* – funkce, které se dají zavolat na objekty -této třídy. -Speciální metoda `__init__` (která se automaticky volá při vytvoření objektu -této třídy) bude tyto atributy nastavovat. -Metoda `move`, kterou budeme volat při každém „tahu“ hry, je pak bude -měnit. +Na všechno, co se ve hře může stát, nadefinujeme *metody*. +Zatím budou dvě: začátek hry a pohyb hada. + +Na začátku hry se zavolá metoda `__init__`. +Má trochu divné jméno se dvěma podtržítkama na každé straně. +Podle toho Python ví, že tahle metoda je speciální a se má volat +při vytvoření objektu. + +Metoda `__init__` nastaví celý stav hry jako *atributy*. +Stav hry je všechno, co potřebujeme o hře vědět a může se to časem měnit. +V našem případě to zatím budou souřadnice hada a jídla. + +Metoda `move`, kterou budeme volat při každém „tahu“ hry, je bude tyhle +atributy měnit. -Pro funkčnost, kterou zatím náš had umí, bude `had.py` vypadat takto: +Pro funkčnost, kterou zatím náš had umí, bude třída se stavem vypadat +následovně. +Přidej ji do programu hned za nastavení konstant. ```python class State: @@ -115,17 +121,15 @@ class State: del self.snake[0] ``` -Definici třídy dej hned za nastavení konstant. - > [note] > Použij prosím pro třídu jméno `State` a i atributy pojmenuj podle -> materiálů – `snake`, `food`, a později i další, které budeme přidávat. +> materiálů (`snake`, `food`, a později i další). > Bude se ti to hodit. Všimni si, že metody berou argument `self`. To označuje konkrétní objekt, stav hry se kterým metoda pracuje nebo který mění. -Ke všem atributúm přistupují pomocí tečky – +Ke všem atributům přistupují pomocí tečky – self.jméno_atributu. Tak, máme třídu se stavem. @@ -143,8 +147,9 @@ Na to potřebuješ ještě několik změn: * Místo `snake` a `food` ve funkci `on_draw` použij `state.snake` a `state.food` – atributy našeho stavu. - Všimni si že tady nepoužíváme `self` – tohle jméno je pro *metody* v rámci - třídy. Jinde musíme pojmenovat konkrétní objekt, se kterým pracujeme. + Všimni si že tady nepoužíváme `self`, což je jméno které používají jen + *metody* v rámci třídy. + Jinde musíme pojmenovat konkrétní objekt, se kterým pracujeme. * Funkci `move` přepiš tak, aby jen volala metodu `state.move`: @@ -154,7 +159,6 @@ Na to potřebuješ ještě několik změn: ``` Všimni si že ani tady nepoužíváme `self`. - Ten se doplní automaticky – jde o objekt, jehož metodu voláme. Povedlo se? Funguje to jako předtím? Pro kontrolu můžeš svůj program porovnat s mým (ale nejde o jediné správné @@ -221,7 +225,7 @@ Nyní k onomu slíbenému ovládání. Respektive nejdřív k změnám směru. Had ze hry se plazí stále stejným směrem, dokud hráč nezmáckne klávesu. Had z naší ukázky se plazí doprava. -Jestli jsi to ještě udělala{{a}}, zkus zařídit, aby se místo toho +Jestli jsi to ještě neudělal{{a}}, zkus zařídit, aby se místo toho plazil nahoru. {% filter solution %} @@ -286,18 +290,17 @@ To už je doména Pygletu. Je potřeba přidat funkci, která reaguje na stisk klávesy. Aby Pyglet tuhle funkci našel a uměl zavolat, musí se jmenovat `on_key_press`, -musí mít dekorátor `@window.event`, a musí brát dva argumenty: +musí mít dekorátor `@window.event`, a musí brát dva parametry: číslo klávesy, která byla zmáčknutá a informace o modifikátorech jako Shift nebo Ctrl: ```python @window.event -def on_key_press(key_number, modifier): +def on_key_press(key_code, modifier): ... ``` -Druhý argument nebude potřeba, ale musí v hlavičce funkce být: Pyglet použije -dva argumenty. +Druhý parametr nebude potřeba, ale musí v hlavičce funkce být. Podle prvního ale nastav aktuální směr hada. Čísla kláves jsou definována v modulu `pyglet.window.key` jako konstanty se @@ -306,14 +309,14 @@ My použijeme šipky – `LEFT`, `RIGHT`, `UP ` a `DOWN`: ```python @window.event -def on_key_press(key_number, modifier): - if key_number == pyglet.window.key.LEFT: +def on_key_press(key_code, modifier): + if key_code == pyglet.window.key.LEFT: state.snake_direction = -1, 0 - if key_number == pyglet.window.key.RIGHT: + if key_code == pyglet.window.key.RIGHT: state.snake_direction = 1, 0 - if key_number == pyglet.window.key.DOWN: + if key_code == pyglet.window.key.DOWN: state.snake_direction = 0, -1 - if key_number == pyglet.window.key.UP: + if key_code == pyglet.window.key.UP: state.snake_direction = 0, 1 ``` @@ -340,11 +343,8 @@ Pojďme je vyřešit, jednu po druhé. „Hadí“ hry jako ta naše mají dvě varianty: buď je kolem hřiště „zeď“ a hráč při nárazu do okraje prohraje, nebo je hřiště „nekonečné“ – had okrajem proleze a objeví se na druhé straně. - My naprogramujeme tu první variantu – zeď. -Budeme pracovat na chování, na logice hry; ne na vykreslování a ovládání. - Abys zjistil{{a}}, jestli had „vylezl“ z levého okraje okna ven, je potřeba zkontrolovat, jestli x-ová souřadnice hlavy je menší než 0. @@ -380,7 +380,7 @@ Věřím, že zvládneš udělat stejnou kontrolu pro vylezení ze spodního okr Jak ale ošetřit ty zbylé okraje – pravý a horní? Na to je potřeba znát velikost okýnka. -A tu zná Pyglet; třída se stavem k okýnku nemá přístup! +A tu zná Pyglet; třída se stavem by k okýnku neměla mít přístup! Na velikosti herní plochy závisí chování hry. Tahle informace tedy bude tedy muset být součást stavu. @@ -420,10 +420,9 @@ Had je virtuální, nemusíš se bát že mu z toho vyroste boule. ``` {% endfilter %} -A pak nastav *opravdovou* velikost herní plochy. Jak? -V souboru se hrou (`ui.py`), hned po tom co vytvoříš stav (`state`) -a okýnko (`window`) velikost nastav. -Použij celočíselné dělení (se zbytkem), aby velikost byla v celých číslech: +A pak v souboru se hrou hned po tom co vytvoříš stav (`state = State()`) +a okýnko (`window`) nastav *opravdovou* velikost. +Použij celočíselné dělení, aby počet políček byl v celých číslech: ```python state.width = window.width // TILE_SIZE @@ -638,7 +637,7 @@ Zaříďme teď, aby hra skončila i když narazí sám do sebe. Jak na to? Do metody `move`, vedle kontrola vylezení z hrací plochy, -dej kód který zařídí následující: +dej kód který udělá následující: * Pokud jsou souřadnice nové hlavy už součást hada: * Ukonči hru (podobně jako po nárazu do stěny). @@ -698,7 +697,7 @@ kousky kódu, které prohru implementují: * „Zastaveni hada“ místo všech výskytů `raise("Game Over")`. * „Zabránění pohybu“ na úplný začátek metody `move` (příkaz `return` okamžitě ukončí provádění metody). -* „Grafická indikace“ do `ui.py`, za sekci pro vybírání obrázku pro kousek +* „Grafická indikace“ za sekci pro vybírání obrázku pro kousek hada. {% endfilter %} @@ -730,7 +729,7 @@ Přidej si na to do stavu hry seznam (v metodě `__init__`): self.queued_directions = [] ``` -Tuhle frontu plň v `ui.py` po každém stisku klávesy, metodou `append`. +Tuhle frontu plň po každém stisku klávesy, metodou `append`. Je potřeba změnit většinu funkce `on_key_press` – místo změny atributu se nový směr přidá do seznamu. Abys nemusel{{a}} psát čtyřikrát `append`, @@ -738,14 +737,14 @@ můžeš uložit nový směr do pomocné proměnné: ```python @window.event -def on_key_press(key_number, modifier): - if key_number == pyglet.window.key.LEFT: +def on_key_press(key_code, modifier): + if key_code == pyglet.window.key.LEFT: new_direction = -1, 0 - if key_number == pyglet.window.key.RIGHT: + if key_code == pyglet.window.key.RIGHT: new_direction = 1, 0 - if key_number == pyglet.window.key.DOWN: + if key_code == pyglet.window.key.DOWN: new_direction = 0, -1 - if key_number == pyglet.window.key.UP: + if key_code == pyglet.window.key.UP: new_direction = 0, 1 state.queued_directions.append(new_direction) ``` @@ -908,14 +907,14 @@ def on_draw(): @window.event -def on_key_press(key_number, modifier): - if key_number == pyglet.window.key.LEFT: +def on_key_press(key_code, modifier): + if key_code == pyglet.window.key.LEFT: new_direction = -1, 0 - if key_number == pyglet.window.key.RIGHT: + if key_code == pyglet.window.key.RIGHT: new_direction = 1, 0 - if key_number == pyglet.window.key.DOWN: + if key_code == pyglet.window.key.DOWN: new_direction = 0, -1 - if key_number == pyglet.window.key.UP: + if key_code == pyglet.window.key.UP: new_direction = 0, 1 state.queued_directions.append(new_direction) @@ -939,7 +938,7 @@ Zkus třeba následující rozšíření: takže jich pak bude na hrací ploše víc. * Hra se bude postupně zrychlovat.
- *(Na to je nejlepší předělat funkci `move` v `ui.py`, aby *sama* + *(Na to je nejlepší předělat funkci `move`, aby *sama* naplánovala, kdy se má příště zavolat. Volání `schedule_interval` tak už nebude potřeba.)* From 3a2758c2ad3b30ae88138f72dbc16cd9040ae83c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 31 Aug 2018 18:26:32 +0200 Subject: [PATCH 13/30] Refine the intro to Python --- lessons/fast-track/bool/index.md | 71 ++- lessons/fast-track/def/index.md | 18 +- lessons/fast-track/dict/index.md | 20 +- lessons/fast-track/for/index.md | 22 +- lessons/fast-track/if/index.md | 14 +- lessons/fast-track/list/index.md | 115 ++++- lessons/fast-track/repl/index.md | 53 +- lessons/fast-track/script/index.md | 88 ++-- lessons/fast-track/str/index.md | 95 ++-- lessons/fast-track/str/static/quote-comic.svg | 466 ++++++++++++++++++ lessons/fast-track/variables/index.md | 46 +- lessons/snake/drawing/index.md | 2 +- 12 files changed, 848 insertions(+), 162 deletions(-) create mode 100644 lessons/fast-track/str/static/quote-comic.svg diff --git a/lessons/fast-track/bool/index.md b/lessons/fast-track/bool/index.md index 855775aa96..7abc6edf06 100644 --- a/lessons/fast-track/bool/index.md +++ b/lessons/fast-track/bool/index.md @@ -21,19 +21,22 @@ Funguje to i se složitějšími výrazy: True ``` -„Větší než“ a „menší než“ používají značky známé z matematiky. -Chceš-li se ale zeptat, jestli jsou dvě čísla stejná, je to trochu jiné: +„Větší než“ a „menší než“ jsou značky známé z matematiky. +Chceš-li se ale zeptat, jestli jsou dvě čísla stejná, je potřba použít +trochu jiný zápis: ``` pycon >>> 1 == 1 True ``` -Jedno rovnítko `=` používáme pro přiřazení hodnoty do proměnné. -Když chceš zkontrolovat, jestli se věci navzájem rovnají, vždy, **vždy** musíš dát dvě rovnítka `==`. +Jedno rovnítko `=` používáme pro *přiřazení* hodnoty do proměnné. +Když chceš zkontrolovat, jestli se věci navzájem *rovnají*, vždy, **vždy** +musíš dát dvě rovnítka `==`. -Další možnosti porovnávání jsou nerovnost (≠), větší než (≤) a meší než (≥). -Většina lidí tyhle symboly nemá na klávesnici, a tak se používá `!=`, `<=` +Další možnosti porovnávání jsou nerovnost (≠), větší nebo rovno (≤) +a meší nebo rovno (≥). +Většina lidí tyhle symboly nemá na klávesnici, a tak Python používá `!=`, `<=` a `>=`. ``` pycon @@ -45,9 +48,35 @@ False True ``` +Už jsi někdy slyšel{{a}} výraz „srovnávat jablka a hrušky“? Zkusme v Pythonu ekvivalent: + +``` pycon +>>> 1 > 'krajta' +Traceback (most recent call last): + File "", line 1, in +TypeError: '>' not supported between instances of 'int' and 'str' +``` + +Stejně jako nelze srovnávat „jablka a hrušky“, +Python není schopen porovnávat řetězce (`str`) a čísla (`int`). +Místo toho zobrazí `TypeError` a říká nám, že tyto dva typy nelze porovnat. + +Co se stane, když v minulé ukázce zaměníš `>` za `==`? + +{% filter solution %} +```pycon +>>> 1 == 'krajta' +False +``` + +Jablka a hrušky nemůžeš porovnávat, ale můžeš si potvrdit že jsou to dvě různé +věci. +{% endfilter %} + + ## Logika -Chceš zkusit ještě něco? Zkus tohle: +Chceš zkusit ještě něco? Zadej tohle: ``` pycon >>> 6 > 2 and 2 < 3 @@ -63,24 +92,12 @@ V Pythonu můžeš zkombinovat několik porovnání do jednoho! * Pokud použiješ operátor `and`, obě strany musí být pravdivé, aby byl celý výraz pravdivý. * Pokud použiješ operátor `or`, stačí aby jen jedna strana z porovnání byla pravdivá. -Už jsi někdy slyšel{{a}} výraz „srovnávat jablka a hrušky“? Zkusme v Pythonu ekvivalent: - -``` pycon ->>> 1 > 'krajta' -Traceback (most recent call last): - File "", line 1, in -TypeError: '>' not supported between instances of 'int' and 'str' -``` - -Stejně jako nelze srovnávat „jablka a hrušky“, -Python není schopen porovnávat řetězce (`str`) a čísla (`int`). -Místo toho zobrazí `TypeError` a říká nám, že tyto dva typy nelze porovnat. - ## Pravdivostní hodnoty Mimochodem, právě ses dozvěděl{{a}} o novém typu objektu v Pythonu. -Říká se mu *pravdivostní hodnota*, nebo častěji anglicky *boolean*. +Podobně jako máme řetězec, číslo, seznam nebo slovník existuje +*pravdivostní hodnota*, nebo častěji anglicky *boolean*. Může mít jednu z dvou hodnot: `True` a `False`. @@ -88,7 +105,7 @@ Aby Python pochopil, že se jedná o tento typ, je potřeba dávat pozor na velikost písmen. `true`, `TRUE`, `tRUE` nebude fungovat – jedině `True` je správně. -Jako každou hodnotu, i pravdivostní hodnotu můžeš uložit do proměnné: +Jako každou hodnotu, i *boolean* můžeš uložit do proměnné: ``` pycon >>> a = True @@ -103,3 +120,13 @@ Stejně tak můžeš uložit i výsledek porovnání: >>> a False ``` + + +## Shrnutí + +V této sekci ses dozvěděl{{a}}: + +* V Pythonu můžeš **porovnávat** pomocí operátorů `>`, `>=`, `==` `<=`, `<`, `!=` +* Operátory `and` a `or` umí **zkombinovat** dvě porovnání. +* **Boolean** (pravdivostní hodnota) je typ, který může mít jednu ze dvou + hodnot: `True` (pravda) nebo `False` (nepravda). diff --git a/lessons/fast-track/def/index.md b/lessons/fast-track/def/index.md index 2616dc51ea..0fa0d083a7 100644 --- a/lessons/fast-track/def/index.md +++ b/lessons/fast-track/def/index.md @@ -13,8 +13,8 @@ Třeba funkce, která tě pozdraví, by měla: * Vypsat „jak se máš?“ Definice funkce v Pythonu začíná klíčovým slovem `def`, -dále je uveden název a závorky (zatím prázdné). -Pak jako po `if` dvojtečka, a odsazené příkazy, +dále je uveden název a následují závorky (zatím prázdné). +Pak je jako po `if` dvojtečka – a odsazené příkazy, které má funkce provést. ```python @@ -73,16 +73,18 @@ NameError: name 'pozdrav' is not defined Python si stěžuje na `NameError` – nezná nic jménem `pozdrav`. Python totiž program čte odzhora dolů. -Až příkazem `def` se „naučí" jak zdravit – +Až příkazem `def` se „naučí" jak zdravit. Předtím, než se k příkazu `def` dostane, funkce neexistuje. {% endfilter %} ## Parametry +Tvoje funkce se dá volat jen jako `pozdrav()`. Funkce jako `len('slovo')` a `print(1 + 2)` umí navíc pracovat s hodnotou. -Pojďme napisať funkciu, ktorá ťa pozdraví menom. +Poďme napisať funkciu, ktorá ťa pozdraví menom. (Uľahčíme si to použitím jazyka, ktorý nepoužíva piaty pád.) +{# XXX: Je to správně slovensky? #} ```python def pozdrav(meno): @@ -138,3 +140,11 @@ pozdrav('Ola') pozdrav('Soňa') ``` + +## Shrnutí + +Co bylo nového tentokrát? + +* **Funkce** umožňuje pojmenovat nějkolik příkazů, a pak je zavolat najednou. +* **Parametry** funkce, hodnoty se kterými funkce pracuje, + se zadávají v závorkách. diff --git a/lessons/fast-track/dict/index.md b/lessons/fast-track/dict/index.md index de756eadee..949b107b0a 100644 --- a/lessons/fast-track/dict/index.md +++ b/lessons/fast-track/dict/index.md @@ -25,9 +25,9 @@ Klíč a hodnota jsou oddělené dvojtečkou, jednotlivé dvojice se od sebe oddělují čárkou, a celý slovník je uzavřený ve složených závorkách. -Když budeš chtít v takovém slovníku něco najít, potřebuješ vědět, co hledat. -Konkrétně *klíč*. -Pomocí hranatých závorek můžeš zjistit hodnotu, která odpovídá danému klíči: +Když budeš chtít v takovém slovníku něco najít, potřebuješ vědět co hledat. +Potřebuješ *klíč*. +Pomocí hranatých závorek můžeš zjistit hodnotu, která danému klíči odpovídá: ``` pycon @@ -35,9 +35,8 @@ Pomocí hranatých závorek můžeš zjistit hodnotu, která odpovídá danému 'Apple' ``` -Je to podobné jako u seznamů, jen v hranatých závorkách není pořadí prvku, -ale klíč. -{# XXX: Slicing taky nejde #} +Je to podobné jako u seznamů, jen v hranatých závorkách není index +(pořadí prvku) nebo rozmezí s dvojtečkou, ale klíč. > [note] > Naopak to nejde – slovník neumožňuje podle hodnoty přímo zjistit klíč. @@ -135,11 +134,10 @@ Verča se přestěhovala do zahraničí a má nové číslo: `+897 3788509`. ## Shrnutí -Skvělé! Nyní víš o programování hodně. V této poslední části jsi poznal{{a}}: +Skvělé! Co víš o slovnících: -* **chyby** - hlášky které Python zobrazí když nerozumí příkazu který jsi zadal{{a}} nebo ho neumí splnit -* **proměnné** - názvy pro objekty, které umožňují psát čitelnější kód -* **seznam** - sekvence objektů uložených v určitém pořadí -* **slovník** - sbírka záznamů klíč–hodnota +* **Záznam** se skládá z **klíče** a **hodnoty**. +* Ve slovníku se hledá pomocí **klíče**. +* Záznamy se dají přepsat, přidat, nebo pomocí `del` smazat. Jsi připraven{{a}} na další část? diff --git a/lessons/fast-track/for/index.md b/lessons/fast-track/for/index.md index 50d5c947d4..bca63c175d 100644 --- a/lessons/fast-track/for/index.md +++ b/lessons/fast-track/for/index.md @@ -4,7 +4,7 @@ Programátoři se neradi opakují. Programování je o automatizaci: nebudeme zdravit každého člověka zvlášť, vezměme seznam padesáti lidí a pozdravíme je všechny najednou! -(Hm, někteří programátoři nejsou moc sociálně nadaní. +(No, někteří programátoři asi nejsou moc sociálně nadaní. Ale jinde se ta automatizace fakt hodí!) Ještě si vzpomínáš na seznamy? @@ -63,14 +63,15 @@ Když chceš něco 200-krát zopakovat, napiš: ```python for i in range(200): - print("Nebudu házet igelit do táboráku!") + print("Nebudu nikdy házet igelit do táboráku!") ``` Jak to funguje? `for i in range(X)` se dá přeložit jako „pro každé číslo od nuly do X“. -Do proměnné `i` Python uloží, pokolikáté cyklem prochází – počínaje, -v programátorském stylu, od nuly: +Funkce `range` onu posloupnost čísel od nuly do X vytvoří. +Do proměnné `i` Python postupně uloží každé číslo, podle toho po kolikáté +cyklem prochází. ```python for i in range(5): @@ -84,25 +85,24 @@ for i in range(5): 4 ``` -`range` je funkce, která vytvoří seznam s posloupností čísel (tato čísla zadáváš jako parametry funkce). +Všimni si, že samotné `5` není zahrnuto ve výsledku: +`range(5)` počítá od 0 do 4. +Když počítáš od nuly a chceš pět čísel, skončíš u čtyřky. -Všimni si, že druhé z těchto dvou čísel není zahrnuto v seznamu, který je výstupem Pythonu (`range (1, 6)` počítá od 1 do 5, ale nezahrnuje číslo 6). To je proto, že "range" je z poloviny otevřený, čímž myslíme, že obsahuje první hodnotu, ale ne poslední. ## Shrnutí A je to. *Jsi naprosto skvěl{{gnd('ý', 'á')}}!* -Tohle byla složitá kapitola, takže bys na sebe měl{{a}} být hrd{{gnd('ý', 'á')}}. +Tohle byla složitá lekce, takže bys na sebe měl{{a}} být hrd{{gnd('ý', 'á')}}. My jsme na tebe velmi hrdí za to, že ses dostal{{a}} tak daleko! Naučil{{a}} ses: -* **Definice funkcí** – jak pojmenovat pár příkazů -* **Cykly** – jak opakovat nějaký postup několikrát po sobě +* **Cyklus** je způsob, jak opakovat nějaký postup několikrát po sobě +* `range` pomáhá když potřebuješ určitý konkrétní počet opakování. Můžeš si jít krátce odpočinout – protáhnout se, projít se, zavřít oči – než se pustíme do další kapitoly. :) 🧁 - - {# XXX: range #} diff --git a/lessons/fast-track/if/index.md b/lessons/fast-track/if/index.md index bcb6498d8e..8f0703c626 100644 --- a/lessons/fast-track/if/index.md +++ b/lessons/fast-track/if/index.md @@ -58,7 +58,7 @@ Ještě lepší program by ale: * Zeptá se na tajné heslo * Když je heslo správné: * Pustí uživatele dovnitř -* Jinak: +* Jinak (tedy pokud heslo nebylo správné): * Spustí alarm K tomu má Python příkaz `else` – „jinak“: @@ -126,11 +126,9 @@ příslušnou hlášku a další možnosti přeskočí. ## Shrnutí -V posledních třech cvičeních ses dozvěděl{{a}} o: - -* **Porovnání věcí** - v Pythonu můžeš porovnávat věci pomocí operátorů `>`, `>=`, `==` `<=`, `<`, `!=` a `and`, `or` -* **Pravdivostní hodnoty / Boolean** - typ, který může mít pouze jednu ze dvou hodnot: `True` nebo `False` -* **Ukládání do souborů** - pokud uložíš kód do souboru, můžeš spouštět větší programy -* **if – elif – else** - příkazy, které umožňují spouštět kód pouze v případě, kdy jsou splněny určité podmínky. +Co jsi viděl{{a}} v této lekci? -Čas na předposlední část této kapitoly! +* Příkazy **if** (pokud), **elif** (jinak, pokud) a **else** (jinak) + podmiňují jiné příkazy. +* **Odsazení** se používá pro podmíněné příkazy, které následují po + `if` apod.. diff --git a/lessons/fast-track/list/index.md b/lessons/fast-track/list/index.md index 4c3e04c497..e7c9449752 100644 --- a/lessons/fast-track/list/index.md +++ b/lessons/fast-track/list/index.md @@ -63,7 +63,23 @@ Vyzkoušej si ji! [59, 42, 30, 19, 12, 3] ``` -Pokud chceš do svého něco přidat seznamu, můžeš to provést pomocí metody +## Přidávání do seznamu + +Podobně jako u řetězců se seznamu dají spojovat pomocí `+`: + +``` pycon +>>> loterie + [5, 6, 7, 8] +[59, 42, 30, 19, 12, 3, 5, 6, 7, 8] +``` + +Tím se vytvoří nový seznam, ten původní zůstává nezměněný: + +``` pycon +>>> loterie +[59, 42, 30, 19, 12, 3] +``` + +Pokud chceš něco přidat do původního seznamu, můžeš to provést pomocí metody `append`. Ale pozor! Tahle metoda potřebuje vědět co má do seznamu přidat Nová hodnota se zadává do závorek: @@ -177,9 +193,6 @@ IndexError: list index out of range Stý prvek od konce v seznamu není. Nastane chyba. {% endfilter %} -## Řezání - -XXX Slicing ## Odstraňování @@ -222,3 +235,97 @@ Zkus si nejdřív vypsat, které to jsou, a pak teprve použít `del`. [42, 3] ``` {% endfilter %} + +Občase se stane, že nechceš smazat prvek podle pozice, ale podle toho, +co v seznamu je. +K tomu slouží hodnota `remove`, která najde a odstraní danou hodnotu: + +```pycon +>>> loterie +[42, 3] +>>> loterie.remove(3) +>>> loterie +[42] +``` + + +## Řezání + +Ze seznamu se dá kromě jednoho prvku vybrat i prvků několik – část seznamu, +takzvaný *podseznam*. + +Pojďme si opět udělat delší seznam čísel: + +``` pycon +>>> cisla = ["První", "Druhý", "Třetí", "Čtvrtý"] +``` + +Budeš-li chtít vybrat prvky od druhého dál, dej do hranatých závorek číslo +tohohle prvku, a za něj dvojtečku. + +``` pycon +>>> cisla[1] +'Druhý' +>>> cisla[1:] +['Druhý', 'Třetí"', 'Čtvrtý'] +``` + +Vybráním podseznamu se seznam nemění, tak můžeš vybírat dál: + +```pycon +>>> cisla +['První', 'Druhý', 'Třetí', 'Čtvrtý'] +>>> cisla[1:] +['Druhý', 'Třetí"', 'Čtvrtý'] +>>> cisla[2:] +['Třetí', 'Čtvrtý'] +>>> cisla[3:] +['Čtvrtý'] +>>> cisla[4:] +[] +``` + +Budeš-li chtít vybrat prvky od začátku *do* některého prvku, dej dvojtečku +*před* číslo prvku, který už ve výsledku nechceš + + +``` pycon +>>> cisla[2] +'Třetí' +>>> cisla[:2] +['První', 'Druhý'] +``` + +Úkol: máš-li nějaký seznam, jak z něj vybereš všechny prvky kromě posledního? + +{% filter solution %} +Poslední číslo má index -1, vyberu tedy prvky do -1: + +``` pycon +>>> cisla[:-1] +['První', 'Druhý', 'Třetí'] +``` + +{% endfilter %} + +Začátek a konec se dá kombinovat – číslo můžeš dát před i za dvojtečku: + +```pycon +>>> cisla +['První', 'Druhý', 'Třetí', 'Čtvrtý'] +>>> cisla[1:-1] +['Druhý', 'Třetí'] +``` + +## Shrnutí + +Uf! O seznamech toho bylo k naučení celkem hodně. Shrňme si, co už umíš: + +* **Seznam** je seřazená sekvence hodnot. +* Pomocí **metod** se seznam dá řadit (`sort`) a obrátit (`reverse`), + nebo se do něj dá přidat (`append`) či odebrat (`remove`) prvek. +* Prvky se dají **vybrat** nebo **odstranit** (`del`) podle indexu. +* Číslování začíná **od nuly**, záporná čísla berou prvky od konce. +* **Podseznam** je určitá část seznamu. + +Jsi připraven{{a}} na další část? diff --git a/lessons/fast-track/repl/index.md b/lessons/fast-track/repl/index.md index 3f92c2f963..9d821f200e 100644 --- a/lessons/fast-track/repl/index.md +++ b/lessons/fast-track/repl/index.md @@ -5,7 +5,7 @@ Chceš-li si začít hrát s Pythonem, otevři *příkazový řádek* a aktivuj Je-li tomu tak, nezbývá než – konečně – pustit Python. K tomu použij příkaz `python`: ``` console -$ python3 +$ python Python 3.6.6 (...) Type "help", "copyright", "credits" or "license" for more information. >>> @@ -31,26 +31,43 @@ Zkusíš i odečítání? A jak je to s násobením? {# XXX: Jak zapsat násobení? `4 x 5` `4 . 5` `4 × 5` `4 * 5` -#} Na kalkulačce bys zadala `4 × 5`, což se na klávesnici píše špatně. -Python proto používá symbol `*` a pro dělení `/`. -Tyhle symboly se odborně nazývají *operátory*. +Python proto používá symbol `*`. ``` pycon >>> 4 * 5 20 +``` + +Symboly jako `+` a `*` se odborně nazývají *operátory*. + +Operátor pro dělení je `/`. + +Při dělení může vzniknout necelé číslo, třeba dva a půl. +Python používá desetinnou *tečku*, ukáže se tedy `2.5`: + +``` python >>> 5 / 2 2.5 ``` -> [note] -> V tomto úvodu budeme zadávat jen celá čísla. -> Dělením ale může vzniknout třeba dva a půl -> (tedy `2.5` – Python používá desetinnou *tečku*). -> Z důvodů, do kterých teď nebudeme zabíhat, se desetinné pozice po dělení -> objeví i když vyjde celé číslo: -> ``` pycon -> >>> 4 / 2 -> 2.0 -> ``` +Z důvodů, do kterých teď nebudeme zabíhat, se při dělení desetinná tečka +objeví i když vyjde číslo celé: +``` pycon +>>> 4 / 2 +2.0 +``` + +Občas se hodí použít dělení se zbytkem. +Výsledek tak zůstane jako celé číslo. +Na to má Python operátory `//` (podíl) a `%` (zbytek): + +``` pycon +>>> 5 // 2 +2 +>>> 5 % 2 +1 +``` + {# XXX: Kolik je @@ -63,3 +80,13 @@ Kolik je > Je ale zvykem psát kolem operátoru jednu mezeru z každé strany – tak jako > v těchto materiálech. > Kód je pak čitelnější. + + +### Shrnutí + +Co ses zatím naučil{{a}}? + +* **Interaktivní režim Pythonu** umožňuje zadávat příkazy (kód) pro + Python a zobrazuje výsledky/odpovědi. +* **Čísla** se používají na matematiku a práci s textem. +* **Operátor** jako `+` a `*` kombinuje hodnoty a vytvoří výsledek. diff --git a/lessons/fast-track/script/index.md b/lessons/fast-track/script/index.md index c480a740b7..1084baa05e 100644 --- a/lessons/fast-track/script/index.md +++ b/lessons/fast-track/script/index.md @@ -3,7 +3,7 @@ Zatím jsi psal{{a}} všechny programy v konzoli v interaktivním režimu Pythonu, který nás omezuje na jeden řádek kódu. Když Python opustíš (nebo vypneš počítač), -všechno co jsi zatím naprogramoval{{a}}, se ztratí. +všechno co jsi zatím naprogramoval{{a}} se ztratí. Větší programy jsou trvanlivější: ukládají se do souborů a dají se kdykoli spustit znovu. @@ -21,34 +21,23 @@ Zkus vypnout Python. Existuje na to funkce `exit()`: >>> exit() ``` -Tak se dostaneš zpět do příkazové řádky. +Tak se dostaneš zpět do příkazové řádky. Pamatuješ na ni? +Už neuvidíš `>>>`, ale řádek končící `$` nebo `>`. Budou tu fungovat příkazy jako `cd` a `mkdir`, ale ne příkazy Pythonu, jako `1 + 1`. -Chceš-li opustit interaktivní režim Pythonu, který jsme dosud používaly, jednoduše zadejte ~ ~ ~ exit() ~ ~ ~ funkci: - -{# (((((((( XXX )))))))) #} -> [Note] -> Pokud budeš chtít Python konzoli ukončit, zadej `exit()` nebo použíj -> zkratku `Ctrl + D` (pro Mac/Linux) nebo `Ctrl + Z` (na Windows). -> Pak již neuvidíš `>>>`. - - -Tak se dostaneš zpět do příkazové řádky. - -Doufám, že máš nainstalovaný textový editor. -Ten teď otevři a napiš do nového souboru tento příkaz: +Doufám, že máš nainstalovaný [textový editor](../../beginners/install-editor/). +Ten teď otevři, udělej si nový soubor a napiš něj tento příkaz: ```python print('Hello, PyLadies!') ``` -Teď vytvořený soubor ulož pod nějakým popisným názvem. -Pojďme ho nazvat `python_intro.py` a ulož si jej na plochu. -Soubor můžeš pojmenovat jakkoliv chceš, ale jméno musí končit na `.py` -Tahle přípona říká editoru nebo i operačnímu systému, -že jde o program v Pythonu a Python ho může spustit. +Nový soubor ulož pod nějakým popisným názvem: `python_intro.py`. +Ulož si jej do adresáře, kam si budeš dávat soubory k tomuto workshopu. +Jméno musí končit na `.py`: tahle přípona říká editoru nebo i +operačnímu systému, že jde o program v Pythonu a Python ho může spustit. > [note] Obarvování > Po uložení by se text měl obarvit. @@ -65,29 +54,13 @@ Tahle přípona říká editoru nebo i operačnímu systému, > To je jeden z důvodů, proč používáme editory kódu :) Pokud máš soubor uložen, je čas jej spustit! -Pomocí dovedností, které jsi se naučil{{a}} v sekci příkazová řádka, +Pomocí dovedností, které jsi se naučil{{a}} v sekci +o [příkazové řádce](../../beginners/cmdline/), *změň adresář* terminálu na plochu. -Na Macu bude příkaz vypadat přibližně takto: - -``` console -(venv) $ cd ~/Desktop -``` - -Na Linuxu to bude vypadat takto (slovo "Desktop" (Plocha) může být -přeloženo třeba do češtiny): - -``` console -(venv) $ cd ~/Desktop -``` - -A na Windows to bude vypadat takto: - -``` doscon -(venv) > cd Desktop -``` - +{% if var('coach-present') %} Pokud nevíš jak dál, požádej o pomoc kouče. +{% endif %} Nyní pomocí Pythonu spusť kód v souboru: @@ -100,12 +73,13 @@ Funguje? Vidíš text? Jesli ano, právě jsi spustil{{a}} svůj první opravdový program v Pythonu! Cítíš se úžasně? + ## Vstup a výstup Funkce `print()`, kterou jsi použila, umí něco *vypsat* na obrazovku. V konzoli se hodnoty výrazů vypisovaly automaticky, abys je mohl{{a}} -průběžně kontrolovat, ale programy v souborech bývají složitější a výpis -každého kroku by byl nepřehledný. +průběžně kontrolovat, ale programy v souborech bývají složitější a výpisy +z každého kroku by byly nepřehledné. Proto na vypsání potřebuješ `print()`. Zkus si to: @@ -142,3 +116,33 @@ Pamatuješ si na funkci, která umí převést řetězec na číslo? letopocet = int(input('Jaký je letos rok? ')) print('Loni byl rok', letopocet - 1) ``` + + +## Komentáře + +Všiml{{a}} sis u předchozího programu poznámek za „mřížkou“ (`#`)? + +``` python +jmeno = 'Ola' + +'Já jsem ' + jmeno # Tohle Python nevypíše + +print(jmeno * 8) # Tohle jo! +``` + +To jsou takzvané *komentáře*. +Jsou určené jen pro lidi: Python je úplně ignoruje. + +Teď, když své programy ukládáš na disk a můžeš se k nim vracet, +je důležité aby byly *čitelné*: aby z nich nejen počítače, ale i lidi +poznali, co mají dělat. +Vždycky když napíšeš nějaký složitější kus kódu k němu zkus přidat komentář +s vysvětlivkou. +Až se k programu za pár dní nebo měsíců vrátíš, poděkuješ si! + + +## Shrnutí + +* Příkaz **python** spustí uložený soubor jako program v Pythonu. +* Funkce **print** vypisuje hodnoty. +* **Komentáře** můžou zpřehlednit složitější kód. Python je ignoruje. diff --git a/lessons/fast-track/str/index.md b/lessons/fast-track/str/index.md index 009a546f20..a49f9f6f20 100644 --- a/lessons/fast-track/str/index.md +++ b/lessons/fast-track/str/index.md @@ -12,12 +12,20 @@ Zkus si to: zadej své jméno do uvozovek, jak vidíš níže: ``` Nyní jsi vytvořil{{a}} svůj první *řetězec*! -Řetězec je programátorský termín pro *text* – posloupnost znaků (písmenek), které mohou být zpracovány počítačem. +Řetězec (angl. *string*) je programátorský termín pro *text* – posloupnost +znaků (písmenek), +které mohou být zpracovány počítačem. Když řetězec zadáváš, musíš ho vždy uzavřít do uvozovek (apostrofů). -Jinak by Python nepoznal, co je text a co jsou instrukce. +Jinak by Python nepoznal, co je text se kterým má pracovat a co jsou instrukce +které má provést. +To je pro počítač docela důležité – lidem podobné věci dojdou z kontextu, +ale počítač je hloupé zařízení. -{# XXX: Assessment here: adding strings together #} +{{ figure( + img=static('quote-comic.svg'), + alt='(Ilustrační komiks. Člověk říká robotovi: "Řekni Pavlovi, ať mi zavolá!". Robot odpoví: "PAVLOVI AŤ MI ZAVOLÁ!")', +) }} Řetězce se dají spojovat – „sečítat“ – pomocí `+`. Zkus toto: @@ -26,21 +34,19 @@ Jinak by Python nepoznal, co je text a co jsou instrukce. 'Já jsem Ola' ``` -> [note] -> Pozor na mezeru! Když zadáš `'Já jsem'+'Ola'`, spojí se ti dvě slova -> dohromady. -> Počítač považuje i mezeru za *znak*; chová se k ní stejně jako k jakémukoli -> písmenku. -> Když nedáš mezeru do uvozovek, nebude součástí řetězce. -> -> Zkus si: -> -> ``` pycon -> >>> 'Já jsem' + ' ' + 'Ola' -> 'Já jsem Ola' -> ``` - -Také můžeš řetězce opakovat – násobit číslem: +Pozor na mezeru! Když zadáš `'Já jsem'+'Ola'`, spojí se ti dvě slova dohromady. +Počítač považuje i mezeru za *znak*; chová se k ní stejně jako k jakémukoli +písmenku. +Když nedáš mezeru do uvozovek, nebude součástí řetězce. + +Zkus si dát do uvozovek i mezeru samotnou: + +``` pycon +>>> 'Já jsem' + ' ' + 'Ola' +'Já jsem Ola' +``` + +Kromě „sečítání“ můžeš řetězce i opakovat – násobit číslem: ``` pycon >>> 'Ola' * 3 @@ -69,26 +75,36 @@ než jsi použil{{a}} ty: ## Funkce a metody -Už umíš řetězce „sčítat“ pomocí `+` (`'Ahoj ' + 'Olo!'`) -a „násobit“ pomocí `*` (`'la' * 3`). +Už umíš řetězce „sčítat“ (`'Ahoj ' + 'Olo!'`) +a „násobit“ (`'la' * 3`). Na všechny ostatní věci, které se s textem dají dělat, ale na klávesnici není dost symbolů. Proto jsou některé operace pojmenované slovně – třeba takzvané *funkce*. Chceš-li znát počet písmen ve svém jméně, zavolej funkci `len`. Napiš `len` (bez uvozovek), pak kulaté závorky, a do těch závorek -své jméno (jako řetězec – v uvozovkách): +své jméno jako řetězec (v uvozovkách): ``` pycon >>> len('Ola') 3 ``` -{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} +Existuje funkce `type`, která zjistí jestli je něco číslo nebo řetězec. +Jak bych ji zavolal? + +{% filter solution %} +``` pycon +>>> type(123) + +>>> type('123') + +``` +{% endfilter %} Kromě funkcí existují *metody*, které se zapisují trochu jinak. -Chceš-li vidět své jméno velkými písmeny, zavolej metody `upper`. +Chceš-li vidět své jméno velkými písmeny, zavolej metodu `upper`. Napiš řetězec, pak tečku, jméno metody `upper` (bez uvozovek) a prázdné závorky: @@ -97,16 +113,22 @@ závorky: 'OLA' ``` -Zkus si zavolat metodu `lower`. +Řetězce mají i metodu `lower`. Zkus ji zavolat na své jméno. -{# XXX: Existuje funkce `type`. Jak bych ji zavolal? #} +{% filter solution %} +``` pycon +>>> 'Ola'.lower() +'ola' +``` +{% endfilter %} -Co je metoda (které voláš s `.`, jako `'Ola'.upper()`) a co je funkce -(kde vložíš informaci do závorek jako (`len('Ola')`) +Co je metoda (které voláš s tečkou, jako `'Ola'.upper()`) a co je funkce +(kde vložíš informaci do závorek jako `len('Ola')`), +to se budeš muset vždycky zapamatovat nebo vyhledat. {# XXX: Move elsewhere? #} -## Skládání +## Skládání výrazů Volání funkce nebo metody můžeš použít jako jinou hodnotu. @@ -119,9 +141,9 @@ Nech Python spočítat matematický výraz `(1 + 3) / 2`: Python napřed sečte `1 + 3` a vyjde mu 4. Čtverku doplní místo `1 + 3` do původního příkladu, a dostane `4 / 2`. -To vydělí a dostane `2`. +To vydělí a dostane `2.0`. -Neboli: `(1 + 3) / 2` = `4 / 2` = `2` +Neboli: `(1 + 3) / 2` = `4 / 2` = `2.0` Zkus se zamyslet, jak Python zpracuje tyto výrazy: @@ -158,19 +180,18 @@ Zkus se zamyslet, jak Python zpracuje tyto výrazy: Podobné skládání je v programování velice časté. Většinu základních stavebních bloků se začátečník naučí za pár -týdnů – a pak je po celou svou progrmátorskou kariéru skládá do -složitějších a složitějších konstrukcí. +týdnů – a pak po celou svou progrmátorskou kariéru objevuje nové způsoby, +jak je poskládat do složitějších a složitějších konstrukcí. ### Shrnutí OK, dost bylo řetězců. Co ses zatím naučil{{a}}: -* **Interaktivní režim Pythonu** umožňuje zadávat příkazy (kód) pro - Python a zobrazuje výsledky/odpovědi. -* **Čísla a řetězce** se používají na matematiku a práci s textem. -* **Operátor** jako `+` a `*` kombinuje hodnoty a vytvoří výsledek. -* **Funkce** a **metody** jako `len()` a `upper()` provádí na hodnotách +* **Řetězce** se používají na práci s textem. +* **Operátory** `+` a `*` se používají na spojování a opakování řetězců. +* **Funkce** a **metody** jako `len()` a `upper()` provádí na řetězcích nějaké akce. +* **Výrazy** se dají skládat dohromady. Čísla, řetězce a operátory a funkce jsou základy většiny programovacích jazyků. diff --git a/lessons/fast-track/str/static/quote-comic.svg b/lessons/fast-track/str/static/quote-comic.svg new file mode 100644 index 0000000000..cd80509d62 --- /dev/null +++ b/lessons/fast-track/str/static/quote-comic.svg @@ -0,0 +1,466 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lessons/fast-track/variables/index.md b/lessons/fast-track/variables/index.md index b03ceaed36..b3828979e4 100644 --- a/lessons/fast-track/variables/index.md +++ b/lessons/fast-track/variables/index.md @@ -83,12 +83,40 @@ která dosud nebyla nastavena. Pokud někdy dojde k této chybě, zkontroluj svůj kód, abys zjistil{{a}}, jestli jsi někde neudělal{{a}} překlep. -> [note] Jména proměnných -> Profesionální programátoři pojmenovávají proměnné anglicky, -> aby jim rozuměli co nejvíc kolegů po celém světě. -> Ze začátku ale doporučujeme češtinu – je tak jasnější, která jména -> si můžeš zvolit {{gnd('sám', 'sama')}} (např. `barva`) a která jsou -> z Pythonu (např. `upper`). -> -> Je ovšem dobré se nepoužívat diakritiku a vyhnout se velkým pímenům: -> místo `Jméno` použij jen `jmeno`. +## Jména proměnných +Profesionální programátoři pojmenovávají proměnné anglicky, +aby jim rozuměli co nejvíc kolegů po celém světě. +Ze začátku ale doporučujeme češtinu – je tak jasnější, která jména +si můžeš zvolit {{gnd('sám', 'sama')}} (např. `barva`) a která jsou +z Pythonu (např. `upper`). +Nevýhoda je, že si časem budeš muset odvyknout. + + +Každopádně je dobré nepoužívat diakritiku a vyhnout se velkým pímenům: +místo `Jméno` použij jen `jmeno`. + + +Která z těchto jmen ti Python dovolí použít jako proměnnou? + +* `tlacitko5` +* `5tlacitko` +* `oblibena barva` +* `oblibena-barva` + +{% filter solution %} + +* `tlacitko5` ano +* `5tlacitko` ne: jména musí začínat písmenkem +* `oblibena barva` ne: to není jedno jméno, ale dvě! +* `oblibena-barva` taky ne: je to výraz `oblibena` mínus `barva` + +Kdybys potřeboval{{a}} ve jménu více slov, použij podtržítko: např. +`oblibena_barva`. +{% endfilter %} + +## Shrnutí + +* **Proměnné** jsou jména pro hodnoty. +* Přiřazením (`=`) můžeš proměnnou nastavit na jakoukoli hodnotu. +* Proměnné pojmenováváme **malými písmenky** bez diakritiky. +* Na oddělení slov v rámci jména můžeme použít **podtržítko**. diff --git a/lessons/snake/drawing/index.md b/lessons/snake/drawing/index.md index c399bb43a6..606616884f 100644 --- a/lessons/snake/drawing/index.md +++ b/lessons/snake/drawing/index.md @@ -241,7 +241,7 @@ pyglet.app.run() Aby bylo ve hře co dělat, budeme potřebovat pro hada krmení. Stáhni si do adresáře s projektem obrázek -[apple.png](({{ static('apple.png') }}) a zkus vykreslit +[apple.png]({{ static('apple.png') }}) a zkus vykreslit jablíčka na následující souřadnice: ```python From 131d6a6f6ae20acd071fe670a4e505c038de6167 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 31 Aug 2018 23:08:06 +0200 Subject: [PATCH 14/30] Add something about tuples and zip --- courses/snake/info.yml | 1 + lessons/fast-track/def/index.md | 61 +++++++++++++++++++++ lessons/fast-track/for/index.md | 4 +- lessons/fast-track/list/index.md | 28 ++++++++++ lessons/fast-track/tuple/index.md | 90 +++++++++++++++++++++++++++++++ lessons/fast-track/tuple/info.yml | 5 ++ 6 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 lessons/fast-track/tuple/index.md create mode 100644 lessons/fast-track/tuple/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml index 6c2298074d..f7a5c1c531 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -58,6 +58,7 @@ plan: - lesson: fast-track/if - lesson: fast-track/def - lesson: fast-track/for + - lesson: fast-track/tuple - title: "Doplnění: list slicing, del, n-tice, zip()" url: null - title: Had diff --git a/lessons/fast-track/def/index.md b/lessons/fast-track/def/index.md index 0fa0d083a7..eb634ef0d9 100644 --- a/lessons/fast-track/def/index.md +++ b/lessons/fast-track/def/index.md @@ -141,6 +141,66 @@ pozdrav('Soňa') ``` +## Vracení + +Další věc, kterou funkce jako `len` umí, je *vrátit* výsledek: + +``` python +delka = len('Ola') +print(delka) # napíše: 3 +``` + +Jak na to? +Ve funkci můžeš použít příkaz `return`, který funkci okamžitě ukončí +a vrátí danou hodnotu: + +```python +def dvojnasobek(x): + return x * 2 + +print(dvojnasobek(42)) +``` + +Zkus napsat funkci, která pátý pád nějakého jména, třeba: + +* `paty_pad('Ola')` → 'Olo' +* `paty_pad('Soňa')` → 'Soňo' +* `paty_pad('Hubert')` → 'Huberte' + +Tohle je velice složitý úkol, tak si ho trochu zjednodušíme. +Funkce by měla dělat tohle: + +* Pokud jméno je „Hubert“: + * vrátí `Huberte` +* Pokud jméno končí na `a`: + * vrátí jméno s `o` místo posledního písmenka +* Jinak: + * Vrátí původní jméno. (Uživatel si toho snad nevšimne.) + +``` python +def paty_pad(jmeno): + if jmeno == 'Hubert': + return 'Huberte' + elif jmeno[-1] == 'a': + return jmeno[:-1] + 'o' + else: + return jmeno +``` + +Dokážeš změnit funkci `pozdrav`, aby zdravila v češtině? + +{% filter solution %} +``` python +def pozdrav(jmeno): + print('Vítam tě,', paty_pad(jmeno)) + +pozdrav('Hubert') +pozdrav('Ola') +pozdrav('Soňa') +``` +{% endfilter %} + + ## Shrnutí Co bylo nového tentokrát? @@ -148,3 +208,4 @@ Co bylo nového tentokrát? * **Funkce** umožňuje pojmenovat nějkolik příkazů, a pak je zavolat najednou. * **Parametry** funkce, hodnoty se kterými funkce pracuje, se zadávají v závorkách. +* `return` ukončí funkci a vrátí hodnotu diff --git a/lessons/fast-track/for/index.md b/lessons/fast-track/for/index.md index bca63c175d..960c69e0db 100644 --- a/lessons/fast-track/for/index.md +++ b/lessons/fast-track/for/index.md @@ -30,8 +30,8 @@ for jmeno in jmena: Celý program bude tedy vypadat takto: ```python -def pozdrav(meno): - print('Vitam ťa,', meno) +def pozdrav(jmeno): + print('Vítam tě,', jmeno) jmena = ['Rachel', 'Monica', 'Phoebe', 'Ola', 'Ty'] for jmeno in jmena: diff --git a/lessons/fast-track/list/index.md b/lessons/fast-track/list/index.md index e7c9449752..f77300329d 100644 --- a/lessons/fast-track/list/index.md +++ b/lessons/fast-track/list/index.md @@ -317,6 +317,33 @@ Začátek a konec se dá kombinovat – číslo můžeš dát před i za dvojte ['Druhý', 'Třetí'] ``` + +## Řezání řetězců + +Hranaté závorky fungují i u řetězců: + +``` pycon +>>> jidlo = 'čokoláda' +>>> jidlo[3] +'o' +>>> jidlo[1:4] +'oko' +``` + +Představ si, že máš v proměnné `jmeno` jméno jako `'Ola'`, +`'Krystýna'` nebo `'Růžena'`. +Jak z něj vytvoříš druhý pád (např. bez `'Růženy'`)? + +{% filter solution %} +Vezmi jméno až po poslední písmeno a přidáš `'y'`. Například: +``` python +>>> jmeno = 'Růžena' +>>> jmeno[:-1] + 'y' +'Růženy' +``` +{% endfilter %} + + ## Shrnutí Uf! O seznamech toho bylo k naučení celkem hodně. Shrňme si, co už umíš: @@ -327,5 +354,6 @@ Uf! O seznamech toho bylo k naučení celkem hodně. Shrňme si, co už umíš: * Prvky se dají **vybrat** nebo **odstranit** (`del`) podle indexu. * Číslování začíná **od nuly**, záporná čísla berou prvky od konce. * **Podseznam** je určitá část seznamu. +* U **řetězců** funguje vybírání prvků a podřetězců podobně Jsi připraven{{a}} na další část? diff --git a/lessons/fast-track/tuple/index.md b/lessons/fast-track/tuple/index.md new file mode 100644 index 0000000000..b3fd659704 --- /dev/null +++ b/lessons/fast-track/tuple/index.md @@ -0,0 +1,90 @@ +# N-tice + +Už víš, že pomocí `return` lze z funkce vracet hodnotu: + +``` python +def dvojnasobek(x): + return x * 2 +``` + +Jak ale napsat funkci, která vrátí dvě hodnoty? +Chci třeba napsat funkci, která spočítá podíl a zbytek po dělení. + +Dvě hodnoty se dají vrátit jako seznam: + +``` python +def podil_a_zbytek(a, b): + podil = a // b + zbytek = a % b + + return [podil, zbytek] + +print(podil_a_zbytek(5, 2)) +``` + +Lepší je ale vrátit *dvojici* čísel – dvě čísla oddělená čárkou: + +``` python +def podil_a_zbytek(a, b): + podil = a // b + zbytek = a % b + + return podil, zbytek + +print(podil_a_zbytek(5, 2)) +``` + +Tomuhle se říká dvojice – nebo trojice, čtveřice, pětice, šestice, prostě +n-tice (angl. *tuple*) hodnot. +Funguje podobně jako seznam, ale nedají se do ní přidávat prvky, nebo odebírat +a jinak měnit. +Když mám trojici, vždycky zůstane jako trojice. + +Když máš n-tici, můžeš ji přiřazením *rozbalit* (angl. *unpack*) +do několika proměnných: + +``` python +podil, zbytek = podil_a_zbytek(5, 2) + +print(podil) +print(zbytek) +``` + +N-tice mají spoustu využití, například: + +* Bod v prostoru má 3 souřadnice – trojice čísel! +* Hrací karta má barvu a hodotu – dvojice čísla a řetězce, např. `(2, 'piky')` + +Občas je potřeba dát n-tice do seznamu, např. abys uložil{{a}} +informace o celém balíčku hracích karet. +V podobných případech je potřeba každou n-tici uzavřít do závorek, +aby bylo jasné kde začíná a kde končí. +Tady je seznam dvojic: + +```python +ruka = [(2, 'piky'), (10, 'kříže'), (8, 'káry')] +``` + +Když takový seznam máš, můžeš ho projít v cyklu `for` s pomocí rozbalování: + +``` python +for hodnota, barva in ruka: + print('Hraju', hodnota, 'a jsou to', barva) +``` + +## Zip + +N-tice, respektive sekvenci n-tic vrací funkce `zip`, +která umožňuje projít zároveň několik seznamů, +jejichž prvky si navzájem odpovídají: + +``` python +veci = ['tráva', 'slunce', 'mrkev', 'řeka'] +barvy = ['zelená', 'žluté', 'oranžová', 'modrá'] +mista = ['na zemi', 'nahoře', 'na talíři', 'za zídkou'] + +for vec, barva, misto in zip(veci, barvy, mista): + print(barva, vec, 'je', misto) +``` + + diff --git a/lessons/fast-track/tuple/info.yml b/lessons/fast-track/tuple/info.yml new file mode 100644 index 0000000000..f3110652a1 --- /dev/null +++ b/lessons/fast-track/tuple/info.yml @@ -0,0 +1,5 @@ +title: N-tice a rozbalování +style: md +attribution: +- Pro PyLadies CZ napsal Petr Viktorin, 2018. +license: cc-by-sa-40 From 968d11f4aec596776ad97687f65b6df0af285743 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 31 Aug 2018 23:42:37 +0200 Subject: [PATCH 15/30] Add info about the `in` operator --- lessons/fast-track/bool/index.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lessons/fast-track/bool/index.md b/lessons/fast-track/bool/index.md index 7abc6edf06..1bb9455399 100644 --- a/lessons/fast-track/bool/index.md +++ b/lessons/fast-track/bool/index.md @@ -93,9 +93,26 @@ V Pythonu můžeš zkombinovat několik porovnání do jednoho! * Pokud použiješ operátor `or`, stačí aby jen jedna strana z porovnání byla pravdivá. +## Přítomnost + +Nebylo by pěkné zjistit, jestli tvoje číslo vyhrálo v loterii? +K tomu budeš potřebovat zjistit, jestli seznam obsahuje daný prvek. +Používá se na to operátor `in`: + +``` pycon +>>> loterie = [3, 42, 12, 19, 30, 59] +>>> 18 in loterie +False +>>> 42 in loterie +True +``` + +Není to úplně porovnání, ale dostaneš stejný druh výsledku. + + ## Pravdivostní hodnoty -Mimochodem, právě ses dozvěděl{{a}} o novém typu objektu v Pythonu. +Právě ses dozvěděl{{a}} o novém typu objektu v Pythonu. Podobně jako máme řetězec, číslo, seznam nebo slovník existuje *pravdivostní hodnota*, nebo častěji anglicky *boolean*. @@ -115,7 +132,7 @@ True Stejně tak můžeš uložit i výsledek porovnání: -``` +``` pycon >>> a = 2 > 5 >>> a False @@ -126,7 +143,7 @@ False V této sekci ses dozvěděl{{a}}: -* V Pythonu můžeš **porovnávat** pomocí operátorů `>`, `>=`, `==` `<=`, `<`, `!=` +* V Pythonu můžeš **porovnávat** pomocí operátorů `>`, `>=`, `==` `<=`, `<`, `!=` a `in` * Operátory `and` a `or` umí **zkombinovat** dvě porovnání. * **Boolean** (pravdivostní hodnota) je typ, který může mít jednu ze dvou hodnot: `True` (pravda) nebo `False` (nepravda). From 30c36533f85cadd8a2d5ce542e9d9ca9da5697a8 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sat, 1 Sep 2018 00:20:34 +0200 Subject: [PATCH 16/30] Rename 'tail' and 'head' snake parts to just 'end' --- lessons/snake/drawing/index.md | 14 +++++++------- lessons/snake/drawing/static/snake-tiles.png | Bin 87807 -> 88658 bytes lessons/snake/drawing/static/snake-tiles.zip | Bin 65885 -> 65861 bytes .../{bottom-head.png => bottom-end.png} | Bin .../{tail-bottom.png => end-bottom.png} | Bin .../{tail-dead.png => end-dead.png} | Bin .../{tail-head.png => end-end.png} | Bin .../{tail-left.png => end-left.png} | Bin .../{tail-right.png => end-right.png} | Bin .../{tail-tongue.png => end-tongue.png} | Bin .../snake-tiles/{tail-top.png => end-top.png} | Bin .../{left-head.png => left-end.png} | Bin .../{right-head.png => right-end.png} | Bin .../snake-tiles/{top-head.png => top-end.png} | Bin lessons/snake/logic/index.md | 16 ++++++++-------- 15 files changed, 15 insertions(+), 15 deletions(-) rename lessons/snake/drawing/static/snake-tiles/{bottom-head.png => bottom-end.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{tail-bottom.png => end-bottom.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{tail-dead.png => end-dead.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{tail-head.png => end-end.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{tail-left.png => end-left.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{tail-right.png => end-right.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{tail-tongue.png => end-tongue.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{tail-top.png => end-top.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{left-head.png => left-end.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{right-head.png => right-end.png} (100%) rename lessons/snake/drawing/static/snake-tiles/{top-head.png => top-end.png} (100%) diff --git a/lessons/snake/drawing/index.md b/lessons/snake/drawing/index.md index 606616884f..629ad3639a 100644 --- a/lessons/snake/drawing/index.md +++ b/lessons/snake/drawing/index.md @@ -317,7 +317,7 @@ Obrázek se jmenuje odkud-kam.png. > [note] > Co jsou taková ta divná „hadí vajíčka”? -> +> > To je pro případ, že by had byl jen jedno políčko dlouhý – a tedy měl hlavu > i ocas na stejném políčku. > V dodělané hře se do takového stavu nedostaneme (had bude začínat s délkou 2), @@ -353,7 +353,7 @@ for path in TILES_DIRECTORY.glob('*.png'): ``` My z každého souboru potřebujeme nejlépe jméno, tedy místo -`snake-tiles/right-head.png` jenom `right-head`. +`snake-tiles/right-end.png` jenom `right-end`. Na to naštěstí existuje atribut `stem` (*kořen*, t.j. jméno bez přípony). Místo `print(path)` použij: @@ -377,7 +377,7 @@ Až to budeš mít, měl by výpis vypadat asi takhle: ``` {'right-tongue': , 'top-tongue': , 'right-top': , 'left-bottom': , - 'tail-left': , 'bottom-tongue': , + 'end-left': , 'bottom-tongue': , 'left-top': , 'bottom-bottom': , ... ``` @@ -406,7 +406,7 @@ A teď zkus načtení obrázků začlenit do programu s hadem! Všechny importy patří nahoru, konstanty pod ně, a dál pak zbytek kódu. Vypisovat načtený slovník ve hře nemusíš. Zato ve vykreslovací funkci použij místo `green_image` -třeba `snake_tiles['tail-head']`. +třeba `snake_tiles['end-end']`. Místo čtverečků se teď objeví kuličky – místo hada budeš mít „housenku“. @@ -440,7 +440,7 @@ def on_draw(): pyglet.gl.glEnable(pyglet.gl.GL_BLEND) pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA) for x, y in snake: - snake_tiles['tail-head'].blit( + snake_tiles['end-end'].blit( x * TILE_SIZE, y * TILE_SIZE, width=TILE_SIZE, height=TILE_SIZE) for x, y in food: red_image.blit( @@ -515,13 +515,13 @@ for a, b, c in zip([None] + snake, snake, snake[1:] + [None]): ``` -1 2 tail right +1 2 end right 2 2 left right 3 2 left top 3 3 bottom top 3 4 bottom top 3 5 bottom right -4 5 left head +4 5 left end ``` Toto je **těžký úkol**. diff --git a/lessons/snake/drawing/static/snake-tiles.png b/lessons/snake/drawing/static/snake-tiles.png index 6b7b1c8d52d5a64b5e1fd0d6b225c359a050f62d..05182e7bf6c46b275e21a4dc5f37cb0f22412e02 100644 GIT binary patch literal 88658 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 z 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%0DLvn~Fv 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 literal 87807 zcmb4qRa6{{7G(p$-L=sWAb4JYB&J^h?wsm z2tZl}9(X6Lvy_||>^2l092cvxE8qKhKnrDcXAwIa8xvb+@FoBt;%H*vY+_96X5nm3 zDj_BJ)tJEq762dxNQnw5yDy)%c_b3edEC9VH54~{X8MSajFO@mGLzyHb#7uu*;L9| zxAtyw>XI&AS`Els3vai2_<2ltOq^%v5$W>C8}h*SqglhA^Q6c@jM^Hj(vyC)GBC}b ziZVSvDoc8L%4=>e@$w|J@MQN9;CAsWESl3%xjXX8KKIFb(sp>cS)fG|h9e7lUzB_p z(h~g7dXRAPfA{B1QvP!oyr6c5|M%1&Gz6XhUWV2D-@|ah4F5eWoFnt!JAFOG_`gs6 zf8ObTJ@o&1r~mcP|MmLD29wEGLu=D+hyeYb7534WJV4^tuiv_ui8#q%ReQf<*XfJV zfmdU;1f`%Uu}E?5cd^bdVWlTGRLvZP(kLmGz^;h6ulFfY{>$%}j4{dFv03 z$c#89m(+h$5QiONuTz?x(i!cx794qZO2g}SnZ?(5S>96VYY5rx;*mE9k4W*Z1bK7Y zvli^M>0eC*tOY`$pqFx1ykWuFaGaPF%qwD@bH&f&xCuW4X|?lfu}t?$?|ys4zQ$v6 zQB&_4qW} zNOJ4YQ8J_uScgI0p!}@T)B9BJ+AtXUd?7@ySWop(Q_HxJ4qAeWdWaf#uUOnnds;~1wvq#6!cV+^DK0$Xt;FeGnL7wiM%0?+$z*q91ue={9 z3`l1&gsE}9Pkyjl{k+>gmX0WV2VQ!Jz`Z{&&d5kQyW8EINa-=r&0J~Ff=j(pUxqO0 zVp<>BM9|Fzj|t6D*xW^P%F;_hq8zHsmDX-wdTt=if621j8d=mDTYpSbGPWR|KTX_~ zJQCgM1I0dEmW2lly(=Pn0sB_%tcBzv{JQ8DJJW0Y({NDN`k}7u$&8p67Ub3~6L}`O zXfrvJVSl$Bn{ZM_ZBl0g)YSUaBe~PWjX~P>ptF!-x=x|lk|)1 zL=PI|$1yy+GC5XWIDth*I78^5`N-OPif700kHj&tWz^ldZojyGbk!H9jnJac@3Lme zk#NCdh7zCkXZ;w&K*|PB#uustw#6OcC4}<5ZfT85Q~E_3!lfZPQ>H+jOPxjRjo?P$ z!2Ygj2EP|KlF7w>1dNbh(DK>C52qie}l5O!7bkd%FkaWsmLD0r4H(YeeQCSGt0sUhN?)R-(%(=XU+0p z?9;n$9LX=gol;s`t*M3$5->wm)iHxL4o4}B%#|XHF!3;G){tgXU{T(bN;EAolLE{V zb7T*vTF&ZZp`Y0N{s+;1|1{M)NTt9tz+M7xD~4%#!d$|UIy^N1UsfLy)s;WY?99xe zYZrPkZmH8t%$~^`ZDqOM;9K@JQGI2Ms2}9zx_geKa?ROKI%KZY9wmAO12=1q#II<= zr1k6}i_3W3nFer*Ee^GDYR02f&HW`wMTx?ubb(7fHIhIn1F%AGL+^H?mRRh!u7ly4 z$kx682^S@)iAmiQHnIAoU%sLhl@-;JPvieNdxqERD6TF-^h>#V{3-*NlZ2+JU?Jv7 z7yai&X;9wu()=lp6OTWPL#{pCsyHp`M{#$;&os4JAGth9k=(sqoR9L-`nMN!g|`X@ zU--hGT0jHMqui~w$1YLT8NX!lFx^{k9EeazZi(u`V&;`J(Y0`CjU(vt{prsusO^)J zC~_#=e_cV0TGoJn-Bh;V2~8Pg_l^1hkn97w&N_kZfitWUY+)Rct8hu1FW9;uBO-_LiTUA4im2b< zdGr}ym+#6lgU5-1wV*0q9ze9UnVMu)$=41nx6cV?t<78xQMW6#{ZN6fSQ3%>)h1pv zr^Wa*7BnDohT4UWGRlq#eyQ#-0y%s)Rwa=Ee4yktB~!f>QcXh5y~|yN!%#0JC#4Gl zVc>i29<(%MWsUG^1_`N}qJ!Y_ten(tG_Jo$h=e1=0)jBUN_$u_sz80m6|AK~s2S^B zjA70nnEvNBeN(iJY;p-RK>qKJA6 zc9Op|w+yE;eY(&e2*l%P6&4A9{jkhlhdr-N9N9=8Mw$pu#(a0TSucv!EYow_>&iR# zh=qlPK}896(Sh739`Vu6WyEkOY-PA59AnK;@nXq-%7LM3I07Vsgr=Jr9Y9{1L z6{)3)C?C_QoB1%3fk+7z3dfl;?8F^(0DJ5Jh&*TGMDwdc*6p$sw^6#2b6yqW&Q@i4`H zn#MFO@9RtytW4x1Nw}hWYHdXTe$lbhVO=>QmL-rnsZdiQmJ6#4<^jx;YZAoOUn$Z&i2( zZQiBVkFI^L5P6C8XXX!7LUiJ^M_=Hhx%uNe@@5 z?UNlDb`aPn1rH&Ocm^)qPj<{}mMhs?lA=Z5A*FG_U-Of^6xL7Z5uuYVs|IY z)gsN*=IFR_^3>ELAn`;8qjV(a-MWIiz%zeKl_UPbT*sD`r(P8#naG@&7jF% z%lgSNofp)*FknDQFH4fqKR;g9Xu12j_l%P;@*kg(He%upYpZHQn~uz4|52{JZH>o3 z)I&p54jQX`f{qEIZN+!d60Tu2|3=IC0|Pl??YRl)`sc3*etxh`4RbN6LjCpy?Ti+;xmudrX=zz^nwQwh3kg3}D4*y1 z?aXrWSmTVZCQoT%@U=NXY#m?7NUZL7Klyv&sh(b(Z$<`8*8f2kFLg~U-P9lUuR(Xz z54GmZ`4UQzBAn#Li4Y^%>5(XnGoxeW{!@HZaHWu4wv{))rfh}U8TZ>^8g`Iv`x!!R zgQjuA_epvMTsjYak|X-Cbr|T1B}2nAtA*{s^B8@syvC9fhSrnA7HU_uUxRJnjVQvM zNeb@yj1CyjMhLZ1?ag7s4-2@}loq9$OIIes9MoCE6isxpb)4_<4GdeR;|_UCYL44< ze>g}0bj;ig4y(wJ^Z`#4PY%*)KU3h};e09Ht=OHxC|)4(R6Hk*;=&XiXK32@5-*lx z*TE1Y&)D)U&zP|NBrNE7d1y0{oZ6K5-+Hyw4&NYIpjhyF{<+x5l7i3y!rqx`ax}O3 zkY2Ari?%u)w{iM*8oGdDYuR?ojEsO$Ru!+ZhkIW4FnsND$zgTI19jcwI#bq2mrQ-S z`&~(^c%kSlmHW?ZbtTQPVz$AMqP}{0*V_~2pmCiB8d_ZXV%0Fqm_c&6s$eRu><^n_ z3Ra-_7SWv;){n~^bw;Os%)C>#AHWzIoKV?`|4BZ3G2gpq!ix}N#Pd!Z15pZ$IQvpv zdT2O__MWP7h-5d?sUu;8Jy=emb5xAlY@aO7@O%ug6sWTLY5pi#iU&vq*8lo59OFZ} ztyvvvTTr|I>u{`yUPcQi_jCKdi9AMX^H#mmhLSHbFnNcoo=*7)aVO zpo^2Z7__a=RwJe+&B=afsqIEgo9jv)Tk39dH!Er99U-nhdyWY|Iu@|*Ash{1-z`zf z8JKxfnbv8f*qDl(I1&=LiCWCo8yoK64P?685e@Z7<$qFohiG8LWwH~G4J{!qJP1Ez z?~bR`k98duW3EtJPK{C?jL1zWPknBVCnn(}|ADfyd{}{pR*DO;5OY5Km#9}R*n|qB zXpllfm*Nn~oP&$K2fZWA3vLr36mycxQdxkDg~+tlT_`J+6!mv_w^>f3f={rg{R$Fg zRIJ|b838F(#J&1OihcXb!O$%gvoXrgS{RqhGuHhGbv&q1<`5L*@sQ~REv)$9^;Kh%6M+IpLb$>iFRTH4NCGdFEcBH z$6!9vB8WS~|LNIS^`IhOqHBNY=P=Y$P#D@^kBQpMi{<@ZYq2e(raP2g_k9t#gxpDc zt)!&>L21BPaS=;28U%zk%S%)G?V$+t^C@H!9eNz=_Wa{XGuq8_@W)39d_}ZNs*CmL zj@WGKE?m33%Dup_SLRnpX`BWej5Pm~{k#UxD#+rJrb%n$>Awhll3UoJ=;qcdG@UX= zApQzMiF#lcID9(qb2m+Z9M7x_TdHX55rq-Jxl+eZ&i1E`@w4v$ZYw3W8(YIil_pS< z5b`3w1q!2tp17tA1-Nc%)wFjU^;NPBonI^Vdu465Y-QS0V6-+Q}_3~pGPmOQ8jqC{E{YLV2|9c z_l_>4rH#~zSl;VFzk(~gu{bmUPO(j4vw%bwL~}x2z-1<(by3R zbE)WR7t=l717eMkF(AR?X(#Q|XS2rQ97v_9ENXC_1up!nXzIeFn=?ciBkDqQ@ADyii%gyW-KYC-2h;?D*F~;k>pEx+5^I6kPEJjVn zt?5@V(gY8dbP=v@?_CR-7@^*a#B6usf51|ZYD=-#5dR-djgK7Wgk(ke-Hth7%1oXz zNtDvmr?IE7fZq9j0z$XiYKI~^9gp@M`EdLBVFc=Ve7EPQAfG9p^=7?y%1=XQwZX%w zFMDX%U=>e7Q$~b^4Uajm{OX8=@=5u)k5x#LHH+Y|W4t2&^8ro*&D*LaxM)uMLsnM6 zY#UW$pcb}SriwgQk$8egus~fBr6tjuV)F^(1-`MnZ>KEwDvOahwt*i-tr1*0=+~#- z*ifYCYW96Xfc{G&w?JA!jv=-j*T5OIQ8lQV{fTi;9~!;U~!!C;R@NUN8#nG_~K2}N}}yTxz>`%-96C>e5i z{me2!7QkW|{Otz@5N+~X!dH1CtHM!L%psAX zZnk*rkFGvEaR?aItk_@2`0{`Bl?fIv2G3G1%iHuUMj9>7*CSIQXU|T0+Ev?A=Tw&2 zq;p)_TN36ooJ6L1Cyq^J3Ujw$I!5#rLOyN4G$51HBKiq`S)JAyg=4=u zr99--G94V33u?r)MK!W~!=h4q$3r8!iY^gNl(&mE$RDvm`E}&3>xpDTMx*Za@f@Vt1>IHKr8EO1K?>y0$ zaMwend@wvkC0ZGE8)8#yZe)Ccwqo(L_k^#&{NE)fZM`_mD;5up0QAo&ul-D1eTXoU1I|adIF`k3nSrqXUc+I>J z2LDG~T2NfBJ;2|w?RWY&gz~fQv8H#HG6Ra%q)S?JaBMfOu9_2#%O5Hp${!L8u{e1= z*ufHrs;B!BW6xwF3jxWrE$&11tzJ&nYFR~y2 z3{!}<1eFK~Jqp5g3P_FrEMiM{D#lRRuWds>OG zb+(3RmX!wzII&1uIeg0%-@wog#4jz^uBKuT14SIfdB90i2d#8NljI)XqiNRwSJS-$ z27qsT2T?q1QL>T{HFKh-5qAbLL-3U@tgpOm;Q8bmr#81Kj7|AuAR%te5no7yvzDM&2RcY~q;Py-sl^>XD)-anTgeAa%1Z>VS za^fSKQ}q&UVV?nfxfEdjrj-L!mW^Qog*1HoF@r@s>|2-CD~G@tS{6%jFx$sROmGa_ zTxR$oA~lLMs{ffU7)*9_4IL$1h756#o(3(c%b5z_)$73b5z1&~v83x7Yz!MY^7d+n z=1rTytIaCt#f0jE>%c=ytY%uBQ<&S9pzpX%Y|?qn!7j~g-%^6HB(JHMs>~q4tS5~# zZn#dB4!~d3FZWS2P4LekvNh#y{lXwsv_$SdB=tb@dOG{KXRVw*## zjOly7WF$z+2;0A+k&=D)6jk?Ne+!*CMN%_nR5zSz1k@EcV5r!f# zWy&nB60>zc4x|O%LiU}thKF^~;4qr^e!@{~1y}MXvPvx89`}#GkEL@17+Vm;u)U5cRg#KiFm9IIL z%~2u=yJndV9PIzd92T~34*>Z}MF=qP=>rp!452W=O*EYJ{H$J|%sVnFC-5x{&K|6C zQu~DY_Exw*AO?VI2_EYn1g%O6_R_FD;KN2>D0V%9-<@AWkE`NoNO6A7-jpn|)r4Lo z_T7)Un*C|At_d+_kCZQ~ zA1sos;`kC$?1LPfGz**N@=1D5;w~FJV~x*S!jb6&*(w!=<^P(Myl3hiOBnp2**A$F@{Pn0~(t>L|%F@Y&Ocd|>!@l5{Y=%!9gQktUz zjU$7$au&@$UzPJ}){qgkJBl6K;S|@pDX{scJCYJ*yRaFkBvr!~={eidzMnKx#_JT6 zbbGF)S-C)?orN2k>cfDWDF|zy!0`>RxptC<-m zy^LmTA{ZN1S`HzW-Q@&tN755h!`)guyhq;f4INFur0Mkc?X$P8)*>deGP{$W>b1}@ z2GGm}0086O0SM!Op+O|luRpqVWz4b2A9K6gn-GtJlCZ@PRXeO}(V|T){Rj0ZG_XgP zzKc82ioYEfu!wV009w!HB%SbBVP!xr^khoyHnIiG0W>2eks&PMmQfI6L~h@MISGMo z{|T<0h?ltfh=f%xRfY%}4@iIZfxZxE14yFIBjhc?kW9!#U2iN0FS11!9Ihub;a5%g9r6r?CkR*dXA@&_KW2#8xxvXQ6C{%t6H_{TIEz(7_!$H)&UY z^&khTl)d@GMkCQ^40MI}kQupYe;V#FC#I!fLC=k2Qt$|*XEYYkWnExDHJqXru+b=~ z4Ap^>=rWj!u&|IH46s=Y{#|awY0qi~N-J&cInI8{S|sK!M3mGl1kVoSu)qk$RCMf}S4upp@lyNAi(`}VE6Rd}93nvxZwW-SNG(QCz8g`OIcecrf?vpu3aU?wW3^a~j| zVuhC-)m~~%;IJB^r&qaFCg@Mh8E)>F<9}*!b_dLw%!S7l5V<{9nYHi4On%5`*n$hi z{QC|q`Zfi3!QyD==Xc{v?C^;@!n$p)lUs?bJRZ+rv%@x1B;=L;;9A*iI!Ir>!WKz0 z^O}SqWJa}4$k_DB@%esA9^bNbg*J6Asc*K*R8(8JN?607+w^}b1Ak+c7;ah6>yoitFmwa^O&$Xo!XsWZ0#* z7b_BcwLRk+_aFr`3GqNx%^G~qdH3fEmXZ?t7ev$fUR;e6oZgYmU5+z!JeDMXTu>b3 zTE%%ttw~o`n6o%(erFihwoSsW=;Gjjl>9!g;_s2-GZ+X?4OmP@SyGm5?273pXY*vs zuUijg>6x)LWI@!Nc%ahASrM8=D0TqpDz^Aj>e-}-=M+3WZu5iH--`IrE7}vg2TI5@ z^o$^N7=B+eBT=OSE9bxjCzWDGLS`soOiA+a($Q{bIrc}$xOn`JHy^_Z&ld36U_Esp9HuFs`8%O?sB3@;9h}3o zFh~C(sj^jGp=AAx3m>*87KOrx`fMqw^E?xlimR`jZk@2B$MdVFx*#P{mf2?Y{) zqx*ORb(#`SiL8!KZv;cUu)zs(MPw@^ZT?VOQkOfZb7+X_QB|T-CgcqNn>qMYp(bmP*o|z3ayz+? zwvhC3VOx)oOFoD8N?5I8{Y>sO%ipTW2^diN{fV&Q$jW&QR_FKV>IAr3oX|p5;?p5n7w2vJJB*O95o0#C>+Kd8ChRIcXuSeww19FV;yrS zn>SF(XqA)Nzwm7q(C27qZh7S#qyXIMu)ZaW%qb;PxhZtl(MIv4KBr8cIvj8?DA#v4 z8a1UX@+scDJud7BZ%b~qKj_6b% zED7?O47UEe`m1H5?6Kig{pLH#E1TjW@s421{DJ72H}ki_`a!!ZvLN+p=Y1}0jle%6 zzMl<$GK@;P|EY^QWFUHNyFRy3iAPjnA@BIOD`qQn3Pax1CGn>J__t~c*Rq(>+3MyD z^eTquhSEI1`ss0@my+c@ewn&X+cTTGvz(ab-Y&C{iAil`i^@R7;bHADykvT<}2% zY9zA?=wnWjFLg^r%6?b&YK{B4f3TVdsGM(VQTWPwBnkT{tOO^H`x5u{xv#zzFh_nq zaXz^=$Vs8<2h&xJ-6nY?ROR-}IR^`e^HMqt8xw6)>{iW#V?{JpNig&!LKDYK)#5{L zr1#)3Jb)W8_eovtZ(|R6*t@*N^fj|#0Ebi4AAY@| zgua1NiSnnrj-uh6D)#;LOB`D?)c;Zfru!UKq~60SB;hTSP6HON_n!!GiMXbTzIMy9 zLKcnShYGc9nO=Rk*TQzwpK1XlAgWq)m?TyzN z&mp(Y20y-$51mFB&AxShd5?`Vx5f3tejHau!Zib#4VHq9!;Ma+(GC(uHt%g)$*bV< z{cu4FODvcxVdGhBw0i$INYA2}d!C(1B;>R|UH24FhGhUGy4FE@%oZj<)jVdCrg|XG zG@73Tk!KMK+10^e#1AJ_-2}hr{2`#BdhQeQ8eGL)u^Xa@;KuKs``-|A)o^o+T3Au2 zgp=%+XdxHHb`_|32V;D32CfToR&Fvl5nqqE+BO$Ymi%Y3=h|{re2v{`5R{?kyB8Hu_T#r+(f~w`nYj1 zq6dULTLcW&V<9$6>rtMfLT|r8Wo=f~MW5e3c7SLO#(v4j2rsxeYtJj*w{3F5@{+uz z;RR^)$}<<{o#nDG8W6ru_f_eKp0!pi_F}oYr$Xn7bb1$Q$O1>*r$iU6(+hnBfLul9 zaU?fs3B^QA5V#D#uvhG==AV-DyCbT~RBBj)yX}NL2g}xTNSn;ARTK*Zk zsVic*D+=0Ar(ED+xXn3M84*=Ju7g>{B04Ti{lRm>(C6-93q1RcE(5z8;H z8B+0kOrT%4jXnRQdSi6^xY*e_btonE>|K%v)*h}J&=`^A-?tz%r}3g=zp;0b8CTWH z2SfN(iE-d4aK>|g=QtmbBFhQ-{;6)d&9&fSeyDhVMb`drsVTQLbmP9CL$IyAVJ!FdXvv=RfCh=OW_@q!W6FGs&S7`$>IdAhX~Q zv>(rKw(@FNu!ZSJ2L_w+f*mS9L1ImKR>#Bqu`&C@l?j?16-g5xJ3FDECc6p1ESqQ!I#IiEXhdTwI9aDD$S2 z#`G}n{%Ez^)E-Z4iQ0<;aY3bsR`bH(At4vsvUCbp=)YQMdwE8|e6BAy(E(w$GYtgA zRevDvvu2;Ex7Vjh@l7OsqPR<#ygsdnuPEX4?K{vqS>(Z^MdyM zw~W{DjM&*;D(1x9YDm6aD+x|{$9t9HlLxakgOeYJuc(^zl6^Y8>nBC~XxmBE0$Q1w zQ`(H-*>;-7`pASYR9oN?L9~V)>uV$QX5>PKu9;a*e&6D`i^hr7kiO*Hn7FP8humLeN(^u<0piN)004vXCMOZ0o67@Y zTG=f`k4)R}I$Rw-P09JupG#+uK}!sl8HsPeM*U;RTCFpt#4d5WdOz~d_wXZ4Z*c{N zS?{yzX@WVA1@*0CP2QOI;-=Ow@5KMahXI$0t$ip2DLP<3ByRO zfuHb4+8XQA9qeYqEMYgA4$eShy_A{DpPNU~9?KuRR_*19zT2#O zs}>-ud~!T4y1ZM+M5=*5r^h(h3h8J;I6+#5e@eq#lsD&5nT+E+0XE(;+Vw_rtotkI zRKZaFfX_HILOn;UNS-Votb$vEzI^4_@>_L>_PpkvDElZ%JO1{JYcEt%`a+b0jJ^z? zbH?g*Ve5lj{`*!BnEyv-5|K>Y^9`vy{ayoA^rQR8GF*q=MWBq#tNY-%JCO1}uM_t#ovntwEtR?Mjk4+3y70+7j89?VE zI?VWM+9`-#)SN1)e&+NlnL9|S*fAd`Kz>E<#+3~4dzCX}!0GGQwSzhA$S?|L{ZzTR z+EtOGs2bj(=h)N5(UrW2)}a5Nkjq(x^UgKK@lI$!8MK+61M+%Z0dQD#vKPzs_3`Qc zCI-o~;^AXCe-o_F39I(o!&v1e=})NK_}fk=9C4CI1#hnvx@Em9TkWg*88jy#oSeb+ zQTEQ$TN^ITf|l3qgTRLWfu7|6jSZxy4C?Z17&6b_kwqt!oJLjhgTUWT}{Z5vc^XUkhrO0LD z#H$ZyJXN$u_&=kvA~-tkbT~UEf~;Enk%Y3{;Wk>&;G=kI6O0-#I}dqr{qBb%?d27) zOhpH-WAwJ_No)dfz4J0BT?ty+vk*5TQMDJLwh-_NgJ16aP~F;p?;w-BQ8Q>R#Fobp zdxQFsv`u^W>*P|O==5FBHDoOZGwkM;Rwx?Ki zTd!an&-XrR2Tk5}F>bC=DC`^-B8N3$RL!%Si=b}u2)yWY`HrneUV`pgi3yDmVjzQT z^>3T(w$ksSI=2^VI$hC)H(&)~X>SE$h7cLM3mXIDpW1`Z75wo0e3sVkL(}gll+L{n z0F#rB`+JSIby}7DIO4sdn|F79gl@dNQIktfK13VYQh$Qa6n-^qmo~JcCfgkafVk~* zx|Buk`}|e|GNqDTzg`;3X0RS)5IjBa*kNL(zdqa959z#-*e+$$FL$%)_0I9Mf3G-| z6jnJYsaNQ-=uW9MXBTZLHc-p%MouQ~9M@*#79kL>`cS(iaoLm27fjJqebhin?DiQ^ zhdxBtjnMYBLqK>Ln`xl~Kl}MQdpno$4UsrI?$Gm!>hksW>2l)jp0|)lus$QO}QZrgPvZ*=7? znV`;~%5e-R3xx&o{I6G$U!>9w|8g+UfPP z3#ds}Tx3}HJ%BAk-V1bc|Mx7fGEwk)miDqqzza2I_1dU)8^F}!P<|`oeKrpzNgLkl zk=^z7I!bx}kZjj)(}R;}J#fPR#?@Nn$I+p#&{MThm#(99RW@w{Zh z`Ml?ac;`B#5zLYpdE~E(B#uCq5T?<>n4e>CtOk$j@t8s#N^dv$4>UE z6&}}~i?QDQYRKnI8$2ByScjFfj_yRL&cm*B{uc{x^W9IY^;S6k0rP5^LGcyqF)b4G z)RMJrw>9^xPx9T#?LGhvBYK9nE7ZKFF24b_bG!iTdtN0-dvmIR^@Wtf_TPxGwhv~{ zmZRUNc^oc_ULpOSi*YY+&ZPWZg;y*9HRsaar>8#m`y9SuQm|<8N)B^+-dG2y-oTEg zz3hvXXul9f-FED^zjhsr`RU^FZ!)XyTM8Ew8$iMOV>($#s^~Y4c8@!1YiM&DKmXXb zJs0;gwT=*~PY{Eg?5&?8_0}Khkxa2kw>h7d88<~LJmEJMvw}|Df&7=@^oy@$etog9 zUjlrYntAIT)T3R=v@VKAxE)r;-h#5DRvx^Ft!KD5l%P8gdp)S4xA!aj;6rN=s!b62 z9eX6~w{Fuf24g<+j|<;Xkw+=5KWS+1y%KHQ52MH~w_|z(mqls=k6q*XXjR7ltRFCn zr_Uaj`0^Z;YZK<`%vI7NU*3GGf7{Ti;wS(ZZ0Eaq6KA&`GreAhR*VAulI&OiJiB>e zObBrJ*CGNCmP8abaT)8kqRnarkAaPw+i1isW}#;JfYl?N#yhfbL`G1W#GC}C6{8Q^ zmpkjeEalfo{n)M4mMoDKO0%Ad&`sI%-UP3Nb=h#~or^08=5{xpkT1GNAxT0Dw$X6413=ld`eP9_zUoZrGhA|m$s+cZU`DLGkdkDJfTTqO8OkTov&&Yi) z&`I944bHVc}n;kc%1j%a5(DOsdwGeL=MM$K41hJl&ofiQk2tPE_PQmOi^lD8BvK@B~ zrNH_w)89cByy1PlU#6GCEH&mlY!E=0=8X%SUXn*L;xQh=k(jyVqSYpBo-1;<@g>&3 ze0Aa%=}%c*Tiz|rGhP>q=$J(f<3*}>mp4@8_3&z0K5zohF1o)aQDUn6QYH>KTIBXu z)XGTT&F0=ac=Q4h?^=mp83!tMHF8!XSwFf7%rUf0joWzY5#+2>*B+2_atu9t#99qDLBM^G&(2&*)2kH+RL-;WuN%8ToWpxh4r)G8w&g-4j&j*EM%PZmI zPV1p3o)IU7L0SGk=MgY*$Y(=bUfR@WmSSRF6VPY$0)j&BL)a>Bi4pR{fjvNZ6f#_` zz_444Z@*2=xPvCqHY#y$vs$ha=xY=9Z`u5ZX(Z()!MHbiDF!a5tpSQ~!-t+fl>voc zb5?9Wti4l9jVlE>=y_LGEhY&5V?eS$)09hENRNOtg9THzkMz-^lQr1U2Vk5Xyys`# z{U8tN&3@6hAxhNL20p9=xX5N_TezmPPOAM;F%qdQ(R3|v+~JI{t;K^JoVU8^BXlD` zfsjW2syY>hYx)cO=Y|BZr7L>%$*%Ee{qF(o0SjD?&~GB`y3PY~950oIpd5%K&Gq%e zhE?DkrBG564oVDww(GHxY$YyPBq*!q9!d@+1#97t zH65(v%NZd2_#46;Ac5$x#jdt?qo9V^NYeyY4QxD0c7!OCgiy-iAvPYq&9~y@rEvPH zkGg5KmDUubBa`?Rq9aepoA68^LWN zGaehgLXY+cIqUZhr+1X-XJac)YrZ|;T?9GE^i1Ydk&_GW)^K%ZSB)n?H`zkN+)=NJ zFuB`$t~F88owCTHBS0c)!puxoSwGVoK{M?Ec};_O#aFhwLuc#ZrWP-jGbEmJm{X>L;<%tHZDfb5*&zx=EU;`qV(U)3gVc78CigInPt(z2F4OY8@lA zNvzRI0*UwG8$ z%y0qT4#JQ@#N+7X?crW|UM6qr8l5l8v2txHINBp03VnOo0NsKIG)2F9)DiBC*%rT|^q{syC5`Asy1epXDPG%xZb5AR*Iizh-&VXX zK~5`?!1g#eDF|v@F17B98R?*am>Kqc9;@J`K-5k9H*C&^p0{iQP5GrL*9|9h7;X+# zD}jK?WyH&NHz{6+bF$fnFTt|`uuQX0wyo^~8xCP;^VaQvOqpVHRUQ{Yjp*7k9>Q`g7X=M^iiOF;6z-`27qSedDB*-XaiprH%h9Sv2l-LoTH*VdrVyEx`$MLW4H7{PTv*`A93_3vy(a;hykwGNa7RNk1p+rI>E`{Ut_ zTv5m^?gv!-u?xG}f-}EjYzHPfTm?{!u>pj6sB2N#tycuz#}yU+R#0gvz2n(yQLxW8 zNYxdaMFKqjC;V4#?na(4MlJ23T8zJ3GX6UY;HR?H#N!wK)_BL)xbLLb>jgxd)Q;kP z(OJE1p=s=d9LH-JL?RJ7v#fjT%>!4SFP%wIR!{>_nmJNhMS@)S(cPsQMl zrT6$ZF9qm>5;@nU^?wX zZNHUy-h$;1?(hi}?sp^=g?V~CF@1J7hjV-N7I@t?%I?(ISs&Fs9t4>F6>?{*0dBmy za`4|z2@F_$V;NjTSjy{38QkZ?u0d7P@#8yvyBBDD`30$;dk)pkcQRQvF4Ec;oe z^-~F{GZg6X>VBwWJvLBd?yEq``kRvX)mF)64&fV0PAN2p6CRJNJlR46lJgn-auMC& zUG0z9t3WlJT7dwTn1PNP5ohoFg!^nehj<6;(bJWfo|^IQ!rXFIp26|AtJn@X>nOfk z9p2XgwVj%5IYV*_p@9##9jqE*y>q7}r|my2z^RDal@gujisJqh_lJEDjL5j*Mjppb z5*5{!u*gC1h}kMSn67#m*0gr|PVo;*v>L|qx<$oleCeB!l6Yp&@YN|{&8|;RC%JEo zgYUaTvRkUFFpq}I;hH-bd?TFfr(aAi3ja*Nkj%J)_O|T--VbDxz=Rg;P0u2}@Y%@w zeg8^Q{(6F{f1vh;&-24s;{R~>mO*)RTht)#?yeyO_u%gC?hrhcvBryovtAK81Kwbx#qGBiC?{y7)90*9j5m%tBmX~>&9 zmN#KSd^kMplYS%>CfDn1WNwxZ{2Ufju$xHf&)`raV?}gseEV;@P;J>H#l!m#^%tI_ z32WZOnYtUHY{eu)LJ<%lwjzWSh=LbK?cTu|{=tjeql(|~(t8<`;-=X{MsWQC-aU+5 zmhF_pEvdg8&$Mks*$7_4S|&4sA^(&!*%am6Jq*&`Ao5i_D`}FxC8(AbQb(N+U0g?^%n+fEexl8S7W`0pU z)zi2CVYpx7tAj%TqGscwEf`qcLOCOjGFG!pX|FO`lPtNz0$)g_Y%U^LbHk+uz~Vo! zo=$=xZhdH*HTndpOs&IZqA>35(ji%bmm{FuTzH9tH|np30Ra(e;{j7~eGh?bOdVBC zDA6BIb|N;jQ=cSMQwisBFSO^}WX4I`89 zNT9j(ZseaX<2`3B7*kWzf=~?!4r?|cwN;H9X@$s=QXvLR#NxGo)+vo3ce(ElkkNUa=6Z;NQ|c)0JK`iBb4^B|sg>rj}IcP9Afc(hb`!IKD%Dfq0A z_3)hoU?f5dMvCD2BjQ#%7+Wp2zh$dooV)SzR4BOY@l0E}=kbGLstFI8tddRO%a|jR zbW_EE{xYj9tkN`aO0v@l;X(R;PJc_+oU$ zG^LlgE^YXZb%5xil&M{3e2T!LS4sYLptIG7!&=N%!i`q&QFWzC;1M>EojRtQZ2rF} ziCFY&z!PpXf>-WBASlTQFK^(EG_3dHj*W0TI5TEsSWs$=24>b8TYLqW$A8s67|#Oz zg%lfM|0*sVm&{pFmW?X}x+x!d*g_XZ@Yio1J~lUk9-12w&AekPcfDd;z6pNec3`+X zO!^@rBMY8e8-RpSp+WbzKlfX!1=>h}3J^l`w3QL~G243Z75MWn!mnC|5pUt6&oyt( zK#qn+9nVH@j3J6&VKQyEkE<~VD0@i!vzIXy)r`(GZ0edv4GOwjzWZC$ImlY{KKr)9 z1Xnqh{A8kLCMkTzcp;~-UGt$-_ndugM+`Z{uG2W=BN;nO)ve0@r@aL3J#(jO^YY#) z=?^u!o6+kv>u54LyrAgLucUtqI3`_h(i;Qgb-D$R#>X^j*|hgQIuFZziNl}T3iE`L z9H;bXy|c>r>`l=4p^40x+9Odjvf`+=gg-m8#<&<#a#VsbEr`R$xHlDG>IVSC<1En~ zvG$QBInvKxK4Z;Z08^kG0*Wkn_`TU7k~%rxsQBIQeuIxEW|!~Tr?l1E?F>;k5KS{Y z!BQpZt945GMADb1L{r_Eb}<7g>KbC|4S{Fhrwi_fHRq|PTF>xAt}6`gAH=d(7g~!Z z6^%GDd2-Tv;_-P>5M;t&bzpV(F76Aj`NiI?uxvr(VP;^Rf|=ZuNC7=Lr^jBWC0?ft zm=YTfyHW8RN*VMN_6ICP1cMHiOK%+sxnoDY2tLpnCv-J>hA1EL8zv}b<5WFHrPXn) zk8?fcfW*<9tI7{5x?*N;gQ})l*@0i?vX}^>)eJ|Q;|$=GHe{qzl!95`v*uX{hz2Yj zuy}Rd^A^4i{8{tL$mC6zo4}uS#xK1LWa5a z8nEI}!f5>%1ihb-bmW3?=896$R5<|)dX&g>TY$n}Xv)VNbJfk|)^H}WgkUP~i@dlG zGEVD^VmvTmZHd_2(|`|6k-`uyM5^o1yF-!s{4)5#5}5!((z<=7b##7459+OUt@)UwH5~93c@L$8!G{t zD1xLn_lUe6-`2zV&xBSwKm?B=gA26uh}xBF4D~+qqEwMOq9G0mCbqd==DQ!bH#YoA zsxzVSRmQ%TyT$oes90jUUdeE6&jP*HPg|!<{?;3H*JX}2s>DY`V6ch>HujNnC(%SQ$?L1^C0X>v+&)CENueZ$Nb}8IA-OeP z^bej%d>#KFh%~qdkzU{?-*U_c6cCKhKFLAO@Lu z7|9}zM2<52L)MWO1XCK5v5hsI2DZiw@>0RM=K8V*OG_5p&<7@W1SBN6B~&->>v{hlg%Fs-K0|c--h#qTO2WW#y<5!wFPoIxC6KZB~JCC--Cy=i2f3 z^-NwqRXLQ5sVRc(vi1~s984xf-T(FEOMr=D4wb)EM7nQP6q8q0yf;Z$Ee)>!0M&#co3}*PY7EWK+WR0BwU4T*; zCvSG8b!hrm?ImI!yI$Q!z_quCgnSPtYgSA>@wEJ4ax7j1+uks(@yxt)@dmW70@6fo+sq-2z!>D9|32- zeGZHk1y9MMVpyQi^}+{)-TUS7Tsz)VQFxlVMbP|N5T591sYY;HAKoTMjM~SLXYY%l ziCs?BlNXWGV6x0Og)j-1yx~EUz(eoyz>xX3BtrKMR{Icl2p(W|d~Ps^3b9Axx1NAQ{3KV<}vjLvED_{#uy)?fmA?jtmtS zpX(H44(5-cf>mU$;xNp6`}a%}!`k~gmz`n{$Pyr|ixFh&z>aDB7)O5^BZyx9Fd*`~ z=ZXoAHTuLZ_Dqcn|HE9q3$!uEnW~LxIu#|1XXdjn;q<8=@u;m9RYuA28T*pEy^bGl zChun^PnQKzOCmSl{43gqz`dIbzW)3#=K{N8K9TOXi|>N8vcoi!tTc)=i3!7&`KbP;8-V zv3`=u_2g{%RhvNf;`@~+pAfq~&jyt}$ow2p&&r9PFgMeJrf~BmEA)7uR`Sp@^KZ9w za@yg3JbA@tl+_PKUPg9F`JAZG?qxh~;SxfN*1{4v4v8NYEOhaf;iKd&6X@>L-#9=< z)=lsIBSO|LJLqsG6GLsfu@QL$l(4kXN!%2@CL!5F9||tnUCP`2I};Yx$mB5CzIq$x zgD9CNS@>im&#TWAkz9R?;23@@r>m)63?=8!zMyr~o%Q@ngKF&=HWg|pVIFdGW`U9@ zhPxdFYl~8^HJ0RQEN8ovy&G;tIj{ctQ|-Ygd$ z${sQAcO8USFUqI#MDp9pINLBpv;5P}*x#oGcjX!duyd)yibl-rVRZ-=%A)j6nU8;P z!2bL)xamO1ht>iwvldiy&O>IqbO-aEE%H|7lrSU^Cs*!PJy+Zwe2kv2cCPqmaI(`QyK6DX^v0i3H8>#B1hRvd$cu-}vRC!!`prM*9ru6c4 zXHy=ETmsd`gb)*|sA@PHQ=%?RrltFTb*32pfhE2GmA{d7Bc*kQ*Q=&k-V|kKjz+cB z)q20A?E;0sI}1l;T%6vF92Z{!^YGW+$0+X6_Y=!S^LEx;67^>;Mc|FMhllrJderVp zi;ctmz)n%_o6McL!&bQC^PWpOT;J2s(8W>h_>o_ugC8?cZ|j2Vw5onn$oPGNrp{nP zEt;lInYf;G63vH&j;vk> z2Rv=6HY4@DFc?Vb;oq>2IzF<;@5$iM2iqrBS0^$HC~^k*-aj#Iqwo1;goFX38r8uX zN^Hwp&DezUvjD!aC4-9+ZWi9LRif$SZ8@U350`Agkp?P z5L%Z$6VZyT>jK)T`c|u(qmjvawq5Cb!*0%p3^e<<4t) zI2xs8GrrSsE5p;bb9{iqe^|b`jQfpCVr?{y{}nm!GC?5Y+tr6b=Fm--cbKNAO%Zc< zpd1ul!)>-!)Ftv(#3_?~eQ zq*0Dyba%c;KDKb)OhO)IAmmOT-3eL5buc@Tv0huAm+p3fDOc67P4C?be0tT8HeB0L zotmu(NNim*n~kvJj`Jv6Sorlpvw=*#BUyh+yF`H!UNwm@DtQjo$D8;>zd0_VGt#y$ zefZ;VC6K7c^W!Q_v}dQwj#^i_hJQ~PzJ}K#*y2#Pokg5-+ill1IP{{Qwm(AZPphgO zCwO&b@O3|dG*dV5=VpA?)<`*Op;ys~%%Tg3`Pi~*k_NKPYQw!Uu18(&auh_7h?6^T zYvj)v0TLys7$T2v6;4|$`kQl&MacO~(I$#xBpE5(vDQ%IAqsGTE+QE)ovP#n;k;vD zcM8~xrdiE(p+SaY#sdoc7mqu!Y%q)ixudVia|4-`(fV9hXYhb}NjDJl@wk3rbWyRg z#9i8IT`5njJ=0&PP!B_>&1hXy*5g`d-{fwMxYeW7Zm9d6nXAiCv25cd%gMzl%h_h? zCXX_p_7V!Bb*Gq{Z~=GY*{*G(?;A#>1oVkW&b_cWW7egDrkbit?56KnhD5$eS`X0)ngqI_cMVW~PbsU@uYIa_w zA0V#U<`^q;0Oo;?nCMrs&|8-0)QQs_kTT>{k%AU>H2X{d$%TN!Slv%L+WQdDW4FYj zfBgp&b0l(fzzlw7FGH6~9oo}y!I+Fnnj?SY0dJ^(P`O(>D|$sM@;CVuR}{=n#l_?b zQJzt{QoZcs3)P1==uAAdeZ9Bu0?U-7KzqA$%2)7ik@n@jA0bFLb<`V%iP`ld;<&+t zCIrH5UQGE<@%aLu)<_NNhI*CdArJPw^sni5dA2`CK3~4KK_+_DogszYi^qHMhxAO7 z;jcf(u{_`|>xgX$rL$>*CDu&V$?w`d}#^%+28Wex!)RYO;+`hN2>|LK% zw~}!%=lldUS~Bix&J+k#KV@!)T=DPz4M;i$3|7XfhuJAxpkTlI6O#q23;arVzR++q zH-f8&QUdm$(-`%oZZOb!KOr#{{T-f(tZ+GQNWjVI!7EpezeJQIQLiGIS#O%=p5#zY zWB6kz#YqqVu5o4jvo&=f8C(Q!!*0w#&%D!Gd_+C22SF6?Oy{Rs>RK)$0XYfxkuiH~ zaN40Wh2=y2z6zk`K=H&V!C2fF8h^dzh^(~YjYqQo5s8TjnZ1R-jS3sS@K-Yp^jiJH zDr?VLOaac!zA~_R{SwONk#_^%?tGi6R3PF$K{10ERDo!b4C3|!ahI=3JHkNDSNoiP zS)kV!C5W1zAaR&v|B?ZYa5jz+B3fElx`E)%ad3tXdj?^t4oi##*9iM}4q9a zN?wU--bTVx=Tn*x&-iVugt&19@arF5?i#+yIkql0GFgmxGrza`CJ^HMje4`J4)>kY z*Ly-OG#1iQZ|-?@)F|_1(V&Dg4A!=zhcbn1z@D!71{WO5!SUA%IUfh+7xbn&?TP~* zT&%|8gzV-GpsYhHd`{Aq;2&i?>Sm*-QlA@mx4yh-qa6C%hW&vq1-xNBQau@e>R_Gi z)XtA9-6I&Ca&z2TYcoEQYHGpjZ>2NpA>Fu_U8I4|FXy})!nld4JddC5*rHgPF0a&= z${jT_F}3QYMviE|xWEUJg|)=;255nS#m%a88s;Yr@+A!NMXv1eB>(70Zd>0mE86+F zcC6uyI08YxE>gA}k!3O!_-^$gcLBDh-l}p^s{~Cy5r|!F1S7B2Gwa+PSg4Iwnwl`F z6M27kt^|Rg5Uj8T2+*vH$s$!QHO2Hq(Y)Vh;Tm+W%qR!DW-?;UXl>@h!A1tG33~ z*tY~iCa|TM&iso940(ly!0&6FBhZ+gAp4aDM9#BiNL6KrDRoU?))Aa|uL*xwDZQ=u zLFdbxXw!*=x$xHOFAPcm=344a^R8U=iCh)W!IMC=C(b1v$l0LM9UD|KdtP~fFt0y> z9V&GH1qTVq;&9R~LQt^~N5b=x$`lRl0-a3&oU0BmVPUOHNxEJz0)Q?6oB^;4QLay} zE)}?id`n4$t1PWJb!dz@HRfNDR^2WK2Xo1#1|6o7HFq5Bne_Scayy4e#Jlt)8wIGl^VL4BWdIO_6MER?s$ahsG+H zOl^H_^#jl%`)|FXD&szOI!^KLr}N?UqgJ*e@M=~SMT(D?lhUf2-Q)a97&mlXo-u5g z_XKQVpe6eOJAr$%HKBe0pTP505c`2P!bea^?b&i-8D7NerM^3rJI< zkQ4xqO8=NtE1BVpnhE;0sWF@Vk)zf8FE*MnL~I<9;0QODY61UK&(2|W?+3}nQ%hb( zqnaW+JanUk#QE3gFv5GaefPSwmw-DHLIR^zUXQoC|Nm_hu|UQwwstJcoQ znKcbLb1n(dc!cW!u=~4*-BZr>;B5VGEU8J4({qZZ=SQD_*-!%>dg$P0-Xqqy_AeJ8 z`F=zV3ODq61J8IF5=DLb0@yXenUL(n7!PIoBh98-#5eggB~p_=wja#5_rg>g>;0bP6;Vmd@+#El&E-7+e!c;Lwn0WYF&n{XDW39o={z^@ z;;rW(X%OFhO9c#0(YZ|;a33pHW7vlWi?Z4{MM5X8&tLZ|N-9)Y!H17NH!#Z3dA5J? z;NJ%^Oa!W(&zrm7HEkHIV=IGo0|0evwJaEQNU_ez(G+7R-gj^BcvP5U5%dMfm|{RG zZRvN0_Teg_>b}35yZJi8^xX$ws+i-rj}Pv~6zYQc$6;T0+$l13;#ED|Q%IU-4b0tV zy*8Itip z1SXWdAqi?9;n-^I`gGZ$5fPD|r?-5cT=uk3YNwgN73Uw%Hf`l%BI_kPXFwpMZx^hh z%d4ImLQ%xmJWxzjsW1JD4Qdc?u%6{ePf}^xH?-)8$iD;zL_6iLzFM_Y5F;`1NxzRx zkJk;ir}U(xwzW`qVV1rSMSYocABM1O@D0zZ7!h2^q9$=AfDCR204O%9P6vp`5^Hr< zvXA?-Bz6?Y4S=l$Ph@7&$l}*s%~+InM7GZ4wb9q50a{a(9)iy;K*9nDvDV9ki+?DaZV^{G-u+^wi*)s(U@DnK~`fT@%KiIOO7B&db-s0CD#Ndvtq z^eYz_h3`r&76Addsf`b%F2Hoc1-5wBg^N=fNQ^~T-oH4e(e~Mn*F=~2gOG}Q$(uYD z)I6DhSP9H1hgs;HcZ!ExiW;g0ZzsmRZ2WkTShgvSHw_YYX!)tG#OF|$TAiAcAajc= zWF%T*kjP*>FdV>e$U^#`mTzjv+j5VYoagY@NB5ny4btr)}@5mF>h99B!UMaj9xIm zKTw&-qm!0^ao|~Tf@Ix*t*2~St;_;fQtqIYmT>SYw~X#>?juB<&s+8P&I>S20(K^o z-m7rk>0<*p_=_w;9W8c-p$d|;5)DO7v!15I%csTnX?^*FPBYaW@bm}NzUerq&JVDg zqFe?`&h(DpD)!Rq9D$wzym40CF*AMY2;qQ0ms-Dh){?P#+jVk6ee~J21G?lxS!QRs zI0q1-2O*u$Wg=&)onp0Du{~?QD1pHMxP;NnY;>ks_1hSPDn3LL^l0HdavMUfb7cur z1tiiFi?_IKOJ@dw3C&S~lLO0$5x==`r*YRX$f4Q>Uu)bjb)4Z*$s%X_Vx)l>P7mii=osBdy})|f}=S(kr26j$4kBv z@JXs?J;+yt-MG^HyG3lRYkOw-V+EHjd@VIXp-rqlE!WB`UAhl)`Y=#B5YwtW7y(c} zaEIw9)TmX>`%0m(CFy$6;wUj5(YrUNz~QwXbmDd~zTyX2|Jo9N=Hs?osxxdKF8iUw z6t$WROXFJqq#Q*6jZr%B6EY4Sepe7#i0Qq}LtTg@9?q8xj^wVO8k8!Z&3g1p%J}}Z zyvaiflC2ceUJeZGv)N~cpJa8vTt(1;LI3QcVtR@NHY^RlO9J`HV`owr+*6L?v4_kf zSg|cam+3$*T)P;}edl>6PGx89tVO;H*Lmi+U+pATn%2fwj;)7LSV|uWUaCY{5ct-8mY+dt=1trQe?@vHEQeNR=mIlt+@^#wa~ayYzi--bgaD zxBkuyeI3q67LXj0JdZX(BIPo`dBsBYOYKO~Pvs#^?_m`YV=)mY5Cl^^`AdV)MXmjS z_=}vhs15Vdo`mzXsvFKQ_p;b0w3yHx0~P}qvpfwfK;2IcnKy-}BqeLjsMKqJZ!n2vn1(>Fn~{&>eijcfU|A-p z|G=^h&8*76GB{YEp(~0BcggBGS2q}33aq&BLT-N8mTjpd|4=cI1uqSS;Zi(>#!#is z(WKB?o8(5w_54da4!o)7bDQJycP(ns-}=IzA|NVPtw!4|?U&qRa7)kdSb@M;HqY=< zaz3wvR=z4RP~%SE)(p}E2JETl+r$Gath}y!7P#a-eG6yKJQ5?vM~f3eSq3aI1M~x#xgp`a$EH>QNSiAK4H~Et6@vO@e5gb%aHDNYrKv`Q?^=pU zRBY)0-Zty@&5%fC$#jEohm*cEd98?}RmZ?Ny3$l716#F-^}(k2F|i`tlf5nLc3+2P zJZ9N-Kvy_t;evU`I^*JYZbrHSUnOa79U2#{6l@O92t1Vi+hrd#tfVJ&N_smVp@z1# zKE!bkJD8EFIVDFgfX7$nss30%^i#u0FI_gqnJ?)PRbZ=*`{lKv->V2TV95JTtRiVmr)O#Mm$8Llx@U0Lma* zYWAY^tyJN~R60dj3P-YlaR(SM2jBZ|dVqA*j9rSgO#Z1ZgKJdfM7lvlueEV<4;iw?=s+`c>>wx7#iVVm_kK`wU z`A1SS4*pFmPd{a$r4^y6Q(_XaE%;~6qHhv@k7vt~!A>b;)Wwp7W1!71J1Mp2nB-_J z0t0aYn`A2bCgTv=Gtvyny3@)UL`(+sVOh%#DsjcDkQxq_)t;Kv>%*m~sb#pM|CT=)jrb@i( z{gtsTk{S&Ln-Sxt_{@`M6lyrIP-ou{I|`{-{#<_wrmE)Y`Wd0b@G+BJg-ZPo^7%F0 z56Tw7V+|0B8}v+PF0r*xLqotaXG1ccHso&Gpz=5tIvV&IyDw&I6r=TY$bWIw=qS?( znA%%D7D_avCC9@Br!{!j@6$E8kTODPtIevV{0V$X!OT!16v4pC%u&3|57qmWsmA-m zI_4u+LDDda1%T8-mstkL#>l71H(Op)d~&k7b)T?sVYpz6pLFE6b0phlioTeX5CR*8 zNYy_mL7JdNP+53Flj(k|=BAQ#f0kqH7$~wL@NUSI^$ux#jJZXkac zXSvjF*_fp41vW7(`VmT0A2i-7@{(NQ7~B^57|&H$)7)1f)8xdan!#83L{s-x^qpgsVgCbmGyt z(KTgRPW}OaD*w`H%r~IG{!4#gYB4SNIeEl7au(52J(XvcAdCP%SeymaQl}gF8@Z{Q zHxb+r0s1r%*>!a{LSQ%clxZfN8A#R)MVQaVM97i6k=FUjQs zYBUD{tQ8Fy6TB{TazMk?ujIG@KkoiY7>LO@kN!vgpyk;6FEs)q9c?6Y-1vI#n{ zmP9$+-vl*>=Spl_&g%$Ylx#3Lke~%HvQX{nA%b&r-o~Ov6LsT-g!ah^&cM?0EV?nt zJFYTkfxcsw){A)2SyT4I*)vu(dHwsh3mv+)`aJJHJXV&oP_vqL>mZ2+T0DqP9}uO^ zWV?s);dG6^M%s(E%_x9;;7`7gvmky1e8m^VFZw~NW-i93{Tedy)R}Wnm8DbC^I9z{~6WtZJv=Hx}CEnQ1LeSYUT9HI;~QFL5lIAA`t*{{`BEo z%k;~bBwgdrilvO@D1h~+L}iA=Fmm7Y0U;dX`ic*rNolpJ*UBS7K7oH7w-fWreUJK7 z-pYk_!O^Y|Z#GDt2IO(xwc9e5pTF>zOgKN(jM6M_SdZDAI1wk2RU9$S2Zz_~T(*Cd z57*=S4tRkl$LB3K_0pw;jlhZH36~d4N1Y&KO4A%J?O=giz!JBC56vw9k8l=S>WK;5 zZ*i11v$7oSxmMzQuHwL7XbR=2S#mKdV$dw%+18LPWGWiM9+0v()C;hoPghSIF_?$jQ zq~-BP8q81yS1|v%^DU<@?=S78wG5m*_zN=>;rD7`m~RBfv#kN$jEps>8vD^CAr}bD z{=@y7(L92Lm0w}PCdR6}F9?nQtTc`VJSI8AvCX?dJ}yAv0+L%oiZzE(9R`tf7P+%$ z2q-{GBP58BNN*oaWXYT5&{Q2X62VYN^L&5kMOr&KHCvR8Pe~6hZ#PM4c+8HF|qy%s8n{O28Guk?t(7?& zz*UDW$NX%W8u48zL^sTG<9FrR=ilBfDmpX!^?AIQF#=95gMwpJk|{HPLq@M?gInA` zK*qvFS(=)SWL``R3LwmyNFXt2AnJ_cxTF#vvGb&iYr6m|*F}VfoM3t+-#H&soYs;> zciOrkZ=ilxF5OD805CTCk8A~k+X(;_OekeJWYVPgS#HoR9#7vGKCIk7o+A!mEIt*E z6{qTl&c?G$)-Y=faJOZdnjF0R$|W#&A3d#i;61fesiSiYYB|m>RRbbI1gzk4G{Cb| zV@vecMoR%Odn$fDRu)^7KiuPeSE94&7+3bj1r=;rDsKRtAgXk<)z9>mw25= zsY9^(hhaOCD$`jDB0i@L5*0fLZg?JM%A55dnUm$4SLfTp#)QO>H&TQG8DrJXsgg!| zHSk<`JaS0$rC{{We*u4RM3IK61zVTRGa6-{h)`{$h!UX%^W)!%_FwE z=NYf39JfW?TbMy`5o8x!zOXd$|3z!zOnz9l(tyib14vP|s|g(d(svo{SOTgIgA%!}T#`$ABQ0`1@R_Ro3-JZs^w_;${fkb_GlTu?b z`!ju0oSx)BRZ<<^X#e>Q_oCjQ|K8Db@xA?btKyDdhYiwHM^d18h5Re>ad7=E>VPHp z`^Rs;gD!hlD_fD$by0VdMYZ9q8`#M1$FB~leiWg=&0^1JVUAx`nTBP&`hI(quiD=1 ze9OjT`Ov-c`^S_o!r4WY=}Ikbs?}?^$K+ z9eVTN&iXS5s%A5WP@3`H#dTageUGvy8C7+rH`A}i+qgaM8YJy_<9L~X%uh`whl{rQ zX#g7#@UYEP^$ljT*&U5XUn$Uq!(!a|q&A}Q=1-iD8?FLDVH$D~SzfK@OC%&5EpodA zJBxe{C9vA!+|1!COxae3vU}fxk5N44!yr^n@N*E;1_Hd_&^NtIi0Tfct>orzd5o-~ z5Z1S#j;%}Z_5I6;da*We(Xxg#N{TQYd;hca=M2d00F7B_2%ao3!9D+OdjsMMhxAr#+1Ox3EJ zVW_??gfJSnc@Og0y|^3Z!tnjw^u)GwKZM_JrgjMsr(@p{HeY9Kh8JYaEC^beyf_6s zx0fwZE#XGd+kfAXZuh(%&-#8u*2i6sc<4C)Di#7=Bo+0#ozi?+Bkb~iMeXo>Vot)Um=-t|CRj-XYI1wFXM_IRwAJs8K>qr=#5 zA=rUX)xHwIagJnd!?bea*R7a6?Kq=5C4nVe?-~L$@o;50HB>x49}0TK7w|hrKV!Jh zr^_KjvkhRqX7_!G#C53sbl(0pJn>s!C?ZQ4>it8)|%}XZInGF3tulI<@@OMBwt_ z%Gyx%PX&XR4xq&@T-P2lvrU_ij(h(ZhC1+P)Zpqo{UCxUijOf{Gv1d&bTo-3Qfwz8 z=RKH zbQZif>z}<;JdlCaA>DYpLN!sn)IPF#Vt#W9L9voIIz+t~G!2LQym2eAR@(wOo20Y^ zbuZvRO0vWTj#xMSaTHA8asOebu<9H3b1jLy@6|4I=j($9tKGsy*&x#6JJ#&E zxk&l>cg(vdtis!=Cc)}vp4beN+t%v)Z_GVtQHKHDt8hhMq7>hKLXXchXh&Vper}1~ zik)xn9t_lA4Tve<_LzRxR2U9%UOrQQD|}`B_LgY-*lBTzP<2fZnGv*l*$PE{@kVe# zI8UyP_6mCAzIf^8dfOJfr-T(cU5jee?22f6uprZdI$XQ*+fBUm!q|KqT<21WGpdn) z><8ZTf$ZHG-l5HH21cxl-hbiOO!(ai!$>&8^~T~VT#zTA>-ma>w@F|rD6&^@i1Yo` z^$T>jNZHi|(?&q#gD80Z*%Cne5AH!bKAsp|?S-sP+e6u;? z$6HtGt3LZzVw56&P~|OgPx58=cTSQ)_s%EN0($=t(01(GwW!C~R@c^(8qD+MGtYf$ z;b-+W$ERX}=!Z(~s5ZkX(c^Xq_w@#R@3+_Nt3*>zsU`8y&c{UpQc0U0?eHOhM>}LB zBV^^rCUC7u+DB#hZt+zSe2b-=M{&q+^Ys#Mma5xi>2YRi`}MFR!v11X$l9m*YK~NF z3iCa*>fI76w4OJA%Euf#kO+wKqYrYsW?CJ#wM~J*$6_9DmxdqUSlQ1o7bLUf zJ?Q)opTE5+Rt<$$@kPzB@r1J1Fp5AnJFd??g6!7}3B+KkYfZX!fY(0E-O6$da;s8% ziymDFL|pp3gHo%(EIXS2Bxd(NOTLqAuBJfeZ47cg>BzTyy5P#@H$TVJj=^jmBU%Ntrl_34Mh1!hsTA|U=~%fXNHFvQMhOui(WNs zBP(Z^e#__b$`uccka&GOry{e0n4V%1iHjGTYWgEM&H!R2BH_l{;^AI60}{mD3=QP1 z^XA_N$xE)AlvKI&g`Gw*uKlYu`@knYm-ezBn-a)===(4ZW-mpnmEIjXu#}i%}=I}IUmpS(MMDR>v>CeaJ&LN4n$7g@u&_K+)Quc>(~q`I_Qxd&fhxEZu_4KDVC0hqx$zu#|@ zV-Ow(x%`b*P-Gt;wzsLd89U1fSH9Jc(7dk~GOp8L#dP+5+h)==iX|+ zWm$wuPTC5_a)&R+eh-dzY%hFu1oaJe0x!`+G}eTy)W|Sd+RaLudGee2VgeF^&6$15 z0My`2kVf=E#s~()G#4av4cG`Atr0Yvl1Jcuhc zu2A|?fdRq$)McNO;}nIVAd67tC`M5&&jznp3I?g7z#6KJ?C}Pa+mkM5SF&iyT7!7F zy-*CLrhaSGMTyfftbL%~YQ_ZY3FWh>q&@~v~tadNG zke?{IQhCvTP7G2{qFQW4~lb&A?c&qkj9i>sVfQemU^DR3h(L6?Wtl6dF)PSy08$Ezuw{`OiI9Pd zt`_P+WuhTwoG2z;nI07s*EJu{)id4IS$NVccIrcCr~L~1?V(MuN3_e2gz4M|d1z-q z1;HDAgiF+3*XRH|GGyA@0B$5G5t)e7nB0#dw!2irlB-WE>@5_CYK(8L+Rm!`pJ?7{ zjc`9pvUxPbFJBiDiQ?E~v+6!rH8?6j_Vq};>wFse9*1e+;m1nK6NjPHeCbZY0IUkR z3d=+kJV{n&b8%h>^A7qx{Cjm^?G%@(UQ^1GxSKB@eXQOsp=WG=B`8No(G4kajghW) z!jl=QHnSZ=5{QbpkG3DO?ePAc-p4I(3etIH^KJ<^ei=Km?m zgwKOy^7s>{R|DvJh-84!=N(cL1?qfi65^=qMFWY*2g`oXoE5tV?L_yxI>SP-i}oYE zp3n2X6#pCjAR)Kh6kgwbX7>W8t(dMfQ@a_%M!Uf0cMFLLFAL@&9@fFDHCZH0!w!PU z)jA`lNnLD)4nK5C#WSe3x6gXB#mRouARxaSK>>yMBi3F?r{;jKxQ@|eZv-^$wM(T{ z$!$*}{9Z%?m3gVTTJ5!7dkqpG|8=zXjc#MLj_`rh?#pG7*v0TJ-bEL-rbm72*EtOr zhPxw{%U5}-zebMel@V{4XlACy6%2if^J*Au@j00|U`2sQ}8W9AMdmVa*TV92P&`@({PDb;lec z={e>f`hMjnU9H6S*lv-S)UwNwA7@7?%x`uOZ@zVR5Yx0D2#HZBdTx^zwFs`HeH}K5 z<*mzT{Yvrn>^JaGzv{4x`$iCuhoZ`?wcFLV{=j#M^YzMxKj`&=KZ=3$mHzEPURy5f z8@S-(+a+3++nqT26?#C^=AE{l8kT>aP|W2Z)B6)T5zT%a?)NvsO|QpHk4=ltD0gj` z9Jr{r?eC8pk(l=~5xz)*?*r)H&Q$%P%dV~ZAJ!w={PfQoAe%3F`J2x>vinjXKGNHf zGTmN2bVg)k2or!s8uy*MZ)bk*ig~{|MQ;n@en5E{IApC(g^0Frd_1<_ZJY9p1^ZQo zlkx45_i>_4(0}UXj@JkaI;tQ141bI%K&_s85gjRt@79*@adP#_A{%G;OJsF9y8?>E z+H1n#@7KrTXS+dCzsIrW(Bn@!7~@^~HZrKV>cloTe9~cA}{jHS|P-0zosPG<5;7 zGm0-RR07iroMNUoZ0Btk^epDk)sf#?WKX0(SX-k&bl2c;r*2VIQ)JGVrHcwdRp$F**nx7`_5Mwgt~`Ht@mQX?gi9$;tPSiIdKCdwJc*!8+&ia&fhG6 zPRny~Tuxvquzp4of*SO~rrsBHUXJX2LwD;mKtU!_&KqxaKG`tU*FJ{#nd`Ez@K)d1 z#eBc;2-f25q7;8L=!YZ@@z(f(4?)K`I58Gl<5Mq%dpNEV==Tm|-@^?ufO(oNODzxr z@|bWDQoByquHnXwCuIlT8-?pvqW4X3a%HbLfGs4 z=EPz!F+=`>Ct<|9<}?peD?~|(7oIQu;}!q_ynGO;^@#usLkThODftm&7TMQe3o(X2 zx%I#CCPp?}`Tqi+Q2$q066`-=DLnoEgtgw0seiGF|1YrAKXEL`|9eya6D0P(YwDk` z@js$#|6^1CMA!bm9{Jxj^-rMggCM;=_`ka`;$gpyp$h?|b`j!ax^^-I+nHm^} zRWB?7YcKS84IJ>J3X`;iC_7w@_Nybh(bqsYX!|cE5?D3{p(*pZyPNoY5IHOewaBUyWoUzA3VqgBo;|+BqR_uQ z2we>X!sFyPBgy&iK>JNZm~%JH19oP8o5PwW!{HkjCH8i z*LN@GNz;!(NM?D73*e9NVDp8U=9ykCpJvVke zvaAmja7=;QJ=?e_G0PALcHrPYX*j-jip*d>y+Hugo{gxNaWxBJhH>t`F&>ERUD94$ z2-TO5122BFpTyLdKwqfe1wsi5Dg9}tlsrL6fk_dzPW?Z5;AQgm?wo%UJMdgc!7Xf~ z(%d=@V1&!Cg6m?Cc6j*`CyFKwy80R#gPtvQx}W`>rl&u)R2*?M^qbSTug zKWOo`=yT+e$`6(nIL}_-@K&L55n_x12`kVY0C&=R`zHlYDA_c+2q|{JpM0`ud=XN7 z$5?o$Jzz){u$DuEXM*iz=(Z67Eg&Exg>E6q(`=iC8nkaaF7Q zq7>QRB_?c2N=Z=)9#o+KibRUej#?R|kIf7*M!Kkg#Y98ep04Nn0uV8`Yj#cvxKM06 z0;Znr0zIQVVkJx=M&U%k;7ni{YWkFrX4Vq(R-a`FlE(d$c*p%vJPl7OR+xRyjcg{Sz1m#@ug0uRjj zb+;F6I3_RGuP@UtG|?a2 zK}wp#_O|cqRhqe+#g@`Fs@s6u1GZs9iN#PZ^76*)&fylNi3A9gBJ{GRKEEMzKYsch z=SP{|Z*{5=DkJL@yDv}-1dh4Zg+Y$(YHz*T65de0AM? zYJd{`+<4S9%;0H-hLpAMzLWvBay3AoBinoBs$~x&`2h={1|M532R36j@lVu50dibG z;hw=n1N7!z3^|Jl;Jk4=c-vau1Sr$Yv>^cz06_M0NlZzY;Y6??%F#9$xT!kedt=$} zk$=>1^|V&k)T$bB6$%0$uyn(jJUFJA+DiYNo#M9A zb%L!U|KzF25AIo?6H&grBPoC&MKwUM$z9Xo%MUESAXGp~>*~q?7(Tc-rIgJ4jM9)# zVjz2Ya_;y$wl<`9tEwPLUSH0HKv%}R1OizSuGGz?W!a1i&B;o-+kdk8B(QwT2{$}U!u7U5oc;PQ7m9CDD!Y{Iie}wBV)N?y z8`LnCD?-5)2Jjr#mI`HN_O9*4&KhXf~DcW|OL+dx{!4m}Cb8DKvaJ zjtI~{5gT%SecR4rMpaK(SA1?p2Q5{*ZYQ8sEo)2g;E^_^?_ryJXW9zq4Rb3R{Ci5} zEUmGBB(Nq?Q73RQii?VzsE~ayu71_2vnZA*hjUici{8#V4OiNc5Kobq zeknSgn>x2LA|Ll$on`vI;)mYL2otw5LI@Byyw;ZxsD6A{2~RM9;7D$3wtM4KtONci``q!D%3$(o4)MrNB z5b<6(1_XtQ%PXw|p;`|&Wl$0H6U^nTBmMawMNPb)+(07Btz5JpyB-`-e(ed|L zG~!bG^TQ>g4!^qpdF}iG>98O1Il5a--ZAMZ#{M^Qw6Os^^7qJ{Zvw=Jp0IrLXn$jK zy;bk5Ej>ScK->F^^R=21V3z_qjZ$B_2E!#Gb%bBx-#Y{05&{7dc7Jben>ly3gEw%^ zeQOyO;2QJYYh7rrxt>A$MvK50R*o>OgxG!fev%%I0i2mvZna@3Q0AM9+5RG1OYc>} zZiCVK&Y(})>a1RjQmDgnw$kgnuasO|dF#{Lny$Kj$E1rQz=>**#jax<;=cf2Fsea{ zW3ym`9KVH^mL@fF9De$`{?tBo_8{nh4h#7ewb!B>ay!6|6?YqH(dZLb-9^#BS0-D^ zi5QEsMX%~IZ-0L^O?P#cdg*$XsqZL?a|P+Qa_+0DcPnSS``HY+B~eUn2%_^>exD8| zk-)(f2eNzfrpZ7e9CMx8IfLRMSAU`Yt!;-hn zq?fQK`??#Umj^H174jx2%-%IDLJjZjQh@l#?+Tj}V4ddnt6Zj`yjN&gV=r`F%0C`) ziWC(ED5cGzwx}}F79oXTWoOmZ+U!6(v%XkZBh%MIWk@NIP#8^1kPa(ENaQgrg!)cA zfj}20P9d71itA@a*l@T*XNZaG+MkfKnl;I!gQe8p~s=03N2R=z&$xD^_%--fM3%u4BYRfPYV>N;m$S65%9 zd;Y~^fTbMGjsia@crzGuJbPy|DekCjBT@*jRc5|^j*4|_PKTYFckjgvyd@q37iMn9 z>ebZdw6P0JYma)|J?}+&^vb1?`cK{hNz!qS_!>M$Y%S|N{ny7b^HDPfjytT6=&X>7 zaJA=%_t57a$4=7H4WI4O(}yc9yTrb8IdRw{tVSM+HlooUA}F<4Hz2Dd(#gaUnV75dy> z1e!88W%5%wwLRSzKE-HFi;cf~#dcElg2)5K<2G@QETA&zUK^;sv^!f?5&eQ*9t~f% ziFrrw9_0do2_&c~3u}nvQVL+~ps1&=7O>W#qO~I`VoB?`*xmgs%OK@i*8i#*yQnwW zna8RupG`lyDp-#+fj)MpeK*NYG)F2uBr89vlOL2>J|*Ng4f;r%pBCzts+BY?2$A@7 z^v94Qk17{h%|-7Q*zf8|kKCxBQsDHPHMqd;sCI~6j1Z1 zAo)Dq9BQX1wk8IvFK}&bLI({3FL{p+Uh*BC8`m8T_D({GQx4cou+7N})-HKieu?ww zSYB%4Ht&J*st|>H5du(4jaB?7IZ<=0{ z4LT0dvbyCw5tI4!G5*kMap}vFU$M@mxy-t1N{Dh5{e6~R`uYXLv5m&^S;ASm>XyX{ zascI(YS;8nsZ`zeWF}Y6Qk`U*nM-!BV){hcGjH9Erk^_@RXs=oxc;cXnT+X2-gbUm zx~0`2@FS-T{=cnzbm%ruGx%3$1fpK=B&Kte@c6u}y{A7X9_Z8sWGvwIBAO^uPyqP4IG?+!P>9el;wd{}1xS7Piq zii;5aM>kPM$|+7km=Q{HTk_vi);Y23PE@8A_1};keOHk;1b5uAG4u~$GmR+|LlW8F zjXf=l5hU(}R!ubKO^go7Q&<$KJiyv279Y4zW&{PZqXa_@I&h*C(_4mJnLY?6g&&Si zm-bS)WX;R-ddk(t2eLQEev*+V8*<*j4?oltd}_)nQcal(D$T6%p=!GjSKVZKDQ!GU zIX2xq_;Z5jYb8-d`xrH+@DTGL z58`Ibb5F&tmui?x`xS3$ebWt1{hbO}zo}uh4s1HrwP^h9feJ@8aT-fiUQWS2>R`mn z^QLrx3>OUtPEE@Xc5`PVl`4K(%6>YsJD1k%?76TDDwKKDAW&yS_2b$~&;$?45Ezzh zNSS!^Fc-G=0k+HxL}j4%1e$uVQCW$8zJNOE=Q2{<#i1ZRlOR%lvb{`A@M;ke(qCvn z`3#nO?xRU89P-@>>!q@M^;sUg*X-;RcpoYq%CPNd1!V&e48{+>BrW6V7b1_Q0{1%W zql>x&Nqo`_4H)R6etXVMllkn2o=~KgP&uuet+^A!?YhdR%UPV(3?`Q>+RQeWMGSLw zePs>iqLmzZM&j*59_rtpXoaAF;BQR|Mn(Gsg@I*0HTIi>xzXAl+37{G5e&d{z1-2- zzy+xhyYm8LPh-UR`_k-7@iqVMk=iA{>li>YWgP)1dmnXf(FDKY*H#?W4SY_tT{IsT zT_B3fDxgpGrtaJftr}ny_;ZOXXF=Z1Cvd{sf<>;$^x$V!^S<2c68RtwOq# z4v^#jRQVfkDr+BJFkGhXpFatXBgF5RCv_8L2aOet^)z%Qi*=|lUp zuh3=tsxfbg{AzZG+zwxUKSyLU0jzbtNwwHR&r1I#`NSMZY3WH&g1f&gD7=IL*z>*7 z5xt6gqUx?ili21gz4l@6)@U_h%yrD((Zt_?vSk~)NopN zS5t{}9cAp~DEEfcsmI-hlQ4&i$;;wP9eD8>v`*16en_cn=rs{*YIhFNpjT#L zA##Qpe8^hxQhwnjqZ!BeAQ3NC{d#^jh$}Of^br}+c^6k>x5-NVLD|`` z$%9k7HH02W@+`ErXGi!%-I?sw$P_GU)HzEHCb&Gr)5|S{yLA+1$WEV^8`c(X0Kd%)lL!ero50U71Y+AuhW%{XRWxXSLubbY#9{qsXN^t^op948a>-cHoI}`R^#>Y zmpJ|hQ9sL(xfBPnq{R?8Ia2Z)*hKa%oc%@LSv3r znrE8n{WFMpo_yW>xoEw;rKF?L9j|6&_D$}qh)sBp9f?}6ys^W+y( zXD<#AsVhBaXgi&mt2qz`ZWK-Z7$k)FM^qNoVC!M5HZycZDd5Iiac+rXOyb=qV#eR} z-$I(}KU6WdV40Kl*KNklcOVz#ZyZ9vIG#kac==JM`FgZ^8^(@JM?m)l0Jr4PJA211 zWi_m>&Rf6xW0KmO_u<<{5{@lKJH#ffliAc!bwD8^mIh*mklDZyK9OxK7MJ6~H!IT{ z@8y$vq*}u{i@~p&zMA5y4gqI?5dOY2@)cz?DrcD#+sKtIA=wP^6sn=6Wv3x5O%e7m z_tWL@DS>;^$gb&>>Xcy{`R1DUQhzBU4ooKAW!2>wqJu%R zJ75o@z_R@&`lH`qXt>w2bp^ZSG+TV*c1fL;-%3Tm%_@CCqtD!>?PV4Bw`AVqZ@Q`R z8}Z@MTY==WA*#f88F<*esN zf6t_XK)WeS>(Wy9ViqbZStukX3anvHczu{Y6)H|fgzB!O{1gHA%f z)B6HPEO587HHBH)ZPqx=l)}XS5$jSsmiqw?i#I#C2C{iH+LXSK@x&7?^o1#<<81&g zhW83_g5W(+xp{PQm3AV3OQVqf(91BqA1bXX{x~LZSP9 zz+?m=KHE7?Y6l#Y8oGxjs?o%spEqrklfxkY*9jXdmPik#rVYi|uqu}5eUT}BP>TH- z!tAR1xtag(*L5-_*;!US0XH^~(eZCKSXH@)rAud5EU~~0&Ac6isnG54@9cZKMyg0u zF7eRu;2_cRqP0w2xfup#Zuy~t`$-oUPIfv} z2mGEf$GwM47KM8Bww34P5otcZV7khm_r#S9h^2_8^2p;Sa2rNyCDn5Z3CL)d@shtk zMk`f6{M+KUnoI1#xHw~YFg5h5-Zo9miBhF6q5JJyXzjAAMfgQ7p2OTBaIWA{Rox_4 z^YE4)ahP8wCtP!+G>*jwDZd4vVm;5@%+Eh-i$Jml!bP-~2(@6wM1Eo~lgwST86<^% z_YPL>U=6L=YH?ZF%JyY0v~hjnR7p%w(MaLocSd{v>}}z2lqsSx0x^bZu3+6DN6t_= zw(2g%&YfTO(~h&nfpb)|MJc@-!jmi5LLi2_LOrTl?GN>59eQ-pC=>7+D^=P4Y<$TB zx2HBRP|vN=M6_Wiw`N)0)`s2wv>m-RwS{aqJcw4pB-)&unFh#-sqp~pplzBn6AUCd zdd>&tao6Ip2S4-?Ho3KtA-`E4e4L+TW-Az22pz3Bb-_Rnko2{E>bo)$>us?^@sL~2sb!t}|RBzcy|mNYnU2IDk5qSPg44z-dz16MCqM$KJ*O0029*3;2`dn z;*0cp;ne6L{m38#bb}sUd)e5=Y&+OI?@@pFub=KsUo%R*+!yOOL{8CB-a}@LLDa?F zrMU|A{;qzOT(U3(#>2EimAdo!Fu|f84~-+}lN`BldU*B7J~8E4zStMV!L^Q!4f^Ue zm~Jdq)UC(`3|!t1;6N3~VYV2v4RkEnRySJ| z=ex*`OWJ&H=8^@MtC3u8Px_+2E;`>3T9x>Lel+F>RSy!f1RZCB(btc_HG&sr$XRTb zb38;QYg$SA!D5?YfI)M+Xw&DJ9`Q}1o6Cx-WjdZf&i#A#!itItBb)&!*meamQ4L~f z7RzQ!Jnm^BRwUJ z(LFwtJI|H@g)!G1*7SMu2tI1Fuv`S979V7bKOtM1GL|XnE2m%6nqX!YcTnKktV2xV zt9R-e+*3a(^1Bal;o(ZC;b*-25+sPoOT8iJxSTti6epW)$@^hH)V|AsYnW%sBpP#ot5{{~FIc?0y?uWj4-7npmEj)v;hcJfNCNDP zl&UmHGtK_`%3;~j5Tthmpt;Pz)?t`z^7wE0xIDBa94nC5QG+v;OiZ3RT1Oi&)88H{ z(0G(TX8j29krQ=kd7jK1KKsQ$NT?aF7Yne%H=E)&P~7P!rTb$?1@gs%YhPT2MF6g?d+FnTu}Kt=4s&d1|h!`=P5a#*Lz7 zBZht;vsrk3go|Vp^02Rhw$pbeXw@{MuVfB;WH6K!{7kfGs>kS0Ik3ZIaEvmQIs9ydLb2l)$;d)*;?;wND{=)d^i?!5NYJL?XOiYMIEToR_;L3o;dzE^sB@ zIiY3tevATr4-R7qhO>rRQ%YWvi(Qj8OcW;&NMNyJfSLK{mj)p+$>4AgT1B(R!0}65 z!bZh3#*fc!;}tKHS-is)V`qdZtZi~uXY<`UHuqWdoyGQFWyV1AR?TiZI?t^)^U^=i z57y`7;A7#>k6RGsKF)j$t%}wg z-@B}f_-#@$Vgo);heazK7p74TOc}C3IdTYNc*odOa+8gL#uL=Six25=Z#RBseu;sE zDK&nd7rEXsFx-YF+l>bxdEp689XB!HWpKsLw)4VnsU@5ZwtlKO{d;Pe+i(sF#tijc zjQOZj$9_I&!@{+4rS@3cAhm-%0)D9scT%Zy1F>qIbC(X6CIE-~K1Z~e)0-hz1MPnd zsz?)lQcGc-nm&`J?%{!ulRI&?dB_@?BTm$%gozk}x^6n0dnDqMbaI+zB61+`BOs0u zjvzzKdqa7#;_tE>g;w9?QWua2`F0(-GkYq`F-IyBJ9}>eVI(QqL=9)y8>c7UP%6P} zc2aR_B9S&arS0na*;Tl0fLVDR(8Fo$YZRp3kS}J6&$Uu3K7@04(yGuYync74Z3Ta! zCTj6^PM`>VVP=CqS;fcH2jf02h-}`-rX_HN%klqEy18``T?-iZQNT#$O5K!>`HyBn z>L~<<)nFDfEGn)ROEexS{ zr=3`j+!HXl?C+48y!n~=SBLH^=_~o`f2&U1#hcPv*2!|}txWDJ`y2)eE~HKb+Z0hq z{oH&;3&L&S4Z=)BCu?zvZH%Y`pGw)=qJL&rzQt5&3?E4Pa1Kf<(0v)>XJ=^`cFoZo zfP&#T8I)Mr8gSNZ*`RbGh&UNJIk>qqsq;n$kb3w#hmq#yjoVoJC9V=$_#gB=RMohq z11h<=Kr%}WgHz}{xx%G@Z06@Ff5^$RDI9nz!X0*pQtRag-r_TNBZOq_ z2cq%3buy9$9_OTK$BAi95Bgio_r2i0o3*Y$8-T$}JsFQ&f|}ZGj3fh}bZ!T*9kNvB zMKxIim4DVqxo6CpyElwt7#l^aRUJp@l^@5b11?Soy+x!htA*p@FZI-I&=VFMgB;sw zJiLKLuJUVnASA>9dp!Iy1t^ z(V#)Nx9=T!=CFy!8>`NgU8R7VaZz0FPh7fNQ^%0%xzHLPH1O{AQ>i_*qQmO>W!Dnz z-}Sk1UW2Lc+kr52(xNnTzcPcFURH3)ii0DCW3f z{KDy{v9XZj#w1z91W1Me@G9|Go}4>F%*UJ1OHKI2b^J2~Z5&f`mqEXXk3Pa`!&ji_ zS!P&CoJc$NM?6I%#De^K6B+;h&1duuGIO|v0(1sr#V!(z-uwENPZbsLS|b_Ovj@u+Zv$f2O{Gs?Bo8 z0Y4D1X0w`V+OAC*N|2_Resd895E$_$@g8+Qi^dQ7phCT!Nu$cTictHg;?Mi}40Ckx zWu;e8@#Jb~EfRs5ECPsy$*VtQsKzKi<3~?^ruk#}XWL_g2RetOKPp-yIfyNkA{?}^ znv4|S1kG7Q?&I2=M)lcC72|7{{L=o8ymG4?BcT&ToNajZfP;>I@U;m3OQ~N&_Oi~E zRsAAQ41DqCvsTK|dASf41B-6t3`GIp&;YhDbGu+`vcU%<_bc{FO9ecv^)EUw(aD`P z9vMGq%X@ryrDYex`@ZB2U(3YSmh9Ph^}_g~FjPo{%g-LRB3*Uhp1+*0q*l1&ZgELG z%<>zGjUucGrITn%DtqYtyuZj1`AYn+SFeVz%?hzl`hvh(y)k9KOJykYR2dXqS-+vVI<-5@&x@Ms$3)JB=u++nQ`;X zTrEYeTUbp9?D7A$zSd;tNN-$?v2;D12jzaSXCFgR{+#4cd02HU%s?o7jeE&du|AJF@JAHCEy^aZSrJ!oDT2bgrruG%k>oF5M>anuhz<>4gil-DQZ$UF6!iH z9Ythst#Zx~NMC_Eh1L`hl}^6h;S&Y2#I?^=b9Rd(TcdO_VI{giUO6A57i`%0g8q&Y z(M@~Vm+Rw`cOX#MFPSn|s^AGiT)C{?n%#|*GSV|iBG?nQqP1nZZv+0Jl7_?s0DfYk zYjS%bcE!nDH@L#SYCEDZ`T4bI109&Wzu=5HVr;{zKWf$>C~^vi{?dYnm_qEH-x0fd zw1DIfiav8c(6GV<^xp6Ll)}B@#@~ZE+_4yApby^XTOD=K`5|lb;QqLu4V)2rtGXk5 z>rZ6iss+?3dZ@D?7hPsxqrReR8lFfMuQH)6+*AF^-Xa@Vf;QmVH@~@g-!~j%HvJav z*YJH6+<)9q0Hul62;pQY`c}*BS?%{%^Sao9Ov2D82C3@)y>SbH)#neAtU-A=;qOS8 zMi{CAQTD6RZ78t)R*}3fMRZ(0xN|v{BY`p|4=!KCxcK1hM?b6{tdAiYAvW34qIclR zldZ>m6+~Lm0HWs6`PVbX1hb$z#smNkfU7cKE8!Q_A!HdNX3h)8(AV7lU>UN25UalK z)_t~TN|g2fl8S8iz}4=1aN@!9%8LFM5;_}C#L66Yf*?cIn_oZcXhpP%)`MPpU=`7Qm}5o;(02IoNzec`F`=EdgNl2uuxTG4(eS zrmn+CtLd;~(tf8xiTYa@BgeMYJ%!L{0r2OjpiMBP! z$Qw1#0|exi<8jpFdHh}PA&iZsl-osQqnQ0w7GRnG9WuI@BunmYjltE|>~t>Kj_ZjA zOg*VGmQXcAcz}8Z>{hT1(A~dg)7=#U`YAjjTP;kzDBk;WeLbEckb;L;Anw=-dvWHo zQ#O1*#B`?XeTL6;FFq6BI~>CynF!xl*l4V4LjZjZ){gIi^?pWG!HaQ^HEp*gjA1)a zCi0RCU;7~zZKdS;Z8RpbtYW092LPx65}60pJ$xK=ya_l407vwj-TkmrWFvaNaOfg{ zXxu?Wx6C%rmK6d7R1MoSAj%#v+tlk@ipu}0EoSSXx5(l!^G;^+pk&Two}1iDw4-}L zrEekvz9OuX8x9wJBv*YnHy`57YteGd!8@gt zz-*q3&I|o;-zx+-3fXkuoR_<>y_@`M&m|s-NL4|k#u-Klb)X1(p(y+v8Le-LTL5Y#AIaT$74TEz z_2Z(cnR~~2Qcox%u6yzinAUv!uxykispKdGp$T)2|1_{WSyA2saJBH3l zR6%^mGX|1Uu3~No5V{U{@wF=MEt07?K~FOmGKF=wG`{+qw}fUlC$fa6EV|tKC_P&#haOlT%QppB1N*_40aXICR8;r+t%uE%k^5riUII;B1^0@J2pci9n)StM@X5danhTZzUM$s<>^ zkXvfMYf3+=FUP^7+;z2#+Ier*oJ3tkaU#O$gEmwnR`U0fiEG=YljN0mQUuEYgxSn;DQNz6h!q#x#t^EQ zsu+44f84rLk%0#orcQQ*05O<48BWfoQMgVHp%;@?WhXe|&~^doFVaH78VEFe$tdYt zfUA5$IvT+hr0m+zoKmTIsB@4Js#<25jBN;+sQa0eQr09@yGrVTw?$pteqGfUwJ4Y0 zCK96teBt|2%tTGSKREa&&PX`dUTh&5d_1aPz~HIe%=kYz$el2V_9CL9tjdgkX$}b_ z=m!q0c!S`)D?G9BvOj9n=3EJ&1mm%KZ1%{+Z?*S~tDx4Lw-NG#9p@Tm?^}c3N0OI} zAtV8-H{&=XDreUN8E7Birc9i0O2_RRIYM}*G`%SIpuka+lG5jlbv7x<8%2f=u{_`Y zVXC;U5T2F6r^~L(!FpQs#2pV9fIre+u*Hei&E_1h!)~1n-S7$Xc0qV!;40J!;4{7> z)~D90RZB-WrL(KL)c|%2u{3bodRwQ9`vIVE+?tdEM@T4dfsrvz-HJQr^h_l+4Nq~>`MM1GlQwy$ygkMGfq5UI%g|rC2s1TbMZx}!z?8ji=c5-!pEX5)gEoxdv=z~%jIE)Ni z$5dD8h2F{-<1BQ8a{tuSD3(>gy{CI+uyWhUIgMjM6?toG-$%m@Q}jU0=I`!Su#Eb# zQ8eLX+%90dEM6bwB=T&7!SL1cdF;eH@!W3EaLtWrNgaQ*@H56z6v27d+ZjzQ)9{{C ztk|z_L^T$A*NeJNP8?7lMjD43_cS&qpx8qx+WsE2k)BZ%de8bsRtk zTZV{-5BL63e3-2XtbN|n(;dyd`p9; zp7=Tp1!a~JD$fcc56*jS(My^2Dmpz0D2Jt`ba{^y+wh>w&f}_*MC9^Ls&+f7ekO?R zc{5zNm%-stz+UKF-RDLG9UbxUP}Zq$nPq4&A%qI7$VOW5P0(k*=Ocf9Ptbzn?$gC7 z!k+@Vjqvru0Sw_z2ozWD&DOUIzhf)IXe_`T!9in}w9-l7sbKkHId7>J6?-Lu+xI~7 zdmA4}{f^9c$N2gFlx8L;6@+`Op1N7&-i3VRgUu)rIMV^+zTQFbk~enVgQ6d&Uam>n z`7qbaL_s=1Sho^?FgklD{;0lkljS{Q%W3@d^K4*wGWKHzIy}Kp56o#V1k9juPx$1W z4>C8RaQIAYIjRV1tsBxR%6fDve^tK(5xhqU6x%lHY0EY@Pe#hO`P(c0P48NS6NWw| zPT}4jM1$71u8Z@rPq6oZbDyqL-v$X=yC;!o5XCRT(AhQw;nq7mO8C@p817A^GY$U?RV>ay+hd$XM0hLaw;M%BXZGWncaVO_Dtt?w@U^l5^M65xgKacX%}vi zj(SeEHhCfP?GA0>8s~mReaMNm3*RXR9Iz)Z^yl__yz<2zmaQ3nxIZ?m9;k=OUzi1) zv5m$1tlK^A;xD8%2VcGA0A|PhCXuF{SaLe*SFsr+mzRUgdu#WqK#P*c2CRef^Wrlv z24-Fc=q_Q9&@#HvhD;@rn#xINSzBlsCdn;}wy+Hxs`nOx14y%#DpJuw(Di!R8 zsDz$v*8|*FYao=#x_$6fSXSfPh90Y_;$9DPkL`-cQzwEg!v{AeDwtXW)PL^icyN$hzTi0>*Ra{C znYA*hN}|dibgMUB`A>)PdOhYlP_#w4fG&Z1o(P@VvOZzgYoHGBnNqx{e9E{OnflzH z_2z-1fXC4;Wjp>U{HH9#AD)35Ilnz;xc8;SnI!DKPq|_l9b!XD^;dkqs{2;e>Pt`F=YINryd>M%AInDT{D80~4wHp^(qrq^412MW@@z$izU}&Wz8@{zWOL z@SyO^GiFRalMlL~$DG4?{Q9YAF~_6hUX1w_%@4x+XPy3LAHO*RNRn3l9=wfTiMq4nk9k|j3Hhb5kP z$J_V)Nc#7qQwrqV*SgR9!osk|<#Lc*T?kFS2keB8m)p2#V4vInsy3tDZDtxS#)tfs zBPXf6u)qw_{JZcr)wJA$T4Z|SnlmuuaNL*b=Y{SG(izLiy;+!dda52Y2Ak%q8r*j? zh{fr;X1FFG+$19DHq_@0czgVl>hyu`_~>bkWkYZiy287n?}57E7W@EZHL!Y35IO0g z=20GKb-e|-`Z*V&MY0ZSE*|OZ9@8GPtJ~k_1~e##`DQTQ1S#6$YRP}Pacp~@edo6E z*TDyZr4X{4g6A$pal1peE9~s;F!TPE?{=MT;WWcKF*RDYUJ% z^`4aN5uDFkcvo*Tl!)!nk?_N(c8Bw^``0{75Yoi*ACq%i;eLlOL}^EH!zVhQN8_}0 zfq!!WihkY~^T$!l(+Zi5EQEyJ52Sv4`Ezo=Pomfx2EUQr&&y?~MT6`G6%L z$PDk?uiad@w{%1G1KUWh=zFn&%tvNR0-eJ~&O%}|q-}Qv2g^FPh#?Z6M%I9DNp8zn z4&wJ0IVSGLpmO85S2Pp>PjEWp;v0@t#ciw>Jf`BG&FI4}!l4v!bFbciAPu|@xTOL4 zD4z>y%`MZy!W+Z!>ExntD)04a2MW!6C)APU-0?@do`KZIn*AP#TM=+njPUd6ZNgN& zCHS_FI>f<%z8)g%Wu!8)fF}dDm&A~mDMAOLfaOMXaV4e<>GwEX`?UTprT7sh@ViAb9bXoG?-#4# zd(ENEnHOJiX12|q&5>6X1wyVDHG!(VXLklqL%F}oCJI9dCn8UKr z-`H{or;oDE25Hv1Y8_|fVvZk#{A&1>eV3+?O_Vx`NUOOLr4vLoX!>k{YV*V&M zNQ zB22Lu?Nb5)w(IE1LS7m4!i+{TyKxn1x#*N}SK_UZk<{{I5DE=^`X2p?KiUZ98yg~2 z&)+{)Ef2&=967})l}JpVmcJY&vdQ5@mEd%7poC*O-t!oZw)i)-Wan%ezLo0u{3zr6 zXbf&a=Bna7;*Rgu+I&t{bgyi30v&@!PG>&k_5l5DLC54d5bN=2kW*B^z zQmh$G38z^hjY5a6v^p4E2T2EXW|oB@9?M-Y%(J`kPv3{7YM3j$n2jA>5eF|Q_o$!; zo~_pRh7K4oIILvt$>vf69rQ8qAHV;FY9d2O@BH9X-p5HHtZ~WnWs}HizPz0RyMHf} zIoxxq>7u~!727+<6D>UchD<%Ja>9k>@|6=d>!a2uJ3a)W2MXyO%X1TsSObcnpFQS| z$e*&txnpe@EXrU!-=ITMw_7TrZTPWgJ21|3e!>SXK0DEYO6px!2z!1Lrz#8BP9iC(yXRe>QA}Ih0t{;^JW(hhouzRO~}OmieFC;p9{V^ zSa-!uZ0bPE48EbfbE%$5rR>B-GM1t>ww$`lY!Y1su>#+ip#UA=zn2B<7=p z`><@`!v=h`d>4_loVS!+3aLO4Bip?F%m%@;DXaAB92g#tbP%bA^+Xe)PYK*vu}ykZ zHD{%B0wl6_gOBn=C68?BQ7O(2-EGUa+pnhSc;e@jvqSEA?l(xyD>vHwZhD{3kUryL zFNIO6(75F}O#I}j9?+JjwOXoysO@#dND9A@KI3cOU#f(?Qo)p&;Ymwol@n3+ym;~& z;;MjOc*EX?sipB`u3E!q=ERS%8`PGUxwv`7%B*2l@ulhmx4n4GWa(R|>cGv8OvDrO zxYXXbnQuM*P=|(Nk8Jvv2&eP@NlwJ@O9Q9+!El z99A(6YCiuOq@Dj9BuzJ?!Wj;{K~DmTfg{eBr5m{+adLha^v~PaA4(@(X2YDT4jBC= zOZVyO^2|+jcfEcDK2HktUr@2@-)-@Cb>W@0okXASB1U{BK_(=W>U74QyX-D#K6;4X z=zF`0X8mf)<2QBZsHu5lAE;4;6WMsTIhQlmn~VrQwQ;|8w&AUaWivb{sDmr?p~V@Y0b($b3A4iM#4flkG9VblS*;Dm)J+I4aaq+iJm#?MNddFU{L=T$N zNy8cFEt`HZdxVAjf%|^vIj|kuME992YmgkaB7pJw{%Q9eF`oGR6mfs(*$b?j0ee^j zT*L_2H6?;F8$+Pr`U_sh+7p}4q3b8PJ;vc{kXKSDJ_vj8Po{8K6Uh_)>!#)lh)1-# z1uCbN6E2!=+5>*b&7WYMY2oU6E+a57yffHv{d)iY8mBrODC3|@IU3Q{L&^qWuW1x@ z!4V8=R6ySPofTVoz71V;ts1ev5^tzh&FOE2&%06 zS^AZMrGdNOU?Eft9jy^|Ckj(b?=W{G6|~Or2n5wvwPIej^rcz-fP!C~#xoFd*K~kh zFOzlDmtx5#9A_Cok!}0}eFdetf)N&V-{LT6J9wAR&y?C1E81AE<~#hgHgd2vdR#&}9;n;s- zcL0J{%j(z)`QN|(6PP2-`!Cq$-^Zp6h{jV^-|FNn6J6!nBrV{=qxbWlu zDyo0J#{a#k|FK8@cTN4Xb8q5hQUm_oyC$0t_WSN&prf_+|3}(ahE@3m-yXUf>29Q@ z8)+#8q`SMjLApVtOS&8B?oR3M?(X~I@A=>Oe7~rVoO9UkJ~Ojt&swvl{4y9ZMn>2k zPP#_-fgT48LVUt^gH!ha3mEvYjsEkC@90Hp94HP^hM6V^oU%Y@*nDCNuQmdjvOW^og6m=c4%9K0k&fVPMf-mQUaDYiC87q4bowc-U?;>xW?jE3wj?n9+@|Hb0Ppbvo_Nyi<|@;R{b-e&;dpV(%N^l3x%TYcNn0-HFSkGql^Sf>irJP4SsyX zOXGaee8VDGQw(m}kLp4l+r}4nxXZr2s=um5fLUt3nq)ry|9x2_{NUi+8CM~JtYWe7 zWX6yHk&>ze4)_xwRRW-{uyP0^kKJPKFH8W;`LBgXh6dvwk|EcnkEKQOgG5idEAiiF zRV}OC?K=5hCq%+Yg93e|Xh|8CN~B3iW#RPTVWoutf%0FKhzMlVx;qR{u{FBMSbz{k zgqgtypJ|&1G|tTsd^^W&-b%9iAD=ozl>ng)EGy(ZFA@7of$o>zIIR2H=w-` zR@%2@`s^bE6S1*wZ&<`b_TpL^T$GMd@1~^Oe=gIxuBJO;Sj9p(^^=*EDk1`m)u2lz zm01D$GS1B~R;*$wT-&GOWsg#1ImAH8`U8(cx@xipw^tmB{ui=j(ahCg0CIaryC%ht zt&6Q$O6=~*1WZYh0K5$ETNV@>(84Q2+DsZEo;_b!w1}kzXG6Wy_5ItiZA(n@OxIe; zL27X;w)`zF&>YMJpd$i0!~o6(?9RYB;-wT3cY;X99vG-;Vgo~9Um&m{Mwx@{;nZ zoi3{B0Vry%tq}$?t3_85TTJQzDL{#_rVrLzV-E7_c4fIF16Ky&f5LyqehC|qo05io z!Ms2f(AvQMBj8dhR+IOwM?YruJMPQ!)P_LMe077rVI8}E3rMh#9K2C=AL`##PFfC$Mg0|y5ZVF8dUr!!}N(!I(B*NijaL{E5SC&cOxoj`TjZ0#V`xtMS!<{waq4lkSXz-7eAfP(ZSM)!Wg!SUsqeb-IN z7H-tDLpgRuVx4RlFWmg>75`QcIKJ&Ej^5+|z^_#mZp2ZL(L$f#`fvbE7=Q<{9{nVZ zgl)dgW@`&@{KMr#k0t9G?zynIf*5_U>+&Rj<4J9Gc)2hBU-Rpm>uKA075$R_$%SLKk1{K zrWdJzb$-L<@vlXGAk1#lN-$jYs*XZU56=JIyB?gjc{ax)Ew_)n5AiN~^D6~l%Ez*! zu~pavWz#9j?e7H1JL%$z{ATwBCIQc4A#C;c#~#aV0>97wnZMzq-G`IBVh6y&l6OsP zNjyR5=*8vPZi?@uo0)V8_9xx=@O66+I};OqlLdsC3zdGBA85}_Cv#lXZpe&y?IA;` zgK`6MhrXBMf=bxW_9cRrczDY zPN+ANA{;4za1-4_{8?`By=}U^l5it_<8XylP0y|yWIH!^8Z5n@(5(~&JTAaq*#=B{ zo7I*5{$sZCFRA3CUwq?Rz+&G21INI0bv~j_(9D0eR3(aqt_JS(4|aVz=9`A{iZ+hH zIr{^u8U`3n4F0fQ2d6LC8feyJE{^qI_%V#qcC593&D`z8xq1wEu3-h^CHZ^$58oD-8);rC zj?P^iSb1O7q?(ZcT_#t#IzX2xz^VD>Z$9b)v>(|D6@m+Yh$*hk{BS_{#ErEf2c4)v z5LV=iPY{;nn@XT*3v>V)jT$AinV zw?7B7k-mTEF2w9Gq3}*lheLD;(#u6O{Dez@L?reNa?-qZN_Uo2LRjK_DPgT^9U9yU z?7dIlC;Y9p-$zPbL-yLXqD(n8^W&@5EoxXtLP7n6F3_{I>j$_8&U7EDC4%zF)Y&b* zLRG&SutONVKD=A}I>Lzv$kq!ez2A<5^XAv$T8tfvpACr){MghZm4S{4iY$*NIYS#q zCJ;#-d(i%_sVod>vW2~EgvcLiyXdN4V&Z9EvXl?`C$NAST0k@L^`i$`wQ%izAqLdY1XE57SD zM+h*TDcrda=d*M5GPmc$hJHZH=Eg0O)D0Bnua5{{@5pM@>ky4zjS|8!%58zKJtjfa znJ*l8Mohypkz0vd17NWfai;2X0kbt4o$+d`-7^7Jjla`{uemrhYmNS}>BLv~2PnJ< z#Dw+C7Sv7o{@WuW9~5ya08$H_4E8pdm}X zLuEgJXf%;w)8BO51l3-L)Gpy7MBI_FPXrPI7^WLa8?<89EZIfBWM2bKsX^nupGvMr z0;G?Xi{x$8mmtgS0pe;W@M_Ufnv;bxhzv7#Xs=fRfL(Qqu$XmdZbjYIf@XPFW3mx8 zrMDu}aNK)?sMjtorKZOUM4GKG3;8s+3ky0p!8zBw0H3H82Cn9UBid`LRt<= z!@;?Rp-?&=;_(|VjoYX6c8$|+b4u{^|IUvZKObny4)|GbXDiv7{qQ(EN>4 ziC(FAo&OS(4{74uL^S&sA@;nOIU?6D6a(X(-nlAp?`)1)9ddp2!iCBW>cd$aw*dO| z3s8K|r`lksyG}gYQ^+^6F;O=Xte8d&d(YDQa4)B)PqhdpFDa`*0%F4X*v{aATEA`gPkbdsNE z#f*V3bE~SKloV|VFEx3<$cU^a<@ZkY=8=A03ag-!2g4P77JSwb$Bp^ug5)(|JMFAC zT>ZUY6y+GWHjv8QpMO3%IXJZseH55{sW(~ANgJFscwxH8ZF(Khi;53bi z0orO1b>eK4!BD0D98aN&x!$$@u7!2V&J&Z+w|$?H_zOxhfKZ6G9#U}Tbic~4b;R;X)djVdNV7G zkzb*M8DEaWPP%{s{1=H;26VTKeglT+PJJwZMa))am7=`f#9Fw6%jYtv->bc3zLqMt zuZ-4^fyh{rM*c6!+C|aY2Z4qw^OHZSiW&bQqv8G9@RqP7A!~v$W@0Zu4zOin#7rr?9q-CRgLRh1>seT96Sz{Z^+OxC z%U4(zGrh+3bgARM`u@rKdK8Ht0L8R1J*rtlSNxAW0UQyS!3c8KS4#Wg+v%p%FWlgB z42H!g!`Fs(Zjr5xh0DRb>6JIfC{zPyF>A>xKa?kK#oR26-#&lnniW_e3Z8G3W|@0sXQ<8~gDd^}im zX($Ph4`05SoQ>vCa2I>L*@zm?&dxNuH<=vZj($Yy9w1Ms`r}JUiqth57f3JU%R+(@ zUe!sTaN%(aj8j^BNWZf*V4m+g4i5lJ9{q|1>n{YI10_uY_a(=PO=EnKU#s=6b~5h8 z>p)oPNNH)FM{#jU^O;0Jlz3T2@lZsn-5KX;B)$VKfh18!#smK~n@h;A*skw}@S1!3 zYD*aA*h+E~>VwzKC3$=k`=rbh=EuppuX3xaGfFn>zP%-PY9Qcc{>ghL%z?Br_|rHX z!Dj!GL>^Jw*E^_3Ju>W(J^aJ4HK7hQm2>si7e_rLw3&=1^|pRV9LXr^Sb>DT9Ixoj z;)4=XU)}-WpTeI)S1+`2LeC9^Tb``FHfN_vrt9AnDwu5jg$vZ=={~DzzT0CHSo}#T zt)o%MJR<#%rnl%nj5YYmA5UJEi^Wx)0vL@PQ+td#kSS0=Am}<2Hl^z0ROTT%{Vvqk z7o^Tz1VmKSQ=z4)a(Fq4L?r1Xm^zg85vH+qp-Yf+fy=a;A>pR(=5OB59xBo$QVa1~ zqE@Q%KHSX}`1Spyu6G@UjIKWc(S4G@>$1Y&vhtw#HddfVaMu4?6px8QyW^aI8~xoY zqu{h=MZa}?RMXZ$B^3$qM?Cwf_VwCbtc<72Pc43nU^%mBtt@WkM6jJWITSIfCz>S3 zq>xlUc))aw-y|aI?fKO<_6RMGCRj8kTr%65e0un!*IFB_)?dvJSLpZ=q*M5xGxjbtH@V$YczZ79?Lb2M zY-o6xuU z+^ePYp)jHBQ9ntX>BlqjLwX(R2YFKkplv^w;V5iOy?_2s4XM(;Ns-`OGC?kI*9K;T z{f#JA%h-3iW&eAmzfXstpwC|Ex2DmCcKfZFj%>%jF_4iYz}IR?4la2#trfXzp+tkV zMB}yG1SPE(qxGwWID z@jIDo#N8XWeU_E>3Q`;y*P2FBlU;We0gLkQ#djCw10HK4iR{u6Kdwtp{D`JmD#o{f zH}H>I?OJZrclet6{9W4y%V3##p-UZQ^ks9T>0~`~e6v$-i=SUt*)r5!}?e4BS7XD^5)a8>c#43SMWI>v>M8VXf0|HU> zp(7F7u637&9>!1MrQW?5Xjl)9zaW(bFs6C2tpXFzsFHeAyIhb&pOR(^z(BF9hpZG{ z9y-@Cy82aexk0Q&@Y+squPG#lyaf@MNEGi089a8o-cF!)vm#jGhbqtPda2`}d)7W2 zeFzp`umZAz{fzo##aKlUgg!*oP$*)dLyw*=pOU}KpVpzf=Q*0MlbhuEoU3GXEwlCo7;U4|cBmq8lVU^aFg8jmEw;lF+jx%amCSQe~YV z!#{QMro3_n*X|}Ar5}ZJ?mj@3t)`D26p-NUI!=1cjkXF-tuUNy+s=By@c}No?J7b* z1mX)&gsPSjtEd+#=Ikzk{JG@EZmE;rPeuMBr^{m{Gwo$v?@PO8;51&+$8j7YGQO&z zGb>jzw*0dJ&^YlnG0LgVP#!C$L!d&q^8zmzqtD%{Zc4}-*=J1UZz{+x zh?%=&c8{2dXRc6`XX@lvQyp#RS*)Gbji>Z09x30I5lXu#Mt0Vt(-V*O^W=zDoK#d* zQI+`Wlsa%(YOu`0|2Nh(+WLG^OxhoAybAe`K-|*Ik&OG_hcRvjiT|DfPmJl=BuQ%b z+D|v)p{9jf z-ry#PCZf(-68}q~Idg+vIFtZ+XEFCD+zliM`dvI;4>k|;yP|G|xzF?Iym+h%;dd{a zJ;l2_2N;-C>*Fg)timn15X9D|Z=JRvln=>Wrrqw>rT$PpAE#bzT_7d25sBt9G}SZ{ zk9jX_k>P#{27&S%i=s4Wi0!D2oD!63D@m1@J?OC#`IYCg%dKctIr4_7a{w``sw`Cz z`NISQ*YV6Nj$_s11{gf4hHRDicsA7W!{!nT(nXP2?DQ|(3QMt&DC#!zBL;XK1t31C z->Tk(p!0)j|01+PWhma&abyRIoij~cC_G8vyuv_l&XQPFVpl^n_WI>NM~JO6CFRJp z#GlD*BCr8nLDXK^my`m_zZoOS`0k4(aYW59EWFTq@TyQH<*;RH3iRq8Bi~frYAfhm z2p0@K(8DT{823*Y+{H{-v9SQTfo=pT531E^*3GdEyfdAq?SsVcxEdEHWiL6_IC)1B z_&%KcNHdpea`ouZ^tuNnLL{_LRW($s&w}8n9QAu(&y|y1Nj_&_1#j11Afa14gXQkQeJ7yU1aCD)#S ziR63CL%s1#KO8vX)lpjbqUK18CSHs3$F&R#d)Z`(mxDmI7ye&pE791;+6!lgvTn8C zOfflRlsW%v<*HO8!^1_LP~jI~jgc10Wil=flXIhz*WzKukALh%Nm2&OeAv?N!p@KA zgmjqlKiHh=N<@M;p7d!YqcmIlmBo#5hJgJt8# zVLavPmVv8&Vd*4@ilCk09gE*vM2o>x>0T5H1LrU*PB9QyW#TgoSMyttdzCV=K`#sQ;I}k}pe4x=l=HS?sU&Pt*B^Vk?oifBvkkLz80ftVWJ!iNbWyPr zR?7Q$t>Pjq#Y2o;i`7iEOZI=XpjL-dXRPcqBb%Vno2(ouvfIcn;=NqcrTELCP*EP- z5Iainzv8Xl9y<;52dv=&4VZvSGJ%x+f=AQJhqHMq<(-Q~6VdfVpF)NTZR|P|o#eNu z__lW8B){ChUx-COW7*r4+=#S0m^Mg33~QXZaC zTPL2L^=GG&T5it^$&R-Xmx$0kzFWgPEwvejCJ_}wyR0h_;s*E*V zO=H6LZy9e+nS!&MQ;YW>!8ZrD(AHnqVUnR+YV@_Zr5nudh-_sRyjQT=DRnXThvIAQD8ZNeB zv@hCO+s2L};2TqE7!(XQ7sw@GPSG>`cadcu!3L>bj z@LvwlP0_vkY|Iz$3BNGCkn*9dt+eGMOC5nurxP-1fDNyxR&(sk)1UYOBdn64{n_DN zgNO-QWxe2i7pCA4D0mn>|?52vxvD+(*!{Xj5>5^P&XD-{<}k$d|8IJ z>cYNO&#>RIr&3{M*U`nJr;Jm`X4U{vRMyodoVul|X{aMe{$|#&m4e50=vS3Gh|04; z{ltAF}0ReP9(k!8cO;MGx1!{tAZ~1oA zili)$gM4H_rV5+NjUQ|R17~H`@SJ z;h{QB&JxiWT{?{9Z?3&slRLtZ@*fD{einW&3ae9By%i#2@r5yJHkA8-;^aj&^r99#r*$q8gxC4!lD= zJV(opDe>!pePl%W*Y#@Xyq+>!P-oD0CjrGF+s=~mzyND}2;^Znt}q9&9%zHMcqUjA zLH}9`w(^I5BwwVZJsCV6Of|1loSNh#zVAhP^WHp6K(PPsD;?Gxd4w#xd;8Kpag$MT z$eURyZnE>uPh-y&Pf4JTvOTb`K*Vy;=JUs&!nfb+$Q-+S%D3C>uBbBXhLL3?-wAWfzxa2WkFZL-RRL^1TDxEg?O)EbrQ4`(B86@{T`jyU7JJ> z6zWntf4(-E&Fg&2(@Jw-IaU)erDW97Hr?N>R4xLIYmMW6&$*YQbZl>S@bFWl-w{Eb zQO-d4-{MvzOBzd|AxTmfsyzpaQ^T_brX3AbTJl^B!@>wJ)dkfVy`!6ys9&|`FOEb_ zMbd=-{1U79&m6a!gO5s3L^JjLb$T4_v&ojb7-LPE0^1*nFpZYW=BYPt?c?l7z!bT- z>UQcT@0~-e9;{q*-_W+lwsp@cv&8;i181qnw9 z-G&-UJ7}9*L?~VGMpiclCWA{Ipl^~z5jGN1IHrwRx~Fn+c!o5i=q^ zdZA~hW%t8!I^4ff&j_&Q1&>HD+= zupZOgPsAV4>hXj|(fo2oJbeUR9kob?&-kYsjX6}nYsSaHLC!|bpX1c$mite!np)@` z$=R({Tcd{QzlkpkR~?oAs*W)TN;z&R6=O?M!vHGJphADG5+J{4R>14T%#Y!Z7qj=8 z!Z!Vt>1rFU0z>w*6RQqG^>74<(X*r^W9`Ojz5cl*udR;-t3u5@i9bG&8A@D={4Z(z zalmozw6Mx|ggNnrrEl{11UBqJ;5Sg^AF;1P)ESF=ty<~JyGD`+WDGkfx_hs%r`Mg6 z!uOc^Hs+Knz~>>1k+?+lwq6;ZmbWRRA+6WRBc z@3pU-$ukX0ga7j)N&^*R?2H39=;TJkDGak~>tm!F=^^XC;Gy-`t(QrO^-_gnr#tOO zjHM}jju#?Is54i*2cc|02%tEj0Cvi0hX2?+D|OobCeS+M90`8;Rzi|Ab7@3M_95jj zJ9?Q3Fa`CLunF5Ccz2?vu3+l=vn+hq!`B^|A5VbPC&_V#KoP3M=8_8b{L=c03ie2! ztBUj<@@V5)G9a+TdqAI3G^0LKidDBt^67kUy=}=|O*6CO=5+i+%j21Qsq1Ix&0auM{nC6+#^AA;x z-42!TSV5zDmSa}=e&p|4Q9Hq4eySP>zfvi#uqrr=N2UV(srqvj{(Z8_GH}a+@IwF< z6)4h-@su2T?A=avFroo}>67vJ9a~}nKfqb!{;qNiUI?qrd^hraa7fFIApm|cMbLn~ zhp~jg*$XN1(8&p?fTI!`8F-WTA#5du$m%|Ju+2U%rUX%rWJx5)KY?gGz}78~2>%m1}_f@g9R~?<|%yH&`qqe!Dr3Ls4*Ng(?%wuTjydx(n#kt(_SW|vP z#KaNpA7_!CC|ALIu{d8yrm*3VK6$1y^LuRn)ut`traM{{!`#9A9-37V8Znx37@?lR zr1yH>@}z~!kQet}btK5q4G0?uG`6#V*8)P-z}wx67i4w4cBfYGgTa*~@mG;JymA?> z(2$S`U<1(5I+a*eHcqcj#UEYq+@qt~BE4>YBprIKA<8AFKn9qH#FQlumQgxZ`5rTN z^)h|-4&En79Muluom&ol{!YX?KCWxqulwRgu}#Bj?NBgCcy~O_;PQaXFE?O}B%NTA zk@?yCV{}8vR`tSg)8(qup9%KH1HMZ4*0`S~z1F6RG_zBYkg!OaqwA14v0HMaV2Ns|}VsXyOu z#z8;1c(Hr{w&Hp0XI$;i2KPsE&$E^@z1Mxdh+H&*%)i`2G7M1-2)gGkTh`8CJx4CP z(PRG7Q6&Wx;!}rXeZg7`j?$%&pmm;#4Gg|G))E5NzX?|k-96ToXbFdwz>rAdOQ`=g zqJMZ-JE-PSEv<`IM&MH@JCha!zxs*H_k*N4Zb`-!=MyE5b_lDdR-=$CurinuQ@zW? zxXLiBS*+PjqbsHyzkm4h$E;LNJcMZV$ig2IFi?SZ@BCfq)w* zxanb60dDB=r}e(#^{wmL&nyWS!+!}THT;V?eO*JO(XVqQ!Z?4j*{kOAb+JF|H+^gr z*6)RdgVWxcVPmH5acH021cYGaumFY_SZFipJfGkimt|`Anz3ScYOPi{g%p#+4;IZJK#H@r`g5b6% zqQ=6P^$b!u@=;{S1><27|5+|VHTHzAGj8*AGhqG8g0?_*G}b+mjI+wVY%8ri3YEy* zeBr26R{ZfQZ2tE>Qn;SE7nJyuBfwRW9)(&!__j&O_xBCeI3wLJ{!f<&=&vdX+~TnC z352ct=iKOm&W=hKYn!ejJ?e68l= zeU7^LX&PrX6a5~fL|X8l*`=>I@!=k9n@!0*K86!b`kyqOTwgnPBwLQ!^yadJx^YAw z57OuU3PBe23NC9l2p{S`J#xmG5(<*`(eR$*_;DrI=#ix!s-dA8J}1*2bUPIbYz#e1 z@GSxSNtou@PC~#JpX9{5oki%6TV7*N%efA}y8l+>>l(}Sh!M=m>4eKZ$g;&~4Y}>Q zsj8?4hu%Y8KJb0&XI;mWsAY1OtAay#=-1#mOHKUow(^@rJ-!to$|~A2r<0;xgq|fQ zPaaX-p9_mONVv&YxY&1Jm(B5_bVwWAgpL*W+=%@c!ZxZr)!h=laWHKfL4SA1sH$Oc zM)gF2E8di zawHT{pDYNW274-Q>9dKx1AbiW7ffULfsBzKM+D+ig$Lj8pitU$>w+K#Ge$O#E5^ut zI8dO2R+3j-cSh*+B>ka-fKSj9hSU7hKWEVE?9e+`pLpFjwXN266o~>uZ@2%Js>S>DXh9TTYATa-uh_uyVotb${)y3?IArTm(T2+$#8$QEu~Y z^+fc#s~c3bw3?3VzU(0&VkJ~NHZJHe>0tahIcs5kxLMHY&wr-k<2onFXNf#0$Y;4) zMs%OOC8?s?D9yf%sqP8WR4oa zF=Mum>60cb=d;#g0dQU1cL#1l4HqMku7z);e5tNj2L@(9f+ZP2`Hlk4+m5sgk>QVk zY2(MD2OfX}x$r>xAUEa2&yB9-zM}&Nq9%%iLYYEgZ;=je%ZT)$fjHvT%ql&5_kAFleh&aAj5l*pmHHVQmcX zv;l=S@H_O@PicbIC;%~@-wXUI z&~1d+P8)zGdQu?uMOb{WqTlaL!LWc8zXQ`Tlb^VfxI#oOL?m%(0oxz=x`%B=u5qbR z$VD?G=bWn9|0cJi})c+@avhF$)^-i6r^S?_FF`?yzo`w!n3o=I$2E_2Q} zNr_SH+~t6SNj1$S8HnU#HYkl=dO0em|FrWrdq~z4>KN;|$a2(lB;|W$Rk#WsYos=G z(-W;XnJlbEOj7Lv#*Q~?^kH;9Wld^tvs{<0NDqJ@osC^K0YFYWq}>+)kOoYyl6d)o zfei6q$z9BmIm}cCQ@jFgwLakAjZi7BHf}y{)t~=>f55^mEiA38mL(EE3Zcq;$>_3s zq|4JqMIq&J#d@LuGr?hoVYWmzurfOdtBQ?hRh-hNo+R6JCfK^=0z!l%>$~Rbq@+gI zkOuP=RcQ+pok`~i&yIf=rZ+ZK@^pHA12TRXeq~)l-9@ZKPndo!SJ>nx4P$aMB!C;) z^0^ZLkOqsDOb)Z6kY4`J-YsaCAr%kA`mA^~&fonvi%PaYd0byrDBm9Udrn3F_x>>H{HzynDSVlg+f(W2_Clj6ET8@knFgEluP?hO!TRr zV{KGR3riFXa7(qMVOfdzQJTDGvN&7{;oQe{p+#EGu7yQzx@ zB$sgNc+EB@I;Ojr>pujygo2C1YxO;&4z$cFT~6#n!XOpj5Vh9hIi3`q|8- zvl%al0J}!kGALUt0F18)I4#C(qp$?pffCrCqR$Fag-UU<$-)Xl^g$4SJ^WCeIk$eb zr*avxPGQherWd2$3iQrzqH+pv`J(tgT!6^`-Eq|O5w*#>NXEakXbG}7bj^ycw9lpZ zs`)#z=s$HKphIa=->lB(&6{T+{(m}TeyFn8HbMRGkNAJog#PdLp#RUNCDjLE&L2pe zZ(lw4d%sljw0~H8BzmrJu@;Z$i{yggh4;VFjzD?oMN+k>-LNhVd)gqjrs0RE+zzCvH>~R>hxI#Tg`{4Bi-j?hx>hr zS1g~qUYM9L%WmRTcZS)0Hf_2EDs>wT%yD`I4c!;l1sH*l#JlNis)Y{=N>A}R;kxeN zi{O3TX)Q3Bk5911m(~7>!@sF(JHjOA$3yb;-R98%fxwuP+K_!%X9?{NP8~^+!psZU zY(Q-2f@9KsDcjXpZ616&W&-!pv3an3pgbXZVn?0eQP@}|w*T*e914s-)?7(|_09kD zX#;dDgfi+MVw*#Lho}Z|bS~=sx59OvO*}aCYP#x@9a6_gmgiaG7To4J%O2G;jSK3d zu$Wr{qK6?XSI4Kbjgv$aKRBUqQQyJfi^z&q|8BQ~<515xEYFjQw#c|$@cfG&td_$v z&h_jYyZuR6`|(#)otIgEF0G#+oa`gU-pC3MC=M~p`4nh}O>fU5jk^uU@x1$&dhH;m zqkiU=6R!q#CXzBTc)lRNKk=EN%Loly4r`ro%_z;~t+?%8lO(y6SykKw4Nu6+FWUr` zqLmvr#9cQg#JwX4P9fxeo$Sz5-uHxjobFKC9L0Wjh_P`c3uQjQ3Ebtu#8xLJQ##K_xsEGqUMwD+U*4e2C;0w-suZ{^ z+a*^fn^APZ6LKhM;8fepZNmSc9X|@VW>_o$UFITkzHcbQ^KSUp*4>>ff`S3 zyJylC1c6(1*{W4w)lV*^XTItxLRw0i7$cSy7a`E zO+hIoOlFR#`=XBYBv^@0B_s2)J>2lJp%#r3rQ3~f-7D)5ZD77agWlxl`Y9|~qRrpt zmetq$$<6cb_H480(zSwycxs0OZS9fqc~F|Tv%4?P zb-|S&Z)>f?qvut~g6&>je4>503TOGUNd>3vR+Y|r&X8CAzdnyvFq=TMob|eP zXSN_z@LaI~Bb7jBo%sl?_hWl)0n_;b9M7ru=Q?fpRZDNsILpqxk zZ7%tb?vdJ-GA}rpPp_EtaHbGUy-TY;2;MJSZy_)yVCNJZC-j?ZZTC?9IBMw4tFND1 z?Dkmi3#dQE^xuD|*jEMHW!U??S?T_a6n3b?OJ zwLQ{c>Qy9ufXf#n(6IJovhGN~|0|IxG^Btr$iUtf5wzVzlX1Vq#DhRa9~N2h09tkH zrhOjejLL%SzUBj%`8bWaR|_fj(=nLb~`)NdKArTF)fslFAXtf#j(!;SkqFoz8f%9Y}9wBNQi ze16t>p6<`+DTTVbf+jC9RIAUa+tNyFMXhLe!$k49jC19o1FeRKuU-l)dv^9;cs$xIt-bJ4S$KhAb-V2m_9j|4BRFt?43M-RGVazR z*E7v=_OLN32}eBAiJ-M z_Ph$wFLWxOTUa^F;dYW5u3Jeg2n~-ch>-GjEDvdy4IQ5ioFS?F8D~tbH@stp7yP!X zZ*EE~_usBhdgy+lZ0!w2>FPaJy>&d_ChE_FNJgq%!9bzUJ>6W^$3pF3l^JCXr(y-? zqs>E`c^5NTwvToMDr!DzJw4;zzRTg|9j1*Ie*8Wl6h6*9fj8qrGlJbE7EG`X7~2aA zj`a)PQ(E4z8EM|#)Z?qQ-mjUd4jE=@UCBE9Kc4rYug`aks7p=o%a@$c*BY7$gfOh? z2*2(cY{jeIEsxtWYj_KY;f=oDd~iG+n`jVA1B;a!h&z4s`nJW$#Sq4ROO zHgUBdqSr|kdJLqNSLcl)YHRY8yc?l@3(6#t3GTBW<HX`jB$h@$`G`)BKjg@-RB z>*8uMhuEU9JO^Jp*rnA?`XOH}sqIbr{?e=H+^n5B^vi?PH7<|+k%v4F4~$O2T3Y{x zK1!bl8^HjFhl;zMH$|jJb=`R9c2vRdvoFFDAOE_||NLx#_${B#N@z>=G_fi+orbJh z01T-S4^Q?nvwxp z4?;obU)@WbpxJ1Hl>ugGiLriFdhjt&>lyg<9*S;t!@XZ@9_E-nq!)AvZlUVW&nAc= z*9Io~M1tw;pKE>EV!Hwid2lqeowM(>eEpskxil#74@yr=B}<9>&ckhb7%Zf$zja@0 zC%KjF(2W}JLQ3)HgjkFRc%Ydjp19mR#8{_&_0;Pp%alJ$`}?yoS6o~Swqw0yZm)I< zt9XuujRLQ?qSrZkxN%&`P=c8w!Y2|GH#PjHi(F5Uiof9X+HzwcoF!h24rgR21t9CKU z@fEOyfxZQX!p^VW(@diOVu%heuUu^-u>kHGnriL*m=Fm6!e z7iGscj+Me6!Db=0U>-97DUB^vm!8-B0-f{!ZM;}bM0uy_BFHgiFou0 zz9ZDhn}*XAu;=p};{F`7z3l7BQHFMbG8Z~=>2dvhLvj}~q^&S8oTSoHOB}Cx0@3|Eym>TWFJV)bi}zG@9?Q1V-vO*Y4x`0IC~ zSn0>-xh8beX2OMm%puZhPB=ovth=!>g3l~&EVH7-J(ji$p_G*;eZ#t5PZbyOd&9Ec z*?^2XpN2*w22F3@WX>Dh1@kIVL)IsM}`TxS9I=4Q=KXJ zThd`i0kauaJghBxQ%19UF_nh#gAfK-*pBJI`sDkY<$f_$a2bmWO)=-%%VYD;?zvAd za>E}BN=MLix2#L$dv_FmQ#2@MgFqu46SoYKbg8Lpthr5V1xT# z@fnGudFXKHf7~Q$M_=R!c5S3V>XJF+hIA%I=TsYUZks5>qr5Hm7*(tWzFy{bJZT4b zslfAHU)6-;6SNZV*$^UCw3_e)F*XrZ;JbmZ@&B^XzmX$z+15@|_2Fl{(mdKfP2}}} zNMt#wCl5WI^sqC3RzJp7u*uG{xw1w~I7^ol^!Jdn>^iDw1%1(03!OqlrlOQVm~cFO z<>P6>INBWZ32%gG5OhE*ZzDMn(0p9yINqOLUW<;j>djw0N6@{9blt&c>^*KpS+`^j zGM3xulmG(#QPs>UgX=*Zh4N+WhBV9C_r_mFhSd6}pwr>wJ|`x8KgEL))U|VqdH%{r zWQ&v9lkMnN&^TfX*4!CxX(>Hxlq4Yw8GIZU{z@pJe+E-0BBISgMAn3YQ_#S?_VWD_ z0m|z-MVRb}Kiy0){nA4&<+!P8gor@Fk!9!DhAU4fzlQsY$1ImO|D0VcjSL~gQZ=Dh zQ`0ZBmitSjkSgQdkJUL!dMcm!tHGb;hV!kiMxt%|4Q%?CUY~S2Mn*OV>e~a(Ue~(s zTkG2(n54MXCYF=oa>w=Zrp7Xb%z;5BYr*i96#jizT$det=Yg4t76T6Bn^EJD>-lqD zsKimKm5tNlPY60b`7OkXy1Q8w8z$IoP{gm&e%H%ip7)2}B6I?ukE=30vDRM8QZG&g zo3XmU**L->-X7JKd5yqST~iedMwMKbcxSgX-rlG$48eS>pr2MByjyZaiSx&`H-i?6 zMDfm_G#UJn$=M1`SFYE?nd0LXI^lv3;rMzVWMHXcy|0};H!{8uyzaJd<#DzXKHZIx znShabLHD!n#Ix`QJ_)|bUaveOx7>Ze%?;-;JVlf<9MVamwCluQ^;_en?(R--znyoVy}$cs zk8#hq=f@di0gKh$wW@noO{@7l#Zr|58DMIE)G@hpW1MEwMsK?_hR7dsx&BDrcF9l? zpn<}uG`TZe@)}MLa}t=r>I0n=o3TX2dlh7>cQk(4_t7Mkt*0eH-~n1xb6-khdQo>i z^eXr|D)5f;zAAG$;OiSD(p}fB{wbv6S;Om8Bx)+#4Sw@!k)&xq<{h+hsEFxpZt=R` z)1XQJ!$&>q>BDYS0fsRAGshb;f79f0UP&6o)zx`cpB%++m2=_5bFY~=Q&!S}=5yI0 zh%vJ9(Bp(NM{WZ+=76Hh$4~cdZ(xt3mbJ+OH%J{0tG?`^-zUAb$CO-mqro~uv^E-X z9BVb8*9TI183@};!kSNvj0E}3>sP01YRWu3NE`H*U-14WcUJOe&4ED4@syzJ^-TQg zmw9WDttZ?2Z6Y!MOKcVq*%3Pf)T`-I{h3bnxsGqR+WVI6RX@p`cj#F@Wb9`ko>&hA zBlrN%9Q%o*t_#HG2LgjQnXj1q_eO=rpFjcYhI6nWkhkZkns8{g+Vm6ew-_G~A0ZSe z=vFYw;qe3RFP@q%=+hBPauJBJvxa|VEr+ntx^A1vEjWHU?esX2cI#HEYtIyu*ECy` z-Nh&AJ&Cc338(5K2p~P zBiBD=FE56mvEgb!;m{YQgVu2xlfBJF;H%_mh~vn{aJGy1mEm;bg~FmQ&cmDag$)xT zRgODqSbDADo!u_V@U`?h)rFY#lRmV%!lX7zqn;=?Yt|Bc>bxF5GVSdp!P~Tgo!y$l zD?0WS!We}RV)d_L2(3n<`uj?0a^&xZpgkyVr(umfKOsLq5 zGkg^?n4M1(8r1j$=`usq*-MAeepDUXhR|LtT+7PX8oWt0NdXVi5(K0!S=CTtL@*GR zH~FyB8!UJM3g`J;-|cEXgS$6OmS*~y>ZZMFM2xC1CW+V~?FQIY}rxu7l2k|h_`WE$@2hg(U@p5%~ zcdL9=X+fI84D^_9D0V|+9Rn&O)~B{*;Dy}cABpcRxu4*X)~FOzKU9qkGltfh5~%ja zzSZv12clXli9M`^g+hn7K?7U3WpJ>WblY1t{w@~9YUEuotWCH7=#kzkyR|(Qw_y%3 ztTqJJqapnoL}{gtqz?JNQMJ1IByPXwDHN*qQ=~hX{7syj5d<^JZ$U_W107d>bP1@k zW(PBre83L7z|BMZz*7}wEOj(f_&ohi`P_Ib9CMnJ+nt0p%geB#&1I%#ogWqx-$2Xb zl9NI8L~k70$q*gr;Rj9gqwrK;?e z`xm7N1I*)TKHC0~X9E_-zL^!tt4^4DFqK=byD4{ypH543UCMkM9b7@0`JJRqMnc6Iy{sb^gH!-Lm(HmK! zfhL$_M9ZO{xCVY7Llsfu4{(AD-H)cvxJ#XCPpWazYcd*w+#Ej@ANgB^#OcbTpz%lS z0sm`3z!u8cFNe{A)GAbG86yhoFi@T9>=FJTT^}s`*wqs67W|iD6#36q38@P8>bP?^ zWXwj=b3#RDT@5Ke-S`lmHH#WzyU&MfLOF1*orXm%^qz;bw*7)E28;CEFSMvG z{sRxV3J>z@vtq=H9I|*w%_G4&S_deKNk|Qbons~!%}EvKKbNfAr*yhNPaSS}sK3cz z>G%VTTy?R@c#fdaaXLy{kduf;kt+AI^-M?5iH(v6=13@yHhS~jrNA;$lt@~J7fV6# zxh_(PTAWn3sVO*pzO7uvTt1D>xx|yP6MGuY7g;GrmAB^TA8}K_7uCb6u0M4ia7r#9 zdtMtmyK|M%SgGxmR&LQ3hGX|csHaa^&qY$7No3hv^OzB~032z6oeM>P*4YmIs(_+G ztoGXo?!vsMd(`vS$cGcDzA8c{S^mqD5UL(FSZ&4(6WXI&f5qRP_3bF^Z;rckmQ%x= zZ~03c9WF+wm|YrM_E|qoszenzZHH^q7(4}5%)R0z@ib#9RpPS4lZ{9mHOL+X(^Wkm zz*M?jM<+e>uUM{*5J<@gNhqj%-U??P=(aA3)NnSeNX-ik0_q4wv(JP&XZJFFM~+Yc ztDhUyckbrgg>2QMfFLpd&RyaTI?L|L?xZF;@2a@ji@wDkG9|hn3bpOZd-AvB@{n=4 z#6;QP$8K9ZnbG)rOSXyfp;PO8uKE@Jmclp*|~j!UM19i2Fzvc-}+P*1QdZlaJ*3kturi~9A`1A5Ux&6p|`gFd=2>nk!d ze)E7$s^zFG%din2^~;VW*)Xh2p-4z*U+)^r7wpA!Scq@_t8K(iWC@H6=)#;)n?iCy zS9->DV|>hq&v@3_V6Ca2dI2aLRoISPIDaS0RqiLd_J&XuK9S;Pyy@{NX87u}?aP-rky1*wHRG^&0dSz%W z;|H6yVE7+bcyqJ73P~N3X_Iaxq~zCQQdkPOpNWC2WM{(cW0k3TH|J{1R+-&x>w(Tg z{;U~(wRSarB`<}9u>O$6I=i|yjAZbiXbif;J#?%8&{%L`=~NEweFZHgZx)WJzj@36n)dP; zGxml*8!#t;1!Cz1Xk>aex*6Ih23F~+eR5yBkK;~ z>?{Aey$T_|S4g@94dxkOT3?qS81j;ca`qYCDp0VHbj&uH(yJAOiKZ)rGp0SO zaH?&uwZ%#`EG>7biIQ49)aqMtN@9%=0II2JuPR*CZSbS& zZH|~1Zj#$ngunBMW>oE-pwVm6uf~_gVmg~);IcTfLTB)jSE={%%LsqYy3gStyFB~@ zPp#bK!adLaB`&hEwTKe~z==rf8K*h}!wI|ZCoE2u2RE2giz&R*0$$^4Ok|p#9r&5W z%yy2@Gd-9{Fm}0SNr<@$AM#xc;iZgy&&mD!C{X6y5?Je6x@8{OKjQh_s_BRMjMU86 zMv0>Z?%?nrId%>5p6feR<i8Ab0YSAv!GrR#Q#!aNYqx9_zf#Ltfz2o# zY2hB=)}l=u0&XNj%`E1c%Hyd%fk6HiTv1vCZQ28>Z#Hh4{>KIz8m{2oL+qB7C zh%#8Az`#-82P{)T7BdQ!0afjzL#?BWD+Ruwsi!mHBd+snL=*KN!y(@FDO%qVQz@3} z%dDsffJ&rraZMC6ZPE3>4S%@7VJo66%phCPcT8@U!j@5b*n*N8Q>DaT3>+C z;aDYQb!Gl{Er5y*>png~Us(*;DQ5Rsb}_n4R82sE({P4d=mMkFXC5I}e(j@{7lP3! z$ligmLkwPekpQC>zYJ{!na1Cj|u=jNZW9~%;zB%L2p1MVgnab1iCKelMs3&&6x17g+ zLrfCzZFtRa*e9gCYX4SCwpovSNa-{>(WKjjj91Yv(ZkW`+p?Et;VX95wjwTFVwvk_ zXz%tdetvY(sWg2UVld9wVV$cqdgwPsTdKKf=ZCy`C}f*xv1iGJHJzYB?VdKPZ=kwX zA3e>g(^I)w<8`X*WkpebihAG_ovG6)8(kSk>a_vJQ(`VB+f-r>DU#M;~%K6D<1};iS~khrvtCoq7LA{h@cVUe!l`Fz;#T z+EJ83-*+6>d-zFcBcJ$BwPgYL|H8yUuX|vv|A6ahm9D`A>x^q;qco2D@j(t1q3R3C z!3oKLS^nf&LN&w%tK)3-^Wli_Qg^L@UJdewgB1mSjXo)feYsmLfgVvSe%c!CM7Pva zOYIDDPzHR!$sB%kF?)o@O$C+uPFo!rr6q!h2;21#zfBKm4f>jAx<<~dakDutpkL@U zdVSxyw?Tq`?AdrZL%HjHOMZGq&<2WtjU!`}Ai>OZVbcHo>ym;!{5Uqi6o}uS_FtsB}u*H@yuhFqmAvk-D{e&do=t zb4r1SE1tg;^|MCm@CQF~$80WJ5k4PKF6lwN%El2r7g9#j1;0F9*V{+78^DX@HpnR~ z=J)XmI+4_gC#f?{7|Gawo)DQN6vz-aVBH4)47!CrIAlyBTL=l7OQ?6sp4|QOaUGnt z*WY>-1PqhmvZRL#yrJ8X-a2?l2KlHE!N%c=IK;$!Vq>Q)I41?WNkwDZRBtF_To5)4 zD8Krh*bpivBe-Tro`)T*%e`mB1Q2ojja31U14dKhG<66(CSscpce*T>@eky!Kf>?5 zrI6MlUfQjy;+K6cbIA+ejrD5d^&7l(u6_g~2+`g0>=ZU4>#+O;5$Qg&E-evdk=VMp zAwn>KuTuh>4cO0zU&r;;%9P1cGF5RNr7iPvJMGXc=7I}G$GJ{Tr}HMxZ!^qw=~BCy zv2)kN38J4;fnj&?p9JSIS0aHGp()?oBE zwr%o6$+l;0 zcu`5^Ud_Q-&tDo!~yl%a{t z-sC~fH#{B(9y2{Hk+JBfbVsEgq2SkMo$7+}o955{xc@*$M8WTMO1iec*U?N;QIiZo z*t+>ts0CV6+GJPTFyX-Bctyb64IrUx^|1IDXU(GRkB;799XsR_!^&77B^JBa>5z2J zF6iszZ^kwRR)MpYD6mlf_0^n4a;zq8pg_j(GH+ydI?hVZL#1_hqCwbbjJa*L^lM9Z z(Nf);_sysY=}hC+YxYrG!7I)ui9JQ*pD$KxSBHPpA-Ni_*PTM*Y^a=Z)*s`vN=qPn5kw28ca>^fI}yVB0u^;ahzeZerM_osI@k~5~kOAbJ7 zJ|Di)Oh7T%ENin>eQO0OzAu&AzbiNjOsY9hzTzptu|NQ)0#6sXEccT&k%et8BTf?i z3n(I+7^sYMqmI?q_FH5SWXDOW*~dO?4^E)R{k{iF%XmB;h9ZOn6_X-%PEaj7z%3J* zO!9NaoKW3W7sg5VzM~X)o|a_^)hzVllCDikWBRYT{u@^a&;_x$sdkdGP-SHb97Ie3ZS4>-=xL5gw( zARwMIo@*+4xj{l|?DRSnnz%5inZMz=jhqi`a(Y(iSNuqGTH~Nc4^+d}$fa~uBnuNcnjpY&%?t~9>oxQe|8VfkO#_7&20p>> zgAQEvlPfS{CVt%d$%vxa6W(8?3L7&2Ze$2ka~8MHJF6F- z?X(16Ke2PKzK~9ekRt^Q1ON#gcQn8_+dBSgPMs`i^h#OXXR5P^&>1h;5x-J0SukW08F%s1Cg%3pLWac2N#uz3jq4E9OdY=!!;}cvq zC$ZrKfE+q)IH*hR3aMQuOv$7ganO8f6jA8n! z*lXz;KgZni`JWA2HBANiB9b>Y&(<%@5#H7;(Y@f;53P(iDuopoF5yCg0GRjZNpBXP zknOcT8=BW>aH*S#`oHjjE)g|ha}tAoW&rLb+@fUnhJD0?x1*FBqUkwj!$~vxeSUEJ1^cpqn{|Y=y`?0p^1e%p2jYb~$k^XU(0+bLn95&3hTeGY>u6B3* zV3gdCt9NhS2bPB zw@$qq=*g@gvY%YBz^ujs7=|(xcy(6y=6*B%gjk+Ah5d~ zQNgmNtw^X{E5EQYXx$Sps!5rtc|gxun5Z$NrE$gn_=2+gWM317FiwZ_2Zs?k3own4 z-iHtKUKa^V`|Kfg`M-WIvQngJO&l=~td;Ai7$aAo0Ts^nLOeedTa@`-(5Hc1<(@?xy}N|! zEbAnP%5g@N;COa(mYw4$GeBKL*3vkz9nY;WeP#SKj5q!5#aYd7Dk|eEFqZlxa;rB> zV(k;!qI|^J4_(7=L>~Y?l)sh?2C#y5v&U(S$Z1_a_CBSDW`4Dy4p~!1aKqk$6wl`X z{kzF8<`gk@T`?rSJ$4Y|Ko_TD00ve53rd3@CCrj2j>~XxLZiG?5`eJ)SUC>O7BCk7 zLSp|GzekFM0Jz?+Zh-MYf~XfvVQz`Rn58lQC(J@>6oD=iUDKu4zRCTe6cKQOo!tse z{hDZnpCwqwP1AT6dnkEy_HgD15RU@!Sjnmb6yU1H2s$FMBn#dvqYvK=r`|-w*ATm4 zg$%r5>D=vXAtC9d_gy%c)Ulp~_N5q%Zz@FSsQ45O#0Jt`^AHUtu$7`KELIiP1w$tO zH8bnrV7&u9VpghH zA~&B{+1|lktOI30ic)~b@Zx)(;qIh8pHSJ!qnsdB;9g^;F+|dU%s$Wu4o|*?$=Dmf z=p?NR8dxVea~w>HMB&b`e%daup}GE9W?(`D<>;%Bgb+#`2-A2nBNuzXHF$JXb*zyk ztxCy3%j`=Yq>3b2iPc_C{@ZV7wPEAqjZ(*ZKF^Pf#4bf3<6$OW#EFolBVT@^!9Hfx5!PFKD!xq= zOBWC?eBx;kCjR-={)-8jiR2(Gu@l6$QNQVv`WKD9+#zBRVh`}ni^0o3sM91O^OQ_< zV$xCil#mSuhE(Vczcf)xsJT<~a=5AK2ZI*xck0{XSN9*K37p07oK5ifl>*O)McNf6 zvn?6xXYbU7I4GiMZF_6#mWIG_m%kh+e^IDw!m58?oG8gN$50zY3U=*?|5Ag3)@Q31`r93|#t~45cs1 zEAlwa!V}k>xmXJK!gNGq*;>g$2k+%==VmK!e_=|?tA1y%-mG>oar%v15KP{ExtFm@ zJ#k423WGbC({0ve-CAG>f!yLR&)lhvi^~mJdcty7|K=#M?d(-gIAJ?r? zc)sDGH#S2(87wMf;3}bXYe|hsjpc5xXO-4#e`n9x9OegM6MqaIzT(01HKcx8CPu|n zCf}7YaST!v9D#%BL1t{MtlXLuGKatcss6DP_{mZ%(r9*240^_3fdviTfccbG9QH`M zR1^7>(XlfC9FL6BVUWg>y+%YMmd76I9i`!?5n@LDfGO82AVdRwU0mWC+MUYpqM5F4GXg- zalOg8#Xc8ekELT`BTi5OzZ{lxY{RNN?+?W!6&~Jsjn3G0E#Emci#c^IM?S2JxZxR= zM_T&ZL)Y!bZm?xv;lTCwu_0oHd8vK*# z9|Mh4b8I9#G3#s!THR}>mnwsUgWUDyr4AqyXW10xY=*EQ9~wh#9@dXd<8t^0vtLLX zW2zOs&sb#%;>RLnDsL%KQi3Y;TVZtON)ZIo<+IV~NEC&L!(j3n6yY*S#zX}+$-?bw z=oVd=pO&#MYrPG>1E*s8X0_O31~MXN^xWm1Nu1GOGO=kG$$H5oF9*9?q9`;lh4o9b zSJ_WFY!6!KwCuhFL8(<9bkCRBe+fEmu+o1!7(Z&D`>Y~lWPuTrB$SBZ#>vG)Qe>*f zVo4F9BfwQETbjThl7iZ$E;ap0ggr?5gfYu$r{QPUct-nToTf{mY)nxMGF7R&3)>Hw z$A?FzTu5NTj|$h!{u%BG&q15Ra>i5u`@sJQG?eb<9%(kZuwT~I1A4Y8>_K@Q~ z=vNftSYfHY#3GZ9N!Y9g1TcLuXPQZn#(+l^I)xTk(gRd%8=g;OB&QC%VQ6=qIv!j- zr*p0Oc0&N4tYq*kKQ0;0$did^wS8Wn4nrJZ+BLDyC8Gct=M!7#pu^NYxY*z&wi}kw znfRuFM9Xt&?MmHsOor;Oz`PA#3#7hD zITShEs?nLrq4+u%jnY7(xF){PHy*xPr)S@<6C`>ep@kjNC-47by(E6$5$sTE-G@sXV1qe z#gIHM&eDLqd|fnAtcr0StEFD{4AY%lpBOecVmPW4h?DxMXapb}&|qD>;lwV?KRjfv7r@OE%rZ6>um)k-3-7;)Wo|CxM}J+qNQn zvpjBQV-0YyaLQWTaEtd>XS}j1f9s$5tsh%fBvSEvb?L;cI|5i?MDJ*3b4vg|&6cp< zFvN4?;XdDX(f#d_(8cp9)iMpP!Ck>e9IN-zNNQK(Y5A}8acjtGR!GikScQ;sXrTS& zQFb7MYK2U%t=4PdFYx+S_e2%q?E_>b60n3m4La2bij#}UOH4MIxokvAx~NXdE13tA zu;Y!ax4W;cJL83Pw+Dcvqj8^xo>0Q>F8LSiEsF|Pr_FLSvs7wq>tjgh;A^0hs%=G6 z;wYa*H)F+G4oGAFiYmubkDxC5DeIxEyns-?9~Mk;loyk!=9zr`14}e)y)I4?X0Gl^ zfesCjvNVLaYfWu4*7T`a$wN)91Rbphi_oG%`nKgT{3X+2-IX~oNXW56Q7&MWm|Ay^ z-l84PUS%KUlSK%BO#Ye1w@Hdd1$4eYVLa?j?u}dR9~nqY!duZ_s8w6v>2(`d>v%KuJog1uoapT*% z;rjN;JtW$gc#1R2o+PHjXGVdmNZ@D=01lg-gPbFswtNViX1qLSkT~G^7ftCN(HiNFsfd z7i5!jyC-Bm0ug9q^ZaLMbC?IQf00iHp6tjo4-pu#$yP?dUGOG~b656V0c$o#o&GX+ zX@KA^I$dVnOh_`R#Ob%LM!bd-UPIQ79ro01hB-;PJpw-=V!=MN2;mLQ>AL6CZ&C*yWz_vw>0}4^kxhe5x}q%gpvm38uA1qwW8T3mf0g4!4sAo%#hVULw?;T6Aw-oiHVD0hg0)=W=CLl0x&3X-bx2CC6!QyL4b@vms_j+MW6q zQfymU)K=o9U7d!bd;k$2i7wWkUn%C92Y-eQ^lqe_nf|mh(j!lo`v@~9^`uXz@uwT! zH*H*q=v}1aa3nVhzl1t@yo7@7f^tkvqI#O5PxWGSY7e^O4I|cV8c*ao6G*X{&}=uB z#mPEME-u5dp&Q6T?2RTB0nqEH<1G42Ij7Pcei_iKRWPnWFwTLDyHr243>T`HtKu5m(ws(E z3m1y_!{2E*)m?u6X48V{1BE}sCu|asFt#K^qeBa_tiTU?#FGPoqX@f+Qk^AY*dV%hyo6AE76f@rNrY_y$aNGaD}({;dOE(qvHCTF{B2f)j*_ zQY{NZ^tqlEd-Sm$4!hV~S14w(!Y@GP33WA#Wp&hCd`{d&VzT}F5>Lsy!H%yLs05Ly zTwjQ0P$kcQrlGTsh9t5uuvb2YkoLqE(QOP+@fB5dS_!O{HZTnl26#fjw4ru!^oH0b z#?-7Zr+8=h|22hB6GeP86F4fic3qx+60U&~uHd3dlx1|iI{O1U+hR9n#q?~>`HN1g zg;Cb|2sHY!@DzZD2k1ik^0}tGTxJgTB$kkg_%q~xG+K{S-+q%BVq-07TOhqH23{rt z_XsyMGVuzI_vT?GE6rbXg>73vwn1EASeP2zfD5>h)ju!+Z%>u@PES}chiyU1Ge0BI zEdp9QhZ8I_9RvjJO;SWqnJ_$$QGh+`srtz&-nnYEF-_K%V!KzrC#2U5Kk84RL))G1 z$jL}JjSOi#JTT)dAs3LQNzU#rj5}Qgd>XUVeIwO<&x$8BlFAKrt?=P;;fkyBoqqmf z8}(Q6a%ZqD3)mK5zse)-xW2%gbkF5LNLon3!%NTi$w!vUFIeMY(61$?S(K$(usF|= zoffl~71$TW*FcaM)U3s|1pc;`c}*aD#-(>3l0)uic~+u zh9nB0g5#FwzDkS_v0=%KMNby8ZAcl`C}7LFeFwS*=%#KU_`Gd?Iiftxo}HD_U zkX<7%{VDiGrduaP%GOz>rAA=1+}0fUnz5(}WBMl^lB|XKevFS>3Xl%_<)AYg^Vk6t zks~S8zXa2>c&l|vm158HHQhw51LKit>XL9YHU+wd=q5e1ZWXY#{u*H#fBQi;?LT-g z0R}f1IABB)H7urD3CBIC>&6nZi-U5wEjx1s1YCj3-W6Yf@K8oM`p?Y`w4oXd# z>R(#;?%mhQ2RE4U&E;(9MFVit{?Qyrg zN>VzUKF>8_n@;f!`SJU0o||^Db!GF1VsX^+c*7|LIIlL&ZY)bK{lfNK;o;F}^yW!R zr2931{EvNu?s39^`P$GHyy}vdz2&kNueHD2Yx<;E>2jjtY;?o8y_Y{mZ)oC0&XSVi zJ*jGy3oM*rOSW5-ERF%0zeEFlDs*y_6H~T3+wDE!TI-6>sf7YR<=2eeXMTI^?fv7aGR6rYvx%kRdvUj{F`qB z&}Xo5lmFq`_+JnIf8h*(wAKF{`Rj82(=71&e|kgsFQxeJBY(Z@e_!)2IsT_9F3JSc zKLx(c(Hiu}y!vs|IL(h`-?v{|4DGd=QoMUR?FQo<%uTUu`(*oEVBK~d4l16&8?D!d z2BI1rh0DaT6@Fp@Tq@fla5}E1pRHciX~=dH+uYE8^4fU<@eymnQax zFh($ZBGcpqhAKOs2-dtG8r_>}BN4r>5mZ&b?aaqFz!dn;+PHq`Q*pjnE0x!J9=-iL}>b5Lc3t+-SWv6K$iw{qFnS!i6+61KNP+*Isy85-Y0v z6S4<9#hX6ch;vY~)9PFU3`I{SR7XGJueW4oFyt8D#2lQ_SVjF5_Aw1|p$(>Fng zZevopIds>3emkBj*nH8WwXJ`3xA|u%Ym?+a+D_+p>OGCkzHjD2sQ5!Rg3V!d)<-7C z>+xZZ<~-(N^sGZ~k%mA~*fI+nyO%u`B>FUIyr-q(2FsD>d#9V8W#9^$ntg9S-1Rbg z_`%e}N*?d)7=Nyd#qTkUkCG^k%?e|iD1Y5~5t%bKe0Tcpa74PkkdTvS=I6{0s?OKb zuHvHlji;>ri3o%$nq{GOt={u8kyD@8?{7A6e3BI2?@Dgork~+(*l^__*w7Rj1pYW? zdT<1TWve-^tXMWXX`r@P>*sCTw>-Wf5*Vm0(SN4lRdC5)obtJ5({3q;8E3AxSK7?~ zBQo)kW#8{X&nY_S;KYl2(Et5CTI~fMcaqBMww54o+<2#$p0@(iGt2AeX2*%#UF}Zp z_1I{$$vBDy8tSYnrDX;AwaE|tl0VWNZZE_eD@p_9*cdH?;z8biMZVXVwvc0UE89E* zVQ-7xb#&zrBS5WtZ|4&czE5>p{x9q`Ub;hv`T0Yp$wNJ^>?3;ORiB<1_B#XVpy?Bl z|ZTrpGzux!V^Z^dQ0TH3z#mzno#M1zlGW6LpVl z#D5|Ccxz;2w=wa(MW{IOj(Uf%ezZdS?)+JEv6lC7RZTKTQ^|~$YoZ~0F=J4MBWtic z(c}bUZDJrf3eP(v#P?PU;rK@VX4+DnOSr#=ZElG_^KJi9>D>tBx!=4co?#PZAIi1U zZxg>^l&6z1CglB`1DE;hUB(F6DT8s&V$U?M+56(tc;$zXsX-qG3QsDxi!=Bl4O{2U zdtk-%II2KX$f4{TD9+^j=gnsgsIXgeoCUAcQ;Vz}E!TF*DbV^8rv=}47O$qm(^pr5 z?D**^yPq$<&*J{*TNXS1litxWcN^nxtt62c0%rT;Zkx{t-+fsFe;>{HZjpCfEk_); zoXXv%a(^bkK3qZc4e_*?*q@kGxtX=K%H`m@FN4@{Z1f78tf+mu?z9pjDq#%pAs$%o73ADd1!)=AB5 z*bJ|vWni6KP`*dqc3;-$ESt}NS#mx`Q5?&-{As;h3(_yD$X3nhrgQc3pMCHOu_g){ zDd6}cXX){{jCg5aJ49YTJf-${q`s?fOfx*bdC)NdjzHbfzvy^q%0IU4nVFB#H9G`* zY5TMxw?SkOpvWF#$+0oC+yZF*$SiRNDqQI1OXh!JymqUxe+Fwu|^%04uog<%LIz|^8 zgJynwWl{5a67%TrMbru~~=o zhM}Rj2OiC&^UX|QMhPU?SN<_F%{%CEVSWiv7j9i@ zV@Q9eWkTp&j`7_@XxX8vwadk`icw`L%AEq$3vqjJ;bw_B$^ge>;FY|sgG<@Q;{O=+ zg)@Po=>0&yEQKp^4A{}?N;nUBoJTbmPH}jG9Gr;$vguX9d(PPTZm7A3-g2+OKH0hO z&0;uR_|KK9uFHg;WCCP#1{y=jWPMT+SORVFjNotmC*#`X>xd88h@`M;;urTaidcMU zD`L;AeX?^fsx(<=Uadx4!Z`j6)JqestR$r}ZNG?tn??ES*Gf00bIL-rLAN$0sPDUB zY6yj^8$=7$3GEZ0Cu;^220Y?+8P{if#mEGT9=pS3ywzMJ4&o)jxfj#+gZTzbA#RqH zS&=WbpsUMut-)~UY6W1ur0ooCvT7#ilVMjIr^pruYPoVr)q8GHh$((;4onzqX9qD_ zFEzU&P9KiE_!ft~EG$}Bc&k1NWr#Emb^XSLJ>8SUgr}^N!EZRsR2L*P$zC7M-d6n<=osKj(fzeZMpzhY<+I6vu{)y?*)9v~qRX+NtR8nLD1ry5x!27F$v09B#-4Fxf{s z{MP|3(JUnuEBHaK6U&&p&+$EP&hQHMRP2T4UEqk%XyZ{Q$(%~BOiR^OB#kFR)xVZ@ z>ocZ%Q3cwQ8sQ@6rJjT;R_yRcY7`jt?pa^#*wZCldMiG*)x-z?=m%3CL# zArfKrAYu8-d#SViZ zD5=^-q5le!pdOBstyXv9w)QRv+O(qcC;R198qEUb9C0=F<4ZI)Wf?8lC9;jJ69ej%+M0IZ{wqe*cE1M=a4x5>XR%RyMO2%``F6Uf-J?$J(EFaRDbfBnYn6Na>T2&Ui zNMqf}Lgle?FnnYr7Fcusx>l6)KG zX-#;I-}$!wiT^I;nNoygW`?l&8aG@34U2BefLAX1`%xUkC<{VntYu^M-cZXp3R<&}Z>Z`=g+8 zTb7*B8lvoDa_yn(JB-Z-8AHSO!Qf5;Qlv)tNI`@L5pxMd*7dZDeL1zt!`crc)M(P` zawI;T6lY58dQ;zYEwzrJ&dnR*06*0iL7OKp940M6N5QM#MNgCEGIEbiKbKlN_r-lR zCI{JlKD+jGMH84DRuB#^D={$gRk$!$!=VD2*L~9kg|hB_80Kc7SFYwYk>SteDKY$= z)pj?Ou4%*LPb%I_=?Ol~Bc3<%>R`Ezl^&9h%ht0nN}NENh`|Vcxgz0=xAuzGCCgX-_i{)P=uuMIQhPEnhiP zgSaz_hOF;=E8{X*%^8l60ew?pu5VGo)gzJAJ5e9cpE@inwr{?-qO;iO(IDh-;BQgL z-3k5mf9lHYD~gm8>s%Drt(NRS*HY4!IrbK!(lXr+eWNSA9_3zF+b>bF>IyT)pBcVS zR@nMPWNepg)F|~vi!D^8<<}~@AKxYaVTP}r}6+wHNjI` z&+QEl1*Nmb|0GtTKgYGu{-^_}f2A$| jog(^gP3b#4eF*bP0l+XkK**z13 diff --git a/lessons/snake/drawing/static/snake-tiles.zip b/lessons/snake/drawing/static/snake-tiles.zip index 7faf9e410509a2e2420b5b7bb27fb956caf2d612..dbcccc23a1fdb12b83fa6f07664d6915fcf22b00 100644 GIT binary patch delta 2103 zcmZ`)eP~-%6o2$ZQDUHmnnKoIf=pU;HaRs||Etyhk2X++N)o!zSq}6F; zj!gd=%f1eejybG@fUBZwd;5=O_Yd`X zh(T}2jnB9hX)^_!RwgRnFbM)RM=1a=NQ#L$-irPGVAx0^65Ckn2zL@5JW;dH$efeY zU#31JB~U9<2KL%jo_=?1Y|KxbsL5rb=EB>t&DFr2*ODvajCXlIAEm+Wy!wKPWUuX7)VNIldXFd59JapTs3*QILe^4s#(OI9QZ zRs^}I9nS>w$rhDeJQ=v+PPiW2fO|qmC7v`HZr4)zKDwcO{TDTu8M)6Nh_Brx38~2f z+|ODya&Ek5^m`rwl3^$0vL;AnBxsF4g}v`*wUblr>;y;06B@C>$+tAxx26>Bt7H0S zE$^1AXE~G0*Sk|bvmp4)fPS|<%xRppX`Zh5Ct8l~7N=T|9>xD8B<*bJ&Owds;G|Ri z0#)PFcXw*Jewi05C8`yE_PI^q4>?Ag5vl_7{>^YGZpOZaJzVXztzw7hQeCUo{a$5g zAkc}F-@iRZ2OGx=8_$yPz!WCvk5H=N}k#PTlYvpM^wjC?7 z_;L%wez5Wc!*$hlwak!Fr{>h*j=;pqGaQ#BxOX}k?yshMHcgn?202 zJ8fZYp__AEg82h_bq@C*7@-exIofOK(bqP=Vv&=eomU_}v%wog^bnO)szm?yqVB*JosO8+K&e zOk4eHlP{TG@gES$*w(#bnqBymzE0!~vM{;Vzoxz8%rQD{E}^DIkSqo!$+;cg&en2j zC$h45V~SxiQ zpvb~muc80R9f)MOjIiU;H*Rz(pFlKyJuhC#BWDc%Kqi8pH^~CyT;g35*WymQKu7GpkqfT+E z^5rsOJ)ih;;XRZF7JDJ$PNxfYa!wu^UjO3~-{|4w7UPWB%Aw63>(BJdtYK{ zsE-Gqk%Rsg+#~N=LZ8x8sEE|U^Py7l?vX~>b^YjhdH3gWoq+`T;*R!(TPOgQnz0G1 z9K$nlNsdtwX_qkvq8UAn8;HLyN4q*5ly_~3A7wjk<|Iohc=}xDf(y}f8Q{UB;#s<2 zmF>()CDRUXEx3}pa5-ZT=dZI$j*Ew=ZwSQ6xj1sGU5<8nNo%CJBvTPuuDosl{$8Dr z_CQZp_oKmq-VPt5HJ9X?N8JtR8ImRN=TRxttpv%8r5RtZx-D`re`Nt!Rn|&i>i)>V zG`7vK@LtADVCqK6!M<^9hQV3MMqu}s0(XtF1ioeGX4qKT){CjBdnbpw>)MQRb{8q^ zMpL22!h=Iu0>7{uD%;GD9V`OOHJln4^I#xcPn&6D{hj8tYfmFx9n@q^RCi;Y)B3!` zu20%Zb&G49_T6@(i%C|hyDV|qqkf{3B&!1x*IyC8Uqabp$1bX>TTF%j_9_ivBW zi9#o8F3Q{y0{(ne=6?=>w~r#71xnI1vMKh}$Q*j~Sn^Z6eVl+zAF|N8MkD173?&Tu z75J5LU?wa@3sF49@(2dPr8W6_@wM%b65W=p%()@UXST*($>MogY>byU~Eg zQkR#>m1zPNvNGox1a3_rumj4|ltwV)JG>w9#ggA5wiyC`VuszPo*B7;M!#}OP=TMi zpz4spptIOJ2XueT7MNb&vGH=51pK?clRU=zS)tLeu>}72@Ka1Zg`jFMFNQ~%UF2^# x&T!g`OW{_=49iRG21l{ErKTV8!-7A`$`bh56x>X46HN?bGG0RyI(QGC{Rfd%%Fh4* diff --git a/lessons/snake/drawing/static/snake-tiles/bottom-head.png b/lessons/snake/drawing/static/snake-tiles/bottom-end.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/bottom-head.png rename to lessons/snake/drawing/static/snake-tiles/bottom-end.png diff --git a/lessons/snake/drawing/static/snake-tiles/tail-bottom.png b/lessons/snake/drawing/static/snake-tiles/end-bottom.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/tail-bottom.png rename to lessons/snake/drawing/static/snake-tiles/end-bottom.png diff --git a/lessons/snake/drawing/static/snake-tiles/tail-dead.png b/lessons/snake/drawing/static/snake-tiles/end-dead.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/tail-dead.png rename to lessons/snake/drawing/static/snake-tiles/end-dead.png diff --git a/lessons/snake/drawing/static/snake-tiles/tail-head.png b/lessons/snake/drawing/static/snake-tiles/end-end.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/tail-head.png rename to lessons/snake/drawing/static/snake-tiles/end-end.png diff --git a/lessons/snake/drawing/static/snake-tiles/tail-left.png b/lessons/snake/drawing/static/snake-tiles/end-left.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/tail-left.png rename to lessons/snake/drawing/static/snake-tiles/end-left.png diff --git a/lessons/snake/drawing/static/snake-tiles/tail-right.png b/lessons/snake/drawing/static/snake-tiles/end-right.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/tail-right.png rename to lessons/snake/drawing/static/snake-tiles/end-right.png diff --git a/lessons/snake/drawing/static/snake-tiles/tail-tongue.png b/lessons/snake/drawing/static/snake-tiles/end-tongue.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/tail-tongue.png rename to lessons/snake/drawing/static/snake-tiles/end-tongue.png diff --git a/lessons/snake/drawing/static/snake-tiles/tail-top.png b/lessons/snake/drawing/static/snake-tiles/end-top.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/tail-top.png rename to lessons/snake/drawing/static/snake-tiles/end-top.png diff --git a/lessons/snake/drawing/static/snake-tiles/left-head.png b/lessons/snake/drawing/static/snake-tiles/left-end.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/left-head.png rename to lessons/snake/drawing/static/snake-tiles/left-end.png diff --git a/lessons/snake/drawing/static/snake-tiles/right-head.png b/lessons/snake/drawing/static/snake-tiles/right-end.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/right-head.png rename to lessons/snake/drawing/static/snake-tiles/right-end.png diff --git a/lessons/snake/drawing/static/snake-tiles/top-head.png b/lessons/snake/drawing/static/snake-tiles/top-end.png similarity index 100% rename from lessons/snake/drawing/static/snake-tiles/top-head.png rename to lessons/snake/drawing/static/snake-tiles/top-end.png diff --git a/lessons/snake/logic/index.md b/lessons/snake/logic/index.md index f450377353..b07f4ddd90 100644 --- a/lessons/snake/logic/index.md +++ b/lessons/snake/logic/index.md @@ -39,8 +39,8 @@ def on_draw(): pyglet.gl.glEnable(pyglet.gl.GL_BLEND) pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA) for x, y in snake: - source = 'tail' # (Tady případně je nějaké - dest = 'head' # složitější vybírání políčka) + source = 'end' # (Tady případně je nějaké + dest = 'end' # složitější vybírání políčka) snake_tiles[source + '-' + dest].blit( x * TILE_SIZE, y * TILE_SIZE, width=TILE_SIZE, height=TILE_SIZE) for x, y in food: @@ -201,8 +201,8 @@ def on_draw(): pyglet.gl.glEnable(pyglet.gl.GL_BLEND) pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA) for x, y in state.snake: - source = 'tail' # (Tady případně je nějaké - dest = 'head' # složitější vybírání políčka) + source = 'end' # (Tady případně je nějaké + dest = 'end' # složitější vybírání políčka) snake_tiles[source + '-' + dest].blit( x * TILE_SIZE, y * TILE_SIZE, width=TILE_SIZE, height=TILE_SIZE) for x, y in state.food: @@ -688,7 +688,7 @@ kousky kódu, které prohru implementují: ```python # Grafická indikace - if dest == 'head' and not state.snake_alive: + if dest == 'end' and not state.snake_alive: dest = 'dead' ``` @@ -895,9 +895,9 @@ def on_draw(): pyglet.gl.glEnable(pyglet.gl.GL_BLEND) pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA) for x, y in state.snake: - source = 'tail' # (Tady případně je nějaké - dest = 'head' # složitější vybírání políčka) - if dest == 'head' and not state.snake_alive: + source = 'end' # (Tady případně je nějaké + dest = 'end' # složitější vybírání políčka) + if dest == 'end' and not state.snake_alive: dest = 'dead' snake_tiles[source + '-' + dest].blit( x * TILE_SIZE, y * TILE_SIZE, width=TILE_SIZE, height=TILE_SIZE) From aad73a582bfc407fd4bbeee876399409decac277 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Sat, 1 Sep 2018 00:24:37 +0200 Subject: [PATCH 17/30] snake logic: Rename a heading --- lessons/snake/logic/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/snake/logic/index.md b/lessons/snake/logic/index.md index b07f4ddd90..71f30c8058 100644 --- a/lessons/snake/logic/index.md +++ b/lessons/snake/logic/index.md @@ -75,7 +75,7 @@ Jestli ano, gratuluji! Zvývá směr hada ovládat šipkami na klávesnici, a většina hry bude hotová! -## Ven se stavem +## Třída pro stav Než uděláme interaktivního hada, zkusíme trošku uklidit. Program se nám rozrůstá a za chvíli bude složité se v něm vyznat. From 29140e5bbce4237cf867dd6ae02a32e6e5b87f9a Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 4 Oct 2018 18:49:38 +0200 Subject: [PATCH 18/30] beginners/cmdline: Add forgotten {{a}} --- lessons/beginners/cmdline/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/beginners/cmdline/index.md b/lessons/beginners/cmdline/index.md index 462dc1354e..669735fbdd 100644 --- a/lessons/beginners/cmdline/index.md +++ b/lessons/beginners/cmdline/index.md @@ -159,7 +159,7 @@ Pokud máš adresář `Desktop` nebo `Plocha`, přejdi tam. Pak nezapomeň ově Jsi-li na Linuxu nebo macOS, dej si pozor na velikost písmen: na těchto systémech jsou `Desktop` a `desktop` dvě různá jména. -Jsi-li na Windows, `cd` už jsi používala – tento příkaz se chová různě +Jsi-li na Windows, `cd` už jsi používal{{a}} – tento příkaz se chová různě podle toho, jestli něco napíšeš za něj nebo ne. {% call sidebyside() %} From d22822e81b1c120326dcc767141ac9259ab4c079 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 4 Oct 2018 18:50:08 +0200 Subject: [PATCH 19/30] beginners/venv-setup: Remove coach-present notes --- lessons/beginners/venv-setup/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lessons/beginners/venv-setup/index.md b/lessons/beginners/venv-setup/index.md index 015e6f653b..d20ed36b70 100644 --- a/lessons/beginners/venv-setup/index.md +++ b/lessons/beginners/venv-setup/index.md @@ -100,9 +100,9 @@ C:\Users\Helena\{{rootname}} 05/08/2014 07:28 PM

01 {% endcall %} -{% if var('coach-present') -%} +{# XXX: if var('coach-present') -%} Výsledek pro kontrolu ukaž koučovi. -{%- endif %} +{%- endif #} ## Virtuální prostředí @@ -171,9 +171,9 @@ V grafickém prohlížeči souborů to vypadá např. takto: alt="(adresáře '01' a 'venv' vedle sebe)", ) }} -{% if var('coach-present') -%} +{# XXX: if var('coach-present') -%} Výsledek pro kontrolu ukaž koučovi. -{%- endif %} +{%- endif #} ### Aktivace virtuálního prostředí From 7626adcd33fc4045b139f59c87c23fa4dbac53ae Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 4 Oct 2018 18:52:39 +0200 Subject: [PATCH 20/30] Don't assume specific lesson people learned the command line in --- lessons/beginners/install/linux.md | 2 +- lessons/beginners/install/macos.md | 2 +- lessons/fast-track/script/index.md | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lessons/beginners/install/linux.md b/lessons/beginners/install/linux.md index 0a3b60455b..f8746a03e9 100644 --- a/lessons/beginners/install/linux.md +++ b/lessons/beginners/install/linux.md @@ -8,7 +8,7 @@ Nezalekni se – většinu sekcí pravděpodobně přeskočíš. :) ## Instalace Pythonu 3 Na Linuxu většinou Python 3 už bývá. Abys to zkontroloval{{a}}, spusť -v [příkazové řádce]({{ lesson_url('beginners/cmdline') }}) příkaz: +v příkazové řádce příkaz: ```console $ python3 --version diff --git a/lessons/beginners/install/macos.md b/lessons/beginners/install/macos.md index 524075214c..3aa4703e71 100644 --- a/lessons/beginners/install/macos.md +++ b/lessons/beginners/install/macos.md @@ -4,7 +4,7 @@ Nainstaluj si nástroj [Homebrew](http://brew.sh), který řeší a zjednodušuj instalaci aplikací a knihoven, které budeme potřebovat pro programování. Jak na to? -Spusť v [příkazové řádce]({{ lesson_url('beginners/cmdline') }}) příkaz: +Spusť v příkazové řádce příkaz: ```console $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" diff --git a/lessons/fast-track/script/index.md b/lessons/fast-track/script/index.md index 1084baa05e..cf31c748fe 100644 --- a/lessons/fast-track/script/index.md +++ b/lessons/fast-track/script/index.md @@ -55,8 +55,7 @@ operačnímu systému, že jde o program v Pythonu a Python ho může spustit. Pokud máš soubor uložen, je čas jej spustit! Pomocí dovedností, které jsi se naučil{{a}} v sekci -o [příkazové řádce](../../beginners/cmdline/), -*změň adresář* terminálu na plochu. +o příkazové řádce, *změň adresář* terminálu na plochu. {% if var('coach-present') %} Pokud nevíš jak dál, požádej o pomoc kouče. From 26c74160dc24ced8a4eb4552d2f94f9611213aa2 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 4 Oct 2018 18:53:11 +0200 Subject: [PATCH 21/30] Add fast-track lesson for command line basics --- courses/snake/info.yml | 2 +- lessons/fast-track/cmdline/index.md | 312 ++++++++++++++++++ lessons/fast-track/cmdline/info.yml | 8 + lessons/fast-track/cmdline/static/dirs.png | Bin 0 -> 3429 bytes .../cmdline/static/windows-cmd-properties.png | Bin 0 -> 23872 bytes 5 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 lessons/fast-track/cmdline/index.md create mode 100644 lessons/fast-track/cmdline/info.yml create mode 100644 lessons/fast-track/cmdline/static/dirs.png create mode 100644 lessons/fast-track/cmdline/static/windows-cmd-properties.png diff --git a/courses/snake/info.yml b/courses/snake/info.yml index f7a5c1c531..6e8c556337 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -38,7 +38,7 @@ plan: - title: Příprava slug: preparation materials: - - lesson: beginners/cmdline + - lesson: fast-track/cmdline - lesson: beginners/install - lesson: beginners/venv-setup - lesson: beginners/install-editor diff --git a/lessons/fast-track/cmdline/index.md b/lessons/fast-track/cmdline/index.md new file mode 100644 index 0000000000..4e9b54cb30 --- /dev/null +++ b/lessons/fast-track/cmdline/index.md @@ -0,0 +1,312 @@ +{%- macro sidebyside(titles=['Unix', 'Windows']) -%} +
+ {%- for title in titles -%} +
+

{{ title }}

+{%- filter markdown() -%} +```{%- if title.lower().startswith('win') -%}dosvenv{%- else -%}console{%- endif -%} +{{ caller() | extract_part(loop.index0, '---') | dedent }} +``` +{%- endfilter -%} +
+ {%- endfor -%} +
+{%- endmacro -%} + +{%- if var('pyladies') -%} +{% set purpose = 'PyLadies' %} +{% set dirname = 'pyladies' %} +{%- else -%} +{% set purpose = 'Python' %} +{% set dirname = 'naucse-python' %} +{%- endif -%} + + +# Příkazová řádka + +Většina uživatelů ovládá počítač v *grafickém rozhraní* – myší nebo prstem +kliká na ikonky, vybírá příkazy z menu a kouká na animace. +Programátoři ale často ovládají počítač *textově*, v příkazové řádce: +napíšou příkaz nebo otázku a přečtou si případnou odpověď. +Někteří to nemají moc rádi (příkazy je potřeba si pamatovat), někteří si +to užívají (textové příkazy lze jednoduše opakovat a automatizovat), +ale fakt je, že bez základní znalosti příkazové řádky se programátor neobejde. + +Seznamme se tedy se způsobem, který programátoři používají na zadávání příkazů. + +Příkazová řádka (respektive program, kterému se říká i *konzole* či *terminál*; +anglicky *command line*, *console*, *terminal*) +se na různých systémech otevírá různě: + +* Windows (české): Start → napsat na klávesnici „cmd“ → Příkazový řádek +* Windows (anglické): Start → napsat na klávesnici „cmd“ → Command Prompt +* macOS (anglický): Applications → Utilities → Terminal +* Linux (GNOME): Menu Aktivity (levý horní roh) → hledat Terminál +* Linux (KDE): Hlavní Menu → hledat Konsole + +Nevíš-li si rady, zkus +{% if var('coach-present') -%} +se zeptat kouče. +{%- else -%} +buď googlit, nebo se zeptat e-mailem. +{%- endif %} + +Po otevření konzole tě uvítá okýnko s řádkem textu, +kterým počítač vybízí k zadání příkazu. +Podle systému bude tento řádek končit buď znakem `$` nebo `>`, +před nímž můžou být ještě další informace: + +{% call sidebyside(titles=['Unix (Linux, macOS)', 'Windows']) %} +$ +--- +> +{% endcall %} + +Podle systému se potom liší i samotné příkazy, které budeš zadávat. + +> [note] Velikost písma +> Je-li ve Windows moc malé písmo, klikni na ikonku okna a vyber Možnosti. +> V záložce Písmo si pak můžeš vybrat větší font. +> +> +> {{ figure( + img=static('windows-cmd-properties.png'), + alt='Screenshot menu příkazové řádky', +) }} +> +> Na ostatních systémech hledej v nastavení, nebo zkus +> Ctrl++ a +> Ctrl+- (příp. se Shift). + + + +## První příkaz + +Začneme jednoduchým příkazem. +Napiš `whoami` (z angl. *who am I?* – kdo jsem?) +a stiskni Enter. +Objeví se přihlašovací jméno. Třeba u Heleny to vypadalo takhle: + +{% call sidebyside() %} +$ whoami +helena +--- +> whoami +pocitac\Helena +{% endcall %} + + + +> [note] +> Znak `$` nebo `>` je v ukázce jen proto, aby bylo jasné, že zadáváme +> příkaz do příkazové řádky. +> Vypíše ho počítač, většinou ještě s něčím před ním, +> takže ho nepiš sama! Zadej jen `whoami` a Enter. +> +> Stejně tak počítač sám vypíše přihlašovací jméno. + + +## Aktuální adresář + +Příkazová řádka pracuje vždy v nějakém *adresáři* (neboli *složce*, +angl. *directory*, *folder*). + +Je to podobné, jako když si na počítači otevřeš prohlížeč souborů. +Na každém počítači takový program vypadá trochu jinak, ale většinou máš +nahoře jméno aktuálního adresáře a v hlavním okýnku seznam souborů, +které v tom adresáři jsou: + +{{ figure( + img=static('dirs.png'), + alt='Screenshot prohlížeče souborů', +) }} + +Podobně příkazová řádka je vždy „v“ nějakém *aktuálním adresáři*. +Který to je, to bývá napsáno před znakem `$` nebo `>` (občas ve zkrácené podobě). +Vždycky se ale dá vypsat příkazem, který se podle systému +jmenuje `pwd` nebo `cd` (z angl. *print working directory* – vypiš pracovní +adresář, resp. *current directory* – aktuální adresář). + +{% call sidebyside() %} +$ pwd +/home/helena/ +--- +> cd +C:\Users\helena +{% endcall %} + +U tebe se bude aktuální adresář nejspíš jmenovat trochu jinak. + +Tento adresář – ten, ve kterém příkazová řádka „začíná“ – je tvůj +*domovský adresář*. +Typicky obsahuje všechny tvoje soubory a nastavení. + + +## Co v tom adresáři je? + +V prohlížeči souborů se ukazují soubory v aktuálním adresáři neustále. +V příkazové řádce si o ně ale musíš „říct“ příkazem `ls` nebo `dir` +(z angl. *list* – vyjmenovat, resp. *directory* – adresář). +Ten vypíše, co aktuální adresář obsahuje: všechny soubory, +včetně podadresářů, které se v aktuálním adresáři nacházejí. +Na některých systémech ukáže jen jména, jinde i další informace. +Například: + +{% call sidebyside() %} +$ ls +Applications +Desktop +Downloads +Music +… +--- +> dir + Directory of C:\Users\helena +05/08/2014 07:28 PM Applications +05/08/2014 07:28 PM Desktop +05/08/2014 07:28 PM Downloads +05/08/2014 07:28 PM Music +… +{% endcall %} + +Na tvém počítači nejspíš budou jiné soubory, ale aspoň `Desktop` a `Music` +(nebo `Plocha` a `Hudba`) na většině počítačů jsou. + + +## Kopírování textu + +Z příkazové řádky se dá kopírovat text. +Háček je ale v tom, že to nejde přes Ctrl+C – tahle +zkratka tu znamená něco jiného. + +Zkus si zkopírovat jméno aktuálního adresáře. + +* Na **Linuxu** všech systémech text vyber myší, pak klikni pravým tlačítkem + myši a z menu vyber kopírování. + Případně funguje zkratka Ctrl+Insert. + +* Na **macOS** to je nejjednodušší: text vyber a zkopíruj pomocí + +C + +* Na **Windows** napřed klikni na ikonku okýnka, rozbal *Edit* a vyber + *Vybrat* (*Select*). Pak text vyber myší a zkopíruj klávesou + Enter. + + (Na některých verzích Windows jde vybírat přímo myší, nemusíš přes menu.) + +Zkus zkopírované jméno adresáře vložit do grafického prohlížeče souborů. +Měl{{a}} bys pak vidět obsah i tam. + +V dalších sekcích budeme potřebovat adresáře `Desktop` a `Music` (nebo `Plocha` +a `Hudba`). +Jestli je ve svém domovském adresáři nemáš, v grafickém prohlížeči si je +vytvoř a v příkazové řádce zkontroluj, že je máš. + +{% call sidebyside() %} +$ ls +… +Desktop +Music +… +--- +> dir + Directory of C:\Users\helena +… +05/08/2014 07:28 PM Desktop +05/08/2014 07:28 PM Music +… +{% endcall %} + + +## Změna aktuálního adresáře + +Aktuální adresář se dá změnit pomocí příkazu `cd` +(z angl. *change directory* – změnit adresář). +Za `cd` se píše jméno adresáře, kam chceš přejít. + +> [note] Déjà vu? +> Jsi-li na Windows, příkaz `cd` už jsi používal{{a}}. +> Chová se ale různě podle toho, jestli něco napíšeš za něj nebo ne! + +Přejdi do adresáře `Desktop` (nebo `Plocha`). +Pak si nový aktuální adresář vypiš, aby sis ověřil{{a}}, +že jsi na správném místě. + +{% call sidebyside() %} +$ cd Desktop +$ pwd +/home/helena/Desktop +--- +> cd Desktop +> cd +C:\Users\helena\Desktop +{% endcall %} + +> [note] Velikost písmen +> Jsi-li na Linuxu nebo macOS, dej si pozor na velikost písmen: na těchto +> systémech jsou `Desktop` a `desktop` dvě různá jména. + +> [note] Windows a disky +> Pokud přecházíš do adresáře na jiném disku, +> například `D:` místo `C:`, je potřeba kromě `cd` +> zadat jméno disku s dvojtečkou jako zvláštní příkaz (např. `D:`). + + +## Cesta zpět + +Zkusíme teď místo do `Desktop` (nebo `Plocha`) přejít do `Music` +(nebo `Hudba)`. + +Když zadáš `cd Music`, pravděpodobně uvidíš *chybu*: v aktuálním +adresáři (`Desktop`) žádné `Music` není. + +Aby ses do něj dostal{{a}}, musíš nejdřív zpátky, do „nadřazeného“ adresáře. +To dělá příkaz `cd ..` – `cd`, mezera, a dvě tečky. +Zkus ho zadat a pak se podívat, jak se aktuální adresář změnil: + +{% call sidebyside() %} +$ cd .. +$ pwd +/home/helena +--- +> cd .. +> cd +C:\Users\helena +{% endcall %} + +Z domovského adresáře už můžeš zadat `cd Music` (nebo `cd Hudba`) bez chyby. + + +## Další příkazy + +Textových příkazů existuje daleko víc než `whoami` a `cd`. +Z příkazové řádky můžeš vytvářet adresáře, měnit soubory, nebo si třeba přečíst +e-mail. + +I „grafické“ programy, které máš na počítači nainstalované, jdou +z příkazové řádky spustit – a to většinou jen zadáním jména. +Zkus, jestli na tvém počítači bude fungovat `firefox`, `notepad`, `safari` +nebo `gedit`. + +Při učení Pythonu si ale vystačíme s málem: s `cd`/`pwd` a několika příkazy, +které zanedlouho nainstalujeme – například `python`. + + +## Konec + +Nakonec vyzkoušej ještě jeden příkaz. +Ten, který příkazovou řádku zavírá: `exit`. + +Příkaz `exit` funguje stejně na všech systémech. +Proto už nebudu používat ukázku rozdělenou pro Unix a Windows. + +```console +$ exit +``` + +Ve zbytku těchto materiálů budeme pro kód, který je potřeba zadat do +příkazové řádky, používat unixovské `$`. +S touto konvencí se setkáš i ve většině návodů na internetu. +Používáš-li Windows, je dobré si na `$` zvyknout, i když ve své +řádce máš místo něj `>`. + diff --git a/lessons/fast-track/cmdline/info.yml b/lessons/fast-track/cmdline/info.yml new file mode 100644 index 0000000000..e384bff995 --- /dev/null +++ b/lessons/fast-track/cmdline/info.yml @@ -0,0 +1,8 @@ +title: Úvod do příkazové řádky +style: md +attribution: +- Pro PyLadies CZ napsal Petr Viktorin, 2014-2018. +- | + Založeno na tutoriálu [Django Girls]. + [Django Girls]: https://tutorial.djangogirls.org/en/intro_to_command_line/ +license: cc-by-sa-40 diff --git a/lessons/fast-track/cmdline/static/dirs.png b/lessons/fast-track/cmdline/static/dirs.png new file mode 100644 index 0000000000000000000000000000000000000000..5126a1ec959266b389419bb4812e0a96dde02713 GIT binary patch literal 3429 zcmai1X*3&JyN*vwYiK^yRLY@62ScftTj#4dsJUuZw9%kM)I3Cj9Mp+fQ4}3g+Cxn# zH795dMbhHXQjIZYLI{!Rrgze0;rD8 zj>$D`L`OxrcCl=~ zUawVh^YbC3>OcQ%Tz*wmH9fXGTzvJJWZ30qjd6JtmwjMmWAmX=J!<=ht-U?a-QE4R ztLyZTi>qsXK>^6mQ&?DdbJEMrEx`UD#)N;ua5T`2yOfugM`g0KP-1VGkc@CsM zOY{Wt#*O4_T1rYuRTapR;;a6nU%vb&A%QJZ%AP~Rg<#O0E zkWd48uP#LFS2U?Day=j*fFNV$?k>wKl%u0K3b8Dx$UG#ZHc$5Q9EnJzBnc|Wh_ku{ z6ZiHa!otG(zODhC79cARjLp7dFGjHUN9wCF7z|{j1Y}dJbG(AopDv-6s-B;hcLM@> z$*!cubz-sDukdk2SRy}S<}z<*#c>Dk$88XB3r?0ggK#`%-x512blwpV*pW=&0v5~;4Xwy#mW(zX;T z$QpfRZL;^-jK0g0!+8}I(b%n5)FO6RUPSDDvEcU*5kEIq zVG^rT?eg}F-k}nYj7171Z1PTY=5vZ#Fjc$Lt358ohv@O4sg`=Jf3nVJnL5|&)fp#Q zHD(2cQbh5!8ymqaBt9YZN?%So_y7u<={mZn>z}9XlE$?C8RmkI; zCt{wgm1`Mr=(M78VkEJY12qKaQ(=(vY!; zgH7uJyix3Zxj1iY>!BR@KBKgppsimT>dI(JprM9Y`*=YGMK(BoTY$kvD#R{|ol-C{ zm|xyXNlB^k?(`@NS@0UpSd?Habv|2X!q4(9%Yw_UshcbLJO0Duwe~M(OurkVm}Jui z)O-Ah@nKMx%oJxL5fu0*-Rt!J-d;{==}?gm(#p)NHz(`5;~~5_P!=>LValJ@+wJO; z0P>4NAXraoNjb))eN+j@Lv!#5$I}KK^M?(A8bq}d12N6PbJAidKH$?xv7he09sIZ7 z;$itrN?k+a9_z{&x$*^Ub{yjj2jXfTeSZ$(iXanq_@ngG+-o+kp4u_aYN1p=Ht(~> zalf!6-?&_B76sOO%_c|ufPQ@K1GLO5&YKn6OLa5a5N4MekL$Das;?1*|9eF#Z;gOB}RAc zUSsKIRcx(a4lvrh8`zbs6~+ug0w_4fM_di-(4_hf8VXYMTT;lLv2eKZ%$ds9(SrU6 zfSG>&bRdt~2W@!jYcfO^*{QGMiKB}pq3w5DOm~S&3&*2`^ z{--yS-Yyxt*%(Wr4rz(#o+!OgKSyo>wxJ1eXV&*KX^K42fcvw|Z!I8UC3<+GOFTUj ziXud~aQlTk4iJQ$&)6X{&GwT>9^Vw_20CGKmA3K2tiDxIm!?3Ozl(Ba=730c_GqVl zc_R>df6d@@dP9k#FJ+;FxRU9@9PFr+EO1W0kBV80Ou~-ISsHeBF9H#J?-d-a zFd3y#)ay2&1dD)>d^gZ?67>ry_ZZ&wo3v~+2z9I*7zN1asx8TMD@?iX?pJu2TKqou z%;x1>nKz7cqSrg`Hv07Tsm;FDmI;4+yj1AKBH6;KGR661n@^gh`d_T)KOYXglSc)Q z+ja-}en~6B%sDgxLvKa&_|hpsTInCWai)2**+>Aj>FL58;|-l#Mw6m`jIE<*SO)7e zdj-jR90>@4wQf<+JkSzIPpjV1j%X@V3K>1!#yP6I>FI|UXZgnPqbCZB_WrWOAD}!* zF7hcPJ{{;Y7)5+Lvgzv7o*cbj(TT=jpz?+}z&HE;|@|7Rurz2N>y sgMUBs|2)0*<#BY$m-qf%9K%sG+Q92P(!@h~UnGE)xgEInhHvtJ0dght%>V!Z literal 0 HcmV?d00001 diff --git a/lessons/fast-track/cmdline/static/windows-cmd-properties.png b/lessons/fast-track/cmdline/static/windows-cmd-properties.png new file mode 100644 index 0000000000000000000000000000000000000000..ebb2040b0a9a3ddd60c7965f13b38f64608fc0a6 GIT binary patch literal 23872 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 VS> literal 0 HcmV?d00001 From fc0d9ebe4df1fc6cc148426e6fb28ddae7b02327 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 4 Oct 2018 18:58:09 +0200 Subject: [PATCH 22/30] fast-track/script: Change to the lesson directory, not desktop --- lessons/fast-track/script/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/fast-track/script/index.md b/lessons/fast-track/script/index.md index cf31c748fe..512480dfc2 100644 --- a/lessons/fast-track/script/index.md +++ b/lessons/fast-track/script/index.md @@ -55,7 +55,7 @@ operačnímu systému, že jde o program v Pythonu a Python ho může spustit. Pokud máš soubor uložen, je čas jej spustit! Pomocí dovedností, které jsi se naučil{{a}} v sekci -o příkazové řádce, *změň adresář* terminálu na plochu. +o příkazové řádce, *změň adresář* na ten, kam jsi soubor uložil{{a}}. {% if var('coach-present') %} Pokud nevíš jak dál, požádej o pomoc kouče. From 67d6469953dc12b6972848a5a5875be45bbff6b8 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 5 Oct 2018 18:33:10 +0200 Subject: [PATCH 23/30] Hotfix: Update Python download link for Windows The download page was "simplified", which invalidates our instructions :( --- lessons/beginners/install/windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/beginners/install/windows.md b/lessons/beginners/install/windows.md index 6d2940ad36..e0210ce66c 100644 --- a/lessons/beginners/install/windows.md +++ b/lessons/beginners/install/windows.md @@ -1,6 +1,6 @@ # Instalace Pythonu pro Windows -Běž na [stahovací stránku Pythonu](https://www.python.org/downloads/) +Běž na [stahovací stránku Pythonu](https://www.python.org/downloads/release/python-370/) a stáhni si instalátor nejnovější stabilní verze Pythonu. Ověř si že je to verze **3.6.0 nebo novější** – verze 3.6.0 má jistá vylepšení, která budeme v tomto kurzu používat. From a03f40937d87914a273ad1a57a5b4644fb359428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Proch=C3=A1zka?= Date: Thu, 11 Oct 2018 22:19:40 +0200 Subject: [PATCH 24/30] Update index.md --- lessons/fast-track/str/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/fast-track/str/index.md b/lessons/fast-track/str/index.md index a49f9f6f20..4e09b8915b 100644 --- a/lessons/fast-track/str/index.md +++ b/lessons/fast-track/str/index.md @@ -159,7 +159,7 @@ Zkus se zamyslet, jak Python zpracuje tyto výrazy: ```pycon >>> len('Ola'.upper()) -4 +3 ``` ```pycon From 76d9eb0d9bdb9b1fac90ca1a82955c2d99c2d45e Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 12 Oct 2018 19:26:50 +0200 Subject: [PATCH 25/30] Add a lesson on importing and randomness --- courses/snake/info.yml | 1 + lessons/snake/import/index.md | 84 +++++++++++++++++++++++++++++++++++ lessons/snake/import/info.yml | 4 ++ 3 files changed, 89 insertions(+) create mode 100644 lessons/snake/import/index.md create mode 100644 lessons/snake/import/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml index 6e8c556337..a651113673 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -52,6 +52,7 @@ plan: - lesson: fast-track/conversion - lesson: fast-track/variables - lesson: fast-track/list + - lesson: snake/import - lesson: fast-track/dict - lesson: fast-track/bool - lesson: fast-track/script diff --git a/lessons/snake/import/index.md b/lessons/snake/import/index.md new file mode 100644 index 0000000000..b4244eb1b6 --- /dev/null +++ b/lessons/snake/import/index.md @@ -0,0 +1,84 @@ +# Import a náhoda + +V Pythonu je spousta funkčnosti k dispozici přímo – funkce jako `print`, `len` +nebo `int` můžeš rovnou použít. +Ještě víc věcí je v Pythonu sice k dispozici, ale jen když si „o ně řekneš“. +Jsou sdružené do *modulů* – souborů funkcí (a dalších věcí), které spolu nějak +souvisí. + +Například když chceme pracovat s náhodnými hodnotami, můžeš využít modul +`random`. +Naimportuj z něj funkci `randrange`: + +```pycon +>>> from random import randrange +``` + +Jakmile to uděláš, funkce `randrange` ti bude k dispozici. +Můžeš ji zavolat, a dostat tak náhodné číslo: + +```pycon +>>> randrange(6) +3 +>>> randrange(6) +1 +>>> randrange(6) +2 +>>> randrange(6) +4 +>>> randrange(6) +5 +>>> randrange(6) +3 +>>> randrange(6) +0 +>>> randrange(6) +3 +>>> randrange(6) +1 +``` + +Argument funkce `randrange` udává, kolik možných výsledků může vrátit. +Funkce pak vrací čísla od nuly, takže `randrange(6)` může vrátit od 0, 1, 2, +3, 4 nebo 5. Šestku už ne. + + +## Náhoda a seznamy + +Naimportuj si ještě dvě funkce: + +```pycon +>>> from random import choice, shuffle +``` + +První z nich, `choice`, umí vybrat náhodný prvek ze seznamu: + +```pycon +>>> loterie = [3, 42, 12, 19, 30, 59] +>>> choice(loterie) +12 +>>> choice(loterie) +30 +``` + +Druhá, `shuffle`, umožní seznam náhodně zamíchat. +Podobně jako metoda `sort`, `shuffle` nic nevrací – jen potichu změní pořadí: + +```pycon +>>> loterie = [3, 42, 12, 19, 30, 59] +>>> shuffle(loterie) +>>> loterie +[12, 59, 19, 42, 3, 30] +>>> shuffle(loterie) +>>> loterie +[59, 3, 30, 19, 12, 42] +``` + +## Shrnutí + +Tohle byla docela krátká sekce – ale důležitá! + +* **Import** nám může zpřístupnit funkce z **modulů**, + které nejsou k dispozici přímo v Pythonu. +* Modul `random` obsahuje funkce na výběr náhodných čísel nebo náhodných + prvků ze seznamu. diff --git a/lessons/snake/import/info.yml b/lessons/snake/import/info.yml new file mode 100644 index 0000000000..7c79a401b2 --- /dev/null +++ b/lessons/snake/import/info.yml @@ -0,0 +1,4 @@ +title: Import a náhoda +style: md +attribution: Pro Hadí workshop napsal Petr Viktorin, 2018. +license: cc-by-sa-40 From 93ae6a66923206a6a16d1761a688e0a5f481ccc8 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 1 Feb 2019 17:55:40 +0100 Subject: [PATCH 26/30] fast-track: Rewordings and minor reorderings/additions --- lessons/fast-track/bool/index.md | 11 ++++---- lessons/fast-track/def/index.md | 4 +-- lessons/fast-track/dict/index.md | 8 +++--- lessons/fast-track/if/index.md | 8 +++--- lessons/fast-track/list/index.md | 38 ++++++++++++--------------- lessons/fast-track/pyglet/index.md | 2 +- lessons/fast-track/script/index.md | 17 +++++++----- lessons/fast-track/tuple/index.md | 13 ++++----- lessons/fast-track/variables/index.md | 16 +++++++---- 9 files changed, 62 insertions(+), 55 deletions(-) diff --git a/lessons/fast-track/bool/index.md b/lessons/fast-track/bool/index.md index 1bb9455399..7e77d1dd2e 100644 --- a/lessons/fast-track/bool/index.md +++ b/lessons/fast-track/bool/index.md @@ -96,8 +96,7 @@ V Pythonu můžeš zkombinovat několik porovnání do jednoho! ## Přítomnost Nebylo by pěkné zjistit, jestli tvoje číslo vyhrálo v loterii? -K tomu budeš potřebovat zjistit, jestli seznam obsahuje daný prvek. -Používá se na to operátor `in`: +Máš-li seznam, operátorem `in` se můžeš zeptat, jestli je v něm daný prvek: ``` pycon >>> loterie = [3, 42, 12, 19, 30, 59] @@ -107,16 +106,16 @@ False True ``` -Není to úplně porovnání, ale dostaneš stejný druh výsledku. +Není to úplně porovnání, ale dostaneš stejný druh výsledku jako s `<` či `==`. ## Pravdivostní hodnoty Právě ses dozvěděl{{a}} o novém typu objektu v Pythonu. -Podobně jako máme řetězec, číslo, seznam nebo slovník existuje -*pravdivostní hodnota*, nebo častěji anglicky *boolean*. +Už známe typy řetězc, číslo, seznam nebo slovník; přidali jsme k nim +*pravdivostní hodnotu*, nebo častěji anglicky *boolean*. -Může mít jednu z dvou hodnot: `True` a `False`. +Pravdivostní hodnoty jsou jenom dvě: `True` (pravda) nebo `False` (nepravda). Aby Python pochopil, že se jedná o tento typ, je potřeba dávat pozor na velikost písmen. diff --git a/lessons/fast-track/def/index.md b/lessons/fast-track/def/index.md index eb634ef0d9..331a105436 100644 --- a/lessons/fast-track/def/index.md +++ b/lessons/fast-track/def/index.md @@ -80,7 +80,7 @@ Předtím, než se k příkazu `def` dostane, funkce neexistuje. ## Parametry Tvoje funkce se dá volat jen jako `pozdrav()`. -Funkce jako `len('slovo')` a `print(1 + 2)` umí navíc pracovat s hodnotou. +Funkce ale jako `len('slovo')` a `print(1 + 2)` umí navíc pracovat s hodnotou. Poďme napisať funkciu, ktorá ťa pozdraví menom. (Uľahčíme si to použitím jazyka, ktorý nepoužíva piaty pád.) @@ -161,7 +161,7 @@ def dvojnasobek(x): print(dvojnasobek(42)) ``` -Zkus napsat funkci, která pátý pád nějakého jména, třeba: +Zkus se zamyslet, jak napsat funkci, která pátý pád nějakého jména. Třeba: * `paty_pad('Ola')` → 'Olo' * `paty_pad('Soňa')` → 'Soňo' diff --git a/lessons/fast-track/dict/index.md b/lessons/fast-track/dict/index.md index 949b107b0a..4d75c1b746 100644 --- a/lessons/fast-track/dict/index.md +++ b/lessons/fast-track/dict/index.md @@ -1,7 +1,7 @@ # Slovníky Jiný typ hodnot, které v sobě mohou obsahovat další hodnoty, je *slovník*. -Pro příklad si představ překladový slovník, třeba česko-anglický: +Pro příklad si představ překladový slovník, třeba tenhle česko-anglický: * **Jablko**: Apple * **Knoflík**: Button @@ -11,7 +11,7 @@ Slovník v Pythonu obsahuje záznamy, a každý záznam přiřazuje nějakému *klíči* nějakou *hodnotu*. V našem příkladu je klíči *Jablko* přiřazena hodnota *Apple*, klíči *Knoflík* náleží hodnota *Button* -a klič *Myš* ukazuje na *Mouse*. +a klíč *Myš* ukazuje na *Mouse*. V Pythonu by se takový slovník napsal následovně: @@ -21,7 +21,7 @@ V Pythonu by se takový slovník napsal následovně: Naše klíče a hodnoty jsou slova – krátké texty, tedy řetězce, které je potřeba dát do uvozovek. -Klíč a hodnota jsou oddělené dvojtečkou, +Každý klíč je od své hodnoty oddělený dvojtečkou, jednotlivé dvojice se od sebe oddělují čárkou, a celý slovník je uzavřený ve složených závorkách. @@ -36,7 +36,7 @@ Pomocí hranatých závorek můžeš zjistit hodnotu, která danému klíči odp ``` Je to podobné jako u seznamů, jen v hranatých závorkách není index -(pořadí prvku) nebo rozmezí s dvojtečkou, ale klíč. +(pořadí prvku) nebo rozmezí s dvojtečkou, ale právě klíč. > [note] > Naopak to nejde – slovník neumožňuje podle hodnoty přímo zjistit klíč. diff --git a/lessons/fast-track/if/index.md b/lessons/fast-track/if/index.md index 8f0703c626..74768f6171 100644 --- a/lessons/fast-track/if/index.md +++ b/lessons/fast-track/if/index.md @@ -20,7 +20,7 @@ Lepší program by dělal tohle: * Když je heslo správné: * Pustí uživatele dovnitř -Anglicky se „když“ řekne *if*. A to je i jméno Pythoního příkazu. +Anglicky se „když“ řekne *if*. A to je i jméno Pythonního příkazu. Používá se takhle: ```python @@ -53,7 +53,7 @@ Zadej heslo: sezam ## Jinak V předchozím příkladu byl kód proveden pouze v případě, že podmínka byla splněna. -Ještě lepší program by ale: +Ještě lepší program by ale byl tenhle: * Zeptá se na tajné heslo * Když je heslo správné: @@ -85,7 +85,7 @@ Napišme program, který okomentuje hlasitost hudby: * Když je hlasitost do 20: * vypíše „Je to dost potichu.“ * Jinak, když je hlasitost do 40: - * vypíše „Jako hudba v pozadí dobré.“ + * vypíše „Jako hudba na pozadí dobré.“ * Jinak, když je hlasitost do 60: * vypíše „Skvělé, slyším všechny detaily.“ * Jinak, když je hlasitost do 80: @@ -102,7 +102,7 @@ hlasitost = int(input('Jaká je nastavená hlasitost rádia? ')) if hlasitost < 20: print("Je to dost potichu.") elif hlasitost < 40: - print("Jako hudba v pozadí dobré.") + print("Jako hudba na pozadí dobré.") elif hlasitost < 60: print("Skvělé, slyším všechny detaily.") elif hlasitost < 80: diff --git a/lessons/fast-track/list/index.md b/lessons/fast-track/list/index.md index f77300329d..e2ff2a37a8 100644 --- a/lessons/fast-track/list/index.md +++ b/lessons/fast-track/list/index.md @@ -44,7 +44,7 @@ Teď si zkus seznam seřadit. Na to existuje metoda `sort`: >>> loterie.sort() ``` -Tato funkce nic nevrátí, jen změní pořadí čísel v seznamu. +Tato metoda nic nevrátí, ale „potichu“ změní pořadí čísel v seznamu. Znovu si ho vypiš, ať vidíš co se stalo: ``` pycon @@ -65,7 +65,7 @@ Vyzkoušej si ji! ## Přidávání do seznamu -Podobně jako u řetězců se seznamu dají spojovat pomocí `+`: +Podobně jako u řetězců se seznamy dají spojovat pomocí `+`: ``` pycon >>> loterie + [5, 6, 7, 8] @@ -81,7 +81,7 @@ Tím se vytvoří nový seznam, ten původní zůstává nezměněný: Pokud chceš něco přidat do původního seznamu, můžeš to provést pomocí metody `append`. -Ale pozor! Tahle metoda potřebuje vědět co má do seznamu přidat +Ale pozor! Tahle metoda potřebuje vědět co má do seznamu přidat. Nová hodnota se zadává do závorek: ``` pycon @@ -198,7 +198,7 @@ Stý prvek od konce v seznamu není. Nastane chyba. Chceš-li ze seznamu něco odstranit, můžeš opět použít indexy. Tentokrát s příkazem `del`. -Následující kód odstraní počáteční číslo seznamu, tedy prvek číslo 0: +Následujícím kódem odstraň počáteční číslo seznamu, tedy prvek číslo 0: ``` pycon >>> del loterie[0] @@ -221,21 +221,6 @@ Zkusíš odstranit poslední prvek? ``` {% endfilter %} -A co prostřední tři? -Zkus si nejdřív vypsat, které to jsou, a pak teprve použít `del`. - -{% filter solution %} -``` pycon ->>> loterie -[42, 30, 19, 12, 3] ->>> loterie[1:-1] -[30, 19, 12] ->>> del loterie[1:-1] ->>> loterie -[42, 3] -``` -{% endfilter %} - Občase se stane, že nechceš smazat prvek podle pozice, ale podle toho, co v seznamu je. K tomu slouží hodnota `remove`, která najde a odstraní danou hodnotu: @@ -317,10 +302,21 @@ Začátek a konec se dá kombinovat – číslo můžeš dát před i za dvojte ['Druhý', 'Třetí'] ``` +Řezání funguje i pro příkaz `del`. +Zkus vymazat prostřední dvě čísla: + +``` pycon +>>> cisla +['První', 'Druhý', 'Třetí', 'Čtvrtý'] +>>> del cisla[1:-1] +>>> cisla +['První', 'Čtvrtý'] +``` + ## Řezání řetězců -Hranaté závorky fungují i u řetězců: +Hranaté závorky fungují i u řetězců, kde vybírají písmenka: ``` pycon >>> jidlo = 'čokoláda' @@ -330,7 +326,7 @@ Hranaté závorky fungují i u řetězců: 'oko' ``` -Představ si, že máš v proměnné `jmeno` jméno jako `'Ola'`, +Představ si, že máš v proměnné `jmeno` ženské jméno jako `'Ola'`, `'Krystýna'` nebo `'Růžena'`. Jak z něj vytvoříš druhý pád (např. bez `'Růženy'`)? diff --git a/lessons/fast-track/pyglet/index.md b/lessons/fast-track/pyglet/index.md index e2bdce0b92..f410bbdd47 100644 --- a/lessons/fast-track/pyglet/index.md +++ b/lessons/fast-track/pyglet/index.md @@ -67,7 +67,7 @@ Spusť ho. Mělo by se objevit černé okýnko. > Jestli dostaneš chybu > `AttributeError: module 'pyglet' has no attribute 'window'`, zkontroluj si, > zě jsi soubor pojmenoval{{a}} `grafika.py` a ne `pyglet.py`. -> Soubor v editoru„ulož jako `grafika.py`, případný soubor `pyglet.py` smaž, +> Soubor v editoru ulož jako `grafika.py`, případný soubor `pyglet.py` smaž, > a zkus to znovu. Hotovo? Pojďme si vysvětlit, co se v tomhle programu děje. diff --git a/lessons/fast-track/script/index.md b/lessons/fast-track/script/index.md index 512480dfc2..320ff6e13c 100644 --- a/lessons/fast-track/script/index.md +++ b/lessons/fast-track/script/index.md @@ -13,7 +13,7 @@ Vyzkoušejme si to. Budeme potřebovat: * Ukončit interaktivní režim Pythonu * Otevřít editor kódu * Uložit kód do nového souboru -* Spustit ho! +* Spustit kód ze souboru! Zkus vypnout Python. Existuje na to funkce `exit()`: @@ -28,7 +28,7 @@ ale ne příkazy Pythonu, jako `1 + 1`. Doufám, že máš nainstalovaný [textový editor](../../beginners/install-editor/). -Ten teď otevři, udělej si nový soubor a napiš něj tento příkaz: +Ten teď otevři, udělej si nový soubor a napiš do něj tento příkaz: ```python print('Hello, PyLadies!') @@ -50,7 +50,7 @@ operačnímu systému, že jde o program v Pythonu a Python ho může spustit. > Nazývá se to "zvýrazňování syntaxe" a je to užitečná funkce. > Chce to trochu praxe, ale barvy můžou napovědět > že ti chybí uvozovka za řetězcem -> nebo máš překlep v klíčovém slovu jako `del`. +> nebo máš překlep v klíčovém slově jako `del`. > To je jeden z důvodů, proč používáme editory kódu :) Pokud máš soubor uložen, je čas jej spustit! @@ -61,7 +61,10 @@ o příkazové řádce, *změň adresář* na ten, kam jsi soubor uložil{{a}}. Pokud nevíš jak dál, požádej o pomoc kouče. {% endif %} -Nyní pomocí Pythonu spusť kód v souboru: +Nyní pomocí Pythonu spusť kód v souboru: zadej příkaz `python`, mezeru +a jméno souboru ke spuštění. +(Je to podobné jako příkaz `cd` pro konkrétní adresář – +cd jmeno_adresare.) ``` console (venv) $ python python_intro.py @@ -75,7 +78,7 @@ Cítíš se úžasně? ## Vstup a výstup -Funkce `print()`, kterou jsi použila, umí něco *vypsat* na obrazovku. +Funkce `print()`, kterou jsi použil{{a}}, umí něco *vypsat* na obrazovku. V konzoli se hodnoty výrazů vypisovaly automaticky, abys je mohl{{a}} průběžně kontrolovat, ale programy v souborech bývají složitější a výpisy z každého kroku by byly nepřehledné. @@ -105,6 +108,7 @@ Odpověď pak vrátí jako řetězec, který si můžeš uložit do proměnné: ``` python jmeno = input('Jak se jmenuješ? ') + print(jmeno, 'umí programovat!') ``` @@ -113,6 +117,7 @@ Pamatuješ si na funkci, která umí převést řetězec na číslo? ``` python letopocet = int(input('Jaký je letos rok? ')) + print('Loni byl rok', letopocet - 1) ``` @@ -142,6 +147,6 @@ Až se k programu za pár dní nebo měsíců vrátíš, poděkuješ si! ## Shrnutí -* Příkaz **python** spustí uložený soubor jako program v Pythonu. +* Příkaz **python** pustí uložený soubor jako program v Pythonu. * Funkce **print** vypisuje hodnoty. * **Komentáře** můžou zpřehlednit složitější kód. Python je ignoruje. diff --git a/lessons/fast-track/tuple/index.md b/lessons/fast-track/tuple/index.md index b3fd659704..2c763c5490 100644 --- a/lessons/fast-track/tuple/index.md +++ b/lessons/fast-track/tuple/index.md @@ -34,10 +34,10 @@ def podil_a_zbytek(a, b): print(podil_a_zbytek(5, 2)) ``` -Tomuhle se říká dvojice – nebo trojice, čtveřice, pětice, šestice, prostě -n-tice (angl. *tuple*) hodnot. -Funguje podobně jako seznam, ale nedají se do ní přidávat prvky, nebo odebírat -a jinak měnit. +Tomuhle se říká dvojice – a podobně se tvoří trojice, čtveřice, pětice, +šestice, prostě n-tice (angl. *tuple*) hodnot. +Funguje podobně jako seznam, ale nedá se měnit – např. se do ní nedají +přidávat další prvky pomocí `append`. Když mám trojici, vždycky zůstane jako trojice. Když máš n-tici, můžeš ji přiřazením *rozbalit* (angl. *unpack*) @@ -74,7 +74,7 @@ for hodnota, barva in ruka: ## Zip -N-tice, respektive sekvenci n-tic vrací funkce `zip`, +N-tice, respektive sekvenci n-tic, vrací funkce `zip`, která umožňuje projít zároveň několik seznamů, jejichž prvky si navzájem odpovídají: @@ -87,4 +87,5 @@ for vec, barva, misto in zip(veci, barvy, mista): print(barva, vec, 'je', misto) ``` - +V tomhle cyklu dostaneš napřed trojici prvních prvků ze všech tří seznamů, +pak trojici všech druhých prvků, pak třetích, a tak dále. diff --git a/lessons/fast-track/variables/index.md b/lessons/fast-track/variables/index.md index b3828979e4..91fa6bb626 100644 --- a/lessons/fast-track/variables/index.md +++ b/lessons/fast-track/variables/index.md @@ -16,10 +16,11 @@ To se zapíše takto: Proměnná `jmeno` teď bude mít hodnotu `'Ola'`. Jak sis mohl{{a}} všimnout, tenhle příkaz nic nevrátil – Python nevypsal -žádný výslede. +žádný výsledek. Jak tedy víme, že proměnná skutečně existuje? -Zadej samotné jméno proměnné (tedy `jmeno`) a stiskni Enter: +Zadej samotné jméno proměnné (tedy `jmeno`, bez uvozovek) a stiskni +Enter: ``` pycon >>> jmeno @@ -100,15 +101,20 @@ Která z těchto jmen ti Python dovolí použít jako proměnnou? * `tlacitko5` * `5tlacitko` +* `tlačítko` * `oblibena barva` * `oblibena-barva` +* `oblibenaBarva` {% filter solution %} -* `tlacitko5` ano -* `5tlacitko` ne: jména musí začínat písmenkem +* `tlacitko5` ano. +* `5tlacitko` ne: jména musí začínat písmenkem. +* `tlačítko` ano, ale je diakritice (`č`, `í`) je lepší se vyhnout. * `oblibena barva` ne: to není jedno jméno, ale dvě! -* `oblibena-barva` taky ne: je to výraz `oblibena` mínus `barva` +* `oblibena-barva` taky ne: to Python bere jako odečtení dvou proměnných + (`oblibena` mínus `barva`). +* `oblibenaBarva` ano, ale velkým písmenům je lepší se vyhnout. Kdybys potřeboval{{a}} ve jménu více slov, použij podtržítko: např. `oblibena_barva`. From 336ad008a8be5a3d2310a412058699d40d85fccf Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 1 Feb 2019 17:56:11 +0100 Subject: [PATCH 27/30] Snake workshop: Add a section on the random module (and importing) --- courses/snake/info.yml | 2 +- lessons/fast-track/random/index.md | 55 ++++++++++++++++++++++++++++++ lessons/fast-track/random/info.yml | 5 +++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 lessons/fast-track/random/index.md create mode 100644 lessons/fast-track/random/info.yml diff --git a/courses/snake/info.yml b/courses/snake/info.yml index a651113673..4133cb22ea 100644 --- a/courses/snake/info.yml +++ b/courses/snake/info.yml @@ -52,7 +52,7 @@ plan: - lesson: fast-track/conversion - lesson: fast-track/variables - lesson: fast-track/list - - lesson: snake/import + - lesson: fast-track/random - lesson: fast-track/dict - lesson: fast-track/bool - lesson: fast-track/script diff --git a/lessons/fast-track/random/index.md b/lessons/fast-track/random/index.md new file mode 100644 index 0000000000..3cd715ab59 --- /dev/null +++ b/lessons/fast-track/random/index.md @@ -0,0 +1,55 @@ +# Náhoda + +Občas je potřeba vybrat náhodnou hodnotu. +Na to není v Pythonu funkce k dispozici přímo, ale dá se zpřístupnit +pomocí příkazu `import`" + +```pycon +>>> from random import randrange +>>> randrange(6) +3 +``` + +Neboli: + +* Z modulu `random` (který obsahuje funkce kolem náhodných hodnot) + zpřístupni funkci `randrange` (která umí vybírat náhodná čísla). +* Vyber náhodné číslo ze šesti možností. + +Volání funkce `randrange` několikrát opakuj. +Jaká čísla můžeš dostat? + +{% filter solution %} +Čísla od 0 do 5 – šestku ne. +Programátoři totiž počítají od nuly, a když počítáš od nuly a chceš šest čísel, dostaneš se jen k pětce. +{% endfilter %} + +Modulů jako `random`, ze kterých se dají *naimportovat* užitečná rozšiření, +je spousta – na práci s textem, kreslení obrázků, práci se soubory nebo dny +v kalendáři, kompresi dat, posílání e-mailů, stahování z internetu… +Stačí jen vědět (nebo umět najít), jak se ten správný modul a funkce jmenuje. +A kdyby nestačilo to, co má Python zabudované v sobě, další rozšiřující moduly +se dají doinstalovat. + +## Náhodný výběr + +Když už jsme u náhody, zkusme si ještě vylosovat náhodné číslo v loterii. +Na výběr ze seznamu má modul `random` funkci `choice`: + +```pycon +>>> from random import choice +>>> loterie = [3, 42, 12, 19, 30, 59] +>>> choice(loterie) +12 +``` + +Podobně se dá vybrat náhodná karta z ruky, náhodný účastník kurzu, +náhodná barva – cokoli, co umíš dát do seznamu. + + +## Shrnutí + +* Příkaz **import** ti dá k dispozici funkčnost, která není k dispozici přímo + v Pythonu. +* Modul **random** obsahuje funkce **randrange** (náhodné číslo) a **choice** + (náhodný prvek seznamu). diff --git a/lessons/fast-track/random/info.yml b/lessons/fast-track/random/info.yml new file mode 100644 index 0000000000..80fe54e5e2 --- /dev/null +++ b/lessons/fast-track/random/info.yml @@ -0,0 +1,5 @@ +title: Náhoda +style: md +attribution: +- Pro PyLadies Brno napsal Petr Viktorin, 2019. +license: cc-by-sa-40 From f82b8106bd9da01d667e19c952c3e2f1a0d0dda8 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 1 Feb 2019 17:56:37 +0100 Subject: [PATCH 28/30] snake/drawing: Use nested loops instead of pathlib.Path --- lessons/snake/drawing/index.md | 68 ++++++++++------------------------ lessons/snake/logic/index.md | 28 +++++++------- 2 files changed, 34 insertions(+), 62 deletions(-) diff --git a/lessons/snake/drawing/index.md b/lessons/snake/drawing/index.md index 629ad3639a..18d8fc648e 100644 --- a/lessons/snake/drawing/index.md +++ b/lessons/snake/drawing/index.md @@ -229,7 +229,7 @@ def on_draw(): window.clear() for x, y in snake: green_image.blit(x * TILE_SIZE, y * TILE_SIZE, - width=TILE_SIZE, height=TILE_SIZE) + width=TILE_SIZE, height=TILE_SIZE) pyglet.app.run() ``` @@ -267,10 +267,10 @@ def on_draw(): window.clear() for x, y in snake: green_image.blit(x * TILE_SIZE, y * TILE_SIZE, - width=TILE_SIZE, height=TILE_SIZE) + width=TILE_SIZE, height=TILE_SIZE) for x, y in food: red_image.blit(x * TILE_SIZE, y * TILE_SIZE, - width=TILE_SIZE, height=TILE_SIZE) + width=TILE_SIZE, height=TILE_SIZE) pyglet.app.run() ``` @@ -336,43 +336,29 @@ bottom_top = pyglet.image.load('snake-tiles/bottom-top.png') Ale obrázků je spousta, tímhle způsobem by to bylo zdlouhavé a nejspíš bys na některý zapomněl{{a}}. -Proto Pythonu řekneme, aby nám dal všechny soubory s koncovkou `.png` v daném -adresáři. -Na to se dá použít třída `Path` z modulu [`pathlib`](https://docs.python.org/3/library/pathlib.html). -Zkus si do nového souboru, třeba `experiment.py`, napsat následující kód -a spustit ho. -Dokážeš vysvětlit, co dělá? +Proto si obrázky načteme automaticky, v cyklu, a dáme je do slovníku. -```python -from pathlib import Path - -TILES_DIRECTORY = Path('snake-tiles') - -for path in TILES_DIRECTORY.glob('*.png'): - print(path) -``` +Program bude vypadat takhle: -My z každého souboru potřebujeme nejlépe jméno, tedy místo -`snake-tiles/right-end.png` jenom `right-end`. -Na to naštěstí existuje atribut `stem` (*kořen*, t.j. jméno bez přípony). -Místo `print(path)` použij: +* Začni s prázdným slovníkem. +* Pro každý *začátek* (`bottom`, `end`, `left`, `right`, `top`): + * Pro každý *konec* (`bottom`, `end`, `left`, `right`, `top`, `dead`, `tongue`): + * Budeme načítat obrázek „začátek-konec“; tento + klíč si dej do proměnné + * Načti obrázek klíč.png + * Ulož obrázek do slovníku pod klíč. ```python - print(path.stem) +snake_tiles = {} +for start in ['bottom', 'end', 'left', 'right', 'top']: + for end in ['bottom', 'end', 'left', 'right', 'top', 'dead', 'tongue']: + key = start + '-' + end + image = pyglet.image.load('snake-tiles/' + key + '.png') + snake_tiles[key] = image ``` -Funguje? Máš vypsané všechny možné kousky hada? - -Teď budeme chtít načíst obrázky do *slovníku*. -*Klíče* slovníku, podle kterých budeme vyhledávat, budou jména, která jsi -právě vypsal{{a}}. -*Hodnoty* pak budou pygletí obrázky, které ve hře můžeš rovnou vykreslit. - -Začni s prázdným slovníkem, `{}`, a v cyklu `for` do něj postupně přidávej -záznamy. Pak celý slovník vypiš. - -Až to budeš mít, měl by výpis vypadat asi takhle: +Výpis vypadat asi takhle: ``` {'right-tongue': , 'top-tongue': , @@ -382,22 +368,6 @@ Až to budeš mít, měl by výpis vypadat asi takhle: ... ``` -{% filter solution %} -```python -from pathlib import Path - -import pyglet - -TILES_DIRECTORY = Path('snake-tiles') - -snake_tiles = {} -for path in TILES_DIRECTORY.glob('*.png'): - snake_tiles[path.stem] = pyglet.image.load(path) - -print(snake_tiles) -``` -{% endfilter %} - ## Housenka diff --git a/lessons/snake/logic/index.md b/lessons/snake/logic/index.md index 71f30c8058..4f426c3b09 100644 --- a/lessons/snake/logic/index.md +++ b/lessons/snake/logic/index.md @@ -16,20 +16,20 @@ XXX - Nestíhám dopsat, omlouvám se Tvůj program teď, doufám, vypadá nějak takhle: ```python -from pathlib import Path - import pyglet TILE_SIZE = 64 -TILES_DIRECTORY = Path('snake-tiles') snake = [(1, 2), (2, 2), (3, 2), (3, 3), (3, 4), (3, 5), (4, 5)] food = [(2, 0), (5, 1), (1, 4)] red_image = pyglet.image.load('apple.png') snake_tiles = {} -for path in TILES_DIRECTORY.glob('*.png'): - snake_tiles[path.stem] = pyglet.image.load(path) +for start in ['bottom', 'end', 'left', 'right', 'top']: + for end in ['bottom', 'end', 'left', 'right', 'top', 'dead', 'tongue']: + key = start + '-' + end + image = pyglet.image.load('snake-tiles/' + key + '.png') + snake_tiles[key] = image window = pyglet.window.Window() @@ -166,12 +166,9 @@ Pro kontrolu můžeš svůj program porovnat s mým (ale nejde o jediné správ {% filter solution %} ```python -from pathlib import Path - import pyglet TILE_SIZE = 64 -TILES_DIRECTORY = Path('snake-tiles') class State: def __init__(self): @@ -188,8 +185,11 @@ class State: red_image = pyglet.image.load('apple.png') snake_tiles = {} -for path in TILES_DIRECTORY.glob('*.png'): - snake_tiles[path.stem] = pyglet.image.load(path) +for start in ['bottom', 'end', 'left', 'right', 'top']: + for end in ['bottom', 'end', 'left', 'right', 'top', 'dead', 'tongue']: + key = start + '-' + end + image = pyglet.image.load('snake-tiles/' + key + '.png') + snake_tiles[key] = image window = pyglet.window.Window() @@ -816,7 +816,6 @@ from pathlib import Path import pyglet TILE_SIZE = 64 -TILES_DIRECTORY = Path('snake-tiles') class State: def __init__(self): @@ -879,8 +878,11 @@ class State: red_image = pyglet.image.load('apple.png') snake_tiles = {} -for path in TILES_DIRECTORY.glob('*.png'): - snake_tiles[path.stem] = pyglet.image.load(path) +for start in ['bottom', 'end', 'left', 'right', 'top']: + for end in ['bottom', 'end', 'left', 'right', 'top', 'dead', 'tongue']: + key = start + '-' + end + image = pyglet.image.load('snake-tiles/' + key + '.png') + snake_tiles[key] = image window = pyglet.window.Window() From 05e013bbdeef0b9e10b64a7b4df35a973bbc7c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Pavl=C3=A1sek?= Date: Fri, 1 Feb 2019 22:17:00 +0100 Subject: [PATCH 29/30] fix typo --- lessons/fast-track/script/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/fast-track/script/index.md b/lessons/fast-track/script/index.md index 320ff6e13c..15d97c865d 100644 --- a/lessons/fast-track/script/index.md +++ b/lessons/fast-track/script/index.md @@ -93,7 +93,7 @@ jmeno = 'Ola' print(jmeno * 8) # Tohle jo! ``` -Do závorek funkce `print()` můěš dát i víc hodnot oddělených čárkami. +Do závorek funkce `print()` můžeš dát i víc hodnot oddělených čárkami. ``` python jmeno = 'Amálka' From 9f4298d1b8a7ece2fdda4132a62ac6b75499659c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 1 Jul 2019 15:36:28 +0200 Subject: [PATCH 30/30] Remove duplicate lesson The content in snake/import is available in fast-track/random. --- lessons/snake/import/index.md | 84 ----------------------------------- lessons/snake/import/info.yml | 4 -- 2 files changed, 88 deletions(-) delete mode 100644 lessons/snake/import/index.md delete mode 100644 lessons/snake/import/info.yml diff --git a/lessons/snake/import/index.md b/lessons/snake/import/index.md deleted file mode 100644 index b4244eb1b6..0000000000 --- a/lessons/snake/import/index.md +++ /dev/null @@ -1,84 +0,0 @@ -# Import a náhoda - -V Pythonu je spousta funkčnosti k dispozici přímo – funkce jako `print`, `len` -nebo `int` můžeš rovnou použít. -Ještě víc věcí je v Pythonu sice k dispozici, ale jen když si „o ně řekneš“. -Jsou sdružené do *modulů* – souborů funkcí (a dalších věcí), které spolu nějak -souvisí. - -Například když chceme pracovat s náhodnými hodnotami, můžeš využít modul -`random`. -Naimportuj z něj funkci `randrange`: - -```pycon ->>> from random import randrange -``` - -Jakmile to uděláš, funkce `randrange` ti bude k dispozici. -Můžeš ji zavolat, a dostat tak náhodné číslo: - -```pycon ->>> randrange(6) -3 ->>> randrange(6) -1 ->>> randrange(6) -2 ->>> randrange(6) -4 ->>> randrange(6) -5 ->>> randrange(6) -3 ->>> randrange(6) -0 ->>> randrange(6) -3 ->>> randrange(6) -1 -``` - -Argument funkce `randrange` udává, kolik možných výsledků může vrátit. -Funkce pak vrací čísla od nuly, takže `randrange(6)` může vrátit od 0, 1, 2, -3, 4 nebo 5. Šestku už ne. - - -## Náhoda a seznamy - -Naimportuj si ještě dvě funkce: - -```pycon ->>> from random import choice, shuffle -``` - -První z nich, `choice`, umí vybrat náhodný prvek ze seznamu: - -```pycon ->>> loterie = [3, 42, 12, 19, 30, 59] ->>> choice(loterie) -12 ->>> choice(loterie) -30 -``` - -Druhá, `shuffle`, umožní seznam náhodně zamíchat. -Podobně jako metoda `sort`, `shuffle` nic nevrací – jen potichu změní pořadí: - -```pycon ->>> loterie = [3, 42, 12, 19, 30, 59] ->>> shuffle(loterie) ->>> loterie -[12, 59, 19, 42, 3, 30] ->>> shuffle(loterie) ->>> loterie -[59, 3, 30, 19, 12, 42] -``` - -## Shrnutí - -Tohle byla docela krátká sekce – ale důležitá! - -* **Import** nám může zpřístupnit funkce z **modulů**, - které nejsou k dispozici přímo v Pythonu. -* Modul `random` obsahuje funkce na výběr náhodných čísel nebo náhodných - prvků ze seznamu. diff --git a/lessons/snake/import/info.yml b/lessons/snake/import/info.yml deleted file mode 100644 index 7c79a401b2..0000000000 --- a/lessons/snake/import/info.yml +++ /dev/null @@ -1,4 +0,0 @@ -title: Import a náhoda -style: md -attribution: Pro Hadí workshop napsal Petr Viktorin, 2018. -license: cc-by-sa-40