29.10.2014 Views

COMPRESIA datelor - GInfo

COMPRESIA datelor - GInfo

COMPRESIA datelor - GInfo

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Bits&Bytes... (3)<br />

serial<br />

<strong>COMPRESIA</strong> <strong>datelor</strong><br />

Claudiu Soroiu<br />

În cadrul acestui episod al serialului dedicat compresiilor de date vã vom<br />

prezenta metoda de compresie cu dicþionare Lempel Ziv, cea mai rapidã<br />

metodã de compresie, ºi variante ale acesteia.<br />

<strong>GInfo</strong> nr. 13/3 - martie 2003<br />

42<br />

Metoda de compresie LZ (Lempel-Ziv) a fost implementatã<br />

pentru prima datã de cãtre Abraham Lempel ºi Jacob<br />

Ziv în anul 1977 ºi aceastã implementare este denumitã<br />

LZ77. Ulterior metoda a suferit unele modificãri ºi au apãrut<br />

variantele LZ78, LZW (Lempel-Ziv-Welch - 1984),<br />

LZSS (Lempel-Ziv-Storer-Szymanski - 1986).<br />

Metoda LZ77<br />

Metoda de compresie LZ77 constã în pãstrarea ultimelor n<br />

simboluri generate de o sursã de informaþie S ºi gãsirea<br />

celei mai lungi secvenþe de lungime maximã L s<br />

(L s<br />

< n) de<br />

simboluri generate de sursa S în cadrul secvenþei de n<br />

simboluri stocate.<br />

Algoritmul de compresie<br />

Algoritmul de compresie pentru varianta LZ77 este foarte<br />

simplu. La început avem un ºir T care conþine n simboluri.<br />

Fiecare dintre cele n simboluri se iniþializeazã cu primul<br />

simbol al alfabetului unei surse de informaþie S. În continuare,<br />

se pãstreazã primele L S<br />

simboluri generate de sursa<br />

de informaþie S pe ultimele L S<br />

poziþii din ºirul T. Cele L S<br />

simboluri se transmit la ieºirea E.<br />

La pasul urmãtor avem un ºir w iniþial de lungime 0.<br />

Atâta timp cât ºirul w se regãseºte în ºirul T acesta este concatenat<br />

cu urmãtorul simbol generat de sursa de informaþie<br />

S. Vom nota prin w i<br />

ºirul obþinut din primele i simboluri ale<br />

ºirului w. Fie i lungimea lui w în momentul în care acesta<br />

nu se mai regãseºte în ºirul T; aceasta înseamnã cã ºirul w i-1<br />

este cel mai lung ºir generat de sursa S care se aflã în ºirul<br />

T începând de la poziþia p. La ieºirea E se transmite poziþia<br />

p, numãrul (i - 1) ºi simbolul c de pe ultima poziþie a ºirului<br />

w, ceea ce se explicã prin faptul cã urmãtoarele i elemente<br />

ale ºirului iniþial se obþin din i - 1 simboluri consecutive din<br />

ºirul T începând de la poziþia p ºi simbolul c. ªirul T se deplaseazã<br />

la stânga cu i poziþii, iar ultimele i poziþii vor fi<br />

umplute cu simbolurile ºirului w. Acest pas se executã pânã<br />

când sursa de informaþie S nu mai genereazã simboluri.<br />

Pentru a descrie în pseudocod algoritmii din cadrul<br />

acestui articol, vom nota cu '+' operaþia de concatenare<br />

dintre douã ºiruri de simboluri sau dintre un ºir de simboluri<br />

ºi un caracter, vom considera cã prima poziþie a unui<br />

ºir de simboluri este 0 ºi vom avea nevoie de urmãtorii<br />

subalgoritmi:<br />

• Citeºteªir(S, I) - citeºte de la sursa de informaþie S<br />

un ºir de maxim I simboluri pe care îl returneazã ca rezultat;<br />

• CiteºteSim(S) - citeºte de la sursa de informaþie S un<br />

singur simbol pe care îl returneazã ca rezultat;<br />

• CiteºteNum(S) - citeºte de la sursa de informaþie S un<br />

ºir de simboluri pe care îl converteºte la un numãr care<br />

este returnat ca rezultat;<br />

• CiteºteBit(S) - citeºte de la sursa de informaþie S un<br />

ºir de simboluri pe care îl converteºte la o valoare logicã<br />

(0 sau 1) care constituie rezultatul subalgoritmului;<br />

• Genereazã(S) - returneazã ca rezultat valoarea logicã<br />

adevãrat dacã sursa S mai genereazã simboluri ºi valoarea<br />

fals în caz contrar;<br />

• Transmite(E, I 1<br />

, ..., I n<br />

) - transmite la ieºirea E conþinutul<br />

variabilelor I 1<br />

, ..., I n<br />

;<br />

• Lungime(w) - returneazã ca rezultat lungimea ºirului de<br />

simboluri w;<br />

• Primele(s, i) - returneazã ca rezultat ºirul de simboluri<br />

obþinut din primele i simboluri ale ºirului s;<br />

• Ultimele(s, i) - returneazã ca rezultat ºirul de simboluri<br />

obþinut din ultimele i simboluri ale ºirului s;<br />

• Gãsit(s, s 1<br />

) - returneazã ca rezultat valoarea logicã<br />

adevãrat dacã ºirul s 1<br />

este subºir al ºirului s ºi valoarea<br />

fals în caz contrar;<br />

• Poziþie(s, s 1<br />

) - returneazã ca rezultat poziþia de început<br />

a primei apariþii a ºirului s 1<br />

în ºirul s dacã ºirul s 1<br />

este<br />

subºir al ºirului s ºi valoarea -1 în caz contrar.<br />

În continuare vom prezenta algoritmul de compresie<br />

în pseudocod:


se iniþializeazã n cu o constantã<br />

se iniþializeazã L S<br />

cu o constantã<br />

se iniþializeazã T<br />

w ← Citeºteªir(S, L S<br />

)<br />

Transmite(E, w)<br />

T ← Primele(T, n - L S<br />

)+w<br />

dacã nu Genereazã(S) atunci<br />

ieºire<br />

sfârºit dacã<br />

cât timp Genereazã(S) executã<br />

w ← ""<br />

cât timp Genereazã(S) ºi Gãsit(T, w) executã<br />

c ← CiteºteSim(S)<br />

w ← w+c<br />

sfârºit cât timp<br />

i ← Lungime(w)<br />

p ← Poziþie(T, Primele(w, i - 1))<br />

Transmite(E, p, i - 1, c)<br />

T ← Ultimele(T, n - i) + w<br />

sfârºit cât timp<br />

În figura 1 este ilustrat modul în care se realizeazã<br />

compresia unui ºir de simboluri folosind metoda LZ77. Se<br />

poate observa foarte uºor felul în care este actualizat ºirul<br />

de simboluri T ºi cum variazã ºirul w la fiecare pas. Pasul 0<br />

reprezintã pasul de dinaintea instrucþiunii repetitive cât<br />

timp.<br />

Figura 1: Exemplu de compresie cu LZ77<br />

Algoritmul de decompresie<br />

Algoritmul de decompresie pentru metoda LZ77 constã în<br />

interpretarea ºirului comprimat de simboluri generate de o<br />

sursã de informaþie S.<br />

Iniþial se citesc L S<br />

simboluri care se transmit ºi sunt<br />

stocate ºi pe ultimele L S<br />

poziþii ale ºirului T de lungime n.<br />

În continuare, la fiecare pas se citeºte un triplet (p, i, c),<br />

se transmit i simboluri din T începând cu poziþia p, se<br />

transmite simbolul c, T se deplasezã la stânga cu i + 1 poziþii<br />

ºi ultimele i + 1 poziþii din T se completeazã cu ºirul<br />

obþinut din cele i + 1 simboluri transmise.<br />

În pseudocod acest algoritm este:<br />

se iniþializeazã n cu o constantã<br />

se iniþializeazã L S<br />

cu o constantã<br />

se iniþializeazã T<br />

w ← Citeºteªir(S, L S<br />

)<br />

Transmite(E, w)<br />

T ← Primele(T, n - L S<br />

)+w<br />

dacã nu Genereazã(S) atunci<br />

ieºire<br />

sfârºit dacã<br />

cât timp Genereazã(S) executã<br />

p ← CiteºteNum(S)<br />

i ← CiteºteNum(S)<br />

c ← CiteºteSim(S)<br />

w ← Primele(Ultimele(T, n - p), i) + c<br />

Transmite(E, w)<br />

T ← Ultimele(T, n - i - 1) + w<br />

sfârºit cât timp<br />

Observaþii<br />

Complexitatea algoritmului de compresie este O(n · nr),<br />

unde nr este numãrul de simboluri generate de sursa de informaþie<br />

S, deoarece funcþia de cãutare a unui subºir întrun<br />

ºir are complexitatea O(n) ºi modificarea ºirului T se<br />

realizeazã în maxim O(n) paºi, în funcþie de algoritmul<br />

utilizat (dacã se utilizeazã un ºir circular, modificarea poate<br />

avea loc în O(1) paºi).<br />

Complexitatea algoritmului de decompresie este O(nr)<br />

în cazul în care modificarea ºirului T se face în O(1) paºi ºi<br />

construirea lui w se face la fiecare pas folosind O(i) instrucþiuni.<br />

În general ºirul T de simboluri poartã numele de fereastrã<br />

mobilã, acest algoritm fiind cel mai simplu algoritm<br />

de compresie din clasa algoritmilor de compresie cu<br />

ferestre mobile. Dicþionarul în cazul algoritmului LZ77<br />

este constituit chiar de fereastra mobilã T.<br />

Din cauzã cã ºirul T este format numai din ultimele n<br />

simboluri generate de sursa de informaþie S algoritmul<br />

LZ77 nu este optim, deoarece nu mai apar referinþe la codificãri<br />

anterioare deci, dacã mai apare un ºir de simboluri<br />

care trebuie codificate identic cu un ºir codificat anterior,<br />

se întâmplã destul de des sã nu fie codificat în aceeaºi manierã<br />

(folosind un singur triplet (p, i, c)) fapt care duce la<br />

creºterea lungimii codificãrii întregului ºir de simboluri<br />

generate de sursa S. Din acest motiv, cercetãtorii Abraham<br />

Lempel ºi Jacob Ziv au renunþat la fereastra mobilã ºi în<br />

anul 1978 au realizat o nouã implementare în care dicþionarul<br />

de compresie era constituit de ºirurile de simboluri<br />

codificate anterior.<br />

LZ77 este un algoritm fundamental de compresie a<br />

<strong>datelor</strong> ºi stã la baza clasei de algoritmi de compresie cu<br />

fereastrã mobilã, în timp ce LZ78 este baza unei noi clase<br />

de algoritmi de compresie.<br />

Metoda LZSS<br />

În cazul metodei LZ77, se observã foarte uºor cã dacã ultimul<br />

ºir de simboluri w i-1<br />

care se regãseºte în ºirul T este<br />

43<br />

serial<br />

<strong>GInfo</strong> nr. 13/3 - martie 2003


serial<br />

<strong>GInfo</strong> nr. 13/3 - martie 2003<br />

44<br />

chiar ºirul vid atunci, pentru a reprezenta ºirul w care se<br />

codificã se transmit numerele p ºi (i - 1) care au valoarea 0<br />

ºi simbolul din ºirul w. Aceasta înseamnã cã pentru a codifica<br />

un singur simbol trebuie douã numere care sunt inutile.<br />

Metoda LZSS constituie o îmbunãtãþire asupra metodei<br />

LZ77. Îmbunãtãþirea este aceea cã în cazul enunþat<br />

anterior, dacã avem de codificat un singur simbol, se transmite<br />

bitul 0 urmat de simbol, iar dacã avem de codificat un<br />

ºir mai lung de simboluri, se transmite bitul 1 urmat de<br />

perechea (p, i). În acest ultim caz, la iteraþia urmãtoare<br />

ºirul w va fi iniþializat cu ºirul format din ultimul simbol<br />

generat de sursa S.<br />

În concluzie, dacã lungimea codificãrii unui ºir este<br />

mai mare decât ºirul necodificat, atunci se va transmite la<br />

ieºire necodificat, precedat de un bit setat pe 0. Se observã<br />

cã în cazul acestui algoritm, dacã este nevoie sã se codifice<br />

un ºir, în fereastra mobilã se va introduce doar cel mai<br />

lung subºir care se regãseºte în aceasta ºi nu primul subºir<br />

care nu se regãseºte (cum se întâmplã în cazul algoritmului<br />

de compresie LZ77).<br />

Algoritmul de compresie LZSS este:<br />

se iniþializeazã n cu o constantã<br />

se iniþializeazã L S<br />

cu o constantã<br />

se iniþializeazã T<br />

w ← Citeºteªir(S, L S<br />

)<br />

Transmite(E, w)<br />

T ← Primele(T, n - L S<br />

)+w<br />

dacã nu Genereazã(S) atunci<br />

ieºire<br />

sfârºit dacã<br />

w ← ""<br />

cât timp Genereazã(S) executã<br />

cât timp Genereazã(S) ºi Gãsit(T, w) executã<br />

c ← CiteºteSim(S)<br />

w ← w+c<br />

sfârºit cât timp<br />

i ← Lungime(w)<br />

dacã i=1atunci<br />

Transmite(E, 0, c)<br />

w' ← ""<br />

altfel<br />

p ← Poziþie(T, Primele(w, i))<br />

dacã p=-1atunci<br />

i ← i-1<br />

p ← Poziþie(T, Primele(w, i))<br />

w' ← c<br />

dacã i=1atunci<br />

Transmite(E, 0, Primele(w, 1))<br />

altfel<br />

Transmite(E, 1, p, i )<br />

sfârºit dacã<br />

altfel<br />

w' ← ""<br />

Transmite(E, 1, p, i )<br />

sfârºit dacã<br />

sfârºit dacã<br />

T ← Ultimele(T, n - i) + Primele(w, i)<br />

w ← w'<br />

sfârºit cât timp<br />

În figura urmãtoare se poate observa modul de compresie<br />

a unui ºir de simboluri generate de o sursã S, folosind<br />

algoritmul LZSS:<br />

Figura 2: Exemplu de compresie cu LZSS<br />

Decompresia unui ºir de simboluri comprimat cu metoda<br />

LZSS se realizeazã la fel ca în cazul algoritmului<br />

LZ77 cu precizarea cã în momentul decodificãrii unei perechi<br />

se verificã bitul care o precede, ºi anume, dacã bitul<br />

este 0, atunci, la ieºire se va transmite un simbol c, iar dacã<br />

este 1, atunci, la ieºire se va transmite subºirul din fereastra<br />

mobilã care începe de la o poziþie p ºi are lungimea i. Acþiunea<br />

de decodificare va fi urmatã de actualizarea ferestrei<br />

mobile.<br />

În continuare prezentãm varianta pseudocod a algoritmului<br />

de decompresie LZSS:<br />

se iniþializeazã n cu o constantã<br />

se iniþializeazã L S<br />

cu o constantã<br />

se iniþializeazã T<br />

w ← Citeºteªir(S, L S<br />

)<br />

Transmite(E, w)<br />

T ← Primele(T, n - L S<br />

)+w<br />

dacã nu Genereazã(S) atunci<br />

ieºire<br />

sfârºit dacã<br />

cât timp Genereazã(S) executã<br />

b ← CiteºteBit(S)<br />

dacã b=0atunci<br />

c ← CiteºteSim(S)<br />

w ← c<br />

i ← 1<br />

altfel


p ← CiteºteNum(S)<br />

i ← CiteºteNum(S)<br />

w ← Primele(Ultimele(T, n - p), i)<br />

sfârºit dacã<br />

Transmite(E, w)<br />

T ← Ultimele(T, n - i) + w<br />

sfârºit cât timp<br />

memorie) nu se mai adaugã elemente în aceasta, acest fapt<br />

ducând la ineficienþa algorimtului pentru date foarte multe<br />

ºi pentru multe apariþii ale unor ºiruri de simboluri care nu<br />

se aflã printre elementele listei.<br />

În figura 3 se poate observa modul în care se realizeazã<br />

compresia <strong>datelor</strong> folosind algorimtul prezentat anterior.<br />

Ordinele de complexitate ale algoritmilor de compresie<br />

ºi decompresie pentru metoda LZSS sunt aceleaºi cu<br />

cele ale algoritmilor de compresie, respectiv decompresie,<br />

pentru algoritmul LZ77, în schimb, un ºir de simboluri generat<br />

de o sursã de informaþie S este comprimat mai bine<br />

dacã se foloseºte algoritmul LZSS.<br />

Metoda LZ78<br />

Spre deosebire de cele douã metode de compresie a <strong>datelor</strong><br />

prezentate anterior, metoda LZ78 nu foloºte o fereastrã<br />

mobilã, ci reþine toate ºirurile de simboluri codificate anterior<br />

într-o listã.<br />

La începutul compresiei, mãrimea listei de elemente T<br />

codificate anterior este 1 ºi conþine pe poziþia 0 ºirul vid.<br />

La un pas, se considerã lista elementelor obþinutã la pasul<br />

anterior ºi se citeºte de la o sursã de informaþie S cel mai<br />

scurt ºir de simboluri w care nu se aflã în lista elementelor<br />

T. În aceastã listã se va adãuga ºirul w, iar la ieºirea E se va<br />

transmite o pereche formatã din numãrul de ordine al primei<br />

apariþii a ºirului obþinut din ºirul w prin eliminarea<br />

ultimului simbol din acesta.<br />

Pentru a putea prezenta algoritmul de compresie LZ78<br />

avem nevoie de subalgoritmul Cautã(s, w), care primeºte<br />

ca parametri o listã de ºiruri de simboluri s ºi un ºir de<br />

simboluri w, returnând ca rezultat numãrul de ordine al primei<br />

apariþii a ºirului w în lista s. Dacã w nu apare printre elementele<br />

listei s, atunci rezultatul subalgoritmului va fi -1.<br />

Vom considera cã numãrul de ordine al primului ºir care<br />

apare în lista s este 0.<br />

T[0] ← w //iniþial, lista T conþine doar ºirul vid<br />

k ← 1<br />

//k reprezintã mãrimea listei T<br />

cât timp Genereazã(S) executã<br />

w ← ""<br />

cât timp Genereazã(S) ºi Cautã(T, w) ≥ 0 executã<br />

c ← CiteºteSim(S)<br />

w ← w+c<br />

sfârºit cât timp<br />

T[k] ← w<br />

k ← k+1<br />

i ← Lungime(w)<br />

w ← Primele(w, i - 1)<br />

i ← Cautã(T, w)<br />

Transmite(E, i, c)<br />

sfârºit cât timp<br />

În practicã, atunci când dimensiunea listei T ajunge la<br />

o valoare prestabilitã (datoritã insuficienþei resurselor de<br />

Figura 3: Exemplu de compresie cu LZ78<br />

Algoritmul de decompresie devine acum foarte simplu<br />

deoarece, la fiecare pas, se interpreteazã o pereche (i, T)<br />

care se citeºte de la sursa de informaþii ºi se transmite ºirul<br />

care se aflã pe poziþia i în lista T urmat de caracterul din<br />

pereche.<br />

Iniþial, ca ºi în cazul compresiei, lista T conþine doar<br />

ºirul vid. La fiecare pas se adaugã în lista T ºirul format din<br />

elementul de pe poziþia i din T ºi din caracterul care a fost<br />

citit.<br />

În pseudocod, algoritmul de decompresie LZ78 este:<br />

T[0] ← w //iniþial, lista T conþine doar ºirul vid<br />

k ← 1<br />

//k reprezintã mãrimea listei T<br />

cât timp Genereazã(S) executã<br />

i ← CiteºteNum(S)<br />

c ← CiteºteSim(S)<br />

Transmite(E, T[i], c)<br />

T[k] ← T[i] + c<br />

k ← k+1<br />

sfârºit cât timp<br />

Complexitatea algoritmului de compresie are ordinul<br />

O(m · n), unde m reprezintã media lungimii ºirurilor de<br />

simboluri care se aflã în lista T, în cazul în care se foloseºte<br />

un algoritm banal de cãutare, iar n reprezintã numãrul<br />

total de simboluri generate de o sursã de informaþie S. În<br />

cazul în care se foloºte un algoritm performant de cãutare<br />

ºi lista T este reprezentatã folosind arbori de sufixe, atunci<br />

aceastã complexitate scade foarte mult.<br />

45<br />

serial<br />

<strong>GInfo</strong> nr. 13/3 - martie 2003


Algoritmul de decompresie are ordinul de complexitate<br />

O(n), unde n reprezintã numãrul de simboluri care trebuie<br />

decodificate.<br />

algoritmul LZ78 care, pentru a comprima acelaºi ºir de<br />

simboluri, transmite 11 coduri ºi 11 simboluri.<br />

serial<br />

<strong>GInfo</strong> nr. 13/3 - martie 2003<br />

Metoda LZW<br />

Welch a observat o deficienþã a algoritmului LZ78, ajungând<br />

la concluzia cã pentru a decodifica un ºir de simboluri<br />

nu este nevoie de o pereche formatã dintr-un indice ºi<br />

un simbol.<br />

Prin urmare, acesta a modificat algoritmii de compresie<br />

ºi decompresie astfel:<br />

• lista T era iniþializatã cu ºiruri de simboluri, fiecare ºir de<br />

simboluri fiind format din câte un simbol al alfabetului<br />

sursei de informaþie S. În lista T sunt atâtea ºiruri câte<br />

simboluri are alfabetul;<br />

• la fiecare pas din iteraþie:<br />

♦ ºirul w este iniþializat cu ultimul simbol al ºirul w obþinut<br />

la pasul anterior;<br />

♦ în lista T se adaugã cel mai scurt ºir w, obþinut prin<br />

concatenãri succesive cu simboluri generate de sursa<br />

S, care nu se alfã în T;<br />

♦ la ieºire se transmite un singur cod care reprezintã numãrul<br />

de ordine al apariþiei lui w din care se extrage<br />

ultimul simbol.<br />

Acest algoritm este cunoscut sub denumirea LZW.<br />

În continuare prezentãm în pseudocod algoritmul care<br />

realizeazã compresia unui ºir de simboluri generate de o<br />

sursã de informaþie S pentru metoda LZW. În figura 4 se<br />

poate observa modul în care se realizeazã compresia unui<br />

ºir de simboluri.<br />

se iniþializeazã T cu cele m simboluri ale alfabetului sursei S<br />

k ← m<br />

//k reprezintã mãrimea listei, T<br />

w ← ""<br />

cât timp Genereazã(S) executã<br />

cât timp Genereazã(S) ºi Cautã(T, w) ≥ 0 executã<br />

c ← CiteºteSim(S)<br />

w ← w+c<br />

sfârºit cât timp<br />

i ← Cautã(T, w)<br />

dacã i ≥ 0 atunci<br />

Transmite(E, i)<br />

altfel<br />

T[k] ← w<br />

k ← k+1<br />

i ← Lungime(w)<br />

w ← Primele(w, i - 1)<br />

i ← Cautã(T, w)<br />

Transmite(E, i)<br />

w ← c<br />

sfârºit dacã<br />

sfârºit cât timp<br />

//sursa S nu mai genereazã simboluri,<br />

sfârºitul compresiei<br />

Figura 4: Exemplu de compresie cu LZW<br />

Algoritmul de decompresie este asemãnãtor cu cel de<br />

la metoda LZ78 cu deosebirea cã în lista T se adaugã ºirul<br />

format din ºirul decodificat la pasul anterior ºi primul<br />

simbol al ºirului decodificat la pasul curent.<br />

În pseudocod, acest algoritm este:<br />

se iniþializeazã T cu cele m simboluri ale alfabetului sursei S<br />

k ← m<br />

//k reprezintã mãrimea listei, T<br />

i ← CiteºteNum(S)<br />

w ← T[i]<br />

Transmite(E, w)<br />

cât timp Genereazã(S) executã<br />

i ← CiteºteNum(S)<br />

T[k] ← w + Primele(T[i], 1)<br />

w = T[i]<br />

Transmite(E, T[i])<br />

k ← k+1<br />

sfârºit cât timp<br />

Ordinele de complexitate ale algoritmilor de compresie<br />

ºi decompresie ale metodei LZW sunt aceleaºi ca ºi în<br />

cazul metodei LZ78.<br />

Algoritmii LZ78 ºi LZW, datoritã rapiditãþii, sunt utilizaþi<br />

des în programele comerciale de compresie singurul<br />

inconvenient fiind acela cã mãrimea listei T trebuie limitatã<br />

datoritã cantitãþii mici de resurse disponibile pe sistemele<br />

de calcul.<br />

46<br />

Pe exemplul din figura 4 se poate observa cã pentru a<br />

comprima ºirul se transmit 14 coduri, spre deosebire de<br />

Claudiu Soroiu este redactor al <strong>GInfo</strong> ºi poate fi contactat prin e-mail la<br />

adresa csoroiu@yahoo.com.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!