Základy tvorby souborů typu X3D

Pavel Tišnovský 31. 1. 2008

V dnešní části seriálu o grafických formátech a metaformátech si ukážeme základy tvorby souborů uložených podle syntaxe jazyka X3D. Popíšeme si také profily X3D, pomocí kterých se určují vlastnosti ukládaných souborů a také způsob vytváření plošných objektů spolu s nastavením jejích vlastností.

Obsah

1. Základy tvorby souborů typu X3D
2. Profily X3D
3. Nejčastěji používané datové typy
4. Hierarchie objektových typů
5. Vytváření geometrických objektů – uzel typu Shape
6. Geometrické objekty ležící v rovině
7. Literatura
8. Obsah následující části tohoto seriálu

1. Základy tvorby souborů typu X3D

V předchozí části tohoto seriálu jsme si uvedli základní informace o jazyku X3D, který je určený pro popis plošných výkresů i trojrozměrných scén spolu s definicí dalších vlastností těchto scén, resp. objektů v těchto scénách uložených. Například je možné navázání některých objektů na programové skripty (typicky bývají napsané v JavaScriptu nebo Javě), použití shaderů atd. Kromě toho je možné do scén vkládat i velmi složité objekty, například NURBS či částicové systémy.

Také jsme si řekli, že existují tři navzájem odlišné způsoby zápisu (syntaxe): syntaxe odvozená od jazyka VRML, který je ideovým předchůdcem X3D, syntaxe založená na obecném značkovacím jazyce XML (X3D má svoje vlastní DTD – viz literatura) a konečně binární kódování všech objektů uložených ve scéně. V demonstračních příkladech, které budu v následujících částech tohoto seriálu ukazovat, budu používat především původní "VRML" syntaxi, někdy doplněnou o XML variantu. Rozdíl mezi těmito dvěma způsoby zápisu je víceméně kosmetický, protože obě dvě varianty mají prakticky shodné vyjadřovací schopnosti.

Ve druhé kapitole si popíšeme takzvané profily X3D, pomocí kterých je možné stanovit, jaké vlastnosti vyžaduje daný X3D soubor po prohlížeči. Vzhledem k tomu, že atributy objektů jsou popsány hodnotami různých datových typů, budeme se touto problematikou zabývat v kapitole třetí. Na toto téma navážeme i ve čtvrté kapitole, kde bude vypsána celá hierarchie objektových typů. V následující kapitole si vysvětlíme způsob použití jednoho z nejdůležitějších uzlů – uzlu typu Shape, který slouží pro zápis nových geometrických objektů do souborů typu X3D. V šesté kapitole budou popsány ty geometrické objekty, které leží v rovině a hodí se tedy pro tvorbu 2D (plošných) výkresů. Jedná se například o kružnici, disk (vyplněný kruh), kruhový oblouk, polyčáru nebo množinu trojúhelníků.

2. Profily X3D

Pomocí takzvaných profilů je možné přímo v souborech uložených v některém ze tří možných formátů X3D (VRML, XML či binární syntaxe) předepsat, jaké vlastnosti by měl splňovat prohlížeč, aby bylo možné daný soubor bez problémů zpracovat, tj. zobrazit v požadované kvalitě a umožnit například pohyb uživatele ve virtuálním prostoru. Tvůrci formátu X3D se zavedením profilů snažili (možná trochu paradoxně) dosáhnout co největší kompatibility mezi prohlížeči, protože se předpokládá, že prohlížeč nemusí zvládat všechny možnosti, které formát X3D nabízí (to by byl na některých platformách prakticky neřešitelný problém).

Tvůrce prohlížeče se tedy nemusí snažit implementovat všechny funkce X3D, ale může se soustředit pouze na korektní implementaci určité podmnožiny funkcí. V některých případech nemusí být ani podpora obecnějšího profilu žádoucí, protože X3D není použit pouze pro popis virtuální reality, ale například i pro přenos výkresů mezi různými (mnohdy značně odlišnými) aplikacemi typu CAD a GIS. Specifikace X3D uvádí následující profily:

  1. Core profile: Ve své podstatě se jedná o minimální profil, který by měly podporovat všechny prohlížeče X3D souborů. Mezi omezení daná normou patří například maximálně 500 synovských uzlů ve stromu (redukce objemu paměti), maximálně 8 současně použitých světel (omezení některých grafických karet, tato hodnota se přenáší i do dalších profilů), rozlišení textur maximálně 256×256 pixelů (redukce objemu paměti i omezení velmi starých grafických akcelerátorů) a rozsah typu double alespoň 1e±12 s přesností 1e-7 (průnik množin rozsahu a přesnosti pro nejpoužívanější architektury procesorů).
  2. Interchange profile: Tento profil je určen především pro přenos geometrických dat mezi různými aplikacemi. Z tohoto důvodu se nepředpokládá, že by se v souboru X3D vyskytovaly například odkazy na programové skripty. Minimální podporované rozlišení textur se zvětšilo na 512×512 pixelů a oproti výše uvedenému profilu Code je možné textury ukládat do formátů PNG i JPEG.
  3. CADInterchange profile: Poměrně zajímavý a potenciálně užitečný profil, který je určen pro přenos dat mezi různými systémy typu CAD či CAM. Soubory uložené v tomto profilu mohou plně využívat uzly typu IndexedQuadSet, QuadSet, CADAssembly, CADFace, CADLayer či CADPart.
  4. Interactive profile: Prohlížeče, které tento profil nabízí, by měly zcela dokonale zvládat práci s událostmi, podporovat senzory, všechny vstupní zařízení a navigaci. Užití tohoto profilu je zřejmé – aplikace virtuální reality, systémy pro výuku či simulace, jednoduché hry apod.
  5. MPEG-4 interactive profile: Profil navržený tak, aby umožňoval spolupráci se standardem MPEG-4. V mnoha ohledech se podobá dále zmíněnému profilu Immersive.
  6. Immersive profile: Jedná se o pravděpodobně nejrozšířenější profil, alespoň co se týká počtu souborů. V tomto profilu je možné ukládat prakticky jakoukoli prostorovou scénu, protože sice nějaké limity existují, ale v praxi nejsou příliš omezující. Například plocha určená jednotlivými vrcholy by měla mít méně než 15 000 vrcholů, výškové pole zadané maximálně 16 000 výšek, polyčára by měla být zadaná nejvýše 5000 vrcholy, animovaná textura může být uložena ve formátu MPEG-1, atd. Jak je z tohoto výčtu patrné, jedná se opravdu o teoretické limity, které se v praxi těžko překročí.
  7. Full profile: Podle názvu tohoto profilu by se mohlo zdát, že na soubory v tomto profilu ukládané nejsou kladeny žádné limity. To však není zcela pravda, některá omezení (která pomáhají v implementaci prohlížečů) mohou existovat, například maximální délky vektorů (typicky 15 000 hodnot nebo 20 000 v jednom vektoru v závislosti na datovém typu) či rozměry matic (typicky je maximální počet prvků matice omezen na 256).

Připomeňme si, že profil se zapisuje přímo do hlavičky souboru typu X3D. V případě použití VRML syntaxe může zápis vypadat následovně:

#X3D V3.0 utf8
PROFILE Interchange

Transform {
    children [
        Shape {
            geometry Sphere {
            }
        }
        Transform {
            translation 2.0 0.0 0.0
                children [
                DEF Joe Shape {
                    geometry Sphere { radius 0.2
                    }
                }
            ]
        }
        Transform {
            translation -2.0 0.0 0.0
                children [
                USE Joe
                ]
        }
    ]
}

3. Nejčastěji používané datové typy

Ve formátu X3D je celá scéna zapsána pomocí uzlů hierarchicky umístěných do stromové struktury. Vlastnosti jednotlivých objektů, tj. jejich geometrické informace, barva povrchu, textura, orientace normálových vektorů k povrchu objektů aj. jsou popsány pomocí atributů těchto uzlů, tj. většinou celočíselných hodnot, hodnot uložených ve formátu pohyblivé řádové čárky či znakových řetězců (v tomto případě se jedná o skalární hodnoty). V počítačové grafice se velmi často pracuje s vektory (například i barva je popsána třísložkovým vektorem) a maticemi, jejichž prvky (celočíselné i reálné hodnoty, řetězce) mohou být také zapisovány ve formě atributů. Ve formátu X3D jsou rozeznávány následující systémově definované datové typy (některé méně obvyklé typy jsem vynechal):

Označení Poznámka
SFBool jedna hodnota TRUE nebo FALSE
MFBool vektor více pravdivostních hodnot TRUE nebo FALSE
SFColor zápis barvy ve formátu RGB
MFColor vektor více barev
SFColorRGBAzápis barvy ve formátu RGBA (průhlednost)
MFColorRGBAvektor více barev uložených ve formátu RGBA
SFFloat IEEE float (přesnost alespoň 6 cifer)
MFFloat vektor IEEE float (přesnost alespoň 6 cifer)
SFDouble hodnota v pohyblivé řádové čárce s dvojitou přesností
MFDouble vektor hodnot SFDouble
SFImage pixmapa uložená ve formátu RGB
MFImage vektor pixmap uložených ve formátu RGB
SFInt32 celočíselná hodnota se znaménkem
MFInt32 vektor celočíselných hodnot
SFMatrix3dmatice o rozměrech 3×3 s hodnotami ve formátu double (většinou transformační)
SFMatrix3fmatice o rozměrech 3×3 s hodnotami ve formátu float (většinou transformační)
SFMatrix4dmatice o rozměrech 4×4 s hodnotami ve formátu double (většinou transformační)
SFMatrix4fmatice o rozměrech 4×4 s hodnotami ve formátu float (většinou transformační)
SFRotationrotace zadaná čtyřmi hodnotami (vektorem a úhlem)
SFString řetězec, ve formátu X3D vždy UTF
MFString pole řetězců, ve formátu X3D vždy UTF
SFVec2f 2D vektor s hodnotami uloženými ve formátu float
SFVec3f 3D vektor s hodnotami uloženými ve formátu float
SFVec4f 4D vektor s hodnotami uloženými ve formátu float
SFVec2d 2D vektor s hodnotami uloženými ve formátu double
SFVec3d 3D vektor s hodnotami uloženými ve formátu double
SFVec4d 4D vektor s hodnotami uloženými ve formátu double
MFVec2f vektor 2D vektorů s hodnotami uloženými ve formátu float
MFVec3f vektor 3D vektorů s hodnotami uloženými ve formátu float
MFVec4f vektor 4D vektorů s hodnotami uloženými ve formátu float
MFVec2d vektor 2D vektorů s hodnotami uloženými ve formátu double
MFVec3d vektor 3D vektorů s hodnotami uloženými ve formátu double
MFVec4d vektor 4D vektorů s hodnotami uloženými ve formátu double
SFTime časový údaj (Unixový čas)
MFTime vektor časových údajů (Unixový čas)

4. Hierarchie objektových typů

Od základních datových typů, které byly uvedeny v předchozí kapitole, jsou odvozeny další datové typy, které se většinou nazývají objektové. Většinou platí, že každý objektový typ je zapsán v samostatném uzlu hierarchicky umístěném do stromu, proto můžeme (s určitým zjednodušením) považovat objektové datové typy za samotné uzly, což poněkud zjednodušuje jejich další popis. Vzhledem k tomu, že se v následujících částech tohoto seriálu budu k jednotlivým objektovým typům vracet, bude zde uvedena jejich hierarchie tak, jak ji specifikuje standard X3D. "Objektovost" datových typů se projevuje zejména při skriptování, protože prakticky k jakémukoli uzlu ve scéně (a samozřejmě i k jeho atributům) je možné pomocí programového skriptu přistupovat, typicky pomocí známé tečkové notace. Hierarchie typů je následující:


X3DField -+- SFBool
          +- SFColor
          +- SFColorRGBA
          +- SFDouble
          +- SFFloat
          +- SFImage
          +- SFInt32
          +- SFNode
          +- SFRotation
          +- SFString
          +- SFTime
          +- SFVec2d
          +- SFVec2f
          +- SFVec3d
          +- SFVec3f
          |
          +- X3DArrayField -+- MFBool
                            +- MFColor
                            +- MFColorRGBA
                            +- MFDouble
                            +- MFFloat
                            +- MFImage
                            +- MFInt32
                            +- MFNode
                            +- MFRotation
                            +- MFString
                            +- MFTime
                            +- MFVec2d
                            +- MFVec2f
                            +- MFVec3d
                            +- MFVec3f

X3DBoundedObject

X3DMetadataObject

X3DUrlObject
X3DNode
  | 
  +- X3DProtoInstance
  |
  +- X3DAppearanceNode -+- Appearance
  |
  +- X3DAppearanceChildNode -+- FillProperties
  |                          +- LineProperties
  |                          |
  |                          +- X3DMaterialNode -+- Material
  |                          |
  |                          +- X3DTextureNode -+- X3DTexture2DNode -+- ImageTexture (X3DUrlObject)*
  |                          |                  |                    +- MovieTexture (X3DSoundSourceNode, X3DUrlObject)*
  |                          |                  |                    +- PixelTexture
  |                          |                  +- MultiTexture
  |                          |   
  |                          +- X3DTextureTransformNode -+- X3DTextureTransform2DNode -+- TextureTransform
  |                                                      +- MultiTextureTransform
  |
  +- X3DGeometryNode -+- Arc2D
  |                   +- ArcClose2D
  |                   +- Box
  |                   +- Circle2D
  |                   +- Cone
  |                   +- Cylinder
  |                   +- Disk2D
  |                   +- ElevationGrid
  |                   +- Extrusion
  |                   +- GeoElevationGrid
  |                   +- IndexedLineSet
  |                   +- LineSet
  |                   +- PointSet
  |                   +- Polyline2D
  |                   +- Polypoint2D
  |                   +- Rectangle2D
  |                   +- Sphere
  |                   +- Text
  |                   +- TriangleSet2D 
  |                   |
  |                   +- X3DComposedGeometryNode -+- IndexedFaceSet
  |                   |                           +- IndexedTriangleFanSet
  |                   |                           +- IndexedTriangleSet
  |                   |                           +- IndexedTriangleStripSet
  |                   |                           +- TriangleFanSet
  |                   |                           +- TriangleSet
  |                   |                           +- TriangleStripSet
  |                   |
  |                   +- X3DParametricGeometryNode -+- NurbsCurve
  |                                                 +- NurbsSweptSurface
  |                                                 +- NurbsSwungSurface
  |                                                 +- X3DNurbsSurfaceGeometryNode -+- NurbsPatchSurface
  |                                                                                 +- NurbsTrimmedSurface
  |
  +- GeoOrigin
  |
  +- X3DGeometricPropertyNode -+- X3DColorNode -+- Color
  |                            |                +- ColorRGBA
  |                            |
  |                            +- X3DCoordinateNode -+- Coordinate
  |                            |                     +- CoordinateDouble
  |                            |                     +- GeoCoordinate
  |                            |
  |                            +- HAnimDisplacer
  |                            |
  |                            +- X3DNormalNode -+- Normal
  |                            |
  |                            +- X3DTextureCoordinateNode -+- MultiTextureCoordinate
  |                                                         +- TextureCoordinate
  |                                                         +- TextureCoordinateGenerator
  |
  +- X3DFontStyleNode -+- FontStyle                               
  |
  +- MetadataDouble (X3DMetadataObject)*
  +- MetadataFloat (X3DMetadataObject)*
  +- MetadataInteger (X3DMetadataObject)*
  +- MetadataSet (X3DMetadataObject)*
  +- MetadataString (X3DMetadataObject)*
  |
  +- Contour2D
  +- NurbsTextureCoordinate
  +- X3DNurbsControlCurveNode -+- ContourPolyline2D
  |                            +- NurbsCurve2D
  |
  +- X3DChildNode -+- X3DBindableNode -+- Fog
                   |                   +- GeoViewpoint
                   |                   +- NavigationInfo
                   |                   +- Viewpoint
                   |                   +- X3DBackgroundNode -+- Background 
                   |                                         +- TextureBackground
                   |
                   +- Inline (X3DUrlObject, X3DBoundedObject)*
                   |
                   +- StaticGroup (X3DBoundedObject)*
                   |
                   +- X3DShapeNode -+- Shape (X3DBoundedObject)*
                   |
                   +- X3DGroupingNode (X3DBoundedObject)* -+- Anchor
                   |                                       +- Billboard
                   |                                       +- Collision (X3DSensorNode)*
                   |                                       +- EspduTransform
                   |                                       +- GeoLocation
                   |                                       +- GeoLOD
                   |                                       +- Group
                   |                                       +- HAnimJoint
                   |                                       +- HAnimSegment
                   |                                       +- HAnimSite
                   |                                       +- LOD
                   |                                       +- Switch
                   |                                       +- Transform
                   |      
                   +- NurbsSet (X3DBoundedObject)*
                   +- NurbsOrientationInterpolator
                   +- NurbsPositionInterpolator
                   +- NurbsSurfaceInterpolator
                   |
                   +- HAnimHumanoid (X3DBoundedObject)*
                   |
                   +- ReceiverPdu (X3DBoundedObject)*
                   +- SignalPdu (X3DBoundedObject)*
                   +- TransmitterPdu (X3DBoundedObject)*
                   |
                   +- X3DInterpolatorNode -+- ColorInterpolator
                   |                       +- CoordinateInterpolator
                   |                       +- CoordinateInterpolator2D
                   |                       +- GeoPositionInterpolator
                   |                       +- NormalInterpolator
                   |                       +- OrientationInterpolator
                   |                       +- PositionInterpolator
                   |                       +- PositionInterpolator2D
                   |                       +- ScalarInterpolator
                   |                   
                   +- X3DLightNode -+- DirectionalLight
                   |                +- PointLight
                   |                +- SpotLight 
                   |
                   +- X3DScriptNode (X3DUrlObject)* -+- Script
                   |
                   +- X3DSensorNode -+- TimeSensor (X3DTimeDependentNode)*
                   |                 +- Collision (X3DGroupingNode)*
                   |                 +- X3DEnvironmentalSensorNode -+- ProximitySensor
                   |                 |                              +- VisibilitySensor
                   |                 |
                   |                 +- X3DKeyDeviceSensorNode -+- KeySensor
                   |                 |                          +- StringSensor
                   |                 |
                   |                 +- X3DNetworkSensorNode +- LoadSensor
                   |                 | 
                   |                 +- X3DPointingDeviceSensorNode -+- X3DDragSensorNode -+- CylinderSensor
                   |                                                 |                     +- PlaneSensor
                   |                                                 |                     +- SphereSensor
                   |                                                 |
                   |                                                 +- X3DTouchSensorNode -+- GeoTouchSensor
                   |                                                                        +- TouchSensor
                   |
                   +- X3DSoundNode -+- Sound
                   |
                   +- X3DTimeDependentNode -+- TimeSensor (X3DSensorNode)*
                   |                        |
                   |                        +- X3DSoundSourceNode -+- AudioClip (X3DUrlObject) *
                   |                                               +- MovieTexture (X3DTexture2DNode, X3DUrlObject)*
                   |
                   +- X3DSequencerNode -+- BooleanSequencer
                   |                    +- IntegerSequencer
                   |
                   +- X3DTriggerNode -+- BooleanTrigger
                   |                  +- IntegerTrigger
                   |                  +- TimeTrigger
                   |
                   +- BooleanFilter
                   +- BooleanToggle
                   |
                   +- X3DInfoNode --+- GeoMetadata
                                    +- WorldInfo

5. Vytváření geometrických objektů – uzel typu Shape

Při vytváření geometrických objektů v rovině nebo prostoru se prakticky nevyhneme použití uzlu typu Shape. Tento uzel typicky obsahuje několik poduzlů, zejména poduzel appearance (vzhled objektu, tj. jeho povrchu), geometry (geometrie objektu, tj. jeho rozměry a tvar), bboxCenter (střed obalového kvádru) a bboxSize (velikost obalového kvádru). V případě, že není uvedený poduzel geometry, není objekt vykreslen, protože prohlížeč nemůže vědět, jaký by měl mít tvar.

Střed a velikost obalového kvádru (bounding box) většinou není zapotřebí zadávat; v případě absence těchto poduzlů se za střed dosadí hodnota [0, 0, 0] a velikost je nekonečná ve všech třech rozměrech. Poduzel typu appearance typicky obsahuje další typy uzlů, buď se specifikací materiálu povrchu tělesa, nebo texturou, která má být na povrch tělesa namapována. Kromě toho je možné (navíc oproti VRML) zadat i způsob vyplňování plošek i styl čáry hran – tyto vizuální vlastnosti těles se většinou uplatňují při tvorbě dvojrozměrných výkresů.

6. Geometrické objekty ležící v rovině

Do uzlu typu Shape je vložen, jak jsme si ostatně řekli už v předchozí kapitole, i poduzel se specifikací geometrie (rozměrů a velikosti) daného objektu. Může se jednat buď o plošný objekt nebo objekt trojrozměrný. Předchůdce formátu X3D, tj. jazyk VRML, v podstatě kromě bodů a úseček žádné skutečné 2D objekty neobsahoval, ovšem X3D ve své snaze o prosazení na poli CAD/CAM některé nejpoužívanější 2D objekty do svého repertoáru zahrnul. Jedná se především o následující typy objektů:

Jméno uzluPopis
Arc2Dkruhový oblouk
ArcClose2Dkruhová výseč nebo úseč
Circle2Dkružnice (nevyplněná)
Disk2Dkruh (vyplněný) nebo vyplněné mezikruží
Polyline2Dlomená čára (polyčára)
Polypoint2Dseznam bodů
Rectangle2Dobdélník s hranami rovnoběžnými s lokálním souřadným systémem
TriangleSet2Dmnožina plošných trojúhelníků

Bližší popis těchto uzlů i způsob jejich použití bude uveden příště.

widgety

7. Literatura

  1. Foley, van Dam, Feiner and Hughes:
    Computer Graphics Principles and Practice,
    2nd Edition, Addison Wesley, Reading, MA, 1990.
  2. Piegl, Les and Tiller, Wayne:
    The NURBS Book, 2nd Edition,
    Springer-Verlag (Berlin), 1997, ISBN: 3-540-61545-8.
  3. ISO/IEC 14772-1:1997,
    Information technology - Computer graphics and image processing - The Virtual reality modeling language (VRML) - Part 1: Functional specification and UTF-8 encoding.
  4. ISO/IEC 19776,
    Information technology - Computer graphics and image processing - Extensible 3D (X3D) encodings.
  5. ISO/IEC 19776-1,
    Part 1: Extensible Markup Language (XML) encoding
  6. ISO/IEC 19776-2,
    Part 2: Classic VRML encoding
  7. ISO/IEC 19776-3, Part 3: Compressed binary encoding

8. Obsah následující části tohoto seriálu

V následující části seriálu o grafických formátech a metaformátech si řekneme, jakým způsobem se do souborů typu X3D dají ukládat trojrozměrné scény složené jak z "plných" trojrozměrných těles, tj. koule, válce, kužele atd., tak i z ploch. Uvidíme, že již při samotném zápisu geometrie objektů i jejich vzhledu toho formát X3D svým uživatelům nabízí mnohem více než jeho ideový předchůdce jazyk VRML.

Našli jste v článku chybu?
120na80.cz: Co je padesátkrát sladší než cukr?

Co je padesátkrát sladší než cukr?

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

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

Podnikatel.cz: Zorientujte se. Odkdy se vás týká EET?

Zorientujte se. Odkdy se vás týká EET?

Vitalia.cz: Jaký je rozdíl mezi brambůrky a chipsy?

Jaký je rozdíl mezi brambůrky a chipsy?

DigiZone.cz: Test: brýle pro virtuální realitu Exos Urban

Test: brýle pro virtuální realitu Exos Urban

Podnikatel.cz: Takhle se prodávají mražené potraviny

Takhle se prodávají mražené potraviny

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

Podnikatel.cz: Byla finanční manažerka, teď cvičí jógu

Byla finanční manažerka, teď cvičí jógu

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

Nova opět stahuje „milionáře“

Lupa.cz: Aukro.cz mění majitele. Vrací se do českých rukou

Aukro.cz mění majitele. Vrací se do českých rukou

Vitalia.cz: Tohle jsou nejlepší česká piva podle odborníků

Tohle jsou nejlepší česká piva podle odborníků

DigiZone.cz: Rapl: seriál, který vás smíří s ČT

Rapl: seriál, který vás smíří s ČT

Vitalia.cz: Jsou vegani a vyrábějí nemléko

Jsou vegani a vyrábějí nemléko

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

Vitalia.cz: Test dětských svačinek: Tyhle ne!

Test dětských svačinek: Tyhle ne!

Podnikatel.cz: EET pro e-shopy? Postavené na hlavu

EET pro e-shopy? Postavené na hlavu

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: Mordparta: trochu podchlazený 87. revír

Mordparta: trochu podchlazený 87. revír

Vitalia.cz: Tahák, jak vyzrát nad zápachem z úst

Tahák, jak vyzrát nad zápachem z úst