Winuser's Blog

5 grudnia 2011

część I : Dlaczego ten kod źle działa ? (C++)

Filed under: C++,Programowanie — winuser @ 3:09
Tags: , ,

Tak to już jest w życiu kodera, że często popełnia głupie błędy. Często te błędy są banalne, kuriozalne, groteskowe i jak chcecie je jeszcze nazywajcie. Sam już nieraz się z tym spotkałem (we własnym kodzie). Było to jakiś miesiąc temu kiedy siedziałem nad pewnym błędem a debugowanie aplikacji wcale nie dawało tak jasnych odpowiedzi na pytania jak wtedy tego chciałem. Zdarza się, że w człowiek jest tak „zagoniony” że poprostu nie zauważa jak oto walnął pięknego byka w kodzie (dla osoby z zewnątrz może być on widzialny dosłownie na pierwszy rzut oka).

Pierwszym przykładem, jest operator != bardzo często zresztą stosowany w przeróżnych pętlach, if`ach itd. Dlaczego może on być zagrożeniem ? Popatrzmy na przykład w kodzie :

void Fun()
{
    static unsigned int ret = 0;
    char* buf = NULL;

    ret = klasa->recv()

    if(ret != 0)
    {
        buf = new char[ret];
        // tutaj cos robimy z buf
        delete [] buf;
    }
}

Przykład trywialny, pod pewnym względem z nie wiadomo skąd wzięty. Załóżmy że metoda recv z klasy klasa zwróci nam -1 (dajmy na to kod błędu). Samo sprawdzenie czy nie jest równe 0 nie daje nam w tym przypadku bezpieczeństwa. Zostanie utworzona (złe słowo, będzie próba utworzenia) tablicy z ujemnym rozmiarem, co oczywiscie zaowocuje access violation. Sam na czymś podobnym się złapałem i postanowiłem troszkę bardziej myśleć przy warunkach.

Kolejny ładny przykład, znów groteskowy. Łatwo o niego gdy już jesteśmy mocno zmęczeni :

void Fun(int elem_id)
{
    for(int current_id = 0;
    current_id < elem_id; ++elem_id)
    {
        cout << current_id;
    }
}

Istnieje wiele wersji tej pętli („dlaczego te gówno nie chce działać ?!”), np

void Fun(int elem_id)
{
    for(int current_id = 0; current_id < elem_id; ++current_id)
    {
        klasa->Operacja(--current_id);
    }
}

Może ci się to wydawać śmieszne (albo i nie jeśli sam przeżywasz często to co ja) ale po 20 h pisania niemal non stop naprawde trudno to dostrzec. Po prostu wiesz, że produkujesz shit (bo jak inaczej nazwać podobne konstrukcje), męczysz się, podnosisz ciśnienie 6 kawą i nie możesz dostrzec tego głupiego błędu ! Ale to już w sumie temat na innego posta.

W najbliższym czasie wrzucę część drugą wpisu, tym razem będzie ona dotyczyć języka PHP.

18 listopada 2010

C++ kontra PHP

Filed under: C++,PHP,Programowanie,Projekty,WWW — winuser @ 9:42
Tags: , , , , ,

Tak jak ostatnio obiecałem, tak oto zamieszczam moje przemyślenia / badania kwesti wydajności programów kompilowanych (C++) oraz skryptów (PHP). Jest sprawą oczywistą że walka jest nierówna, że porównanie może nie mieć sensu, że te języki stworzono do innych zadań. Ale olejmy na chwilę te wszystkie gadki, jak naprawdę przekłada się to co mówią ludzie na prawdziwe pomiary ? Sprawdziłem to i w tym wpisie można przeczytać efekty tego. Zamieszczam również kod klasy C++ do mierzenia czasu wykonania funkcji czy bloku programu. Zasady sprawdzania były proste, postawiony serwer www z użyciem popularnego pakietu WebServ (do testowania skryptu PHP) oraz skompilowany program C++ (użyłem kompilatora G++) w wersji release wrzucony do folderu CGI-BIN, odpalany z poziomu przeglądarki internetowej Opera. Na pierwszy ogień poszła konktatencja napisów. Żeby walka była wyrównana (zresztą nie może i tak być o wyrównanej walce mowy), to w kodzie C++ użyłem klasy std::string zamiast zwykłych wskaźników char, bo wynik mógłby się okazać wręcz miażdżący dla PHP. Niestety nawet mimo tego się taki okazał.. Wynik PHP: ~27 sekund, wynik C++: ~1.8 sekundy. Kod programu C++ :

#include <iostream>
#include <string>

#include "PerformanceTimer.h"

using namespace std;

int main()
{
	cout << "Content-type: text/html" << endl << endl;
	cout << "<html><head><title>Obliczanie</title>";
	cout << "</head><body>" << endl;
	cout << "<h1>Wyniki obliczen</h1>";
	
	PerformanceTimer pt;
	string napis;
	
	pt.Start();
	for (int i = 0; i < 100000000; i++)
	{
		napis += i;
	}
	pt.Stop();
	
	cout << (pt.GetTime() / (double)10000000) << endl;
	cout << "</body></html>";
	
	return 0;
}

Skrypt PHP:

<html>
	<head>
		<title>Obliczanie</title>
	</head>
	<body>
		<h1>Wyniki obliczen</h1>
		<?php
			$starttime = microtime(true);
			for ($i = 0; $i < 100000000; $i++)
			{
				$napis += $i;
			}
			$stoptime = microtime(true);
			
			echo round($stoptime - $starttime, 5);
		?>
	</body>
</html>

Wykonywanie kodu tego typu (tak wielka ilość iteracji) nie zdarza się raczej zbyt często, aczkolwiek daje pewien obraz sytuacji. W pierwszym teście to, który wygra dość łatwo można było przewidzieć. Ale co gdybyśmy chcieli potestować odczyt i zapis do pliku ? Sprawdziłem. Tym razem testowałem trzy rzeczy, pierwsza odczyt plików i zapis w PHP, druga to odczyt i zapis z użyciem strumieni C++, ostatnia rzecz którą testowałem to odczyt oraz zapis pliku z użyciem funkcji API systemu Windows. Wyniki tym razem nie są już aż tak miażdżące, lecz nadal odrazu widać który sposób jest wydajniejszy. W celu lepszego zobrazowania sytuacji stworzyłem wykres. Jest on wyskalowany w sekundach. Rozmiar pliku na którym testowane były operacje zapis / odczyt można w prosty sposób obliczyć: rozmiar_bufora * ilosc_iteracji = ~ 125 MB.

Dołączam równiez kod C++ użyty do odczytu / zapisu Win32 :

#include <iostream>
#include <string>

#include "PerformanceTimer.h"

using namespace std;

int main()
{
	cout << "Content-type: text/html" << endl << endl;
	cout << "<html><head><title>Obliczanie</title>";
	cout << "</head><body>" << endl;
	cout << "<h1>Wyniki obliczen</h1>";
	
	PerformanceTimer pt;
	DWORD dwWrite;
	
	HANDLE hFile = CreateFile("plik.bin",
							  GENERIC_READ | GENERIC_WRITE,
							  0,
							  0,
							  CREATE_ALWAYS,
							  0,
							  0);
	char szBuffer[255];
	memset(&szBuffer, 0, sizeof(szBuffer));
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		WriteFile(hFile, szBuffer, sizeof(szBuffer), &dwWrite, 0);
	}
	pt.Stop();
	
	cout << (pt.GetTime() / (double) 10000000) << endl;
	CloseHandle(hFile);
	
	hFile = CreateFile("plik.bin",
					   GENERIC_READ | GENERIC_WRITE,
					   0,
					   0,
					   OPEN_EXISTING,
					   0,
					   0);
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		ReadFile(hFile, szBuffer, sizeof(szBuffer), &dwWrite, 0);
	}
	pt.Stop();
	
	cout << (pt.GetTime() / (double) 10000000) << endl;
	CloseHandle(hFile);
	
	cout << "</body></html>";
	return 0;
}

Kod użyty do odczytu / zapisu z użyciem strumieni :

#include <iostream>
#include <fstream>
#include <string>

#include "PerformanceTimer.h"
		
using namespace std;

int main()
{
	cout << "Content-type: text/html" << endl << endl;
	cout << "<html><head><title>Obliczanie</title>";
	cout << "</head><body>" << endl;
	cout << "<h1>Wyniki obliczen</h1>";
	
	PerformanceTimer pt;
	char szBuffer[255];
	ofstream file;
	
	memset(&szBuffer, 0, sizeof(szBuffer));
	file.open("plik.bin");
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		file << szBuffer;
	}
	pt.Stop();
	
	file.close();
	cout << (pt.GetTime() / (double) 10000000) << endl;
	
	ifstream file_2("plik.bin");
	
	pt.Start();
	for (int i = 0; i < 500000; i++)
	{
		file_2.read(szBuffer, sizeof(szBuffer));
	}
	pt.Stop();
	
	file_2.close();
	cout << (pt.GetTime() / (double) 10000000) << endl;

	cout << "</body></html>";
	return 0;
}

A to kod dla PHP :

<html>
	<head>
		<title>Obliczanie</title>
	</head>
	<body>
		<h1>Wyniki obliczen</h1>
		<?php
			for ($i = 0; $i < 255; $i++) $buffer .= "6";
			
			$file = fopen("plik.bin", "w");
			flock($plik, LOCK_EX);
			
			$starttime = microtime(true);
			for ($i = 0; $i < 500000; $i++)
			{
				fwrite($file, $buffer);
			}
			$stoptime = microtime(true);
			
			flock($file, LOCK_UN);
			fclose($file);
			echo round($stoptime - $starttime, 5) . "<br/>";
			
			$file = fopen("plik.bin", "r");
			flock($file, LOCK_SH);
			
			$starttime = microtime(true);
			for ($i = 0; $i < 500000; $i++)
			{
				fread($file, 255);
			}
			$stoptime = microtime(true);
			
			echo "<br/>" . round($stoptime - $starttime, 5) . "<br/>";
			flock($file, LOCK_UN);
			fclose($file);
		?>
	</body>
</html>

Na koniec mała konkluzja tego testu. Od początku wierzyłem że lepsze wyniki uzyska program pisany w C++ i tak też się okazało. Lecz żeby było ciekawiej, to dodam, nie zawsze wyniki uzyskiwane były tak dobre. Nie wiem od czego to zależy, w każdy razie program uruchamiany osobno (nie poprzez serwer www na żadanie przeglądarki) uzyskiwał stabilniejsze i krótsze czasy. Czasem nawet o 1/3. A w przypadku zapisu do pliku wyniki okazywały się być nawet gorsze (!). Mimo tego jednak uważam, że używanie programów CGI kompilowanych może znacząco podnieść wydajność treści dynamicznej, aczkolwiek jest bardziej złożone niż zwykły skrypt w PHP. Ten test nie miał za zadanie oczywiście w żaden sposób pokazać wyższości jednego języka nad drugim. Obydwa lubię i tak już zostanie. Potraktujcie ten test raczej jako ciekawostkę, bo raczej chyba nikt nie będzie pisał www z użyciem C++.
Kod klasy PerformanceTimer można pobrać z pod tego adresu : http://sourceforge.net/projects/performancetime/files/PerformanceTimer.cab/download Jest to klasa napisana z użyciem kodu zawartego w książce „Windows via C/C++” i ja ten kod opakowałem w klasę aby było wygodniej.

17 listopada 2010

Strona internetowa w C++

Filed under: C++,Programowanie,WWW — winuser @ 18:04
Tags: , ,

Osoby obyte w temacie www pewnie w żaden sposób nie zdziwi temat tego wpisu, a inni powiedzą: „co do cholery?”. Ale to prawda, można pisać strony internetowe w języku C++. W języku C też można. Brzmi zachęcająco ? Można też w wielu innych językach które obsługują STDIN i STDOUT (np. Perl, VisualBasic czy Ruby). Ten wpis będzie o pisaniu stron www z użyciem języka C++, resztę sobie podaruję.
Kluczem do odpowiedzi na pytanie „jak to możliwe?” jest słowo „CGI”. Jest to niezmienny standard od 1995 roku. Dawno temu wykorzystywany był do generowania dynamicznie stron, chociaż dziś nadal ma swoją pozycję nieco umniejszoną. Zwykle skrypty CGI pisze się w języku Perl, ale byłoby nudne opisywać tutaj strony www + Perl.
Co wogóle potrzebne jest do tego aby można było tworzyć strony w C++ ? Po pierwsze serwer www z obsługą CGI, jakiś kompilator C++ (ja tutaj użyłem G++). Pliki należy skompilować i wrzucić do folderu cgi-bin. Jeśli z jakiegoś powodu nie uda się uruchomić aplikacji, to najprawdopodobniej serwer wypluje błąd 500. Naturalnie jeśli serwer postawiony jest na systemie Windows to pliki muszą być zbudowane pod tym systemem, jak UNIX to unixowe pliki wykonywalne i tak dalej. Poniżej przedstawiam kod jakiejś prostej strony wypluwającej napis „Jakas tam strona internetowa”.

#include <iostream>
#include <cstdlib>

using namespace std;

int main(int argc, char* argv[])
{
	cout << "Content-type: text/plain" << endl << endl;
	cout << "Jakas tam strona internetowa.";
	
	return EXIT_SUCCESS;
}

Ale co by było gdybyśmy chcieli wyrzucić na wyjście trochę formatowanego kodu HTML ? Trzeba wysłać odpowiednie nagłówki HTTP, a potem kod HTML.

#include <iostream>
#include <cstdlib>

using namespace std;

int main(int argc, char* argv[])
{
	cout << "Content-type: text/plain" << endl << endl;
	cout << "<html><head><title>Tytul strony</title>";
	cout << "</head><body>" << endl;
	cout << "<h1>Jakas tam strona internetowa.</h1>" << endl;
	cout << "A to maly wpisik" << endl;
	cout << "</body></html>";
	
	return EXIT_SUCCESS;
}

Wynikiem wykonania tego programu będzie w przeglądarce :

Niestety pisanie stron w ten sposób jest dosyć uciążliwe i podatne na błędy. Trzeba też się martwić o nagłówki HTTP. Ale przecież zawsze można napisać własną klasę do obsługi tego, co znacznie uprościłoby całość a także zmniejszyła podatność na błędy. Osobiście interesuje mnie sprawa wydajności strony napisanej w C++ w porównaniu z PHP. Jest to nieco bardziej złożony temat, dlatego postanowiłem zostawić sobie go na kolejny wpis.

18 sierpnia 2010

Poszukiwany grafik do małego projektu

Filed under: C++,Programowanie,Projekty — winuser @ 9:09
Tags: , , , , , ,

Ostatnio w wolnym czasie zacząłem sobie pisać dwa projekty. Pierwszy to klasa do obsługi gniazd (z opcją SSL) i zdarzeniami, która jest napisana w około 50 %. Drugi projekt który będzie tematem tego wpisu, to gra 😀 Jest to popularna gra w statki. Kiedy byłem dzieckiem zawsze w to grałem z kolegami / rodzeństwem. Gra odbywała się na kartkach papieru. Postanowiłem ją przenieść do komputera. Oczywiście zdaję sobie sprawę że takie gry dzisiaj tworzą o niebo lepsze, ale tworzenie jej to przecież tylko forma rozrywki 😉

Aplikacja jest pisana w języku C++, z wykorzystaniem windows API  (GDI, winsock). Ano właśnie do czego winsock ? Bo będzie to gra sieciowa. Na chwilę obecną mam już gotowe plansze i ogólnie jakiś tam interfejs. Ale. Nie byłoby tego posta gdyby nie pewna ważna sprawa. Otóż ja sam grafikiem jest raczej marnym, dlatego poszukuję osoby która by mi wykonała obrazki statków (rzut z góry). Potrzebne będzie dokładnie 5 rodzajów statków. Dla kogoś kto orientuje się w grafice to pewnie nic trudnego, dla mnie natomiast coś niewykonalnego 😛 Oczywiście osobę tę umieściłbym w stronie „O programie” w poczecie autorów. Tak więc, jeśli ktoś jest chętny to piszcie w komentarzach. Obrazki nie muszą (nawet nie mogą) być przesadnie realistyczne. Przydały by się tutaj raczej zdolości „pixelart”a.

A oto dwa screeny z nie ukończonej gry. Plansza główna :

Zrzut okna rozpoczynania nowej gry :

30 lipca 2010

Moje przemyślenia na temat *IDE* eclipse

Filed under: C++,Programowanie — winuser @ 10:58
Tags: , , ,

Ten wpis nie powstałby gdyby nie to, że ostatnio zostałem w pewnym sensie zmuszony do pracy na tym pseudo środowisku programistycznym. Dawno temu też miałem okazję przyjrzeć się tej aplikacji (i to kilka razy, zawsze go porzucałem). Kiedy byłem jeszcze na etapie badania różnych środowisk. No i tak wpadło mi w rękę Eclipse. Ten wpis nie jest jakąś formą rzetelnego testu porównawczego, odrazu zaznaczam dla wielbicieli i javowców tego *ide* (bo mnie tu zaraz zlinczują).

W dzisiejszych czasach dąży się do tego aby wszystko uprościć, aby zbędne opcje wyeliminować a całość była przejrzysta. Tymczasem twórcy owego środowiska obrali całkiem inną ścieżkę. Wystarczy zajrzeć w okno ustawień, aby się przerazić :

I teraz weź się człowieku tutaj odnajdź. Spędź pół dnia na rozgryzienie tego wszystkiego. Kolejną pomyłką jest jak dla mnie wzięte z kosmosu kolorwanie kodu :

W żadnym z IDE których używałem nie miałem nieprzyjemności oglądania czegoś takiego. No ale cóż, kolorwanie można jeszcze zmienić, w końcu od czegoś te 2,5 miliona opcji w ustawieniach siedzi. Kolejna sprawa która mnie drażni to brak instalatora. Ludzie zakładają że skoro ktoś programuje to pewnie będzie też potrafił sobie skopiować alikację do jakiegoś tam folderu i używać. No ok, tylko że to chyba też wymaga czasu i jest nie wygodne ? Kolejny minus dla tego czegoś. Co mnie jeszcze drażni w tej aplikacji ? Została napisana w języku Java, a więc wymaga potężnego JDK (czyli kolejne setki MB śmieci na dysku i bynajmniej nie chodzi mi tutaj o miejsce na dysku bo zakupiłem ostatnio 500 GB HDD). Uruchamia się powoooli, interfejs się ładuje, pokazuje pasek postępu.. W normalnych aplikacjach nie do pomyślenia. Jak może się interfejs ładować ? W normalnej aplikacji napisane w C++ i Qt to zajęłoby ułamki sekund. Ale nie w Java. Tutaj musi być pasek postępu dla ładowania interfejsu. Żałosne. Co jeszcze mi nie pasuje w tym środowisku ? Jak już wspomniałem, konfiguracja. Żeby cokolwiek zbudować skompilować zlinkować trzeba przekopać się przez tyle opcji że bania mała. No.. jak już ktoś sobie skonfigurował to całe nie wiadomo co, to wtedy może *budować*.

Jeszcze takie spostrzeżenie na koniec, jako początkujący adept tego *świetnego* środowiska, chciałem otworzyć pewien projekt. Co się ukazało moim oczom :

i bądź tu mądry, otwórz projekt. Właśnie dlatego nie znoszę tej aplikacji. Kompletny brak intuicyjności w obsłudze. Wszystko porobili po swojemu olewając istniejące konwencje w tworzeniu oprogramowania. Wszystko trzeba opanować od nowa.

I nasuwa się pytanie. Ludzie! Dlaczego tego używacie ? Przecież jest tyle świetnych środowisk programistycznych którym do pięt nie dorasta Eclipse, pozwolę sobie tutaj chociaż wymienić Code::Blocks (z którym praca to czysta przyjemnośc), Visual Studio czy Pelles C lub nawet C++ Builder..

19 lipca 2010

Klasa SMTP (Simple Mail Transfer Protocol) z obsługą TLS – wysyłanie email z poziomu C++

Filed under: C++,Programowanie,Projekty — winuser @ 9:29
Tags: , , , , ,

Jakiś czas temu (liczony w miesiącach a może nawet dawniej) potrzebowałem nie skomplikowanej klasy do obsługi wysyłania email poprzez prokół SMTP w języku C++. Ostatnio wraz z kolegą pracujemy nad pewnym projektem no i potrzeba wróciła. Dlatego powstała ta klasa, a w sumie dwie. Jeszcze aby wszystkiego stało się zadość, dodam że klasa ta powstała w oparciu o kod do obsługi SMTP w języku C który znajduje się tutaj http://www.muquit.com/muquit/software/mailsend/mailsend.html Ile kodu skopiowano z wspomnianej wyżej biblioteki mailsend ? Otóż ja niczego nie kopiowałem 😛 Spojrzałem jedynie na jakiej zasadzie to wygląda i zaimplementowałem po swojemu. Tak więc mogę powiedzieć że jestem autorem kodu który tutaj przedstawiam. W zasadzie jest to moje drugie podejście do klasy SMTP, poprzednie mimo że zwieńczone sukcesem to jednak nie obsługiwało TLS, dlatego koncepcja została zmieniona, została napisana klasa Sock która służy do komunikacji TCP, oparta o Winsock 2 i bibliotekę OpenSSL. W tym wydaniu klasy obsługuje ona już m.in gmail.com (czyli połączenie z użyciem TLS) i wszelkie inne typu o2.pl. Całość jest bajecznie prosta, jako że protokół SMTP jest protokołem tekstowym i bardzo łatwo zrozumieć o co w nim wogóle chodzi.

Jeśli chodzi o klasę, to została w niej zaimplementowana tylko podstawowa funkcjonalność SMTP, a więc zalogowanie przy użyciu AUTH LOGIN oraz wysłanie wiadomości. Klasa korzysta z biblioteki OpenSSL, którą należy pobrać i zbudować dla używanego kompilatora, pobrać ją można z pod adresu http://www.openssl.org/ w sieci jest wiele poradników jak budować tą bibliotekę (tak, miałem z tym problem :D). Po wprowadzeniu pewnych zmian, klasa powinna działać również na UNIX`ach (chodzi tutaj głównie o klasę Sock). Dlatego jest *prawie* cross-platformowa 😛 No to tyle.

PS. Nie wyrażam zgody na używanie klasy w komercyjnych projektach. Wszelkie spostrzeżenia i uwagi proszę umieszczać w komentarzach.

Link do kodu  http://www.filefactory.com/file/b2a44bb/n/secure_smtp.cab Niestety jak nie będziecie pobierać to link zdechnie 😉 W razie czego proszę o info.

Musiałem wyedytować ten post, poprzednio kod uploadowałem na serwis fileimport.com, miał być 60 dni ale oczywiście na drugi dzień został usunięty. Tak więc szczerze nie polecam serwisu do hostingu plików fileimport.com !

Dopisek numer2. Zmodyfikowałem kod tak aby możliwe było jego działnie bez biblioteki OpenSSL. Wystarczy zdefiniować globalnie jeden symbol – SLL_ENABLED lub też go nie definiować. Wtedy w zależności od tej stałej będą włączane nagłówki i używane funkcje SSL. Oczywiście po wyłączeniu obsługa np. Gmail.com już nie będzie możliwa.

 

Link do źródła klasy : http://s1.katowice.pl/files/secure_smtp.cab

10 listopada 2009

Co u mnie

Filed under: C++,Programowanie,Uncategorized — winuser @ 13:58
Tags: , ,

Postanowiłem dodać nowy wpis ponieważ dawno nie pisałem. A więc co u mnie ? Szukam pracy. I można to tak nazwać dosłownie bowiem dotychczasowe gadanie kolegów / rodziców nt. znalezienia pracy zweryfikowałem sam. I powiem, że nie jest to łatwe ponieważ nie wielu pracodawców zamierza przyjmować ludzi do pracy bez doświadczenia w danej dziedzinie.

Jeśli chodzi o programowanie, to ostatnio zajmuję się projektem który nazwałem ‚Tlen prowokator’. Jest to kopia ‚GG prowokatora’. Kopia, ale tylko w sposobie działania, ponieważ GUI oraz technologia wykonania są całkiem inne. Napisanie tego zajęło mi około 12 h pracy. Jednak ostatnio zatrzymałem się na jednej funkcji. Mianowicie funkcja `UrlDecode` mająca w swoim prostym założeniu konwertować znaki zapisane hexadecymalnie na system dziesiętny, a następnie zrzutować na typ `char`. Jednak w wersji `anglojęzycznej` byłoby to tylko tak proste ponieważ nasz Tlen używa znaków diaktrycznych, oraz jakby inaczej kodowania innego niż w systemie Windows (Windows CP-1250). Przeglądałem kody bibliotek typu `libtlen / 2` jednak tam korzystają z niestandardowych funkcji w wyniku czego aby zrealizować rekodowanie musiałbym dodać około 150 (jak nie więcej) linii kodu, podczas kiedy cały projekt ma w chwili obecnej około 900. Ale musze to skończyć w najbliższych dniach.