LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> 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 8105×

Ú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ů

15.5.2017 23:50 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 18. května od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.5.2017 16:42 /Honza Javorek
PyCon CZ, česká konference o programovacím jazyce Python, se po dvou úspěšných ročnících v Brně bude letos konat v Praze, a to 8. až 10. června. Na konferenci letos zavítá např. i Armin Ronacher, známý především jako autor frameworku Flask, šablon Jinja2/Twig, a dalších projektů. Těšit se můžete na přednášky o datové analytice, tvorbě webu, testování, tvorbě API, učení a mentorování programování, přednášky o rozvoji komunity, o použití Pythonu ve vědě nebo k ovládání nejrůznějších zařízení (MicroPython). Na vlastní prsty si můžete na workshopech vyzkoušet postavit Pythonem ovládaného robota, naučit se učit šestileté děti programovat, efektivně testovat nebo si v Pythonu pohrát s kartografickým materiálem. Kupujte lístky, dokud jsou.
Přidat komentář

2.5.2017 9:20 /Eva Rázgová
Putovní konference československé Drupal komunity "DrupalCamp Československo" se tentokrát koná 27. 5.2017 na VUT FIT v Brně. Můžete načerpat a vyměnit si zkušenosti z oblasti Drupalu 7 a 8, UX, SEO, managementu týmového vývoje, využití Dockeru pro Drupal a dalších. Vítáni jsou nováčci i experti. Akci pořádají Slovenská Drupal Asociácia a česká Asociace pro Drupal. Registrace na webu .
Přidat komentář

1.5.2017 20:31 /Pavel `Goldenfish' Kysilka
PR: 25.5.2017 proběhne v Praze konference na téma Firemní informační systémy. Hlavními tématy jsou: Informační systémy s vlastní inteligencí, efektivní práce s dokumenty, mobilní přístup k datům nebo využívání cloudu.
Přidat komentář

15.4.2017 15:20 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě IoT a radiokomunikace? Přijď na sraz spolku OpenAlt, který se bude konat ve středu 19. dubna od 18:30 v Šenkovně (Sokolská 60, Praha 2).
Přidat komentář

5.3.2017 19:12 /Redakce Linuxsoft.cz
PR: 23. března proběhne v Praze konferenci na téma Cloud computing v praxi. Hlavními tématy jsou: Nejžhavější trendy v oblasti cloudu a cloudových řešení, Moderní cloudové služby, Infrastruktura současných cloudů, Efektivní využití cloudu, Nástrahy cloudových řešení a jak se jim vyhnout.
Přidat komentář

27.2.2017 22:12 /František Kučera
Pozvánka na 137. sraz OpenAlt – Praha: Tentokrát jsme si pro vás připravili neobvyklou akci. Ve středu 1.3. v 17:30 nás přivítá sdružení CZ.NIC ve svých prostorách v Milešovské ulici číslo 5 na Praze 3, kde si pro nás připravili krátkou prezentaci jejich činnosti. Následně navštívíme jejich datacentrum pod Žižkovskou věží. Provedou nás prostory, které jsou běžnému smrtelníkovi nedostupné!
Po ukončení prohlídky se všchni odebereme do hostince U vodoucha, Jagelonská 21, Praha 3 pochutnat si na některém z vybraných piv či dát si něco na zub. Rezervaci máme od 19:30, heslo je OpenAlt.
Ale pozor! Do prostor datového centra máme omezený přístup, dostane se tam pouze 10 lidí! Takže kdo přijde dříve, ten má přednost, a občanky s sebou! Kdo nebude chtít na prohlídku datového centra, může se pomalu přesunout do hostince U vodoucha a u nepřeberné nabídky piv počkat na ostatní.
Přidat komentář

18.1.2017 0:49 /František Kučera
Členové a příznivci spolku OpenAlt se pravidelně schází v Praze a Brně. Fotky z pražských srazů za uplynulý rok si můžete prohlédnout na stránkách spolku. Příští sraz se koná už 19. ledna – tentokrát je tématem ergonomie ovládání počítače – tzn. klávesnice, myši a další zařízení. Také budete mít příležitost si prohlédnout pražský hackerspace Brmlab.
Přidat komentář

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

> Poslední diskuze

15.6.2017 9:34 / Ondřej Havlas
php,

10.6.2017 10:39 / Temple
sell home for cash

11.5.2017 23:32 / lelo
Re: Problém se správcem balíčků

11.5.2017 5:45 / davd mašek
Re: Problém se správcem balíčků

10.5.2017 22:54 / lelo
Re: Problém se správcem balíčků

Více ...

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