Knihovna (výpočetní technika) - Library (computing)

Ilustrace aplikace, která využívá libvorbisfile přehrát Ogg Vorbis soubor

V informatice je knihovna soubor energeticky nezávislých zdrojů používaných počítačovými programy , často k vývoji softwaru . Ty mohou zahrnovat konfigurační data, dokumentaci, data nápovědy, šablony zpráv, předem napsaný kód a podprogramy , třídy , hodnoty nebo specifikace typu . V operačním systému IBM OS/360 a jeho následnících se označují jako dělené datové sady .

Knihovna je také sbírka implementací chování, psané z hlediska jazyka, který má dobře definované rozhraní , kterým je chování vyvolán. Například lidé, kteří chtějí psát program na vyšší úrovni lze použít knihovnu, aby se systémová volání namísto provádění těchto systémových volání a znova a znova. Chování navíc zajišťuje opětovné použití více nezávislými programy. Program vyvolá chování poskytované knihovnou prostřednictvím mechanismu jazyka. Například v jednoduchém imperativním jazyce, jako je C, je chování v knihovně vyvoláno pomocí normálního volání funkce C. To, co odlišuje volání od funkce knihovny, od bytí k jiné funkci ve stejném programu, je způsob, jakým je kód organizován v systému.

Kód knihovny je organizován tak, že jej může používat více programů, které k sobě nemají žádné spojení, zatímco kód, který je součástí programu, je organizován tak, aby jej bylo možné použít pouze v rámci jednoho programu. Toto rozlišení může získat hierarchickou představu, když se program rozroste, například program s více miliony řádků. V takovém případě mohou existovat interní knihovny, které jsou znovu použity nezávislými dílčími částmi velkého programu. Charakteristickým rysem je, že knihovna je organizována za účelem opětovného použití nezávislými programy nebo podprogramy a uživatel potřebuje znát pouze rozhraní, nikoli vnitřní podrobnosti knihovny.

Hodnota knihovny spočívá v opětovném použití standardizovaných programových prvků. Když program vyvolá knihovnu, získá chování implementované uvnitř této knihovny, aniž by musel toto chování implementovat sám. Knihovny podporují modulární sdílení kódu a usnadňují distribuci kódu.

Chování implementované knihovnou lze připojit k vyvolávajícímu programu v různých fázích životního cyklu programu . Pokud je kód knihovny přístupný během sestavení vyvolávajícího programu, pak se knihovně říká statická knihovna . Alternativou je vytvořit spustitelný soubor vyvolávajícího programu a distribuovat jej nezávisle na implementaci knihovny. Chování knihovny je propojeno poté, co byl spustitelný soubor vyvolán k provedení, buď jako součást procesu spuštění provádění, nebo uprostřed provádění. V tomto případě se knihovně říká dynamická knihovna (načtená za běhu ). Dynamickou knihovnu lze načíst a propojit při přípravě programu k provedení pomocí linkeru . Alternativně může uprostřed provádění aplikace aplikace výslovně požadovat načtení modulu .

Většina kompilovaných jazykůstandardní knihovnu , i když programátoři mohou také vytvářet vlastní knihovny. Většina moderních softwarových systémů poskytuje knihovny, které implementují většinu systémových služeb. Takové knihovny uspořádaly služby, které moderní aplikace vyžadují. Většina kódů používaných moderními aplikacemi je poskytována v těchto systémových knihovnách.

Dějiny

Žena pracující vedle kartotéky obsahující podprogramovou knihovnu na kotoučích děrné pásky pro počítač EDSAC.

V roce 1947 Goldstine a von Neumann spekulovali, že by bylo užitečné vytvořit „knihovnu“ podprogramů pro jejich práci na stroji IAS , časném počítači, který v té době ještě nebyl funkční. Představili si fyzickou knihovnu magnetických drátových záznamů , přičemž každý vodič ukládal opakovaně použitelný počítačový kód.

Inspirován von Neumannem, Wilkes a jeho tým zkonstruovali EDSAC . Kartotéka na děrné pásce měl knihovnu podprogram pro tento počítač. Programy pro EDSAC se skládaly z hlavního programu a sekvence podprogramů zkopírovaných z knihovny podprogramů. V roce 1951 tým vydal první učebnici programování, The Preparation of Programs for an Electronic Digital Computer , která podrobně popisuje vznik a účel knihovny.

COBOL zahrnoval „primitivní schopnosti pro knihovní systém“ v roce 1959, ale Jean Sammet je zpětně popsal jako „nedostatečné vybavení knihovny“.

JOVIAL měl komunikační fond (COMPOOL), zhruba knihovnu hlavičkových souborů.

Dalším významným přispěvatelem k modernímu konceptu knihovny je inovace podprogramu FORTRAN . Podprogramy FORTRAN lze kompilovat nezávisle na sobě, ale kompilátoru chyběl linker . Takže před zavedením modulů do Fortran-90 nebyla kontrola typu mezi podprogramy FORTRAN možná.

V polovině šedesátých let byly běžné kopírovací a makro knihovny pro assemblery. Počínaje popularitou systému IBM System/360 se staly běžnými také knihovny obsahující jiné typy textových prvků, např. Systémové parametry.

Simula byl první objektově orientovaný programovací jazyk a jeho třídy byly téměř totožné s moderním konceptem používaným v jazycích Java , C ++ a C# . Třída Pojem Simula byl také předek obalu v Ada a modulu z Modula-2 . I když byly původně vytvořeny v roce 1965, třídy Simula mohly být zahrnuty do souborů knihovny a přidány v době kompilace.

Propojení

Knihovny jsou důležité v procesu propojení nebo vazby programu , který řeší odkazy známé jako odkazy nebo symboly na moduly knihovny. Propojovací proces obvykle automaticky provádí program linker nebo pořadač, který prohledává sadu knihoven a dalších modulů v daném pořadí. Obvykle není považováno za chybu, pokud lze cíl odkazu v dané sadě knihoven najít vícekrát. Propojení lze provést při vytvoření spustitelného souboru nebo při každém použití programu za běhu .

Řešenými odkazy mohou být adresy pro skoky a další rutinní volání. Mohou být v hlavním programu nebo v jednom modulu v závislosti na jiném. Jsou vyřešeny na pevné nebo přemístitelné adresy (ze společné základny) přidělením runtime paměti pro paměťové segmenty každého odkazovaného modulu.

Některé programovací jazyky používají funkci zvanou chytré propojení, kdy si linker uvědomuje nebo je integrován s kompilátorem, takže linker ví, jak se používají externí odkazy, a kód v knihovně, která se ve skutečnosti nikdy nepoužívá , i když je na ni interně odkazováno, lze vyřazeno z kompilované aplikace. Například program, který používá pouze celá čísla pro aritmetiku nebo neprovádí vůbec žádné aritmetické operace, může vyloučit rutiny knihovny s pohyblivou řádovou čárkou. Tato funkce inteligentního propojení může vést k menším velikostem souborů aplikace a menšímu využití paměti.

Přemístění

Některé odkazy v programu nebo modulu knihovny jsou uloženy v relativní nebo symbolické podobě, kterou nelze vyřešit, dokud nebudou všem kódům a knihovnám přiřazeny konečné statické adresy. Přemístění je proces úpravy těchto referencí a provádí ho buď linker, nebo zavaděč . Přemístění obecně nelze provést pro jednotlivé knihovny samotné, protože adresy v paměti se mohou lišit v závislosti na programu, který je používá, a dalších knihovnách, se kterými jsou kombinovány. Kód nezávislý na poloze se vyhýbá odkazům na absolutní adresy, a proto nevyžaduje přemístění.

Statické knihovny

Když je propojení prováděno během vytváření spustitelného souboru nebo jiného souboru objektu, je známé jako statické propojení nebo časná vazba . V tomto případě propojení obvykle provádí linker , ale může jej provést také překladač . Statické knihovny , také známý jako archiv , je určen k staticky propojeny. Původně existovaly pouze statické knihovny. Při překompilování jakýchkoli modulů je nutné provést statické propojení.

Všechny moduly požadované programem jsou někdy staticky propojeny a zkopírovány do spustitelného souboru. Tento proces a výsledný samostatný soubor je znám jako statické sestavení programu. Statická sestava nemusí vyžadovat žádné další přemisťování, pokud je použita virtuální paměť a není požadována randomizace rozložení adresního prostoru .

Sdílené knihovny

Sdílená knihovna nebo sdílený objekt je soubor, který má být sdílena spustitelné soubory a další sdílených objektových souborů. Moduly používané programem se načítají z jednotlivých sdílených objektů do paměti v době načítání nebo za běhu , než aby byly kopírovány linkerem, když pro program vytvoří jeden monolitický spustitelný soubor.

Sdílené knihovny lze během kompilace staticky propojovat, což znamená, že odkazy na moduly knihovny jsou vyřešeny a modulům je přidělena paměť při vytvoření spustitelného souboru. Propojení sdílených knihoven se však často odkládá, dokud nejsou načteny.

Většina moderních operačních systémů může mít soubory sdílené knihovny stejného formátu jako spustitelné soubory. To nabízí dvě hlavní výhody: zaprvé vyžaduje, aby byl pro oba vyroben pouze jeden zavaděč, nikoli dva (mít jeden zavaděč je považováno za hodnotu, která stojí za přidanou složitost). Za druhé, umožňuje použít spustitelné soubory také jako sdílené knihovny, pokud mají tabulku symbolů . Typickými kombinovanými formáty spustitelných a sdílených knihoven jsou ELF a Mach-O (oba v Unixu) a PE (Windows).

V některých starších prostředích, jako je 16bitový Windows nebo MPE pro HP 3000 , byla v kódu sdílené knihovny povolena pouze data založená na zásobníku (lokální) nebo byla na kód sdílené knihovny kladena jiná významná omezení.

Sdílení paměti

Kód knihovny může být sdílen v paměti více procesy , stejně jako na disku. Pokud je použita virtuální paměť, procesy by spustily stejnou fyzickou stránku RAM, která je mapována do různých adresních prostorů procesů. To má výhody. Například v systému OpenStep měly aplikace často velikost jen několik set kilobajtů a rychle se načítaly; většina jejich kódu byla umístěna v knihovnách, které již byly načteny pro jiné účely operačním systémem.

Programy mohou dosáhnout sdílení RAM pomocí kódu nezávislého na poloze , jako v Unixu , což vede ke složité, ale flexibilní architektuře, nebo pomocí běžných virtuálních adres, jako ve Windows a OS/2 . Tyto systémy zajišťují pomocí různých triků, jako je předmapování adresního prostoru a rezervace slotů pro každou sdílenou knihovnu, velkou pravděpodobnost, že budou sdíleny. Třetí alternativou je jednoúrovňový obchod , jak jej používá IBM System/38 a jeho nástupci. To umožňuje kód závislý na poloze, ale nijak výrazně neomezuje, kam lze kód umístit nebo jak jej lze sdílet.

V některých případech mohou různé verze sdílených knihoven způsobovat problémy, zvláště když knihovny různých verzí mají stejný název souboru a různé aplikace nainstalované v systému vyžadují konkrétní verzi. Takový scénář je znám jako DLL Hell , pojmenovaný podle souboru DLL systému Windows a OS/2 . Většina moderních operačních systémů po roce 2001 má metody čištění, které takové situace eliminují, nebo používají „soukromé“ knihovny specifické pro aplikaci.

Dynamické propojení

Dynamické propojení nebo pozdní vazba se provádí při načítání programu ( doba načítání ) nebo při běhu (při běhu ), nikoli při vytváření spustitelného souboru. Dynamicky propojená knihovna ( dynamicky propojená knihovna nebo DLL pod Windows a OS/2 ; obraz s možností sdílení pod OpenVMS ; dynamický sdílený objekt nebo DSO v systémech podobných Unixu ) je knihovna určená pro dynamické propojení. Při vytváření spustitelného souboru provede linker pouze minimální množství práce ; pouze zaznamenává, jaké knihovní rutiny program potřebuje, a názvy indexů nebo čísla rutin v knihovně. Většina práce na propojení se provádí v okamžiku načtení aplikace (doba načítání) nebo během provádění (běh). Potřebný propojovací program, nazývaný „dynamický linker“ nebo „propojovací zavaděč“, je obvykle součástí základního operačního systému . (Je však možné, a ne mimořádně obtížné, napsat program, který používá dynamické propojení a obsahuje vlastní dynamický linker, a to i pro operační systém, který sám neposkytuje žádnou podporu pro dynamické propojení.)

Programátoři původně vyvinuli dynamické propojení v operačním systému Multics , počínaje rokem 1964, a MTS ( Michigan Terminal System ), postaveném na konci šedesátých let minulého století.

Optimalizace

Vzhledem k tomu, že se sdílené knihovny na většině systémů nemění často, mohou systémy vypočítat pravděpodobnou adresu načtení pro každou sdílenou knihovnu v systému dříve, než je potřeba, a uložit tyto informace do knihoven a spustitelných souborů. Pokud každá načtená sdílená knihovna prošla tímto procesem, pak se každá načte na její předem určenou adresu, což urychluje proces dynamického propojení. Tato optimalizace je známá jako předběžná vazba v systému macOS a předběžná vazba v systému Linux. Nevýhody této techniky zahrnují čas potřebný k předběžnému výpočtu těchto adres pokaždé, když se změní sdílené knihovny, nemožnost použít randomizaci rozložení adresního prostoru a požadavek na dostatečný virtuální adresní prostor pro použití (problém, který bude zmírněn přijetím 64 -bitové architektury, alespoň prozatím ).

Umístění knihoven za běhu

Funkce zavaděčů pro sdílené knihovny se velmi liší. Některé závisí na spustitelném souboru, který ukládá explicitní cesty ke knihovnám. Jakákoli změna názvu knihovny nebo rozložení systému souborů způsobí selhání těchto systémů. Běžněji je v spustitelném souboru uložen pouze název knihovny (a nikoli cesta), přičemž operační systém poskytuje metodu pro nalezení knihovny na disku na základě nějakého algoritmu.

Pokud je odstraněna, přesunuta nebo přejmenována sdílená knihovna, na které závisí spustitelný soubor, nebo pokud je nekompatibilní verze knihovny zkopírována na místo, které je ve vyhledávání dříve, spustitelný soubor se nepodaří načíst. Tomu se říká peklo závislosti , které existuje na mnoha platformách. (Neslavná) varianta Windows je běžně známá jako DLL peklo . K tomuto problému nemůže dojít, pokud je každá verze každé knihovny jednoznačně identifikována a každý program odkazuje na knihovny pouze pomocí jejich úplných jedinečných identifikátorů. Problémy „DLL pekla“ u dřívějších verzí systému Windows vznikaly z toho, že se k řešení dynamických odkazů v programech používaly pouze názvy knihoven, u nichž nebylo zaručeno, že budou jedinečné. (Aby se předešlo „peklu DLL“, novější verze systému Windows do značné míry spoléhají na možnosti programů instalovat soukromé knihovny DLL - v podstatě částečné ústup od používání sdílených knihoven - spolu s mechanismy, které zabraňují nahrazení sdílených systémových knihoven DLL jejich dřívějšími verzemi. )

Microsoft Windows

Microsoft Windows zkontroluje registr, aby určil správné místo pro načtení knihoven DLL, které implementují objekty COM , ale u ostatních knihoven DLL zkontroluje adresáře v definovaném pořadí. Nejprve systém Windows zkontroluje adresář, do kterého program načetl ( soukromá knihovna DLL ); všechny adresáře nastavené voláním SetDllDirectory()funkce; adresáře System32, System a Windows; poté aktuální pracovní adresář; a nakonec adresáře určené proměnnou prostředí PATH . Aplikace napsané pro .NET Framework (od roku 2002), také zkontrolujte Global Assembly Cache jako primární úložiště sdílených souborů dll, abyste odstranili problém s DLL peklem .

OpenStep

OpenStep použil flexibilnější systém a při prvním spuštění systému shromažďoval seznam knihoven z řady známých míst (podobně jako koncept PATH). Přesouvání knihoven nepůsobí vůbec žádné problémy, přestože uživatelům při prvním spuštění systému vznikají časové náklady.

Unixové systémy

Většina unixových systémů má „vyhledávací cestu“ určující adresáře systému souborů, ve kterých lze hledat dynamické knihovny. Některé systémy určují výchozí cestu v konfiguračním souboru , jiné ji napevno zakódují do dynamického zavaděče. Některé formáty spustitelných souborů mohou určit další adresáře, ve kterých se budou hledat knihovny pro konkrétní program. To lze obvykle přepsat proměnnou prostředí , i když je to zakázáno pro programy setuid a setgid, takže uživatel nemůže vynutit, aby takový program spustil libovolný kód s oprávněním root. Vývojářům knihoven doporučujeme umístit své dynamické knihovny na místa ve výchozí vyhledávací cestě. Na druhou stranu to může způsobit, že instalace nových knihoven bude problematická a tato „známá“ umístění se rychle stanou domovem stále většího počtu knihovních souborů, což zkomplikuje správu.

Dynamické načítání

Dynamické načítání, podmnožina dynamického propojení, zahrnuje načítání a vykládání dynamicky propojené knihovny za běhu na vyžádání. Taková žádost může být podána implicitně nebo explicitně. Implicitní požadavky se dělají, když kompilátor nebo statický linker přidá odkazy na knihovny, které obsahují cesty k souborům nebo jednoduše názvy souborů. Explicitní požadavky se dělají, když aplikace provádějí přímé volání API operačního systému.

Většina operačních systémů, které podporují dynamicky propojené knihovny, také podporuje dynamické načítání takových knihoven prostřednictvím API linkeru za běhu . Například Microsoft Windows používá funkce API , , a s Microsoft Dynamic Link knihovny ; POSIX -založené systémy, včetně nejvíce Unix a Unix-like systémech, použití , a . Některé vývojové systémy tento proces automatizují. LoadLibraryLoadLibraryExFreeLibraryGetProcAddressdlopendlclosedlsym

Objektové knihovny

Ačkoli byl průkopníkem původně v 60. letech, dynamické propojení se k operačním systémům používaným spotřebiteli dostalo až koncem 80. let. To bylo obecně k dispozici v nějaké formě ve většině operačních systémů na počátku 1990. Ve stejném období se objektově orientované programování (OOP) stává významnou součástí programovacího prostředí. OOP s runtime vazbou vyžaduje další informace, které tradiční knihovny nedodávají. Kromě názvů a vstupních bodů kódu umístěného uvnitř vyžadují také seznam objektů, na kterých závisí. Toto je vedlejší účinek jedné z hlavních výhod OOP, dědičnosti, což znamená, že části úplné definice jakékoli metody mohou být na různých místech. Nejde jen o pouhý výčet, že jedna knihovna vyžaduje služby jiné: ve skutečném systému OOP nemusí být samotné knihovny v době kompilace známy a mohou se lišit systém od systému.

Současně mnoho vývojářů pracovalo na myšlence víceúrovňových programů, ve kterých by „displej“ běžící na stolním počítači využíval pro ukládání nebo zpracování dat služby sálového počítače nebo minipočítače . Například program na počítači s grafickým uživatelským rozhraním by odesílal zprávy do minipočítače, aby vrátil malé vzorky obrovské sady dat k zobrazení. Vzdálené volání procedur (RPC) již tyto úkoly zvládlo, ale neexistoval žádný standardní systém RPC.

Většina dodavatelů minipočítačů a sálových počítačů brzy podnítila projekty ke spojení těchto dvou a vytvořila formát knihovny OOP, který lze použít kdekoli. Takové systémy byly známé jako objektové knihovny nebo distribuované objekty , pokud podporovaly vzdálený přístup (ne všechny). Microsoft COM je příkladem takového systému pro místní použití. DCOM, upravená verze modelu COM, podporuje vzdálený přístup.

Nějakou dobu si objektové knihovny udržovaly status „další velké věci“ ve světě programování. Bylo vyvinuto mnoho úsilí o vytvoření systémů, které by běžely napříč platformami, a společnosti soutěžily ve snaze dostat vývojáře do svého vlastního systému. Jako příklady lze uvést IBM 's System Object Model (SOM / DSOM), Sun Microsystems ' distribuovaných objektů Everywhere (DOE), Next 's Přenosné distribuovaných objektů (PDO), Digital je ObjectBroker , Microsoft Component Object Model (COM / DCOM) a libovolný počet systémů založených na CORBA .

Knihovny tříd

Knihovny tříd jsou hrubým ekvivalentem OOP starších typů knihoven kódů. Obsahují třídy , které popisují charakteristiky a definují akce ( metody ), které zahrnují objekty. Knihovny tříd se používají k vytváření instancí nebo objektů s jejich charakteristikami nastavenými na konkrétní hodnoty. V některých jazycích OOP, jako je Java , je rozdíl jasný, protože třídy jsou často obsaženy v souborech knihoven (jako je formát JAR souboru Java ) a objekty s instancí se nacházejí pouze v paměti (i když potenciálně je možné je v samostatných souborech nastavit jako trvalé ). V jiných, jako Smalltalk , jsou knihovny tříd pouze výchozím bodem pro obraz systému, který zahrnuje celý stav prostředí, třídy a všechny instance objektů.

Dnes je většina třídních knihoven uložena v úložišti balíků (například Maven Central pro Javu). Kód klienta explicitně deklaruje závislosti na externích knihovnách v konfiguračních souborech sestavení (například Maven Pom v Javě).

Vzdálené knihovny

Další řešení problému knihovny spočívá v použití zcela samostatných spustitelných souborů (často v nějaké odlehčené formě) a jejich volání pomocí vzdáleného volání procedur (RPC) přes síť do jiného počítače. Tento přístup maximalizuje opětovné použití operačního systému: kód potřebný k podpoře knihovny je stejný kód, který se používá k zajištění podpory aplikací a zabezpečení pro každý jiný program. Navíc takové systémy nevyžadují, aby knihovna existovala na stejném počítači, ale mohou předávat požadavky přes síť.

Takový přístup však znamená, že každé volání knihovny vyžaduje značné množství režie. Volání RPC je mnohem dražší než volání sdílené knihovny, která již byla načtena na stejném počítači. Tento přístup se běžně používá v distribuované architektuře, která hojně využívá taková vzdálená volání, zejména systémy klient-server a aplikační servery, jako je Enterprise JavaBeans .

Knihovny pro generování kódu

Knihovny generování kódu jsou API na vysoké úrovni, které mohou generovat nebo transformovat bajtový kód pro Javu . Používá je programování orientované na aspekty , některé rámce pro přístup k datům a pro testování ke generování dynamických objektů proxy. Používají se také k zachycení přístupu do pole.

Pojmenování souborů

Většina moderních unixových systémů

Systém ukládá libfoo.aa libfoo.sosoubory ukládá do adresářů jako /lib, /usr/libnebo /usr/local/lib. Názvy souborů vždy začínají liba končí příponou .a( archiv , statická knihovna) nebo .so(sdílený objekt, dynamicky propojená knihovna). Některé systémy mohou mít více názvů pro dynamicky propojenou knihovnu. Tyto názvy obvykle sdílejí stejnou předponu a mají různé přípony označující číslo verze. Většina jmen jsou názvy pro symbolické odkazy na nejnovější verzi. Například na některých systémech libfoo.so.2bude název souboru pro druhou hlavní revizi rozhraní dynamicky propojené knihovny libfoo. Tyto .lasoubory někdy v knihovně adresářích jsou Libtool archivy, které nejsou použitelné v systému jako takového.

Operační Systém Mac

Systém dědí konvence statické knihovny z BSD , přičemž knihovna je uložena v .asouboru, a může používat .sodynamicky propojené knihovny ve stylu ( .dylibmísto toho s příponou). Většina knihoven v systému macOS se však skládá z „rámců“ umístěných ve speciálních adresářích nazývaných „ svazky “, které obalují požadované soubory a metadata knihovny. Například volaný framework MyFrameworkby byl implementován do volaného balíčku MyFramework.framework, MyFramework.framework/MyFrameworkpřičemž buď je to soubor dynamicky propojené knihovny, nebo je to symbolický odkaz na soubor dynamicky propojené knihovny v MyFramework.framework/Versions/Current/MyFramework.

Microsoft Windows

Knihovny dynamických odkazů mají obvykle příponu *.DLL, ačkoli jiné přípony názvů souborů mohou identifikovat dynamicky propojené knihovny specifického účelu, např. *.OCXPro knihovny OLE . Revize rozhraní jsou buď zakódovány v názvech souborů, nebo jsou odebrány pomocí rozhraní objektů COM . V závislosti na tom, jak jsou kompilovány, *.LIBmohou být soubory buď statickými knihovnami, nebo reprezentacemi dynamicky propojitelných knihoven potřebných pouze během kompilace, známých jako „ importované knihovny “. Na rozdíl od světa UNIX , který používá různé přípony souborů, při propojování se .LIBsouborem v systému Windows musíte nejprve vědět, zda se jedná o běžnou statickou knihovnu nebo knihovnu importu. V druhém případě .DLLmusí být soubor přítomen za běhu.

Viz také

Poznámky

Reference

Další čtení