Laborator 5 - Procese 2

Înainte de laborator

Utilizare terminal

Pentru a deschide un terminal nou:

Scurtătură Descriere
Ctrl+Alt+t pentru a deschide o nouă fereastră de terminal

Puteți folosi următoarele scurtături în terminal:

Scurtătură Descriere
Ctrl+Shift+t pentru a deschide un nou tab
Ctrl+PageDown pentru a merge la tab-ul următor
Ctrl+PageUp pentru a merge la tab-ul precedent
Alt+<index> pentru a sări direct la un tab
Ctrl+d pentru a închide un tab (sau comanda exit)

Pentru a naviga (scrolling) în cadrul unui terminal, mai ales atunci când o comandă afișează mult text, folosiți următoarele scurtături:

Scurtătură Descriere
Shift+PgDown pentru a derula în jos
Shift+PgUp pentru a derula în sus

Alte scurtături utile:

Scurtătură Descriere
Ctrl+Shift+c copiere text din terminal
Ctrl+Shift+v lipire text în terminal
Shift+Insert lipire text în terminal

Paginile de manual sunt adesea de mari dimensiuni și avem nevoie să le parcurgem rapid (să navigăm prin ele). Pentru aceasta, după ce deschidem pagina de manual a unei comenzi, putem folosi combinațiile de taste de mai jos pentru a naviga în pagină:

Tastă Scurtă descriere
/string_to_search / (adică tasta slash) e folosită pentru a căuta string_to_search în pagina de manual
n (next) pentru a merge la următoarea apariție a cuvântului căutat cu /
N (Shift + n) pentru a merge la precedenta apariție a cuvântului
q (quit) pentru a închide pagina de manual
Enter pentru a derula în jos o linie
f (forward) sau Space pentru a derula în jos un ecran
b (backward) pentru a derula în sus un ecran
d (down) pentru a derula în jos jumătate de ecran
u (up) pentru a derula în sus jumătate de ecran

Obiective

  • Înțelegerea conceptelor legate de procese
  • Dobândirea de competențe de monitorizare și interacțiune cu procesele
  • Obținerea de abilități de lucru cu utilitare și comenzi Linux
  • Obținerea de noțiuni de bază legate de comunicarea inter-proces: pipe-uri și semnale

Pe scurt despre Git

Pe parcursul laboratoarelor, pentru descărcarea fișierelor necesare laboratorului, vom folosi Git. Git este un sistem de controlul versiunii și e folosit pentru versionarea codului în proiectele software mari. Celor interesați să aprofundeze conceptele din spatele comenzii git, precum și utilizări avansate, le recomandăm cursul practic online de pe gitimmersion.

Informațiile despre laboratorul de USO se găsesc în acest repository Git.

Pentru a pregăti infrastructura de laborator rulați comenzile de mai jos într-un terminal. Deschideți un terminal folosind combinația de taste Ctrl+Alt+t. În listarea de mai jos student@uso:~$ este promptul unde introduceți comenzile, pe acela nu-l tastați.

student@uso:~$ cd ~
student@uso:~$ git clone https://github.com/systems-cs-pub-ro/uso-lab.git
student@uso:~$ cd uso-lab/02-process/support/

Cam atât cu pregătirea laboratorului. Acum haideți să ne apucăm de treabă! :-)

Concepte

Vizualizarea proceselor din sistem (ps, pstree, top, htop)

Ierarhia de procese în Linux este sub formă arborescentă; putem vizualiza folosind pstree (similar cu tree de la sistemul de fișiere)

Folosind ps fără nici un parametru vizualizăm procesele din shell-ul curent asociate utilizatorului curent.

student@uso:~$ ps
  PID TTY          TIME CMD
22101 pts/0    00:00:00 bash
22209 pts/0    00:00:00 ps

Tot cu ps putem vizualiza un snapshot al tuturor proceselor. Aceasta se poate obține folosind două variante ale comenzii:

student@uso:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3 160140  7044 ?        Ss   10:39   0:02 /sbin/init spla
root         2  0.0  0.0      0     0 ?        S    10:39   0:00 [kthreadd]
[...]
student  22101  0.0  0.2  31236  5192 pts/0    Ss   19:38   0:00 bash
student  22114  0.0  0.2  31236  5008 pts/1    Ss+  19:38   0:00 bash
root     22151  0.0  0.3  25656  6260 ?        S    19:40   0:00 /sbin/dhclient 
student  22191  0.0  0.1  46012  3656 pts/0    R+   19:48   0:00 ps aux

Un utilitar echivalent lui Windows Task Manager pentru vizualizarea în timp real a proceselor care rulează, în linie de comandă, este htop.

student@uso:~$ htop

Atributele unui proces

Procesul este identificat în sistem cu ajutorul unui număr numit PID (process ID). Acesta este unic în sistem. Atunci când un proces este creat, se asignează un PID nou, următorul crescător liber.

Un alt atribut important este PID-ul procesului părinte, PPID. Având o structură ierarhică, toate procesele au un părinte, părintele tuturor fiind init sau systemd (în funcție de sistem) și are PID-ul 1.

Atributul COMMAND ne spune numele procesului sau comanda cu care a fost creat:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
student  23176  0.0  0.1  46012  3644 pts/0    R+   22:06   0:00 ps aux

Pentru o listă completă de atribute, verificați manualul.

Foreground & Background (&, fg, bg, jobs)

Există mai multe stări în care un proces se poate afla:

  1. Starea în care rulează
  2. Starea în care este oprit: se folosește Ctrl+Z
  3. Starea în care este terminat (procesul nu mai există): se folosește Ctrl+C

Apăsând o combinație de taste din cele de mai sus, trimitem un semnal procesului:

Taste Semnificație
Ctrl+C trimite SIGINT
Ctrl+Z trimite SIGSTOP
Ctrl+\ trimite SIGQUIT

În secțiunea Demo exemplificăm cum se trece prin aceste stări.

Semnale (kill)

Un utilizator poate trimite un semnal unui proces folosind comanda kill! Este foarte important să înțelegem că scopul principal al utilitarului nu este omorârea de procese, deși poate face și asta. O listă a tuturor semnalelor posibile ce pot fi trimise aflăm prin

student@uso:~$ kill -l   

Utilitarele pkill și killall termină procesele folosind ca argument numele procesului și nu PID-ul (ca la kill).

Redirectare (>, >>, <, |)

Redirectare stdout (standard output, în general mesaje afișate prin comenzi similare cu printf din C). Pentru a redirecta lista proceselor într-un fișier, folosim următoarea comandă:

student@uso:~$ ps aux > procese.txt

Astfel, am specificat procesului să nu mai afișeze rezultatul pe ecran, ci într-un fișier. Diferența între > și » este că primul înlocuiește conținutul fișierului procese.txt, pe când al2lea adaugă la sfârșitul fișierului.

Operatorul < folosit comanda < fisier.txt setează comenzii intrarea fisier.txt.

student@uso:~$ grep "Disable" < vm-actions-log.txt 
* Disable terminal bell and scrolling in terminal:
* Disable cursor blinking in terminal:
* Disable DNS usage in SSH server:
* Disable automated screen locking:

Comunicarea interprocese, folosind pipe |

Operatorul | este foarte important și uzual folosit. Acesta ia rezultatul primei comenzi și îl oferă ca intrare la a2a comandă. Câteva exemple:

student@uso:~$ ps aux | grep sleep
student  22406  0.0  0.0  16116   828 pts/0    S    20:28   0:00 sleep 1000
student  22408  0.0  0.0  23076  1084 pts/0    S+   20:28   0:00 grep --color=auto sleep
student@uso:~$ tree | grep Documents
├── Documents

Se pot înlănțui 2 sau mai multe comenzi.

Procesele daemon

Procesele daemon sunt procese ce rulează în fundal. De obicei, acestea sunt servicii ce servesc anumite funcții specifice. Acestea pot fi recunoscute ca având procesul părinte cu PID 1 (procesul init sau systemd).

Demo

Vizualizarea proceselor din sistem (ps, pstree, top, htop)

Folosind ps fără nici un parametru vizualizăm procesele din shell-ul curent asociate utilizatorului curent.

student@uso:~$ ps
  PID TTY          TIME CMD
22101 pts/0    00:00:00 bash
22209 pts/0    00:00:00 ps

Tot cu ps putem vizualiza un snapshot al tuturor proceselor. Aceasta se poate obține folosind două variante ale comenzii:

student@uso:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3 160140  7044 ?        Ss   10:39   0:02 /sbin/init spla
root         2  0.0  0.0      0     0 ?        S    10:39   0:00 [kthreadd]
[...]
student  22101  0.0  0.2  31236  5192 pts/0    Ss   19:38   0:00 bash
student  22114  0.0  0.2  31236  5008 pts/1    Ss+  19:38   0:00 bash
root     22151  0.0  0.3  25656  6260 ?        S    19:40   0:00 /sbin/dhclient 
student  22191  0.0  0.1  46012  3656 pts/0    R+   19:48   0:00 ps aux

Un utilitar echivalent lui Windows Task Manager pentru vizualizarea în timp real a proceselor care rulează, în linie de comandă, este htop.

student@uso:~$ htop

Atributele unui proces

În mod implicit, când afișăm procesele, ni se arată următoarele atribute:

student@uso:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
[...]

Putem specifica ce atribute să ne afișeze și în ce ordine dorim:

student@uso:~$ ps -ax -o ppid,pid,cmd
 PPID   PID CMD
    0     1 /sbin/init splash
    0     2 [kthreadd]
[...]

Pentru a selecta doar procesele pornite de utilizatorul student:

student@uso:~$ ps -f -u student
UID        PID  PPID  C STIME TTY          TIME CMD
student    900     1  0 11:10 ?        00:00:00 /lib/systemd/systemd --user
student    901   900  0 11:10 ?        00:00:00 (sd-pam)
[...]

Foreground & Background (&, fg, bg, jobs)

Vom folosi ca exemplu utilitarul sleep. Trebuie să știm dacă procesul nostru rulează sau nu. Pentru a verifica acest lucru, dintr-un alt terminal, ne folosim de utilitarul ps:

Terminal 1:

student@uso:~$ sleep 100

Terminal 2:

student@uso:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3 160140  7044 ?        Ss   10:39   0:02 /sbin/init spla
root         2  0.0  0.0      0     0 ?        S    10:39   0:00 [kthreadd]
[...]
student  22268  0.0  0.0  16116   884 pts/0    S    19:54   0:00 sleep 100
student  22281  0.0  0.1  46012  3744 pts/0    R+   19:54   0:00 ps aux

Am găsit procesul sleep în sistem. Putem folosi utilitarul pgrep pentru a afla PID-ul procesului.

student@uso:~$ pgrep sleep
22268

Pentru a opri procesul, vom folosi combinația de taste Ctrl+Z:

student@uso:~$ sleep 100
student@uso:~$ ^Z
[1]+  Stopped                 sleep 100
student@uso:~$ jobs
[1]+  Stopped                 sleep 100

Am folosit utilitarul jobs pentru a vedea ce procese sunt active în terminalul curent. De aici putem folosi bg (background) pentru a porni procesul în mod interactiv sau fg (foreground) pentru a porni procesul în mod neinteractiv. Mai simplu, la bg putem da alte comenzi în timp ce programul nostru rulează, iar la fg nu putem să dăm alte comenzi.

Semnale (kill)

Vom folosi în continuare comanda kill pentru a trimite semnale proceselor. Această comandă nu omoară neapărat procesul, în ciuda numelui.

student@uso:~$ kill --help
kill: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
    Send a signal to a job.

Dintr-un alt terminal aflăm PID-ul procesului sleep folosind utilitarul pgrep. Pentru a termina procesul, trimitem semnalul 9 (SIGKILL):

student@uso:~$ jobs
[1]+  Stopped                 sleep 100
student@uso:~$ pgrep sleep
22286
student@uso:~$ kill -9 22286
student@uso:~$ jobs
[1]+  Killed                  sleep 100

Am transmis semnalul 9 (SIGKILL) procesului 22286, iar acesta a fost terminat instant.

Redirectare

Pentru a redirecta lista proceselor într-un fișier, folosim următoarea comandă:

student@uso:~$ ps aux > procese.txt

Astfel, am specificat procesului să nu mai afișeze rezultatul pe ecran, ci într-un fișier. Diferența între > și » este că primul înlocuiește conținutul fișierului procese.txt, pe când al2lea adaugă la sfârșitul fișierului. Astfel, executând a2a oară comanda:

student@uso:~$ ps aux >> procese.txt

Vom avea în fișierul procese.txt afișat de 2 ori ieșirea comenzii.

Comunicare interprocese, folosind |

Operatorul | este foarte important și uzual folosit. Acesta ia rezultatul primei comenzi și îl oferă ca intrare la a doua comandă. Câteva exemple:

student@uso:~$ ps aux | grep sleep
student  22406  0.0  0.0  16116   828 pts/0    S    20:28   0:00 sleep 1000
student  22408  0.0  0.0  23076  1084 pts/0    S+   20:28   0:00 grep --color=auto sleep
student@uso:~$ tree | grep Documents
├── Documents

Basics

Vizualizarea proceselor din sistem (ps, pstree, top, htop)

Folosind ps fără nici un parametru vizualizăm procesele din shell-ul curent asociate utilizatorului curent.

student@uso:~$ ps
  PID TTY          TIME CMD
22101 pts/0    00:00:00 bash
22209 pts/0    00:00:00 ps

Parametrul aux asociat lui ps ne arată toate procesele din sistem:

student@uso:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3 160140  7044 ?        Ss   10:39   0:02 /sbin/init spla
root         2  0.0  0.0      0     0 ?        S    10:39   0:00 [kthreadd]
[...]
student  22101  0.0  0.2  31236  5192 pts/0    Ss   19:38   0:00 bash
student  22114  0.0  0.2  31236  5008 pts/1    Ss+  19:38   0:00 bash
root     22151  0.0  0.3  25656  6260 ?        S    19:40   0:00 /sbin/dhclient 
student  22191  0.0  0.1  46012  3656 pts/0    R+   19:48   0:00 ps aux

Atributele unui proces

Pentru a selecta doar procesele pornite de utilizatorul student folosim -u:

student@uso:~$ ps -f -u student
UID        PID  PPID  C STIME TTY          TIME CMD
student    900     1  0 11:10 ?        00:00:00 /lib/systemd/systemd --user
student    901   900  0 11:10 ?        00:00:00 (sd-pam)
[...]

Putem specifica ce atribute să ne afișeze și în ce ordine dorim:

student@uso:~$ ps -ax -o ppid,pid,cmd
 PPID   PID CMD
    0     1 /sbin/init splash
    0     2 [kthreadd]
[...]

Până a trece mai departe, trebuie să vă asigurați că ați înțeles cum trebuie navigarea printr-o ierarhie de procese. Pentru asta, parcurgeți următoarele exerciții după care verificați cu asistentul că totul este în regulă.

  1. Afișați toate procesele din sistem care să conțină date legate de PID, PID-ul părintelui, user-ul care deține procesul și comanda care a pornit procesul
  2. Filtrați procesele după utilizatorul curent (student)
  3. Afișați procesele în mod interactiv (folosind top/htop)

Need to Know

Foreground & Background (&, fg, bg, jobs)

Vom folosi ca exemplu programul bg-proc.sh. Acesta afișează în fiecare secundă câte un mesaj “Tick” sau “Tock”. Pornim programul:

student@uso:~/.../02-process/support$ ./bg-proc.sh 
Tick!
Tock!
Tick!
^C

L-am terminat cu Ctrl+C:

Îl pornim din nou și de data asta îl oprim cu Ctrl+Z. Ce observăm?

student@uso:~/.../02-process/support$ ./bg-proc.sh 
Tick!
Tock!
Tick!
^Z
[1]+  Stopped                 ./bg-proc.sh

Verficăm dacă procesul încă există în sistem:

student@uso~/.../02-process/support$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3 160140  7152 ?        Ss   oct08   0:03 /sbin/init splash
root         2  0.0  0.0      0     0 ?        S    oct08   0:00 [kthreadd]
[...]
**student  23597  0.0  0.1  21532  3532 pts/0    T    09:53   0:00 /bin/bash ./bg-proc.sh**
student  23600  0.0  0.0  16116   780 pts/0    T    09:53   0:00 sleep 1
student  23601  0.0  0.1  46012  3784 pts/0    R+   09:53   0:00 ps aux

Pentru a reporni procesul avem 2 variante:

  1. Pornim procesul în mod interactiv folosind comanda bg. Asta înseamnă că noi putem da comenzi, chiar dacă în fundal este un proces care afișează text
  2. Pornim procesul în mod neinteractiv folosind comanda fg. Asta înseamnă că procesul oprit anterior a revenit în prim-plan în terminal. Nu vom putea da alte comenzi.
student@uso:~/.../02-process/support$ ./bg-proc.sh
Tick!
Tock!
 
[1]+  Stopped                 ./bg-proc.sh
student@uso:~/.../02-process/support$ bg
[1]+ ./bg-proc.sh &
student@uso:~/.../02-process/support$ Tick!
Tock!
lsTick!
 
batman.sh  bg-proc.sh  it-s-a-trap.sh
student@uso:~/.../02-process/support$ Tock!
Tick!
Tock!
^C
student@uso:~/.../02-process/support$ Tick!
Tock!

Puteți observa că am încercat să termin programul folosind Ctrl+C. Acest lucru nu a fost posibil pentru că acesta rula în fundal. Pentru asta trebuie să aducem procesul în prim-plan și să îl terminăm sau să îi aflăm PID-ul și să-l terminăm folosind utilitarul kill.

Exerciții

  1. Porniți programul bg-proc.sh.
  2. Treceți-l în starea foreground și apoi în background.
  3. Terminați procesul cu Ctrl+C și cu utilitarul kill
  4. Faceți același lucru și cu programul it-s-a-trap.sh

Redirectare

Pentru a redirecta lista proceselor într-un fișier, folosim următoarea comandă:

student@uso:~$ ps aux > procese.txt

Un alt exemplu de redirectare este:

student@uso:~/.../02-process/support$ echo "prima linie din fisier" > fis.txt
student@uso:~/.../02-process/support$ cat fis.txt 
prima linie din fisier
student@uso:~/.../02-process/support$ echo "a2a linie din fisier" >> fis.txt 
student@uso:~/.../02-process/support$ cat fis.txt 
prima linie din fisier
a2a linie din fisier
student@uso:~/.../02-process/support$ echo "a3a linie din fisier" > fis.txt 
student@uso:~/.../02-process/support$ cat fis.txt 
a3a linie din fisier

Putem observa că la a3a linie am folosit > în loc de » și am șters conținutul anterior al fișierului.

Comunicare interprocese, folosind |

Putem căuta după un anumit proces din sistem astfel:

student@uso:~$ ps aux | grep sleep
student  22406  0.0  0.0  16116   828 pts/0    S    20:28   0:00 sleep 1000
student  22408  0.0  0.0  23076  1084 pts/0    S+   20:28   0:00 grep --color=auto sleep

Care este logica din spatele comenzii? În loc să ne afișeze nouă pe ecran rezultatul comenzii ps aux, acesta a fost transmis către următoarea comandă grep. Comanda din urmă a căutat cuvântul sleep în rezultatul comenzi ps aux.

Exerciții

  1. Afișați recursiv toate fișierele și directoarele din uso-lab, redirectând totul într-un fișier. Înspectați fișierul pentru verificare.
  2. Înlănțuiți comanda precedentă cu grep pentru a căuta în uso-lab fișierele ce conțin cuvântul lab.

Nice to Know

Pentru această secțiune trebuie să vă asigurați că sunteți în directorul potrivit. Rulați comanda

cd ~/uso-lab/02-process/support/

Valori de eroare

Putem verifica dacă comanda executată anterior s-a executat cu succes folosind $?:

student@uso:~/.../02-process/support$ cat README.md 
uso
===
 
   * Directorul ''lab02'' conține toate fișierele și structura de directoare necesare rezolvării laboratorului 2 de către studenți
student@uso:~/.../02-process/support$ echo $?
0
student@uso:~/.../02-process/support$ cat fisier-care-nu-exista.txt
cat: fisier-care-nu-exista.txt: No such file or directory
student@uso:~/.../02-process/support$ echo $?
1

Atunci când valoarea este 0, procesul s-a executat cu succes. Orice diferit de 0 este o eroare.

Exerciții

  1. Încercați să afișați un fișier ce nu există. Ce cod de eroare primiți?
  2. Încercați să rulați o comandă cu parametri aleatori (ex: ps -ewqgew). Ce cod de eroare primiți?

Structura arborescentă a proceselor

Afișăm toate procesele din sistem cu atributele PID, PPID, CMD:

student@uso:~/.../02-process/support$ ps ax -o pid,ppid,cmd
  PID  PPID CMD
    1     0 /sbin/init splash
[...]
19540     2 [jfsSync]
22046     2 [kworker/0:1]
22090   900 /usr/lib/gnome-terminal/gnome-terminal-server
22101 22090 bash
22114 22090 bash
22234     1 /usr/bin/python3 /usr/bin/update-manager --no-update --no-focus-on-map
22559     1 /usr/sbin/cupsd -l
22560     1 /usr/sbin/cups-browsed
22742     2 [loop10]
22785     1 /usr/lib/snapd/snapd
22913     2 [loop12]
23200     2 [kworker/u2:0]
23394   530 /sbin/dhclient -d -q -sf /usr/lib/NetworkManager/nm-dhcp-helper -pf /run/dhclient-enp0s8.pid -lf /var/lib/NetworkManager/dhclient-fda81623-2338-36f
23519     2 [kworker/u2:1]
23974     2 [kworker/u2:2]
24107 22101 ps ax -o pid,ppid,cmd

Putem observa că părintele comenzii executate de noi este bash; are PID-ul 22101.

Exerciții

  1. Afișați structura arborescentă a proceselor. Folosiți utilitarul pstree menționat anterior.
  2. Încercați să obțineți același efect folosind utilitarul ps (hint: căutați în man după cuvântul tree).
  3. Care este diferența dintre cele două moduri de afișare? Oferă aceleași informații?

Get a Life

Trimiterea de semnale unui proces

Pentru acest exercițiu trebuie să vă asigurați că sunteți în directorul potrivit. Rulați comanda

cd ~/uso-lab/02-process/support/

În directorul respectiv este scriptul batman.sh:

student@uso:~/.../02-process/support$ ls
batman.sh  bg-proc.sh  it-s-a-trap.sh

Rulați scriptul batman.sh. Procesul interceptează toate semnalele cu indecși de la 1 la 13, mai puțin 9 (din motive evidente). De fiecare dată când primește un semnal cu indexul între 1 și 13 el afișează pe ecran un caracter. Mai jos aveți maparea dintre indecșii semnalelor și caracterul afișat:

Index semnal Caracter
1 o
2 u
3 c
4 d
5 e
6 z
Index semnal Caracter
7 s
8 h
10 (space)
11 r
12 k
13 l

2.1 Într-un alt terminal aflați PID-ul procesului și trimiteți-i semnale astfel încât procesul să afișeze pe ecran șirul de caractere uso rullz.

Recuperare fișier folosind procfs

Descărcați un fișier video de pe Internet. Puteți instala și utiliza youtube-dl pentru a descărca un film de pe YouTube.

Rulați filmul cu un player de filme. În timp ce rulează, ștergeți fișierul.

Până la a termina de rulat filmul, recuperați fișierul folosind procfs (din /proc), din directorul aferent procesului player de filme.

Inspectare comenzi de investigare procese

Folosind utilitarul strace inspectați ce fișiere din procfs (din /proc) sunt deschide de utilitarul lsof pentru afișarea descriptorilor deschiși de un proces existent, de utilitarul pmap pentru afișarea memorie unui proces și de utilitarul free pentru afișarea memoriei disponibile din sistem.

sde/laboratoare/05_ro_procese.txt · Last modified: 2020/03/17 16:57 by ioana_maria.culic
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0