From b65cbc9d866055404c3428f7bd8c47adcd490c5e Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Fri, 23 Nov 2012 11:30:19 +0400
Subject: [PATCH 01/35] allowing business objects set null values for objects
 properties if they not required

---
 doc/ChangeLog                   |  9 +++++++--
 meta/types/ObjectType.class.php | 11 ++++++-----
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 893da219ef..02dd26326a 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,9 +1,14 @@
-2012-24-10  Alexey S. Denisov
+2012-11-18  Nikita V. Konstantinov
+	* meta/types/ObjectType.class.php:
+		update for Business objects - now you can setSomeProperty(null)
+		for Objects properties if it's not required
+
+2012-10-24  Alexey S. Denisov
 	* main/Flow/CarefulDatabaseRunner.class.php
 		main/UnifiedContainer/UnifiedContainer.class.php:
 			CarefulDatabaseRunner and UnifiedContainer will use InnerTransaction
 
-2012-24-10  Alexey S. Denisov
+2012-10-24  Alexey S. Denisov
 	* global.inc.php.tpl
 		main/Autoloader/Autoloader.class.php
 		main/Autoloader/AutoloaderClassNotFound.class.php
diff --git a/meta/types/ObjectType.class.php b/meta/types/ObjectType.class.php
index fa90a9b6ec..b0661f00f3 100644
--- a/meta/types/ObjectType.class.php
+++ b/meta/types/ObjectType.class.php
@@ -204,7 +204,6 @@ public function toSetter(
 			
 			$name = $property->getName();
 			$methodName = 'set'.ucfirst($name);
-			$classHint = $this->getHint();
 			
 			if ($holder) {
 				return <<<EOT
@@ -221,16 +220,18 @@ public function {$methodName}({$property->getType()->getClassName()} \${$name})
 
 EOT;
 			} else {
+				$defaultValue = $property->isOptional() ? ' = null' : '';
+
 				if ($property->getFetchStrategyId() == FetchStrategy::LAZY) {
 					$method = <<<EOT
 
 /**
  * @return {$property->getClass()->getName()}
 **/
-public function {$methodName}({$this->className} \${$name})
+public function {$methodName}({$this->className} \${$name}{$defaultValue})
 {
 	\$this->{$name} = \${$name};
-	\$this->{$name}Id = \${$name}->getId();
+	\$this->{$name}Id = \${$name} ? \${$name}->getId() : null;
 
 	return \$this;
 }
@@ -238,7 +239,7 @@ public function {$methodName}({$this->className} \${$name})
 /**
  * @return {$property->getClass()->getName()}
 **/
-public function {$methodName}Id(\$id)
+public function {$methodName}Id(\$id{$defaultValue})
 {
 	\$this->{$name} = null;
 	\$this->{$name}Id = \$id;
@@ -253,7 +254,7 @@ public function {$methodName}Id(\$id)
 /**
  * @return {$property->getClass()->getName()}
 **/
-public function {$methodName}({$this->className} \${$name})
+public function {$methodName}({$this->className} \${$name}{$defaultValue})
 {
 	\$this->{$name} = \${$name};
 

From 12241e14df177f5aa5030eb7b60fc27145767ac6 Mon Sep 17 00:00:00 2001
From: "Igor V. Gulyaev" <igulyaev@gmail.com>
Date: Mon, 17 Dec 2012 12:55:56 +0400
Subject: [PATCH 02/35] * replace  deprecated key_exists by array_key_exists.
 cosmetic

---
 core/Form/Primitives/PrimitiveNoValue.class.php | 2 +-
 main/Net/Http/HeaderUtils.class.php             | 8 +++-----
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/core/Form/Primitives/PrimitiveNoValue.class.php b/core/Form/Primitives/PrimitiveNoValue.class.php
index ffbbf528de..186ded9ccb 100644
--- a/core/Form/Primitives/PrimitiveNoValue.class.php
+++ b/core/Form/Primitives/PrimitiveNoValue.class.php
@@ -48,7 +48,7 @@ public function importValue($value)
 		public function import($scope)
 		{
 			if (
-				key_exists($this->name, $scope)
+				array_key_exists($this->name, $scope)
 				&& $scope[$this->name] == null
 			)
 				return $this->imported = true;
diff --git a/main/Net/Http/HeaderUtils.class.php b/main/Net/Http/HeaderUtils.class.php
index b6042a9ff7..07ec0bac6e 100644
--- a/main/Net/Http/HeaderUtils.class.php
+++ b/main/Net/Http/HeaderUtils.class.php
@@ -122,11 +122,9 @@ public static function sendNotCachedHeader()
 		public static function sendContentLength($length)
 		{
 			Assert::isInteger($length);
-			
-			header(
-				"Content-Length: {$length}"
-			);
-			
+
+			header("Content-Length: {$length}");
+
 			self::$headerSent = true;
 		}
 		

From 697c16cf0148a41838b5e999e250039796b7bc3e Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Sun, 25 Nov 2012 13:44:42 +0400
Subject: [PATCH 03/35] PrimitiveIdentifier now can export/import objects by
 custom methods

---
 .../IdentifiablePrimitive.class.php           | 41 +++++++++++-
 .../Primitives/PrimitiveIdentifier.class.php  | 24 ++++---
 doc/ChangeLog                                 |  7 +++
 test/core/PrimitiveIdentifierTest.class.php   | 63 ++++++++++++++++++-
 4 files changed, 123 insertions(+), 12 deletions(-)

diff --git a/core/Form/Primitives/IdentifiablePrimitive.class.php b/core/Form/Primitives/IdentifiablePrimitive.class.php
index 8015fbd3d1..66a39cd876 100644
--- a/core/Form/Primitives/IdentifiablePrimitive.class.php
+++ b/core/Form/Primitives/IdentifiablePrimitive.class.php
@@ -16,6 +16,7 @@ abstract class IdentifiablePrimitive
 		extends PrimitiveInteger // parent class doesn't really matter here
 	{
 		protected $className = null;
+		private $extractMethod = 'getId';
 		
 		/**
 		 * due to historical reasons, by default we're dealing only with
@@ -25,6 +26,29 @@ abstract class IdentifiablePrimitive
 		
 		abstract public function of($className);
 		
+		/**
+		 * @param mixed $extractMethod
+		 * @return IdentifiablePrimitive
+		 */
+		public function setExtractMethod($extractMethod)
+		{
+			if (is_callable($extractMethod)) {
+				/* all ok, call what you want */
+			} elseif (strpos($extractMethod, '::') === false) {
+				Assert::isTrue(
+					method_exists($this->className, $extractMethod),
+					"knows nothing about '".$this->className
+					."::{$extractMethod}' method"
+				);
+			} else {
+				ClassUtils::checkStaticMethod($extractMethod);
+			}
+			
+			$this->extractMethod = $extractMethod;
+			
+			return $this;
+		}
+		
 		/**
 		 * @return string
 		**/
@@ -77,7 +101,7 @@ public function exportValue()
 			if (!$this->value)
 				return null;
 			
-			return $this->value->getId();
+			return $this->actualExportValue($this->value);
 		}
 		
 		/* void */ protected function checkNumber($number)
@@ -95,5 +119,20 @@ protected function castNumber($number)
 			
 			return $number;
 		}
+		
+		protected function actualExportValue($value)
+		{
+			if (!ClassUtils::isInstanceOf($value, $this->className)) {
+				return null;
+			}
+			
+			if (is_callable($this->extractMethod)) {
+				return call_user_func($this->extractMethod, $value);
+			} elseif (strpos($this->extractMethod, '::') === false) {
+				return $value->{$this->extractMethod}($value);
+			} else {
+				ClassUtils::callStaticMethod($this->extractMethod, $value);
+			}
+		}
 	}
 ?>
\ No newline at end of file
diff --git a/core/Form/Primitives/PrimitiveIdentifier.class.php b/core/Form/Primitives/PrimitiveIdentifier.class.php
index 3aa8be9f62..1459dce99a 100644
--- a/core/Form/Primitives/PrimitiveIdentifier.class.php
+++ b/core/Form/Primitives/PrimitiveIdentifier.class.php
@@ -55,7 +55,9 @@ public function dao()
 		**/
 		public function setMethodName($methodName)
 		{
-			if (strpos($methodName, '::') === false) {
+			if (is_callable($methodName)) {
+				/* all ok, call what you want */
+			} elseif (strpos($methodName, '::') === false) {
 				$dao = $this->dao();
 				
 				Assert::isTrue(
@@ -63,8 +65,9 @@ public function setMethodName($methodName)
 					"knows nothing about '".get_class($dao)
 					."::{$methodName}' method"
 				);
-			} else
+			} else {
 				ClassUtils::checkStaticMethod($methodName);
+			}
 			
 			$this->methodName = $methodName;
 			
@@ -79,7 +82,7 @@ public function importValue($value)
 					
 					return
 						$this->import(
-							array($this->getName() => $value->getId())
+							array($this->getName() => $this->actualExportValue($value))
 						);
 				
 				} catch (WrongArgumentException $e) {
@@ -105,7 +108,7 @@ public function import($scope)
 			) {
 				$value = $scope[$this->name];
 				
-				$this->raw = $value->getId();
+				$this->raw = $this->actualExportValue($value);
 				$this->setValue($value);
 				
 				return $this->imported = true;
@@ -139,12 +142,13 @@ public function import($scope)
 		
 		protected function actualImportValue($value)
 		{
-			return
-				(strpos($this->methodName, '::') === false)
-					? $this->dao()->{$this->methodName}($value)
-					: ClassUtils::callStaticMethod(
-						$this->methodName, $value
-					);
+			if (is_callable($this->methodName)) {
+				return call_user_func($this->methodName, $value);
+			} elseif (strpos($this->methodName, '::') === false) {
+				return $this->dao()->{$this->methodName}($value);
+			} else {
+				return ClassUtils::callStaticMethod($this->methodName, $value);
+			}
 		}
 	}
 ?>
\ No newline at end of file
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 02dd26326a..30baffc73d 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,4 +1,11 @@
+2012-11-25  Nikita V. Konstantinov
+
+	* core/Form/Primitives/PrimitiveIdentifier.class.php
+		core/Form/Primitives/PrimitiveIdentifier.class.php:
+			PrimitiveIdentifier now can export/import objects by custom methods
+
 2012-11-18  Nikita V. Konstantinov
+
 	* meta/types/ObjectType.class.php:
 		update for Business objects - now you can setSomeProperty(null)
 		for Objects properties if it's not required
diff --git a/test/core/PrimitiveIdentifierTest.class.php b/test/core/PrimitiveIdentifierTest.class.php
index 22aa16eddf..6f6c000f1a 100644
--- a/test/core/PrimitiveIdentifierTest.class.php
+++ b/test/core/PrimitiveIdentifierTest.class.php
@@ -1,7 +1,7 @@
 <?php
 	/* $Id$ */
 	
-	final class PrimitiveIdentifierTest extends TestCase
+	final class PrimitiveIdentifierTest extends TestCaseDAO
 	{
 		public function testEmpty()
 		{
@@ -20,5 +20,66 @@ public function testEmpty()
 				$this->assertFalse($prm->importValue($value));
 			}
 		}
+		
+		/**
+		 * @group pi
+		 */
+		public function testCustomImportExport()
+		{
+			$dbs = DBTestPool::me()->getPool();
+			if (empty($dbs)) {
+				$this->fail('For test required at least one DB in config');
+			}
+			DBPool::me()->setDefault(reset($dbs));
+			
+			$moscow = TestCity::create()->setCapital(true)->setName('Moscow');
+			$moscow->dao()->add($moscow);
+
+			$stalingrad = TestCity::create()->setCapital(false)->setName('Stalingrad');
+			$stalingrad->dao()->add($stalingrad);
+
+			$prms = array();
+			$prms[] = Primitive::identifier('city')->
+				setScalar(true)->
+				of('TestCity')->
+				setMethodName('PrimitiveIdentifierTest::getCityByName')->
+				setExtractMethod('PrimitiveIdentifierTest::getCityName');
+			
+			$prms[] = Primitive::identifier('city')->
+				setScalar(true)->
+				of('TestCity')->
+				setMethodName(array(get_class($this), 'getCityByName'))->
+				setExtractMethod(function(TestCity $city) {return $city->getName();});
+			
+			foreach ($prms as $prm) {
+				$prm->import(array('city' => 'Moscow'));
+				$this->assertEquals($moscow, $prm->getValue());
+				$this->assertEquals('Moscow', $prm->exportValue());
+
+				$prm->importValue($stalingrad);
+				$this->assertequals($stalingrad, $prm->getValue());
+				$this->assertequals('Stalingrad', $prm->exportValue());
+
+				$prm->import(array('city' => $moscow));
+				$this->assertEquals($moscow, $prm->getValue());
+				$this->assertEquals('Moscow', $prm->exportValue());
+			}
+		}
+		
+		/**
+		 * @param string $name
+		 * @return TestCity
+		 */
+		public static function getCityByName($name)
+		{
+			return Criteria::create(TestCity::dao())->
+				add(Expression::eq('name', DBValue::create($name)))->
+				get();
+		}
+		
+		public static function getCityName(TestCity $city)
+		{
+			return $city->getName();
+		}
 	}
 ?>
\ No newline at end of file

From 04080c3cd501c94d6d6ef2ed4c6de6d60e49917b Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Sun, 25 Nov 2012 13:51:51 +0400
Subject: [PATCH 04/35] fix author name in doc/Changelog at last line

---
 doc/ChangeLog | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 30baffc73d..8ffc3f8978 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,4 +1,4 @@
-2012-11-25  Nikita V. Konstantinov
+2012-11-25  Alexey S. Denisov
 
 	* core/Form/Primitives/PrimitiveIdentifier.class.php
 		core/Form/Primitives/PrimitiveIdentifier.class.php:

From 1d58ed147e2c4eb5982e79eaa3a43f1547cc1399 Mon Sep 17 00:00:00 2001
From: "Evgeniy V. Kokovikhin" <dovg@dovg.ru>
Date: Tue, 4 Dec 2012 13:52:05 +0400
Subject: [PATCH 05/35] + getLink moved from constant to class property

---
 main/DAOs/GenericDAO.class.php               |  4 +++-
 meta/builders/AutoDaoBuilder.class.php       |  2 +-
 meta/builders/BaseBuilder.class.php          | 19 ++++++++-----------
 meta/builders/DictionaryDaoBuilder.class.php |  1 +
 test/misc/TestCaseDB.class.php               |  1 +
 5 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/main/DAOs/GenericDAO.class.php b/main/DAOs/GenericDAO.class.php
index 569e7718c1..dc8c8c5a83 100644
--- a/main/DAOs/GenericDAO.class.php
+++ b/main/DAOs/GenericDAO.class.php
@@ -18,6 +18,8 @@ abstract class GenericDAO extends Singleton implements BaseDAO
 	{
 		private $identityMap	= array();
 		
+		protected $linkName		= null;
+		
 		abstract public function getTable();
 		abstract public function getObjectName();
 		
@@ -71,7 +73,7 @@ public function completeObject(Identifiable $object)
 		**/
 		public function getLinkName()
 		{
-			return null;
+			return $this->linkName;
 		}
 		
 		public function getIdName()
diff --git a/meta/builders/AutoDaoBuilder.class.php b/meta/builders/AutoDaoBuilder.class.php
index 6a8a5a62f0..034a610949 100644
--- a/meta/builders/AutoDaoBuilder.class.php
+++ b/meta/builders/AutoDaoBuilder.class.php
@@ -37,7 +37,7 @@ abstract class Auto{$class->getName()}DAO extends {$parentName}
 {
 
 EOT;
-
+			
 			$out .= self::buildPointers($class)."\n}\n";
 			
 			return $out.self::getHeel();
diff --git a/meta/builders/BaseBuilder.class.php b/meta/builders/BaseBuilder.class.php
index 9efc4c85ca..d5d89e949d 100644
--- a/meta/builders/BaseBuilder.class.php
+++ b/meta/builders/BaseBuilder.class.php
@@ -24,6 +24,14 @@ protected static function buildPointers(MetaClass $class)
 			$out = null;
 			
 			if (!$class->getPattern() instanceof AbstractClassPattern) {
+				if ($source = $class->getSourceLink()) {
+					$out .= <<<EOT
+	protected \$linkName =  '{$source}';
+	
+
+EOT;
+				}
+				
 				if (
 					$class->getIdentifier()->getColumnName() !== 'id'
 				) {
@@ -78,17 +86,6 @@ public function uncacheLists()
 EOT;
 			}
 			
-			if ($source = $class->getSourceLink()) {
-				$out .= <<<EOT
-
-
-public function getLinkName()
-{
-	return '{$source}';
-}
-EOT;
-			}
-			
 			return $out;
 		}
 		
diff --git a/meta/builders/DictionaryDaoBuilder.class.php b/meta/builders/DictionaryDaoBuilder.class.php
index 92257fa92b..8612850d9f 100644
--- a/meta/builders/DictionaryDaoBuilder.class.php
+++ b/meta/builders/DictionaryDaoBuilder.class.php
@@ -30,6 +30,7 @@ abstract class Auto{$class->getName()}DAO extends StorableDAO
 {$pointers}
 }
 
+
 EOT;
 			
 			return $out.self::getHeel();
diff --git a/test/misc/TestCaseDB.class.php b/test/misc/TestCaseDB.class.php
index 064a88c364..8b1b561f16 100644
--- a/test/misc/TestCaseDB.class.php
+++ b/test/misc/TestCaseDB.class.php
@@ -28,6 +28,7 @@ protected function getDBCreator() {
 		 * @return DB
 		 */
 		protected function getDbByType($type) {
+			
 			foreach (DBTestPool::me()->getPool() as $db) {
 				if (get_class($db) == $type)
 					return $db;

From 8b4eccf013deacddef3b1b35814006ffc67c1fbd Mon Sep 17 00:00:00 2001
From: "Evgeniy V. Kokovikhin" <dovg@dovg.ru>
Date: Tue, 4 Dec 2012 14:00:04 +0400
Subject: [PATCH 06/35] cleanup

---
 meta/builders/DictionaryDaoBuilder.class.php | 1 -
 test/misc/TestCaseDB.class.php               | 1 -
 2 files changed, 2 deletions(-)

diff --git a/meta/builders/DictionaryDaoBuilder.class.php b/meta/builders/DictionaryDaoBuilder.class.php
index 8612850d9f..92257fa92b 100644
--- a/meta/builders/DictionaryDaoBuilder.class.php
+++ b/meta/builders/DictionaryDaoBuilder.class.php
@@ -30,7 +30,6 @@ abstract class Auto{$class->getName()}DAO extends StorableDAO
 {$pointers}
 }
 
-
 EOT;
 			
 			return $out.self::getHeel();
diff --git a/test/misc/TestCaseDB.class.php b/test/misc/TestCaseDB.class.php
index 8b1b561f16..064a88c364 100644
--- a/test/misc/TestCaseDB.class.php
+++ b/test/misc/TestCaseDB.class.php
@@ -28,7 +28,6 @@ protected function getDBCreator() {
 		 * @return DB
 		 */
 		protected function getDbByType($type) {
-			
 			foreach (DBTestPool::me()->getPool() as $db) {
 				if (get_class($db) == $type)
 					return $db;

From 15feea7d6ae5f20995113fd3ff7b930d343e9483 Mon Sep 17 00:00:00 2001
From: "Evgeniy V. Kokovikhin" <dovg@dovg.ru>
Date: Tue, 4 Dec 2012 18:48:31 +0400
Subject: [PATCH 07/35] more undestandable method using

---
 main/DAOs/GenericDAO.class.php | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/main/DAOs/GenericDAO.class.php b/main/DAOs/GenericDAO.class.php
index dc8c8c5a83..48cac7dcb4 100644
--- a/main/DAOs/GenericDAO.class.php
+++ b/main/DAOs/GenericDAO.class.php
@@ -18,7 +18,7 @@ abstract class GenericDAO extends Singleton implements BaseDAO
 	{
 		private $identityMap	= array();
 		
-		protected $linkName		= null;
+		private $linkName		= null;
 		
 		abstract public function getTable();
 		abstract public function getObjectName();
@@ -73,7 +73,7 @@ public function completeObject(Identifiable $object)
 		**/
 		public function getLinkName()
 		{
-			return $this->linkName;
+			return $this->getDefaultLinkName();
 		}
 		
 		public function getIdName()
@@ -361,6 +361,11 @@ public function registerWorkerUncacher(UncacherBase $uncacher)
 			DBPool::getByDao($this)->registerUncacher($uncacher);
 		}
 		
+		final protected function getDefaultLinkName()
+		{
+			return $this->linkName;
+		}
+		
 		protected function inject(
 			InsertOrUpdateQuery $query,
 			Identifiable $object

From dba8e22d4f9d4b379aaa50d8280597f86cfff25c Mon Sep 17 00:00:00 2001
From: "Evgeniy V. Kokovikhin" <dovg@dovg.ru>
Date: Tue, 4 Dec 2012 19:09:03 +0400
Subject: [PATCH 08/35]  b897ed8 rolled back

---
 main/DAOs/GenericDAO.class.php | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/main/DAOs/GenericDAO.class.php b/main/DAOs/GenericDAO.class.php
index 48cac7dcb4..dc8c8c5a83 100644
--- a/main/DAOs/GenericDAO.class.php
+++ b/main/DAOs/GenericDAO.class.php
@@ -18,7 +18,7 @@ abstract class GenericDAO extends Singleton implements BaseDAO
 	{
 		private $identityMap	= array();
 		
-		private $linkName		= null;
+		protected $linkName		= null;
 		
 		abstract public function getTable();
 		abstract public function getObjectName();
@@ -73,7 +73,7 @@ public function completeObject(Identifiable $object)
 		**/
 		public function getLinkName()
 		{
-			return $this->getDefaultLinkName();
+			return $this->linkName;
 		}
 		
 		public function getIdName()
@@ -361,11 +361,6 @@ public function registerWorkerUncacher(UncacherBase $uncacher)
 			DBPool::getByDao($this)->registerUncacher($uncacher);
 		}
 		
-		final protected function getDefaultLinkName()
-		{
-			return $this->linkName;
-		}
-		
 		protected function inject(
 			InsertOrUpdateQuery $query,
 			Identifiable $object

From 8f3ff0645f5e4513256f55dddf47881414ef6b6c Mon Sep 17 00:00:00 2001
From: "Evgeniy V. Kokovikhin" <dovg@dovg.ru>
Date: Thu, 6 Dec 2012 16:47:50 +0400
Subject: [PATCH 09/35] + changelog

---
 doc/ChangeLog | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 8ffc3f8978..c5258c5b39 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,9 @@
+2012-12-06  Evgeny V. Kokovikhin
+	* main/DAOs/GenericDAO.class.php 
+		meta/builders/AutoDaoBuilder.class.php 
+		meta/builders/BaseBuilder.class.php:
+			dbLink became a property
+
 2012-11-25  Alexey S. Denisov
 
 	* core/Form/Primitives/PrimitiveIdentifier.class.php

From 53cf8633885206f523cc97e392ef8af1e554dcc7 Mon Sep 17 00:00:00 2001
From: vasu <vasu.ru@ya.ru>
Date: Sun, 16 Dec 2012 20:52:52 +0400
Subject: [PATCH 10/35] do not forward stderr > stdout

---
 meta/bin/build.php                       |  7 ++---
 meta/classes/ColoredTextOutput.class.php | 22 ++++++++++++++--
 meta/classes/MetaOutput.class.php        | 33 +++++++++++++++++++++---
 meta/classes/TextOutput.class.php        | 20 ++++++++++++++
 4 files changed, 71 insertions(+), 11 deletions(-)

diff --git a/meta/bin/build.php b/meta/bin/build.php
index 81eb0b70e8..497a2fb842 100755
--- a/meta/bin/build.php
+++ b/meta/bin/build.php
@@ -116,11 +116,9 @@ function init()
 	
 	function stop($message = null)
 	{
-		echo $message."\n\n";
+		fwrite(STDERR, $message."\n\n");
 		
 		help();
-		
-		die();
 	}
 	
 	// paths
@@ -342,5 +340,4 @@ function stop($message = null)
 	}
 	
 	$out->getOutput()->resetAll();
-	$out->newLine();
-?>
\ No newline at end of file
+	$out->newLine();
\ No newline at end of file
diff --git a/meta/classes/ColoredTextOutput.class.php b/meta/classes/ColoredTextOutput.class.php
index c406298507..6b78b5feac 100644
--- a/meta/classes/ColoredTextOutput.class.php
+++ b/meta/classes/ColoredTextOutput.class.php
@@ -41,5 +41,23 @@ public function resetAll()
 			
 			return $this;
 		}
-	}
-?>
\ No newline at end of file
+
+		/**
+		 * @return string colored text
+		**/
+		public function wrapString(
+			$text,
+			$attribute = ConsoleMode::ATTR_RESET_ALL,
+			$foreground = ConsoleMode::FG_WHITE,
+			$background = ConsoleMode::BG_BLACK
+		)
+		{
+			return
+				chr(0x1B)
+				.'['.$attribute.';'
+				.$foreground .';'
+				.$background .'m'
+				.$text
+				.chr(0x1B) .'[0m';
+		}
+	}
\ No newline at end of file
diff --git a/meta/classes/MetaOutput.class.php b/meta/classes/MetaOutput.class.php
index d9f5db7e3d..360be3714e 100644
--- a/meta/classes/MetaOutput.class.php
+++ b/meta/classes/MetaOutput.class.php
@@ -92,7 +92,7 @@ public function warningLine($text)
 		**/
 		public function error($text, $bold = false)
 		{
-			return $this->defaultText($text, ConsoleMode::FG_RED, $bold);
+			return $this->errorText($text, ConsoleMode::FG_RED, $bold);
 		}
 		
 		/**
@@ -100,7 +100,7 @@ public function error($text, $bold = false)
 		**/
 		public function errorLine($text, $bold = false)
 		{
-			return $this->defaultTextLine($text, ConsoleMode::FG_RED, $bold);
+			return $this->errorTextLine($text, ConsoleMode::FG_RED, $bold);
 		}
 		
 		/**
@@ -156,5 +156,30 @@ private function defaultTextLine($text, $color, $bold)
 			
 			return $this;
 		}
-	}
-?>
\ No newline at end of file
+
+		/**
+		 * @return MetaOutput
+		**/
+		private function errorText($text, $color, $bold)
+		{
+			if ($this->out instanceof ColoredTextOutput)
+				$text = $this->out->wrapString($text);
+
+			$this->out->writeErr($text);
+
+			return $this;
+		}
+
+		/**
+		 * @return MetaOutput
+		**/
+		private function errorTextLine($text, $color, $bold)
+		{
+			if ($this->out instanceof ColoredTextOutput)
+				$text = $this->out->wrapString($text);
+
+			$this->out->writeErrLine($text);
+
+			return $this;
+		}
+	}
\ No newline at end of file
diff --git a/meta/classes/TextOutput.class.php b/meta/classes/TextOutput.class.php
index 541957d445..6c61ee90d6 100644
--- a/meta/classes/TextOutput.class.php
+++ b/meta/classes/TextOutput.class.php
@@ -34,6 +34,26 @@ public function writeLine($text)
 			return $this;
 		}
 		
+		/**
+		 * @return TextOutput
+		**/
+		public function writeErr($text)
+		{
+			fwrite(STDERR, $text);
+
+			return $this;
+		}
+
+		/**
+		 * @return TextOutput
+		**/
+		public function writeErrLine($text)
+		{
+			fwrite(STDERR, $text .PHP_EOL);
+
+			return $this;
+		}
+
 		/**
 		 * @return TextOutput
 		**/

From 3f1e8eae9d7169cf9faf14f09f46caf2224a4ebf Mon Sep 17 00:00:00 2001
From: vasu <vasu.ru@ya.ru>
Date: Wed, 19 Dec 2012 03:29:25 +0400
Subject: [PATCH 11/35] security holes: getActualValue

---
 core/Form/Primitives/BasePrimitive.class.php  | 18 +++++++++++++---
 core/Form/Primitives/PrimitiveAlias.class.php | 19 ++++++++---------
 core/Form/Primitives/TimeList.class.php       | 21 +++++++++++++++----
 3 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/core/Form/Primitives/BasePrimitive.class.php b/core/Form/Primitives/BasePrimitive.class.php
index d7cbe2f8b3..20af7b8b2e 100644
--- a/core/Form/Primitives/BasePrimitive.class.php
+++ b/core/Form/Primitives/BasePrimitive.class.php
@@ -72,22 +72,34 @@ public function getRawValue()
 		{
 			return $this->raw;
 		}
+
+		public function getValueOrDefault()
+		{
+			if ($this->value !== null)
+				return $this->value;
+
+			return $this->default;
+		}
 		
+		/**
+		 * @deprecated since version 1.0
+		 * @see getSafeValue, getValueOrDefault
+		 */
 		public function getActualValue()
 		{
-			if (null !== $this->value)
+			if ($this->value !== null)
 				return $this->value;
 			elseif ($this->imported)
 				return $this->raw;
 			
 			return $this->default;
 		}
-		
+
 		public function getSafeValue()
 		{
 			if ($this->imported)
 				return $this->value;
-			
+
 			return $this->default;
 		}
 		
diff --git a/core/Form/Primitives/PrimitiveAlias.class.php b/core/Form/Primitives/PrimitiveAlias.class.php
index 33fe5cfbe2..d1f9fc423f 100644
--- a/core/Form/Primitives/PrimitiveAlias.class.php
+++ b/core/Form/Primitives/PrimitiveAlias.class.php
@@ -57,25 +57,24 @@ public function getRawValue()
 			return $this->primitive->getRawValue();
 		}
 		
+
+		public function getValueOrDefault()
+		{
+			return $this->primitive->getValueOrDefault();
+		}
+
 		/**
 		 * @deprecated by getFormValue
+		 * since version 1.0 by getValueOrDefault
 		**/
 		public function getActualValue()
 		{
-			if (null !== $this->primitive->getValue())
-				return $this->primitive->getValue();
-			elseif ($this->primitive->isImported())
-				return $this->primitive->getRawValue();
-			
-			return $this->primitive->getDefault();
+			return $this->primitive->getActualValue();
 		}
 		
 		public function getSafeValue()
 		{
-			if ($this->primitive->isImported())
-				return $this->primitive->getValue();
-			
-			return $this->primitive->getDefault();
+			return $this->primitive->getSafeValue();
 		}
 		
 		public function getFormValue()
diff --git a/core/Form/Primitives/TimeList.class.php b/core/Form/Primitives/TimeList.class.php
index 405f382f78..35c7f1cc07 100644
--- a/core/Form/Primitives/TimeList.class.php
+++ b/core/Form/Primitives/TimeList.class.php
@@ -53,17 +53,30 @@ public function import($scope)
 			
 			return ($this->value !== array());
 		}
-		
+
+		public function getValueOrDefault()
+		{
+			if (is_array($this->value) && $this->value[0])
+				return $this->value;
+
+			return array($this->default);
+		}
+
+		/**
+		 * @deprecated deprecated since version 1.0
+		 * @see getSafeValue, getValueOrDefault
+		 * @return type
+		 */
 		public function getActualValue()
 		{
 			if (is_array($this->value) && $this->value[0])
 				return $this->value;
 			elseif (is_array($this->raw) && $this->raw[0])
 				return $this->raw;
-			
+
 			return array($this->default);
 		}
-		
+
 		public static function stringToTimeList($string)
 		{
 			$list = array();
@@ -86,4 +99,4 @@ public function exportValue()
 			throw new UnimplementedFeatureException();
 		}
 	}
-?>
\ No newline at end of file
+?>

From 3527a1c26dcc826668019460cd6206b123fe56ca Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Sun, 23 Dec 2012 14:36:16 +0400
Subject: [PATCH 12/35] fixcs after previous commit

---
 core/Form/Primitives/PrimitiveAlias.class.php | 1 -
 core/Form/Primitives/TimeList.class.php       | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/core/Form/Primitives/PrimitiveAlias.class.php b/core/Form/Primitives/PrimitiveAlias.class.php
index d1f9fc423f..927a61c1a4 100644
--- a/core/Form/Primitives/PrimitiveAlias.class.php
+++ b/core/Form/Primitives/PrimitiveAlias.class.php
@@ -57,7 +57,6 @@ public function getRawValue()
 			return $this->primitive->getRawValue();
 		}
 		
-
 		public function getValueOrDefault()
 		{
 			return $this->primitive->getValueOrDefault();
diff --git a/core/Form/Primitives/TimeList.class.php b/core/Form/Primitives/TimeList.class.php
index 35c7f1cc07..8ebf1c897d 100644
--- a/core/Form/Primitives/TimeList.class.php
+++ b/core/Form/Primitives/TimeList.class.php
@@ -99,4 +99,4 @@ public function exportValue()
 			throw new UnimplementedFeatureException();
 		}
 	}
-?>
+?>
\ No newline at end of file

From abbc8f7207f32f92f8b0951255d3eef0ca24608a Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Mon, 16 Apr 2012 16:27:38 +0400
Subject: [PATCH 13/35] InnerMetaProperty (ValueObject) unquoting binary field
 fix

---
 doc/ChangeLog                          | 5 +++++
 main/Base/AbstractProtoClass.class.php | 8 ++++----
 main/Base/InnerMetaProperty.class.php  | 2 +-
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index c5258c5b39..190114a632 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2012-12-23  Alexey S. Denisov
+	* main/Base/AbstractProtoClass.class.php
+		main/Base/InnerMetaProperty.class.php:
+			InnerMetaProperty (ValueObject) unquoting binary field fix
+
 2012-12-06  Evgeny V. Kokovikhin
 	* main/DAOs/GenericDAO.class.php 
 		meta/builders/AutoDaoBuilder.class.php 
diff --git a/main/Base/AbstractProtoClass.class.php b/main/Base/AbstractProtoClass.class.php
index 6b229e1a13..d3fb26b9be 100644
--- a/main/Base/AbstractProtoClass.class.php
+++ b/main/Base/AbstractProtoClass.class.php
@@ -121,9 +121,9 @@ public function endPrefetch(array $objectList)
 			return $objectList;
 		}
 		
-		public static function makeOnlyObject($className, $array, $prefix = null)
+		public static function makeOnlyObject($className, $array, $prefix = null, ProtoDAO $parentDao = null)
 		{
-			return self::assemblyObject(new $className, $array, $prefix);
+			return self::assemblyObject(new $className, $array, $prefix, $parentDao);
 		}
 		
 		public static function completeObject(Prototyped $object)
@@ -383,13 +383,13 @@ private static function fetchEncapsulants(Prototyped $object)
 		}
 		
 		private static function assemblyObject(
-			Prototyped $object, $array, $prefix = null
+			Prototyped $object, $array, $prefix = null, ProtoDAO $parentDao = null
 		)
 		{
 			if ($object instanceof DAOConnected)
 				$dao = $object->dao();
 			else
-				$dao = null;
+				$dao = $parentDao ?: null;
 			
 			$proto = $object->proto();
 			
diff --git a/main/Base/InnerMetaProperty.class.php b/main/Base/InnerMetaProperty.class.php
index 0c8a776b86..8d8c5b9958 100644
--- a/main/Base/InnerMetaProperty.class.php
+++ b/main/Base/InnerMetaProperty.class.php
@@ -75,7 +75,7 @@ public function toValue(ProtoDAO $dao = null, $array, $prefix = null)
 			
 			return $proto->completeObject(
 				$proto->makeOnlyObject(
-					$this->getClassName(), $array, $prefix
+					$this->getClassName(), $array, $prefix, $dao
 				),
 				$array,
 				$prefix

From dce7da58b53da2706cd6378a1fcccb403159b5b4 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Sun, 23 Dec 2012 19:11:48 +0400
Subject: [PATCH 14/35] update doc/Changelog

---
 doc/ChangeLog | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 190114a632..e612c9be61 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,9 +1,27 @@
+2012-12-23  Vasily A. Surikov
+
+	* meta/bin/build.php
+		meta/classes/ColoredTextOutput.class.php
+		meta/classes/MetaOutput.class.php
+		meta/classes/TextOutput.class.php:
+			do not forward stderr > stdout
+
+2012-12-23  Vasily A. Surikov
+
+	* core/Form/Primitives/BasePrimitive.class.php
+		core/Form/Primitives/PrimitiveAlias.class.php
+		core/Form/Primitives/TimeList.class.php:
+			getActualValue marked deprecated and not secure,
+				added instead it method getValueOrDefault
+
 2012-12-23  Alexey S. Denisov
+
 	* main/Base/AbstractProtoClass.class.php
 		main/Base/InnerMetaProperty.class.php:
 			InnerMetaProperty (ValueObject) unquoting binary field fix
 
 2012-12-06  Evgeny V. Kokovikhin
+
 	* main/DAOs/GenericDAO.class.php 
 		meta/builders/AutoDaoBuilder.class.php 
 		meta/builders/BaseBuilder.class.php:
@@ -22,11 +40,13 @@
 		for Objects properties if it's not required
 
 2012-10-24  Alexey S. Denisov
+
 	* main/Flow/CarefulDatabaseRunner.class.php
 		main/UnifiedContainer/UnifiedContainer.class.php:
 			CarefulDatabaseRunner and UnifiedContainer will use InnerTransaction
 
 2012-10-24  Alexey S. Denisov
+
 	* global.inc.php.tpl
 		main/Autoloader/Autoloader.class.php
 		main/Autoloader/AutoloaderClassNotFound.class.php

From 96987facaf64052497d0888167346fcd1c4c128b Mon Sep 17 00:00:00 2001
From: vasu <vasu.ru@ya.ru>
Date: Sun, 23 Dec 2012 19:30:21 +0400
Subject: [PATCH 15/35] add proximal method to Form

---
 core/Form/PlainForm.class.php | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/core/Form/PlainForm.class.php b/core/Form/PlainForm.class.php
index 303ec94c9d..51665ca774 100644
--- a/core/Form/PlainForm.class.php
+++ b/core/Form/PlainForm.class.php
@@ -116,6 +116,15 @@ public function getRawValue($name)
 			return $this->get($name)->getRawValue();
 		}
 		
+		public function getValueOrDefault($name)
+		{
+			return $this->get($name)->getValueOrDefault();
+		}
+		
+		/**
+		 * @deprecated since version 1.0
+		 * @see getValueOrDefault
+		 */
 		public function getActualValue($name)
 		{
 			return $this->get($name)->getActualValue();
@@ -160,4 +169,4 @@ public function getPrimitiveList()
 			return $this->primitives;
 		}
 	}
-?>
\ No newline at end of file
+	
\ No newline at end of file

From 27af2eed4eb300cd82634534ee794964c9fa8785 Mon Sep 17 00:00:00 2001
From: sugrob <sygrob2008@gmail.com>
Date: Mon, 14 Jan 2013 19:22:03 +0400
Subject: [PATCH 16/35] fix MathUtils::getMmult

---
 main/Math/MathUtils.class.php     |  9 ++++++--
 test/main/MathUtilsTest.class.php | 35 ++++++++++++++++++++++++++++++-
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/main/Math/MathUtils.class.php b/main/Math/MathUtils.class.php
index 3db0d44d93..f48e90ff0c 100644
--- a/main/Math/MathUtils.class.php
+++ b/main/Math/MathUtils.class.php
@@ -227,11 +227,16 @@ public static function getMmult(array $list1, array $list2)
 		{
 			$list1Size = count($list1);
 			$list2Size = count($list2);
+
+			Assert::isGreater($list1Size, 0, "Can't multiply empty matrix");
+			Assert::isGreater($list2Size, 0, "Can't multiply empty matrix");
+
+			$list2Width = count($list2[0]);
 			
 			$result = array();
 			
 			for ($i = 0; $i < $list1Size; $i++) {
-				for ($j = 0; $j < $list2Size; $j++) {
+				for ($j = 0; $j < $list2Width; $j++) {
 					$x = 0;
 					
 					for ($k = 0; $k < $list2Size; $k++) {
@@ -269,4 +274,4 @@ public static function compareFloat(
 				return $diff < 0 ? -1 : 1;
 		}
 	}
-?>
\ No newline at end of file
+?>
diff --git a/test/main/MathUtilsTest.class.php b/test/main/MathUtilsTest.class.php
index 1b615d9cd9..096f0265b3 100644
--- a/test/main/MathUtilsTest.class.php
+++ b/test/main/MathUtilsTest.class.php
@@ -28,5 +28,38 @@ public function testCompareFloat()
 				1
 			);
 		}
+
+		public function testMatrixMultiplication()
+		{
+			$left = array(
+				array(1, 2),
+				array(3, 5),
+				array(2, 4)
+			);
+
+			$right = array(
+				array(4, 7, 5),
+				array(3, 1, 4)
+			);
+
+			$this->assertEquals(
+				MathUtils::getMmult($left, $right),
+				array(
+					array(10, 9, 13),
+					array(27, 26, 35),
+					array(20, 18, 26),
+				)
+			);
+
+			try {
+				MathUtils::getMmult(array(), $right);
+				$this->fail("Exception expected here");
+			} catch (WrongArgumentException $e) {}
+
+			try {
+				MathUtils::getMmult($left, array());
+				$this->fail("Exception expected here");
+			} catch (WrongArgumentException $e) {}
+		}
 	}
-?>
\ No newline at end of file
+?>

From e6853eac6e7a0e7a0ec3d580c813cbad46a05d05 Mon Sep 17 00:00:00 2001
From: sugrob <sygrob2008@gmail.com>
Date: Mon, 14 Jan 2013 19:29:23 +0400
Subject: [PATCH 17/35] edit ChangeLog

---
 doc/ChangeLog | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index e612c9be61..734da381f4 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,9 @@
+2013-01-14  Dmitriy V. Snezhinskiy
+
+	* main/Math/MathUtils.class.php 
+		test/main/MathUtilsTest.class.php:
+			fix matrix multiplication, add test
+
 2012-12-23  Vasily A. Surikov
 
 	* meta/bin/build.php

From bd72521e9ad33578b2d395766fafea082384310b Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Wed, 23 Jan 2013 21:15:21 +0400
Subject: [PATCH 18/35] update doc/Changelog

---
 doc/ChangeLog | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 734da381f4..0b9013a692 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,4 +1,4 @@
-2013-01-14  Dmitriy V. Snezhinskiy
+2013-01-23  Dmitriy V. Snezhinskiy
 
 	* main/Math/MathUtils.class.php 
 		test/main/MathUtilsTest.class.php:

From 87be20eafab2d7c6793c7217b6ad185e9d11f69e Mon Sep 17 00:00:00 2001
From: "Igor V. Gulyaev" <igulyaev@setevisor.tv>
Date: Fri, 15 Feb 2013 14:59:53 +0400
Subject: [PATCH 19/35] * bit code cosmetic

---
 main/Net/Http/HeaderUtils.class.php | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/main/Net/Http/HeaderUtils.class.php b/main/Net/Http/HeaderUtils.class.php
index 07ec0bac6e..af98252c8d 100644
--- a/main/Net/Http/HeaderUtils.class.php
+++ b/main/Net/Http/HeaderUtils.class.php
@@ -36,8 +36,9 @@ public static function redirectBack()
 				self::$headerSent = true;
 				self::$redirectSent = true;
 				return $_SERVER['HTTP_REFERER'];
-			} else
-				return false;
+			}
+
+			return false;
 		}
 
 		public static function getRequestHeaderList()
@@ -131,7 +132,7 @@ public static function sendContentLength($length)
 		public static function sendHttpStatus(HttpStatus $status)
 		{
 			header($status->toString());
-			
+
 			self::$headerSent = true;
 		}
 

From 0df011f871f17e439ba4a6dd8f13a9b190e062ef Mon Sep 17 00:00:00 2001
From: Daniel Plainview <n.konstantinov@co.wapstart.ru>
Date: Mon, 25 Mar 2013 12:19:49 +0400
Subject: [PATCH 20/35] remove eval() from Singleton

---
 core/Base/Singleton.class.php | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/core/Base/Singleton.class.php b/core/Base/Singleton.class.php
index 4c2720c2c3..6201e67824 100644
--- a/core/Base/Singleton.class.php
+++ b/core/Base/Singleton.class.php
@@ -31,13 +31,17 @@ final public static function getInstance(
 				if (2 < func_num_args()) {
 					$args = func_get_args();
 					array_shift($args);
-					
-					// can't call protected constructor through reflection
-					eval(
-						'$object = new '.$class
-						.'($args['.implode('],$args[', array_keys($args)).']);'
+
+					// emulation of ReflectionClass->newInstanceWithoutConstructor
+					$object =
+						unserialize(
+							sprintf('O:%d:"%s":0:{}', strlen($class), $class)
+						);
+
+					call_user_func_array(
+						array($object, '__construct'),
+						$args
 					);
-				
 				} else {
 					$object =
 						$args

From 002e130d65391f79c97e124b3e6d453a3deeed35 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Sun, 31 Mar 2013 17:39:21 +0400
Subject: [PATCH 21/35] update doc/ChangeLog

---
 doc/ChangeLog | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 0b9013a692..a55c1e6efd 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2013-03-31  Nikita V. Konstantinov
+
+	* core/Base/Singleton.class.php:
+		Singleton 2+ constructor arguments now without eval
+
 2013-01-23  Dmitriy V. Snezhinskiy
 
 	* main/Math/MathUtils.class.php 

From b56eedd07c47e40fa76b4b48dab042edf824122f Mon Sep 17 00:00:00 2001
From: Slava Tsyrulnik <neemah86@gmail.com>
Date: Mon, 21 Jan 2013 16:43:47 +0400
Subject: [PATCH 22/35] HttpUrl::isValid skips privileged ports validation by
 default

---
 .../Primitives/PrimitiveHttpUrl.class.php     | 14 +++-
 main/Net/HttpUrl.class.php                    | 73 ++++++++++++-------
 test/core/PrimitiveHttpUrlTest.class.php      | 44 +++++++++++
 test/main/HttpUrlTest.class.php               | 42 +++++++++++
 4 files changed, 147 insertions(+), 26 deletions(-)
 create mode 100644 test/core/PrimitiveHttpUrlTest.class.php
 create mode 100644 test/main/HttpUrlTest.class.php

diff --git a/core/Form/Primitives/PrimitiveHttpUrl.class.php b/core/Form/Primitives/PrimitiveHttpUrl.class.php
index 39565d872f..7f9382abcc 100644
--- a/core/Form/Primitives/PrimitiveHttpUrl.class.php
+++ b/core/Form/Primitives/PrimitiveHttpUrl.class.php
@@ -14,13 +14,25 @@
 	**/
 	final class PrimitiveHttpUrl extends PrimitiveString
 	{
+		private $checkPrivilegedPorts = false;
+		
+		public function setCheckPrivilegedPorts($check = true)
+		{
+			$this->checkPrivilegedPorts = $check ? true : false;
+			
+			return $this;
+		}
+		
 		public function import($scope)
 		{
 			if (!$result = parent::import($scope))
 				return $result;
 			
 			try {
-				$this->value = HttpUrl::create()->parse($this->value);
+				$this->value =
+					HttpUrl::create()->
+						parse($this->value)->
+						setCheckPrivilegedPorts($this->checkPrivilegedPorts);
 			} catch (WrongArgumentException $e) {
 				$this->value = null;
 				
diff --git a/main/Net/HttpUrl.class.php b/main/Net/HttpUrl.class.php
index 300cf42f23..2599b6a66e 100644
--- a/main/Net/HttpUrl.class.php
+++ b/main/Net/HttpUrl.class.php
@@ -16,6 +16,8 @@ final class HttpUrl extends Url
 	{
 		protected static $knownSubSchemes	= array();
 		
+		private $checkPrivilegedPorts = false;
+		
 		/**
 		 * @return HttpUrl
 		**/
@@ -85,36 +87,12 @@ public function isValidPort()
 			if (!parent::isValidPort())
 				return false;
 			
-			if (
-				$this->port
-				&& !in_array($this->port, array(80, 443))
-				&& $this->port < 1024
-			)
+			if ($this->checkPrivilegedPorts && $this->isPrivilegedPortUsed())
 				return false;
 			
 			return true;
 		}
 		
-		protected function isValidHostName()
-		{
-			if (!parent::isValidHostName())
-				return false;
-			
-			$charPattern = $this->charPattern(null);
-			
-			// using rfc 2396, in order to detect bad ip address ranges like
-			// 666.666.666.666 which are valid hostnames in generic uri syntax
-			
-			$topLabelPattern = '(([a-z])|([a-z]([a-z0-9-])*[a-z0-9]))\.?';
-			
-			return (
-				preg_match(
-					"/^($charPattern*\.)?{$topLabelPattern}$/i",
-					$this->host
-				) == 1
-			);
-		}
-		
 		public function normalize()
 		{
 			parent::normalize();
@@ -138,5 +116,50 @@ public function makeComparable()
 		{
 			return $this->ensureAbsolute()->normalize()->setFragment(null);
 		}
+		
+		public function setCheckPrivilegedPorts($check = true)
+		{
+			$this->checkPrivilegedPorts = $check ? true : false;
+			
+			return $this;
+		}
+		
+		public function isPrivilegedPortsCheckEnabled()
+		{
+			return $this->checkPrivilegedPorts;
+		}
+		
+		public function isPrivilegedPortUsed()
+		{
+			if (
+				$this->port
+				&& !in_array($this->port, array(80, 443))
+				&& ($this->port < 1024)
+			) {
+				return true;
+			}
+			
+			return false;
+		}
+		
+		protected function isValidHostName()
+		{
+			if (!parent::isValidHostName())
+				return false;
+				
+			$charPattern = $this->charPattern(null);
+				
+			// using rfc 2396, in order to detect bad ip address ranges like
+			// 666.666.666.666 which are valid hostnames in generic uri syntax
+				
+			$topLabelPattern = '(([a-z])|([a-z]([a-z0-9-])*[a-z0-9]))\.?';
+				
+			return (
+					preg_match(
+							"/^($charPattern*\.)?{$topLabelPattern}$/i",
+							$this->host
+			) == 1
+			);
+		}
 	}
 ?>
\ No newline at end of file
diff --git a/test/core/PrimitiveHttpUrlTest.class.php b/test/core/PrimitiveHttpUrlTest.class.php
new file mode 100644
index 0000000000..57e40a30fe
--- /dev/null
+++ b/test/core/PrimitiveHttpUrlTest.class.php
@@ -0,0 +1,44 @@
+<?php
+/***************************************************************************
+ *   Copyright (C) 2013 by Vyacheslav Yu. Tsyrulnik                        *
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU Lesser General Public License as        *
+*   published by the Free Software Foundation; either version 3 of the    *
+*   License, or (at your option) any later version.                       *
+*                                                                         *
+***************************************************************************/
+	
+	final class PrimitiveHttpUrlTest extends TestCase
+	{
+		private $urlWithPrivilegedPort = "https://path.to.some.com:444/hey.html";
+		
+		/**
+		 * @test
+		 */
+		public function privilegedPortIsOkByDefault()
+		{
+			$form = Form::create()->add(Primitive::httpUrl("url"));
+			
+			$form->import(array('url' => $this->urlWithPrivilegedPort));
+			$errors = $form->getErrors();
+			
+			$this->assertFalse(isset($errors["url"]));
+		}
+		
+		/**
+		 * @test
+		 */
+		public function privilegedPortInvalid()
+		{
+			$form = Form::create()->add(Primitive::httpUrl("url")->setCheckPrivilegedPorts());
+			
+			$form->import(array('url' => $this->urlWithPrivilegedPort));
+			$errors = $form->getErrors();
+			
+			$this->assertTrue(isset($errors["url"]));
+			$this->assertEquals(Form::WRONG, $errors["url"]);
+		}
+		
+	}
+?>
\ No newline at end of file
diff --git a/test/main/HttpUrlTest.class.php b/test/main/HttpUrlTest.class.php
new file mode 100644
index 0000000000..3a59984031
--- /dev/null
+++ b/test/main/HttpUrlTest.class.php
@@ -0,0 +1,42 @@
+<?php
+/***************************************************************************
+ *   Copyright (C) 2013 by Vyacheslav Yu. Tsyrulnik                        *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License as        *
+ *   published by the Free Software Foundation; either version 3 of the    *
+ *   License, or (at your option) any later version.                       *
+ *                                                                         *
+ ***************************************************************************/
+	
+	final class HttpUrlTest extends TestCase
+	{
+		private $urlWithPrivilegedPort = "https://path.to.some.com:444/hey.html";
+		
+		/**
+		 * @test
+		 */
+		public function privilegedPortsValidationEnabled()
+		{
+			$url =
+				HttpUrl::create()->
+					parse($this->urlWithPrivilegedPort)->
+					setCheckPrivilegedPorts();
+			
+			$this->assertFalse($url->isValid());
+			$this->assertTrue($url->isPrivilegedPortUsed());
+		}
+		
+		/**
+		 * @test
+		 */
+		public function privilegdPortsValidationDisabled()
+		{
+			$url = HttpUrl::create()->parse($this->urlWithPrivilegedPort);
+				
+			$this->assertTrue($url->isValid());
+			$this->assertTrue($url->isPrivilegedPortUsed());
+		}
+		
+	}
+?>
\ No newline at end of file

From bc2b58476bb58e5cf4cd3a2c968c8f256b26fd4e Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Sun, 31 Mar 2013 17:59:59 +0400
Subject: [PATCH 23/35] update doc/ChangeLog

---
 doc/ChangeLog | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index a55c1e6efd..07db55ea4c 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,11 @@
+2013-03-31  Viatcheslav Y. Tsyrulnik
+
+	* core/Form/Primitives/PrimitiveHttpUrl.class.php
+		main/Net/HttpUrl.class.php
+		test/core/PrimitiveHttpUrlTest.class.php
+		test/main/HttpUrlTest.class.php:
+			HttpUrl::isValid skips privileged ports validation by default
+
 2013-03-31  Nikita V. Konstantinov
 
 	* core/Base/Singleton.class.php:

From 9e9ce3807ee21dac904dd9b3d729bab1758f6a6f Mon Sep 17 00:00:00 2001
From: vatt2001 <vatt2001@gmail.com>
Date: Tue, 26 Mar 2013 15:54:29 +0400
Subject: [PATCH 24/35] * SmartDaoWorker race condition bug fix

---
 main/DAOs/Workers/SmartDaoWorker.class.php | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/main/DAOs/Workers/SmartDaoWorker.class.php b/main/DAOs/Workers/SmartDaoWorker.class.php
index 5782c9d0e3..209def5ee5 100644
--- a/main/DAOs/Workers/SmartDaoWorker.class.php
+++ b/main/DAOs/Workers/SmartDaoWorker.class.php
@@ -125,13 +125,21 @@ private function syncMap($objectKey)
 		{
 			$cache = Cache::me();
 			
-			if (!$map = $cache->mark($this->className)->get($this->indexKey))
+			$mapExists = true;
+			if (!$map = $cache->mark($this->className)->get($this->indexKey)) {
 				$map = array();
+				$mapExists = false;
+			}
 			
 			$map[$objectKey] = true;
-			
-			$cache->mark($this->className)->
-				set($this->indexKey, $map, Cache::EXPIRES_FOREVER);
+
+			if ($mapExists) {
+				$cache->mark($this->className)->
+					replace($this->indexKey, $map, Cache::EXPIRES_FOREVER);
+			} else {
+				$cache->mark($this->className)->
+					set($this->indexKey, $map, Cache::EXPIRES_FOREVER);
+			}
 			
 			return true;
 		}
@@ -161,4 +169,4 @@ private function checkMap($objectKey)
 		}
 		//@}
 	}
-?>
\ No newline at end of file
+?>

From b93d34c7713af96b8562c0fcd2393bc5957da46f Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Mon, 8 Apr 2013 10:57:47 +0400
Subject: [PATCH 25/35] update doc/ChangeLog

---
 doc/ChangeLog | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 07db55ea4c..6f9010f4c7 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,7 @@
+2013-04-08 Artem V. Titarenko
+
+	* main/DAOs/Workers/SmartDaoWorker.class.php: SmartDaoWorker race condition bug fix
+
 2013-03-31  Viatcheslav Y. Tsyrulnik
 
 	* core/Form/Primitives/PrimitiveHttpUrl.class.php

From e08f0975736e96ce61e507d73655606142961655 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Thu, 18 Apr 2013 10:23:03 +0400
Subject: [PATCH 26/35] fixed watermark different keys with transaction and
 without

---
 core/Cache/CachePeer.class.php       |  8 ++++++++
 core/Cache/WatermarkedPeer.class.php | 15 +++++++++++++++
 core/DB/DB.class.php                 |  2 +-
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/core/Cache/CachePeer.class.php b/core/Cache/CachePeer.class.php
index f6c41e1b80..d29d345155 100644
--- a/core/Cache/CachePeer.class.php
+++ b/core/Cache/CachePeer.class.php
@@ -201,6 +201,14 @@ public function disableCompression()
 			return $this;
 		}
 
+		/**
+		 * @return CachePeer
+		 */
+		public function getRuntimeCopy()
+		{
+			return new RuntimeMemory();
+		}
+
 		protected function prepareData($value)
 		{
 			if ($this->compress)
diff --git a/core/Cache/WatermarkedPeer.class.php b/core/Cache/WatermarkedPeer.class.php
index 3319db692d..1643b92c2d 100644
--- a/core/Cache/WatermarkedPeer.class.php
+++ b/core/Cache/WatermarkedPeer.class.php
@@ -17,6 +17,7 @@
 	final class WatermarkedPeer extends SelectivePeer
 	{
 		private $peer		= null;
+		private $originalWatermark = null;
 		private $watermark	= null;
 		
 		/// map class -> watermark
@@ -44,6 +45,7 @@ public function __construct(
 		
 		public function setWatermark($watermark)
 		{
+			$this->originalWatermark = $watermark;
 			$this->watermark = md5($watermark.' ['.ONPHP_VERSION.']::');
 			
 			return $this;
@@ -158,6 +160,19 @@ public function append($key, $data)
 		{
 			return $this->peer->append($this->getActualWatermark().$key, $data);
 		}
+
+		/**
+		 * @return CachePeer
+		 */
+		public function getRuntimeCopy()
+		{
+			$newWm = new WatermarkedPeer(
+				$this->peer->getRuntimeCopy(),
+				$this->originalWatermark
+			);
+			$newWm->map = $this->map;
+			return $newWm;
+		}
 		
 		protected function store(
 			$action, $key, $value, $expires = Cache::EXPIRES_MEDIUM
diff --git a/core/DB/DB.class.php b/core/DB/DB.class.php
index ce170d2f0a..00a5b2d49d 100644
--- a/core/DB/DB.class.php
+++ b/core/DB/DB.class.php
@@ -143,7 +143,7 @@ public function begin(
 			$this->transaction = true;
 			
 			$this->outOfTransactionCachePeer = Cache::me();
-			Cache::setPeer(new RuntimeMemory());
+			Cache::setPeer(Cache::me()->getRuntimeCopy());
 			
 			return $this;
 		}

From 7bab40c7b58f8702f5a7154ea52d14196ce3fc19 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Fri, 19 Apr 2013 09:57:23 +0400
Subject: [PATCH 27/35] update doc/ChangeLog

---
 doc/ChangeLog | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 6f9010f4c7..9272cd1c51 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,10 @@
+2013-04-19 Aleksey S. Denisov
+
+	* core/Cache/CachePeer.class.php
+      core/Cache/WatermarkedPeer.class.php
+      core/DB/DB.class.php:
+        fixed deferent uncache keys with watermark while in db transaction
+
 2013-04-08 Artem V. Titarenko
 
 	* main/DAOs/Workers/SmartDaoWorker.class.php: SmartDaoWorker race condition bug fix

From a069037002e725256bb9feef443857e4b8dbe4bb Mon Sep 17 00:00:00 2001
From: bassta <vasily.stashko@gmail.com>
Date: Thu, 29 Aug 2013 13:28:12 +0400
Subject: [PATCH 28/35] * database connection check fix

---
 core/DB/MySQL.class.php   | 5 +++++
 core/DB/MySQLim.class.php | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/core/DB/MySQL.class.php b/core/DB/MySQL.class.php
index 86e1bdd670..6130c3e175 100644
--- a/core/DB/MySQL.class.php
+++ b/core/DB/MySQL.class.php
@@ -88,6 +88,11 @@ public function disconnect()
 			return $this;
 		}
 		
+		public function isConnected()
+		{
+			return parent::isConnected() && mysql_ping($this->link);
+		}
+		
 		/**
 		 * Same as query, but returns number of
 		 * affected rows in insert/update queries
diff --git a/core/DB/MySQLim.class.php b/core/DB/MySQLim.class.php
index a1f4987cbd..5117aeb266 100644
--- a/core/DB/MySQLim.class.php
+++ b/core/DB/MySQLim.class.php
@@ -73,6 +73,11 @@ public function disconnect()
 			return $this;
 		}
 		
+		public function isConnected()
+		{
+			return parent::isConnected() && mysqli_ping($this->link);
+		}
+		
 		/**
 		 * Same as query, but returns number of
 		 * affected rows in insert/update queries

From cb44fde21d592dc59465b005c0479fb356c949f6 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Tue, 3 Sep 2013 15:39:59 +0400
Subject: [PATCH 29/35] update doc/Changelog

---
 doc/ChangeLog | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index 9272cd1c51..e84b37d6c0 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,9 @@
+2013-09-03 bassta
+
+	* core/DB/MySQL.class.php
+	core/DB/MySQLim.class.php:
+		added (mysqli?_ping) check to isConnected() methods
+
 2013-04-19 Aleksey S. Denisov
 
 	* core/Cache/CachePeer.class.php

From 1dcc408c58b603fa0a0a75bdb664088bf8ce4560 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Wed, 4 Sep 2013 09:58:44 +0400
Subject: [PATCH 30/35] update doc/ChangeLog

---
 doc/ChangeLog | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/ChangeLog b/doc/ChangeLog
index e84b37d6c0..fbcd8d7737 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,17 +1,17 @@
-2013-09-03 bassta
+2013-09-03 Vasily M. Stashko
 
 	* core/DB/MySQL.class.php
 	core/DB/MySQLim.class.php:
 		added (mysqli?_ping) check to isConnected() methods
 
-2013-04-19 Aleksey S. Denisov
+2013-04-19  Aleksey S. Denisov
 
 	* core/Cache/CachePeer.class.php
       core/Cache/WatermarkedPeer.class.php
       core/DB/DB.class.php:
         fixed deferent uncache keys with watermark while in db transaction
 
-2013-04-08 Artem V. Titarenko
+2013-04-08  Artem V. Titarenko
 
 	* main/DAOs/Workers/SmartDaoWorker.class.php: SmartDaoWorker race condition bug fix
 

From 612da2c078d2be6d9fee6ca9bd190ee5143df178 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Wed, 29 Oct 2014 09:43:46 +0300
Subject: [PATCH 31/35] fix MySQLim autocommit by default

---
 core/DB/MySQL.class.php   |  1 +
 core/DB/MySQLim.class.php | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/core/DB/MySQL.class.php b/core/DB/MySQL.class.php
index 6130c3e175..b80b7a971c 100644
--- a/core/DB/MySQL.class.php
+++ b/core/DB/MySQL.class.php
@@ -16,6 +16,7 @@
 	 * @see http://www.php.net/mysql
 	 * 
 	 * @ingroup DB
+	 * @deprecated use MySQLim
 	**/
 	final class MySQL extends Sequenceless
 	{
diff --git a/core/DB/MySQLim.class.php b/core/DB/MySQLim.class.php
index 5117aeb266..00235e16fb 100644
--- a/core/DB/MySQLim.class.php
+++ b/core/DB/MySQLim.class.php
@@ -19,6 +19,8 @@
 	**/
 	final class MySQLim extends Sequenceless
 	{
+		private $needAutoCommit = false;
+
 		/**
 		 * @return MySQLim
 		**/
@@ -30,8 +32,21 @@ public function setDbEncoding()
 		}
 
 		/**
+		 * @param $flag
 		 * @return MySQLim
 		**/
+		public function setNeedAutoCommit($flag)
+		{
+			$this->needAutoCommit = $flag == true;
+			$this->setupAutoCommit();
+			return $this;
+		}
+
+		/**
+		 * @return $this
+		 * @throws DatabaseException
+		 * @throws UnsupportedMethodException
+		 */
 		public function connect()
 		{
 			if ($this->persistent)
@@ -58,6 +73,8 @@ public function connect()
 			
 			if ($this->encoding)
 				$this->setDbEncoding();
+
+			$this->setupAutoCommit();
 			
 			return $this;
 		}
@@ -181,5 +198,12 @@ private function checkSingle($result)
 			
 			return $result;
 		}
+
+		private function setupAutoCommit()
+		{
+			if ($this->isConnected()) {
+				mysqli_autocommit($this->link, $this->needAutoCommit);
+			}
+		}
 	}
 ?>
\ No newline at end of file

From 50fe1e58b9668d67fc1929c7222c4eb24b7cd989 Mon Sep 17 00:00:00 2001
From: "Igor V. Gulyaev" <igulyaev@setevisor.tv>
Date: Fri, 31 Oct 2014 11:37:30 +0300
Subject: [PATCH 32/35] + MySQLim::getTableInfo() bassta implementation.
 Backport from master

---
 core/DB/MySQLim.class.php | 85 ++++++++++++++++++++++++++++++++++++++-
 doc/ChangeLog             |  5 +++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/core/DB/MySQLim.class.php b/core/DB/MySQLim.class.php
index 00235e16fb..2bf6d664d6 100644
--- a/core/DB/MySQLim.class.php
+++ b/core/DB/MySQLim.class.php
@@ -168,7 +168,90 @@ public function queryRaw($queryString)
 		
 		public function getTableInfo($table)
 		{
-			throw new UnimplementedFeatureException();
+			static $types = array(
+				'tinyint'		=> DataType::SMALLINT,
+				'smallint'		=> DataType::SMALLINT,
+				'int'			=> DataType::INTEGER,
+				'mediumint'		=> DataType::INTEGER,
+
+				'bigint'		=> DataType::BIGINT,
+				
+				'double'		=> DataType::DOUBLE,
+				'decimal'		=> DataType::NUMERIC,
+
+				'char'			=> DataType::CHAR,
+				'varchar'		=> DataType::VARCHAR,
+				'text'			=> DataType::TEXT,
+				'tinytext'		=> DataType::TEXT,
+				'mediumtext'	=> DataType::TEXT,
+				
+				'date'			=> DataType::DATE,
+				'time'			=> DataType::TIME,
+				'timestamp'		=> DataType::TIMESTAMP,
+				'datetime'		=> DataType::TIMESTAMP,
+
+				// unhandled types
+				'set'			=> null,
+				'enum'			=> null,
+				'year'			=> null
+			);
+			
+			try {
+				$result = $this->queryRaw('SHOW COLUMNS FROM '.$table);
+			} catch (BaseException $e) {
+				throw new ObjectNotFoundException(
+					"unknown table '{$table}'"
+				);
+			}
+			
+			$table = new DBTable($table);
+			
+			while ($row = mysqli_fetch_array($result)) {
+				$name = strtolower($row['Field']);
+				$matches = array();
+				$info = array('type' => null, 'extra' => null);
+				if (
+					preg_match(
+						'~(\w+)(\((\d+?)\)){0,1}\s*(\w*)~',
+						strtolower($row['Type']),
+						$matches
+					)
+				) {
+					$info['type'] = $matches[1];
+					$info['size'] = $matches[3];
+					$info['extra'] = $matches[4];
+				}
+				
+				Assert::isTrue(
+					array_key_exists($info['type'], $types),
+					
+					'unknown type "'
+					.$types[$info['type']]
+					.'" found in column "'.$name.'"'
+				);
+				
+				if (empty($types[$info['type']]))
+					continue;
+				
+				$column = DBColumn::create(
+					DataType::create($types[$info['type']])->
+						setUnsigned(
+							strtolower($info['extra']) == 'unsigned'
+						)->
+						setNull(strtolower($row['Null']) == 'yes'),
+					
+					$name
+				)->
+				setAutoincrement(strtolower($row['Extra']) == 'auto_increment')->
+				setPrimaryKey(strtolower($row['Key']) == 'pri');
+				
+				if ($row['Default'])
+					$column->setDefault($row['Default']);
+				
+				$table->addColumn($column);
+			}
+			
+			return $table;
 		}
 		
 		public function hasQueue()
diff --git a/doc/ChangeLog b/doc/ChangeLog
index fbcd8d7737..dc1a847a89 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2013-10-25 Vasily M. Stashko
+
+	* core/DB/MySQLim.class.php:
+		added getTableInfo() method implementation
+
 2013-09-03 Vasily M. Stashko
 
 	* core/DB/MySQL.class.php

From 4ef49e61e32d95a5b66abd09b1677010076bd3b0 Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Wed, 29 Oct 2014 11:08:27 +0300
Subject: [PATCH 33/35] fixed RussianTypograph to work with php 5.5

---
 core/Form/Filters/RussianTypograph.class.php | 52 +++++++++++++++-----
 1 file changed, 40 insertions(+), 12 deletions(-)

diff --git a/core/Form/Filters/RussianTypograph.class.php b/core/Form/Filters/RussianTypograph.class.php
index 6d96d692fd..95b7390af9 100644
--- a/core/Form/Filters/RussianTypograph.class.php
+++ b/core/Form/Filters/RussianTypograph.class.php
@@ -63,10 +63,8 @@ final class RussianTypograph extends BaseFilter
 			'~(\s)\s*~u',						// n -> 2 whitespaces to process short strings (bar to a foo)
 			'~([\s\pP]|^)([\w\pL]{1,2})\s~Uu',	// bar a foo | bar to a foo
 			'~(&nbsp;|\s)\s+~u',				// compress whitespaces
-			'~\"(.*)\"~e',						// "qu"o"te"
 			'~\"([^\s]*)\"~',					// "quote"
 			'~\"([^\s]*)\s+([^\s\.]*)\"~',		// "quote quote"
-			'~([\w\pL\']+)~eu'					// rock'n'roll
 		);
 		
 		private static $to = array(
@@ -75,12 +73,12 @@ final class RussianTypograph extends BaseFilter
 			'$1$1',
 			'$1$2&nbsp;',
 			'$1',
-			'\'&laquo;\'.$this->innerQuotes(\'$1\').\'&raquo;\'',
 			'&laquo;$1&raquo;',
 			'&laquo;$1 $2&raquo;',
-			'str_replace("\'", \'&#146;\', \'$1\')'
 		);
-		
+
+		private $replaces = null;
+
 		/**
 		 * @return RussianTypograph
 		**/
@@ -138,20 +136,29 @@ public function apply($value)
 			
 			return CompressWhitespaceFilter::me()->apply($text);
 		}
+
+		/**
+		 * Remove using this method when php 5.3 will no more supported by onPHP
+		 * @param $text
+		 * @return mixed
+		 */
+		public function innerQuotes_php53($text)
+		{
+			return $this->innerQuotes($text);
+		}
 		
 		private function typographize($text)
 		{
 			if (mb_strlen($text) < 2)
 				return $text;
 			
-			return
-				preg_replace(
-					self::$from,
-					self::$to,
-					stripslashes($text)
-				);
+			$text = preg_replace(self::$from, self::$to, stripslashes($text));
+			foreach ($this->getCbReplaces() as $pattern => $callback) {
+				$text = preg_replace_callback($pattern, $callback, $text);
+			}
+			return $text;
 		}
-		
+
 		private function innerQuotes($text)
 		{
 			return
@@ -164,5 +171,26 @@ private function innerQuotes($text)
 					stripslashes($text)
 				);
 		}
+
+		private function getCbReplaces()
+		{
+			if ($this->replaces === null) {
+				$self = $this;
+				$this->replaces = [
+					// "qu"o"te" => '\'&laquo;\'.$this->innerQuotes(\'$1\').\'&raquo;\''
+					'~&laquo;(.*)&raquo;~' => function ($matches) use ($self) {
+						return '&laquo;' . $self->innerQuotes_php53($matches[1]) . '&raquo;';
+					},
+					'~\"(.*)\"~' => function ($matches) use ($self) {
+						return '&laquo;' . $self->innerQuotes_php53($matches[1]) . '&raquo;';
+					},
+					// rock'n'roll => 'str_replace("\'", \'&#146;\', \'$1\')'
+					'~([\w\pL\']+)~u' => function ($matches) {
+						return str_replace("'", '&#146;', $matches[1]);
+					},
+				];
+			}
+			return $this->replaces;
+		}
 	}
 ?>
\ No newline at end of file

From 7a92f92cd9a8d172ed5ce89f6fc823cb175a53ed Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Wed, 29 Oct 2014 11:25:21 +0300
Subject: [PATCH 34/35] replaced in MimePart using of preg_replace to
 preg_replace_callback

---
 main/Net/Mail/MimePart.class.php | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/main/Net/Mail/MimePart.class.php b/main/Net/Mail/MimePart.class.php
index f0e808b0c2..a079b77e80 100644
--- a/main/Net/Mail/MimePart.class.php
+++ b/main/Net/Mail/MimePart.class.php
@@ -222,13 +222,13 @@ public function getEncodedBody()
 				 * @see http://www.php.net/quoted_printable_decode
 				**/
 				case MailEncoding::QUOTED:
-					
-					$string =
-						preg_replace(
-							'/[^\x21-\x3C\x3E-\x7E\x09\x20]/e',
-							'sprintf("=%02x", ord ("$0"));',
-							$this->body
-						);
+					$string = preg_replace_callback(
+						'/[^\x21-\x3C\x3E-\x7E\x09\x20]/',
+						function ($matches) {
+							return sprintf("=%02x", ord($matches[0]));
+						},
+						$this->body
+					);
 					
 					$matches = array();
 					

From fdc94b2df89758db137c87a288a526d89f7537bc Mon Sep 17 00:00:00 2001
From: AlexeyDsov <alexeydsov@gmail.com>
Date: Mon, 24 Nov 2014 10:07:13 +0300
Subject: [PATCH 35/35] different small fixes, see bcbdb5d87dd

---
 core/DB/MyImprovedDialect.class.php           | 10 +---
 core/DB/MySQLim.class.php                     | 23 +++++++-
 .../Primitives/PrimitiveHttpUrl.class.php     |  2 +
 main/Net/Http/HttpClient.class.php            | 34 ++++++++++-
 main/Net/Mail/Mail.class.php                  | 43 ++++++++++----
 main/Utils/IO/StringInputStream.class.php     |  2 +-
 test/config.inc.php.tpl                       |  2 +-
 test/core/PrimitiveTimestampTZTest.class.php  |  2 +-
 test/core/TruncateQueryTest.class.php         |  2 +-
 test/db/InnerTransactionDBTest.class.php      | 59 +++++++++++++++++++
 .../AutoloaderClassPathCacheTest.class.php    |  3 +-
 test/main/OpenIdTest.class.php                | 35 +++++++++++
 test/misc/DBTestPool.class.php                |  3 +
 13 files changed, 192 insertions(+), 28 deletions(-)

diff --git a/core/DB/MyImprovedDialect.class.php b/core/DB/MyImprovedDialect.class.php
index 6b3f0c616c..2f097cb074 100644
--- a/core/DB/MyImprovedDialect.class.php
+++ b/core/DB/MyImprovedDialect.class.php
@@ -27,18 +27,12 @@ public function quoteValue($value)
 				return "''"; // instead of 'null', to be compatible with v. 4
 			
 			return
-				"'"
-				.mysqli_real_escape_string(
-					// can't find better way atm.
-					$this->getLink(),
-					$value
-				)
-				."'";
+				"'".mysqli_real_escape_string($this->getLink(), $value)."'";
 		}
 		
 		public function quoteBinary($data)
 		{
-			return mysqli_real_escape_string(DBPool::me()->getLink()->getLink(), $data);
+			return "'".mysqli_real_escape_string($this->getLink(), $data)."'";
 		}
 	}
 ?>
\ No newline at end of file
diff --git a/core/DB/MySQLim.class.php b/core/DB/MySQLim.class.php
index 2bf6d664d6..fe696c344c 100644
--- a/core/DB/MySQLim.class.php
+++ b/core/DB/MySQLim.class.php
@@ -20,6 +20,7 @@
 	final class MySQLim extends Sequenceless
 	{
 		private $needAutoCommit = false;
+		private $defaultEngine;
 
 		/**
 		 * @return MySQLim
@@ -42,6 +43,17 @@ public function setNeedAutoCommit($flag)
 			return $this;
 		}
 
+		/**
+		 * @param string $engine
+		 * @return MySQLim
+		 */
+		public function setDefaultEngine($engine)
+		{
+			$this->defaultEngine = $engine;
+			$this->setupDefaultEngine();
+			return $this;
+		}
+
 		/**
 		 * @return $this
 		 * @throws DatabaseException
@@ -75,6 +87,7 @@ public function connect()
 				$this->setDbEncoding();
 
 			$this->setupAutoCommit();
+			$this->setupDefaultEngine();
 			
 			return $this;
 		}
@@ -92,7 +105,8 @@ public function disconnect()
 		
 		public function isConnected()
 		{
-			return parent::isConnected() && mysqli_ping($this->link);
+			return (parent::isConnected() || $this->link instanceof \mysqli)
+				&& mysqli_ping($this->link);
 		}
 		
 		/**
@@ -288,5 +302,12 @@ private function setupAutoCommit()
 				mysqli_autocommit($this->link, $this->needAutoCommit);
 			}
 		}
+
+		private function setupDefaultEngine()
+		{
+			if ($this->defaultEngine && $this->isConnected()) {
+				mysqli_query($this->link, 'SET storage_engine='.$this->defaultEngine);
+			}
+		}
 	}
 ?>
\ No newline at end of file
diff --git a/core/Form/Primitives/PrimitiveHttpUrl.class.php b/core/Form/Primitives/PrimitiveHttpUrl.class.php
index 7f9382abcc..706d4e125f 100644
--- a/core/Form/Primitives/PrimitiveHttpUrl.class.php
+++ b/core/Form/Primitives/PrimitiveHttpUrl.class.php
@@ -57,6 +57,8 @@ public function importValue($value)
 					$this->import(
 						array($this->getName() => $value->toString())
 					);
+			} elseif (is_scalar($value)) {
+				return parent::importValue($value);
 			}
 			
 			return parent::importValue(null);
diff --git a/main/Net/Http/HttpClient.class.php b/main/Net/Http/HttpClient.class.php
index a7e2f4a549..525c789932 100644
--- a/main/Net/Http/HttpClient.class.php
+++ b/main/Net/Http/HttpClient.class.php
@@ -15,7 +15,7 @@
 	interface HttpClient
 	{
 		/**
-		 * @param $timeout in seconds
+		 * @param $timeout int in seconds
 		**/
 		public function setTimeout($timeout);
 		public function getTimeout();
@@ -33,8 +33,40 @@ public function setMaxRedirects($maxRedirects);
 		public function getMaxRedirects();
 		
 		/**
+		 * @param $request HttpRequest
 		 * @return HttpResponse
 		**/
 		public function send(HttpRequest $request);
+
+		/**
+		 * @param $key string
+		 * @param $value string
+		 * @return CurlHttpClient
+		**/
+		public function setOption($key, $value);
+
+		/**
+		 * @param $key string
+		 * @return CurlHttpClient
+		**/
+		public function dropOption($key);
+
+		public function getOption($key);
+
+		/**
+		 * @param $really boolean
+		 * @return CurlHttpClient
+		**/
+		public function setNoBody($really);
+
+		public function hasNoBody();
+
+		/**
+		 * @param $maxFileSize int
+		 * @return CurlHttpClient
+		**/
+		public function setMaxFileSize($maxFileSize);
+
+		public function getMaxFileSize();
 	}
 ?>
\ No newline at end of file
diff --git a/main/Net/Mail/Mail.class.php b/main/Net/Mail/Mail.class.php
index a3530783bd..580bd2d86e 100644
--- a/main/Net/Mail/Mail.class.php
+++ b/main/Net/Mail/Mail.class.php
@@ -26,6 +26,7 @@ final class Mail
 		private $encoding		= null;
 		private $contentType	= null;
 		private $returnPath		= null;
+		private $headers        = null;
 		
 		private $sendmailAdditionalArgs	= null;
 		
@@ -104,17 +105,21 @@ public function send()
 			
 			if ($this->cc != null)
 				$headers .= "Cc: ".$this->cc."\n";
-			
-			if ($this->contentType === null)
-				$this->contentType = 'text/plain';
-			
-			$headers .=
-				"Content-type: ".$this->contentType
-				."; charset=".$encoding."\n";
-			
-			$headers .= "Content-Transfer-Encoding: 8bit\n";
-			$headers .= "Date: ".date('r')."\n";
-			
+
+			if (!$this->getHeaders()) {
+				if ($this->contentType === null)
+					$this->contentType = 'text/plain';
+
+				$headers .=
+					"Content-type: ".$this->contentType
+					."; charset=".$encoding."\n";
+
+				$headers .= "Content-Transfer-Encoding: 8bit\n";
+				$headers .= "Date: ".date('r')."\n";
+			} else {
+				$headers .= $this->getHeaders();
+			}
+
 			if (
 				!mail(
 					$to, $subject, $body, $headers,
@@ -221,5 +226,19 @@ public function setReturnPath($returnPath)
 			$this->returnPath = $returnPath;
 			return $this;
 		}
+
+		public function setHeaders($headers)
+		{
+			$this->headers = $headers;
+			return $this;
+		}
+
+		/**
+		 * @return null
+		 */
+		public function getHeaders()
+		{
+			return $this->headers;
+		}
 	}
-?>
\ No newline at end of file
+?>
diff --git a/main/Utils/IO/StringInputStream.class.php b/main/Utils/IO/StringInputStream.class.php
index 69e7c637be..18431e13c7 100644
--- a/main/Utils/IO/StringInputStream.class.php
+++ b/main/Utils/IO/StringInputStream.class.php
@@ -82,7 +82,7 @@ public function read($count)
 				return null;
 			
 			if ($count == 1) {
-				$result = $this->string[$this->position];
+				$result = $this->string[(int)$this->position];
 			} else {
 				$result = substr($this->string, $this->position, $count);
 			}
diff --git a/test/config.inc.php.tpl b/test/config.inc.php.tpl
index 683dee0bf6..9f9b13e2a0 100644
--- a/test/config.inc.php.tpl
+++ b/test/config.inc.php.tpl
@@ -7,7 +7,7 @@
 			'host'	=> '127.0.0.1',
 			'base'	=> 'onphp'
 		),
-		'MySQL' => array(
+		'MySQLim' => array(
 			'user'	=> 'onphp',
 			'pass'	=> 'onphp',
 			'host'	=> '127.0.0.1',
diff --git a/test/core/PrimitiveTimestampTZTest.class.php b/test/core/PrimitiveTimestampTZTest.class.php
index 1e850ebdfb..41530f9254 100644
--- a/test/core/PrimitiveTimestampTZTest.class.php
+++ b/test/core/PrimitiveTimestampTZTest.class.php
@@ -7,7 +7,7 @@ final class PrimitiveTimestampTZTest extends TestCase
 		public function testMarried()
 		{
 			$currentTimeZone = new DateTimeZone(date_default_timezone_get());
-			$now = new DateTime('now', $currentTimeZone);
+			$now = new DateTime('2012-02-01', $currentTimeZone);
 			$zone = $now->format('O');
 
 			$prm = Primitive::timestampTZ('test')->setComplex();
diff --git a/test/core/TruncateQueryTest.class.php b/test/core/TruncateQueryTest.class.php
index d43d4db9f5..6fba786640 100644
--- a/test/core/TruncateQueryTest.class.php
+++ b/test/core/TruncateQueryTest.class.php
@@ -6,7 +6,7 @@ final class TruncateQueryTest extends TestCaseDB
 		public function testQuery()
 		{
 			$pgDialect = $this->getDbByType('PgSQL')->getDialect();
-			$myDialect = $this->getDbByType('MySQL')->getDialect();
+			$myDialect = $this->getDbByType('MySQLim')->getDialect();
 			$liteDialect = $this->getDbByType('SQLitePDO')->getDialect();
 			
 			$query = OSQL::truncate('single_table');
diff --git a/test/db/InnerTransactionDBTest.class.php b/test/db/InnerTransactionDBTest.class.php
index 13c8708050..4c47a2dc00 100644
--- a/test/db/InnerTransactionDBTest.class.php
+++ b/test/db/InnerTransactionDBTest.class.php
@@ -1,6 +1,65 @@
 <?php
 	class InnerTransactionDBTest extends TestCaseDAO
 	{
+		public function setUp()
+		{
+			if (empty(DBTestPool::me()->getPool())) {
+				$this->fail('this test requires db in config');
+			}
+			parent::setUp();
+		}
+
+		public function testSavepoint()
+		{
+			foreach (DBTestPool::me()->getPool() as $connector => $db) {
+				/* @var $db DB */
+				DBPool::me()->setDefault($db);
+				$this->getDBCreator()->fillDB();
+
+				/* @var $moscow TestCity */
+				$moscow = TestCity::dao()->getByLogic(Expression::eq('name', 'Moscow'));
+
+				$savePointName = 'svp';
+				$db->begin();
+				$db->savepointBegin($savePointName);
+
+				$moscow->dao()->save($moscow->setName($newName = 'New Moscow'));
+
+				$db->savepointRelease($savePointName);
+				$db->commit();
+
+				$this->assertNotNull(TestCity::dao()->getByLogic(Expression::eq('name', $newName)));
+			}
+		}
+
+		public function testSavepointRollback()
+		{
+			foreach (DBTestPool::me()->getPool() as $connector => $db) {
+				/* @var $db DB */
+				DBPool::me()->setDefault($db);
+				$this->getDBCreator()->fillDB();
+
+				/* @var $moscow TestCity */
+				$moscow = TestCity::dao()->getByLogic(Expression::eq('name', 'Moscow'));
+
+				$savePointName = 'svp';
+				$db->begin();
+				$db->savepointBegin($savePointName);
+
+				$moscow->dao()->save($moscow->setName($newName = 'New Moscow'));
+
+				$db->savepointRollback($savePointName);
+				$db->commit();
+
+				try {
+					TestCity::dao()->getByLogic(Expression::eq('name', $newName));
+					$this->fail('expects object not found exception');
+				} catch (ObjectNotFoundException $e) {
+					/* ok */
+				}
+			}
+		}
+
 		public function testInnerTransaction()
 		{
 			foreach (DBTestPool::me()->getPool() as $connector => $db) {
diff --git a/test/main/Autoloader/AutoloaderClassPathCacheTest.class.php b/test/main/Autoloader/AutoloaderClassPathCacheTest.class.php
index 3dedc2b317..962af04557 100644
--- a/test/main/Autoloader/AutoloaderClassPathCacheTest.class.php
+++ b/test/main/Autoloader/AutoloaderClassPathCacheTest.class.php
@@ -47,8 +47,7 @@ public function testWithBaseException()
 			
 			//autoload without error, it's allow us to cache data
 			$service->autoload('Form');
-			
-			define('DEBUG', true);
+
 			//second autoload and here we throw error
 			$service->setNamespaceResolver($this->spawnResolver(array(
 				'getPathsCount' => 2,
diff --git a/test/main/OpenIdTest.class.php b/test/main/OpenIdTest.class.php
index d564ed06cb..98d1609c5f 100644
--- a/test/main/OpenIdTest.class.php
+++ b/test/main/OpenIdTest.class.php
@@ -273,5 +273,40 @@ public function send(HttpRequest $request)
 		{
 			return $this->response;
 		}
+
+		public function setOption($key, $value)
+		{
+			throw new UnsupportedMethodException();
+		}
+
+		public function dropOption($key)
+		{
+			throw new UnsupportedMethodException();
+		}
+
+		public function getOption($key)
+		{
+			throw new UnsupportedMethodException();
+		}
+
+		public function setNoBody($really)
+		{
+			throw new UnsupportedMethodException();
+		}
+
+		public function hasNoBody()
+		{
+			throw new UnsupportedMethodException();
+		}
+
+		public function setMaxFileSize($maxFileSize)
+		{
+			throw new UnsupportedMethodException();
+		}
+
+		public function getMaxFileSize()
+		{
+			throw new UnsupportedMethodException();
+		}
 	}
 ?>
\ No newline at end of file
diff --git a/test/misc/DBTestPool.class.php b/test/misc/DBTestPool.class.php
index c020b60cb1..eaf151179b 100644
--- a/test/misc/DBTestPool.class.php
+++ b/test/misc/DBTestPool.class.php
@@ -23,6 +23,9 @@ protected function __construct(array $dbs = array())
 					$credentials['host'],
 					$credentials['base']
 				);
+				if ($this->pool[$connector] instanceof MySQLim) {
+					$this->pool[$connector]->setDefaultEngine('INNODB');
+				}
 			}
 		}
 		
