LINUXSOFT.cz Přeskoč levou lištu

ARCHIV



   

> Programujeme chat s dynamickým načítáním

Ve svém prvním článku jsem psal o dynamickém načítání dat na www stránce. V tomto článku bych chtěl ukázat, jak se dá toto načítání použít například u velice zjednodušeného chatu. K tomuto chatu uvedu i popsaný skript na validaci formuláře, která je u tohoto chatu také použita.

14.3.2013 10:00 | Vladimír Macháček | Články autora | přečteno 12621×

Úvodem

Nejdříve bych se rád zmínil o tom, že tento chat, na kterém budu demonstrovat dynamické načítání dat, je jen praktická ukázka a aby jej bylo možné umístit na stránky, muselo by se ještě pořešit zabezpečení a provést pár úprav. Tím ale nechci říci, že chat o kterém budu dále psát je nefunkční.

Co bude chat umět

Chat o kterém píšu bude pracovat pouze s daty z databáze. Uvádím to proto, že data z chatu, jako například zprávy, je možné načítát ze souboru i je do něj ukládat. Tento jednoduchý chat bude umět pravidelně zobrazovat nové zprávy, online uživatele a mazat neaktivní uživatele. Dále bude mít validaci formuláře, kterou si nebudeme stahovat, ale vytvoříme si ji. Validace bude zahrnovat zobrazování zbývajích znaků, které je ještě možno napsat do jména/zprávy a obarvení inputů podle splněné nebo nesplněné podmínky.

Ukázky z chatu

Jak to bude fungovat

Při načtení dokumentu se provede funkce rf();. Nejdříve se u chatu zobrazí vstupní adresář. Ten zahrnuje input pro vložení přezdívky. Jakmile si uživatel zvolí přezdívku a klikne na tlačítko vstoupit, skryje se vstupní formulář, spustí se interval funkce rf(); a zobrazí se mu právě probíhající konverzace na chatu, online uživatelé a formulář pro psaní zpráv. Při každé odeslané zprávě se provede aktualizace času poslední akce tohoto uživatele a kontrola, jestli nebyl uživatel odhlášen kvůli nečinnosti. Pokud byl odhlášen, skript ho vrátí na úvodní stránku.

Začínáme

Na začátek si jako v předchozím článku stáhneme knihovnu jQuery a vytvoříme adresáře se soubory ze kterých se bude náš chat skládat. Budou to tyto soubory:

  • chat.php
    • js
      • chat.js
      • jquery.js
    • css
      • chat.css
    • php
      • config.php
      • send.php
      • messages.php
      • users.php
      • login.php
      • logout.php
      • cldb.php

Tabulky v databázi

Databáze, ve které budou uloženy tyto dvě tabulky se jmenuje test a porovnávánání v této db je nastaveno na UTF_8_czech_ci. K tomuto příkladu bude potřeba vytvořit 2 tabulky. Jedna bude chatusers a druhá chatmsg. V tabulce chatusers budou následující sloupce:

  • id-(INT)
  • name-(VARCHAR) omezení počtu znaků na 20
  • time-(INT)

Tabulka chatmsg bude vypadat takto:

  • id-(INT)
  • name-(VARCHAR) max. počet znaků bude 20
  • text-(VARCHAR) omezení počtu znaků na 500
  • time-(TIME)

Skript pro vytvoření tabulek


<?php
$dblogin='';//Přihlašovací jméno
$dbpassword='';//Heslo
$db = new PDO('mysql:host=localhost;dbname=test;charset=UTF-8', $dblogin, $dbpassword);//Připojení k databázi
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Nastavení řízení chyb
try {
$stmt=$db->query('CREATE TABLE chatusers (id INT NOT NULL AUTO_INCREMENT ,name VARCHAR( 20 ) NOT NULL ,
time INT NOT NULL ,PRIMARY KEY ( id ))');
    echo 'Tabulka chatusers byla úspěšně vytvořena!<br/>';
} catch(PDOException $e) {
    echo 'Nastala chyba:'.$e;
    };
try {
$stmt=$db->query('CREATE TABLE chatmsg (id INT NOT NULL AUTO_INCREMENT ,name VARCHAR( 20 ) NOT NULL ,
text VARCHAR( 500 ) NOT NULL ,time TIME NOT NULL ,PRIMARY KEY ( id ))');
    echo '<br/>Tabulka chatmsg byla úspěšně vytvořena!';
} catch(PDOException $e) {
    echo 'Nastala chyba'.$e;
    }
?>

Chat.php

V tomto souboru bude hlavní struktura chatu. Chat bude obsahovat 2 formuláře. Jeden bude vstupní, ten bude pro přezdívku a druhý bude pro komentář. Formuláře si budou vzájemně prohazovat pozice a to tak, že se jim budou měnit hodnoty z display:none na display:block a opačně. Struktura tohoto souboru je následující:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/chat.js"></script>
<link rel="stylesheet" href="css/chat.css" />
<title>Chat</title>
</head>

<body>
    <div id="chat">
        <div id="chenter">
        <h3>Chat</h3>
            <form method="post" name="cheform" id="cheform">
                <label for="chnick">Nick:</label><input type="text" name="chnick" id="chnick" placeholder="3-20 znaků" />
                <input type="button" id="ech" disabled="disabled" onclick="eCh();" value="Vstoupit" />
                Zbývající znaky:<span id="nlch"></span>
                <span id="errors"></span>
            </form>
        </div>
           <div id="chroom">
            <div id="chmessages">
                <?php 
                    include('php/messages.php');
                ?>
            </div>
            <div id="chusers">
                <?php 
                    include('php/users.php');
                ?>
            </div>
            <div id="chbottom">
                <form method="post" name="chform" id="chform">
                    <label for="chmessage">Zpráva:<br /><span id="mlch"></span></label>
<
textarea placeholder="3-300 znaků." name="chmessage" id="chmessage"></textarea> <input type="button" id="chsm" disabled="disabled" onclick="sChM();" value="Odeslat"/> </form> </div> </div> </div> </body> </html>

Chat.css

V tomto souboru je css stylování chatu. Je na vás, jaký vzhled si vytvoříte. Důležité jsou pouze následující hodnoty:


#chroom {
    display: none;
}
#chenter {
       display:block;
}
#chusers {
    overflow:auto;
}
#chmessages {
    overflow: auto;
}

Chat.js

Na tomto souboru to vše stojí. Jsou zde vytvořeny funkce pro vstup do chatu, odeslání zpráv, refreshování zpráv a uživatelů a validace formuláře. Každý řádek skriptu je pro jednoduchost, přehlednost a lepší pochopení popsán.


// JavaScript Document
$(document).ready(function(){//Načtení dokumentu
    rf();//Provedení refreshe zpráv a uživatelů v chatu
    chControll();//Provedení kontroly formulářů
    $('#chnick').keyup(chControll);//Začátek zaznamenávání akce kláves
    $('#chmessage').keyup(chControll);//Totéž
    });

function eCh() {//Funkce enter chat(eCh)
    var nl=$('#chnick').val().length;
    if(nl>=3) {
    $('#chenter').css('display','none');
    $('#chroom').css('display','block');
    $.post('php/login.php',{nick:cheform.chnick.value},
        function(output) {//Funkce která vypíše vrácená data
                if(output){//Pokud byla nějaká data vrácena
                    $('#chenter').css('display','block');//Změna displeje z none na block
                    $('#chroom').css('display','none');//Změna displeje z block na none
                    $('#errors').html(output);//#chenter tyto data vypíše
                    } else {
                        $('#chform').css('display','block');//Pokud ne, #chform se nastaví na display:block
                        }
            }
        );
    setInterval(rf,2500);//Nastavení intervalu refreshe
    } else {
        $('#errors').html('Váš nick je příliš krátký');//Pokud je Nick příliš krátký, vypiš varovaní
        }
    };

function sChM() {//Funkce send chat message(sChM)
    var ml=$('#chmessage').val().length;
    var nl=$('#chnick').val().length;
    if(ml>=3 && nl>=3) {
        $.post('php/send.php',{nick:cheform.chnick.value, message:chform.chmessage.value});
        $.post('php/logout.php',{nick:cheform.chnick.value},//Zjisti, jestli nebyl uživatel odhlášen z důvodu neaktivity
            function(output){
                if(output) {
                    $('#chenter').css('display','block');//Změna displeje z none na block
                    $('#chroom').css('display','none');//Změna displeje z block na none
                    $('#errors').html(output);//Vypiš output
                    };
                }
        );
        } else {
            $('#chbottom').append('<span class="chlwarning">Vaše zpráva je příliš krátká.</span>');
            }
    };
    
function rf() {//Funkce refreshování zpráv a uživatelů
    $('#chmessages').load('php/messages.php');//Načtení požadovaného souboru
    $('#chusers').load('php/users.php');//Totéž
    };
    
function chControll() {//Funkce pro kontrolu formuláře
    var lname=$('#chnick').val().length;//Počet znaků #chnick
    var lmessage=$('#chmessage').val().length;//Počet znaků v #chmessage
    var name=$('#chnick').val();//Získání hodnoty #chnick
    var message=$('#chmessage').val();//Získání hodnoty #chmessage
    var nsubstr=name.substring(0,20);//Zkrácení počtu znaků name substring(nsubstr) na maximálních 20
    var msubstr=message.substring(0,500);//Zkrácení počtu znaků message substring(msubstr) na maximálních 500
    var nchleft=20-lname;//Zjištění zbývajících počtu  znaků v #chnick
    var mchleft=500-lmessage;//Zjištění zbývajícího počtu znaků v #chmessage
    $('#nlch').html(nchleft);//Vložení zbývajícíh počtu znaků do nick left characters(nlch)
    $('#mlch').html(mchleft);//Vložení zbývajícího počtu znaků do message left characters(mlch)
    $('#chnick').val(nsubstr);//Vložení omezeného počtu znaků do #chnick
    $('#chmessage').val(msubstr);//Vložení omezeného počtu znaků do #chmessage
    if(lname>=3 && lmessage>=3) {//Pokud jsou splněny podmínky lname a lmessage
        $('#chsm').removeAttr('disabled');//Odeber atribut disable u tlačítka chat send message(chsm)
        } else {//Pokud pomínky nejsou splněny
            $('#chsm').attr('disabled','disabled');//Přidej atribut disabled k tlačítku #chsm
            };
    if(lname<3) {//Pokud je splěna podmínka
        $('#chnick').css('border','3px solid #F00');//Vytvoř červený rámeček okolo #chnick
        $('#ech').attr('disabled','disabled');//Přidej atribut disabled ke tlačítku enter chat(ech)
        } else {//Pokud pomínka není splněna
            $('#chnick').css('border','3px solid #00ff00');//Změn barvu rámečku na zelenou
            $('#ech').removeAttr('disabled');//Odeber atribut disabled
            };
    if(lmessage<3) {//Pokud je podmínka splněna
        $('#chmessage').css('border','3px solid #F00');//Vytvoř červený rámeček kolem zprávy
        } else {//Pokud podmínka není splněna
            $('#chmessage').css('border','3px solid #00ff00');//Změn barvu rámečku na zelenou
            };
    };

Validace formuláře:Validaci formuláře má na starost funkce chControll();. Jsou v ní zaznamenávány hodnoty z inputů #chnick a #chmessage. U nich se měří počet znaků a ten je vkládán na určitá místa. Konkrétně u zprávy to je #mlch a u přezdívky (nicku) #nlch. Obarvení rámečku je zelené pokud je v inputech více znaků než 3. Červeně pokud není. Překročení maximálního počtu znaků je chráněno pomocí nchleft a mchleft. Hodnoty těchto dvou proměnných jsou vkládány na místo základního textu.

Config.php

V tomto souboru bude pouze jméno databáze, přistupovací jméno a heslo, připojení k databázi a proměnná $rewrite.


<?php 
$dbname='';//Jméno databáze
$dblogin='';//Přihlašovací jméno
$dbpassword='';//Heslo
$db = new PDO('mysql:host=localhost;dbname=test;charset=UTF-8', $dblogin, $dbpassword);//Připojení k databázi
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Nastavení řízení chyb
$rewrite=array('<'=>'&lt;', '&'=>'&amp;')//Změna prvku v poli
?>

Login.php

Do tohoto souboru se odešle přezdívka, kterou si uživatel zvolil. Zkontroluje se, zdali již přezdívka neexistuje. Pokud ne, žádná data se nevrátí a uživateli se zobrazí formulář pro psaní zpráv a do tabulky se vloží jeho jméno. Pokud se ale jméno již v tabulce nachází, uživatel bude vrácen na vstupní formulář a bude požádán o zvolení jiné přezdívky.


<?php 
include('config.php');//Načti soubor
$nick=substr(strip_tags(StrTr($_POST['nick'],$rewrite)),0,20);
$time=Time();
try {
    $stmt = $db->prepare("SELECT * FROM `$dbname`.`chatusers` WHERE `name`=?");//Připrav dotaz
    $stmt ->bindParam(1, $nick, PDO::PARAM_STR);//Oddělení parametru od hlavního programu
    $stmt->execute();//Provedení dotazu
    if($stmt->rowCount()==NULL) {//Pokud se počet vrácených řádků rovná 0
    $stmt = $db->prepare("INSERT INTO `$dbname`.`chatusers` (`id` ,`name` ,`time`)VALUES (NULL, ?, ?)");//Vlož do tabulky nick
    $stmt ->bindParam(1, $nick, PDO::PARAM_STR);//Oddělení parametru od hlavního programu
    $stmt ->bindParam(2, $time, PDO::PARAM_INT);//Totéž
    $stmt->execute();//Provedení dotazu
                } else {//Pokud se řádek rovná 1
                    echo 'Toto jméno už existuje, musíte zvolit jiné.';//Vypiš varování
                    }
    } catch (PDOException $e){//Pokud nastala chyba
        exit("Nepodařilo se přihlásit.".$e->getMessage());//Vypiš chybu a hlášku
        }
?>

Logout.php

Skript v tomto souboru zajišťuje, aby uživatel, který byl již odhlášen pro neaktivitu, nemohl pokračovat v konverzaci a musel se znovu přihlásit.


<?php 
include('config.php');//Načti soubor config.php
$nick=substr(strip_tags(StrTr($_POST['nick'],$rewrite)),0,20);//Zkrať počet znaků, odstraň tagy a nahraď "<" za &lt;
try {
        $stmt = $db->prepare("SELECT * FROM `$dbname`.`chatusers` WHERE `name`=?");//Připravení dotazu 
        $stmt ->bindParam(1, $nick, PDO::PARAM_STR);//Rozdělení parametru od hl. programu
        $stmt->execute();//Provedení dotazu
        if($stmt->rowCount()==NULL) echo 'Byly jste odhlášeni pro neaktivitu.';//Pokud nebyl nalezen řádek se jménem vypiš zprávu
        } catch (PDOException $e) {//Pokud nastala chyba
            exit("Nepodařilo se vypsat zprávy.".$e->getMessage());//Vypiš chybu a hlášku
            }
?>

Users.php

Zde se získají všechny řádky v tabulce chusers a vypíší se. Jeden řádek = jeden uživatel.


<?php 
include('config.php');//Načti soubor
try {
    $stmt = $db->query("SELECT * FROM `$dbname`.`chatusers` ");//Dotaz do db
    while ($row = $stmt->fetch()) {//Vypsání dat
        echo '<div class="user">'.$row['name'].'</div>';
        }
    } catch (PDOException $e) {//Pokud nastala chyba
        exit("Nepodařilo se vypsat uživatele.".$e->getMessage());//Vypiš chybu a hlášku
        }
?>

Messages.php

Následujících pár řádků skriptu zajišťuje získání všech zpráv z databáze, seřazení a následný výpis.


<?php 
include('config.php');//Načti soubor config.php
try {
        $stmt = $db->query("SELECT * FROM `$dbname`.`chatmsg` ORDER BY `time`");//Dotaz do db
        while ($row = $stmt->fetch()) {//Vypsání dat podle potřeby
            echo '<div class="msg"><div class="msginf"><span class="msgnick">'.$row['name'].'</span>
<span class="msgdate">'
.$row['time'].'</span></div><div class="msgtext">'.$row['text'].'</div></div>';     }         } catch (Exception $e) {//Pokud nastala chyba             exit("Nepodařilo se vypsat zprávy.".$e->getMessage());//Vypiš chybu a hlášku             } ?>

Send.php

V tomto skriptu jsou 2 try-catch bloky. Uvnitř prvního se provádí odesílání dat do databáze a ve druhém updatovaní času poslední akce uživatele. Čas se updatuje proto aby skript, který bude spouštěn CRONem, mohl smazat offline uživatele, kteří byly po určitou dobu neaktivni. Nastavení této hodnoty je na vás. Je dobré to přizpůsobit minimálnímu časovému intervalu spouštění CRONu. Tak zajistíte, že bude seznam online uživatelů pořád a co nejvíce aktuální.


<?php 
include('config.php');//Načti soubor config.php
$time=Time();
$nick=substr(strip_tags(StrTr($_POST['nick'],$rewrite)),0,20);//Odstraň tagy, přepiš "<" na entitu &lt; a zkrať počet znaků
$message=substr(strip_tags(StrTr($_POST['message'],$rewrite)),0,500);//Totéž
$strftime=StrFTime("%H:%M:%S");//Získání času typu 14:22:36
try {
    $stmt = $db->prepare("INSERT INTO `$dbname`.`chatmsg` (`id` ,`name` ,`text` ,`time`)VALUES (NULL, ?, ?, ?)");//Připravení dotazu
    $stmt ->bindParam(1, $nick, PDO::PARAM_STR);//Rozdělení parametru od hlavního programu
    $stmt ->bindParam(2, $message, PDO::PARAM_STR);//Totéž
    $stmt ->bindParam(3, $strftime, PDO::PARAM_STR);//Totéž
    $stmt->execute();//Proveď dotaz
    } catch (PDOException $e){//Pokud se dotaz nezdařil
        exit("Zprávu se nepodařilo odeslat.".$e->getMessage());//Vypiš zprávu a chybovou hlášku
        }
try {//Zde se provede update času poslední akce tohoto uživatele
    $stmt = $db->prepare("UPDATE `$dbname`.`chatusers` SET `time` =? WHERE `chatusers`.`name` ==?");//Připravení dotazu
    $stmt ->bindParam(1, $strftime, PDO::PARAM_INT);//Rozdělení parametru od hlavního programu
    $stmt ->bindParam(2, $nick, PDO::PARAM_STR);//Totéž
    $stmt->execute();//Proveď dotaz
    } catch (PDOException $e){//Pokud se dotaz nezdařil
        exit("Nepodařilo se aktualizovat váš stav.".$e->getMessage());//Vypiš zprávu a chybovou hlášku
        }
?>

Mazání neaktivních uživatelů

Tento skript musí být spouštěn CRONem. Záleží na vás, jaký interval nastavíte. Pokud nastavíte například na 5 minut, tak musíte u $timeout nastavit na místo hodnoty 3600 jen 300.


<?php 
$dbname='test';//Jméno databáze
$dblogin='';//Přihlašovací jméno
$dbpassword='';//Heslo
$db = new PDO('mysql:host=localhost;dbname=test;charset=UTF-8', $dblogin, $dbpassword);//Připojení k databázi
$time=Time();
$timeout=$time-3600;
$stmt = $db->query("DELETE FROM `$dbname`.`chatusers` WHERE `chatusers`.`time <  $timeout;");//Dotaz do db
$stmt = $db->query("SELECT * FROM `$dbname`.`chatmsg`");
$nrows=$stmt->rowCount();
if($nrows>=80) {//Pokud je počet zpráv větší než 80
    $stmt = $db->query("DELETE FROM `$dbname`.`chatmsg` LIMIT 40");//Smaž polovinu zpráv
};
?>

Verze pro tisk

pridej.cz

 

DISKUZE

Děkujeme za další článek 15.3.2013 09:33 Martin Chudoba




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

28.11.2018 23:56 /František Kučera
Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1

12.11.2018 21:28 /Redakce Linuxsoft.cz
22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář

6.11.2018 2:04 /František Kučera
Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

4.10.2018 21:30 /Ondřej Čečák
LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář

18.9.2018 23:30 /František Kučera
Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

31.7.2023 14:13 / Linda Graham
iPhone Services

30.11.2022 9:32 / Kyle McDermott
Hosting download unavailable

13.12.2018 10:57 / Jan Mareš
Re: zavináč

2.12.2018 23:56 / František Kučera
Sraz

5.10.2018 17:12 / Jakub Kuljovsky
Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2024) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze