Základy programování ve Squeaku - bloky a strukturované příkazy

Pavel Tišnovský 12. 8. 2010

V šesté části seriálu o programovacích jazycích vhodných pro výuku programování si popíšeme, jakým způsobem se ve Squeaku používají bloky a jaký význam bloky mají (společně se třídami Boolean, True, False aj.) při tvorbě strukturovaných příkazů, tj. podmínek a programových smyček.

Obsah

1. Programové bloky

2. Předávání parametrů do bloků

3. Třídy Boolean, True, False a jejich význam

4. Implementace podmíněných příkazů pomocí bloků

5. Zprávy & a |

6. Konstrukce programových smyček s využitím bloků

7. Počítaná smyčka s explicitně zadaným krokem

8. Další typy cyklů

9. Odkazy na Internetu

1. Programové bloky

V předchozí části seriálu o programovacích jazycích vhodných pro výuku programování jsme se v poslední kapitole stručně zmínili o takzvaných programových blocích neboli zkráceně o blocích používaných ve Squeaku i dalších dialektech jazyka Smalltalk. Programový blok se skládá ze dvou částí. První část tvoří nepovinné parametry, které jsou následovány posloupností výrazů. Celý blok je uzavřen do hranatých závorek [] a v případě, že se jedná o blok s parametry, jsou názvy parametrů bloku odděleny od posloupnosti výrazů pomocí znaku roury (pipe, |). Ze způsobu zápisu bloku by se mohlo zdát, že se jedná o obdobu běžných programových bloků známých z jiných programovacích jazyků (begin-end v Pascalu, {} v céčku či Javě atd.), ovšem ve skutečnosti se ve Squeaku bloky chovají poněkud odlišně, především v tom ohledu, že každý blok je současně plnohodnotným objektem, konkrétně instancí třídy BlockClosure.

To mj. znamená, že se bloku–objektu dají posílat různé zprávy a taktéž to, že blok může být parametrem jiných zpráv. Oba zmíněné mechanismy se poměrně často používají mj. i pro implementaci řídicích struktur (podmínek, programových smyček), které si popíšeme v následujících kapitolách. Další velmi důležitou vlastností bloků je to, že jsou vyhodnocovány explicitně, konkrétně po přijetí unární (bezparametrické) zprávy value. Dokud tato zpráva není bloku poslána, chová se blok jako objekt obsahující ve svých atributech seznam parametrů i seznam výrazů (jakým způsobem je uvnitř blok implementován nás prozatím nemusí zajímat), který není nijak vyhodnocován. Pomocí bloků lze, kromě již zmíněných řídicích struktur, implementovat například i uzávěry (closures), popř. zapisovat lambda výrazy, se kterými je ostatně syntaxe zápisu bloku velmi podobná. Například následující lambda výraz představující výpočet druhé mocniny:

λx → x*x

je možné ve Squeaku zapsat velmi jednoduše pomocí bloku:

[ :x | x * x ]

2. Předávání parametrů do bloků

Zastavme se nyní na chvíli u programového bloku, který byl uveden na konci první kapitoly. Jedná se o blok s jedním parametrem pojmenovaným x a jedním výrazem umístěným v těle bloku. Jakým způsobem však lze tento blok vyhodnotit, tj. jak mu lze předat skutečnou hodnotu parametru a získat výsledek (v tomto případě jediného) výrazu, který tvoří jeho tělo? Pokud by se jednalo o blok bez parametrů, byla by situace velmi jednoduchá, protože by postačovalo poslat bloku unární zprávu se selektorem value, což je ukázáno na následujících fragmentech kódu:

[ 6 * 7 ] value
42
[42 factorial] value
1405006117752879898543142606244511569936384000000000
[ 'ahoj' ] value
'ahoj'

U programového bloku, který akceptuje nějaký parametr nebo dokonce více parametrů, je situace odlišná pouze v tom, že se namísto unární zprávy se selektorem value musí bloku poslat zpráva s více parametry (nic jiného než posílání zpráv ostatně Squeak u bloků nezná a ani znát nepotřebuje). Takovým typem zprávy je například zpráva se selektorem value:, která umožňuje předat do bloku jeden parametr, zpráva se selektorem value:value:, pomocí níž lze předat parametry dva atd. Pohledem do System Browseru snadno zjistíme, že pro třídu BlockClosure (a taktéž BlockContext) existují ještě metody zpracovávající zprávy se selektory value:value:va­lue: a value:value:va­lue:value:. Pokud je zapotřebí do bloku předat více jak čtyři parametry (což je ovšem náznak toho, že blok pravděpodobně vykonává víc činností, než je obecně vhodné), lze mu předat zprávu se selektorem valueWithArgu­ments:, která má (jak ostatně název jejího selektoru napovídá – obsahuje jen jednu dvojtečku) pouze jeden parametr, kterým je v tomto případě pole, přičemž počet prvků tohoto pole není omezený. Jak si řekneme dále, lze použít jak konstantní pole, tak i takzvaná pole výrazová.

Vraťme se však k našemu prvnímu příkladu – k programovému bloku, který dokáže vypočítat druhou mocninu svého parametru, popř. poslat zprávu se selektorem * obecnému objektu, který je do bloku předán jako parametr (záleží již pouze na tomto objektu, zda a jak tuto zprávu dokáže zpracovat). Chování tohoto bloku si můžeme jednoduše odzkoušet, například následujícími způsoby. Povšimněte si, že se pokaždé do bloku předává objekt jiného typu, v posledním příkladu konstantní pole (jehož syntaxi jsme si prozatím nepopsali, ale pravděpodobně je z tohoto příkladu zřejmá):

[:x | x*x] value: 42
1764
[:x | x*x] value: 42.5
1806.25
[:x | x*x] value: 1/2
1/4
[:x | x*x] value: #(1 2 3 4 5 6 7 8 9)
#(1 4 9 16 25 36 49 64 81)

3. Třídy Boolean, True, False a jejich význam

Při konstrukci řídicích struktur ve Squeaku s využitím programových bloků se neobejdeme bez znalostí několika metod definovaných v abstraktní třídě Boolean a z ní odvozených tříd pojmenovaných příhodně True a False. Mimochodem, třídy True a False neumožňují vytváření libovolného množství svých instancí, takže v celém virtuálním stroji Squeaku je zaručeno, že existuje pouze jediná instance každé z těchto tříd. Jedná se o takzvané pseudo-proměnné true a false (jejichž hodnotu nelze měnit), které můžeme pro jednoduchost považovat za klíčová slova (dalšími de-facto klíčovými slovy jsou nil, self, super, thisContext a v některých dialektem Smalltalku i homeContext, další klíčová slova ve Squeaku neexistují a ani nejsou zapotřebí).

Omezení počtu instancí tříd True a False na jedináčky (singletony) má samozřejmě svůj význam, protože se tak například umožňuje lepší optimalizace volání jejich metod (posílání zpráv) na úrovni bajtkódu virtuálního stroje Squeaku (nehledě na to, že postačuje porovnávat reference těchto objektů a nikoli jejich atributy). V praxi je volání mnoha metod těchto instancí překládáno jako inline kód, čímž se obchází klasické a poněkud zdlouhavé posílání zpráv. Jinými slovy to znamená, že Squeak dokáže být (alespoň v této oblasti) stejně výkonný jako jiné programovací jazyky s virtuálním strojem a to bez toho, aby musel pro některé programové konstrukce zavádět speciální syntaktické kategorie. Ve třídě Boolean je zadefinováno několik metod, pomocí nichž lze implementovat jak strukturované podmínky, tak i například obdobu zkráceného vyhodnocování výrazů, které známe z některých dalších programovacích jazyků, jakými jsou například C, C++ či Java. Tyto metody jsou popsány v navazujících kapitolách.

4. Implementace podmíněných příkazů pomocí bloků

Nejprve si ukažme použití třídy Boolean (resp. potomků této třídy – singletonů) při konstrukci obdoby strukturovaných podmínek. Základem pro tvorbu těchto řídicích struktur jsou metody ifTrue:, ifFalse:, ifTrue:ifFalse: a ifFalse:ifTrue:. Jejich použití je poměrně jednoduché a přímočaré. Pokud je například singletonu true poslána zpráva se selektorem ifTrue:, vyhodnotí se parametr této zprávy, což by měl být programový blok (provádí se kontrola na typ parametru). V případě, že je zpráva s tímtéž selektorem naopak poslána singletonu false, blok (parametr zprávy) se nevyhodnotí a vrátí se pseudo-proměnná nil, což je jedinečná instance (tj. opět singleton – jedináček) třídy UndefinedObject. Přesně opačný význam má zpráva se selektorem ifFalse:, která v případě, že je jejím příjemcem objekt true vrátí nil a pokud je jejím příjemcem naopak objekt false, vrátí hodnotu vzniklou vyhodnocením bloku, který je v této zprávě předán jako parametr. Podívejme se na jednoduché příklady, v nichž se tyto zprávy posílají přímo objektům true a false:

true ifTrue: [ 42 ]
42
false ifTrue: [ 42 ]
nil
true ifFalse: [ 42 ]
nil
false ifFalse: [ 42 ]
42

Samozřejmě lze použít i složitější a současně i praktičtější konstrukce, protože některé metody vracejí true či false:

1 < 2 ifTrue: [ 'skutecne je 1 mensi nez 2' ]
'skutecne je 1 mensi nez 2'
1 < 2 ifTrue: [ 6*7 ]
42
(1/2) < (1/4) ifTrue: [ 'prvni zlomek je mensi' ]
nil
(1/4) < (1/2) ifTrue: [ 'prvni zlomek je mensi' ]
'prvni zlomek je mensi'
4 isString ifTrue: [ 'objekt je retezcem' ]
nil
'ahoj' isString ifTrue: [ 'objekt je retezcem' ]
'objekt je retezcem'

Další dvě metody ifTrue:ifFalse: a ifFalse:ifTrue: vždy vrátí, samozřejmě v závislosti na příjemci zprávy, jeden z vyhodnocených bloků, jsou tedy obdobou strukturovaných příkazů typu if-then-else:

true ifTrue: [ 'prvni blok' ] ifFalse: [ 'druhy blok' ]
'prvni blok'
false ifTrue: [ 'prvni blok' ] ifFalse: [ 'druhy blok' ]
'druhy blok'
true ifFalse: [ 'prvni blok' ] ifTrue: [ 'druhy blok' ]
'druhy blok'
false ifFalse: [ 'prvni blok' ] ifTrue: [ 'druhy blok' ]
'prvni blok'
1 < 2 ifTrue: [ 'jedna je mensi nez dva' ] ifFalse: [ 'je to presne naopak' ]
'jedna je mensi nez dva'

5. Zprávy & a |

Ve třídě Boolean jsou kromě metod zmíněných v předchozí kapitole dostupné i další užitečné metody, které je možné použít například při vytváření programového kódu, jehož některé části se mají provést pouze při splnění (nebo naopak nesplnění) nějaké podmínky. Jedná se o metody and:, or:, and:and:, or:or: (plus jejich varianty se třemi a čtyřmi parametry), & (ampersand) a | (pipe). Příjemcem těchto zpráv je vždy objekt true nebo false, který se rozhodne, jakým způsobem zpracuje parametr nebo parametry dané zprávy. Popišme si například metodu and: (vlastnosti metody or: jsou obdobné). Pokud je příjemcem zprávy se selektorem and: objekt true, vrátí se hodnota získaná vyhodnocením bloku předaného jako parametr zprávy, ale pokud je příjemcem objekt false, vrátí se, bez ohledu na obsah předaného bloku, samotný příjemce zprávy, tj. objekt false (zde se tedy chování zprávy and: odlišuje od zprávy ifTrue:). Podívejme se na příklady (opět jsou velmi jednoduché):

true and: [ 'blok' ]
'blok'
false and: [ 'blok' ]
false
1<2 and: [ 'jedna je mensi nez dva' ]
'jedna je mensi nez dva'
1>2 and: [ 'jedna je vetsi nez dva' ]
false

Zprávě and: se, i když poněkud vzdáleně, podobá zpráva mající selektor &. Jedná se o binární zprávu, tj. o zprávu posílanou s jedním parametrem. Při poslání této zprávy objektu true se vyhodnotí výraz (nikoli blok!), který je předán v parametru zprávy a vrátí se hodnota vyhodnoceného výrazu. Pokud se naopak tato zpráva pošle objektu false, vždy se vrátí hodnota false (to je logické, protože v Booleovské logice platí, že false and cokoli=false). Důležité přitom je, že se výraz vyhodnotí ve všech případech, tj. i tehdy, kdy je přímo na základě příjemce zprávy zřejmé, že by se výraz ve skutečnosti vyhodnocovat nemusel (viz příklad s objektem false jakožto příjemcem zprávy). Nedochází zde tedy ke zkrácenému vyhodnocování výrazů, na rozdíl od zpráv se selektorem and: a or:. Toto chování si můžeme ukázat na několika demonstračních příkladech:

true & 42
42
false & 42
false
true & (1+1)
2
false & (1+1)
false
true & (1/0)
*** dojde k chybě dělení nulou ***
false & (1/0)
*** dojde k chybě dělení nulou ***

Zpráva | má obdobné chování, které však odpovídá Booleovskému operátoru disjunkce. Pokud je zpráva s tímto selektorem poslána objektu true, vrátí se samotný příjemce zprávy, pokud je naopak poslána objektu false, je vrácen vyhodnocený výraz:

true | 'a'
true
false | 'b'
'b'

6. Konstrukce programových smyček s využitím bloků

Podobným způsobem, jakým jsme vytvářeli strukturované podmíněné příkazy lze ve Squeaku implementovat i programové smyčky, a to jak smyčky s podmínkami vyhodnocovanými na začátku či na konci těla smyčky (typy whilerepeat-until), tak i počítané programové smyčky (for). Jak již pravděpodobně tušíte, ani pro tvorbu smyček není ve Squeaku zavedena žádná speciální syntaktická kategorie, protože si můžeme bez větších omezení vystačit s programovými bloky a zprávami (to mj. znamená i to, že je možné si relativně snadno vytvořit nový typ programové smyčky). Pravděpodobně nejjednodušším typem smyčky, kterou lze ve Squeaku velmi snadno použít, je počítaná smyčka, u níž není k dispozici aktuální hodnota jejího počitadla (právě díky tomu je použití této smyčky jednoduché, složitější typy smyček budou ukázány v dalším textu). Tuto smyčku lze vytvořit pomocí zprávy timesRepeat:, která se pošle některé instanci třídy Integer, tj. většinou číselné konstantě. Podívejme se na příklad použití tohoto typu smyčky (před spuštěním následujícího příkazu si otevřete okno Transcript):

10 timesRepeat: [ Transcript show: 'test' ]

Po spuštění předchozího příkladu se do okna Transcript vypíše desetkrát slovo ‚test‘. Aby se za každé slovo vložil konec řádky, musí se objektu Transcript navíc poslat unární zpráva cr:

10 timesRepeat: [ Transcript show: 'test'. Transcript cr ]

Vzhledem k tomu, že unární i binární zprávy mají vyšší prioritu než zprávy s více parametry, lze zapsat i následující příkaz:

10+20 timesRepeat: [ Transcript show: 'test'. Transcript cr ]

Popř.:

3 factorial timesRepeat: [ Transcript show: 'test'. Transcript cr ]

Namísto číselné konstanty se může použít i proměnná, která je stále instancí třídy Integer, přesněji řečeno jejího potomka SmallInteger:

a:=10
a timesRepeat: [ Transcript show: 'test'. Transcript cr ]

7. Počítaná smyčka s explicitně zadaným krokem

Zůstaňme ještě na chvíli u počítaných smyček. V mnoha případech je nutné přímo v těle smyčky, tj. v případě Squeaku v bloku představujícího tělo smyčky, pracovat s aktuální hodnotou počitadla smyčky. Pro tento účel je možné použít zprávu se selektorem to:do:, kterou lze poslat jakékoli instanci třídy Number a samozřejmě i instancím potomků této třídy, například Integer či SmallInteger. Zpráva s tímto selektorem musí být poslána se dvěma parametry. Prvním parametrem je koncová hodnota počitadla (počáteční hodnota samozřejmě odpovídá hodnotě volaného objektu) a druhým parametrem je jednoparametrický blok, kterému je při každé iteraci předána aktuální hodnota počitadla. V následujícím příkladu je blok volán pro indexy, která nabývají hodnoty od 10 do 20 (včetně obou zmíněných hodnot):

10 to: 20 do: [ :i | Transcript show: i ]

Opět je přehlednější v okně Transcript po každém výpisu provést odřádkování:

10 to: 20 do: [ :i | Transcript show: i. Transcript cr ]

V případě, že je nutné počitadlo smyčky zvyšovat nikoli o jedničku, ale o uživatelem specifikovanou hodnotu, lze namísto zprávy se selektorem to:do: zavolat zprávu mající selektor to:by:do:. V této zprávě je navíc použit další (prostřední) parametr, kterým lze nastavit krok, o nějž se zvyšuje nebo naopak snižuje hodnota počitadla v každé iteraci. Chování této zprávy si můžeme jednoduše otestovat na dvojici příkladů. V prvním příkladu se počitadlo zvyšuje, ovšem s krokem 2, ve druhém příkladu se o dvojku naopak v každé iteraci snižuje:

1 to: 10 by: 2 do: [ :i | Transcript show: i. Transcript cr ]
10 to: 0 by: -2 do: [ :i | Transcript show: i. Transcript cr ]

Squeak si sám ohlídá některé mezní stavy, například pokus o vytvoření nekonečné smyčky s krokem 0. Následující příklad skončí s chybou:

widgety

0 to: 10 by: 0 do: [ :i | Transcript show: i. Transcript cr ]

Jako zajímavost si vyzkoušejte použití zlomků, se kterými lze ve Squeaku pracovat velmi komfortním způsobem:

0 to: 1 by: 1/10 do: [ :i | Transcript show: i. Transcript cr ]

8. Další typy cyklů

Kromě počítaných smyček je ve Squeaku možné relativně snadno používat i smyčky s podmínkou testovanou na začátku či konci těla smyčky a taktéž smyčky typu for-each, u nichž je tělo smyčky voláno pro každý prvek nějaké datové struktury (pole, seznamu…). Pro tyto účely se většinou používají některé zprávy posílané přímo programovým blokům. Jedná se především o zprávy se selektory whileTrue, whileFalse, whileTrue: a whileFalse:. Vzhledem k tomu, že se při použití těchto smyček ve většině případů neobejdeme bez proměnných (o nichž jsme prozatím takticky pomlčeli :-), vysvětlíme si způsob využití těchto zpráv příště, kde si taktéž ukážeme tvorbu tříd a objektů i práci s poli a vlastně tak popis vlastního programovacího jazyka Squeak ukončíme (později se budeme věnovat jeho grafickému uživatelskému rozhraní a způsobu úprav tohoto rozhraní, využití jednotlivých typů nabízených objektů atd.).

9. Odkazy na Internetu

  1. Squeak home page
    http://www.squ­eak.org/
  2. XO: The Children's Machine
    http://wiki.lap­top.org/go/The_Chil­dren's_Machine
  3. Squeak na Wikipedii EN
    http://en.wiki­pedia.org/wiki/Squ­eak
  4. Squeak na Wikipedii CZ
    http://cs.wiki­pedia.org/wiki/Squ­eak
  5. Squeak by Example
    http://squeak­byexample.org/
  6. Squeak Land
    http://www.squ­eakland.org/
  7. SqueakNotes
    http://squeak­.zwiki.org/Squ­eakNotes
  8. Squeak FAQ
    http://wiki.squ­eak.org/squeak/471
  9. Learning Squeak
    http://c2.com/cgi/wi­ki?LearningSqu­eak
  10. Scratch home page
    http://scratch­.mit.edu/
  11. Scratch (programming language)
    http://en.wiki­pedia.org/wiki/Scrat­ch_(programmin­g_language)
  12. Lazarus (Software)
    http://en.wiki­pedia.org/wiki/La­zarus_%28softwa­re%29
  13. FreePascal
    http://www.fre­epascal.org/
  14. „Why I Love Python“ slides
    http://www.min­dviewinc.com/dow­nloads/pub/ec­kel/LovePython­.zip
  15. „Why I love Python“ (presentation)
    http://www.sli­deshare.net/di­dip/why-i-love-python
  16. První jazyk: Python
    http://macek.san­dbox.cz/texty/prvni-jazyk-python/
  17. Programovací jazyk Python
    http://www.py­.cz/FrontPage
  18. Python – Wikipedia CS
    http://cs.wiki­pedia.org/wiki/Pyt­hon
  19. IPython
    http://en.wiki­pedia.org/wiki/I­python
  20. IPython: an interactive computing environment
    http://ipython­.scipy.org/mo­in/
  21. Category:Python
    http://rosetta­code.org/wiki/Ca­tegory:Python
  22. Educational programming language
    http://en.wiki­pedia.org/wiki/E­ducational_pro­gramming_langu­age
  23. Seriál Letní škola programovacího jazyka Logo
    http://www.ro­ot.cz/serialy/let­ni-skola-programovaciho-jazyka-logo/
  24. Logo Tree Project:
    http://www.eli­ca.net/downlo­ad/papers/Logo­TreeProject.pdf
  25. Language Poster (O'Reilly):
    http://www.ore­illy.com/news/grap­hics/prog_lan­g_poster.pdf
  26. Informace o Comenius Logu:
    http://www.com­logo.input.sk/in­dex.html
  27. Stránka nabízející stažení Comenius Loga:
    http://www.com­logo.input.sk/nas­tiahnutie.html
  28. Seminární práce o Comenius Logu:
    http://nwit.ped­f.cuni.cz/rotal9ap/lo­go/
  29. Informace o LEGO/Logu:
    http://educati­on.otago.ac.nz/nzlnet/L­ogo/legologo.html
  30. Informace o systému Elica:
    http://www.eli­ca.net/site/in­dex.html
  31. Informace o systému NetLogo:
    http://ccl.nor­thwestern.edu/ne­tlogo/
  32. Stažení NetLoga:
    http://ccl.nor­thwestern.edu/ne­tlogo/download­.shtml
  33. Uživatelský manuál NetLoga ve formátu PDF:
    http://ccl.nor­thwestern.edu/ne­tlogo/docs/Net­Logo%20User%20Ma­nual.pdf
  34. NetLogo FAQ:
    http://ccl.nor­thwestern.edu/ne­tlogo/docs/faq­.html
  35. Domácí stránka Daniela Azumy (autora implementace Turtle Tracks):
    http://alumnus­.caltech.edu/~da­zuma/home/
  36. Informace o aUCBLogu:
    http://www.phy­sik.uni-augsburg.de/~miche­ler/
  37. Domácí stránka MSW Loga:
    http://www.sof­tronix.com/lo­go.html
  38. Karel online
    http://karel.ol­dium.net/
  39. EDU-SIG: Python in Education
    http://www.pyt­hon.org/commu­nity/sigs/curren­t/edu-sig/
  40. Guido van Robot
    http://en.wiki­pedia.org/wiki/Gu­ido_van_Robot
  41. The Guido van Robot Programming Language
    http://gvr.sou­rceforge.net/
  42. An Introduction to Programming with Karel J. Robot
    http://blog.thin­goid.com/2003/10­/karel-intro/
  43. Teaching a young robot new tricks
    http://blog.thin­goid.com/2003/11­/karel-new-tricks/
  44. Karel and Company – More Robots
    http://blog.thin­goid.com/2003/12­/karel-and-company/
  45. Karel heads for the stars
    http://blog.thin­goid.com/2004/03­/karel-star/
  46. Karel programming language documentation
    http://mormegil­.wz.cz/prog/ka­rel/prog_doc.htm
  47. Karel J. Robot
    http://www.ma­inlandregional­.net/dklipp/Ho­nors%20Computer%20Sci­ence%20Java.htm
  48. Karel (programming language)
    http://en.wiki­pedia.org/wiki/Ka­rel_(programmin­g_language)
  49. Richard E. Pattis
    http://en.wiki­pedia.org/wiki/Richar­d_E._Pattis
  50. XKarel home page
    http://xkarel­.sourceforge.net/en­g/
  51. XKarel – screenshoty oken
    http://xkarel­.sourceforge.net/en­g/program.php#Ok­na
  52. Greenfoot
    http://www.gre­enfoot.org/abou­t/whatis.html
  53. Computer programming – Educational programming languages
    http://www.kid­slike.info/com­puter_program­ming_educatio­nal_programmin­g_languages
  54. Making Great Programmers: Why BASIC is Still Relevant
    http://kidbasic­.sourceforge.net/en/why­.html
  55. Gambas Wiki
    http://en.wiki­books.org/wiki/Gam­bas
  56. Free tool offers ‚easy‘ coding
    http://news.bbc­.co.uk/2/hi/tec­hnology/6647011­.stm
  57. Scratch Lowers Resistance to Programming
    http://www.wi­red.com/gadge­tlab/2009/03/scrat­ch-lowers/
  58. Základy želví grafiky
    http://www.ro­ot.cz/clanky/za­klady-zelvi-grafiky/
  59. Bill Kendrick's Web Turtle
    http://www.so­nic.net/~nbs/web­turtle/
Našli jste v článku chybu?
Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

Lupa.cz: Jak levné procesory změnily svět?

Jak levné procesory změnily svět?

DigiZone.cz: Světový pohár v přímém přenosu na ČT

Světový pohár v přímém přenosu na ČT

DigiZone.cz: Digi2GO u Alza.cz a s balíčkem Sport zdarma

Digi2GO u Alza.cz a s balíčkem Sport zdarma

Podnikatel.cz: Babišovi se nedá věřit, stěžovali si hospodští

Babišovi se nedá věřit, stěžovali si hospodští

Vitalia.cz: Když všichni seli řepku, on vsadil na dýně

Když všichni seli řepku, on vsadil na dýně

Vitalia.cz: Inspekce našla nelegální sklad v SAPĚ. Zase

Inspekce našla nelegální sklad v SAPĚ. Zase

Vitalia.cz: Voda z Vltavy před a po úpravě na pitnou

Voda z Vltavy před a po úpravě na pitnou

Vitalia.cz: 5 důvodů, proč jet na výlov rybníka

5 důvodů, proč jet na výlov rybníka

Podnikatel.cz: Dva měsíce na EET. Budou stačit?

Dva měsíce na EET. Budou stačit?

Vitalia.cz: Kterou dýni můžete jíst za syrova?

Kterou dýni můžete jíst za syrova?

Vitalia.cz: Jak Ondra o astma přišel

Jak Ondra o astma přišel

DigiZone.cz: Funbox 4K v DVB-T2 má ostrý provoz

Funbox 4K v DVB-T2 má ostrý provoz

DigiZone.cz: Parlamentní listy: kde končí PR...

Parlamentní listy: kde končí PR...

Lupa.cz: Hackeři mají data z půlmiliardy účtů Yahoo

Hackeři mají data z půlmiliardy účtů Yahoo

Podnikatel.cz: Udělali jsme velkou chybu, napsal Čupr

Udělali jsme velkou chybu, napsal Čupr

Lupa.cz: Další Češi si nechali vložit do těla čip

Další Češi si nechali vložit do těla čip

DigiZone.cz: Ginx TV: pořad o počítačových hráčích

Ginx TV: pořad o počítačových hráčích

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

Podnikatel.cz: Kalousek chce odklad EET. Předvolební tah?

Kalousek chce odklad EET. Předvolební tah?