[c++] Wydajny odczyt dużych plików tekstowych

0

Witam wszystkich,

Mam do napisania aplikację, która wczytuje słownik z wyrazami i wyłuskuje z niego konkretne wyrazy, które następnie umieszcza w jakimś komponencie (np. RichEdit). Zrobienie tego za pomocą funkcji getline() jest stosunkowo proste, ale wydajność takiego rozwiązania pozostawia wiele do życzenia. Pętla musi przejść przez ponad 100,000 wierszy w pliku i dokonać porównania ze wzorcem, w celu wyłuskania interesującego mnie wyrazu.
Znalazłem w internecie sposób, jak wczytać plik słownika błyskawicznie do jakiegoś komponentu. Oto on:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
ifstream plik("PS_WYRAZY.txt");
char* buf;
plik.seekg(0,ios::end);
int length=plik.tellg();
plik.seekg(0,ios::beg);
buf=new char[length];

plik.read(buf,length);
Form1->RichEdit1->Lines->Add(buf);
}

I faktycznie wczytanie całego pliku do komponentu RichEdit następuje błyskawicznie. Ale...
W jaki sposób mam dokonywać porównania i wpisać tylko interesujące mnie słowa? Zmienna "buf" to tablica, która zawiera ponad 1,300,000 indeksów (każda litera w osobnym indeksie) i nijak nie wiem jak to ugryźć...

Istnieje jakiś sposób na przeszukiwanie tego bufora w celu znalezienia konkretnego słowa? A może trzeba zastosować zupełnie inne rozwiązanie? Męczę się z tym od wczoraj i nie mam już pomysłu. Nawet google przestały mi pomagać. ;-P

Dziękuję z góry za zainteresowanie i pomoc.
Pozdrawiam, Dex.

0

do odczytywania faktycznie najszybszy jest read, imho powinniennes raczej odczytywac blokami, wielokrotnosc 512bajtow, np: 8kB, co do wzorca to szybkim i prostym do napisania algorytmem wyszukiwania jest kmp (knuth morris pratt)

0

Wszelkie operacje wczytywnia i przetwarznia tekstu zrób w buforze .
Wynik końcowy może być prezentowany w kontrolkach graficznych .
Posrednie przetwarzanie tekstu ( lub danych binarnych ) na bieżąco spowlnia dzałanie
programu (np. użycie wczytanych danych z RichEdit) . Fun języka C są bardziej wydajne w operacjach na pliku lub danych zawartych w buf.

0

Ano, zawartość pliku wczytałem do bufora. Tylko teraz powiedz mi jak go mam przetworzyć? ;-P
Na innym forum podpowiedziano mi, żebym zawartość tablicy char skopiował do stringstreama i na nim operował.

Co do algorytmu KMP - widziałem przykładowy kod, ale uważam, że za dużo zachodu z tym będzie.

0

aaa teraz doczytalem, masz zrobic slownik :P
to kmp odpada w sumie bo to do czego innego, przetokenuj plik, wyciagnij z niego klucz i odpowiadajace slowo i stworz drzewo slownikowe

np: masz wezel i w wezel ma a...z dzieci
czas wyszukiwania to bedzie O(l) gdzie l to dlugosc wyrazu klucza :p

inny sposob to mapa (mozesz uzyc hash map z stl)
czas dostepu bedzie w wiekszosci przypadkow taki sam, a pamieciowo chyba wyjdzie mniejszy narzut

0

stringstreama

Wygodne , ...
Zobacz fun C strcmp i podobne .
Dużo zależy od tego czy plik będzie zmieniany w trakcie pracy programu .
Na podstawie słów których poszukujesz można zrobić "mapę" pliku zawierającą
po jednokrotnym wczytaniu położenie (wskaznik w pliku- buforze) szukanych wyrazów , skraca to
czas potrzebny na odczytanie danych związanych z ich lokalizacją .

0

Wszystko ładnie i pięknie, ale ja tu kod potrzebuję. :) Mówisz, że mam użyć tamtego i siamtego, kiedy ja nie do końca wiem, jak to wykorzystać. :)
Uściślę, że ten słownik to zwykły plik tekstowy txt, gdzie każda linia to jedno słowo. Plik ten ma ponad 100,000 takich linii. Teraz pozostaje tylko kwestia przeglądnięcia tego pliku i znalezienia konkretnego słowa. Jak już mówiłem getline() można o kant d**y rozbić, bo przeglądanie i porównywanie wzorca trwa koszmarnie długo.
A kopiowania chara do stringstreama dalej nie bardzo kapuję.
Robię coś w stylu:

ifstream plik("PS_WYRAZY.txt");
char* buf;
plik.seekg(0,ios::end);
int length=plik.tellg();
plik.seekg(0,ios::beg);
buf=new char[length];

plik.read(buf,length);
stringstream ss;
ss<<buf;

No i co dalej... Ech. ;-P

0

No czlowiek dostałeś już informację @cepa i ja rusz trochę mózgownicą
i sam daj kawałek kodu bo na razie to tylko wczytałeś dane do bufora ... [green]

0

Nie czekam na gotowe rozwiązanie tylko w międzyczasie sam coś kombinuję. A jak wykombinuję to dam znać. ;-P

0

No i problem z głowy.
Przedstawię rozwiązanie dla potomnych:

void __fastcall TForm1::Button4Click(TObject *Sender)
{
ifstream plik("PS_WYRAZY.txt");
char* buf;
plik.seekg(0,ios::end);
int length=plik.tellg();
plik.seekg(0,ios::beg);
buf=new char[length];

plik.read(buf,length);
buf[length-3]='\0';
plik.close();

string slowo1;
stringstream ss;
ss<<buf;
delete[] buf;
while(getline(ss,slowo1)){
String dupa=AnsiString(slowo1.begin());
if(dupa=="guz"){
           ShowMessage(dupa); }
}

}

Działa. Bez żadnych hash_map i innych dziwnych rzeczy. ;-P
Pozdrawiam.

0

Taaa... A badz laskaw sie pochwalic ile to cudo teraz pozera pamieci, co?

0

Zamiast teraz pajacować mógłbyś podać przykładowy kod, jak zaoszczędzić pamięć.

Ja natomiast rozwiązałem ten problem tak, jak potrafiłem.

0

Zechciej wyrazac sie jak na publicznym forum przystalo.

Dostales wskazowki, ale nie chciales z nich skorzystac. Ja dodam od siebie, ze zwykle takie wyszukiwanie 'slownikowe' wykonuje sie na B-drzewie, ale najpierw musialbys na ten temat poczytac.

Co do Twojego rozwiazania to jest ok, ale do wydajnego to mu daleko. Oto podstawowe bledy:

  1. Za kazdym kliknieciem powtarzasz wczytywanie pliku, stad przy kazdym wyszukiwaniu wczytujesz caly, duzy plik, zeby go przerobic na stringstream - to zabiera czas. Zrob chociaz jakis cache.
  2. Wyszukujesz wzorzec liniowo - to najwiekszy blad, bo tutaj zdecydowanie lepsze efekty da b-drzewo (O(logn)) albo chociaz haszmapa (O(1)). W drugim przypadku musialbys sobie przygotowac indeks czastek wyrazow, ale to mogloby byc zbyt duze.

Podsumowujac - wczytuj plik tylko raz. Wczytuj go od razu do stringstreama, bo teraz podwojnie tracisz pamiec - na bufor i na stringstreama. Wykorzystaj b-drzewo, zeby wyszukiwanie bylo szybsze.

PS. Nie napisales czym jest wzorzec.

0

Wzorzec to jakieś słowo, którego szukam w słowniku.
Z tym wczytywaniem za każdym kliknięciem i podwójnym buforowaniem to faktycznie masz rację. Popracuję nad tym.
Natomiast jeśli chodzi o b-drzewo i hash mapę to nie będę się z tym bawił. Zapomniałem dodać na początku tematu, że wyszukiwanie wyrazów w tak dużym słowniku to nadprogramowy dodatek do aplikacji, którą wykonuję na zaliczenie. Może być, ale nie musi.
Generalnie program polega na tym, aby podać zbiór liter, po czym następuje wypisanie wszystkich permutacji zadanego zbioru i znalezienie palindromu. A słownik palindromów to raptem 80 słów więc jakieś b-drzewa i inne nie są mi potrzebne do szczęścia.

A wyraziłem się tak jak wyraziłem, bo odebrałem Twoją wypowiedź jak zadzieranie nosa. ;-P

0

Aaaa, jak na zaliczenie i nie jest sednem programu to w zasadzie wystarczy 1. punkt. To i tak przyspieszy dzialanie minimum 2 razy.

0

A próbowałeś posortować ten słownik (np. alfabetycznie) i wtedy szukać? Nie wiem jak z wydajnością takiego rozwiązania, ale wiedząc, ze masz słownik posortowany, powinieneś w jakiś sposób mieć ułatwione szukanie... Mógłbyś wtedy od razu wykluczyć te wpisy, które nie pasują (np. zaczynają się na inną literę niż potrzebujesz)... warto spróbować... :)

pozdrawiam.

0

Słownik z 80 słów to faktycznie super problem... no, ale w zasadzie ilość tu nie ma znaczenia.

Na chama robimy tak:

  1. czytamy całość,
  2. tworzymy tablicę wskaźników
    (przy okazji wpisujemy zera w miejsce znaczników końca linii: '\0' => '\n' lub '\r'
  3. sortujemy tę tablicę wskaźników qsort

Potem szukamy binarnie.

Praktycznie jest to rozwiązanie optymalne:
A. szybkość światła - może być nawet milion haseł + kilka, kilkaset, czy tysiąc znaków na linię,
B. nadmiarowe zużycie pamięci minimalne - tylko ta tablica wskaźników.
C. można tu dopisywać nowe hasła, zmieniać definicje, usuwać, modyfikować - wszystko.

Nawet takie toporne rozwiązanie jest z 1000 razy lepsze od tych złomów z stl...

0

Na jakiej podstawie madralo chcesz posortowac same wskazniki? Wedlug adresu pamieci? Pomysl zanim cos napiszesz.

PS. 'Minimalne zuzycie pamieci' - wskaznik to o ile sie nie myle 4B * Twoj przykladowy milion to 4MB. I chcesz tam szukac binarnie? Wolne zarty.
PS2. 'zlomy z stl' - nie wiesz o czym mowisz, to moze lepiej sie nie wypowiadaj.

0

Heh... ja 7 lat skutecznie unikałem STL'a. Robiłem wszystko by unikać hash_map i innych 'bezużytecznych udziwnień'. No... i w sumie dobrze na tym wyszedłem. Kod płynął sobie zdrowo i wszyscy byli szczęśliwi... do czasu ;). Do czasu, aż zleceniodawca uparł się, że chce tablice haszowe ;). Zagroził, że nie będzie wypłaty no i trzeba było się do tego zmusić...

Cóż... od tego czasu - uważam STL'a i haszmapy za błogosławieństwo! :-D
Po prostu, do tego trzeba dorosnąć ;).

obsługa hash_set opiera się tak naprawdę na 5-10 wierszach w kodzie ;). Nic trudnego, a wydajność przeszukiwania jest porażająca! :).

0
johny_bravo napisał(a)

Na jakiej podstawie madralo chcesz posortowac same wskazniki? Wedlug adresu pamieci? Pomysl zanim cos napiszesz.

PS. 'Minimalne zuzycie pamieci' - wskaznik to o ile sie nie myle 4B * Twoj przykladowy milion to 4MB. I chcesz tam szukac binarnie? Wolne zarty.
PS2. 'zlomy z stl' - nie wiesz o czym mowisz, to moze lepiej sie nie wypowiadaj.

Tablicę wskaźników do haseł normalnie sortujesz - porównujesz np. tak: lstrcmpi(t[i], t[j]);
albo robisz swoją funkcję, np. tak:
int cmpstr(char *a, char *b) { returm lstrcmpi(a,b); }

4 ekstra bajty na linię to praktycznie nic.
Pozycja w prostym słowniku z definicjami ma średnio z 70 znaków,
dodasz te 4, czyli będzie 74 - i to ma być duży narzut?

stl można sobie używać, ale właśnie dla tych 80 elementów;
podobnie te stringlisty z delphi i inne takie toporne złomy pisane przez imbecyli na etacie.

Kiedyś zrobiłem nawet teścik: prosty słownik synonimów.
Gdy zobaczyłem jak to działa na tych obiektach to o mało co nie posrałem się ze śmiechu...
Normalnie mistrzostwo szmaciarstwa - ładowanie, ok. tysiąc słów, trwało grube sekundy, a pamięci żarło z 300%.
Strach pomyśleć co tu się działo z milionem słów...
Różne słowniki robiłem już ze sto lat temu w paskalu, i to tam ze 100 razy szybciej szło na procesorach 100MHz, niż te stl teraz na 100GHz (plus peta bajt ram na dzień dobry, bo inaczej amen).

Zresztą wystarczy wleźć w źródła tych stl - widać ile tam redundancji, setki razy indeksy sprawdzane i tony fuszerki wszelkiej możliwej maści.

Albo takie załadowanie kilku tysięcy pozycji do List/TreeView w VCL - to dopiero złom, hehe. [green]
No ale nie przesadzajmy - to tak jak z samochodami - trzeba przecież czymś jeździć, bo.... benzyna drożeje! [rotfl]
cześć i czołem... oby nie w beton. :-D

0

Jeśli szukasz słowa w całości - najszybsza będzie hash mapa
Jeśli szukasz słowa po prefiksie - najszybsze będzie drzewko, Trie lub Patricia(Radix) tree

Przy 80 wpisach zwykłe wyszukiwanie liniowe wystarczy, zbiór nie musi być posortowany, nie trzeba przyspieszać, bo i tak wyszukiwanie będzie trwało w mgnieniu oka. Jeśli jednak chcesz sobie polepszyć ocenę jakimś szybszym rozwiązaniem to użyj mapy lub drzewa, albo przynajmniej posortuj i wyszukuj binarnie ( O(log(n)) ).

@fju: nie wiesz to nie pir.... głupot. Napisałeś nieprawdę. Zresztą po tym co radzisz widać ahh ... mniejsza o to. Przystopuj bo kocopoły prawisz.

Żeby zobrazować jak to jest przy więskszej ilości wpisów, pokażę tabelkę ze złożonością.
n - ilość słów (czynnik najważniejszy)
m - długość słowa

                             |       | lista         | hash | drzeko
                             | lista | posortowana   | mapa | trie
-----------------------------+-------+---------------+------+--------
budowanie struktury          |  n*m  | n*m(posortow.)| n*m  | n*m
złożoność pamięciowa         |  n*m  | n*m           | n*m  | mniej niż log(n)*m
wyszukiwanie słowa           |  n*m  | log(n)*m      |  m   | m
wyszukiwanie po prefiksie    |  n*m  | log(n)*m      |  -   | m
0

Zaraz, zaraz. Napisales, ze chcesz miec w pamieci tablice wskaznikow, a teraz mowisz o porownywaniu stringow. To sie zastanow teraz gdzie te wskazniki wskazuja i gdzie upchniesz te wszystkie dane. Bo to juz nie jest minimalne zuzycie pamieci. Oprocz tego qsort nie dziala w czasie O(1). A co do zmiany slownika (dopisywania, itp) to nie widze tutaj jakos jakiejs przewagi Twojego 'rozwiazania' nad stl'em. Krotko - wywazasz otwarte drzwi do tego w sposob co najmniej szkolny. Nie chcesz to nie korzystaj z dzialajacych rozwiazan, ale przyjmij do wiadomosci, ze lista JEST wolniejsza od haszmapy czy drzewa TRIE w wyszukiwaniu i juz.

Oprocz tego rzucasz haslami z 10 roznych bajek (stl, VCL, delphi, pascal, itp) i masz wrazenie, ze Twoj belkot brzmi jakkolwiek powaznie. Szkoda gadac.

0
johny_bravo napisał(a)

Zaraz, zaraz. Napisales, ze chcesz miec w pamieci tablice wskaznikow, a teraz mowisz o porownywaniu stringow. To sie zastanow teraz gdzie te wskazniki wskazuja i gdzie upchniesz te wszystkie dane. Bo to juz nie jest minimalne zuzycie pamieci. Oprocz tego qsort nie dziala w czasie O(1). A co do zmiany slownika (dopisywania, itp) to nie widze tutaj jakos jakiejs przewagi Twojego 'rozwiazania' nad stl'em. Krotko - wywazasz otwarte drzwi do tego w sposob co najmniej szkolny. Nie chcesz to nie korzystaj z dzialajacych rozwiazan, ale przyjmij do wiadomosci, ze lista JEST wolniejsza od haszmapy czy drzewa TRIE w wyszukiwaniu i juz.

Ładujemy cały plik - można jednym strzałem do bufora i sprawa załatwiona.
Potem lecisz tym buforem i robisz tak, że wskaźniki z tablicy wskaźników wskazują na pierwszą literę hasła w tym buforze.

qsort to faktycznie dość cienka metoda, tu szybciej wyjdzie od razu wstawiać hasło (czyli wskaźnik) w dobrej pozycji, czyli szukamy binarnie, mamy pozycję k, przesuwamy całość od pozycji k o 1 dalej, i wpisujemy: t[k] = hasło.

Tak będzie kilka razy szybciej - zwłaszcza gdy te hasła będą już częściowo posortowane; wtedy będziemy tylko wstawiać na końcu: t[liczba_hasel++] = hasło.

STL czy inne gotowce zawsze przegrają ze specjalnie zoptymalizowanym kodem, bo to są uniwersalne zabawki do trywialnych rzeczy, a nie jakieś tam super sprawy...

Oprocz tego rzucasz haslami z 10 roznych bajek (stl, VCL, delphi, pascal, itp) i masz wrazenie, ze Twoj belkot brzmi jakkolwiek powaznie. Szkoda gadac.

Aha, chciałeś to samym stl zrobić - tak całkiem bez kompilatora, języka i pewnie jeszcze bez komputera, co? [rotfl]</quote>

0

Dobra, po kolei, chociaz nuzy mnie Twoje zenujace podejscie do tematu. Ostatniego zdania w ogole nie skomentuje, bo najwyrazniej nie umiesz czytac i do tego bawi Cie nabijanie sie na poziomie przedszkolaka.

Ale, zeby scislosci stalo sie zadosc to przeanalizujmy Twoje megasuper rozwiazanie:

  1. Ladowanie pliku do pamieci - tego nie unikniemy raczej, z wyjatkiem ewentualnie jakiegos cache'owania wybranych elementow, wiec omijam.
  2. Qsort jest cienki. Ok, nie jest idealny. Ale to co podales dalej to sortowanie przez wstawianie O(n2), gdzie qsort to srednio O(nlogn). Gratuluje wyboru lepszej metody, wykazales sie znajomoscia podstaw sortowania.
  3. 'Kilka razy szybciej' - nie ma to jak super analiza poparta dowodami. Okreslenie 'przyspieszenia' jest baaaardzo naukowe, nie ma co.

A teraz porownanie wyszukiwania przez hashmape (bo do drzewa trie nie ma co twojego sposobu porownywac, absolutnie sie do tego nie nadaje).

  1. Ladowanie pliku i wstawianie do haszmapy to O(1), o ile pamietam (wyliczenie wartosci z funkcji haszujacej)
  2. Wyszukiwanie w haszmapie to O(1).

Jakies pytania co do porownania? Bo z mojej strony EOT.

0
johny_bravo napisał(a)

Dobra, po kolei, chociaz nuzy mnie Twoje zenujace podejscie do tematu. Ostatniego zdania w ogole nie skomentuje, bo najwyrazniej nie umiesz czytac i do tego bawi Cie nabijanie sie na poziomie przedszkolaka.

Ale, zeby scislosci stalo sie zadosc to przeanalizujmy Twoje megasuper rozwiazanie:

  1. Ladowanie pliku do pamieci - tego nie unikniemy raczej, z wyjatkiem ewentualnie jakiegos cache'owania wybranych elementow, wiec omijam.
  2. Qsort jest cienki. Ok, nie jest idealny. Ale to co podales dalej to sortowanie przez wstawianie O(n2), gdzie qsort to srednio O(nlogn). Gratuluje wyboru lepszej metody, wykazales sie znajomoscia podstaw sortowania.
  3. 'Kilka razy szybciej' - nie ma to jak super analiza poparta dowodami. Okreslenie 'przyspieszenia' jest baaaardzo naukowe, nie ma co.

A teraz porownanie wyszukiwania przez hashmape (bo do drzewa trie nie ma co twojego sposobu porownywac, absolutnie sie do tego nie nadaje).

  1. Ladowanie pliku i wstawianie do haszmapy to O(1), o ile pamietam (wyliczenie wartosci z funkcji haszujacej)
  2. Wyszukiwanie w haszmapie to O(1).

Jakies pytania co do porownania? Bo z mojej strony EOT.

Qsort jest wolniejszy, bo liczba porównań tych haseł/tekstów tu decyduje, a nie kopiowań 4bajtowych wskaźników.

Ładowanie do hashmapy byłoby może szybsze, ale nie jest to aż tak rewelacyjne, bo alokujesz tu pamięć w tysiącach kawałków, liczysz te klucze, występują kolizje kluczy.
Trzeba pamiętać klucze, listy, wskaźniki - cała ta struktura sieciowa żre tony ekstra pamięci,
a czas budowy takiej sieci nie jest wcale taki malutki.

Ale to odpada bo słownik ma być sortowany, tak aby można było wywalić tekst na ekran w tradycyjnej postaci.

Takie coś sprawdzamy praktycznie, a teoretycznie to można dużo gadać.
Był już taki jeden mistrz od gedankeneksperymentów - napierdzielił tyle głupot, że teraz nawet 40 wymiarów czasowych żadnego wrażenia nie robi na motłochu - ot, normalna rzecz... :-D

1
fju napisał(a)

szukamy binarnie, mamy pozycję k
wyszukiwanie binarne O(log(n)),
w kroku m=1..n przeszukujemy tablicę wielkości m, czyli w sumie mamy
log(1) + log(2) + ... + log(n) = log(n!)

fju napisał(a)

przesuwamy całość od pozycji k o 1 dalej
w kroku m=1..n średnio przesuniemy połowę z m elementów, w sumie 1/2 + 2/2 + 3/2 + ... + n/2 = n^2 / 4
[soczek]

0
adf88 napisał(a)
fju napisał(a)

szukamy binarnie, mamy pozycję k
wyszukiwanie binarne O(log(n)),
w kroku m=1..n przeszukujemy tablicę wielkości m, czyli w sumie mamy
log(1) + log(2) + ... + log(n) = log(n!)

fju napisał(a)

przesuwamy całość od pozycji k o 1 dalej
w kroku m=1..n średnio przesuniemy połowę z m elementów, w sumie 1/2 + 2/2 + 3/2 + ... + n/2 = n^2 / 4
[soczek]

No i dobrze: n*log(n) > ln(n!), czyli to idzie szybciej od qsort,
a pamięci są bardzo szybkie, i nawet takie n^2 dla miliona pozycji pójdzie szybko.

0

No tak, przeciez komputery sa szybkie, wiec po co sie zlozonoscia przejmowac, nie? Ostatnio stazysta w firmie, w ktorej pracuje, popelnij sql'a pobierajacego do sesji 0,5MB danych. I tez argumentowal, ze klient pewnie ma szybszy serwer niz my (nasz czasem odpalal timeout). Argument o takiej samej mocy jak Twoj...

PS. Kto powiedzial, ze slownik ma byc posortowany? Ja chce znalezc dany element (a np. przy haszmapie idzie to wiele razy szybciej niz Twoje rozwiazanie), a nie sortowac elementy. I zastanow sie co jest celem. Wedlug mnie - szybkie znalezienie elementu, wedlug Ciebie trzymanie ladnej struktury elementow.

0

Pewnie że ta asymptotyczna złożoność ma niekiedy niewielkie znaczenie,
porównaj sobie: 0.000000001n^2 i 1000000000log(n).

Tam masz n^2 kopiowań 4 bajtów, a kopiowanie 4 bajtów trwa tyle samo co 1, 8, 16, 64 i nawet większej liczby, bo to zależy od sprzętu - szerokość szyny danych, itp. (jednego bitu nie przekopiujesz).

A porównanie tekstów to skomplikowana sprawa - zwłaszcza takie słownikowe: abc == a b c.
Operacja porównania za pomocą lstrcmpi trwa setki razy dłużej od kopiowania kilku bajtów w miejscu.

1

To do mnie czy do adf88? Bo nijak nie pasuje do tego co ja napisalem, ani tego co on.

Co do porownania, to przeciez Ty chcesz sortowac, nie my :D Wiec to Ty bedziesz porownywal stringi, a nie my. W haszmapie wyliczana jest funkcja skrotu (nie ma porownania stringu), w drzewku Trie sprawdzane sa kolejne litery i w ten sposob trawersowane jest drzewo, wiec tutaj ten argument tez upada.

O co Ci chodzi? Na sile starasz sie udowodnic cos, czego nie umiesz udowodnic i dobierasz argumenty nie rozumiejac wypowiedzi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1