From 0868e0642f694bf5c08951f67f5a4b7eadde041a Mon Sep 17 00:00:00 2001
From: Jacek Kowalski <Jacek@jacekk.info>
Date: Thu, 05 Sep 2013 21:22:22 +0000
Subject: [PATCH] Zmiana numeru wersji na 2.6, testy jednostkowe niektórych klas (PHPUnit), dodanych wiele komentarzy dotyczących metod oraz atrybutów (Doxygen), aktualizacja instrukcji instalacji i aktualizacji.

---
 INSTALL                           |    7 
 class/legacy/jsarray.php          |   17 
 tests/Core/BotMsgTest.php         |   99 ++++++
 class/legacy/calendar.php         |    6 
 class/legacy/funcs.php            |   13 
 class/BotMessage.php              |   31 +
 class/BotModule.php               |   40 ++
 class/legacy/main.php             |   10 
 class/BotSession.php              |   73 +++
 Doxyfile                          |  285 +++++++++++++++++++
 tests/Core/BotSessionTest.php     |  136 +++++++++
 class/BotImageGG.php              |    2 
 class/legacy/module.php           |   15 
 tests/Core/Legacy/JSArrayTest.php |   29 +
 class/BotMsg.php                  |   46 ++
 phpunit.xml                       |   10 
 class/BotImage.php                |   17 +
 class/BotUser.php                 |   21 +
 tests/Core/BotMessageTest.php     |   13 
 .travis.yml                       |    8 
 tests/autoload.php                |    2 
 UPGRADE                           |   11 
 class/std.php                     |    6 
 23 files changed, 839 insertions(+), 58 deletions(-)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2e72fdc
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: php 
+php:
+  - 5.5
+  - 5.4
+  - 5.3
+  - 5.2
+
+script: phpunit --coverage-text
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..6eb6f66
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,285 @@
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING      = UTF-8
+PROJECT_NAME           = "Bot Gadu-Gadu"
+PROJECT_NUMBER         = 
+OUTPUT_DIRECTORY       = docs
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = Polish
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        = 
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+QT_AUTOBRIEF           = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = NO
+OPTIMIZE_OUTPUT_JAVA   = NO
+OPTIMIZE_FOR_FORTRAN   = NO
+OPTIMIZE_OUTPUT_VHDL   = NO
+EXTENSION_MAPPING      = 
+BUILTIN_STL_SUPPORT    = NO
+CPP_CLI_SUPPORT        = NO
+SIP_SUPPORT            = NO
+IDL_PROPERTY_SUPPORT   = YES
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+TYPEDEF_HIDES_STRUCT   = NO
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = YES
+EXTRACT_STATIC         = YES
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = YES
+EXTRACT_ANON_NSPACES   = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = NO
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+FORCE_LOCAL_INCLUDES   = NO
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES       = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = NO
+SHOW_FILES             = YES
+SHOW_NAMESPACES        = YES
+FILE_VERSION_FILTER    = 
+LAYOUT_FILE            = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = 
+INPUT_ENCODING         = UTF-8
+FILE_PATTERNS          = *.php
+RECURSIVE              = YES
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = */docs/* */data/* */tests/* */modules/*
+EXCLUDE_SYMBOLS        = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION    = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = NO
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_TIMESTAMP         = YES
+HTML_ALIGN_MEMBERS     = YES
+HTML_DYNAMIC_SECTIONS  = NO
+GENERATE_DOCSET        = NO
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+CHM_INDEX_ENCODING     = 
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+GENERATE_QHP           = NO
+QCH_FILE               = 
+QHP_NAMESPACE          = org.doxygen.Project
+QHP_VIRTUAL_FOLDER     = doc
+QHP_CUST_FILTER_NAME   = 
+QHP_CUST_FILTER_ATTRS  = 
+QHP_SECT_FILTER_ATTRS  = 
+QHG_LOCATION           = 
+GENERATE_ECLIPSEHELP   = NO
+ECLIPSE_DOC_ID         = org.doxygen.Project
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+USE_INLINE_TREES       = NO
+TREEVIEW_WIDTH         = 250
+FORMULA_FONTSIZE       = 10
+SEARCHENGINE           = YES
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = YES
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = 
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = YES
+MSCGEN_PATH            = 
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+DOT_FONTNAME           = FreeSans
+DOT_FONTSIZE           = 10
+DOT_FONTPATH           = 
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+DOT_GRAPH_MAX_NODES    = 50
+MAX_DOT_GRAPH_DEPTH    = 0
+DOT_TRANSPARENT        = NO
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
diff --git a/INSTALL b/INSTALL
index 9529f18..64411ae 100644
--- a/INSTALL
+++ b/INSTALL
@@ -8,8 +8,6 @@
     http://dev.gg.pl/api/pages/botapi.html#rejestracja
 * ustaw serwer WWW tak, by plik BotGG.php był wykonywany po wejściu na
   ustalony przy rejestracji adres
-* ustaw serwer WWW tak, by plik BotIMI.php był wykonywany po wejściu na
-  ustalony w IMified.com adres
 * zmień /sciezka/do/bota w pliku data/update.sh na rzeczywistą, bezwzględną
   ścieżkę do katalogu skryptu
 * wykonuj za pomocą crona polecenie `/sciezka/do/bota/data/update.sh` ok.
@@ -34,12 +32,13 @@
 -------
 
 Jeśli dodajesz/usuwasz moduły lub komendy KONIECZNIE usuń wszystkie pliki
-z katalogu ./cache - w przeciwnym wypadku polecenia te mogą powodować błędy
-w działaniu bota!
+z katalogu ./cache - w przeciwnym wypadku może to powodować błędy
+w działaniu całego bota!
 
 ------------
  INFORMACJA
 ------------
+
 W razie problemów zacznij od zmiany
     error_reporting(E_COMPILE_ERROR|E_PARSE);
 na
diff --git a/UPGRADE b/UPGRADE
index 1c01ce2..28d3823 100644
--- a/UPGRADE
+++ b/UPGRADE
@@ -1,3 +1,14 @@
+Wersję można sprawdzić w pliku ./class/legacy/main.php
+
+===========================
+ AKTUALIZACJA Z WERSJI 2.5
+===========================
+
+* nadpisz wszystkie pliki w katalogu ./class (oraz podkatalogach),
+  za wyjątkiem ./class/config.php
+* zastąp plik ./data/lotto/pobierz.php
+* zastąp plik ./data/tv/wp_parse.php
+
 ===========================
  AKTUALIZACJA Z WERSJI 2.4
 ===========================
diff --git a/class/BotImage.php b/class/BotImage.php
index c02bcf0..e482302 100644
--- a/class/BotImage.php
+++ b/class/BotImage.php
@@ -1,7 +1,24 @@
 <?php
+/**
+ * Interfejs do obsługi obrazków przychodzących
+ */
 abstract class BotImage {
+	/**
+	 * Zmienna przechowująca zasób biblioteki GD2 z obrazkiem
+	 * @var resource $data
+	 */
 	protected $data = NULL;
+	
+	/**
+	 * Funkcja zwracająca zasób GD2 z obrazkiem
+	 * @return resource Zasób GD2
+	 */
 	abstract function getImage();
+	
+	/**
+	 * Funkcja zwracająca dane obrazka w formie ciągu bajtów.
+	 * @return string Obrazek
+	 */
 	abstract function getImageData();
 }
 ?>
\ No newline at end of file
diff --git a/class/BotImageGG.php b/class/BotImageGG.php
index 846388e..ad0ea8b 100644
--- a/class/BotImageGG.php
+++ b/class/BotImageGG.php
@@ -16,7 +16,7 @@
 	
 	function getImageData() {
 		if($this->data === NULL) {
-			$push = new BotGGAPI();
+			$push = new BotAPIGG();
 			$this->data = $push->getImage($this->hash);
 		}
 		
diff --git a/class/BotMessage.php b/class/BotMessage.php
index a958902..30416f8 100644
--- a/class/BotMessage.php
+++ b/class/BotMessage.php
@@ -2,58 +2,71 @@
 class BotMessage {
 	/**
 	 * Informacje o kliencie
-	 * @var BotUser
+	 * @var BotUser $user
 	 */
 	protected $user;
+	
 	/**
 	 * Informacje o kliencie zgodne z poprzednią wersją Bota (dot. API IMified).
 	 * Najczęściej równe {@link BotMessage::$user}
-	 * @var BotUser
+	 * @var BotUser $userAlt
 	 */
 	protected $userAlt;
 	
 	/**
 	 * Sesja przypisana do użytkownika i modułu
-	 * @var BotSession
+	 * @var BotSession $session
 	 */
 	protected $session;
 	
 	/**
 	 * Tekst otrzymany od API - bez zmian
-	 * @var string
+	 * @var string $rawText
 	 */
 	protected $rawText;
 	
 	/**
 	 * Czysty tekst, tylko znaki ASCII, małe litery, podwójne spacje zamienione na pojedyncze
-	 * @var string
+	 * @var string $text
 	 */
 	protected $text;
 	
 	/**
-	 * Tablica obrazków (zobacz klasę BotImage) przesłanych do bota przez użytkownika.
-	 * @var array
+	 * Tablica obrazków (zobacz {@link BotImage}) przesłanych do bota przez użytkownika.
+	 * @var array $images
 	 */
 	protected $images = array();
 	
 	/**
 	 * Komenda, tylko znaki ASCII, małe litery
-	 * @var string
+	 * @var string $command
 	 */
 	private $command;
 	
 	/**
 	 * Argumenty polecenia - oryginalne
-	 * @var string
+	 * @var string $args
 	 */
 	private $args;
 	
+	/**
+	 * Umożliwia dostęp tylko do odczytu do prywanych zmiennych
+	 * @param string $name Nazwa zmiennej
+	 * @return mixed Wartość zmiennej prywatnej
+	 */
 	function __get($name) {
 		return $this->$name;
 	}
 	
+	/**
+	 * Na podstawie nieprzetworzonej wiadomości ({@link BotMessage::$rawText})
+	 * metoda ustawia wszystkie pola klasy.
+	 * @param string $value Nieprzetworzona wiadomość
+	 */
 	function setText($value) {
 		$this->rawText = $value;
+		
+		$value = trim($value);
 		$this->text = funcs::utfToAscii($value);
 		$this->command = funcs::utfToAscii(trim(strtok($value, " \t\r\n")));
 		$this->args = trim(strtok(''));
diff --git a/class/BotModule.php b/class/BotModule.php
index 87df80e..482edd5 100644
--- a/class/BotModule.php
+++ b/class/BotModule.php
@@ -1,11 +1,47 @@
 <?php
 class BotModuleException extends Exception {}
 
-interface BotModule {
-}
+interface BotModule {}
 
+/**
+ * Interfejs klasy inicjującej moduł bota
+ */
 interface BotModuleInit {
+	/**
+	 * Funkcja zwracająca listę obsługiwanych komend.
+	 * Przykład:
+	 * <pre>array(
+	 *   'komenda' => array(
+	 *     array(
+	 *       'file' => 'komenda.php',
+	 *       'class' => 'bot_NAZWAMODULU_module',
+	 *       'method' => 'komenda1',
+	 *       'params' => 'parametr_do_funkcji',
+	 *     ),
+	 *     array(
+	 *       'file' => 'komenda.php',
+	 *       'class' => 'bot_NAZWAMODULU_module',
+	 *       'method' => 'komenda2',
+	 *     ),
+	 *   ),
+	 *   '*' => array(
+	 *     array(
+	 *       'file' => 'test.php',
+	 *       'class' => 'NAZWAMODULU_test',
+	 *       'method' => 'komenda_test',
+	 *     ),
+	 *   ),
+	 * )</pre>
+	 * @return array Lista obsługiwanych komend
+	 */
 	function register();
+	
+	/**
+	 * Zwraca pomoc dla polecenia lub skróconą listę poleceń
+	 * obsługiwanych przez dany moduł.
+	 * @param string|NULL $params Nazwa komendy
+	 * @return BotMsg Pomoc dla komendy
+	 */
 	function help($params = NULL);
 }
 ?>
\ No newline at end of file
diff --git a/class/BotMsg.php b/class/BotMsg.php
index 54c6afa..bf58ce9 100644
--- a/class/BotMsg.php
+++ b/class/BotMsg.php
@@ -1,11 +1,33 @@
 <?php
 class BotMsgException extends Exception {}
+
+/**
+ * Interfejs dla klas przetwarzających wiadomości wychodzące
+ * do formatu właściwego dla danej sieci.
+ */
 interface BotMsgInterface {
+	/**
+	 * Konstruktor
+	 * @param BotMsg $msg Wiadomość do przetworzenia
+	 */
 	function __construct(BotMsg $msg);
+	/**
+	 * Zwraca przetworzoną wiadomość
+	 * @return string Wiadomość po przetworzeniu
+	 */
 	function __toString();
+	
+	/**
+	 * Podaje na wyjście (np. za pomocą echo) wiadomość w formacie
+	 * odpowiednim dla danego API, uwzględniając nagłówki HTTP
+	 * i inne konieczne elementy.
+	 */
 	function sendPullResponse();
 }
 
+/**
+ * Klasa reprezentująca wiadomość wychodzącą.
+ */
 class BotMsg {
 	private $beautiful = TRUE;
 	private $parser = NULL;
@@ -14,14 +36,28 @@
 	private $raw = '';
 	
 	/**
-	 * Włącza lub wyłącza "upiększanie" konwertowanej do czystego tekstu wiadomości, np.:
-	 * <b>abc</b> zamieniane jest na *abc*
-	 * <h1>efg</h1> przechodzi w = efg =
+	 * Włącza lub wyłącza "upiększanie" konwertowanej
+	 * do czystego tekstu ({@link BotMsg::getText()}) wiadomości, np.:
+	 *
+	 * &lt;b&gt;abc&lt;/b&gt; zamieniane jest na \*abc\*
+	 *
+	 * &lt;h1&gt;efg&lt;h1&gt; przechodzi w = efg =
+	 *
 	 * Domyślnie włączone
 	 * @param bool $set Ustawienie "upiększania"
 	 */
+	function setBeautiful($set = FALSE) {
+		if($this->beautiful != $set) {
+			$this->text = $this->html = $this->parser = NULL;
+			$this->beautiful = (bool)$set;
+		}
+	}
+	
+	/**
+	 * @deprecated Zastąpiono funkcją {@link BotMsg::setBeautiful()}
+	 */
 	function beautifulText($set = FALSE) {
-		$this->beautiful = (bool)$set;
+		$this->setBeautiful($set);
 	}
 	
 	/**
@@ -204,7 +240,7 @@
 			}
 		}
 		
-		return $return;
+		return trim($return);
 	}
 	
 	private function parseHTMLDOM($dom) {
diff --git a/class/BotSession.php b/class/BotSession.php
index 36cd174..61511db 100644
--- a/class/BotSession.php
+++ b/class/BotSession.php
@@ -1,18 +1,29 @@
 <?php
 /**
- * Klasa przechowująca dane użytkownika. Całość przypomina mechanizm sesji w PHP.
+ * Klasa przechowująca dane przekazane przez użytkownika,
+ * w szczególności jego ustawienia.
  */
 class BotSession {
 	private $PDO;
 	
 	/**
 	 * Nazwa modułu, którego zmienne klasa przetwarza
-	 * @var string max. 40 znaków
+	 * @var string $class max. 40 znaków
 	 */
 	protected $class = '';
 	protected $class_empty = TRUE;
 	
+	/**
+	 * Pseudo-URL użytkownika.
+	 * @see BotUser
+	 * @var string $user URL użytkownika
+	 */
 	private $user;
+	/**
+	 * Klasa z identyfikatorem użytkownika
+	 * @var BotUser $user_struct
+	 */
+	private $user_struct;
 	
 	/**
 	 * Inicjuje klasę w zależności od użytkownika
@@ -55,10 +66,10 @@
 				$version = 1;
 			}
 			
-			if($version < 3) {
+			if($version < 4) {
 				$this->PDO->query('DELETE FROM data WHERE class IS NULL AND name=\'user_struct\'');
-				$this->PDO->query('INSERT OR REPLACE INTO data (class, name, value) VALUES (\'\', \'_version\', 3)');
-				$version = 3;
+				$this->PDO->query('INSERT OR REPLACE INTO data (class, name, value) VALUES (\'\', \'_version\', 4)');
+				$version = 4;
 			}
 			
 			return;
@@ -71,7 +82,7 @@
 			
 			$this->PDO->query(
 				'CREATE TABLE data (
-					class VARCHAR(50),
+					class VARCHAR(50) NOT NULL DEFAULT \'\',
 					name VARCHAR(40) NOT NULL,
 					value TEXT NOT NULL,
 					PRIMARY KEY (
@@ -81,6 +92,8 @@
 				)'
 			);
 			
+			$this->PDO->query('INSERT INTO data (class, name, value) VALUES (\'\', \'_version\', 4)');
+			
 			$files = glob(BOT_TOPDIR.'/db/*/'.$this->user_struct['user'].'.ggdb');
 			if(!$files) {
 				return;
@@ -89,12 +102,10 @@
 			$this->PDO->beginTransaction();
 			$st = $this->PDO->prepare('INSERT OR REPLACE INTO data (class, name, value) VALUES (?, ?, ?)');
 			
-			$st->execute(array('', '_version', 2));
-			
 			foreach($files as $file) {
 				$data = unserialize(file_get_contents($file));
 				foreach($data as $name => $value) {
-					$st->execute(array($this->class, $name, $value));
+					$st->execute(array($this->class, $name, serialize($value)));
 				}
 			}
 			
@@ -112,6 +123,19 @@
 		}
 	}
 	
+	/**
+	 * Ustawia nazwę modułu/klasy, której zmienne będą przetwarzane
+	 * @param string $class Nazwa modułu
+	 */
+	function setClass($class) {
+		$this->class = $class;
+	}
+	
+	/**
+	 * Pobiera zmienną modułu o podanej nazwie (getter).
+	 * @param string $name Nazwa zmiennej
+	 * @return mixed Wartość zmiennej lub NULL
+	 */
 	function __get($name) {
 		$this->init();
 		
@@ -128,6 +152,11 @@
 		}
 	}
 	
+	/**
+	 * Ustawia zmienną o podanej nazwie
+	 * @param string $name Nazwa zmiennej
+	 * @param mixed $value Wartość zmiennej
+	 */
 	function __set($name, $value) {
 		$this->init();
 		
@@ -135,6 +164,11 @@
 		$st->execute(array($this->class, $name, serialize($value)));
 	}
 	
+	/**
+	 * Sprawdza czy podana zmienna została ustawiona.
+	 * @param string $name Nazwa zmiennej
+	 * @return bool Czy zmienna istnieje?
+	 */
 	function __isset($name) {
 		$this->init();
 		
@@ -145,6 +179,10 @@
 		return ($st[0]>0);
 	}
 	
+	/**
+	 * Usuwa zmienną o podanej nazwie
+	 * @param string $name Nazwa zmiennej
+	 */
 	function __unset($name) {
 		$this->init();
 		
@@ -152,6 +190,10 @@
 		$st->execute(array($this->class, $name));
 	}
 	
+	/**
+	 * Zapamiętuje tablicę zmiennych danego modułu
+	 * @param array $array Tablica zmiennych
+	 */
 	function push($array) {
 		$this->PDO->beginTransaction();
 		foreach($array as $name => $value) {
@@ -160,6 +202,10 @@
 		$this->PDO->commit();
 	}
 	
+	/**
+	 * Zwraca wszystkie ustawione zmienne danego modułu
+	 * @return array Lista wszystkich zmiennych
+	 */
 	function pull() {
 		$this->init();
 		
@@ -169,16 +215,15 @@
 		
 		$return = array();
 		foreach($st as $row) {
-			$return[$row['name']] = $row['value'];
+			$return[$row['name']] = unserialize($row['value']);
 		}
 		
 		return $return;
 	}
 	
-	function setClass($class) {
-		$this->class = $class;
-	}
-	
+	/**
+	 * Usuwa wszystkie zmienne sesyjne danego modułu.
+	 */
 	function truncate() {
 		$this->init();
 		
diff --git a/class/BotUser.php b/class/BotUser.php
index c2b209a..2fe8251 100644
--- a/class/BotUser.php
+++ b/class/BotUser.php
@@ -9,13 +9,13 @@
 	 * - IMified
 	 * - HTTP
 	 * - Local
-	 * @var string
+	 * @var string $interface
 	 */
 	private $interface;
 	
 	/**
 	 * Numer lub identyfikator użytkownika
-	 * @var string
+	 * @var string $uid
 	 */
 	private $uid;
 	
@@ -29,22 +29,30 @@
 	 * - yahoo.imified.com
 	 * - gtalk.imified.com
 	 * - localhost
-	 * @var string
+	 * @var string $network
 	 */
 	private $network;
 	
 	/**
 	 * Identyfikator/unikalna nazwa bota, do którego skierowano zapytanie.
 	 * Najczęściej numer Gadu-Gadu lub botkey w przypadku IMified.com
+	 * @var string $bot
 	 */
 	private $bot;
 	
 	/**
 	 * Parametry zapytania. Przy IMified równe zmiennej $_POST['channel']
-	 * @var string
+	 * @var string $params
 	 */
 	private $params;
 	
+	/**
+	 * Konstruktor. W argumencie otrzymuje pseudo-URL określający użytkownika i sieć.
+	 * Przykłady:
+	 * - Gadu-Gadu://123456\@gadu-gadu.pl
+	 * - IMified://user\\\@jabber\@jabber.imified.com/BOTKEY?private
+	 * @param string $user URL użytkownika
+	 */
 	function __construct($user) {
 		$data = parse_url($user);
 		
@@ -55,6 +63,11 @@
 		$this->params = @$data['query'];
 	}
 	
+	/**
+	 * Umożliwia dostęp tylko do odczytu do prywanych zmiennych
+	 * @param string $name Nazwa zmiennej
+	 * @return mixed Wartość zmiennej prywatnej
+	 */
 	function __get($name) {
 		return $this->$name;
 	}
diff --git a/class/legacy/calendar.php b/class/legacy/calendar.php
index ca28961..8949144 100644
--- a/class/legacy/calendar.php
+++ b/class/legacy/calendar.php
@@ -1,12 +1,14 @@
 <?php
 /**
+ * Klasa obsługująca polskie wyrażenia określające daty
  * @todo Potrzebna jest funkcja, które będzie wyciągać datę z początku lub końca danego ciągu. Patrz: {@link tv::parse_date()}
  */
 class calendar {
 	/**
+	 * Na podstawie podanej daty zwraca uniksowy znacznik czasu
 	 * @param string $date Data w formacie "naturalnym". Np. jutro, 1 stycznia, piątek
-	 * @return int Uniksowy znacznik czasu. Do użycia w funkcji date()
-	 * @uses funcs::utfToAscii()
+	 * @return int Uniksowy znacznik czasu - liczba sekund od północy 1 stycznia 1970
+	 * @see http://www.php.net/date
 	 */
 	static function parse_date($date) {
 		$date = funcs::utfToAscii($date);
diff --git a/class/legacy/funcs.php b/class/legacy/funcs.php
index 492e1e4..fe28ad3 100644
--- a/class/legacy/funcs.php
+++ b/class/legacy/funcs.php
@@ -2,13 +2,24 @@
 class BotLegacyEnd extends Exception {}
 
 class funcs {
+	/**
+	 * Przerywa dalsze wykonywanie modułu i wysyła odpowiedź do klienta
+	 * @deprecated Przestarzałe wraz z wprowadzeniem nowego API.
+	 *  Metoda może zostać usunięta bez ostrzeżenia!
+	 */
 	static function end() {
 		throw new BotLegacyEnd();
 	}
 	
+	/**
+	 * Funkcja usuwa "ogonki" (transliteracja), podwójne spacje i odstępy
+	 * z podanego w parametrze ciągu znaków oraz zamienia wszystkie litery na małe
+	 * @param string $utf Ciąg znaków w UTF-8
+	 * @returns string Ciąg po przetworzeniu
+	 */
 	static function utfToAscii($utf) {
 		$utf = trim(str_replace('  ', ' ', $utf));
-		return strtolower(iconv('utf-8', 'ascii//TRANSLIT', trim($utf)));
+		return strtolower(iconv('utf-8', 'ascii//TRANSLIT', $utf));
 	}
 }
 ?>
\ No newline at end of file
diff --git a/class/legacy/jsarray.php b/class/legacy/jsarray.php
index a3b952d..9961de6 100644
--- a/class/legacy/jsarray.php
+++ b/class/legacy/jsarray.php
@@ -11,8 +11,11 @@
 				// Ignore  < ? php  and  ? >  added above
 				if($token[0] == T_OPEN_TAG OR $token[0] == T_CLOSE_TAG) continue;
 				// String/int element within an array
-				if($token[0] == T_CONSTANT_ENCAPSED_STRING || $token[0] == T_LNUMBER) {
+				if($token[0] == T_CONSTANT_ENCAPSED_STRING) {
 					$element = substr($token[1], 1, -1);
+				}
+				if($token[0] == T_LNUMBER) {
+					$element = $token[1];
 				}
 			}
 			// Nested array
@@ -21,7 +24,7 @@
 			}
 			// End of nested array
 			elseif($token == ']') {
-				// Put elements into the lastest array
+				// Put elements into the latest array
 				if($element !== NULL && $element !== FALSE) {
 					end($stack);
 					$stack[key($stack)][] = $element;
@@ -38,7 +41,7 @@
 			}
 			// Elements separator
 			elseif($token == ',') {
-				// Put elements into the lastest array (]] check)
+				// Put elements into the latest array (]] check)
 				if($element !== FALSE) {
 					end($stack);
 					$stack[key($stack)][] = $element;
@@ -47,11 +50,15 @@
 			}
 			else
 			{
-				return array();
+				return FALSE;
 			}
 		}
 		
-		return $stack[0][0];
+		if(isset($stack[0][0])) {
+			return $stack[0][0];
+		} else {
+			return NULL;
+		}
 	}
 }
 ?>
\ No newline at end of file
diff --git a/class/legacy/main.php b/class/legacy/main.php
index 6949a5d..fe6137d 100644
--- a/class/legacy/main.php
+++ b/class/legacy/main.php
@@ -1,6 +1,12 @@
 <?php
 class main {
-	const VERSION = '2.5';
-	const VERSION_NUM = '2.5';
+	/**
+	 * Wersja bota w formacie: <i>X.Y TYPE</i>, np. <i>2.0 Beta</i>
+	 */
+	const VERSION = '2.6';
+	/**
+	 * Wersja bota, tylko część numeryczna (X.Y), np. <i>2.0</i>
+	 */
+	const VERSION_NUM = '2.6';
 }
 ?>
diff --git a/class/legacy/module.php b/class/legacy/module.php
index d089256..f1b91df 100644
--- a/class/legacy/module.php
+++ b/class/legacy/module.php
@@ -1,18 +1,19 @@
 <?php
 interface module {
 	static function register_cmd();
-	// Returns:
+	// Zwraca:
 	// array(
-	//   'CMD1_NAME' => 'FUNCTION_INSIDE_CLASS',
-	//   'CMD2_NAME' => 'FUNCTION_INSIDE_CLASS',
+	//   'KOMENDA1' => 'METODA_OBSLUGUJACA_KOMENDE1',
+	//   'KOMENDA2' => 'METODA_OBSLUGUJACA_KOMENDE2',
 	//   ...
 	// )
 	
 	static function help($cmd=NULL);
-	// Return help content about command $cmd to GGapi::put*() functions
-	//    if $cmd is NULL return help content for all commands
+	// Zwraca pomoc dotyczącą komendy z użyciem funkcji GGapi::put*()
+	// Jeśli $cmd === NULL, zwraca skróconą listę poleceń modułu
 	
-	// static function FUNCTION_INSIDE_CLASS(CMD_NAME, REST_OF_PLAINTEXT)
-	//    REST_OF_PLAINTEXT is raw (non trimmed etc.) part after command name, without leading space
+	// static function METODA_OBSLUGUJACA_KOMENDE(NAZWA_KOMENDY, ARGUMENTY)
+	//    ARGUMENTY to wszystko poza nazwą komendy, przekazane w taki sposób,
+	//    w jaki zostały otrzymane od użytkownika
 }
 ?>
\ No newline at end of file
diff --git a/class/std.php b/class/std.php
index c173cd5..1f5c246 100644
--- a/class/std.php
+++ b/class/std.php
@@ -30,11 +30,13 @@
 	throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
 }
 
-error_reporting(E_COMPILE_ERROR|E_PARSE);
+if(!defined('PHPUNIT')) {
+	error_reporting(E_COMPILE_ERROR|E_PARSE);
+	set_error_handler('errorToException', E_ALL & ~E_NOTICE);
+}
 
 setlocale(LC_CTYPE, 'pl_PL.utf8', 'pl_PL', 'polish', 'plk');
 mb_internal_encoding('UTF-8');
 libxml_use_internal_errors();
 spl_autoload_register('botAutoload');
-set_error_handler('errorToException', E_ALL & ~E_NOTICE);
 ?>
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..243c123
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,10 @@
+<phpunit bootstrap="tests/autoload.php">
+  <php>
+    <const name="PHPUNIT" value="true" />
+  </php>
+  <testsuites>
+    <testsuite name="Core Test Suite">
+      <directory suffix="Test.php">tests/Core</directory>
+    </testsuite>
+  </testsuites>
+</phpunit>
diff --git a/tests/Core/BotMessageTest.php b/tests/Core/BotMessageTest.php
new file mode 100644
index 0000000..93195c7
--- /dev/null
+++ b/tests/Core/BotMessageTest.php
@@ -0,0 +1,13 @@
+<?php
+class BotMessageTest extends PHPUnit_Framework_TestCase {
+	function testAppend() {
+		$input = '   ąęß  śćżń  óó ';
+		$message = new BotMessage();
+		$message->setText($input);
+		
+		$this->assertEquals($input, $message->rawText);
+		$this->assertEquals('aess sczn oo', $message->text);
+		$this->assertEquals('aess', $message->command);
+		$this->assertEquals('śćżń  óó', $message->args);
+	}
+}
diff --git a/tests/Core/BotMsgTest.php b/tests/Core/BotMsgTest.php
new file mode 100644
index 0000000..36f4fe5
--- /dev/null
+++ b/tests/Core/BotMsgTest.php
@@ -0,0 +1,99 @@
+<?php
+class BotMsgTest extends PHPUnit_Framework_TestCase {
+	function testAppend() {
+		$text = '';
+
+		$substring = 'abc';
+		$msg = new BotMsg($substring);
+		$text .= $substring;
+		
+		$substring = 'cba';
+		$msg->a($substring);
+		$text .= $substring;
+		
+		$substring = 'cba';
+		$msg->append($substring);
+		$text .= $substring;
+
+		$this->assertEquals($text, $msg->getRaw());
+	}
+	
+	function testBeautifilText() {
+		$msg = new BotMsg('<h1>Test</h1><p><u><i>This.</i></u></p><p><b>That!</b></p>');
+		$expect = '= Test ='."\n"
+			.'_/This./_'."\n\n"
+			.'*That!*';
+		$msg->setBeautiful(TRUE);
+		$this->assertEquals($expect, $msg->getText());
+		
+		$expect = 'Test'."\n"
+			.'This.'."\n\n"
+			.'That!';
+		$msg->setBeautiful(FALSE);
+		$this->assertEquals($expect, $msg->getText());
+		
+	}
+	
+	function testGetText() {
+		$msg = new BotMsg('<h2>Test</h2>'."\n"
+			.'<h3>Test h3</h3>'."\n"
+			.'<p><a href="http://jacekk.info">http://jacekk.info</a><br />'."\n"
+			.'<a href="http://jacekk.info">Jacekk.info</a></p>');
+		$expect = '== Test =='."\n"
+			.'=== Test h3 ==='."\n"
+			.'http://jacekk.info'."\n"
+			.'Jacekk.info (http://jacekk.info)';
+		$this->assertEquals($expect, $msg->getText());
+		
+		$msg = new BotMsg('<table>'."\n"
+			.'<tr><th>Header 1</th> <th>Header 2</th></tr>'."\n"
+			.'<tr><td>Cell 1</td> <td>Cell 2<img src="" /></td></tr>'."\n"
+			.'</table>');
+		$expect = '*Header 1*	 *Header 2*'."\n"
+			.'Cell 1	 Cell 2';
+		$this->assertEquals($expect, $msg->getText());
+		
+		$msg = new BotMsg('<h3>Test h3</h3>abc<p>Test</p>');
+		$expect = '=== Test h3 ==='."\n"
+			.'abc'."\n\n"
+			.'Test';
+		$this->assertEquals($expect, $msg->getText());
+	}
+	
+	function testGetHTML() {
+		$msg = new BotMsg('<h1>Test</h1>'."\n"
+			.'<p><u><i>This.</i></u></p>'."\n"
+			.'<p><b color="#fff">That!</b></p>'."\n"
+			.'<p><a>http://jacekk.info</a></p>');
+		$expect = '<h1>Test</h1>'."\n"
+			.'<p><u><i>This.</i></u></p>'."\n"
+			.'<p><b style="color:#fff;">That!</b></p>'."\n"
+			.'<p><a href="http://jacekk.info">http://jacekk.info</a></p>';
+		
+		$this->assertEquals($expect, $msg->getHTML());
+		$this->assertEquals($expect, (string)$msg);
+	}
+	
+	function testHTMLError() {
+		$oldhandler = set_error_handler('errorToException');
+		
+		$msg = new BotMsg('<![CDATA[ <p></p> ]]>');
+		$msg->getHTML();
+		
+		set_error_handler($oldhandler);
+	}
+	
+	function testSleep() {
+		$msg = new BotMsg('<h1>Test</h1><p><u><i>This.</i></u></p><p><b>That!</b></p>');
+		$raw = $msg->getRaw();
+		$text = $msg->getText();
+		$html = $msg->getHTML();
+		
+		$serialized = serialize($msg);
+		$msg = unserialize($serialized);
+		
+		$this->assertEquals($raw, $msg->getRaw());
+		$this->assertEquals($text, $msg->getText());
+		$this->assertEquals($html, $msg->getHTML());
+	}
+}
diff --git a/tests/Core/BotSessionTest.php b/tests/Core/BotSessionTest.php
new file mode 100644
index 0000000..1b2209f
--- /dev/null
+++ b/tests/Core/BotSessionTest.php
@@ -0,0 +1,136 @@
+<?php
+class BotSessionTest extends PHPUnit_Framework_TestCase {
+	function testSessionFolder() {
+		$dbFolder = dirname(__FILE__).'/../../database';
+		
+		$this->assertTrue(is_writable($dbFolder));
+		$this->assertTrue(count(glob($dbFolder.'/*.sqlite')) == 0);
+	}
+	
+	/**
+	 * @depends testSessionFolder
+	 */
+	function testPullEmpty() {
+		$dbFolder = dirname(__FILE__).'/../../database';
+		
+		$session = new BotSession('test://user1@test');
+		$session->setClass('test');
+		
+		$this->assertEquals(array(), $session->pull());
+		$this->assertTrue(count(glob($dbFolder.'/*.sqlite')) == 1);
+	}
+	
+	/**
+	 * @depends testPullEmpty
+	 * @expectedException Exception
+	 */
+	function testSetClass() {
+		$session = new BotSession('test://user1');
+		$session->pull();
+	}
+	
+	/**
+	 * @depends testPullEmpty
+	 */
+	function testLegacyImport() {
+		$dbFolder = dirname(__FILE__).'/../../database';
+		$oldDbFolder = $dbFolder = dirname(__FILE__).'/../../db';
+		
+		$data = array('test' => true, 'other' => 'yes, sir!');
+		$data_serialized = serialize($data);
+		
+		$this->assertTrue(mkdir($oldDbFolder));
+		$this->assertTrue(is_writable($oldDbFolder));
+		$this->assertTrue(mkdir($oldDbFolder.'/test'));
+		
+		$filename = $oldDbFolder.'/test/testUser.ggdb';
+		$this->assertEquals(strlen($data_serialized), file_put_contents($filename, $data_serialized));
+		$this->assertEquals($data_serialized, file_get_contents($filename));
+		
+		$session = new BotSession('test://testUser@test');
+		$session->setClass('test');
+		
+		$this->assertTrue(isset($session->test));
+		$this->assertEquals($data, $session->pull());
+		
+		$this->assertFalse(file_exists($filename));
+		$this->assertTrue(rmdir($oldDbFolder.'/test'));
+		$this->assertTrue(rmdir($oldDbFolder));
+	}
+	
+	/**
+	 * @depends testPullEmpty
+	 */
+	function testManualExample() {
+		$session = new BotSession('test://user1@test');
+		$session->setClass('test');
+		
+		// Ustawienie pojedynczej wartości
+		$session->zmienna = 'To jest test';
+		$this->assertTrue(isset($session->zmienna));
+		$this->assertEquals('To jest test', $session->zmienna);
+		
+		// Usunięcie pojedynczej wartości
+		unset($session->zmienna);
+		$this->assertFalse(isset($session->zmienna));
+		$this->assertEquals(NULL, $session->zmienna);
+		
+		// Ustawienie pojedynczej wartości ponownie
+		$session->zmienna = 'To jest test';
+		$this->assertTrue(isset($session->zmienna));
+		$this->assertEquals('To jest test', $session->zmienna);
+		
+		// Usunięcie wszystkich danych
+		$session->truncate();
+		$this->assertFalse(isset($session->zmienna));
+		$this->assertEquals(NULL, $session->zmienna);
+		$this->assertEquals(array(), $session->pull());
+
+		// Dopisanie (nadpisanie) danych
+		$array = array(
+			'zmienna' => 'To jest test2',
+			'zmienna2' => new DateTime('2012-01-10')
+		);
+		$session->push($array);
+
+		$this->assertEquals('To jest test2', $session->zmienna);
+		$this->assertEquals($array, $session->pull());
+		
+		// push() nie usuwa istniejących danych
+		$session->zmienna3 = '333';
+		$session->push($array);
+		$this->assertNotEquals($array, $session->pull());
+		
+		unset($this->session);
+	}
+	
+	/**
+	 * @depends testManualExample
+	 */
+	function testManualExample2() {
+		$session = new BotSession('test://user1@test');
+		$session->setClass('test');
+		
+		$array = array(
+			'zmienna' => 'To jest test2',
+			'zmienna2' => new DateTime('2012-01-10'),
+			'zmienna3' => '333'
+		);
+		
+		$this->assertEquals($array, $session->pull());
+		
+		
+		$session->setClass('test2');
+		$this->assertEquals(array(), $session->pull());
+	}
+	
+	/**
+	 * @depends testManualExample2
+	 */
+	function testCleanup() {
+		$dbFolder = dirname(__FILE__).'/../../database';
+		foreach(glob($dbFolder.'/*.sqlite') as $file) {
+			unlink($file);
+		}
+	}
+}
diff --git a/tests/Core/Legacy/JSArrayTest.php b/tests/Core/Legacy/JSArrayTest.php
new file mode 100644
index 0000000..f957afe
--- /dev/null
+++ b/tests/Core/Legacy/JSArrayTest.php
@@ -0,0 +1,29 @@
+<?php
+class JSArrayTest extends PHPUnit_Framework_TestCase {
+	public function testEmptyString() {
+		$result = jsarray::parse('');
+		$this->assertSame(NULL, $result);
+	}
+	
+	public function testEmptyArray() {
+		$result = jsarray::parse('[]');
+		$this->assertEquals(array(), $result);
+	}
+	
+	public function testNestedArrays() { 
+		$array = array(
+			array(1, 2, array(), 5, array(6, array(7, 8))),
+			array(9),
+			'10'
+		);
+		$array_js = json_encode($array);
+		$array_decoded = jsarray::parse($array_js);
+		
+		$this->assertEquals($array, $array_decoded);
+	}
+	
+	public function testInvalid() {
+		$result = jsarray::parse('()');
+		$this->assertSame(FALSE, $result);
+	}
+}
diff --git a/tests/autoload.php b/tests/autoload.php
new file mode 100644
index 0000000..dfeb740
--- /dev/null
+++ b/tests/autoload.php
@@ -0,0 +1,2 @@
+<?php
+require_once(dirname(__FILE__).'/../class/std.php');

--
Gitblit v1.9.1