From 4d2c2b4929926913219807cf68b92cd40b663efe Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 14:48:50 +0400
Subject: [PATCH 01/40] Update dependencies

---
 composer.lock | 725 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 530 insertions(+), 195 deletions(-)

diff --git a/composer.lock b/composer.lock
index f58e0d2cb..8258c993a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -366,32 +366,32 @@
     "packages-dev": [
         {
             "name": "doctrine/instantiator",
-            "version": "1.0.5",
+            "version": "1.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
+                "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
-                "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
+                "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3,<8.0-DEV"
+                "php": "^7.1"
             },
             "require-dev": {
                 "athletic/athletic": "~0.1.8",
                 "ext-pdo": "*",
                 "ext-phar": "*",
-                "phpunit/phpunit": "~4.0",
-                "squizlabs/php_codesniffer": "~2.0"
+                "phpunit/phpunit": "^6.2.3",
+                "squizlabs/php_codesniffer": "^3.0.2"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "1.2.x-dev"
                 }
             },
             "autoload": {
@@ -416,7 +416,154 @@
                 "constructor",
                 "instantiate"
             ],
-            "time": "2015-06-14T21:17:01+00:00"
+            "time": "2017-07-22T11:58:36+00:00"
+        },
+        {
+            "name": "myclabs/deep-copy",
+            "version": "1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/DeepCopy.git",
+                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
+                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "doctrine/collections": "^1.0",
+                "doctrine/common": "^2.6",
+                "phpunit/phpunit": "^4.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "DeepCopy\\": "src/DeepCopy/"
+                },
+                "files": [
+                    "src/DeepCopy/deep_copy.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Create deep copies (clones) of your objects",
+            "keywords": [
+                "clone",
+                "copy",
+                "duplicate",
+                "object",
+                "object graph"
+            ],
+            "time": "2017-10-19T19:58:43+00:00"
+        },
+        {
+            "name": "phar-io/manifest",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/manifest.git",
+                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
+                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-phar": "*",
+                "phar-io/version": "^1.0.1",
+                "php": "^5.6 || ^7.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+            "time": "2017-03-05T18:14:27+00:00"
+        },
+        {
+            "name": "phar-io/version",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phar-io/version.git",
+                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
+                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Heuer",
+                    "email": "sebastian@phpeople.de",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Library for handling version information and constraints",
+            "time": "2017-03-05T17:38:23+00:00"
         },
         {
             "name": "phpdocumentor/reflection-common",
@@ -474,29 +621,35 @@
         },
         {
             "name": "phpdocumentor/reflection-docblock",
-            "version": "3.2.2",
+            "version": "4.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157"
+                "reference": "94fd0001232e47129dd3504189fa1c7225010d08"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157",
-                "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
+                "reference": "94fd0001232e47129dd3504189fa1c7225010d08",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.5",
-                "phpdocumentor/reflection-common": "^1.0@dev",
-                "phpdocumentor/type-resolver": "^0.3.0",
+                "php": "^7.0",
+                "phpdocumentor/reflection-common": "^1.0.0",
+                "phpdocumentor/type-resolver": "^0.4.0",
                 "webmozart/assert": "^1.0"
             },
             "require-dev": {
-                "mockery/mockery": "^0.9.4",
-                "phpunit/phpunit": "^4.4"
+                "doctrine/instantiator": "~1.0.5",
+                "mockery/mockery": "^1.0",
+                "phpunit/phpunit": "^6.4"
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.x-dev"
+                }
+            },
             "autoload": {
                 "psr-4": {
                     "phpDocumentor\\Reflection\\": [
@@ -515,20 +668,20 @@
                 }
             ],
             "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2017-08-08T06:39:58+00:00"
+            "time": "2017-11-30T07:14:17+00:00"
         },
         {
             "name": "phpdocumentor/type-resolver",
-            "version": "0.3.0",
+            "version": "0.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/TypeResolver.git",
-                "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773"
+                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773",
-                "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773",
+                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
+                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
                 "shasum": ""
             },
             "require": {
@@ -562,27 +715,27 @@
                     "email": "me@mikevanriel.com"
                 }
             ],
-            "time": "2017-06-03T08:32:36+00:00"
+            "time": "2017-07-14T14:27:02+00:00"
         },
         {
             "name": "phpspec/prophecy",
-            "version": "1.7.5",
+            "version": "1.7.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401"
+                "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401",
-                "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
+                "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
                 "shasum": ""
             },
             "require": {
                 "doctrine/instantiator": "^1.0.2",
                 "php": "^5.3|^7.0",
                 "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
-                "sebastian/comparator": "^1.1|^2.0",
+                "sebastian/comparator": "^1.1|^2.0|^3.0",
                 "sebastian/recursion-context": "^1.0|^2.0|^3.0"
             },
             "require-dev": {
@@ -625,43 +778,44 @@
                 "spy",
                 "stub"
             ],
-            "time": "2018-02-19T10:16:54+00:00"
+            "time": "2018-04-18T13:57:24+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "2.2.4",
+            "version": "6.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+                "reference": "774a82c0c5da4c1c7701790c262035d235ab7856"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/774a82c0c5da4c1c7701790c262035d235ab7856",
+                "reference": "774a82c0c5da4c1c7701790c262035d235ab7856",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3",
-                "phpunit/php-file-iterator": "~1.3",
-                "phpunit/php-text-template": "~1.2",
-                "phpunit/php-token-stream": "~1.3",
-                "sebastian/environment": "^1.3.2",
-                "sebastian/version": "~1.0"
+                "ext-dom": "*",
+                "ext-xmlwriter": "*",
+                "php": "^7.1",
+                "phpunit/php-file-iterator": "^1.4.2",
+                "phpunit/php-text-template": "^1.2.1",
+                "phpunit/php-token-stream": "^3.0",
+                "sebastian/code-unit-reverse-lookup": "^1.0.1",
+                "sebastian/environment": "^3.1",
+                "sebastian/version": "^2.0.1",
+                "theseer/tokenizer": "^1.1"
             },
             "require-dev": {
-                "ext-xdebug": ">=2.1.4",
-                "phpunit/phpunit": "~4"
+                "phpunit/phpunit": "^7.0"
             },
             "suggest": {
-                "ext-dom": "*",
-                "ext-xdebug": ">=2.2.1",
-                "ext-xmlwriter": "*"
+                "ext-xdebug": "^2.6.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.2.x-dev"
+                    "dev-master": "6.0-dev"
                 }
             },
             "autoload": {
@@ -676,7 +830,7 @@
             "authors": [
                 {
                     "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
+                    "email": "sebastian@phpunit.de",
                     "role": "lead"
                 }
             ],
@@ -687,7 +841,7 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2015-10-06T15:47:00+00:00"
+            "time": "2018-04-06T15:39:20+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -779,28 +933,28 @@
         },
         {
             "name": "phpunit/php-timer",
-            "version": "1.0.9",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
+                "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
-                "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f",
+                "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3.3 || ^7.0"
+                "php": "^7.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+                "phpunit/phpunit": "^7.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-master": "2.0-dev"
                 }
             },
             "autoload": {
@@ -815,7 +969,7 @@
             "authors": [
                 {
                     "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
+                    "email": "sebastian@phpunit.de",
                     "role": "lead"
                 }
             ],
@@ -824,33 +978,33 @@
             "keywords": [
                 "timer"
             ],
-            "time": "2017-02-26T11:10:40+00:00"
+            "time": "2018-02-01T13:07:23+00:00"
         },
         {
             "name": "phpunit/php-token-stream",
-            "version": "1.4.12",
+            "version": "3.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
+                "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
-                "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace",
+                "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace",
                 "shasum": ""
             },
             "require": {
                 "ext-tokenizer": "*",
-                "php": ">=5.3.3"
+                "php": "^7.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.2"
+                "phpunit/phpunit": "^7.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.4-dev"
+                    "dev-master": "3.0-dev"
                 }
             },
             "autoload": {
@@ -873,45 +1027,53 @@
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2017-12-04T08:55:13+00:00"
+            "time": "2018-02-01T13:16:43+00:00"
         },
         {
             "name": "phpunit/phpunit",
-            "version": "4.8.36",
+            "version": "7.1.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "46023de9a91eec7dfb06cc56cb4e260017298517"
+                "reference": "6d51299e307dc510149e0b7cd1931dd11770e1cb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517",
-                "reference": "46023de9a91eec7dfb06cc56cb4e260017298517",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6d51299e307dc510149e0b7cd1931dd11770e1cb",
+                "reference": "6d51299e307dc510149e0b7cd1931dd11770e1cb",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-json": "*",
-                "ext-pcre": "*",
-                "ext-reflection": "*",
-                "ext-spl": "*",
-                "php": ">=5.3.3",
-                "phpspec/prophecy": "^1.3.1",
-                "phpunit/php-code-coverage": "~2.1",
-                "phpunit/php-file-iterator": "~1.4",
-                "phpunit/php-text-template": "~1.2",
-                "phpunit/php-timer": "^1.0.6",
-                "phpunit/phpunit-mock-objects": "~2.3",
-                "sebastian/comparator": "~1.2.2",
-                "sebastian/diff": "~1.2",
-                "sebastian/environment": "~1.3",
-                "sebastian/exporter": "~1.2",
-                "sebastian/global-state": "~1.0",
-                "sebastian/version": "~1.0",
-                "symfony/yaml": "~2.1|~3.0"
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-xml": "*",
+                "myclabs/deep-copy": "^1.6.1",
+                "phar-io/manifest": "^1.0.1",
+                "phar-io/version": "^1.0",
+                "php": "^7.1",
+                "phpspec/prophecy": "^1.7",
+                "phpunit/php-code-coverage": "^6.0.1",
+                "phpunit/php-file-iterator": "^1.4.3",
+                "phpunit/php-text-template": "^1.2.1",
+                "phpunit/php-timer": "^2.0",
+                "phpunit/phpunit-mock-objects": "^6.1.1",
+                "sebastian/comparator": "^2.1 || ^3.0",
+                "sebastian/diff": "^3.0",
+                "sebastian/environment": "^3.1",
+                "sebastian/exporter": "^3.1",
+                "sebastian/global-state": "^2.0",
+                "sebastian/object-enumerator": "^3.0.3",
+                "sebastian/resource-operations": "^1.0",
+                "sebastian/version": "^2.0.1"
+            },
+            "require-dev": {
+                "ext-pdo": "*"
             },
             "suggest": {
-                "phpunit/php-invoker": "~1.1"
+                "ext-xdebug": "*",
+                "phpunit/php-invoker": "^2.0"
             },
             "bin": [
                 "phpunit"
@@ -919,7 +1081,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.8.x-dev"
+                    "dev-master": "7.1-dev"
                 }
             },
             "autoload": {
@@ -945,30 +1107,30 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2017-06-21T08:07:12+00:00"
+            "time": "2018-04-18T13:41:53+00:00"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
-            "version": "2.3.8",
+            "version": "6.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+                "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/70c740bde8fd9ea9ea295be1cd875dd7b267e157",
+                "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157",
                 "shasum": ""
             },
             "require": {
-                "doctrine/instantiator": "^1.0.2",
-                "php": ">=5.3.3",
-                "phpunit/php-text-template": "~1.2",
-                "sebastian/exporter": "~1.2"
+                "doctrine/instantiator": "^1.0.5",
+                "php": "^7.1",
+                "phpunit/php-text-template": "^1.2.1",
+                "sebastian/exporter": "^3.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.4"
+                "phpunit/phpunit": "^7.0"
             },
             "suggest": {
                 "ext-soap": "*"
@@ -976,7 +1138,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.3.x-dev"
+                    "dev-master": "6.1-dev"
                 }
             },
             "autoload": {
@@ -991,7 +1153,7 @@
             "authors": [
                 {
                     "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
+                    "email": "sebastian@phpunit.de",
                     "role": "lead"
                 }
             ],
@@ -1001,34 +1163,79 @@
                 "mock",
                 "xunit"
             ],
-            "time": "2015-10-02T06:51:40+00:00"
+            "time": "2018-04-11T04:50:36+00:00"
+        },
+        {
+            "name": "sebastian/code-unit-reverse-lookup",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7 || ^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Looks up which function or method a line of code belongs to",
+            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+            "time": "2017-03-04T06:30:41+00:00"
         },
         {
             "name": "sebastian/comparator",
-            "version": "1.2.4",
+            "version": "3.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
+                "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
-                "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ed5fd2281113729f1ebcc64d101ad66028aeb3d5",
+                "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3",
-                "sebastian/diff": "~1.2",
-                "sebastian/exporter": "~1.2 || ~2.0"
+                "php": "^7.1",
+                "sebastian/diff": "^3.0",
+                "sebastian/exporter": "^3.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.4"
+                "phpunit/phpunit": "^7.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.2.x-dev"
+                    "dev-master": "3.0-dev"
                 }
             },
             "autoload": {
@@ -1059,38 +1266,39 @@
                 }
             ],
             "description": "Provides the functionality to compare PHP values for equality",
-            "homepage": "http://www.github.com/sebastianbergmann/comparator",
+            "homepage": "https://github.com/sebastianbergmann/comparator",
             "keywords": [
                 "comparator",
                 "compare",
                 "equality"
             ],
-            "time": "2017-01-29T09:50:25+00:00"
+            "time": "2018-04-18T13:33:00+00:00"
         },
         {
             "name": "sebastian/diff",
-            "version": "1.4.3",
+            "version": "3.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
+                "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
-                "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8",
+                "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3.3 || ^7.0"
+                "php": "^7.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
+                "phpunit/phpunit": "^7.0",
+                "symfony/process": "^2 || ^3.3 || ^4"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.4-dev"
+                    "dev-master": "3.0-dev"
                 }
             },
             "autoload": {
@@ -1115,34 +1323,37 @@
             "description": "Diff implementation",
             "homepage": "https://github.com/sebastianbergmann/diff",
             "keywords": [
-                "diff"
+                "diff",
+                "udiff",
+                "unidiff",
+                "unified diff"
             ],
-            "time": "2017-05-22T07:24:03+00:00"
+            "time": "2018-02-01T13:45:15+00:00"
         },
         {
             "name": "sebastian/environment",
-            "version": "1.3.8",
+            "version": "3.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
+                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
-                "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
+                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3.3 || ^7.0"
+                "php": "^7.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.8 || ^5.0"
+                "phpunit/phpunit": "^6.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.3.x-dev"
+                    "dev-master": "3.1.x-dev"
                 }
             },
             "autoload": {
@@ -1167,34 +1378,34 @@
                 "environment",
                 "hhvm"
             ],
-            "time": "2016-08-18T05:49:44+00:00"
+            "time": "2017-07-01T08:51:00+00:00"
         },
         {
             "name": "sebastian/exporter",
-            "version": "1.2.2",
+            "version": "3.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
+                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
-                "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937",
+                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3",
-                "sebastian/recursion-context": "~1.0"
+                "php": "^7.0",
+                "sebastian/recursion-context": "^3.0"
             },
             "require-dev": {
                 "ext-mbstring": "*",
-                "phpunit/phpunit": "~4.4"
+                "phpunit/phpunit": "^6.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.3.x-dev"
+                    "dev-master": "3.1.x-dev"
                 }
             },
             "autoload": {
@@ -1234,27 +1445,27 @@
                 "export",
                 "exporter"
             ],
-            "time": "2016-06-17T09:04:28+00:00"
+            "time": "2017-04-03T13:19:02+00:00"
         },
         {
             "name": "sebastian/global-state",
-            "version": "1.1.1",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
-                "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
+                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
+                "php": "^7.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.2"
+                "phpunit/phpunit": "^6.0"
             },
             "suggest": {
                 "ext-uopz": "*"
@@ -1262,7 +1473,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-master": "2.0-dev"
                 }
             },
             "autoload": {
@@ -1285,32 +1496,124 @@
             "keywords": [
                 "global state"
             ],
-            "time": "2015-10-12T03:26:01+00:00"
+            "time": "2017-04-27T15:39:26+00:00"
+        },
+        {
+            "name": "sebastian/object-enumerator",
+            "version": "3.0.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0",
+                "sebastian/object-reflector": "^1.1.1",
+                "sebastian/recursion-context": "^3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+            "time": "2017-08-03T12:35:26+00:00"
+        },
+        {
+            "name": "sebastian/object-reflector",
+            "version": "1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-reflector.git",
+                "reference": "773f97c67f28de00d397be301821b06708fca0be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
+                "reference": "773f97c67f28de00d397be301821b06708fca0be",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Allows reflection of object attributes, including inherited and non-public ones",
+            "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+            "time": "2017-03-29T09:07:27+00:00"
         },
         {
             "name": "sebastian/recursion-context",
-            "version": "1.0.5",
+            "version": "3.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7"
+                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
-                "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
+                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
+                "php": "^7.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.4"
+                "phpunit/phpunit": "^6.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "3.0.x-dev"
                 }
             },
             "autoload": {
@@ -1338,23 +1641,73 @@
             ],
             "description": "Provides functionality to recursively process PHP variables",
             "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2016-10-03T07:41:43+00:00"
+            "time": "2017-03-03T06:23:57+00:00"
+        },
+        {
+            "name": "sebastian/resource-operations",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/resource-operations.git",
+                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                }
+            ],
+            "description": "Provides a list of PHP built-in functions that operate on resources",
+            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+            "time": "2015-07-28T20:34:47+00:00"
         },
         {
             "name": "sebastian/version",
-            "version": "1.0.6",
+            "version": "2.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
+                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
                 "shasum": ""
             },
+            "require": {
+                "php": ">=5.6"
+            },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
             "autoload": {
                 "classmap": [
                     "src/"
@@ -1373,7 +1726,7 @@
             ],
             "description": "Library that helps with managing the version number of Git-hosted PHP projects",
             "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2015-06-21T13:59:46+00:00"
+            "time": "2016-10-03T07:35:21+00:00"
         },
         {
             "name": "squizlabs/php_codesniffer",
@@ -1427,62 +1780,44 @@
             "time": "2018-02-20T21:35:23+00:00"
         },
         {
-            "name": "symfony/yaml",
-            "version": "v3.4.6",
+            "name": "theseer/tokenizer",
+            "version": "1.1.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/symfony/yaml.git",
-                "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb"
+                "url": "https://github.com/theseer/tokenizer.git",
+                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/6af42631dcf89e9c616242c900d6c52bd53bd1bb",
-                "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb",
+                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b",
+                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.5.9|>=7.0.8"
-            },
-            "conflict": {
-                "symfony/console": "<3.4"
-            },
-            "require-dev": {
-                "symfony/console": "~3.4|~4.0"
-            },
-            "suggest": {
-                "symfony/console": "For validating YAML files using the lint command"
+                "ext-dom": "*",
+                "ext-tokenizer": "*",
+                "ext-xmlwriter": "*",
+                "php": "^7.0"
             },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
             "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Yaml\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
+                "classmap": [
+                    "src/"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "MIT"
+                "BSD-3-Clause"
             ],
             "authors": [
                 {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
+                    "name": "Arne Blankerts",
+                    "email": "arne@blankerts.de",
+                    "role": "Developer"
                 }
             ],
-            "description": "Symfony Yaml Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-02-16T09:50:28+00:00"
+            "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+            "time": "2017-04-07T12:08:54+00:00"
         },
         {
             "name": "webmozart/assert",

From 3783e75f5752833b4bf1a3c59c90a67108bdc024 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 15:10:30 +0400
Subject: [PATCH 02/40] Drop support for PHP 5.5

This version is no longer supported. Users of this release should upgrade as soon as possible, as they may be exposed to unpatched security vulnerabilities. http://php.net/supported-versions.php
---
 .travis.yml   | 1 -
 README.md     | 2 +-
 composer.json | 3 ++-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 5aaf587c6..2a2e57815 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,7 +10,6 @@ cache:
     - "$HOME/.composer/cache"
 
 php:
-  - 5.5
   - 5.6
   - 7.0
   - 7.1
diff --git a/README.md b/README.md
index 54414b0ef..87d9f9d40 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
 [![Latest Stable Version](https://img.shields.io/packagist/v/Longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot)
 [![Total Downloads](https://img.shields.io/packagist/dt/Longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot)
 [![Downloads Month](https://img.shields.io/packagist/dm/Longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot)
-[![Minimum PHP Version](http://img.shields.io/badge/php-%3E%3D5.6-8892BF.svg)](https://php.net/)
+[![Minimum PHP Version](http://img.shields.io/badge/php-%3E%3D5.6.4-8892BF.svg)](https://php.net/)
 [![License](https://img.shields.io/packagist/l/Longman/telegram-bot.svg)](https://github.com/php-telegram-bot/core/LICENSE.md)
 
 
diff --git a/composer.json b/composer.json
index bc8055478..572036683 100644
--- a/composer.json
+++ b/composer.json
@@ -18,11 +18,12 @@
         }
     ],
     "require": {
-        "php": "^5.5|^7.0",
+        "php": ">=5.6.4|^7.0",
         "ext-pdo": "*",
         "ext-curl": "*",
         "ext-mbstring": "*",
         "monolog/monolog": "^1.23",
+        "monolog/monolog": "^1.23",
         "guzzlehttp/guzzle": "^6.3"
     },
     "require-dev": {

From 3ea4b04867f0a65fdc7a04fd20e1e5a22825acc3 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 15:58:26 +0400
Subject: [PATCH 03/40] Move Request class inside http namespace

---
 src/Commands/AdminCommands/ChatsCommand.php   |  20 +-
 src/Commands/AdminCommands/CleanupCommand.php |  16 +-
 src/Commands/AdminCommands/DebugCommand.php   |   4 +-
 .../AdminCommands/SendtoallCommand.php        |   6 +-
 .../AdminCommands/SendtochannelCommand.php    |  72 +++---
 src/Commands/AdminCommands/WhoisCommand.php   |   2 +-
 src/Commands/Command.php                      |   2 +-
 src/Commands/SystemCommand.php                |   2 +-
 .../SystemCommands/CallbackqueryCommand.php   |   2 +-
 .../SystemCommands/GenericCommand.php         |   1 -
 .../SystemCommands/GenericmessageCommand.php  |   4 +-
 .../SystemCommands/InlinequeryCommand.php     |   4 +-
 src/Commands/SystemCommands/StartCommand.php  |   1 -
 src/Entities/CallbackQuery.php                |   5 +-
 src/Entities/InlineQuery.php                  |   4 +-
 src/Entities/Payments/PreCheckoutQuery.php    |   4 +-
 src/Entities/Payments/ShippingQuery.php       |   4 +-
 src/{ => Http}/Request.php                    | 223 ++++++++++++------
 .../CustomTestCommands/HiddenCommand.php      |   2 +-
 .../CustomTestCommands/VisibleCommand.php     |   2 +-
 tests/unit/Entities/ServerResponseTest.php    |  10 +-
 21 files changed, 227 insertions(+), 163 deletions(-)
 rename src/{ => Http}/Request.php (72%)

diff --git a/src/Commands/AdminCommands/ChatsCommand.php b/src/Commands/AdminCommands/ChatsCommand.php
index b5c02d1c7..3d610d692 100644
--- a/src/Commands/AdminCommands/ChatsCommand.php
+++ b/src/Commands/AdminCommands/ChatsCommand.php
@@ -13,7 +13,7 @@
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Entities\Chat;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 class ChatsCommand extends AdminCommand
 {
@@ -53,7 +53,7 @@ public function execute()
         $message = $this->getMessage();
 
         $chat_id = $message->getChat()->getId();
-        $text    = trim($message->getText(true));
+        $text = trim($message->getText(true));
 
         $results = DB::selectChats([
             'groups'      => true,
@@ -63,14 +63,14 @@ public function execute()
             'text'        => ($text === '' || $text === '*') ? null : $text //Text to search in user/group name
         ]);
 
-        $user_chats       = 0;
-        $group_chats      = 0;
+        $user_chats = 0;
+        $group_chats = 0;
         $supergroup_chats = 0;
-        $channel_chats    = 0;
+        $channel_chats = 0;
 
         if ($text === '') {
             $text_back = '';
-        } elseif ($text === '*') {
+        } else if ($text === '*') {
             $text_back = 'List of all bot chats:' . PHP_EOL;
         } else {
             $text_back = 'Chat search results:' . PHP_EOL;
@@ -80,7 +80,7 @@ public function execute()
             foreach ($results as $result) {
                 //Initialize a chat object
                 $result['id'] = $result['chat_id'];
-                $chat         = new Chat($result);
+                $chat = new Chat($result);
 
                 $whois = $chat->getId();
                 if ($this->telegram->getCommandObject('whois')) {
@@ -94,19 +94,19 @@ public function execute()
                     }
 
                     ++$user_chats;
-                } elseif ($chat->isSuperGroup()) {
+                } else if ($chat->isSuperGroup()) {
                     if ($text !== '') {
                         $text_back .= '- S ' . $chat->getTitle() . ' [' . $whois . ']' . PHP_EOL;
                     }
 
                     ++$supergroup_chats;
-                } elseif ($chat->isGroupChat()) {
+                } else if ($chat->isGroupChat()) {
                     if ($text !== '') {
                         $text_back .= '- G ' . $chat->getTitle() . ' [' . $whois . ']' . PHP_EOL;
                     }
 
                     ++$group_chats;
-                } elseif ($chat->isChannel()) {
+                } else if ($chat->isChannel()) {
                     if ($text !== '') {
                         $text_back .= '- C ' . $chat->getTitle() . ' [' . $whois . ']' . PHP_EOL;
                     }
diff --git a/src/Commands/AdminCommands/CleanupCommand.php b/src/Commands/AdminCommands/CleanupCommand.php
index 171da4d83..332d1fa06 100644
--- a/src/Commands/AdminCommands/CleanupCommand.php
+++ b/src/Commands/AdminCommands/CleanupCommand.php
@@ -13,7 +13,7 @@
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Exception\TelegramException;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 use Longman\TelegramBot\TelegramLog;
 use PDOException;
 
@@ -108,13 +108,13 @@ class CleanupCommand extends AdminCommand
      */
     private function getSettings($custom_time = '')
     {
-        $tables_to_clean      = self::$default_tables_to_clean;
+        $tables_to_clean = self::$default_tables_to_clean;
         $user_tables_to_clean = $this->getConfig('tables_to_clean');
         if (is_array($user_tables_to_clean)) {
             $tables_to_clean = $user_tables_to_clean;
         }
 
-        $clean_older_than      = self::$default_clean_older_than;
+        $clean_older_than = self::$default_clean_older_than;
         $user_clean_older_than = $this->getConfig('clean_older_than');
         if (is_array($user_clean_older_than)) {
             $clean_older_than = array_merge($clean_older_than, $user_clean_older_than);
@@ -122,7 +122,7 @@ private function getSettings($custom_time = '')
 
         // Convert numeric-only values to days.
         array_walk($clean_older_than, function (&$time) use ($custom_time) {
-            if (!empty($custom_time)) {
+            if (! empty($custom_time)) {
                 $time = $custom_time;
             }
             if (is_numeric($time)) {
@@ -143,7 +143,7 @@ private function getSettings($custom_time = '')
      */
     private function getQueries($settings)
     {
-        if (empty($settings) || !is_array($settings)) {
+        if (empty($settings) || ! is_array($settings)) {
             throw new TelegramException('Settings variable is not an array or is empty!');
         }
 
@@ -352,7 +352,7 @@ public function execute()
     {
         $message = $this->getMessage();
         $user_id = $message->getFrom()->getId();
-        $text    = $message->getText(true);
+        $text = $message->getText(true);
 
         $data = [
             'chat_id'    => $user_id,
@@ -360,7 +360,7 @@ public function execute()
         ];
 
         $settings = $this->getSettings($text);
-        $queries  = $this->getQueries($settings);
+        $queries = $this->getQueries($settings);
 
         $infos = [];
         foreach ($settings['tables_to_clean'] as $table) {
@@ -378,7 +378,7 @@ public function execute()
         Request::sendMessage($data);
 
         $rows = 0;
-        $pdo  = DB::getPdo();
+        $pdo = DB::getPdo();
         try {
             $pdo->beginTransaction();
 
diff --git a/src/Commands/AdminCommands/DebugCommand.php b/src/Commands/AdminCommands/DebugCommand.php
index ec9b0d831..c00185a88 100644
--- a/src/Commands/AdminCommands/DebugCommand.php
+++ b/src/Commands/AdminCommands/DebugCommand.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\DB;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Admin "/debug" command
@@ -54,7 +54,7 @@ public function execute()
 
         $data = ['chat_id' => $chat->getId()];
 
-        if ($text !== 'glasnost' && !$chat->isPrivateChat()) {
+        if ($text !== 'glasnost' && ! $chat->isPrivateChat()) {
             $data['text'] = 'Only available in a private chat.';
 
             return Request::sendMessage($data);
diff --git a/src/Commands/AdminCommands/SendtoallCommand.php b/src/Commands/AdminCommands/SendtoallCommand.php
index a05a56658..846458008 100644
--- a/src/Commands/AdminCommands/SendtoallCommand.php
+++ b/src/Commands/AdminCommands/SendtoallCommand.php
@@ -13,7 +13,7 @@
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\Entities\Message;
 use Longman\TelegramBot\Entities\ServerResponse;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Admin "/sendtoall" command
@@ -75,7 +75,7 @@ public function execute()
             return $this->replyToChat('No users or chats found.');
         }
 
-        $total  = 0;
+        $total = 0;
         $failed = 0;
 
         $text = 'Message sent to:' . PHP_EOL;
@@ -88,7 +88,7 @@ public function execute()
 
                 /** @var Message $message */
                 $message = $result->getResult();
-                $chat    = $message->getChat();
+                $chat = $message->getChat();
                 if ($chat->isPrivateChat()) {
                     $name = $chat->getFirstName();
                     $type = 'user';
diff --git a/src/Commands/AdminCommands/SendtochannelCommand.php b/src/Commands/AdminCommands/SendtochannelCommand.php
index d8d3de78e..2990a7d16 100644
--- a/src/Commands/AdminCommands/SendtochannelCommand.php
+++ b/src/Commands/AdminCommands/SendtochannelCommand.php
@@ -15,7 +15,7 @@
 use Longman\TelegramBot\Entities\Chat;
 use Longman\TelegramBot\Entities\Keyboard;
 use Longman\TelegramBot\Entities\Message;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 class SendtochannelCommand extends AdminCommand
 {
@@ -68,7 +68,7 @@ public function execute()
         // if the command is recalled when the conversation is already started
         in_array($type, ['command', 'text'], true) && $type = 'message';
 
-        $text           = trim($message->getText(true));
+        $text = trim($message->getText(true));
         $text_yes_or_no = ($text === 'Yes' || $text === 'No');
 
         $data = [
@@ -79,13 +79,13 @@ public function execute()
         $this->conversation = new Conversation($user_id, $chat_id, $this->getName());
 
         $notes = &$this->conversation->notes;
-        !is_array($notes) && $notes = [];
+        ! is_array($notes) && $notes = [];
 
         $channels = (array) $this->getConfig('your_channel');
         if (isset($notes['state'])) {
             $state = $notes['state'];
         } else {
-            $state                    = (count($channels) === 0) ? -1 : 0;
+            $state = (count($channels) === 0) ? -1 : 0;
             $notes['last_message_id'] = $message->getMessageId();
         }
 
@@ -115,7 +115,7 @@ public function execute()
 
                     break;
                 }
-                $notes['channel']         = $text;
+                $notes['channel'] = $text;
                 $notes['last_message_id'] = $message->getMessageId();
                 // Jump to state 1
                 goto insert;
@@ -149,7 +149,7 @@ public function execute()
                     );
                     break;
                 }
-                $notes['channel']         = $text;
+                $notes['channel'] = $text;
                 $notes['last_message_id'] = $message->getMessageId();
 
             // no break
@@ -166,21 +166,21 @@ public function execute()
                     break;
                 }
                 $notes['last_message_id'] = $message->getMessageId();
-                $notes['message']         = $message->getRawData();
-                $notes['message_type']    = $type;
+                $notes['message'] = $message->getRawData();
+                $notes['message_type'] = $type;
             // no break
             case 2:
-                if (!$text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
+                if (! $text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
                     $notes['state'] = 2;
                     $this->conversation->update();
 
                     // Grab any existing caption.
                     if ($caption = $message->getCaption()) {
                         $notes['caption'] = $caption;
-                        $text             = 'No';
-                    } elseif (in_array($notes['message_type'], ['video', 'photo'], true)) {
+                        $text = 'No';
+                    } else if (in_array($notes['message_type'], ['video', 'photo'], true)) {
                         $text = 'Would you like to insert a caption?';
-                        if (!$text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
+                        if (! $text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
                             $text .= PHP_EOL . 'Type Yes or No';
                         }
 
@@ -191,7 +191,7 @@ public function execute()
                         break;
                     }
                 }
-                $notes['set_caption']     = ($text === 'Yes');
+                $notes['set_caption'] = ($text === 'Yes');
                 $notes['last_message_id'] = $message->getMessageId();
             // no break
             case 3:
@@ -214,7 +214,7 @@ public function execute()
                 }
             // no break
             case 4:
-                if (!$text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
+                if (! $text_yes_or_no || $notes['last_message_id'] === $message->getMessageId()) {
                     $notes['state'] = 4;
                     $this->conversation->update();
 
@@ -229,7 +229,7 @@ public function execute()
                         $data['reply_markup'] = $yes_no_keyboard;
 
                         $data['text'] = 'Would you like to post it?';
-                        if (!$text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
+                        if (! $text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
                             $data['text'] .= PHP_EOL . 'Type Yes or No';
                         }
                         $result = Request::sendMessage($data);
@@ -237,7 +237,7 @@ public function execute()
                     break;
                 }
 
-                $notes['post_message']    = ($text === 'Yes');
+                $notes['post_message'] = ($text === 'Yes');
                 $notes['last_message_id'] = $message->getMessageId();
             // no break
             case 5:
@@ -245,7 +245,7 @@ public function execute()
 
                 if ($notes['post_message']) {
                     $data['parse_mode'] = 'markdown';
-                    $data['text']       = $this->publish(
+                    $data['text'] = $this->publish(
                         new Message($notes['message'], $this->telegram->getBotUsername()),
                         $notes['channel'],
                         $notes['caption']
@@ -273,7 +273,7 @@ public function execute()
      * @todo Looking for a more significant name
      *
      * @param \Longman\TelegramBot\Entities\Message $message
-     * @param array                                 $data
+     * @param array $data
      *
      * @return \Longman\TelegramBot\Entities\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -285,23 +285,23 @@ protected function sendBack(Message $message, array $data)
 
         if ($type === 'message') {
             $data['text'] = $message->getText(true);
-        } elseif ($type === 'audio') {
-            $data['audio']     = $message->getAudio()->getFileId();
-            $data['duration']  = $message->getAudio()->getDuration();
+        } else if ($type === 'audio') {
+            $data['audio'] = $message->getAudio()->getFileId();
+            $data['duration'] = $message->getAudio()->getDuration();
             $data['performer'] = $message->getAudio()->getPerformer();
-            $data['title']     = $message->getAudio()->getTitle();
-        } elseif ($type === 'document') {
+            $data['title'] = $message->getAudio()->getTitle();
+        } else if ($type === 'document') {
             $data['document'] = $message->getDocument()->getFileId();
-        } elseif ($type === 'photo') {
+        } else if ($type === 'photo') {
             $data['photo'] = $message->getPhoto()[0]->getFileId();
-        } elseif ($type === 'sticker') {
+        } else if ($type === 'sticker') {
             $data['sticker'] = $message->getSticker()->getFileId();
-        } elseif ($type === 'video') {
+        } else if ($type === 'video') {
             $data['video'] = $message->getVideo()->getFileId();
-        } elseif ($type === 'voice') {
+        } else if ($type === 'voice') {
             $data['voice'] = $message->getVoice()->getFileId();
-        } elseif ($type === 'location') {
-            $data['latitude']  = $message->getLocation()->getLatitude();
+        } else if ($type === 'location') {
+            $data['latitude'] = $message->getLocation()->getLatitude();
             $data['longitude'] = $message->getLocation()->getLongitude();
         }
 
@@ -312,8 +312,8 @@ protected function sendBack(Message $message, array $data)
      * Publish a message to a channel and return success or failure message in markdown format
      *
      * @param \Longman\TelegramBot\Entities\Message $message
-     * @param string|int                            $channel_id
-     * @param string|null                           $caption
+     * @param string|int $channel_id
+     * @param string|null $caption
      *
      * @return string
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -327,7 +327,7 @@ protected function publish(Message $message, $channel_id, $caption = null)
 
         if ($res->isOk()) {
             /** @var Chat $channel */
-            $channel          = $res->getResult()->getChat();
+            $channel = $res->getResult()->getChat();
             $escaped_username = $channel->getUsername() ? $this->getMessage()->escapeMarkdown($channel->getUsername()) : '';
 
             $response = sprintf(
@@ -337,9 +337,9 @@ protected function publish(Message $message, $channel_id, $caption = null)
             );
         } else {
             $escaped_username = $this->getMessage()->escapeMarkdown($channel_id);
-            $response         = "Message not sent to *{$escaped_username}*" . PHP_EOL .
-                                '- Does the channel exist?' . PHP_EOL .
-                                '- Is the bot an admin of the channel?';
+            $response = "Message not sent to *{$escaped_username}*" . PHP_EOL .
+                '- Does the channel exist?' . PHP_EOL .
+                '- Is the bot an admin of the channel?';
         }
 
         return $response;
@@ -356,7 +356,7 @@ protected function publish(Message $message, $channel_id, $caption = null)
     public function executeNoDb()
     {
         $message = $this->getMessage();
-        $text    = trim($message->getText(true));
+        $text = trim($message->getText(true));
 
         if ($text === '') {
             return $this->replyToChat('Usage: ' . $this->getUsage());
diff --git a/src/Commands/AdminCommands/WhoisCommand.php b/src/Commands/AdminCommands/WhoisCommand.php
index ad5e26155..453d41869 100644
--- a/src/Commands/AdminCommands/WhoisCommand.php
+++ b/src/Commands/AdminCommands/WhoisCommand.php
@@ -17,7 +17,7 @@
 use Longman\TelegramBot\Entities\Chat;
 use Longman\TelegramBot\Entities\PhotoSize;
 use Longman\TelegramBot\Entities\UserProfilePhotos;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Admin "/whois" command
diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index cd99cf469..3421c3be5 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -16,7 +16,7 @@
 use Longman\TelegramBot\Entities\InlineQuery;
 use Longman\TelegramBot\Entities\Message;
 use Longman\TelegramBot\Entities\Update;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 use Longman\TelegramBot\Telegram;
 
 /**
diff --git a/src/Commands/SystemCommand.php b/src/Commands/SystemCommand.php
index e604ba473..237105c4f 100644
--- a/src/Commands/SystemCommand.php
+++ b/src/Commands/SystemCommand.php
@@ -10,7 +10,7 @@
 
 namespace Longman\TelegramBot\Commands;
 
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 abstract class SystemCommand extends Command
 {
diff --git a/src/Commands/SystemCommands/CallbackqueryCommand.php b/src/Commands/SystemCommands/CallbackqueryCommand.php
index c92894755..de5c2ed57 100644
--- a/src/Commands/SystemCommands/CallbackqueryCommand.php
+++ b/src/Commands/SystemCommands/CallbackqueryCommand.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Commands\SystemCommands;
 
 use Longman\TelegramBot\Commands\SystemCommand;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Callback query command
diff --git a/src/Commands/SystemCommands/GenericCommand.php b/src/Commands/SystemCommands/GenericCommand.php
index ff11fd3de..b024949a4 100644
--- a/src/Commands/SystemCommands/GenericCommand.php
+++ b/src/Commands/SystemCommands/GenericCommand.php
@@ -11,7 +11,6 @@
 namespace Longman\TelegramBot\Commands\SystemCommands;
 
 use Longman\TelegramBot\Commands\SystemCommand;
-use Longman\TelegramBot\Request;
 
 /**
  * Generic command
diff --git a/src/Commands/SystemCommands/GenericmessageCommand.php b/src/Commands/SystemCommands/GenericmessageCommand.php
index 8d362fb42..b19d67e33 100644
--- a/src/Commands/SystemCommands/GenericmessageCommand.php
+++ b/src/Commands/SystemCommands/GenericmessageCommand.php
@@ -10,9 +10,9 @@
 
 namespace Longman\TelegramBot\Commands\SystemCommands;
 
-use Longman\TelegramBot\Conversation;
-use Longman\TelegramBot\Request;
 use Longman\TelegramBot\Commands\SystemCommand;
+use Longman\TelegramBot\Conversation;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Generic message command
diff --git a/src/Commands/SystemCommands/InlinequeryCommand.php b/src/Commands/SystemCommands/InlinequeryCommand.php
index 8b6714f18..d1fb4f721 100644
--- a/src/Commands/SystemCommands/InlinequeryCommand.php
+++ b/src/Commands/SystemCommands/InlinequeryCommand.php
@@ -11,9 +11,7 @@
 namespace Longman\TelegramBot\Commands\SystemCommands;
 
 use Longman\TelegramBot\Commands\SystemCommand;
-use Longman\TelegramBot\Entities\InlineQuery\InlineQueryResultArticle;
-use Longman\TelegramBot\Entities\InputMessageContent\InputTextMessageContent;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Inline query command
diff --git a/src/Commands/SystemCommands/StartCommand.php b/src/Commands/SystemCommands/StartCommand.php
index b471a7410..a7322d32c 100644
--- a/src/Commands/SystemCommands/StartCommand.php
+++ b/src/Commands/SystemCommands/StartCommand.php
@@ -11,7 +11,6 @@
 namespace Longman\TelegramBot\Commands\SystemCommands;
 
 use Longman\TelegramBot\Commands\SystemCommand;
-use Longman\TelegramBot\Request;
 
 /**
  * Start command
diff --git a/src/Entities/CallbackQuery.php b/src/Entities/CallbackQuery.php
index 37cbed0e2..eeca33442 100644
--- a/src/Entities/CallbackQuery.php
+++ b/src/Entities/CallbackQuery.php
@@ -10,7 +10,7 @@
 
 namespace Longman\TelegramBot\Entities;
 
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Class CallbackQuery.
@@ -19,7 +19,8 @@
  *
  * @method string  getId()              Unique identifier for this query
  * @method User    getFrom()            Sender
- * @method Message getMessage()         Optional. Message with the callback button that originated the query. Note that message content and message date will not be available if the message is too old
+ * @method Message getMessage()         Optional. Message with the callback button that originated the query. Note that message content and message date will
+ *     not be available if the message is too old
  * @method string  getInlineMessageId() Optional. Identifier of the message sent via the bot in inline mode, that originated the query
  * @method string  getData()            Data associated with the callback button. Be aware that a bad client can send arbitrary data in this field
  */
diff --git a/src/Entities/InlineQuery.php b/src/Entities/InlineQuery.php
index b90c0bfd8..68d90f464 100644
--- a/src/Entities/InlineQuery.php
+++ b/src/Entities/InlineQuery.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Entities;
 
 use Longman\TelegramBot\Entities\InlineQuery\InlineQueryResult;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Class InlineQuery
@@ -41,7 +41,7 @@ protected function subEntities()
      * Answer this inline query with the passed results.
      *
      * @param InlineQueryResult[] $results
-     * @param array               $data
+     * @param array $data
      *
      * @return ServerResponse
      */
diff --git a/src/Entities/Payments/PreCheckoutQuery.php b/src/Entities/Payments/PreCheckoutQuery.php
index b86e7647a..59534ff65 100644
--- a/src/Entities/Payments/PreCheckoutQuery.php
+++ b/src/Entities/Payments/PreCheckoutQuery.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Entities\Entity;
 use Longman\TelegramBot\Entities\User;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Class PreCheckoutQuery
@@ -45,7 +45,7 @@ public function subEntities()
     /**
      * Answer this pre-checkout query.
      *
-     * @param bool  $ok
+     * @param bool $ok
      * @param array $data
      *
      * @return \Longman\TelegramBot\Entities\ServerResponse
diff --git a/src/Entities/Payments/ShippingQuery.php b/src/Entities/Payments/ShippingQuery.php
index 0425254d9..5c3b843d5 100644
--- a/src/Entities/Payments/ShippingQuery.php
+++ b/src/Entities/Payments/ShippingQuery.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Entities\Entity;
 use Longman\TelegramBot\Entities\User;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Class ShippingQuery
@@ -42,7 +42,7 @@ public function subEntities()
     /**
      * Answer this shipping query.
      *
-     * @param bool  $ok
+     * @param bool $ok
      * @param array $data
      *
      * @return \Longman\TelegramBot\Entities\ServerResponse
diff --git a/src/Request.php b/src/Http/Request.php
similarity index 72%
rename from src/Request.php
rename to src/Http/Request.php
index a6ba4a530..7f7c3b601 100644
--- a/src/Request.php
+++ b/src/Http/Request.php
@@ -8,72 +8,139 @@
  * file that was distributed with this source code.
  */
 
-namespace Longman\TelegramBot;
+namespace Longman\TelegramBot\Http;
 
 use GuzzleHttp\Client;
 use GuzzleHttp\Exception\RequestException;
+use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Entities\File;
 use Longman\TelegramBot\Entities\ServerResponse;
 use Longman\TelegramBot\Exception\TelegramException;
+use Longman\TelegramBot\Telegram;
+use Longman\TelegramBot\TelegramLog;
 
 /**
  * Class Request
  *
- * @method static ServerResponse getUpdates(array $data)              Use this method to receive incoming updates using long polling (wiki). An Array of Update objects is returned.
- * @method static ServerResponse setWebhook(array $data)              Use this method to specify a url and receive incoming updates via an outgoing webhook. Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update. In case of an unsuccessful request, we will give up after a reasonable amount of attempts. Returns true.
- * @method static ServerResponse deleteWebhook()                      Use this method to remove webhook integration if you decide to switch back to getUpdates. Returns True on success. Requires no parameters.
- * @method static ServerResponse getWebhookInfo()                     Use this method to get current webhook status. Requires no parameters. On success, returns a WebhookInfo object. If the bot is using getUpdates, will return an object with the url field empty.
- * @method static ServerResponse getMe()                              A simple method for testing your bot's auth token. Requires no parameters. Returns basic information about the bot in form of a User object.
- * @method static ServerResponse forwardMessage(array $data)          Use this method to forward messages of any kind. On success, the sent Message is returned.
+ * @method static ServerResponse getUpdates(array $data)              Use this method to receive incoming updates using long polling (wiki). An Array of Update
+ *     objects is returned.
+ * @method static ServerResponse setWebhook(array $data)              Use this method to specify a url and receive incoming updates via an outgoing webhook.
+ *     Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update. In case of an
+ *     unsuccessful request, we will give up after a reasonable amount of attempts. Returns true.
+ * @method static ServerResponse deleteWebhook()                      Use this method to remove webhook integration if you decide to switch back to getUpdates.
+ *     Returns True on success. Requires no parameters.
+ * @method static ServerResponse getWebhookInfo()                     Use this method to get current webhook status. Requires no parameters. On success,
+ *     returns a WebhookInfo object. If the bot is using getUpdates, will return an object with the url field empty.
+ * @method static ServerResponse getMe()                              A simple method for testing your bot's auth token. Requires no parameters. Returns basic
+ *     information about the bot in form of a User object.
+ * @method static ServerResponse forwardMessage(array $data)          Use this method to forward messages of any kind. On success, the sent Message is
+ *     returned.
  * @method static ServerResponse sendPhoto(array $data)               Use this method to send photos. On success, the sent Message is returned.
- * @method static ServerResponse sendAudio(array $data)               Use this method to send audio files, if you want Telegram clients to display them in the music player. Your audio must be in the .mp3 format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
- * @method static ServerResponse sendDocument(array $data)            Use this method to send general files. On success, the sent Message is returned. Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
+ * @method static ServerResponse sendAudio(array $data)               Use this method to send audio files, if you want Telegram clients to display them in the
+ *     music player. Your audio must be in the .mp3 format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in
+ *     size, this limit may be changed in the future.
+ * @method static ServerResponse sendDocument(array $data)            Use this method to send general files. On success, the sent Message is returned. Bots can
+ *     currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
  * @method static ServerResponse sendSticker(array $data)             Use this method to send .webp stickers. On success, the sent Message is returned.
- * @method static ServerResponse sendVideo(array $data)               Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). On success, the sent Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.
- * @method static ServerResponse sendVoice(array $data)               Use this method to send audio files, if you want Telegram clients to display the file as a playable voice message. For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as Audio or Document). On success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
+ * @method static ServerResponse sendVideo(array $data)               Use this method to send video files, Telegram clients support mp4 videos (other formats
+ *     may be sent as Document). On success, the sent Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may be
+ *     changed in the future.
+ * @method static ServerResponse sendVoice(array $data)               Use this method to send audio files, if you want Telegram clients to display the file as
+ *     a playable voice message. For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as Audio or Document). On
+ *     success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
  * @method static ServerResponse sendVideoNote(array $data)           Use this method to send video messages. On success, the sent Message is returned.
- * @method static ServerResponse sendMediaGroup(array $data)          Use this method to send a group of photos or videos as an album. On success, an array of the sent Messages is returned.
+ * @method static ServerResponse sendMediaGroup(array $data)          Use this method to send a group of photos or videos as an album. On success, an array of
+ *     the sent Messages is returned.
  * @method static ServerResponse sendLocation(array $data)            Use this method to send point on the map. On success, the sent Message is returned.
- * @method static ServerResponse editMessageLiveLocation(array $data) Use this method to edit live location messages sent by the bot or via the bot (for inline bots). A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the edited message was sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse stopMessageLiveLocation(array $data) Use this method to stop updating a live location message sent by the bot or via the bot (for inline bots) before live_period expires. On success, if the message was sent by the bot, the sent Message is returned, otherwise True is returned.
- * @method static ServerResponse sendVenue(array $data)               Use this method to send information about a venue. On success, the sent Message is returned.
+ * @method static ServerResponse editMessageLiveLocation(array $data) Use this method to edit live location messages sent by the bot or via the bot (for inline
+ *     bots). A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the
+ *     edited message was sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse stopMessageLiveLocation(array $data) Use this method to stop updating a live location message sent by the bot or via the bot
+ *     (for inline bots) before live_period expires. On success, if the message was sent by the bot, the sent Message is returned, otherwise True is returned.
+ * @method static ServerResponse sendVenue(array $data)               Use this method to send information about a venue. On success, the sent Message is
+ *     returned.
  * @method static ServerResponse sendContact(array $data)             Use this method to send phone contacts. On success, the sent Message is returned.
- * @method static ServerResponse sendChatAction(array $data)          Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.
- * @method static ServerResponse getUserProfilePhotos(array $data)    Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos object.
- * @method static ServerResponse getFile(array $data)                 Use this method to get basic info about a file and prepare it for downloading. For the moment, bots can download files of up to 20MB in size. On success, a File object is returned. The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> is taken from the response. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling getFile again.
- * @method static ServerResponse kickChatMember(array $data)          Use this method to kick a user from a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse unbanChatMember(array $data)         Use this method to unban a previously kicked user in a supergroup or channel. The user will not return to the group or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to work. Returns True on success.
- * @method static ServerResponse restrictChatMember(array $data)      Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift restrictions from a user. Returns True on success.
- * @method static ServerResponse promoteChatMember(array $data)       Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user. Returns True on success.
- * @method static ServerResponse exportChatInviteLink(array $data)    Use this method to export an invite link to a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns exported invite link as String on success.
- * @method static ServerResponse setChatPhoto(array $data)            Use this method to set a new profile photo for the chat. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse deleteChatPhoto(array $data)         Use this method to delete a chat photo. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse setChatTitle(array $data)            Use this method to change the title of a chat. Titles can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse setChatDescription(array $data)      Use this method to change the description of a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse pinChatMessage(array $data)          Use this method to pin a message in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the channel. Returns True on success.
- * @method static ServerResponse unpinChatMessage(array $data)        Use this method to unpin a message in a supergroup or a channel. The bot must be an administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the channel. Returns True on success.
- * @method static ServerResponse leaveChat(array $data)               Use this method for your bot to leave a group, supergroup or channel. Returns True on success.
- * @method static ServerResponse getChat(array $data)                 Use this method to get up to date information about the chat (current name of the user for one-on-one conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
- * @method static ServerResponse getChatAdministrators(array $data)   Use this method to get a list of administrators in a chat. On success, returns an Array of ChatMember objects that contains information about all chat administrators except other bots. If the chat is a group or a supergroup and no administrators were appointed, only the creator will be returned.
+ * @method static ServerResponse sendChatAction(array $data)          Use this method when you need to tell the user that something is happening on the bot's
+ *     side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.
+ * @method static ServerResponse getUserProfilePhotos(array $data)    Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos
+ *     object.
+ * @method static ServerResponse getFile(array $data)                 Use this method to get basic info about a file and prepare it for downloading. For the
+ *     moment, bots can download files of up to 20MB in size. On success, a File object is returned. The file can then be downloaded via the link
+ *     https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> is taken from the response. It is guaranteed that the link will be valid for at
+ *     least 1 hour. When the link expires, a new one can be requested by calling getFile again.
+ * @method static ServerResponse kickChatMember(array $data)          Use this method to kick a user from a group, a supergroup or a channel. In the case of
+ *     supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot must be
+ *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse unbanChatMember(array $data)         Use this method to unban a previously kicked user in a supergroup or channel. The user
+ *     will not return to the group or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to work.
+ *     Returns True on success.
+ * @method static ServerResponse restrictChatMember(array $data)      Use this method to restrict a user in a supergroup. The bot must be an administrator in
+ *     the supergroup for this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift restrictions from a user.
+ *     Returns True on success.
+ * @method static ServerResponse promoteChatMember(array $data)       Use this method to promote or demote a user in a supergroup or a channel. The bot must be
+ *     an administrator in the chat for this to work and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user.
+ *     Returns True on success.
+ * @method static ServerResponse exportChatInviteLink(array $data)    Use this method to export an invite link to a supergroup or a channel. The bot must be an
+ *     administrator in the chat for this to work and must have the appropriate admin rights. Returns exported invite link as String on success.
+ * @method static ServerResponse setChatPhoto(array $data)            Use this method to set a new profile photo for the chat. Photos can't be changed for
+ *     private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse deleteChatPhoto(array $data)         Use this method to delete a chat photo. Photos can't be changed for private chats. The
+ *     bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse setChatTitle(array $data)            Use this method to change the title of a chat. Titles can't be changed for private chats.
+ *     The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse setChatDescription(array $data)      Use this method to change the description of a supergroup or a channel. The bot must be
+ *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse pinChatMessage(array $data)          Use this method to pin a message in a supergroup or a channel. The bot must be an
+ *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
+ *     channel. Returns True on success.
+ * @method static ServerResponse unpinChatMessage(array $data)        Use this method to unpin a message in a supergroup or a channel. The bot must be an
+ *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
+ *     channel. Returns True on success.
+ * @method static ServerResponse leaveChat(array $data)               Use this method for your bot to leave a group, supergroup or channel. Returns True on
+ *     success.
+ * @method static ServerResponse getChat(array $data)                 Use this method to get up to date information about the chat (current name of the user
+ *     for one-on-one conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
+ * @method static ServerResponse getChatAdministrators(array $data)   Use this method to get a list of administrators in a chat. On success, returns an Array
+ *     of ChatMember objects that contains information about all chat administrators except other bots. If the chat is a group or a supergroup and no
+ *     administrators were appointed, only the creator will be returned.
  * @method static ServerResponse getChatMembersCount(array $data)     Use this method to get the number of members in a chat. Returns Int on success.
- * @method static ServerResponse getChatMember(array $data)           Use this method to get information about a member of a chat. Returns a ChatMember object on success.
- * @method static ServerResponse setChatStickerSet(array $data)       Use this method to set a new group sticker set for a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat requests to check if the bot can use this method. Returns True on success.
- * @method static ServerResponse deleteChatStickerSet(array $data)    Use this method to delete a group sticker set from a supergroup. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat requests to check if the bot can use this method. Returns True on success.
- * @method static ServerResponse answerCallbackQuery(array $data)     Use this method to send answers to callback queries sent from inline keyboards. The answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned.
+ * @method static ServerResponse getChatMember(array $data)           Use this method to get information about a member of a chat. Returns a ChatMember object
+ *     on success.
+ * @method static ServerResponse setChatStickerSet(array $data)       Use this method to set a new group sticker set for a supergroup. The bot must be an
+ *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
+ *     requests to check if the bot can use this method. Returns True on success.
+ * @method static ServerResponse deleteChatStickerSet(array $data)    Use this method to delete a group sticker set from a supergroup. The bot must be an
+ *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
+ *     requests to check if the bot can use this method. Returns True on success.
+ * @method static ServerResponse answerCallbackQuery(array $data)     Use this method to send answers to callback queries sent from inline keyboards. The
+ *     answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned.
  * @method static ServerResponse answerInlineQuery(array $data)       Use this method to send answers to an inline query. On success, True is returned.
- * @method static ServerResponse editMessageText(array $data)         Use this method to edit text and game messages sent by the bot or via the bot (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse editMessageCaption(array $data)      Use this method to edit captions of messages sent by the bot or via the bot (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse editMessageReplyMarkup(array $data)  Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse deleteMessage(array $data)           Use this method to delete a message, including service messages, with certain limitations. Returns True on success.
+ * @method static ServerResponse editMessageText(array $data)         Use this method to edit text and game messages sent by the bot or via the bot (for inline
+ *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse editMessageCaption(array $data)      Use this method to edit captions of messages sent by the bot or via the bot (for inline
+ *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse editMessageReplyMarkup(array $data)  Use this method to edit only the reply markup of messages sent by the bot or via the bot
+ *     (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse deleteMessage(array $data)           Use this method to delete a message, including service messages, with certain
+ *     limitations. Returns True on success.
  * @method static ServerResponse getStickerSet(array $data)           Use this method to get a sticker set. On success, a StickerSet object is returned.
- * @method static ServerResponse uploadStickerFile(array $data)       Use this method to upload a .png file with a sticker for later use in createNewStickerSet and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success.
- * @method static ServerResponse createNewStickerSet(array $data)     Use this method to create new sticker set owned by a user. The bot will be able to edit the created sticker set. Returns True on success.
- * @method static ServerResponse addStickerToSet(array $data)         Use this method to add a new sticker to a set created by the bot. Returns True on success.
- * @method static ServerResponse setStickerPositionInSet(array $data) Use this method to move a sticker in a set created by the bot to a specific position. Returns True on success.
- * @method static ServerResponse deleteStickerFromSet(array $data)    Use this method to delete a sticker from a set created by the bot. Returns True on success.
+ * @method static ServerResponse uploadStickerFile(array $data)       Use this method to upload a .png file with a sticker for later use in createNewStickerSet
+ *     and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success.
+ * @method static ServerResponse createNewStickerSet(array $data)     Use this method to create new sticker set owned by a user. The bot will be able to edit
+ *     the created sticker set. Returns True on success.
+ * @method static ServerResponse addStickerToSet(array $data)         Use this method to add a new sticker to a set created by the bot. Returns True on
+ *     success.
+ * @method static ServerResponse setStickerPositionInSet(array $data) Use this method to move a sticker in a set created by the bot to a specific position.
+ *     Returns True on success.
+ * @method static ServerResponse deleteStickerFromSet(array $data)    Use this method to delete a sticker from a set created by the bot. Returns True on
+ *     success.
  * @method static ServerResponse sendInvoice(array $data)             Use this method to send invoices. On success, the sent Message is returned.
- * @method static ServerResponse answerShippingQuery(array $data)     If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is returned.
- * @method static ServerResponse answerPreCheckoutQuery(array $data)  Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True is returned.
+ * @method static ServerResponse answerShippingQuery(array $data)     If you sent an invoice requesting a shipping address and the parameter is_flexible was
+ *     specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is
+ *     returned.
+ * @method static ServerResponse answerPreCheckoutQuery(array $data)  Once the user has confirmed their payment and shipping details, the Bot API sends the
+ *     final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True
+ *     is returned.
  */
 class Request
 {
@@ -209,7 +276,7 @@ class Request
      */
     public static function initialize(Telegram $telegram)
     {
-        if (!($telegram instanceof Telegram)) {
+        if (! ($telegram instanceof Telegram)) {
             throw new TelegramException('Invalid Telegram pointer!');
         }
 
@@ -226,7 +293,7 @@ public static function initialize(Telegram $telegram)
      */
     public static function setClient(Client $client)
     {
-        if (!($client instanceof Client)) {
+        if (! ($client instanceof Client)) {
             throw new TelegramException('Invalid GuzzleHttp\Client pointer!');
         }
 
@@ -242,12 +309,12 @@ public static function setClient(Client $client)
     public static function getInput()
     {
         // First check if a custom input has been set, else get the PHP input.
-        if (!($input = self::$telegram->getCustomInput())) {
+        if (! ($input = self::$telegram->getCustomInput())) {
             $input = file_get_contents('php://input');
         }
 
         // Make sure we have a string to work with.
-        if (!is_string($input)) {
+        if (! is_string($input)) {
             throw new TelegramException('Input must be a string!');
         }
 
@@ -282,13 +349,13 @@ public static function generateGeneralFakeServerResponse(array $data = [])
         //some data to let iniatilize the class method SendMessage
         if (isset($data['chat_id'])) {
             $data['message_id'] = '1234';
-            $data['date']       = '1441378360';
-            $data['from']       = [
+            $data['date'] = '1441378360';
+            $data['from'] = [
                 'id'         => 123456789,
                 'first_name' => 'botname',
                 'username'   => 'namebot',
             ];
-            $data['chat']       = ['id' => $data['chat_id']];
+            $data['chat'] = ['id' => $data['chat_id']];
 
             $fake_response['result'] = $data;
         }
@@ -309,7 +376,7 @@ public static function generateGeneralFakeServerResponse(array $data = [])
     private static function setUpRequestParams(array $data)
     {
         $has_resource = false;
-        $multipart    = [];
+        $multipart = [];
 
         // Convert any nested arrays into JSON strings.
         array_walk($data, function (&$item) {
@@ -319,7 +386,7 @@ private static function setUpRequestParams(array $data)
         //Reformat data array in multipart way if it contains a resource
         foreach ($data as $key => $item) {
             $has_resource |= (is_resource($item) || $item instanceof \GuzzleHttp\Psr7\Stream);
-            $multipart[]  = ['name' => $key, 'contents' => $item];
+            $multipart[] = ['name' => $key, 'contents' => $item];
         }
         if ($has_resource) {
             return ['multipart' => $multipart];
@@ -332,7 +399,7 @@ private static function setUpRequestParams(array $data)
      * Execute HTTP Request
      *
      * @param string $action Action to execute
-     * @param array  $data   Data to attach to the execution
+     * @param array $data Data to attach to the execution
      *
      * @return string Result of the HTTP Request
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -344,8 +411,8 @@ public static function execute($action, array $data = [])
             $data['reply_markup'] = json_encode($data['reply_markup']);
         }
 
-        $result                  = null;
-        $request_params          = self::setUpRequestParams($data);
+        $result = null;
+        $request_params = self::setUpRequestParams($data);
         $request_params['debug'] = TelegramLog::getDebugLogTempStream();
 
         try {
@@ -353,7 +420,7 @@ public static function execute($action, array $data = [])
                 '/bot' . self::$telegram->getApiKey() . '/' . $action,
                 $request_params
             );
-            $result   = (string) $response->getBody();
+            $result = (string) $response->getBody();
 
             //Logging getUpdates Update
             if ($action === 'getUpdates') {
@@ -384,12 +451,12 @@ public static function downloadFile(File $file)
         }
 
         $tg_file_path = $file->getFilePath();
-        $file_path    = $download_path . '/' . $tg_file_path;
+        $file_path = $download_path . '/' . $tg_file_path;
 
         $file_dir = dirname($file_path);
         //For safety reasons, first try to create the directory, then check that it exists.
         //This is in case some other process has created the folder in the meantime.
-        if (!@mkdir($file_dir, 0755, true) && !is_dir($file_dir)) {
+        if (! @mkdir($file_dir, 0755, true) && ! is_dir($file_dir)) {
             throw new TelegramException('Directory ' . $file_dir . ' can\'t be created');
         }
 
@@ -435,7 +502,7 @@ public static function encodeFile($file)
      * @todo Write debug entry on failure
      *
      * @param string $action
-     * @param array  $data
+     * @param array $data
      *
      * @return \Longman\TelegramBot\Entities\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -477,7 +544,7 @@ public static function send($action, array $data = [])
      * @todo Would be nice to find a better solution for this!
      *
      * @param string $action
-     * @param array  $data
+     * @param array $data
      */
     protected static function addDummyParamIfNecessary($action, array &$data)
     {
@@ -510,7 +577,7 @@ private static function ensureNonEmptyData(array $data)
      */
     private static function ensureValidAction($action)
     {
-        if (!in_array($action, self::$actions, true)) {
+        if (! in_array($action, self::$actions, true)) {
             throw new TelegramException('The action "' . $action . '" doesn\'t exist!');
         }
     }
@@ -532,7 +599,7 @@ public static function sendMessage(array $data)
         do {
             //Chop off and send the first message
             $data['text'] = mb_substr($text, 0, 4096);
-            $response     = self::send('sendMessage', $data);
+            $response = self::send('sendMessage', $data);
 
             //Prepare the next message
             $text = mb_substr($text, 4096);
@@ -545,7 +612,7 @@ public static function sendMessage(array $data)
      * Any statically called method should be relayed to the `send` method.
      *
      * @param string $action
-     * @param array  $data
+     * @param array $data
      *
      * @return \Longman\TelegramBot\Entities\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -577,8 +644,8 @@ public static function emptyResponse()
      * Send message to all active chats
      *
      * @param string $callback_function
-     * @param array  $data
-     * @param array  $select_chats_params
+     * @param array $data
+     * @param array $select_chats_params
      *
      * @return array
      * @throws TelegramException
@@ -588,7 +655,7 @@ public static function sendToActiveChats(
         array $data,
         array $select_chats_params
     ) {
-        if (!method_exists(Request::class, $callback_function)) {
+        if (! method_exists(Request::class, $callback_function)) {
             throw new TelegramException('Method "' . $callback_function . '" not found in class Request.');
         }
 
@@ -598,7 +665,7 @@ public static function sendToActiveChats(
         if (is_array($chats)) {
             foreach ($chats as $row) {
                 $data['chat_id'] = $row['chat_id'];
-                $results[]       = call_user_func(Request::class . '::' . $callback_function, $data);
+                $results[] = call_user_func(Request::class . '::' . $callback_function, $data);
             }
         }
 
@@ -609,7 +676,7 @@ public static function sendToActiveChats(
      * Enable request limiter
      *
      * @param boolean $enable
-     * @param array   $options
+     * @param array $options
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
@@ -622,12 +689,12 @@ public static function setLimiter($enable = true, array $options = [])
 
             $options = array_merge($options_default, $options);
 
-            if (!is_numeric($options['interval']) || $options['interval'] <= 0) {
+            if (! is_numeric($options['interval']) || $options['interval'] <= 0) {
                 throw new TelegramException('Interval must be a number and must be greater than zero!');
             }
 
             self::$limiter_interval = $options['interval'];
-            self::$limiter_enabled  = $enable;
+            self::$limiter_enabled = $enable;
         }
     }
 
@@ -638,7 +705,7 @@ public static function setLimiter($enable = true, array $options = [])
      * @link https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this
      *
      * @param string $action
-     * @param array  $data
+     * @param array $data
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
@@ -671,7 +738,7 @@ private static function limitTelegramRequests($action, array $data = [])
                 'deleteChatStickerSet',
             ];
 
-            $chat_id           = isset($data['chat_id']) ? $data['chat_id'] : null;
+            $chat_id = isset($data['chat_id']) ? $data['chat_id'] : null;
             $inline_message_id = isset($data['inline_message_id']) ? $data['inline_message_id'] : null;
 
             if (($chat_id || $inline_message_id) && in_array($action, $limited_methods)) {
@@ -684,9 +751,9 @@ private static function limitTelegramRequests($action, array $data = [])
 
                     $requests = DB::getTelegramRequestCount($chat_id, $inline_message_id);
 
-                    $chat_per_second   = ($requests['LIMIT_PER_SEC'] == 0); // No more than one message per second inside a particular chat
+                    $chat_per_second = ($requests['LIMIT_PER_SEC'] == 0); // No more than one message per second inside a particular chat
                     $global_per_second = ($requests['LIMIT_PER_SEC_ALL'] < 30);    // No more than 30 messages per second to different chats
-                    $groups_per_minute = (((is_numeric($chat_id) && $chat_id > 0) || !is_null($inline_message_id)) || ((!is_numeric($chat_id) || $chat_id < 0) && $requests['LIMIT_PER_MINUTE'] < 20));    // No more than 20 messages per minute in groups and channels
+                    $groups_per_minute = (((is_numeric($chat_id) && $chat_id > 0) || ! is_null($inline_message_id)) || ((! is_numeric($chat_id) || $chat_id < 0) && $requests['LIMIT_PER_MINUTE'] < 20));    // No more than 20 messages per minute in groups and channels
 
                     if ($chat_per_second && $global_per_second && $groups_per_minute) {
                         break;
diff --git a/tests/unit/Commands/CustomTestCommands/HiddenCommand.php b/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
index acc82a13b..9fac12d59 100644
--- a/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
+++ b/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Commands\UserCommands;
 
 use Longman\TelegramBot\Commands\UserCommand;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Test "/hidden" command to test $show_in_help
diff --git a/tests/unit/Commands/CustomTestCommands/VisibleCommand.php b/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
index 6d800e896..bb7634beb 100644
--- a/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
+++ b/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Commands\UserCommands;
 
 use Longman\TelegramBot\Commands\UserCommand;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Test "/visible" command to test $show_in_help
diff --git a/tests/unit/Entities/ServerResponseTest.php b/tests/unit/Entities/ServerResponseTest.php
index c321ac4a1..31db5feb2 100644
--- a/tests/unit/Entities/ServerResponseTest.php
+++ b/tests/unit/Entities/ServerResponseTest.php
@@ -14,7 +14,7 @@
 
 use Longman\TelegramBot\Entities\Message;
 use Longman\TelegramBot\Entities\ServerResponse;
-use Longman\TelegramBot\Request;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * @package         TelegramTest
@@ -41,8 +41,8 @@ public function sendMessageOk()
 
     public function testSendMessageOk()
     {
-        $result        = $this->sendMessageOk();
-        $server        = new ServerResponse(json_decode($result, true), 'testbot');
+        $result = $this->sendMessageOk();
+        $server = new ServerResponse(json_decode($result, true), 'testbot');
         $server_result = $server->getResult();
 
         self::assertTrue($server->isOk());
@@ -220,8 +220,8 @@ public function getUserProfilePhotos()
 
     public function testGetUserProfilePhotos()
     {
-        $result        = $this->getUserProfilePhotos();
-        $server        = new ServerResponse(json_decode($result, true), 'testbot');
+        $result = $this->getUserProfilePhotos();
+        $server = new ServerResponse(json_decode($result, true), 'testbot');
         $server_result = $server->getResult();
 
         $photos = $server_result->getPhotos();

From 4e84bce5eaa3eebd27bb5c0e99b5b7544ed3c6c6 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 17:02:14 +0400
Subject: [PATCH 04/40] Move ServerResponse class inside http namespace

---
 src/Commands/AdminCommands/ChatsCommand.php   |  2 +-
 src/Commands/AdminCommands/CleanupCommand.php |  4 +--
 .../AdminCommands/SendtoallCommand.php        |  4 +--
 .../AdminCommands/SendtochannelCommand.php    |  4 +--
 src/Commands/AdminCommands/WhoisCommand.php   |  2 +-
 src/Commands/Command.php                      | 10 +++----
 src/Commands/SystemCommand.php                |  2 +-
 .../SystemCommands/GenericmessageCommand.php  |  4 +--
 src/Entities/Payments/PreCheckoutQuery.php    |  2 +-
 src/Entities/Payments/ShippingQuery.php       |  2 +-
 src/Http/Request.php                          | 10 +++----
 src/{Entities => Http}/ServerResponse.php     | 29 +++++++++++++++++--
 tests/unit/Entities/ServerResponseTest.php    |  2 +-
 13 files changed, 50 insertions(+), 27 deletions(-)
 rename src/{Entities => Http}/ServerResponse.php (88%)

diff --git a/src/Commands/AdminCommands/ChatsCommand.php b/src/Commands/AdminCommands/ChatsCommand.php
index 3d610d692..e5c9abf12 100644
--- a/src/Commands/AdminCommands/ChatsCommand.php
+++ b/src/Commands/AdminCommands/ChatsCommand.php
@@ -45,7 +45,7 @@ class ChatsCommand extends AdminCommand
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Commands/AdminCommands/CleanupCommand.php b/src/Commands/AdminCommands/CleanupCommand.php
index 332d1fa06..31b206f20 100644
--- a/src/Commands/AdminCommands/CleanupCommand.php
+++ b/src/Commands/AdminCommands/CleanupCommand.php
@@ -326,7 +326,7 @@ private function getQueries($settings)
     /**
      * Execution if MySQL is required but not available
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function executeNoDb()
     {
@@ -345,7 +345,7 @@ public function executeNoDb()
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Commands/AdminCommands/SendtoallCommand.php b/src/Commands/AdminCommands/SendtoallCommand.php
index 846458008..c822bebcd 100644
--- a/src/Commands/AdminCommands/SendtoallCommand.php
+++ b/src/Commands/AdminCommands/SendtoallCommand.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\Entities\Message;
-use Longman\TelegramBot\Entities\ServerResponse;
+use Longman\TelegramBot\Http\ServerResponse;
 use Longman\TelegramBot\Http\Request;
 
 /**
@@ -48,7 +48,7 @@ class SendtoallCommand extends AdminCommand
     /**
      * Execute command
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Commands/AdminCommands/SendtochannelCommand.php b/src/Commands/AdminCommands/SendtochannelCommand.php
index 2990a7d16..88da2cef9 100644
--- a/src/Commands/AdminCommands/SendtochannelCommand.php
+++ b/src/Commands/AdminCommands/SendtochannelCommand.php
@@ -54,7 +54,7 @@ class SendtochannelCommand extends AdminCommand
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse|mixed
+     * @return \Longman\TelegramBot\Http\ServerResponse|mixed
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
@@ -275,7 +275,7 @@ public function execute()
      * @param \Longman\TelegramBot\Entities\Message $message
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     protected function sendBack(Message $message, array $data)
diff --git a/src/Commands/AdminCommands/WhoisCommand.php b/src/Commands/AdminCommands/WhoisCommand.php
index 453d41869..3ea56eafc 100644
--- a/src/Commands/AdminCommands/WhoisCommand.php
+++ b/src/Commands/AdminCommands/WhoisCommand.php
@@ -52,7 +52,7 @@ class WhoisCommand extends AdminCommand
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index 3421c3be5..7ee5a202c 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -143,7 +143,7 @@ public function setUpdate(Update $update = null)
     /**
      * Pre-execute command
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function preExecute()
@@ -176,7 +176,7 @@ public function preExecute()
     /**
      * Execute command
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     abstract public function execute();
@@ -184,7 +184,7 @@ abstract public function execute();
     /**
      * Execution if MySQL is required but not available
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function executeNoDb()
@@ -393,7 +393,7 @@ protected function removeNonPrivateMessage()
      * @param string $text
      * @param array  $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function replyToChat($text, array $data = [])
     {
@@ -413,7 +413,7 @@ public function replyToChat($text, array $data = [])
      * @param string $text
      * @param array  $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function replyToUser($text, array $data = [])
     {
diff --git a/src/Commands/SystemCommand.php b/src/Commands/SystemCommand.php
index 237105c4f..61e7b381b 100644
--- a/src/Commands/SystemCommand.php
+++ b/src/Commands/SystemCommand.php
@@ -20,7 +20,7 @@ abstract class SystemCommand extends Command
      * Although system commands should just work and return a successful ServerResponse,
      * each system command can override this method to add custom functionality.
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function execute()
     {
diff --git a/src/Commands/SystemCommands/GenericmessageCommand.php b/src/Commands/SystemCommands/GenericmessageCommand.php
index b19d67e33..035156358 100644
--- a/src/Commands/SystemCommands/GenericmessageCommand.php
+++ b/src/Commands/SystemCommands/GenericmessageCommand.php
@@ -42,7 +42,7 @@ class GenericmessageCommand extends SystemCommand
     /**
      * Execution if MySQL is required but not available
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function executeNoDb()
     {
@@ -53,7 +53,7 @@ public function executeNoDb()
     /**
      * Execute command
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Entities/Payments/PreCheckoutQuery.php b/src/Entities/Payments/PreCheckoutQuery.php
index 59534ff65..e198f1a69 100644
--- a/src/Entities/Payments/PreCheckoutQuery.php
+++ b/src/Entities/Payments/PreCheckoutQuery.php
@@ -48,7 +48,7 @@ public function subEntities()
      * @param bool $ok
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function answer($ok, array $data = [])
     {
diff --git a/src/Entities/Payments/ShippingQuery.php b/src/Entities/Payments/ShippingQuery.php
index 5c3b843d5..bf423c20d 100644
--- a/src/Entities/Payments/ShippingQuery.php
+++ b/src/Entities/Payments/ShippingQuery.php
@@ -45,7 +45,7 @@ public function subEntities()
      * @param bool $ok
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function answer($ok, array $data = [])
     {
diff --git a/src/Http/Request.php b/src/Http/Request.php
index 7f7c3b601..be52759e2 100644
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -14,7 +14,7 @@
 use GuzzleHttp\Exception\RequestException;
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Entities\File;
-use Longman\TelegramBot\Entities\ServerResponse;
+use Longman\TelegramBot\Http\ServerResponse;
 use Longman\TelegramBot\Exception\TelegramException;
 use Longman\TelegramBot\Telegram;
 use Longman\TelegramBot\TelegramLog;
@@ -504,7 +504,7 @@ public static function encodeFile($file)
      * @param string $action
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function send($action, array $data = [])
@@ -589,7 +589,7 @@ private static function ensureValidAction($action)
      *
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function sendMessage(array $data)
@@ -614,7 +614,7 @@ public static function sendMessage(array $data)
      * @param string $action
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function __callStatic($action, array $data)
@@ -632,7 +632,7 @@ public static function __callStatic($action, array $data)
      * No request to telegram are sent, this function is used in commands that
      * don't need to fire a message after execution
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function emptyResponse()
diff --git a/src/Entities/ServerResponse.php b/src/Http/ServerResponse.php
similarity index 88%
rename from src/Entities/ServerResponse.php
rename to src/Http/ServerResponse.php
index b573e9f80..f47bf978a 100644
--- a/src/Entities/ServerResponse.php
+++ b/src/Http/ServerResponse.php
@@ -6,7 +6,7 @@
  * file that was distributed with this source code.
  */
 
-namespace Longman\TelegramBot\Entities;
+namespace Longman\TelegramBot\Http;
 
 /**
  * Class ServerResponse
@@ -20,7 +20,7 @@
  *
  * @todo method ResponseParameters getParameters()  Field which can help to automatically handle the error
  */
-class ServerResponse extends Entity
+class ServerResponse
 {
     /**
      * ServerResponse constructor.
@@ -47,7 +47,30 @@ public function __construct(array $data, $bot_username)
             }
         }
 
-        parent::__construct($data, $bot_username);
+        //Make sure we're not raw_data inception-ing
+        if (array_key_exists('raw_data', $data)) {
+            if ($data['raw_data'] === null) {
+                unset($data['raw_data']);
+            }
+        } else {
+            $data['raw_data'] = $data;
+        }
+
+        $data['bot_username'] = $bot_username;
+
+        $this->assignMemberVariables($data);
+    }
+
+    /**
+     * Helper to set member variables
+     *
+     * @param array $data
+     */
+    protected function assignMemberVariables(array $data)
+    {
+        foreach ($data as $key => $value) {
+            $this->$key = $value;
+        }
     }
 
     /**
diff --git a/tests/unit/Entities/ServerResponseTest.php b/tests/unit/Entities/ServerResponseTest.php
index 31db5feb2..9f48673a0 100644
--- a/tests/unit/Entities/ServerResponseTest.php
+++ b/tests/unit/Entities/ServerResponseTest.php
@@ -13,7 +13,7 @@
 namespace Longman\TelegramBot\Tests\Unit;
 
 use Longman\TelegramBot\Entities\Message;
-use Longman\TelegramBot\Entities\ServerResponse;
+use Longman\TelegramBot\Http\ServerResponse;
 use Longman\TelegramBot\Http\Request;
 
 /**

From 7cfd0b6b33bf9e63b911768f5fc04f5352245536 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 17:31:47 +0400
Subject: [PATCH 05/40] Fix failing tests

---
 src/Http/ServerResponse.php                   | 78 +++++++++++++++----
 .../Entities/InlineKeyboardButtonTest.php     |  2 +
 tests/unit/Entities/KeyboardButtonTest.php    |  2 +
 tests/unit/TelegramTest.php                   | 11 ++-
 4 files changed, 74 insertions(+), 19 deletions(-)

diff --git a/src/Http/ServerResponse.php b/src/Http/ServerResponse.php
index f47bf978a..b08bb164e 100644
--- a/src/Http/ServerResponse.php
+++ b/src/Http/ServerResponse.php
@@ -8,16 +8,20 @@
 
 namespace Longman\TelegramBot\Http;
 
+use Longman\TelegramBot\Entities\Chat;
+use Longman\TelegramBot\Entities\ChatMember;
+use Longman\TelegramBot\Entities\File;
+use Longman\TelegramBot\Entities\Message;
+use Longman\TelegramBot\Entities\Update;
+use Longman\TelegramBot\Entities\User;
+use Longman\TelegramBot\Entities\UserProfilePhotos;
+use Longman\TelegramBot\Entities\WebhookInfo;
+
 /**
  * Class ServerResponse
  *
  * @link https://core.telegram.org/bots/api#making-requests
  *
- * @method bool   getOk()          If the request was successful
- * @method mixed  getResult()      The result of the query
- * @method int    getErrorCode()   Error code of the unsuccessful request
- * @method string getDescription() Human-readable description of the result / unsuccessful request
- *
  * @todo method ResponseParameters getParameters()  Field which can help to automatically handle the error
  */
 class ServerResponse
@@ -25,7 +29,7 @@ class ServerResponse
     /**
      * ServerResponse constructor.
      *
-     * @param array  $data
+     * @param array $data
      * @param string $bot_username
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -36,7 +40,7 @@ public function __construct(array $data, $bot_username)
         unset($data['raw_data']);
         $data['raw_data'] = $data;
 
-        $is_ok  = isset($data['ok']) ? (bool) $data['ok'] : false;
+        $is_ok = isset($data['ok']) ? (bool) $data['ok'] : false;
         $result = isset($data['result']) ? $data['result'] : null;
 
         if ($is_ok && is_array($result)) {
@@ -94,7 +98,47 @@ protected function isAssoc(array $array)
      */
     public function isOk()
     {
-        return (bool) $this->getOk();
+        return $this->getOk();
+    }
+
+    /**
+     * If response is ok
+     *
+     * @return bool
+     */
+    public function getOk()
+    {
+        return isset($this->ok) ? (bool) $this->ok : false;
+    }
+
+    /**
+     * Return result
+     *
+     * @return mixed
+     */
+    public function getResult()
+    {
+        return isset($this->result) ? $this->result : null;
+    }
+
+    /**
+     * Return error code
+     *
+     * @return int
+     */
+    public function getErrorCode()
+    {
+        return isset($this->error_code) ? $this->error_code : null;
+    }
+
+    /**
+     * Return human-readable description of the result / unsuccessful request
+     *
+     * @return string
+     */
+    public function getDescription()
+    {
+        return isset($this->description) ? $this->description : null;
     }
 
     /**
@@ -122,7 +166,7 @@ public function printError($return = false)
     /**
      * Create and return the object of the received result
      *
-     * @param array  $result
+     * @param array $result
      * @param string $bot_username
      *
      * @return \Longman\TelegramBot\Entities\Chat|\Longman\TelegramBot\Entities\ChatMember|\Longman\TelegramBot\Entities\File|\Longman\TelegramBot\Entities\Message|\Longman\TelegramBot\Entities\User|\Longman\TelegramBot\Entities\UserProfilePhotos|\Longman\TelegramBot\Entities\WebhookInfo
@@ -134,16 +178,15 @@ private function createResultObject($result, $bot_username)
         $result['raw_data'] = null;
 
         $result_object_types = [
-            'total_count' => 'UserProfilePhotos', //Response from getUserProfilePhotos
-            'file_id'     => 'File',              //Response from getFile
-            'title'       => 'Chat',              //Response from getChat
-            'username'    => 'User',              //Response from getMe
-            'user'        => 'ChatMember',        //Response from getChatMember
-            'url'         => 'WebhookInfo',       //Response from getWebhookInfo
+            'total_count' => UserProfilePhotos::class, //Response from getUserProfilePhotos
+            'file_id'     => File::class,              //Response from getFile
+            'title'       => Chat::class,              //Response from getChat
+            'username'    => User::class,              //Response from getMe
+            'user'        => ChatMember::class,        //Response from getChatMember
+            'url'         => WebhookInfo::class,       //Response from getWebhookInfo
         ];
         foreach ($result_object_types as $type => $object_class) {
             if (isset($result[$type])) {
-                $object_class = __NAMESPACE__ . '\\' . $object_class;
 
                 return new $object_class($result);
             }
@@ -156,7 +199,7 @@ private function createResultObject($result, $bot_username)
     /**
      * Create and return the objects array of the received result
      *
-     * @param array  $result
+     * @param array $result
      * @param string $bot_username
      *
      * @return null|\Longman\TelegramBot\Entities\ChatMember[]|\Longman\TelegramBot\Entities\Update[]
@@ -185,4 +228,5 @@ private function createResultObjects($result, $bot_username)
 
         return $results;
     }
+
 }
diff --git a/tests/unit/Entities/InlineKeyboardButtonTest.php b/tests/unit/Entities/InlineKeyboardButtonTest.php
index fc0cb0747..9c44a02ce 100644
--- a/tests/unit/Entities/InlineKeyboardButtonTest.php
+++ b/tests/unit/Entities/InlineKeyboardButtonTest.php
@@ -95,6 +95,8 @@ public function testInlineKeyboardButtonSuccess()
         new InlineKeyboardButton(['text' => 'message', 'switch_inline_query_current_chat' => 'switch_inline_query_current_chat_value']);
         new InlineKeyboardButton(['text' => 'message', 'switch_inline_query_current_chat' => '']); // Allow empty string.
         new InlineKeyboardButton(['text' => 'message', 'pay' => true]);
+
+        $this->assertTrue(true);
     }
 
     public function testInlineKeyboardButtonCouldBe()
diff --git a/tests/unit/Entities/KeyboardButtonTest.php b/tests/unit/Entities/KeyboardButtonTest.php
index 018164a3c..097ed8d92 100644
--- a/tests/unit/Entities/KeyboardButtonTest.php
+++ b/tests/unit/Entities/KeyboardButtonTest.php
@@ -44,6 +44,8 @@ public function testKeyboardButtonSuccess()
         new KeyboardButton(['text' => 'message']);
         new KeyboardButton(['text' => 'message', 'request_contact' => true]);
         new KeyboardButton(['text' => 'message', 'request_location' => true]);
+
+        $this->assertTrue(true);
     }
 
     public function testInlineKeyboardButtonCouldBe()
diff --git a/tests/unit/TelegramTest.php b/tests/unit/TelegramTest.php
index e219c7512..1ea3a8d3c 100644
--- a/tests/unit/TelegramTest.php
+++ b/tests/unit/TelegramTest.php
@@ -41,7 +41,7 @@ protected function setUp()
 
         // Create a few dummy custom commands paths.
         foreach ($this->custom_commands_paths as $custom_path) {
-            mkdir($custom_path);
+            @mkdir($custom_path);
         }
     }
 
@@ -49,7 +49,7 @@ protected function tearDown()
     {
         // Clean up the custom commands paths.
         foreach ($this->custom_commands_paths as $custom_path) {
-            rmdir($custom_path);
+            @rmdir($custom_path);
         }
     }
 
@@ -144,4 +144,11 @@ public function testGetCommandsList()
         $this->assertInternalType('array', $commands);
         $this->assertNotCount(0, $commands);
     }
+
+    public function testContainer()
+    {
+        $telegram = new Telegram(self::$dummy_api_key, 'testbot');
+
+        $this->assertInstanceOf(\Illuminate\Container\Container::class, $telegram);
+    }
 }

From d711159cbff2fb4bfab2f4f75d306db6417b2ed5 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 17:46:41 +0400
Subject: [PATCH 06/40] Remove unused import

---
 src/Http/Request.php | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/Http/Request.php b/src/Http/Request.php
index be52759e2..aa8b22118 100644
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -14,7 +14,6 @@
 use GuzzleHttp\Exception\RequestException;
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Entities\File;
-use Longman\TelegramBot\Http\ServerResponse;
 use Longman\TelegramBot\Exception\TelegramException;
 use Longman\TelegramBot\Telegram;
 use Longman\TelegramBot\TelegramLog;

From 404efd8e9372555a11b2e927b9177d94817b99de Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 17:52:49 +0400
Subject: [PATCH 07/40] Create http kernel class

---
 src/Http/Kernel.php | 58 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 src/Http/Kernel.php

diff --git a/src/Http/Kernel.php b/src/Http/Kernel.php
new file mode 100644
index 000000000..304852db8
--- /dev/null
+++ b/src/Http/Kernel.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * This file is part of the TelegramBot package.
+ *
+ * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Longman\TelegramBot\Http;
+
+use Longman\TelegramBot\Entities\Update;
+use Longman\TelegramBot\Telegram;
+
+class Kernel
+{
+    /**
+     * The application implementation.
+     *
+     * @var \Longman\TelegramBot\Telegram
+     */
+    protected $app;
+
+    /**
+     * Create a new HTTP kernel instance.
+     *
+     * @param  \Longman\TelegramBot\Telegram $app
+     *
+     * @return void
+     */
+    public function __construct(Telegram $app)
+    {
+        $this->app = $app;
+    }
+
+    /**
+     * Handle an incoming HTTP request.
+     *
+     * @param  \Longman\TelegramBot\Request2 $request
+     *
+     * @return \Longman\TelegramBot\Response
+     *
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public function handle(Request $request)
+    {
+        $params = $request->json();
+
+        $update = new Update($params->all(), $this->app->getBotUsername());
+
+        if ($response = $this->app->processUpdate($update)) {
+            return $response->isOk();
+        }
+
+        return $response;
+    }
+}

From 47564d825df8cdf3369cdccbc1e9e22f00e08975 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 17:53:37 +0400
Subject: [PATCH 08/40] Old request class renamed to Client

---
 src/Commands/AdminCommands/ChatsCommand.php   |   4 +-
 src/Commands/AdminCommands/CleanupCommand.php |  10 +-
 src/Commands/AdminCommands/DebugCommand.php   |  10 +-
 .../AdminCommands/SendtoallCommand.php        |   4 +-
 .../AdminCommands/SendtochannelCommand.php    |   8 +-
 src/Commands/AdminCommands/WhoisCommand.php   |   8 +-
 src/Commands/Command.php                      |  18 +-
 src/Commands/SystemCommand.php                |   4 +-
 .../SystemCommands/CallbackqueryCommand.php   |   4 +-
 .../SystemCommands/GenericmessageCommand.php  |   6 +-
 .../SystemCommands/InlinequeryCommand.php     |   4 +-
 src/Entities/CallbackQuery.php                |   4 +-
 src/Entities/InlineQuery.php                  |   4 +-
 src/Entities/Payments/PreCheckoutQuery.php    |   4 +-
 src/Entities/Payments/ShippingQuery.php       |   4 +-
 src/Http/Client.php                           | 769 ++++++++++++++++++
 .../CustomTestCommands/HiddenCommand.php      |   4 +-
 .../CustomTestCommands/VisibleCommand.php     |   4 +-
 tests/unit/Entities/ServerResponseTest.php    |   6 +-
 tests/unit/TelegramTest.php                   |   9 +
 20 files changed, 833 insertions(+), 55 deletions(-)
 create mode 100644 src/Http/Client.php

diff --git a/src/Commands/AdminCommands/ChatsCommand.php b/src/Commands/AdminCommands/ChatsCommand.php
index e5c9abf12..5c7120895 100644
--- a/src/Commands/AdminCommands/ChatsCommand.php
+++ b/src/Commands/AdminCommands/ChatsCommand.php
@@ -13,7 +13,7 @@
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Entities\Chat;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 class ChatsCommand extends AdminCommand
 {
@@ -135,6 +135,6 @@ public function execute()
             'text'    => $text_back,
         ];
 
-        return Request::sendMessage($data);
+        return Client::sendMessage($data);
     }
 }
diff --git a/src/Commands/AdminCommands/CleanupCommand.php b/src/Commands/AdminCommands/CleanupCommand.php
index 31b206f20..83af45906 100644
--- a/src/Commands/AdminCommands/CleanupCommand.php
+++ b/src/Commands/AdminCommands/CleanupCommand.php
@@ -13,7 +13,7 @@
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Exception\TelegramException;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 use Longman\TelegramBot\TelegramLog;
 use PDOException;
 
@@ -339,7 +339,7 @@ public function executeNoDb()
             'text'       => '*No database connection!*',
         ];
 
-        return Request::sendMessage($data);
+        return Client::sendMessage($data);
     }
 
     /**
@@ -375,7 +375,7 @@ public function execute()
 
         $data['text'] = 'Cleaning up tables:' . PHP_EOL . implode(PHP_EOL, $infos);
 
-        Request::sendMessage($data);
+        Client::sendMessage($data);
 
         $rows = 0;
         $pdo = DB::getPdo();
@@ -395,7 +395,7 @@ public function execute()
             $pdo->rollBack();   // rollback changes on exception (useful if you want to track down error - you can't replicate it when some of the data is already deleted...)
 
             $data['text'] = '*Database cleanup failed!* _(check your error logs)_';
-            Request::sendMessage($data);
+            Client::sendMessage($data);
 
             throw new TelegramException($e->getMessage());
         }
@@ -406,6 +406,6 @@ public function execute()
             $data['text'] = '*No data to clean!*';
         }
 
-        return Request::sendMessage($data);
+        return Client::sendMessage($data);
     }
 }
diff --git a/src/Commands/AdminCommands/DebugCommand.php b/src/Commands/AdminCommands/DebugCommand.php
index c00185a88..3fd19bc8e 100644
--- a/src/Commands/AdminCommands/DebugCommand.php
+++ b/src/Commands/AdminCommands/DebugCommand.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\DB;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Admin "/debug" command
@@ -57,7 +57,7 @@ public function execute()
         if ($text !== 'glasnost' && ! $chat->isPrivateChat()) {
             $data['text'] = 'Only available in a private chat.';
 
-            return Request::sendMessage($data);
+            return Client::sendMessage($data);
         }
 
         $debug_info = [];
@@ -95,10 +95,10 @@ public function execute()
         $webhook_info_title = '*Webhook Info:*';
         try {
             // Check if we're actually using the Webhook method.
-            if (Request::getInput() === '') {
+            if (Client::getInput() === '') {
                 $debug_info[] = $webhook_info_title . ' `Using getUpdates method, not Webhook.`';
             } else {
-                $webhook_info_result = json_decode(Request::getWebhookInfo(), true)['result'];
+                $webhook_info_result = json_decode(Client::getWebhookInfo(), true)['result'];
                 // Add a human-readable error date string if necessary.
                 if (isset($webhook_info_result['last_error_date'])) {
                     $webhook_info_result['last_error_date_string'] = date('Y-m-d H:i:s', $webhook_info_result['last_error_date']);
@@ -118,6 +118,6 @@ public function execute()
         $data['parse_mode'] = 'Markdown';
         $data['text'] = implode(PHP_EOL, $debug_info);
 
-        return Request::sendMessage($data);
+        return Client::sendMessage($data);
     }
 }
diff --git a/src/Commands/AdminCommands/SendtoallCommand.php b/src/Commands/AdminCommands/SendtoallCommand.php
index c822bebcd..f9ddef97f 100644
--- a/src/Commands/AdminCommands/SendtoallCommand.php
+++ b/src/Commands/AdminCommands/SendtoallCommand.php
@@ -13,7 +13,7 @@
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\Entities\Message;
 use Longman\TelegramBot\Http\ServerResponse;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Admin "/sendtoall" command
@@ -60,7 +60,7 @@ public function execute()
         }
 
         /** @var ServerResponse[] $results */
-        $results = Request::sendToActiveChats(
+        $results = Client::sendToActiveChats(
             'sendMessage',     //callback function to execute (see Request.php methods)
             ['text' => $text], //Param to evaluate the request
             [
diff --git a/src/Commands/AdminCommands/SendtochannelCommand.php b/src/Commands/AdminCommands/SendtochannelCommand.php
index 88da2cef9..589e80574 100644
--- a/src/Commands/AdminCommands/SendtochannelCommand.php
+++ b/src/Commands/AdminCommands/SendtochannelCommand.php
@@ -15,7 +15,7 @@
 use Longman\TelegramBot\Entities\Chat;
 use Longman\TelegramBot\Entities\Keyboard;
 use Longman\TelegramBot\Entities\Message;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 class SendtochannelCommand extends AdminCommand
 {
@@ -232,7 +232,7 @@ public function execute()
                         if (! $text_yes_or_no && $notes['last_message_id'] !== $message->getMessageId()) {
                             $data['text'] .= PHP_EOL . 'Type Yes or No';
                         }
-                        $result = Request::sendMessage($data);
+                        $result = Client::sendMessage($data);
                     }
                     break;
                 }
@@ -255,7 +255,7 @@ public function execute()
                 }
 
                 $this->conversation->stop();
-                $result = Request::sendMessage($data);
+                $result = Client::sendMessage($data);
         }
 
         return $result;
@@ -305,7 +305,7 @@ protected function sendBack(Message $message, array $data)
             $data['longitude'] = $message->getLocation()->getLongitude();
         }
 
-        return Request::send('send' . ucfirst($type), $data);
+        return Client::send('send' . ucfirst($type), $data);
     }
 
     /**
diff --git a/src/Commands/AdminCommands/WhoisCommand.php b/src/Commands/AdminCommands/WhoisCommand.php
index 3ea56eafc..3fc14b5cd 100644
--- a/src/Commands/AdminCommands/WhoisCommand.php
+++ b/src/Commands/AdminCommands/WhoisCommand.php
@@ -17,7 +17,7 @@
 use Longman\TelegramBot\Entities\Chat;
 use Longman\TelegramBot\Entities\PhotoSize;
 use Longman\TelegramBot\Entities\UserProfilePhotos;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Admin "/whois" command
@@ -141,7 +141,7 @@ public function execute()
                     //Code from Whoami command
                     $limit    = 10;
                     $offset   = null;
-                    $response = Request::getUserProfilePhotos(
+                    $response = Client::getUserProfilePhotos(
                         [
                             'user_id' => $user_id,
                             'limit'   => $limit,
@@ -163,7 +163,7 @@ public function execute()
                             $data['photo']   = $file_id;
                             $data['caption'] = $text;
 
-                            return Request::sendPhoto($data);
+                            return Client::sendPhoto($data);
                         }
                     }
                 } elseif ($chat->isGroupChat()) {
@@ -182,6 +182,6 @@ public function execute()
 
         $data['text'] = $text;
 
-        return Request::sendMessage($data);
+        return Client::sendMessage($data);
     }
 }
diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index 7ee5a202c..5fe6fc220 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -16,7 +16,7 @@
 use Longman\TelegramBot\Entities\InlineQuery;
 use Longman\TelegramBot\Entities\Message;
 use Longman\TelegramBot\Entities\Update;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 use Longman\TelegramBot\Telegram;
 
 /**
@@ -156,7 +156,7 @@ public function preExecute()
             $message = $this->getMessage();
 
             if ($user = $message->getFrom()) {
-                return Request::sendMessage([
+                return Client::sendMessage([
                     'chat_id'    => $user->getId(),
                     'parse_mode' => 'Markdown',
                     'text'       => sprintf(
@@ -167,7 +167,7 @@ public function preExecute()
                 ]);
             }
 
-            return Request::emptyResponse();
+            return Client::emptyResponse();
         }
 
         return $this->execute();
@@ -198,7 +198,7 @@ public function executeNoDb()
             'text'    => 'Sorry no database connection, unable to execute "' . $this->name . '" command.',
         ];
 
-        return Request::sendMessage($data);
+        return Client::sendMessage($data);
     }
 
     /**
@@ -375,7 +375,7 @@ protected function removeNonPrivateMessage()
 
             if (!$chat->isPrivateChat()) {
                 // Delete the falsely called command message.
-                Request::deleteMessage([
+                Client::deleteMessage([
                     'chat_id'    => $chat->getId(),
                     'message_id' => $message->getMessageId(),
                 ]);
@@ -398,13 +398,13 @@ protected function removeNonPrivateMessage()
     public function replyToChat($text, array $data = [])
     {
         if ($message = $this->getMessage() ?: $this->getEditedMessage() ?: $this->getChannelPost() ?: $this->getEditedChannelPost()) {
-            return Request::sendMessage(array_merge([
+            return Client::sendMessage(array_merge([
                 'chat_id' => $message->getChat()->getId(),
                 'text'    => $text,
             ], $data));
         }
 
-        return Request::emptyResponse();
+        return Client::emptyResponse();
     }
 
     /**
@@ -418,12 +418,12 @@ public function replyToChat($text, array $data = [])
     public function replyToUser($text, array $data = [])
     {
         if ($message = $this->getMessage() ?: $this->getEditedMessage()) {
-            return Request::sendMessage(array_merge([
+            return Client::sendMessage(array_merge([
                 'chat_id' => $message->getFrom()->getId(),
                 'text'    => $text,
             ], $data));
         }
 
-        return Request::emptyResponse();
+        return Client::emptyResponse();
     }
 }
diff --git a/src/Commands/SystemCommand.php b/src/Commands/SystemCommand.php
index 61e7b381b..fc3e8b8e4 100644
--- a/src/Commands/SystemCommand.php
+++ b/src/Commands/SystemCommand.php
@@ -10,7 +10,7 @@
 
 namespace Longman\TelegramBot\Commands;
 
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 abstract class SystemCommand extends Command
 {
@@ -25,6 +25,6 @@ abstract class SystemCommand extends Command
     public function execute()
     {
         //System command, return empty ServerResponse by default
-        return Request::emptyResponse();
+        return Client::emptyResponse();
     }
 }
diff --git a/src/Commands/SystemCommands/CallbackqueryCommand.php b/src/Commands/SystemCommands/CallbackqueryCommand.php
index de5c2ed57..bc831c65e 100644
--- a/src/Commands/SystemCommands/CallbackqueryCommand.php
+++ b/src/Commands/SystemCommands/CallbackqueryCommand.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Commands\SystemCommands;
 
 use Longman\TelegramBot\Commands\SystemCommand;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Callback query command
@@ -56,7 +56,7 @@ public function execute()
             $callback($this->getUpdate()->getCallbackQuery());
         }
 
-        return Request::answerCallbackQuery(['callback_query_id' => $this->getUpdate()->getCallbackQuery()->getId()]);
+        return Client::answerCallbackQuery(['callback_query_id' => $this->getUpdate()->getCallbackQuery()->getId()]);
     }
 
     /**
diff --git a/src/Commands/SystemCommands/GenericmessageCommand.php b/src/Commands/SystemCommands/GenericmessageCommand.php
index 035156358..de434a31c 100644
--- a/src/Commands/SystemCommands/GenericmessageCommand.php
+++ b/src/Commands/SystemCommands/GenericmessageCommand.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Commands\SystemCommand;
 use Longman\TelegramBot\Conversation;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Generic message command
@@ -47,7 +47,7 @@ class GenericmessageCommand extends SystemCommand
     public function executeNoDb()
     {
         //Do nothing
-        return Request::emptyResponse();
+        return Client::emptyResponse();
     }
 
     /**
@@ -69,6 +69,6 @@ public function execute()
             return $this->telegram->executeCommand($command);
         }
 
-        return Request::emptyResponse();
+        return Client::emptyResponse();
     }
 }
diff --git a/src/Commands/SystemCommands/InlinequeryCommand.php b/src/Commands/SystemCommands/InlinequeryCommand.php
index d1fb4f721..68753ef5b 100644
--- a/src/Commands/SystemCommands/InlinequeryCommand.php
+++ b/src/Commands/SystemCommands/InlinequeryCommand.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Commands\SystemCommands;
 
 use Longman\TelegramBot\Commands\SystemCommand;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Inline query command
@@ -45,6 +45,6 @@ public function execute()
         //$user_id      = $inline_query->getFrom()->getId();
         //$query        = $inline_query->getQuery();
 
-        return Request::answerInlineQuery(['inline_query_id' => $this->getUpdate()->getInlineQuery()->getId()]);
+        return Client::answerInlineQuery(['inline_query_id' => $this->getUpdate()->getInlineQuery()->getId()]);
     }
 }
diff --git a/src/Entities/CallbackQuery.php b/src/Entities/CallbackQuery.php
index eeca33442..b38eb0ed0 100644
--- a/src/Entities/CallbackQuery.php
+++ b/src/Entities/CallbackQuery.php
@@ -10,7 +10,7 @@
 
 namespace Longman\TelegramBot\Entities;
 
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Class CallbackQuery.
@@ -46,7 +46,7 @@ public function subEntities()
      */
     public function answer(array $data = [])
     {
-        return Request::answerCallbackQuery(array_merge([
+        return Client::answerCallbackQuery(array_merge([
             'callback_query_id' => $this->getId(),
         ], $data));
     }
diff --git a/src/Entities/InlineQuery.php b/src/Entities/InlineQuery.php
index 68d90f464..78bdcebff 100644
--- a/src/Entities/InlineQuery.php
+++ b/src/Entities/InlineQuery.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Entities;
 
 use Longman\TelegramBot\Entities\InlineQuery\InlineQueryResult;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Class InlineQuery
@@ -47,7 +47,7 @@ protected function subEntities()
      */
     public function answer(array $results, array $data = [])
     {
-        return Request::answerCallbackQuery(array_merge([
+        return Client::answerCallbackQuery(array_merge([
             'callback_query_id' => $this->getId(),
             'results'           => $results,
         ], $data));
diff --git a/src/Entities/Payments/PreCheckoutQuery.php b/src/Entities/Payments/PreCheckoutQuery.php
index e198f1a69..d28c32022 100644
--- a/src/Entities/Payments/PreCheckoutQuery.php
+++ b/src/Entities/Payments/PreCheckoutQuery.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Entities\Entity;
 use Longman\TelegramBot\Entities\User;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Class PreCheckoutQuery
@@ -52,7 +52,7 @@ public function subEntities()
      */
     public function answer($ok, array $data = [])
     {
-        return Request::answerPreCheckoutQuery(array_merge([
+        return Client::answerPreCheckoutQuery(array_merge([
             'pre_checkout_query_id' => $this->getId(),
             'ok'                    => $ok,
         ], $data));
diff --git a/src/Entities/Payments/ShippingQuery.php b/src/Entities/Payments/ShippingQuery.php
index bf423c20d..9948a7fd1 100644
--- a/src/Entities/Payments/ShippingQuery.php
+++ b/src/Entities/Payments/ShippingQuery.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Entities\Entity;
 use Longman\TelegramBot\Entities\User;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Class ShippingQuery
@@ -49,7 +49,7 @@ public function subEntities()
      */
     public function answer($ok, array $data = [])
     {
-        return Request::answerShippingQuery(array_merge([
+        return Client::answerShippingQuery(array_merge([
             'shipping_query_id' => $this->getId(),
             'ok'                => $ok,
         ], $data));
diff --git a/src/Http/Client.php b/src/Http/Client.php
new file mode 100644
index 000000000..24a3592fd
--- /dev/null
+++ b/src/Http/Client.php
@@ -0,0 +1,769 @@
+<?php
+/**
+ * This file is part of the TelegramBot package.
+ *
+ * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Longman\TelegramBot\Http;
+
+use GuzzleHttp\Client as GuzzleClient;
+use GuzzleHttp\Exception\RequestException;
+use Longman\TelegramBot\DB;
+use Longman\TelegramBot\Entities\File;
+use Longman\TelegramBot\Exception\TelegramException;
+use Longman\TelegramBot\Telegram;
+use Longman\TelegramBot\TelegramLog;
+
+/**
+ * Class Request
+ *
+ * @method static ServerResponse getUpdates(array $data)              Use this method to receive incoming updates using long polling (wiki). An Array of Update
+ *     objects is returned.
+ * @method static ServerResponse setWebhook(array $data)              Use this method to specify a url and receive incoming updates via an outgoing webhook.
+ *     Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update. In case of an
+ *     unsuccessful request, we will give up after a reasonable amount of attempts. Returns true.
+ * @method static ServerResponse deleteWebhook()                      Use this method to remove webhook integration if you decide to switch back to getUpdates.
+ *     Returns True on success. Requires no parameters.
+ * @method static ServerResponse getWebhookInfo()                     Use this method to get current webhook status. Requires no parameters. On success,
+ *     returns a WebhookInfo object. If the bot is using getUpdates, will return an object with the url field empty.
+ * @method static ServerResponse getMe()                              A simple method for testing your bot's auth token. Requires no parameters. Returns basic
+ *     information about the bot in form of a User object.
+ * @method static ServerResponse forwardMessage(array $data)          Use this method to forward messages of any kind. On success, the sent Message is
+ *     returned.
+ * @method static ServerResponse sendPhoto(array $data)               Use this method to send photos. On success, the sent Message is returned.
+ * @method static ServerResponse sendAudio(array $data)               Use this method to send audio files, if you want Telegram clients to display them in the
+ *     music player. Your audio must be in the .mp3 format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in
+ *     size, this limit may be changed in the future.
+ * @method static ServerResponse sendDocument(array $data)            Use this method to send general files. On success, the sent Message is returned. Bots can
+ *     currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
+ * @method static ServerResponse sendSticker(array $data)             Use this method to send .webp stickers. On success, the sent Message is returned.
+ * @method static ServerResponse sendVideo(array $data)               Use this method to send video files, Telegram clients support mp4 videos (other formats
+ *     may be sent as Document). On success, the sent Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may be
+ *     changed in the future.
+ * @method static ServerResponse sendVoice(array $data)               Use this method to send audio files, if you want Telegram clients to display the file as
+ *     a playable voice message. For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as Audio or Document). On
+ *     success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
+ * @method static ServerResponse sendVideoNote(array $data)           Use this method to send video messages. On success, the sent Message is returned.
+ * @method static ServerResponse sendMediaGroup(array $data)          Use this method to send a group of photos or videos as an album. On success, an array of
+ *     the sent Messages is returned.
+ * @method static ServerResponse sendLocation(array $data)            Use this method to send point on the map. On success, the sent Message is returned.
+ * @method static ServerResponse editMessageLiveLocation(array $data) Use this method to edit live location messages sent by the bot or via the bot (for inline
+ *     bots). A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the
+ *     edited message was sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse stopMessageLiveLocation(array $data) Use this method to stop updating a live location message sent by the bot or via the bot
+ *     (for inline bots) before live_period expires. On success, if the message was sent by the bot, the sent Message is returned, otherwise True is returned.
+ * @method static ServerResponse sendVenue(array $data)               Use this method to send information about a venue. On success, the sent Message is
+ *     returned.
+ * @method static ServerResponse sendContact(array $data)             Use this method to send phone contacts. On success, the sent Message is returned.
+ * @method static ServerResponse sendChatAction(array $data)          Use this method when you need to tell the user that something is happening on the bot's
+ *     side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.
+ * @method static ServerResponse getUserProfilePhotos(array $data)    Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos
+ *     object.
+ * @method static ServerResponse getFile(array $data)                 Use this method to get basic info about a file and prepare it for downloading. For the
+ *     moment, bots can download files of up to 20MB in size. On success, a File object is returned. The file can then be downloaded via the link
+ *     https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> is taken from the response. It is guaranteed that the link will be valid for at
+ *     least 1 hour. When the link expires, a new one can be requested by calling getFile again.
+ * @method static ServerResponse kickChatMember(array $data)          Use this method to kick a user from a group, a supergroup or a channel. In the case of
+ *     supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot must be
+ *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse unbanChatMember(array $data)         Use this method to unban a previously kicked user in a supergroup or channel. The user
+ *     will not return to the group or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to work.
+ *     Returns True on success.
+ * @method static ServerResponse restrictChatMember(array $data)      Use this method to restrict a user in a supergroup. The bot must be an administrator in
+ *     the supergroup for this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift restrictions from a user.
+ *     Returns True on success.
+ * @method static ServerResponse promoteChatMember(array $data)       Use this method to promote or demote a user in a supergroup or a channel. The bot must be
+ *     an administrator in the chat for this to work and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user.
+ *     Returns True on success.
+ * @method static ServerResponse exportChatInviteLink(array $data)    Use this method to export an invite link to a supergroup or a channel. The bot must be an
+ *     administrator in the chat for this to work and must have the appropriate admin rights. Returns exported invite link as String on success.
+ * @method static ServerResponse setChatPhoto(array $data)            Use this method to set a new profile photo for the chat. Photos can't be changed for
+ *     private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse deleteChatPhoto(array $data)         Use this method to delete a chat photo. Photos can't be changed for private chats. The
+ *     bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse setChatTitle(array $data)            Use this method to change the title of a chat. Titles can't be changed for private chats.
+ *     The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse setChatDescription(array $data)      Use this method to change the description of a supergroup or a channel. The bot must be
+ *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
+ * @method static ServerResponse pinChatMessage(array $data)          Use this method to pin a message in a supergroup or a channel. The bot must be an
+ *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
+ *     channel. Returns True on success.
+ * @method static ServerResponse unpinChatMessage(array $data)        Use this method to unpin a message in a supergroup or a channel. The bot must be an
+ *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
+ *     channel. Returns True on success.
+ * @method static ServerResponse leaveChat(array $data)               Use this method for your bot to leave a group, supergroup or channel. Returns True on
+ *     success.
+ * @method static ServerResponse getChat(array $data)                 Use this method to get up to date information about the chat (current name of the user
+ *     for one-on-one conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
+ * @method static ServerResponse getChatAdministrators(array $data)   Use this method to get a list of administrators in a chat. On success, returns an Array
+ *     of ChatMember objects that contains information about all chat administrators except other bots. If the chat is a group or a supergroup and no
+ *     administrators were appointed, only the creator will be returned.
+ * @method static ServerResponse getChatMembersCount(array $data)     Use this method to get the number of members in a chat. Returns Int on success.
+ * @method static ServerResponse getChatMember(array $data)           Use this method to get information about a member of a chat. Returns a ChatMember object
+ *     on success.
+ * @method static ServerResponse setChatStickerSet(array $data)       Use this method to set a new group sticker set for a supergroup. The bot must be an
+ *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
+ *     requests to check if the bot can use this method. Returns True on success.
+ * @method static ServerResponse deleteChatStickerSet(array $data)    Use this method to delete a group sticker set from a supergroup. The bot must be an
+ *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
+ *     requests to check if the bot can use this method. Returns True on success.
+ * @method static ServerResponse answerCallbackQuery(array $data)     Use this method to send answers to callback queries sent from inline keyboards. The
+ *     answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned.
+ * @method static ServerResponse answerInlineQuery(array $data)       Use this method to send answers to an inline query. On success, True is returned.
+ * @method static ServerResponse editMessageText(array $data)         Use this method to edit text and game messages sent by the bot or via the bot (for inline
+ *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse editMessageCaption(array $data)      Use this method to edit captions of messages sent by the bot or via the bot (for inline
+ *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse editMessageReplyMarkup(array $data)  Use this method to edit only the reply markup of messages sent by the bot or via the bot
+ *     (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
+ * @method static ServerResponse deleteMessage(array $data)           Use this method to delete a message, including service messages, with certain
+ *     limitations. Returns True on success.
+ * @method static ServerResponse getStickerSet(array $data)           Use this method to get a sticker set. On success, a StickerSet object is returned.
+ * @method static ServerResponse uploadStickerFile(array $data)       Use this method to upload a .png file with a sticker for later use in createNewStickerSet
+ *     and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success.
+ * @method static ServerResponse createNewStickerSet(array $data)     Use this method to create new sticker set owned by a user. The bot will be able to edit
+ *     the created sticker set. Returns True on success.
+ * @method static ServerResponse addStickerToSet(array $data)         Use this method to add a new sticker to a set created by the bot. Returns True on
+ *     success.
+ * @method static ServerResponse setStickerPositionInSet(array $data) Use this method to move a sticker in a set created by the bot to a specific position.
+ *     Returns True on success.
+ * @method static ServerResponse deleteStickerFromSet(array $data)    Use this method to delete a sticker from a set created by the bot. Returns True on
+ *     success.
+ * @method static ServerResponse sendInvoice(array $data)             Use this method to send invoices. On success, the sent Message is returned.
+ * @method static ServerResponse answerShippingQuery(array $data)     If you sent an invoice requesting a shipping address and the parameter is_flexible was
+ *     specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is
+ *     returned.
+ * @method static ServerResponse answerPreCheckoutQuery(array $data)  Once the user has confirmed their payment and shipping details, the Bot API sends the
+ *     final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True
+ *     is returned.
+ */
+class Client
+{
+    /**
+     * Telegram object
+     *
+     * @var \Longman\TelegramBot\Telegram
+     */
+    private static $telegram;
+
+    /**
+     * URI of the Telegram API
+     *
+     * @var string
+     */
+    private static $api_base_uri = 'https://api.telegram.org';
+
+    /**
+     * Guzzle Client object
+     *
+     * @var \GuzzleHttp\Client
+     */
+    private static $client;
+
+    /**
+     * Input value of the request
+     *
+     * @var string
+     */
+    private static $input;
+
+    /**
+     * Request limiter
+     *
+     * @var boolean
+     */
+    private static $limiter_enabled;
+
+    /**
+     * Request limiter's interval between checks
+     *
+     * @var float
+     */
+    private static $limiter_interval;
+
+    /**
+     * Available actions to send
+     *
+     * This is basically the list of all methods listed on the official API documentation.
+     *
+     * @link https://core.telegram.org/bots/api
+     *
+     * @var array
+     */
+    private static $actions = [
+        'getUpdates',
+        'setWebhook',
+        'deleteWebhook',
+        'getWebhookInfo',
+        'getMe',
+        'sendMessage',
+        'forwardMessage',
+        'sendPhoto',
+        'sendAudio',
+        'sendDocument',
+        'sendSticker',
+        'sendVideo',
+        'sendVoice',
+        'sendVideoNote',
+        'sendMediaGroup',
+        'sendLocation',
+        'editMessageLiveLocation',
+        'stopMessageLiveLocation',
+        'sendVenue',
+        'sendContact',
+        'sendChatAction',
+        'getUserProfilePhotos',
+        'getFile',
+        'kickChatMember',
+        'unbanChatMember',
+        'restrictChatMember',
+        'promoteChatMember',
+        'exportChatInviteLink',
+        'setChatPhoto',
+        'deleteChatPhoto',
+        'setChatTitle',
+        'setChatDescription',
+        'pinChatMessage',
+        'unpinChatMessage',
+        'leaveChat',
+        'getChat',
+        'getChatAdministrators',
+        'getChatMembersCount',
+        'getChatMember',
+        'setChatStickerSet',
+        'deleteChatStickerSet',
+        'answerCallbackQuery',
+        'answerInlineQuery',
+        'editMessageText',
+        'editMessageCaption',
+        'editMessageReplyMarkup',
+        'deleteMessage',
+        'getStickerSet',
+        'uploadStickerFile',
+        'createNewStickerSet',
+        'addStickerToSet',
+        'setStickerPositionInSet',
+        'deleteStickerFromSet',
+        'sendInvoice',
+        'answerShippingQuery',
+        'answerPreCheckoutQuery',
+    ];
+
+    /**
+     * Some methods need a dummy param due to certain cURL issues.
+     *
+     * @see Client::addDummyParamIfNecessary()
+     *
+     * @var array
+     */
+    private static $actions_need_dummy_param = [
+        'deleteWebhook',
+        'getWebhookInfo',
+        'getMe',
+    ];
+
+    /**
+     * Initialize
+     *
+     * @param \Longman\TelegramBot\Telegram $telegram
+     *
+     * @throws TelegramException
+     */
+    public static function initialize(Telegram $telegram)
+    {
+        if (! ($telegram instanceof Telegram)) {
+            throw new TelegramException('Invalid Telegram pointer!');
+        }
+
+        self::$telegram = $telegram;
+        self::setClient(new GuzzleClient(['base_uri' => self::$api_base_uri]));
+    }
+
+    /**
+     * Set a custom Guzzle HTTP Client object
+     *
+     * @param Client $client
+     *
+     * @throws TelegramException
+     */
+    public static function setClient(GuzzleClient $client)
+    {
+        if (! ($client instanceof GuzzleClient)) {
+            throw new TelegramException('Invalid GuzzleHttp\Client pointer!');
+        }
+
+        self::$client = $client;
+    }
+
+    /**
+     * Set input from custom input or stdin and return it
+     *
+     * @return string
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function getInput()
+    {
+        // First check if a custom input has been set, else get the PHP input.
+        if (! ($input = self::$telegram->getCustomInput())) {
+            $input = file_get_contents('php://input');
+        }
+
+        // Make sure we have a string to work with.
+        if (! is_string($input)) {
+            throw new TelegramException('Input must be a string!');
+        }
+
+        self::$input = $input;
+
+        TelegramLog::update(self::$input);
+
+        return self::$input;
+    }
+
+    /**
+     * Generate general fake server response
+     *
+     * @param array $data Data to add to fake response
+     *
+     * @return array Fake response data
+     */
+    public static function generateGeneralFakeServerResponse(array $data = [])
+    {
+        //PARAM BINDED IN PHPUNIT TEST FOR TestServerResponse.php
+        //Maybe this is not the best possible implementation
+
+        //No value set in $data ie testing setWebhook
+        //Provided $data['chat_id'] ie testing sendMessage
+
+        $fake_response = ['ok' => true]; // :)
+
+        if ($data === []) {
+            $fake_response['result'] = true;
+        }
+
+        //some data to let iniatilize the class method SendMessage
+        if (isset($data['chat_id'])) {
+            $data['message_id'] = '1234';
+            $data['date'] = '1441378360';
+            $data['from'] = [
+                'id'         => 123456789,
+                'first_name' => 'botname',
+                'username'   => 'namebot',
+            ];
+            $data['chat'] = ['id' => $data['chat_id']];
+
+            $fake_response['result'] = $data;
+        }
+
+        return $fake_response;
+    }
+
+    /**
+     * Properly set up the request params
+     *
+     * If any item of the array is a resource, reformat it to a multipart request.
+     * Else, just return the passed data as form params.
+     *
+     * @param array $data
+     *
+     * @return array
+     */
+    private static function setUpRequestParams(array $data)
+    {
+        $has_resource = false;
+        $multipart = [];
+
+        // Convert any nested arrays into JSON strings.
+        array_walk($data, function (&$item) {
+            is_array($item) && $item = json_encode($item);
+        });
+
+        //Reformat data array in multipart way if it contains a resource
+        foreach ($data as $key => $item) {
+            $has_resource |= (is_resource($item) || $item instanceof \GuzzleHttp\Psr7\Stream);
+            $multipart[] = ['name' => $key, 'contents' => $item];
+        }
+        if ($has_resource) {
+            return ['multipart' => $multipart];
+        }
+
+        return ['form_params' => $data];
+    }
+
+    /**
+     * Execute HTTP Request
+     *
+     * @param string $action Action to execute
+     * @param array $data Data to attach to the execution
+     *
+     * @return string Result of the HTTP Request
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function execute($action, array $data = [])
+    {
+        //Fix so that the keyboard markup is a string, not an object
+        if (isset($data['reply_markup'])) {
+            $data['reply_markup'] = json_encode($data['reply_markup']);
+        }
+
+        $result = null;
+        $request_params = self::setUpRequestParams($data);
+        $request_params['debug'] = TelegramLog::getDebugLogTempStream();
+
+        try {
+            $response = self::$client->post(
+                '/bot' . self::$telegram->getApiKey() . '/' . $action,
+                $request_params
+            );
+            $result = (string) $response->getBody();
+
+            //Logging getUpdates Update
+            if ($action === 'getUpdates') {
+                TelegramLog::update($result);
+            }
+        } catch (RequestException $e) {
+            $result = ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
+        } finally {
+            //Logging verbose debug output
+            TelegramLog::endDebugLogTempStream('Verbose HTTP Request output:' . PHP_EOL . '%s' . PHP_EOL);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Download file
+     *
+     * @param \Longman\TelegramBot\Entities\File $file
+     *
+     * @return boolean
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function downloadFile(File $file)
+    {
+        if (empty($download_path = self::$telegram->getDownloadPath())) {
+            throw new TelegramException('Download path not set!');
+        }
+
+        $tg_file_path = $file->getFilePath();
+        $file_path = $download_path . '/' . $tg_file_path;
+
+        $file_dir = dirname($file_path);
+        //For safety reasons, first try to create the directory, then check that it exists.
+        //This is in case some other process has created the folder in the meantime.
+        if (! @mkdir($file_dir, 0755, true) && ! is_dir($file_dir)) {
+            throw new TelegramException('Directory ' . $file_dir . ' can\'t be created');
+        }
+
+        $debug_handle = TelegramLog::getDebugLogTempStream();
+
+        try {
+            self::$client->get(
+                '/file/bot' . self::$telegram->getApiKey() . '/' . $tg_file_path,
+                ['debug' => $debug_handle, 'sink' => $file_path]
+            );
+
+            return filesize($file_path) > 0;
+        } catch (RequestException $e) {
+            return ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
+        } finally {
+            //Logging verbose debug output
+            TelegramLog::endDebugLogTempStream('Verbose HTTP File Download Request output:' . PHP_EOL . '%s' . PHP_EOL);
+        }
+    }
+
+    /**
+     * Encode file
+     *
+     * @param string $file
+     *
+     * @return resource
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function encodeFile($file)
+    {
+        $fp = fopen($file, 'rb');
+        if ($fp === false) {
+            throw new TelegramException('Cannot open "' . $file . '" for reading');
+        }
+
+        return $fp;
+    }
+
+    /**
+     * Send command
+     *
+     * @todo Fake response doesn't need json encoding?
+     * @todo Write debug entry on failure
+     *
+     * @param string $action
+     * @param array $data
+     *
+     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function send($action, array $data = [])
+    {
+        self::ensureValidAction($action);
+        self::addDummyParamIfNecessary($action, $data);
+
+        $bot_username = self::$telegram->getBotUsername();
+
+        if (defined('PHPUNIT_TESTSUITE')) {
+            $fake_response = self::generateGeneralFakeServerResponse($data);
+
+            return new ServerResponse($fake_response, $bot_username);
+        }
+
+        self::ensureNonEmptyData($data);
+
+        self::limitTelegramRequests($action, $data);
+
+        $response = json_decode(self::execute($action, $data), true);
+
+        if (null === $response) {
+            throw new TelegramException('Telegram returned an invalid response! Please review your bot name and API key.');
+        }
+
+        return new ServerResponse($response, $bot_username);
+    }
+
+    /**
+     * Add a dummy parameter if the passed action requires it.
+     *
+     * If a method doesn't require parameters, we need to add a dummy one anyway,
+     * because of some cURL version failed POST request without parameters.
+     *
+     * @link https://github.com/php-telegram-bot/core/pull/228
+     *
+     * @todo Would be nice to find a better solution for this!
+     *
+     * @param string $action
+     * @param array $data
+     */
+    protected static function addDummyParamIfNecessary($action, array &$data)
+    {
+        if (in_array($action, self::$actions_need_dummy_param, true)) {
+            // Can be anything, using a single letter to minimise request size.
+            $data = ['d'];
+        }
+    }
+
+    /**
+     * Make sure the data isn't empty, else throw an exception
+     *
+     * @param array $data
+     *
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    private static function ensureNonEmptyData(array $data)
+    {
+        if (count($data) === 0) {
+            throw new TelegramException('Data is empty!');
+        }
+    }
+
+    /**
+     * Make sure the action is valid, else throw an exception
+     *
+     * @param string $action
+     *
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    private static function ensureValidAction($action)
+    {
+        if (! in_array($action, self::$actions, true)) {
+            throw new TelegramException('The action "' . $action . '" doesn\'t exist!');
+        }
+    }
+
+    /**
+     * Use this method to send text messages. On success, the sent Message is returned
+     *
+     * @link https://core.telegram.org/bots/api#sendmessage
+     *
+     * @param array $data
+     *
+     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function sendMessage(array $data)
+    {
+        $text = $data['text'];
+
+        do {
+            //Chop off and send the first message
+            $data['text'] = mb_substr($text, 0, 4096);
+            $response = self::send('sendMessage', $data);
+
+            //Prepare the next message
+            $text = mb_substr($text, 4096);
+        } while (mb_strlen($text, 'UTF-8') > 0);
+
+        return $response;
+    }
+
+    /**
+     * Any statically called method should be relayed to the `send` method.
+     *
+     * @param string $action
+     * @param array $data
+     *
+     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function __callStatic($action, array $data)
+    {
+        // Make sure to add the action being called as the first parameter to be passed.
+        array_unshift($data, $action);
+
+        // @todo Use splat operator for unpacking when we move to PHP 5.6+
+        return call_user_func_array('static::send', $data);
+    }
+
+    /**
+     * Return an empty Server Response
+     *
+     * No request to telegram are sent, this function is used in commands that
+     * don't need to fire a message after execution
+     *
+     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function emptyResponse()
+    {
+        return new ServerResponse(['ok' => true, 'result' => true], null);
+    }
+
+    /**
+     * Send message to all active chats
+     *
+     * @param string $callback_function
+     * @param array $data
+     * @param array $select_chats_params
+     *
+     * @return array
+     * @throws TelegramException
+     */
+    public static function sendToActiveChats(
+        $callback_function,
+        array $data,
+        array $select_chats_params
+    ) {
+        if (! method_exists(Client::class, $callback_function)) {
+            throw new TelegramException('Method "' . $callback_function . '" not found in class Request.');
+        }
+
+        $chats = DB::selectChats($select_chats_params);
+
+        $results = [];
+        if (is_array($chats)) {
+            foreach ($chats as $row) {
+                $data['chat_id'] = $row['chat_id'];
+                $results[] = call_user_func(Client::class . '::' . $callback_function, $data);
+            }
+        }
+
+        return $results;
+    }
+
+    /**
+     * Enable request limiter
+     *
+     * @param boolean $enable
+     * @param array $options
+     *
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function setLimiter($enable = true, array $options = [])
+    {
+        if (DB::isDbConnected()) {
+            $options_default = [
+                'interval' => 1,
+            ];
+
+            $options = array_merge($options_default, $options);
+
+            if (! is_numeric($options['interval']) || $options['interval'] <= 0) {
+                throw new TelegramException('Interval must be a number and must be greater than zero!');
+            }
+
+            self::$limiter_interval = $options['interval'];
+            self::$limiter_enabled = $enable;
+        }
+    }
+
+    /**
+     * This functions delays API requests to prevent reaching Telegram API limits
+     *  Can be disabled while in execution by 'Request::setLimiter(false)'
+     *
+     * @link https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this
+     *
+     * @param string $action
+     * @param array $data
+     *
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    private static function limitTelegramRequests($action, array $data = [])
+    {
+        if (self::$limiter_enabled) {
+            $limited_methods = [
+                'sendMessage',
+                'forwardMessage',
+                'sendPhoto',
+                'sendAudio',
+                'sendDocument',
+                'sendSticker',
+                'sendVideo',
+                'sendVoice',
+                'sendVideoNote',
+                'sendMediaGroup',
+                'sendLocation',
+                'editMessageLiveLocation',
+                'stopMessageLiveLocation',
+                'sendVenue',
+                'sendContact',
+                'sendInvoice',
+                'editMessageText',
+                'editMessageCaption',
+                'editMessageReplyMarkup',
+                'setChatTitle',
+                'setChatDescription',
+                'setChatStickerSet',
+                'deleteChatStickerSet',
+            ];
+
+            $chat_id = isset($data['chat_id']) ? $data['chat_id'] : null;
+            $inline_message_id = isset($data['inline_message_id']) ? $data['inline_message_id'] : null;
+
+            if (($chat_id || $inline_message_id) && in_array($action, $limited_methods)) {
+                $timeout = 60;
+
+                while (true) {
+                    if ($timeout <= 0) {
+                        throw new TelegramException('Timed out while waiting for a request spot!');
+                    }
+
+                    $requests = DB::getTelegramRequestCount($chat_id, $inline_message_id);
+
+                    $chat_per_second = ($requests['LIMIT_PER_SEC'] == 0); // No more than one message per second inside a particular chat
+                    $global_per_second = ($requests['LIMIT_PER_SEC_ALL'] < 30);    // No more than 30 messages per second to different chats
+                    $groups_per_minute = (((is_numeric($chat_id) && $chat_id > 0) || ! is_null($inline_message_id)) || ((! is_numeric($chat_id) || $chat_id < 0) && $requests['LIMIT_PER_MINUTE'] < 20));    // No more than 20 messages per minute in groups and channels
+
+                    if ($chat_per_second && $global_per_second && $groups_per_minute) {
+                        break;
+                    }
+
+                    $timeout--;
+                    usleep(self::$limiter_interval * 1000000);
+                }
+
+                DB::insertTelegramRequest($action, $data);
+            }
+        }
+    }
+}
diff --git a/tests/unit/Commands/CustomTestCommands/HiddenCommand.php b/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
index 9fac12d59..1b9a8b2de 100644
--- a/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
+++ b/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Commands\UserCommands;
 
 use Longman\TelegramBot\Commands\UserCommand;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Test "/hidden" command to test $show_in_help
@@ -51,6 +51,6 @@ class HiddenCommand extends UserCommand
      */
     public function execute()
     {
-        return Request::emptyResponse();
+        return Client::emptyResponse();
     }
 }
diff --git a/tests/unit/Commands/CustomTestCommands/VisibleCommand.php b/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
index bb7634beb..870dd23b9 100644
--- a/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
+++ b/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
@@ -11,7 +11,7 @@
 namespace Longman\TelegramBot\Commands\UserCommands;
 
 use Longman\TelegramBot\Commands\UserCommand;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * Test "/visible" command to test $show_in_help
@@ -51,6 +51,6 @@ class VisibleCommand extends UserCommand
      */
     public function execute()
     {
-        return Request::emptyResponse();
+        return Client::emptyResponse();
     }
 }
diff --git a/tests/unit/Entities/ServerResponseTest.php b/tests/unit/Entities/ServerResponseTest.php
index 9f48673a0..537edde51 100644
--- a/tests/unit/Entities/ServerResponseTest.php
+++ b/tests/unit/Entities/ServerResponseTest.php
@@ -14,7 +14,7 @@
 
 use Longman\TelegramBot\Entities\Message;
 use Longman\TelegramBot\Http\ServerResponse;
-use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Client;
 
 /**
  * @package         TelegramTest
@@ -259,7 +259,7 @@ public function testGetFile()
     public function testSetGeneralTestFakeResponse()
     {
         //setWebhook ok
-        $fake_response = Request::generateGeneralFakeServerResponse();
+        $fake_response = Client::generateGeneralFakeServerResponse();
 
         $server = new ServerResponse($fake_response, 'testbot');
 
@@ -269,7 +269,7 @@ public function testSetGeneralTestFakeResponse()
         self::assertEquals('', $server->getDescription());
 
         //sendMessage ok
-        $fake_response = Request::generateGeneralFakeServerResponse(['chat_id' => 123456789, 'text' => 'hello']);
+        $fake_response = Client::generateGeneralFakeServerResponse(['chat_id' => 123456789, 'text' => 'hello']);
 
         $server = new ServerResponse($fake_response, 'testbot');
 
diff --git a/tests/unit/TelegramTest.php b/tests/unit/TelegramTest.php
index 1ea3a8d3c..e45c63195 100644
--- a/tests/unit/TelegramTest.php
+++ b/tests/unit/TelegramTest.php
@@ -151,4 +151,13 @@ public function testContainer()
 
         $this->assertInstanceOf(\Illuminate\Container\Container::class, $telegram);
     }
+
+    public function testCustom()
+    {
+        $telegram = new Telegram(self::$dummy_api_key, 'testbot');
+
+        $telegram->handle();
+
+        $this->assertTrue(true);
+    }
 }

From 81799e298958c1c04c3d6865d23722a984ca4902 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 17:54:26 +0400
Subject: [PATCH 09/40] Create http request class

---
 src/Http/Request.php | 755 +------------------------------------------
 1 file changed, 3 insertions(+), 752 deletions(-)

diff --git a/src/Http/Request.php b/src/Http/Request.php
index aa8b22118..83d8569fe 100644
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -10,760 +10,11 @@
 
 namespace Longman\TelegramBot\Http;
 
-use GuzzleHttp\Client;
-use GuzzleHttp\Exception\RequestException;
-use Longman\TelegramBot\DB;
-use Longman\TelegramBot\Entities\File;
-use Longman\TelegramBot\Exception\TelegramException;
-use Longman\TelegramBot\Telegram;
-use Longman\TelegramBot\TelegramLog;
+use Illuminate\Http\Request as LaravelRequest;
 
-/**
- * Class Request
- *
- * @method static ServerResponse getUpdates(array $data)              Use this method to receive incoming updates using long polling (wiki). An Array of Update
- *     objects is returned.
- * @method static ServerResponse setWebhook(array $data)              Use this method to specify a url and receive incoming updates via an outgoing webhook.
- *     Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update. In case of an
- *     unsuccessful request, we will give up after a reasonable amount of attempts. Returns true.
- * @method static ServerResponse deleteWebhook()                      Use this method to remove webhook integration if you decide to switch back to getUpdates.
- *     Returns True on success. Requires no parameters.
- * @method static ServerResponse getWebhookInfo()                     Use this method to get current webhook status. Requires no parameters. On success,
- *     returns a WebhookInfo object. If the bot is using getUpdates, will return an object with the url field empty.
- * @method static ServerResponse getMe()                              A simple method for testing your bot's auth token. Requires no parameters. Returns basic
- *     information about the bot in form of a User object.
- * @method static ServerResponse forwardMessage(array $data)          Use this method to forward messages of any kind. On success, the sent Message is
- *     returned.
- * @method static ServerResponse sendPhoto(array $data)               Use this method to send photos. On success, the sent Message is returned.
- * @method static ServerResponse sendAudio(array $data)               Use this method to send audio files, if you want Telegram clients to display them in the
- *     music player. Your audio must be in the .mp3 format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in
- *     size, this limit may be changed in the future.
- * @method static ServerResponse sendDocument(array $data)            Use this method to send general files. On success, the sent Message is returned. Bots can
- *     currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
- * @method static ServerResponse sendSticker(array $data)             Use this method to send .webp stickers. On success, the sent Message is returned.
- * @method static ServerResponse sendVideo(array $data)               Use this method to send video files, Telegram clients support mp4 videos (other formats
- *     may be sent as Document). On success, the sent Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may be
- *     changed in the future.
- * @method static ServerResponse sendVoice(array $data)               Use this method to send audio files, if you want Telegram clients to display the file as
- *     a playable voice message. For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as Audio or Document). On
- *     success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
- * @method static ServerResponse sendVideoNote(array $data)           Use this method to send video messages. On success, the sent Message is returned.
- * @method static ServerResponse sendMediaGroup(array $data)          Use this method to send a group of photos or videos as an album. On success, an array of
- *     the sent Messages is returned.
- * @method static ServerResponse sendLocation(array $data)            Use this method to send point on the map. On success, the sent Message is returned.
- * @method static ServerResponse editMessageLiveLocation(array $data) Use this method to edit live location messages sent by the bot or via the bot (for inline
- *     bots). A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the
- *     edited message was sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse stopMessageLiveLocation(array $data) Use this method to stop updating a live location message sent by the bot or via the bot
- *     (for inline bots) before live_period expires. On success, if the message was sent by the bot, the sent Message is returned, otherwise True is returned.
- * @method static ServerResponse sendVenue(array $data)               Use this method to send information about a venue. On success, the sent Message is
- *     returned.
- * @method static ServerResponse sendContact(array $data)             Use this method to send phone contacts. On success, the sent Message is returned.
- * @method static ServerResponse sendChatAction(array $data)          Use this method when you need to tell the user that something is happening on the bot's
- *     side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.
- * @method static ServerResponse getUserProfilePhotos(array $data)    Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos
- *     object.
- * @method static ServerResponse getFile(array $data)                 Use this method to get basic info about a file and prepare it for downloading. For the
- *     moment, bots can download files of up to 20MB in size. On success, a File object is returned. The file can then be downloaded via the link
- *     https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> is taken from the response. It is guaranteed that the link will be valid for at
- *     least 1 hour. When the link expires, a new one can be requested by calling getFile again.
- * @method static ServerResponse kickChatMember(array $data)          Use this method to kick a user from a group, a supergroup or a channel. In the case of
- *     supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot must be
- *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse unbanChatMember(array $data)         Use this method to unban a previously kicked user in a supergroup or channel. The user
- *     will not return to the group or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to work.
- *     Returns True on success.
- * @method static ServerResponse restrictChatMember(array $data)      Use this method to restrict a user in a supergroup. The bot must be an administrator in
- *     the supergroup for this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift restrictions from a user.
- *     Returns True on success.
- * @method static ServerResponse promoteChatMember(array $data)       Use this method to promote or demote a user in a supergroup or a channel. The bot must be
- *     an administrator in the chat for this to work and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user.
- *     Returns True on success.
- * @method static ServerResponse exportChatInviteLink(array $data)    Use this method to export an invite link to a supergroup or a channel. The bot must be an
- *     administrator in the chat for this to work and must have the appropriate admin rights. Returns exported invite link as String on success.
- * @method static ServerResponse setChatPhoto(array $data)            Use this method to set a new profile photo for the chat. Photos can't be changed for
- *     private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse deleteChatPhoto(array $data)         Use this method to delete a chat photo. Photos can't be changed for private chats. The
- *     bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse setChatTitle(array $data)            Use this method to change the title of a chat. Titles can't be changed for private chats.
- *     The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse setChatDescription(array $data)      Use this method to change the description of a supergroup or a channel. The bot must be
- *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse pinChatMessage(array $data)          Use this method to pin a message in a supergroup or a channel. The bot must be an
- *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
- *     channel. Returns True on success.
- * @method static ServerResponse unpinChatMessage(array $data)        Use this method to unpin a message in a supergroup or a channel. The bot must be an
- *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
- *     channel. Returns True on success.
- * @method static ServerResponse leaveChat(array $data)               Use this method for your bot to leave a group, supergroup or channel. Returns True on
- *     success.
- * @method static ServerResponse getChat(array $data)                 Use this method to get up to date information about the chat (current name of the user
- *     for one-on-one conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
- * @method static ServerResponse getChatAdministrators(array $data)   Use this method to get a list of administrators in a chat. On success, returns an Array
- *     of ChatMember objects that contains information about all chat administrators except other bots. If the chat is a group or a supergroup and no
- *     administrators were appointed, only the creator will be returned.
- * @method static ServerResponse getChatMembersCount(array $data)     Use this method to get the number of members in a chat. Returns Int on success.
- * @method static ServerResponse getChatMember(array $data)           Use this method to get information about a member of a chat. Returns a ChatMember object
- *     on success.
- * @method static ServerResponse setChatStickerSet(array $data)       Use this method to set a new group sticker set for a supergroup. The bot must be an
- *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
- *     requests to check if the bot can use this method. Returns True on success.
- * @method static ServerResponse deleteChatStickerSet(array $data)    Use this method to delete a group sticker set from a supergroup. The bot must be an
- *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
- *     requests to check if the bot can use this method. Returns True on success.
- * @method static ServerResponse answerCallbackQuery(array $data)     Use this method to send answers to callback queries sent from inline keyboards. The
- *     answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned.
- * @method static ServerResponse answerInlineQuery(array $data)       Use this method to send answers to an inline query. On success, True is returned.
- * @method static ServerResponse editMessageText(array $data)         Use this method to edit text and game messages sent by the bot or via the bot (for inline
- *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse editMessageCaption(array $data)      Use this method to edit captions of messages sent by the bot or via the bot (for inline
- *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse editMessageReplyMarkup(array $data)  Use this method to edit only the reply markup of messages sent by the bot or via the bot
- *     (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse deleteMessage(array $data)           Use this method to delete a message, including service messages, with certain
- *     limitations. Returns True on success.
- * @method static ServerResponse getStickerSet(array $data)           Use this method to get a sticker set. On success, a StickerSet object is returned.
- * @method static ServerResponse uploadStickerFile(array $data)       Use this method to upload a .png file with a sticker for later use in createNewStickerSet
- *     and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success.
- * @method static ServerResponse createNewStickerSet(array $data)     Use this method to create new sticker set owned by a user. The bot will be able to edit
- *     the created sticker set. Returns True on success.
- * @method static ServerResponse addStickerToSet(array $data)         Use this method to add a new sticker to a set created by the bot. Returns True on
- *     success.
- * @method static ServerResponse setStickerPositionInSet(array $data) Use this method to move a sticker in a set created by the bot to a specific position.
- *     Returns True on success.
- * @method static ServerResponse deleteStickerFromSet(array $data)    Use this method to delete a sticker from a set created by the bot. Returns True on
- *     success.
- * @method static ServerResponse sendInvoice(array $data)             Use this method to send invoices. On success, the sent Message is returned.
- * @method static ServerResponse answerShippingQuery(array $data)     If you sent an invoice requesting a shipping address and the parameter is_flexible was
- *     specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is
- *     returned.
- * @method static ServerResponse answerPreCheckoutQuery(array $data)  Once the user has confirmed their payment and shipping details, the Bot API sends the
- *     final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True
- *     is returned.
- */
-class Request
-{
-    /**
-     * Telegram object
-     *
-     * @var \Longman\TelegramBot\Telegram
-     */
-    private static $telegram;
-
-    /**
-     * URI of the Telegram API
-     *
-     * @var string
-     */
-    private static $api_base_uri = 'https://api.telegram.org';
-
-    /**
-     * Guzzle Client object
-     *
-     * @var \GuzzleHttp\Client
-     */
-    private static $client;
-
-    /**
-     * Input value of the request
-     *
-     * @var string
-     */
-    private static $input;
-
-    /**
-     * Request limiter
-     *
-     * @var boolean
-     */
-    private static $limiter_enabled;
-
-    /**
-     * Request limiter's interval between checks
-     *
-     * @var float
-     */
-    private static $limiter_interval;
-
-    /**
-     * Available actions to send
-     *
-     * This is basically the list of all methods listed on the official API documentation.
-     *
-     * @link https://core.telegram.org/bots/api
-     *
-     * @var array
-     */
-    private static $actions = [
-        'getUpdates',
-        'setWebhook',
-        'deleteWebhook',
-        'getWebhookInfo',
-        'getMe',
-        'sendMessage',
-        'forwardMessage',
-        'sendPhoto',
-        'sendAudio',
-        'sendDocument',
-        'sendSticker',
-        'sendVideo',
-        'sendVoice',
-        'sendVideoNote',
-        'sendMediaGroup',
-        'sendLocation',
-        'editMessageLiveLocation',
-        'stopMessageLiveLocation',
-        'sendVenue',
-        'sendContact',
-        'sendChatAction',
-        'getUserProfilePhotos',
-        'getFile',
-        'kickChatMember',
-        'unbanChatMember',
-        'restrictChatMember',
-        'promoteChatMember',
-        'exportChatInviteLink',
-        'setChatPhoto',
-        'deleteChatPhoto',
-        'setChatTitle',
-        'setChatDescription',
-        'pinChatMessage',
-        'unpinChatMessage',
-        'leaveChat',
-        'getChat',
-        'getChatAdministrators',
-        'getChatMembersCount',
-        'getChatMember',
-        'setChatStickerSet',
-        'deleteChatStickerSet',
-        'answerCallbackQuery',
-        'answerInlineQuery',
-        'editMessageText',
-        'editMessageCaption',
-        'editMessageReplyMarkup',
-        'deleteMessage',
-        'getStickerSet',
-        'uploadStickerFile',
-        'createNewStickerSet',
-        'addStickerToSet',
-        'setStickerPositionInSet',
-        'deleteStickerFromSet',
-        'sendInvoice',
-        'answerShippingQuery',
-        'answerPreCheckoutQuery',
-    ];
-
-    /**
-     * Some methods need a dummy param due to certain cURL issues.
-     *
-     * @see Request::addDummyParamIfNecessary()
-     *
-     * @var array
-     */
-    private static $actions_need_dummy_param = [
-        'deleteWebhook',
-        'getWebhookInfo',
-        'getMe',
-    ];
-
-    /**
-     * Initialize
-     *
-     * @param \Longman\TelegramBot\Telegram $telegram
-     *
-     * @throws TelegramException
-     */
-    public static function initialize(Telegram $telegram)
-    {
-        if (! ($telegram instanceof Telegram)) {
-            throw new TelegramException('Invalid Telegram pointer!');
-        }
-
-        self::$telegram = $telegram;
-        self::setClient(new Client(['base_uri' => self::$api_base_uri]));
-    }
-
-    /**
-     * Set a custom Guzzle HTTP Client object
-     *
-     * @param Client $client
-     *
-     * @throws TelegramException
-     */
-    public static function setClient(Client $client)
-    {
-        if (! ($client instanceof Client)) {
-            throw new TelegramException('Invalid GuzzleHttp\Client pointer!');
-        }
-
-        self::$client = $client;
-    }
-
-    /**
-     * Set input from custom input or stdin and return it
-     *
-     * @return string
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function getInput()
-    {
-        // First check if a custom input has been set, else get the PHP input.
-        if (! ($input = self::$telegram->getCustomInput())) {
-            $input = file_get_contents('php://input');
-        }
-
-        // Make sure we have a string to work with.
-        if (! is_string($input)) {
-            throw new TelegramException('Input must be a string!');
-        }
-
-        self::$input = $input;
-
-        TelegramLog::update(self::$input);
-
-        return self::$input;
-    }
-
-    /**
-     * Generate general fake server response
-     *
-     * @param array $data Data to add to fake response
-     *
-     * @return array Fake response data
-     */
-    public static function generateGeneralFakeServerResponse(array $data = [])
-    {
-        //PARAM BINDED IN PHPUNIT TEST FOR TestServerResponse.php
-        //Maybe this is not the best possible implementation
-
-        //No value set in $data ie testing setWebhook
-        //Provided $data['chat_id'] ie testing sendMessage
-
-        $fake_response = ['ok' => true]; // :)
-
-        if ($data === []) {
-            $fake_response['result'] = true;
-        }
-
-        //some data to let iniatilize the class method SendMessage
-        if (isset($data['chat_id'])) {
-            $data['message_id'] = '1234';
-            $data['date'] = '1441378360';
-            $data['from'] = [
-                'id'         => 123456789,
-                'first_name' => 'botname',
-                'username'   => 'namebot',
-            ];
-            $data['chat'] = ['id' => $data['chat_id']];
-
-            $fake_response['result'] = $data;
-        }
-
-        return $fake_response;
-    }
-
-    /**
-     * Properly set up the request params
-     *
-     * If any item of the array is a resource, reformat it to a multipart request.
-     * Else, just return the passed data as form params.
-     *
-     * @param array $data
-     *
-     * @return array
-     */
-    private static function setUpRequestParams(array $data)
-    {
-        $has_resource = false;
-        $multipart = [];
-
-        // Convert any nested arrays into JSON strings.
-        array_walk($data, function (&$item) {
-            is_array($item) && $item = json_encode($item);
-        });
-
-        //Reformat data array in multipart way if it contains a resource
-        foreach ($data as $key => $item) {
-            $has_resource |= (is_resource($item) || $item instanceof \GuzzleHttp\Psr7\Stream);
-            $multipart[] = ['name' => $key, 'contents' => $item];
-        }
-        if ($has_resource) {
-            return ['multipart' => $multipart];
-        }
-
-        return ['form_params' => $data];
-    }
-
-    /**
-     * Execute HTTP Request
-     *
-     * @param string $action Action to execute
-     * @param array $data Data to attach to the execution
-     *
-     * @return string Result of the HTTP Request
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function execute($action, array $data = [])
-    {
-        //Fix so that the keyboard markup is a string, not an object
-        if (isset($data['reply_markup'])) {
-            $data['reply_markup'] = json_encode($data['reply_markup']);
-        }
-
-        $result = null;
-        $request_params = self::setUpRequestParams($data);
-        $request_params['debug'] = TelegramLog::getDebugLogTempStream();
-
-        try {
-            $response = self::$client->post(
-                '/bot' . self::$telegram->getApiKey() . '/' . $action,
-                $request_params
-            );
-            $result = (string) $response->getBody();
-
-            //Logging getUpdates Update
-            if ($action === 'getUpdates') {
-                TelegramLog::update($result);
-            }
-        } catch (RequestException $e) {
-            $result = ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
-        } finally {
-            //Logging verbose debug output
-            TelegramLog::endDebugLogTempStream('Verbose HTTP Request output:' . PHP_EOL . '%s' . PHP_EOL);
-        }
-
-        return $result;
-    }
-
-    /**
-     * Download file
-     *
-     * @param \Longman\TelegramBot\Entities\File $file
-     *
-     * @return boolean
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function downloadFile(File $file)
-    {
-        if (empty($download_path = self::$telegram->getDownloadPath())) {
-            throw new TelegramException('Download path not set!');
-        }
-
-        $tg_file_path = $file->getFilePath();
-        $file_path = $download_path . '/' . $tg_file_path;
-
-        $file_dir = dirname($file_path);
-        //For safety reasons, first try to create the directory, then check that it exists.
-        //This is in case some other process has created the folder in the meantime.
-        if (! @mkdir($file_dir, 0755, true) && ! is_dir($file_dir)) {
-            throw new TelegramException('Directory ' . $file_dir . ' can\'t be created');
-        }
 
-        $debug_handle = TelegramLog::getDebugLogTempStream();
-
-        try {
-            self::$client->get(
-                '/file/bot' . self::$telegram->getApiKey() . '/' . $tg_file_path,
-                ['debug' => $debug_handle, 'sink' => $file_path]
-            );
-
-            return filesize($file_path) > 0;
-        } catch (RequestException $e) {
-            return ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
-        } finally {
-            //Logging verbose debug output
-            TelegramLog::endDebugLogTempStream('Verbose HTTP File Download Request output:' . PHP_EOL . '%s' . PHP_EOL);
-        }
-    }
-
-    /**
-     * Encode file
-     *
-     * @param string $file
-     *
-     * @return resource
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function encodeFile($file)
-    {
-        $fp = fopen($file, 'rb');
-        if ($fp === false) {
-            throw new TelegramException('Cannot open "' . $file . '" for reading');
-        }
-
-        return $fp;
-    }
-
-    /**
-     * Send command
-     *
-     * @todo Fake response doesn't need json encoding?
-     * @todo Write debug entry on failure
-     *
-     * @param string $action
-     * @param array $data
-     *
-     * @return \Longman\TelegramBot\Http\ServerResponse
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function send($action, array $data = [])
-    {
-        self::ensureValidAction($action);
-        self::addDummyParamIfNecessary($action, $data);
-
-        $bot_username = self::$telegram->getBotUsername();
-
-        if (defined('PHPUNIT_TESTSUITE')) {
-            $fake_response = self::generateGeneralFakeServerResponse($data);
-
-            return new ServerResponse($fake_response, $bot_username);
-        }
-
-        self::ensureNonEmptyData($data);
-
-        self::limitTelegramRequests($action, $data);
-
-        $response = json_decode(self::execute($action, $data), true);
-
-        if (null === $response) {
-            throw new TelegramException('Telegram returned an invalid response! Please review your bot name and API key.');
-        }
-
-        return new ServerResponse($response, $bot_username);
-    }
-
-    /**
-     * Add a dummy parameter if the passed action requires it.
-     *
-     * If a method doesn't require parameters, we need to add a dummy one anyway,
-     * because of some cURL version failed POST request without parameters.
-     *
-     * @link https://github.com/php-telegram-bot/core/pull/228
-     *
-     * @todo Would be nice to find a better solution for this!
-     *
-     * @param string $action
-     * @param array $data
-     */
-    protected static function addDummyParamIfNecessary($action, array &$data)
-    {
-        if (in_array($action, self::$actions_need_dummy_param, true)) {
-            // Can be anything, using a single letter to minimise request size.
-            $data = ['d'];
-        }
-    }
-
-    /**
-     * Make sure the data isn't empty, else throw an exception
-     *
-     * @param array $data
-     *
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    private static function ensureNonEmptyData(array $data)
-    {
-        if (count($data) === 0) {
-            throw new TelegramException('Data is empty!');
-        }
-    }
-
-    /**
-     * Make sure the action is valid, else throw an exception
-     *
-     * @param string $action
-     *
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    private static function ensureValidAction($action)
-    {
-        if (! in_array($action, self::$actions, true)) {
-            throw new TelegramException('The action "' . $action . '" doesn\'t exist!');
-        }
-    }
-
-    /**
-     * Use this method to send text messages. On success, the sent Message is returned
-     *
-     * @link https://core.telegram.org/bots/api#sendmessage
-     *
-     * @param array $data
-     *
-     * @return \Longman\TelegramBot\Http\ServerResponse
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function sendMessage(array $data)
-    {
-        $text = $data['text'];
-
-        do {
-            //Chop off and send the first message
-            $data['text'] = mb_substr($text, 0, 4096);
-            $response = self::send('sendMessage', $data);
-
-            //Prepare the next message
-            $text = mb_substr($text, 4096);
-        } while (mb_strlen($text, 'UTF-8') > 0);
-
-        return $response;
-    }
-
-    /**
-     * Any statically called method should be relayed to the `send` method.
-     *
-     * @param string $action
-     * @param array $data
-     *
-     * @return \Longman\TelegramBot\Http\ServerResponse
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function __callStatic($action, array $data)
-    {
-        // Make sure to add the action being called as the first parameter to be passed.
-        array_unshift($data, $action);
-
-        // @todo Use splat operator for unpacking when we move to PHP 5.6+
-        return call_user_func_array('static::send', $data);
-    }
-
-    /**
-     * Return an empty Server Response
-     *
-     * No request to telegram are sent, this function is used in commands that
-     * don't need to fire a message after execution
-     *
-     * @return \Longman\TelegramBot\Http\ServerResponse
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function emptyResponse()
-    {
-        return new ServerResponse(['ok' => true, 'result' => true], null);
-    }
-
-    /**
-     * Send message to all active chats
-     *
-     * @param string $callback_function
-     * @param array $data
-     * @param array $select_chats_params
-     *
-     * @return array
-     * @throws TelegramException
-     */
-    public static function sendToActiveChats(
-        $callback_function,
-        array $data,
-        array $select_chats_params
-    ) {
-        if (! method_exists(Request::class, $callback_function)) {
-            throw new TelegramException('Method "' . $callback_function . '" not found in class Request.');
-        }
-
-        $chats = DB::selectChats($select_chats_params);
-
-        $results = [];
-        if (is_array($chats)) {
-            foreach ($chats as $row) {
-                $data['chat_id'] = $row['chat_id'];
-                $results[] = call_user_func(Request::class . '::' . $callback_function, $data);
-            }
-        }
-
-        return $results;
-    }
-
-    /**
-     * Enable request limiter
-     *
-     * @param boolean $enable
-     * @param array $options
-     *
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function setLimiter($enable = true, array $options = [])
-    {
-        if (DB::isDbConnected()) {
-            $options_default = [
-                'interval' => 1,
-            ];
-
-            $options = array_merge($options_default, $options);
-
-            if (! is_numeric($options['interval']) || $options['interval'] <= 0) {
-                throw new TelegramException('Interval must be a number and must be greater than zero!');
-            }
-
-            self::$limiter_interval = $options['interval'];
-            self::$limiter_enabled = $enable;
-        }
-    }
-
-    /**
-     * This functions delays API requests to prevent reaching Telegram API limits
-     *  Can be disabled while in execution by 'Request::setLimiter(false)'
-     *
-     * @link https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this
-     *
-     * @param string $action
-     * @param array $data
-     *
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    private static function limitTelegramRequests($action, array $data = [])
-    {
-        if (self::$limiter_enabled) {
-            $limited_methods = [
-                'sendMessage',
-                'forwardMessage',
-                'sendPhoto',
-                'sendAudio',
-                'sendDocument',
-                'sendSticker',
-                'sendVideo',
-                'sendVoice',
-                'sendVideoNote',
-                'sendMediaGroup',
-                'sendLocation',
-                'editMessageLiveLocation',
-                'stopMessageLiveLocation',
-                'sendVenue',
-                'sendContact',
-                'sendInvoice',
-                'editMessageText',
-                'editMessageCaption',
-                'editMessageReplyMarkup',
-                'setChatTitle',
-                'setChatDescription',
-                'setChatStickerSet',
-                'deleteChatStickerSet',
-            ];
-
-            $chat_id = isset($data['chat_id']) ? $data['chat_id'] : null;
-            $inline_message_id = isset($data['inline_message_id']) ? $data['inline_message_id'] : null;
-
-            if (($chat_id || $inline_message_id) && in_array($action, $limited_methods)) {
-                $timeout = 60;
-
-                while (true) {
-                    if ($timeout <= 0) {
-                        throw new TelegramException('Timed out while waiting for a request spot!');
-                    }
-
-                    $requests = DB::getTelegramRequestCount($chat_id, $inline_message_id);
-
-                    $chat_per_second = ($requests['LIMIT_PER_SEC'] == 0); // No more than one message per second inside a particular chat
-                    $global_per_second = ($requests['LIMIT_PER_SEC_ALL'] < 30);    // No more than 30 messages per second to different chats
-                    $groups_per_minute = (((is_numeric($chat_id) && $chat_id > 0) || ! is_null($inline_message_id)) || ((! is_numeric($chat_id) || $chat_id < 0) && $requests['LIMIT_PER_MINUTE'] < 20));    // No more than 20 messages per minute in groups and channels
-
-                    if ($chat_per_second && $global_per_second && $groups_per_minute) {
-                        break;
-                    }
+class Request extends LaravelRequest
+{
 
-                    $timeout--;
-                    usleep(self::$limiter_interval * 1000000);
-                }
 
-                DB::insertTelegramRequest($action, $data);
-            }
-        }
-    }
 }

From d959a397ad2be8aa04b52fb355619fd559f49d98 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 17:54:47 +0400
Subject: [PATCH 10/40] Update dependencies and refactor main application class

---
 composer.json    |    5 +-
 composer.lock    | 1377 ++++++++++++++++++++++++++++++++++++++++------
 src/Telegram.php |  147 ++---
 3 files changed, 1306 insertions(+), 223 deletions(-)

diff --git a/composer.json b/composer.json
index 572036683..bf979859e 100644
--- a/composer.json
+++ b/composer.json
@@ -23,11 +23,14 @@
         "ext-curl": "*",
         "ext-mbstring": "*",
         "monolog/monolog": "^1.23",
-        "monolog/monolog": "^1.23",
+        "illuminate/container": "5.4.*|5.5.*|5.6.*",
+        "illuminate/support": "5.4.*|5.5.*|5.6.*",
+        "illuminate/http": "5.4.*|5.5.*|5.6.*",
         "guzzlehttp/guzzle": "^6.3"
     },
     "require-dev": {
         "phpunit/phpunit": "^4.8|^5.7|^6.5|^7.0",
+        "symfony/var-dumper": "3.4.*|~4.0",
         "squizlabs/php_codesniffer": "^3.2"
     },
     "autoload": {
diff --git a/composer.lock b/composer.lock
index 8258c993a..65ad85677 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,75 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "c7d1725771953f0ab9ce92df1e3cc9b3",
+    "content-hash": "7c255adb4c8e326379dc2e0f62b9976f",
     "packages": [
+        {
+            "name": "doctrine/inflector",
+            "version": "v1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/inflector.git",
+                "reference": "5527a48b7313d15261292c149e55e26eae771b0a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a",
+                "reference": "5527a48b7313d15261292c149e55e26eae771b0a",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^6.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "Common String Manipulations with regard to casing and singular/plural rules.",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "inflection",
+                "pluralize",
+                "singularize",
+                "string"
+            ],
+            "time": "2018-01-09T20:05:19+00:00"
+        },
         {
             "name": "guzzlehttp/guzzle",
             "version": "6.3.2",
@@ -53,56 +120,901 @@
             ],
             "authors": [
                 {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Guzzle is a PHP HTTP client library",
+            "homepage": "http://guzzlephp.org/",
+            "keywords": [
+                "client",
+                "curl",
+                "framework",
+                "http",
+                "http client",
+                "rest",
+                "web service"
+            ],
+            "time": "2018-03-26T16:33:04+00:00"
+        },
+        {
+            "name": "guzzlehttp/promises",
+            "version": "v1.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/promises.git",
+                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Promise\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                }
+            ],
+            "description": "Guzzle promises library",
+            "keywords": [
+                "promise"
+            ],
+            "time": "2016-12-20T10:07:11+00:00"
+        },
+        {
+            "name": "guzzlehttp/psr7",
+            "version": "1.4.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/guzzle/psr7.git",
+                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
+                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0",
+                "psr/http-message": "~1.0"
+            },
+            "provide": {
+                "psr/http-message-implementation": "1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "GuzzleHttp\\Psr7\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Michael Dowling",
+                    "email": "mtdowling@gmail.com",
+                    "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Tobias Schultze",
+                    "homepage": "https://github.com/Tobion"
+                }
+            ],
+            "description": "PSR-7 message implementation that also provides common utility methods",
+            "keywords": [
+                "http",
+                "message",
+                "request",
+                "response",
+                "stream",
+                "uri",
+                "url"
+            ],
+            "time": "2017-03-20T17:10:46+00:00"
+        },
+        {
+            "name": "illuminate/container",
+            "version": "v5.6.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/illuminate/container.git",
+                "reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/illuminate/container/zipball/4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
+                "reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/contracts": "5.6.*",
+                "php": "^7.1.3",
+                "psr/container": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.6-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Illuminate\\Container\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                }
+            ],
+            "description": "The Illuminate Container package.",
+            "homepage": "https://laravel.com",
+            "time": "2018-01-21T02:13:38+00:00"
+        },
+        {
+            "name": "illuminate/contracts",
+            "version": "v5.6.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/illuminate/contracts.git",
+                "reference": "322ec80498b3bf85bc4025d028e130a9b50242b9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/illuminate/contracts/zipball/322ec80498b3bf85bc4025d028e130a9b50242b9",
+                "reference": "322ec80498b3bf85bc4025d028e130a9b50242b9",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1.3",
+                "psr/container": "~1.0",
+                "psr/simple-cache": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.6-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Illuminate\\Contracts\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                }
+            ],
+            "description": "The Illuminate Contracts package.",
+            "homepage": "https://laravel.com",
+            "time": "2018-04-07T17:05:26+00:00"
+        },
+        {
+            "name": "illuminate/filesystem",
+            "version": "v5.6.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/illuminate/filesystem.git",
+                "reference": "c9ab9376076cedd88a374d7281d62b619634d578"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/illuminate/filesystem/zipball/c9ab9376076cedd88a374d7281d62b619634d578",
+                "reference": "c9ab9376076cedd88a374d7281d62b619634d578",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/contracts": "5.6.*",
+                "illuminate/support": "5.6.*",
+                "php": "^7.1.3",
+                "symfony/finder": "~4.0"
+            },
+            "suggest": {
+                "league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
+                "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
+                "league/flysystem-cached-adapter": "Required to use the Flysystem cache (~1.0).",
+                "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
+                "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0)."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.6-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Illuminate\\Filesystem\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                }
+            ],
+            "description": "The Illuminate Filesystem package.",
+            "homepage": "https://laravel.com",
+            "time": "2018-04-06T13:15:37+00:00"
+        },
+        {
+            "name": "illuminate/http",
+            "version": "v5.6.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/illuminate/http.git",
+                "reference": "1c58a1fd0b668c9d7203c6e69ba7391431815e47"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/illuminate/http/zipball/1c58a1fd0b668c9d7203c6e69ba7391431815e47",
+                "reference": "1c58a1fd0b668c9d7203c6e69ba7391431815e47",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/session": "5.6.*",
+                "illuminate/support": "5.6.*",
+                "php": "^7.1.3",
+                "symfony/http-foundation": "~4.0",
+                "symfony/http-kernel": "~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.6-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Illuminate\\Http\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                }
+            ],
+            "description": "The Illuminate Http package.",
+            "homepage": "https://laravel.com",
+            "time": "2018-03-12T13:37:01+00:00"
+        },
+        {
+            "name": "illuminate/session",
+            "version": "v5.6.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/illuminate/session.git",
+                "reference": "90bb5857fb64e269d8d331f02f820555ee471f64"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/illuminate/session/zipball/90bb5857fb64e269d8d331f02f820555ee471f64",
+                "reference": "90bb5857fb64e269d8d331f02f820555ee471f64",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/contracts": "5.6.*",
+                "illuminate/filesystem": "5.6.*",
+                "illuminate/support": "5.6.*",
+                "php": "^7.1.3",
+                "symfony/finder": "~4.0",
+                "symfony/http-foundation": "~4.0"
+            },
+            "suggest": {
+                "illuminate/console": "Required to use the session:table command (5.6.*)."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.6-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Illuminate\\Session\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                }
+            ],
+            "description": "The Illuminate Session package.",
+            "homepage": "https://laravel.com",
+            "time": "2018-03-06T14:29:02+00:00"
+        },
+        {
+            "name": "illuminate/support",
+            "version": "v5.6.17",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/illuminate/support.git",
+                "reference": "cc8d6f5cef3a901de6bb7d1b362102a6db001085"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/illuminate/support/zipball/cc8d6f5cef3a901de6bb7d1b362102a6db001085",
+                "reference": "cc8d6f5cef3a901de6bb7d1b362102a6db001085",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/inflector": "~1.1",
+                "ext-mbstring": "*",
+                "illuminate/contracts": "5.6.*",
+                "nesbot/carbon": "^1.24.1",
+                "php": "^7.1.3"
+            },
+            "conflict": {
+                "tightenco/collect": "<5.5.33"
+            },
+            "suggest": {
+                "illuminate/filesystem": "Required to use the composer class (5.6.*).",
+                "symfony/process": "Required to use the composer class (~4.0).",
+                "symfony/var-dumper": "Required to use the dd function (~4.0)."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.6-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Illuminate\\Support\\": ""
+                },
+                "files": [
+                    "helpers.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                }
+            ],
+            "description": "The Illuminate Support package.",
+            "homepage": "https://laravel.com",
+            "time": "2018-04-17T12:26:47+00:00"
+        },
+        {
+            "name": "monolog/monolog",
+            "version": "1.23.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/monolog.git",
+                "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
+                "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0",
+                "psr/log": "~1.0"
+            },
+            "provide": {
+                "psr/log-implementation": "1.0.0"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+                "doctrine/couchdb": "~1.0@dev",
+                "graylog2/gelf-php": "~1.0",
+                "jakub-onderka/php-parallel-lint": "0.9",
+                "php-amqplib/php-amqplib": "~2.4",
+                "php-console/php-console": "^3.1.3",
+                "phpunit/phpunit": "~4.5",
+                "phpunit/phpunit-mock-objects": "2.3.0",
+                "ruflin/elastica": ">=0.90 <3.0",
+                "sentry/sentry": "^0.13",
+                "swiftmailer/swiftmailer": "^5.3|^6.0"
+            },
+            "suggest": {
+                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+                "ext-mongo": "Allow sending log messages to a MongoDB server",
+                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+                "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
+                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+                "php-console/php-console": "Allow sending log messages to Google Chrome",
+                "rollbar/rollbar": "Allow sending log messages to Rollbar",
+                "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+                "sentry/sentry": "Allow sending log messages to a Sentry server"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Monolog\\": "src/Monolog"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                }
+            ],
+            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+            "homepage": "http://github.com/Seldaek/monolog",
+            "keywords": [
+                "log",
+                "logging",
+                "psr-3"
+            ],
+            "time": "2017-06-19T01:22:40+00:00"
+        },
+        {
+            "name": "nesbot/carbon",
+            "version": "1.26.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/briannesbitt/Carbon.git",
+                "reference": "e3d9014279133a3cccc01f6a691322a2d5a6a87b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e3d9014279133a3cccc01f6a691322a2d5a6a87b",
+                "reference": "e3d9014279133a3cccc01f6a691322a2d5a6a87b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9",
+                "symfony/translation": "~2.6 || ~3.0 || ~4.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "~2",
+                "phpunit/phpunit": "^4.8.35 || ^5.7"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Brian Nesbitt",
+                    "email": "brian@nesbot.com",
+                    "homepage": "http://nesbot.com"
+                }
+            ],
+            "description": "A simple API extension for DateTime.",
+            "homepage": "http://carbon.nesbot.com",
+            "keywords": [
+                "date",
+                "datetime",
+                "time"
+            ],
+            "time": "2018-04-17T15:35:42+00:00"
+        },
+        {
+            "name": "psr/container",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/container.git",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Container\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common Container Interface (PHP FIG PSR-11)",
+            "homepage": "https://github.com/php-fig/container",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interface",
+                "container-interop",
+                "psr"
+            ],
+            "time": "2017-02-14T16:28:37+00:00"
+        },
+        {
+            "name": "psr/http-message",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-message.git",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP messages",
+            "homepage": "https://github.com/php-fig/http-message",
+            "keywords": [
+                "http",
+                "http-message",
+                "psr",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "time": "2016-08-06T14:39:51+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "Psr/Log/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2016-10-10T12:19:37+00:00"
+        },
+        {
+            "name": "psr/simple-cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/simple-cache.git",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\SimpleCache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for simple caching",
+            "keywords": [
+                "cache",
+                "caching",
+                "psr",
+                "psr-16",
+                "simple-cache"
+            ],
+            "time": "2017-10-23T01:57:42+00:00"
+        },
+        {
+            "name": "symfony/debug",
+            "version": "v4.0.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/debug.git",
+                "reference": "5961d02d48828671f5d8a7805e06579d692f6ede"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/5961d02d48828671f5d8a7805e06579d692f6ede",
+                "reference": "5961d02d48828671f5d8a7805e06579d692f6ede",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1.3",
+                "psr/log": "~1.0"
+            },
+            "conflict": {
+                "symfony/http-kernel": "<3.4"
+            },
+            "require-dev": {
+                "symfony/http-kernel": "~3.4|~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Debug\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Debug Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-03T05:24:00+00:00"
+        },
+        {
+            "name": "symfony/event-dispatcher",
+            "version": "v4.0.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/event-dispatcher.git",
+                "reference": "63353a71073faf08f62caab4e6889b06a787f07b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/63353a71073faf08f62caab4e6889b06a787f07b",
+                "reference": "63353a71073faf08f62caab4e6889b06a787f07b",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1.3"
+            },
+            "conflict": {
+                "symfony/dependency-injection": "<3.4"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/config": "~3.4|~4.0",
+                "symfony/dependency-injection": "~3.4|~4.0",
+                "symfony/expression-language": "~3.4|~4.0",
+                "symfony/stopwatch": "~3.4|~4.0"
+            },
+            "suggest": {
+                "symfony/dependency-injection": "",
+                "symfony/http-kernel": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\EventDispatcher\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Guzzle is a PHP HTTP client library",
-            "homepage": "http://guzzlephp.org/",
-            "keywords": [
-                "client",
-                "curl",
-                "framework",
-                "http",
-                "http client",
-                "rest",
-                "web service"
-            ],
-            "time": "2018-03-26T16:33:04+00:00"
+            "description": "Symfony EventDispatcher Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-06T07:35:43+00:00"
         },
         {
-            "name": "guzzlehttp/promises",
-            "version": "v1.3.1",
+            "name": "symfony/finder",
+            "version": "v4.0.8",
             "source": {
                 "type": "git",
-                "url": "https://github.com/guzzle/promises.git",
-                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
+                "url": "https://github.com/symfony/finder.git",
+                "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
-                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
+                "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.5.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.0"
+                "php": "^7.1.3"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.4-dev"
+                    "dev-master": "4.0-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "GuzzleHttp\\Promise\\": "src/"
+                    "Symfony\\Component\\Finder\\": ""
                 },
-                "files": [
-                    "src/functions_include.php"
+                "exclude-from-classmap": [
+                    "/Tests/"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -111,53 +1023,51 @@
             ],
             "authors": [
                 {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Guzzle promises library",
-            "keywords": [
-                "promise"
-            ],
-            "time": "2016-12-20T10:07:11+00:00"
+            "description": "Symfony Finder Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-04T05:10:37+00:00"
         },
         {
-            "name": "guzzlehttp/psr7",
-            "version": "1.4.2",
+            "name": "symfony/http-foundation",
+            "version": "v4.0.8",
             "source": {
                 "type": "git",
-                "url": "https://github.com/guzzle/psr7.git",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
+                "url": "https://github.com/symfony/http-foundation.git",
+                "reference": "d0864a82e5891ab61d31eecbaa48bed5a09b8e6c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0864a82e5891ab61d31eecbaa48bed5a09b8e6c",
+                "reference": "d0864a82e5891ab61d31eecbaa48bed5a09b8e6c",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.4.0",
-                "psr/http-message": "~1.0"
-            },
-            "provide": {
-                "psr/http-message-implementation": "1.0"
+                "php": "^7.1.3",
+                "symfony/polyfill-mbstring": "~1.1"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.0"
+                "symfony/expression-language": "~3.4|~4.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.4-dev"
+                    "dev-master": "4.0-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "GuzzleHttp\\Psr7\\": "src/"
+                    "Symfony\\Component\\HttpFoundation\\": ""
                 },
-                "files": [
-                    "src/functions_include.php"
+                "exclude-from-classmap": [
+                    "/Tests/"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -166,84 +1076,85 @@
             ],
             "authors": [
                 {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
                 },
                 {
-                    "name": "Tobias Schultze",
-                    "homepage": "https://github.com/Tobion"
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "PSR-7 message implementation that also provides common utility methods",
-            "keywords": [
-                "http",
-                "message",
-                "request",
-                "response",
-                "stream",
-                "uri",
-                "url"
-            ],
-            "time": "2017-03-20T17:10:46+00:00"
+            "description": "Symfony HttpFoundation Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-03T05:24:00+00:00"
         },
         {
-            "name": "monolog/monolog",
-            "version": "1.23.0",
+            "name": "symfony/http-kernel",
+            "version": "v4.0.8",
             "source": {
                 "type": "git",
-                "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4"
+                "url": "https://github.com/symfony/http-kernel.git",
+                "reference": "6dd620d96d64456075536ffe3c6c4658dd689021"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
-                "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6dd620d96d64456075536ffe3c6c4658dd689021",
+                "reference": "6dd620d96d64456075536ffe3c6c4658dd689021",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.0",
-                "psr/log": "~1.0"
+                "php": "^7.1.3",
+                "psr/log": "~1.0",
+                "symfony/debug": "~3.4|~4.0",
+                "symfony/event-dispatcher": "~3.4|~4.0",
+                "symfony/http-foundation": "~3.4.4|~4.0.4"
+            },
+            "conflict": {
+                "symfony/config": "<3.4",
+                "symfony/dependency-injection": "<3.4.5|<4.0.5,>=4",
+                "symfony/var-dumper": "<3.4",
+                "twig/twig": "<1.34|<2.4,>=2"
             },
             "provide": {
-                "psr/log-implementation": "1.0.0"
+                "psr/log-implementation": "1.0"
             },
             "require-dev": {
-                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
-                "doctrine/couchdb": "~1.0@dev",
-                "graylog2/gelf-php": "~1.0",
-                "jakub-onderka/php-parallel-lint": "0.9",
-                "php-amqplib/php-amqplib": "~2.4",
-                "php-console/php-console": "^3.1.3",
-                "phpunit/phpunit": "~4.5",
-                "phpunit/phpunit-mock-objects": "2.3.0",
-                "ruflin/elastica": ">=0.90 <3.0",
-                "sentry/sentry": "^0.13",
-                "swiftmailer/swiftmailer": "^5.3|^6.0"
+                "psr/cache": "~1.0",
+                "symfony/browser-kit": "~3.4|~4.0",
+                "symfony/config": "~3.4|~4.0",
+                "symfony/console": "~3.4|~4.0",
+                "symfony/css-selector": "~3.4|~4.0",
+                "symfony/dependency-injection": "^3.4.5|^4.0.5",
+                "symfony/dom-crawler": "~3.4|~4.0",
+                "symfony/expression-language": "~3.4|~4.0",
+                "symfony/finder": "~3.4|~4.0",
+                "symfony/process": "~3.4|~4.0",
+                "symfony/routing": "~3.4|~4.0",
+                "symfony/stopwatch": "~3.4|~4.0",
+                "symfony/templating": "~3.4|~4.0",
+                "symfony/translation": "~3.4|~4.0",
+                "symfony/var-dumper": "~3.4|~4.0"
             },
             "suggest": {
-                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
-                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
-                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
-                "ext-mongo": "Allow sending log messages to a MongoDB server",
-                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
-                "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
-                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
-                "php-console/php-console": "Allow sending log messages to Google Chrome",
-                "rollbar/rollbar": "Allow sending log messages to Rollbar",
-                "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
-                "sentry/sentry": "Allow sending log messages to a Sentry server"
+                "symfony/browser-kit": "",
+                "symfony/config": "",
+                "symfony/console": "",
+                "symfony/dependency-injection": "",
+                "symfony/var-dumper": ""
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0.x-dev"
+                    "dev-master": "4.0-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "Monolog\\": "src/Monolog"
-                }
+                    "Symfony\\Component\\HttpKernel\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -251,47 +1162,51 @@
             ],
             "authors": [
                 {
-                    "name": "Jordi Boggiano",
-                    "email": "j.boggiano@seld.be",
-                    "homepage": "http://seld.be"
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
-            "homepage": "http://github.com/Seldaek/monolog",
-            "keywords": [
-                "log",
-                "logging",
-                "psr-3"
-            ],
-            "time": "2017-06-19T01:22:40+00:00"
+            "description": "Symfony HttpKernel Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-06T16:25:03+00:00"
         },
         {
-            "name": "psr/http-message",
-            "version": "1.0.1",
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.7.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/php-fig/http-message.git",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
+                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.0"
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "1.7-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "Psr\\Http\\Message\\": "src/"
-                }
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -299,49 +1214,74 @@
             ],
             "authors": [
                 {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Common interface for HTTP messages",
-            "homepage": "https://github.com/php-fig/http-message",
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
             "keywords": [
-                "http",
-                "http-message",
-                "psr",
-                "psr-7",
-                "request",
-                "response"
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
             ],
-            "time": "2016-08-06T14:39:51+00:00"
+            "time": "2018-01-30T19:27:44+00:00"
         },
         {
-            "name": "psr/log",
-            "version": "1.0.2",
+            "name": "symfony/translation",
+            "version": "v4.0.8",
             "source": {
                 "type": "git",
-                "url": "https://github.com/php-fig/log.git",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
+                "url": "https://github.com/symfony/translation.git",
+                "reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+                "url": "https://api.github.com/repos/symfony/translation/zipball/e20a9b7f9f62cb33a11638b345c248e7d510c938",
+                "reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.0"
+                "php": "^7.1.3",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "conflict": {
+                "symfony/config": "<3.4",
+                "symfony/dependency-injection": "<3.4",
+                "symfony/yaml": "<3.4"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/config": "~3.4|~4.0",
+                "symfony/dependency-injection": "~3.4|~4.0",
+                "symfony/finder": "~2.8|~3.0|~4.0",
+                "symfony/intl": "~3.4|~4.0",
+                "symfony/yaml": "~3.4|~4.0"
+            },
+            "suggest": {
+                "psr/log": "To use logging capability in translator",
+                "symfony/config": "",
+                "symfony/yaml": ""
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "4.0-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "Psr\\Log\\": "Psr/Log/"
-                }
+                    "Symfony\\Component\\Translation\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -349,18 +1289,17 @@
             ],
             "authors": [
                 {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Common interface for logging libraries",
-            "homepage": "https://github.com/php-fig/log",
-            "keywords": [
-                "log",
-                "psr",
-                "psr-3"
-            ],
-            "time": "2016-10-10T12:19:37+00:00"
+            "description": "Symfony Translation Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-02-22T10:50:29+00:00"
         }
     ],
     "packages-dev": [
@@ -1779,6 +2718,130 @@
             ],
             "time": "2018-02-20T21:35:23+00:00"
         },
+        {
+            "name": "symfony/polyfill-php72",
+            "version": "v1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php72.git",
+                "reference": "8eca20c8a369e069d4f4c2ac9895144112867422"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/8eca20c8a369e069d4f4c2ac9895144112867422",
+                "reference": "8eca20c8a369e069d4f4c2ac9895144112867422",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php72\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-01-31T17:43:24+00:00"
+        },
+        {
+            "name": "symfony/var-dumper",
+            "version": "v4.0.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/var-dumper.git",
+                "reference": "e1b4d008100f4d203cc38b0d793ad6252d8d8af0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e1b4d008100f4d203cc38b0d793ad6252d8d8af0",
+                "reference": "e1b4d008100f4d203cc38b0d793ad6252d8d8af0",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1.3",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php72": "~1.5"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
+            },
+            "require-dev": {
+                "ext-iconv": "*",
+                "twig/twig": "~1.34|~2.4"
+            },
+            "suggest": {
+                "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
+                "ext-intl": "To show region name in time zone dump"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.0-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "Resources/functions/dump.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Component\\VarDumper\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony mechanism for exploring and dumping PHP variables",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "debug",
+                "dump"
+            ],
+            "time": "2018-04-04T05:10:37+00:00"
+        },
         {
             "name": "theseer/tokenizer",
             "version": "1.1.0",
@@ -1876,7 +2939,7 @@
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
-        "php": "^5.5|^7.0",
+        "php": ">=5.6.4|^7.0",
         "ext-pdo": "*",
         "ext-curl": "*",
         "ext-mbstring": "*"
diff --git a/src/Telegram.php b/src/Telegram.php
index 10d2a5087..c243c0f42 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -14,23 +14,27 @@
 defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');
 
 use Exception;
+use Illuminate\Container\Container;
 use Longman\TelegramBot\Commands\Command;
-use Longman\TelegramBot\Entities\ServerResponse;
 use Longman\TelegramBot\Entities\Update;
 use Longman\TelegramBot\Exception\TelegramException;
+use Longman\TelegramBot\Http\Kernel;
+use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\ServerResponse;
 use PDO;
 use RecursiveDirectoryIterator;
 use RecursiveIteratorIterator;
 use RegexIterator;
 
-class Telegram
+class Telegram extends Container
 {
     /**
      * Version
      *
      * @var string
      */
-    protected $version = '0.53.0';
+    const VERSION = '0.53.0';
 
     /**
      * Telegram API key
@@ -53,6 +57,13 @@ class Telegram
      */
     protected $bot_id = '';
 
+    /**
+     * Container
+     *
+     * @var \Illuminate\Contracts\Container\Container
+     */
+    protected $container;
+
     /**
      * Raw request data (json) for webhook methods
      *
@@ -119,7 +130,7 @@ class Telegram
     /**
      * ServerResponse of the last Command execution
      *
-     * @var \Longman\TelegramBot\Entities\ServerResponse
+     * @var \Longman\TelegramBot\Http\ServerResponse
      */
     protected $last_command_response;
 
@@ -166,26 +177,42 @@ public function __construct($api_key, $bot_username = '')
             throw new TelegramException('API KEY not defined!');
         }
         preg_match('/(\d+)\:[\w\-]+/', $api_key, $matches);
-        if (!isset($matches[1])) {
+        if (! isset($matches[1])) {
             throw new TelegramException('Invalid API KEY defined!');
         }
-        $this->bot_id  = $matches[1];
+        $this->bot_id = $matches[1];
         $this->api_key = $api_key;
 
-        if (!empty($bot_username)) {
+        if (! empty($bot_username)) {
             $this->bot_username = $bot_username;
         }
 
+        $this->registerBaseBindings();
+
         //Add default system commands path
         $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
 
-        Request::initialize($this);
+        Client::initialize($this);
+    }
+
+    /**
+     * Register the basic bindings into the container.
+     *
+     * @return void
+     */
+    protected function registerBaseBindings()
+    {
+        static::setInstance($this);
+
+        $this->instance('app', $this);
+
+        $this->instance(Telegram::class, $this);
     }
 
     /**
      * Initialize Database connection
      *
-     * @param array  $credential
+     * @param array $credential
      * @param string $table_prefix
      * @param string $encoding
      *
@@ -204,7 +231,7 @@ public function enableMySql(array $credential, $table_prefix = null, $encoding =
     /**
      * Initialize Database external connection
      *
-     * @param PDO    $external_pdo_connection PDO database object
+     * @param PDO $external_pdo_connection PDO database object
      * @param string $table_prefix
      *
      * @return \Longman\TelegramBot\Telegram
@@ -241,7 +268,7 @@ public function getCommandsList()
 
                 foreach ($files as $file) {
                     //Remove "Command.php" from filename
-                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
+                    $command = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
                     $command_name = strtolower($command);
 
                     if (array_key_exists($command_name, $commands)) {
@@ -313,7 +340,7 @@ public function getCustomInput()
     /**
      * Get the ServerResponse of the last Command execution
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      */
     public function getLastCommandResponse()
     {
@@ -326,7 +353,7 @@ public function getLastCommandResponse()
      * @param int|null $limit
      * @param int|null $timeout
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function handleGetUpdates($limit = null, $timeout = null)
@@ -335,7 +362,7 @@ public function handleGetUpdates($limit = null, $timeout = null)
             throw new TelegramException('Bot Username is not defined!');
         }
 
-        if (!DB::isDbConnected() && !$this->getupdates_without_database) {
+        if (! DB::isDbConnected() && ! $this->getupdates_without_database) {
             return new ServerResponse(
                 [
                     'ok'          => false,
@@ -363,7 +390,7 @@ public function handleGetUpdates($limit = null, $timeout = null)
                 $offset = $this->last_update_id + 1;    //As explained in the telegram bot API documentation
             }
 
-            $response = Request::getUpdates(
+            $response = Client::getUpdates(
                 [
                     'offset'  => $offset,
                     'limit'   => $limit,
@@ -381,9 +408,9 @@ public function handleGetUpdates($limit = null, $timeout = null)
                 $this->processUpdate($result);
             }
 
-            if (!DB::isDbConnected() && !$custom_input && $this->last_update_id !== null && $offset === 0) {
+            if (! DB::isDbConnected() && ! $custom_input && $this->last_update_id !== null && $offset === 0) {
                 //Mark update(s) as read after handling
-                Request::getUpdates(
+                Client::getUpdates(
                     [
                         'offset'  => $this->last_update_id + 1,
                         'limit'   => 1,
@@ -409,22 +436,12 @@ public function handle()
             throw new TelegramException('Bot Username is not defined!');
         }
 
-        $this->input = Request::getInput();
-
-        if (empty($this->input)) {
-            throw new TelegramException('Input is empty!');
-        }
+        /** @var \Longman\TelegramBot\Http\Kernel $kernel */
+        $kernel = $this->make(Kernel::class);
 
-        $post = json_decode($this->input, true);
-        if (empty($post)) {
-            throw new TelegramException('Invalid JSON!');
-        }
+        $response = $kernel->handle(Request::capture());
 
-        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
-            return $response->isOk();
-        }
-
-        return false;
+        return $response;
     }
 
     /**
@@ -444,7 +461,7 @@ protected function getCommandFromType($type)
      *
      * @param \Longman\TelegramBot\Entities\Update $update
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function processUpdate(Update $update)
@@ -467,7 +484,7 @@ public function processUpdate(Update $update)
             $type = $message->getType();
             if ($type === 'command') {
                 $command = $message->getCommand();
-            } elseif (in_array($type, [
+            } else if (in_array($type, [
                 'new_chat_members',
                 'left_chat_member',
                 'new_chat_title',
@@ -497,7 +514,8 @@ public function processUpdate(Update $update)
         $last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
         if ($last_id && count($last_id) === 1) {
             TelegramLog::debug('Duplicate update received, processing aborted!');
-            return Request::emptyResponse();
+
+            return Client::emptyResponse();
         }
 
         DB::insertRequest($this->update);
@@ -515,10 +533,10 @@ public function processUpdate(Update $update)
      */
     public function executeCommand($command)
     {
-        $command     = strtolower($command);
+        $command = strtolower($command);
         $command_obj = $this->getCommandObject($command);
 
-        if (!$command_obj || !$command_obj->isEnabled()) {
+        if (! $command_obj || ! $command_obj->isEnabled()) {
             //Failsafe in case the Generic command can't be found
             if ($command === 'generic') {
                 throw new TelegramException('Generic command missing!');
@@ -566,9 +584,9 @@ protected function sanitizeCommand($command)
      */
     public function enableAdmin($admin_id)
     {
-        if (!is_int($admin_id) || $admin_id <= 0) {
+        if (! is_int($admin_id) || $admin_id <= 0) {
             TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
-        } elseif (!in_array($admin_id, $this->admins_list, true)) {
+        } else if (! in_array($admin_id, $this->admins_list, true)) {
             $this->admins_list[] = $admin_id;
         }
 
@@ -652,16 +670,16 @@ public function isDbEnabled()
     /**
      * Add a single custom commands path
      *
-     * @param string $path   Custom commands path to add
-     * @param bool   $before If the path should be prepended or appended to the list
+     * @param string $path Custom commands path to add
+     * @param bool $before If the path should be prepended or appended to the list
      *
      * @return \Longman\TelegramBot\Telegram
      */
     public function addCommandsPath($path, $before = true)
     {
-        if (!is_dir($path)) {
+        if (! is_dir($path)) {
             TelegramLog::error('Commands path "%s" does not exist.', $path);
-        } elseif (!in_array($path, $this->commands_paths, true)) {
+        } else if (! in_array($path, $this->commands_paths, true)) {
             if ($before) {
                 array_unshift($this->commands_paths, $path);
             } else {
@@ -675,8 +693,8 @@ public function addCommandsPath($path, $before = true)
     /**
      * Add multiple custom commands paths
      *
-     * @param array $paths  Custom commands paths to add
-     * @param bool  $before If the paths should be prepended or appended to the list
+     * @param array $paths Custom commands paths to add
+     * @param bool $before If the paths should be prepended or appended to the list
      *
      * @return \Longman\TelegramBot\Telegram
      */
@@ -755,7 +773,7 @@ public function getDownloadPath()
      * Or you can add the api key for external service.
      *
      * @param string $command
-     * @param array  $config
+     * @param array $config
      *
      * @return \Longman\TelegramBot\Telegram
      */
@@ -822,9 +840,9 @@ public function getVersion()
      * Set Webhook for bot
      *
      * @param string $url
-     * @param array  $data Optional parameters.
+     * @param array $data Optional parameters.
      *
-     * @return \Longman\TelegramBot\Entities\ServerResponse
+     * @return \Longman\TelegramBot\Http\ServerResponse
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function setWebhook($url, array $data = [])
@@ -833,7 +851,7 @@ public function setWebhook($url, array $data = [])
             throw new TelegramException('Hook url is empty!');
         }
 
-        $data        = array_intersect_key($data, array_flip([
+        $data = array_intersect_key($data, array_flip([
             'certificate',
             'max_connections',
             'allowed_updates',
@@ -841,13 +859,13 @@ public function setWebhook($url, array $data = [])
         $data['url'] = $url;
 
         // If the certificate is passed as a path, encode and add the file to the data array.
-        if (!empty($data['certificate']) && is_string($data['certificate'])) {
-            $data['certificate'] = Request::encodeFile($data['certificate']);
+        if (! empty($data['certificate']) && is_string($data['certificate'])) {
+            $data['certificate'] = Client::encodeFile($data['certificate']);
         }
 
-        $result = Request::setWebhook($data);
+        $result = Client::setWebhook($data);
 
-        if (!$result->isOk()) {
+        if (! $result->isOk()) {
             throw new TelegramException(
                 'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
             );
@@ -864,9 +882,9 @@ public function setWebhook($url, array $data = [])
      */
     public function deleteWebhook()
     {
-        $result = Request::deleteWebhook();
+        $result = Client::deleteWebhook();
 
-        if (!$result->isOk()) {
+        if (! $result->isOk()) {
             throw new TelegramException(
                 'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
             );
@@ -899,14 +917,14 @@ protected function ucwordsUnicode($str, $encoding = 'UTF-8')
     protected function ucfirstUnicode($str, $encoding = 'UTF-8')
     {
         return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
-               . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
+            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
     }
 
     /**
      * Enable Botan.io integration
      *
      * @param  string $token
-     * @param  array  $options
+     * @param  array $options
      *
      * @return \Longman\TelegramBot\Telegram
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -928,7 +946,7 @@ public function enableBotan($token, array $options = [])
      */
     public function enableLimiter(array $options = [])
     {
-        Request::setLimiter(true, $options);
+        Client::setLimiter(true, $options);
 
         return $this;
     }
@@ -942,28 +960,27 @@ public function enableLimiter(array $options = [])
      */
     public function runCommands($commands)
     {
-        if (!is_array($commands) || empty($commands)) {
+        if (! is_array($commands) || empty($commands)) {
             throw new TelegramException('No command(s) provided!');
         }
 
-        $this->run_commands  = true;
+        $this->run_commands = true;
         $this->botan_enabled = false;   // Force disable Botan.io integration, we don't want to track self-executed commands!
 
-        $result = Request::getMe();
+        $result = Client::getMe();
 
         if ($result->isOk()) {
             $result = $result->getResult();
 
-            $bot_id       = $result->getId();
-            $bot_name     = $result->getFirstName();
+            $bot_id = $result->getId();
+            $bot_name = $result->getFirstName();
             $bot_username = $result->getUsername();
         } else {
-            $bot_id       = $this->getBotId();
-            $bot_name     = $this->getBotUsername();
+            $bot_id = $this->getBotId();
+            $bot_name = $this->getBotUsername();
             $bot_username = $this->getBotUsername();
         }
 
-
         $this->enableAdmin($bot_id);    // Give bot access to admin commands
         $this->getCommandsList();       // Load full commands list
 

From 8085388e4fb944cd613df2a07844f521d3b9646c Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 18:03:38 +0400
Subject: [PATCH 11/40] Delete composer.lock file to avoid dependencies problem
 during building

---
 .gitignore    |    1 +
 composer.lock | 2948 -------------------------------------------------
 2 files changed, 1 insertion(+), 2948 deletions(-)
 delete mode 100644 composer.lock

diff --git a/.gitignore b/.gitignore
index c0546a714..5776d8103 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 .idea
 .phpintel
 composer.phar
+composer.lock
 
 # Local System Files (i.e. cache, logs, etc.) #
 /cache
diff --git a/composer.lock b/composer.lock
deleted file mode 100644
index 65ad85677..000000000
--- a/composer.lock
+++ /dev/null
@@ -1,2948 +0,0 @@
-{
-    "_readme": [
-        "This file locks the dependencies of your project to a known state",
-        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
-        "This file is @generated automatically"
-    ],
-    "content-hash": "7c255adb4c8e326379dc2e0f62b9976f",
-    "packages": [
-        {
-            "name": "doctrine/inflector",
-            "version": "v1.3.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/inflector.git",
-                "reference": "5527a48b7313d15261292c149e55e26eae771b0a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a",
-                "reference": "5527a48b7313d15261292c149e55e26eae771b0a",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.2"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.3.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Roman Borschel",
-                    "email": "roman@code-factory.org"
-                },
-                {
-                    "name": "Benjamin Eberlei",
-                    "email": "kontakt@beberlei.de"
-                },
-                {
-                    "name": "Guilherme Blanco",
-                    "email": "guilhermeblanco@gmail.com"
-                },
-                {
-                    "name": "Jonathan Wage",
-                    "email": "jonwage@gmail.com"
-                },
-                {
-                    "name": "Johannes Schmitt",
-                    "email": "schmittjoh@gmail.com"
-                }
-            ],
-            "description": "Common String Manipulations with regard to casing and singular/plural rules.",
-            "homepage": "http://www.doctrine-project.org",
-            "keywords": [
-                "inflection",
-                "pluralize",
-                "singularize",
-                "string"
-            ],
-            "time": "2018-01-09T20:05:19+00:00"
-        },
-        {
-            "name": "guzzlehttp/guzzle",
-            "version": "6.3.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/68d0ea14d5a3f42a20e87632a5f84931e2709c90",
-                "reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90",
-                "shasum": ""
-            },
-            "require": {
-                "guzzlehttp/promises": "^1.0",
-                "guzzlehttp/psr7": "^1.4",
-                "php": ">=5.5"
-            },
-            "require-dev": {
-                "ext-curl": "*",
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4",
-                "psr/log": "^1.0"
-            },
-            "suggest": {
-                "psr/log": "Required for using the Log middleware"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "6.3-dev"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "src/functions_include.php"
-                ],
-                "psr-4": {
-                    "GuzzleHttp\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
-                }
-            ],
-            "description": "Guzzle is a PHP HTTP client library",
-            "homepage": "http://guzzlephp.org/",
-            "keywords": [
-                "client",
-                "curl",
-                "framework",
-                "http",
-                "http client",
-                "rest",
-                "web service"
-            ],
-            "time": "2018-03-26T16:33:04+00:00"
-        },
-        {
-            "name": "guzzlehttp/promises",
-            "version": "v1.3.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/guzzle/promises.git",
-                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
-                "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "GuzzleHttp\\Promise\\": "src/"
-                },
-                "files": [
-                    "src/functions_include.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
-                }
-            ],
-            "description": "Guzzle promises library",
-            "keywords": [
-                "promise"
-            ],
-            "time": "2016-12-20T10:07:11+00:00"
-        },
-        {
-            "name": "guzzlehttp/psr7",
-            "version": "1.4.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/guzzle/psr7.git",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.4.0",
-                "psr/http-message": "~1.0"
-            },
-            "provide": {
-                "psr/http-message-implementation": "1.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "~4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "GuzzleHttp\\Psr7\\": "src/"
-                },
-                "files": [
-                    "src/functions_include.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Michael Dowling",
-                    "email": "mtdowling@gmail.com",
-                    "homepage": "https://github.com/mtdowling"
-                },
-                {
-                    "name": "Tobias Schultze",
-                    "homepage": "https://github.com/Tobion"
-                }
-            ],
-            "description": "PSR-7 message implementation that also provides common utility methods",
-            "keywords": [
-                "http",
-                "message",
-                "request",
-                "response",
-                "stream",
-                "uri",
-                "url"
-            ],
-            "time": "2017-03-20T17:10:46+00:00"
-        },
-        {
-            "name": "illuminate/container",
-            "version": "v5.6.17",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/illuminate/container.git",
-                "reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/container/zipball/4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
-                "reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
-                "shasum": ""
-            },
-            "require": {
-                "illuminate/contracts": "5.6.*",
-                "php": "^7.1.3",
-                "psr/container": "~1.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Illuminate\\Container\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Taylor Otwell",
-                    "email": "taylor@laravel.com"
-                }
-            ],
-            "description": "The Illuminate Container package.",
-            "homepage": "https://laravel.com",
-            "time": "2018-01-21T02:13:38+00:00"
-        },
-        {
-            "name": "illuminate/contracts",
-            "version": "v5.6.17",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/illuminate/contracts.git",
-                "reference": "322ec80498b3bf85bc4025d028e130a9b50242b9"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/contracts/zipball/322ec80498b3bf85bc4025d028e130a9b50242b9",
-                "reference": "322ec80498b3bf85bc4025d028e130a9b50242b9",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "psr/container": "~1.0",
-                "psr/simple-cache": "~1.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Illuminate\\Contracts\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Taylor Otwell",
-                    "email": "taylor@laravel.com"
-                }
-            ],
-            "description": "The Illuminate Contracts package.",
-            "homepage": "https://laravel.com",
-            "time": "2018-04-07T17:05:26+00:00"
-        },
-        {
-            "name": "illuminate/filesystem",
-            "version": "v5.6.17",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/illuminate/filesystem.git",
-                "reference": "c9ab9376076cedd88a374d7281d62b619634d578"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/filesystem/zipball/c9ab9376076cedd88a374d7281d62b619634d578",
-                "reference": "c9ab9376076cedd88a374d7281d62b619634d578",
-                "shasum": ""
-            },
-            "require": {
-                "illuminate/contracts": "5.6.*",
-                "illuminate/support": "5.6.*",
-                "php": "^7.1.3",
-                "symfony/finder": "~4.0"
-            },
-            "suggest": {
-                "league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
-                "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
-                "league/flysystem-cached-adapter": "Required to use the Flysystem cache (~1.0).",
-                "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
-                "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0)."
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Illuminate\\Filesystem\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Taylor Otwell",
-                    "email": "taylor@laravel.com"
-                }
-            ],
-            "description": "The Illuminate Filesystem package.",
-            "homepage": "https://laravel.com",
-            "time": "2018-04-06T13:15:37+00:00"
-        },
-        {
-            "name": "illuminate/http",
-            "version": "v5.6.17",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/illuminate/http.git",
-                "reference": "1c58a1fd0b668c9d7203c6e69ba7391431815e47"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/http/zipball/1c58a1fd0b668c9d7203c6e69ba7391431815e47",
-                "reference": "1c58a1fd0b668c9d7203c6e69ba7391431815e47",
-                "shasum": ""
-            },
-            "require": {
-                "illuminate/session": "5.6.*",
-                "illuminate/support": "5.6.*",
-                "php": "^7.1.3",
-                "symfony/http-foundation": "~4.0",
-                "symfony/http-kernel": "~4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Illuminate\\Http\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Taylor Otwell",
-                    "email": "taylor@laravel.com"
-                }
-            ],
-            "description": "The Illuminate Http package.",
-            "homepage": "https://laravel.com",
-            "time": "2018-03-12T13:37:01+00:00"
-        },
-        {
-            "name": "illuminate/session",
-            "version": "v5.6.17",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/illuminate/session.git",
-                "reference": "90bb5857fb64e269d8d331f02f820555ee471f64"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/session/zipball/90bb5857fb64e269d8d331f02f820555ee471f64",
-                "reference": "90bb5857fb64e269d8d331f02f820555ee471f64",
-                "shasum": ""
-            },
-            "require": {
-                "illuminate/contracts": "5.6.*",
-                "illuminate/filesystem": "5.6.*",
-                "illuminate/support": "5.6.*",
-                "php": "^7.1.3",
-                "symfony/finder": "~4.0",
-                "symfony/http-foundation": "~4.0"
-            },
-            "suggest": {
-                "illuminate/console": "Required to use the session:table command (5.6.*)."
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Illuminate\\Session\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Taylor Otwell",
-                    "email": "taylor@laravel.com"
-                }
-            ],
-            "description": "The Illuminate Session package.",
-            "homepage": "https://laravel.com",
-            "time": "2018-03-06T14:29:02+00:00"
-        },
-        {
-            "name": "illuminate/support",
-            "version": "v5.6.17",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/illuminate/support.git",
-                "reference": "cc8d6f5cef3a901de6bb7d1b362102a6db001085"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/illuminate/support/zipball/cc8d6f5cef3a901de6bb7d1b362102a6db001085",
-                "reference": "cc8d6f5cef3a901de6bb7d1b362102a6db001085",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/inflector": "~1.1",
-                "ext-mbstring": "*",
-                "illuminate/contracts": "5.6.*",
-                "nesbot/carbon": "^1.24.1",
-                "php": "^7.1.3"
-            },
-            "conflict": {
-                "tightenco/collect": "<5.5.33"
-            },
-            "suggest": {
-                "illuminate/filesystem": "Required to use the composer class (5.6.*).",
-                "symfony/process": "Required to use the composer class (~4.0).",
-                "symfony/var-dumper": "Required to use the dd function (~4.0)."
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Illuminate\\Support\\": ""
-                },
-                "files": [
-                    "helpers.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Taylor Otwell",
-                    "email": "taylor@laravel.com"
-                }
-            ],
-            "description": "The Illuminate Support package.",
-            "homepage": "https://laravel.com",
-            "time": "2018-04-17T12:26:47+00:00"
-        },
-        {
-            "name": "monolog/monolog",
-            "version": "1.23.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
-                "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0",
-                "psr/log": "~1.0"
-            },
-            "provide": {
-                "psr/log-implementation": "1.0.0"
-            },
-            "require-dev": {
-                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
-                "doctrine/couchdb": "~1.0@dev",
-                "graylog2/gelf-php": "~1.0",
-                "jakub-onderka/php-parallel-lint": "0.9",
-                "php-amqplib/php-amqplib": "~2.4",
-                "php-console/php-console": "^3.1.3",
-                "phpunit/phpunit": "~4.5",
-                "phpunit/phpunit-mock-objects": "2.3.0",
-                "ruflin/elastica": ">=0.90 <3.0",
-                "sentry/sentry": "^0.13",
-                "swiftmailer/swiftmailer": "^5.3|^6.0"
-            },
-            "suggest": {
-                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
-                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
-                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
-                "ext-mongo": "Allow sending log messages to a MongoDB server",
-                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
-                "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
-                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
-                "php-console/php-console": "Allow sending log messages to Google Chrome",
-                "rollbar/rollbar": "Allow sending log messages to Rollbar",
-                "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
-                "sentry/sentry": "Allow sending log messages to a Sentry server"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Monolog\\": "src/Monolog"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jordi Boggiano",
-                    "email": "j.boggiano@seld.be",
-                    "homepage": "http://seld.be"
-                }
-            ],
-            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
-            "homepage": "http://github.com/Seldaek/monolog",
-            "keywords": [
-                "log",
-                "logging",
-                "psr-3"
-            ],
-            "time": "2017-06-19T01:22:40+00:00"
-        },
-        {
-            "name": "nesbot/carbon",
-            "version": "1.26.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "e3d9014279133a3cccc01f6a691322a2d5a6a87b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e3d9014279133a3cccc01f6a691322a2d5a6a87b",
-                "reference": "e3d9014279133a3cccc01f6a691322a2d5a6a87b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.9",
-                "symfony/translation": "~2.6 || ~3.0 || ~4.0"
-            },
-            "require-dev": {
-                "friendsofphp/php-cs-fixer": "~2",
-                "phpunit/phpunit": "^4.8.35 || ^5.7"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Brian Nesbitt",
-                    "email": "brian@nesbot.com",
-                    "homepage": "http://nesbot.com"
-                }
-            ],
-            "description": "A simple API extension for DateTime.",
-            "homepage": "http://carbon.nesbot.com",
-            "keywords": [
-                "date",
-                "datetime",
-                "time"
-            ],
-            "time": "2018-04-17T15:35:42+00:00"
-        },
-        {
-            "name": "psr/container",
-            "version": "1.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/container.git",
-                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
-                "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\Container\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common Container Interface (PHP FIG PSR-11)",
-            "homepage": "https://github.com/php-fig/container",
-            "keywords": [
-                "PSR-11",
-                "container",
-                "container-interface",
-                "container-interop",
-                "psr"
-            ],
-            "time": "2017-02-14T16:28:37+00:00"
-        },
-        {
-            "name": "psr/http-message",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/http-message.git",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
-                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\Http\\Message\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interface for HTTP messages",
-            "homepage": "https://github.com/php-fig/http-message",
-            "keywords": [
-                "http",
-                "http-message",
-                "psr",
-                "psr-7",
-                "request",
-                "response"
-            ],
-            "time": "2016-08-06T14:39:51+00:00"
-        },
-        {
-            "name": "psr/log",
-            "version": "1.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/log.git",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\Log\\": "Psr/Log/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interface for logging libraries",
-            "homepage": "https://github.com/php-fig/log",
-            "keywords": [
-                "log",
-                "psr",
-                "psr-3"
-            ],
-            "time": "2016-10-10T12:19:37+00:00"
-        },
-        {
-            "name": "psr/simple-cache",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/simple-cache.git",
-                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\SimpleCache\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interfaces for simple caching",
-            "keywords": [
-                "cache",
-                "caching",
-                "psr",
-                "psr-16",
-                "simple-cache"
-            ],
-            "time": "2017-10-23T01:57:42+00:00"
-        },
-        {
-            "name": "symfony/debug",
-            "version": "v4.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/debug.git",
-                "reference": "5961d02d48828671f5d8a7805e06579d692f6ede"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/debug/zipball/5961d02d48828671f5d8a7805e06579d692f6ede",
-                "reference": "5961d02d48828671f5d8a7805e06579d692f6ede",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "psr/log": "~1.0"
-            },
-            "conflict": {
-                "symfony/http-kernel": "<3.4"
-            },
-            "require-dev": {
-                "symfony/http-kernel": "~3.4|~4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Debug\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Debug Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-04-03T05:24:00+00:00"
-        },
-        {
-            "name": "symfony/event-dispatcher",
-            "version": "v4.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "63353a71073faf08f62caab4e6889b06a787f07b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/63353a71073faf08f62caab4e6889b06a787f07b",
-                "reference": "63353a71073faf08f62caab4e6889b06a787f07b",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3"
-            },
-            "conflict": {
-                "symfony/dependency-injection": "<3.4"
-            },
-            "require-dev": {
-                "psr/log": "~1.0",
-                "symfony/config": "~3.4|~4.0",
-                "symfony/dependency-injection": "~3.4|~4.0",
-                "symfony/expression-language": "~3.4|~4.0",
-                "symfony/stopwatch": "~3.4|~4.0"
-            },
-            "suggest": {
-                "symfony/dependency-injection": "",
-                "symfony/http-kernel": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\EventDispatcher\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony EventDispatcher Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-04-06T07:35:43+00:00"
-        },
-        {
-            "name": "symfony/finder",
-            "version": "v4.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/finder.git",
-                "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
-                "reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Finder\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Finder Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-04-04T05:10:37+00:00"
-        },
-        {
-            "name": "symfony/http-foundation",
-            "version": "v4.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "d0864a82e5891ab61d31eecbaa48bed5a09b8e6c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0864a82e5891ab61d31eecbaa48bed5a09b8e6c",
-                "reference": "d0864a82e5891ab61d31eecbaa48bed5a09b8e6c",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "symfony/polyfill-mbstring": "~1.1"
-            },
-            "require-dev": {
-                "symfony/expression-language": "~3.4|~4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\HttpFoundation\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony HttpFoundation Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-04-03T05:24:00+00:00"
-        },
-        {
-            "name": "symfony/http-kernel",
-            "version": "v4.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/http-kernel.git",
-                "reference": "6dd620d96d64456075536ffe3c6c4658dd689021"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6dd620d96d64456075536ffe3c6c4658dd689021",
-                "reference": "6dd620d96d64456075536ffe3c6c4658dd689021",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "psr/log": "~1.0",
-                "symfony/debug": "~3.4|~4.0",
-                "symfony/event-dispatcher": "~3.4|~4.0",
-                "symfony/http-foundation": "~3.4.4|~4.0.4"
-            },
-            "conflict": {
-                "symfony/config": "<3.4",
-                "symfony/dependency-injection": "<3.4.5|<4.0.5,>=4",
-                "symfony/var-dumper": "<3.4",
-                "twig/twig": "<1.34|<2.4,>=2"
-            },
-            "provide": {
-                "psr/log-implementation": "1.0"
-            },
-            "require-dev": {
-                "psr/cache": "~1.0",
-                "symfony/browser-kit": "~3.4|~4.0",
-                "symfony/config": "~3.4|~4.0",
-                "symfony/console": "~3.4|~4.0",
-                "symfony/css-selector": "~3.4|~4.0",
-                "symfony/dependency-injection": "^3.4.5|^4.0.5",
-                "symfony/dom-crawler": "~3.4|~4.0",
-                "symfony/expression-language": "~3.4|~4.0",
-                "symfony/finder": "~3.4|~4.0",
-                "symfony/process": "~3.4|~4.0",
-                "symfony/routing": "~3.4|~4.0",
-                "symfony/stopwatch": "~3.4|~4.0",
-                "symfony/templating": "~3.4|~4.0",
-                "symfony/translation": "~3.4|~4.0",
-                "symfony/var-dumper": "~3.4|~4.0"
-            },
-            "suggest": {
-                "symfony/browser-kit": "",
-                "symfony/config": "",
-                "symfony/console": "",
-                "symfony/dependency-injection": "",
-                "symfony/var-dumper": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\HttpKernel\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony HttpKernel Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-04-06T16:25:03+00:00"
-        },
-        {
-            "name": "symfony/polyfill-mbstring",
-            "version": "v1.7.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
-                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-mbstring": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.7-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Mbstring\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for the Mbstring extension",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "mbstring",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2018-01-30T19:27:44+00:00"
-        },
-        {
-            "name": "symfony/translation",
-            "version": "v4.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/translation.git",
-                "reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation/zipball/e20a9b7f9f62cb33a11638b345c248e7d510c938",
-                "reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "symfony/polyfill-mbstring": "~1.0"
-            },
-            "conflict": {
-                "symfony/config": "<3.4",
-                "symfony/dependency-injection": "<3.4",
-                "symfony/yaml": "<3.4"
-            },
-            "require-dev": {
-                "psr/log": "~1.0",
-                "symfony/config": "~3.4|~4.0",
-                "symfony/dependency-injection": "~3.4|~4.0",
-                "symfony/finder": "~2.8|~3.0|~4.0",
-                "symfony/intl": "~3.4|~4.0",
-                "symfony/yaml": "~3.4|~4.0"
-            },
-            "suggest": {
-                "psr/log": "To use logging capability in translator",
-                "symfony/config": "",
-                "symfony/yaml": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Translation\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Translation Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-02-22T10:50:29+00:00"
-        }
-    ],
-    "packages-dev": [
-        {
-            "name": "doctrine/instantiator",
-            "version": "1.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
-                "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1"
-            },
-            "require-dev": {
-                "athletic/athletic": "~0.1.8",
-                "ext-pdo": "*",
-                "ext-phar": "*",
-                "phpunit/phpunit": "^6.2.3",
-                "squizlabs/php_codesniffer": "^3.0.2"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.2.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Marco Pivetta",
-                    "email": "ocramius@gmail.com",
-                    "homepage": "http://ocramius.github.com/"
-                }
-            ],
-            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
-            "homepage": "https://github.com/doctrine/instantiator",
-            "keywords": [
-                "constructor",
-                "instantiate"
-            ],
-            "time": "2017-07-22T11:58:36+00:00"
-        },
-        {
-            "name": "myclabs/deep-copy",
-            "version": "1.7.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
-                "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.6 || ^7.0"
-            },
-            "require-dev": {
-                "doctrine/collections": "^1.0",
-                "doctrine/common": "^2.6",
-                "phpunit/phpunit": "^4.1"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "DeepCopy\\": "src/DeepCopy/"
-                },
-                "files": [
-                    "src/DeepCopy/deep_copy.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "description": "Create deep copies (clones) of your objects",
-            "keywords": [
-                "clone",
-                "copy",
-                "duplicate",
-                "object",
-                "object graph"
-            ],
-            "time": "2017-10-19T19:58:43+00:00"
-        },
-        {
-            "name": "phar-io/manifest",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phar-io/manifest.git",
-                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0",
-                "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-phar": "*",
-                "phar-io/version": "^1.0.1",
-                "php": "^5.6 || ^7.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Arne Blankerts",
-                    "email": "arne@blankerts.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Heuer",
-                    "email": "sebastian@phpeople.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "Developer"
-                }
-            ],
-            "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
-            "time": "2017-03-05T18:14:27+00:00"
-        },
-        {
-            "name": "phar-io/version",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phar-io/version.git",
-                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df",
-                "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.6 || ^7.0"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Arne Blankerts",
-                    "email": "arne@blankerts.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Heuer",
-                    "email": "sebastian@phpeople.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "Developer"
-                }
-            ],
-            "description": "Library for handling version information and constraints",
-            "time": "2017-03-05T17:38:23+00:00"
-        },
-        {
-            "name": "phpdocumentor/reflection-common",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
-                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
-                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.5"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.6"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jaap van Otterdijk",
-                    "email": "opensource@ijaap.nl"
-                }
-            ],
-            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
-            "homepage": "http://www.phpdoc.org",
-            "keywords": [
-                "FQSEN",
-                "phpDocumentor",
-                "phpdoc",
-                "reflection",
-                "static analysis"
-            ],
-            "time": "2017-09-11T18:02:19+00:00"
-        },
-        {
-            "name": "phpdocumentor/reflection-docblock",
-            "version": "4.3.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "94fd0001232e47129dd3504189fa1c7225010d08"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
-                "reference": "94fd0001232e47129dd3504189fa1c7225010d08",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0",
-                "phpdocumentor/reflection-common": "^1.0.0",
-                "phpdocumentor/type-resolver": "^0.4.0",
-                "webmozart/assert": "^1.0"
-            },
-            "require-dev": {
-                "doctrine/instantiator": "~1.0.5",
-                "mockery/mockery": "^1.0",
-                "phpunit/phpunit": "^6.4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src/"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mike van Riel",
-                    "email": "me@mikevanriel.com"
-                }
-            ],
-            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2017-11-30T07:14:17+00:00"
-        },
-        {
-            "name": "phpdocumentor/type-resolver",
-            "version": "0.4.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpDocumentor/TypeResolver.git",
-                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
-                "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5 || ^7.0",
-                "phpdocumentor/reflection-common": "^1.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "^0.9.4",
-                "phpunit/phpunit": "^5.2||^4.8.24"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src/"
-                    ]
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Mike van Riel",
-                    "email": "me@mikevanriel.com"
-                }
-            ],
-            "time": "2017-07-14T14:27:02+00:00"
-        },
-        {
-            "name": "phpspec/prophecy",
-            "version": "1.7.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
-                "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.2",
-                "php": "^5.3|^7.0",
-                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
-                "sebastian/comparator": "^1.1|^2.0|^3.0",
-                "sebastian/recursion-context": "^1.0|^2.0|^3.0"
-            },
-            "require-dev": {
-                "phpspec/phpspec": "^2.5|^3.2",
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.7.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-0": {
-                    "Prophecy\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Konstantin Kudryashov",
-                    "email": "ever.zet@gmail.com",
-                    "homepage": "http://everzet.com"
-                },
-                {
-                    "name": "Marcello Duarte",
-                    "email": "marcello.duarte@gmail.com"
-                }
-            ],
-            "description": "Highly opinionated mocking framework for PHP 5.3+",
-            "homepage": "https://github.com/phpspec/prophecy",
-            "keywords": [
-                "Double",
-                "Dummy",
-                "fake",
-                "mock",
-                "spy",
-                "stub"
-            ],
-            "time": "2018-04-18T13:57:24+00:00"
-        },
-        {
-            "name": "phpunit/php-code-coverage",
-            "version": "6.0.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "774a82c0c5da4c1c7701790c262035d235ab7856"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/774a82c0c5da4c1c7701790c262035d235ab7856",
-                "reference": "774a82c0c5da4c1c7701790c262035d235ab7856",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-xmlwriter": "*",
-                "php": "^7.1",
-                "phpunit/php-file-iterator": "^1.4.2",
-                "phpunit/php-text-template": "^1.2.1",
-                "phpunit/php-token-stream": "^3.0",
-                "sebastian/code-unit-reverse-lookup": "^1.0.1",
-                "sebastian/environment": "^3.1",
-                "sebastian/version": "^2.0.1",
-                "theseer/tokenizer": "^1.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^7.0"
-            },
-            "suggest": {
-                "ext-xdebug": "^2.6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "6.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
-            "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
-            "keywords": [
-                "coverage",
-                "testing",
-                "xunit"
-            ],
-            "time": "2018-04-06T15:39:20+00:00"
-        },
-        {
-            "name": "phpunit/php-file-iterator",
-            "version": "1.4.5",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
-                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "FilterIterator implementation that filters files based on a list of suffixes.",
-            "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
-            "keywords": [
-                "filesystem",
-                "iterator"
-            ],
-            "time": "2017-11-27T13:52:08+00:00"
-        },
-        {
-            "name": "phpunit/php-text-template",
-            "version": "1.2.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-text-template.git",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
-                "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Simple template engine.",
-            "homepage": "https://github.com/sebastianbergmann/php-text-template/",
-            "keywords": [
-                "template"
-            ],
-            "time": "2015-06-21T13:50:34+00:00"
-        },
-        {
-            "name": "phpunit/php-timer",
-            "version": "2.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f",
-                "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^7.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Utility class for timing",
-            "homepage": "https://github.com/sebastianbergmann/php-timer/",
-            "keywords": [
-                "timer"
-            ],
-            "time": "2018-02-01T13:07:23+00:00"
-        },
-        {
-            "name": "phpunit/php-token-stream",
-            "version": "3.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace",
-                "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace",
-                "shasum": ""
-            },
-            "require": {
-                "ext-tokenizer": "*",
-                "php": "^7.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^7.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Wrapper around PHP's tokenizer extension.",
-            "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
-            "keywords": [
-                "tokenizer"
-            ],
-            "time": "2018-02-01T13:16:43+00:00"
-        },
-        {
-            "name": "phpunit/phpunit",
-            "version": "7.1.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "6d51299e307dc510149e0b7cd1931dd11770e1cb"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6d51299e307dc510149e0b7cd1931dd11770e1cb",
-                "reference": "6d51299e307dc510149e0b7cd1931dd11770e1cb",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-json": "*",
-                "ext-libxml": "*",
-                "ext-mbstring": "*",
-                "ext-xml": "*",
-                "myclabs/deep-copy": "^1.6.1",
-                "phar-io/manifest": "^1.0.1",
-                "phar-io/version": "^1.0",
-                "php": "^7.1",
-                "phpspec/prophecy": "^1.7",
-                "phpunit/php-code-coverage": "^6.0.1",
-                "phpunit/php-file-iterator": "^1.4.3",
-                "phpunit/php-text-template": "^1.2.1",
-                "phpunit/php-timer": "^2.0",
-                "phpunit/phpunit-mock-objects": "^6.1.1",
-                "sebastian/comparator": "^2.1 || ^3.0",
-                "sebastian/diff": "^3.0",
-                "sebastian/environment": "^3.1",
-                "sebastian/exporter": "^3.1",
-                "sebastian/global-state": "^2.0",
-                "sebastian/object-enumerator": "^3.0.3",
-                "sebastian/resource-operations": "^1.0",
-                "sebastian/version": "^2.0.1"
-            },
-            "require-dev": {
-                "ext-pdo": "*"
-            },
-            "suggest": {
-                "ext-xdebug": "*",
-                "phpunit/php-invoker": "^2.0"
-            },
-            "bin": [
-                "phpunit"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "7.1-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "The PHP Unit Testing framework.",
-            "homepage": "https://phpunit.de/",
-            "keywords": [
-                "phpunit",
-                "testing",
-                "xunit"
-            ],
-            "time": "2018-04-18T13:41:53+00:00"
-        },
-        {
-            "name": "phpunit/phpunit-mock-objects",
-            "version": "6.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/70c740bde8fd9ea9ea295be1cd875dd7b267e157",
-                "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/instantiator": "^1.0.5",
-                "php": "^7.1",
-                "phpunit/php-text-template": "^1.2.1",
-                "sebastian/exporter": "^3.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^7.0"
-            },
-            "suggest": {
-                "ext-soap": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "6.1-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Mock Object library for PHPUnit",
-            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
-            "keywords": [
-                "mock",
-                "xunit"
-            ],
-            "time": "2018-04-11T04:50:36+00:00"
-        },
-        {
-            "name": "sebastian/code-unit-reverse-lookup",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
-                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
-                "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.6 || ^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^5.7 || ^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Looks up which function or method a line of code belongs to",
-            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
-            "time": "2017-03-04T06:30:41+00:00"
-        },
-        {
-            "name": "sebastian/comparator",
-            "version": "3.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ed5fd2281113729f1ebcc64d101ad66028aeb3d5",
-                "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1",
-                "sebastian/diff": "^3.0",
-                "sebastian/exporter": "^3.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^7.1"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides the functionality to compare PHP values for equality",
-            "homepage": "https://github.com/sebastianbergmann/comparator",
-            "keywords": [
-                "comparator",
-                "compare",
-                "equality"
-            ],
-            "time": "2018-04-18T13:33:00+00:00"
-        },
-        {
-            "name": "sebastian/diff",
-            "version": "3.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8",
-                "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^7.0",
-                "symfony/process": "^2 || ^3.3 || ^4"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Kore Nordmann",
-                    "email": "mail@kore-nordmann.de"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Diff implementation",
-            "homepage": "https://github.com/sebastianbergmann/diff",
-            "keywords": [
-                "diff",
-                "udiff",
-                "unidiff",
-                "unified diff"
-            ],
-            "time": "2018-02-01T13:45:15+00:00"
-        },
-        {
-            "name": "sebastian/environment",
-            "version": "3.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
-                "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.1"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides functionality to handle HHVM/PHP environments",
-            "homepage": "http://www.github.com/sebastianbergmann/environment",
-            "keywords": [
-                "Xdebug",
-                "environment",
-                "hhvm"
-            ],
-            "time": "2017-07-01T08:51:00+00:00"
-        },
-        {
-            "name": "sebastian/exporter",
-            "version": "3.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937",
-                "reference": "234199f4528de6d12aaa58b612e98f7d36adb937",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0",
-                "sebastian/recursion-context": "^3.0"
-            },
-            "require-dev": {
-                "ext-mbstring": "*",
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.1.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Volker Dusch",
-                    "email": "github@wallbash.com"
-                },
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@2bepublished.at"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides the functionality to export PHP variables for visualization",
-            "homepage": "http://www.github.com/sebastianbergmann/exporter",
-            "keywords": [
-                "export",
-                "exporter"
-            ],
-            "time": "2017-04-03T13:19:02+00:00"
-        },
-        {
-            "name": "sebastian/global-state",
-            "version": "2.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
-                "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "suggest": {
-                "ext-uopz": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Snapshotting of global state",
-            "homepage": "http://www.github.com/sebastianbergmann/global-state",
-            "keywords": [
-                "global state"
-            ],
-            "time": "2017-04-27T15:39:26+00:00"
-        },
-        {
-            "name": "sebastian/object-enumerator",
-            "version": "3.0.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
-                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5",
-                "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0",
-                "sebastian/object-reflector": "^1.1.1",
-                "sebastian/recursion-context": "^3.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Traverses array structures and object graphs to enumerate all referenced objects",
-            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
-            "time": "2017-08-03T12:35:26+00:00"
-        },
-        {
-            "name": "sebastian/object-reflector",
-            "version": "1.1.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/object-reflector.git",
-                "reference": "773f97c67f28de00d397be301821b06708fca0be"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be",
-                "reference": "773f97c67f28de00d397be301821b06708fca0be",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.1-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Allows reflection of object attributes, including inherited and non-public ones",
-            "homepage": "https://github.com/sebastianbergmann/object-reflector/",
-            "time": "2017-03-29T09:07:27+00:00"
-        },
-        {
-            "name": "sebastian/recursion-context",
-            "version": "3.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
-                "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Jeff Welch",
-                    "email": "whatthejeff@gmail.com"
-                },
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                },
-                {
-                    "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
-                }
-            ],
-            "description": "Provides functionality to recursively process PHP variables",
-            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
-            "time": "2017-03-03T06:23:57+00:00"
-        },
-        {
-            "name": "sebastian/resource-operations",
-            "version": "1.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/resource-operations.git",
-                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
-                "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.6.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
-                }
-            ],
-            "description": "Provides a list of PHP built-in functions that operate on resources",
-            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
-            "time": "2015-07-28T20:34:47+00:00"
-        },
-        {
-            "name": "sebastian/version",
-            "version": "2.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
-                "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.6"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
-            "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2016-10-03T07:35:21+00:00"
-        },
-        {
-            "name": "squizlabs/php_codesniffer",
-            "version": "3.2.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
-                "reference": "4842476c434e375f9d3182ff7b89059583aa8b27"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4842476c434e375f9d3182ff7b89059583aa8b27",
-                "reference": "4842476c434e375f9d3182ff7b89059583aa8b27",
-                "shasum": ""
-            },
-            "require": {
-                "ext-simplexml": "*",
-                "ext-tokenizer": "*",
-                "ext-xmlwriter": "*",
-                "php": ">=5.4.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
-            },
-            "bin": [
-                "bin/phpcs",
-                "bin/phpcbf"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.x-dev"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Greg Sherwood",
-                    "role": "lead"
-                }
-            ],
-            "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
-            "homepage": "http://www.squizlabs.com/php-codesniffer",
-            "keywords": [
-                "phpcs",
-                "standards"
-            ],
-            "time": "2018-02-20T21:35:23+00:00"
-        },
-        {
-            "name": "symfony/polyfill-php72",
-            "version": "v1.7.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php72.git",
-                "reference": "8eca20c8a369e069d4f4c2ac9895144112867422"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/8eca20c8a369e069d4f4c2ac9895144112867422",
-                "reference": "8eca20c8a369e069d4f4c2ac9895144112867422",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.7-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php72\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2018-01-31T17:43:24+00:00"
-        },
-        {
-            "name": "symfony/var-dumper",
-            "version": "v4.0.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/var-dumper.git",
-                "reference": "e1b4d008100f4d203cc38b0d793ad6252d8d8af0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e1b4d008100f4d203cc38b0d793ad6252d8d8af0",
-                "reference": "e1b4d008100f4d203cc38b0d793ad6252d8d8af0",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "symfony/polyfill-mbstring": "~1.0",
-                "symfony/polyfill-php72": "~1.5"
-            },
-            "conflict": {
-                "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
-            },
-            "require-dev": {
-                "ext-iconv": "*",
-                "twig/twig": "~1.34|~2.4"
-            },
-            "suggest": {
-                "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
-                "ext-intl": "To show region name in time zone dump"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.0-dev"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "Resources/functions/dump.php"
-                ],
-                "psr-4": {
-                    "Symfony\\Component\\VarDumper\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony mechanism for exploring and dumping PHP variables",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "debug",
-                "dump"
-            ],
-            "time": "2018-04-04T05:10:37+00:00"
-        },
-        {
-            "name": "theseer/tokenizer",
-            "version": "1.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/theseer/tokenizer.git",
-                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b",
-                "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "ext-tokenizer": "*",
-                "ext-xmlwriter": "*",
-                "php": "^7.0"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Arne Blankerts",
-                    "email": "arne@blankerts.de",
-                    "role": "Developer"
-                }
-            ],
-            "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
-            "time": "2017-04-07T12:08:54+00:00"
-        },
-        {
-            "name": "webmozart/assert",
-            "version": "1.3.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/webmozart/assert.git",
-                "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
-                "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.3.3 || ^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.6",
-                "sebastian/version": "^1.0.1"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.3-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Webmozart\\Assert\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Bernhard Schussek",
-                    "email": "bschussek@gmail.com"
-                }
-            ],
-            "description": "Assertions to validate method input/output with nice error messages.",
-            "keywords": [
-                "assert",
-                "check",
-                "validate"
-            ],
-            "time": "2018-01-29T19:49:41+00:00"
-        }
-    ],
-    "aliases": [],
-    "minimum-stability": "stable",
-    "stability-flags": [],
-    "prefer-stable": false,
-    "prefer-lowest": false,
-    "platform": {
-        "php": ">=5.6.4|^7.0",
-        "ext-pdo": "*",
-        "ext-curl": "*",
-        "ext-mbstring": "*"
-    },
-    "platform-dev": []
-}

From f64e3154ad1da439193a2e709494055aad8602de Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 18:09:53 +0400
Subject: [PATCH 12/40] Add fix-code action to composer

---
 composer.json | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/composer.json b/composer.json
index bf979859e..dc84aa6e0 100644
--- a/composer.json
+++ b/composer.json
@@ -47,6 +47,9 @@
         "check-code": [
             "\"vendor/bin/phpcs\" --standard=phpcs.xml -snp --encoding=utf-8 src/ tests/ --report-width=150"
         ],
+        "fix-code": [
+            "\"vendor/bin/phpcbf\" --standard=phpcs.xml -snp --encoding=utf-8 src/ tests/ --report-width=150"
+        ],
         "test": [
             "\"vendor/bin/phpunit\""
         ],

From b217fa7eae7c01ac68e19b2c8a9e2fa4495eb6fc Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 18:10:34 +0400
Subject: [PATCH 13/40] Fix code style

---
 src/Http/Client.php         | 2 +-
 src/Http/Request.php        | 1 -
 src/Http/ServerResponse.php | 2 --
 3 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/Http/Client.php b/src/Http/Client.php
index 24a3592fd..2bad45a43 100644
--- a/src/Http/Client.php
+++ b/src/Http/Client.php
@@ -19,7 +19,7 @@
 use Longman\TelegramBot\TelegramLog;
 
 /**
- * Class Request
+ * Class Client
  *
  * @method static ServerResponse getUpdates(array $data)              Use this method to receive incoming updates using long polling (wiki). An Array of Update
  *     objects is returned.
diff --git a/src/Http/Request.php b/src/Http/Request.php
index 83d8569fe..823063095 100644
--- a/src/Http/Request.php
+++ b/src/Http/Request.php
@@ -12,7 +12,6 @@
 
 use Illuminate\Http\Request as LaravelRequest;
 
-
 class Request extends LaravelRequest
 {
 
diff --git a/src/Http/ServerResponse.php b/src/Http/ServerResponse.php
index b08bb164e..2202a785b 100644
--- a/src/Http/ServerResponse.php
+++ b/src/Http/ServerResponse.php
@@ -187,7 +187,6 @@ private function createResultObject($result, $bot_username)
         ];
         foreach ($result_object_types as $type => $object_class) {
             if (isset($result[$type])) {
-
                 return new $object_class($result);
             }
         }
@@ -228,5 +227,4 @@ private function createResultObjects($result, $bot_username)
 
         return $results;
     }
-
 }

From a2f6ee781ce8f0a8fede0c368208532b0b36eafe Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 18:17:29 +0400
Subject: [PATCH 14/40] Update code style config

---
 composer.json |  15 ++++++-
 phpcs.xml     | 113 +-------------------------------------------------
 2 files changed, 15 insertions(+), 113 deletions(-)

diff --git a/composer.json b/composer.json
index dc84aa6e0..2236dab8d 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,11 @@
     "name": "longman/telegram-bot",
     "type": "library",
     "description": "PHP Telegram bot",
-    "keywords": ["telegram", "bot", "api"],
+    "keywords": [
+        "telegram",
+        "bot",
+        "api"
+    ],
     "license": "MIT",
     "homepage": "https://github.com/php-telegram-bot/core",
     "support": {
@@ -31,7 +35,8 @@
     "require-dev": {
         "phpunit/phpunit": "^4.8|^5.7|^6.5|^7.0",
         "symfony/var-dumper": "3.4.*|~4.0",
-        "squizlabs/php_codesniffer": "^3.2"
+        "squizlabs/php_codesniffer": "^3.2",
+        "longman/php-code-style": "^1.0"
     },
     "autoload": {
         "psr-4": {
@@ -59,5 +64,11 @@
         "test-cov-upload": [
             "wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml"
         ]
+    },
+    "config": {
+        "preferred-install": "dist",
+        "sort-packages": true,
+        "optimize-autoloader": true,
+        "process-timeout": 3600
     }
 }
diff --git a/phpcs.xml b/phpcs.xml
index 69b989102..9ca0df1b0 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -1,117 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<ruleset name="pcsg-generated-ruleset">
+<ruleset name="Project code style checker config">
     <description>PHP Code Sniffer</description>
 
-    <arg name="colors"/>
-
-    <rule ref="PSR2"/>
-
-    <rule ref="Generic.CodeAnalysis.EmptyStatement"/>
-    <rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
-    <rule ref="Generic.CodeAnalysis.UnusedFunctionParameter"/>
-    <rule ref="Generic.CodeAnalysis.JumbledIncrementer"/>
-    <rule ref="Generic.CodeAnalysis.UnconditionalIfStatement"/>
-    <rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>
-
-    <rule ref="Generic.ControlStructures.InlineControlStructure"/>
-
-    <rule ref="Generic.Files.ByteOrderMark"/>
-    <rule ref="Generic.Files.LineEndings"/>
-
-    <rule ref="Generic.Formatting.DisallowMultipleStatements"/>
-    <rule ref="Generic.Formatting.SpaceAfterCast.NoSpace">
-        <type>warning</type>
-    </rule>
-    <rule ref="Generic.Functions.CallTimePassByReference"/>
-    <rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
-
-    <rule ref="Generic.Metrics.NestingLevel">
-        <properties>
-            <property name="nestingLevel" value="7"/>
-        </properties>
-    </rule>
-    <rule ref="Generic.Metrics.CyclomaticComplexity">
-        <properties>
-            <property name="complexity" value="20"/>
-            <property name="absoluteComplexity" value="40"/>
-        </properties>
-    </rule>
-    <rule ref="Generic.Metrics.CyclomaticComplexity.TooHigh">
-        <type>warning</type>
-    </rule>
-    <rule ref="Generic.Metrics.CyclomaticComplexity.MaxExceeded">
-        <type>warning</type>
-    </rule>
-
-    <rule ref="Generic.NamingConventions.ConstructorName"/>
-    <rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
-    <rule ref="Generic.NamingConventions.CamelCapsFunctionName"/>
-
-    <rule ref="Generic.PHP.DeprecatedFunctions"/>
-    <rule ref="Generic.PHP.DisallowShortOpenTag"/>
-    <rule ref="Generic.PHP.ForbiddenFunctions"/>
-    <rule ref="Generic.PHP.LowerCaseConstant"/>
-    <rule ref="Generic.PHP.NoSilencedErrors"/>
-
-    <rule ref="Generic.Strings.UnnecessaryStringConcat"/>
-
-    <rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
-    <rule ref="Generic.WhiteSpace.ScopeIndent"/>
-
-    <rule ref="Generic.Commenting.Todo.CommentFound">
-        <message>Please review this TODO comment: %s</message>
-        <type>warning</type>
-    </rule>
-    <rule ref="Generic.Commenting.Fixme.TaskFound">
-        <message>Please review this FIXME comment: %s</message>
-        <type>warning</type>
-    </rule>
-
-    <rule ref="Generic.Files.LineLength">
-        <properties>
-            <property name="lineLimit" value="120"/>
-            <property name="absoluteLineLimit" value="200"/>
-        </properties>
-    </rule>
-    <rule ref="Generic.Files.LineLength">
-        <exclude name="Generic.Files.LineLength.MaxExceeded"/>
-        <exclude name="Generic.Files.LineLength.TooLong"/>
-    </rule>
-    <!--
-    <rule ref="Generic.Files.LineLength.MaxExceeded">
-        <message>Line contains %s chars, which is longer than the max limit of %s</message>
-        <type>warning</type>
+    <rule ref="./vendor/longman/php-code-style/longish.phpcs.xml">
     </rule>
-    <rule ref="Generic.Files.LineLength.TooLong">
-        <message>Line longer than %s characters; contains %s characters</message>
-        <type>warning</type>
-    </rule> -->
-    <rule ref="Generic.Classes.DuplicateClassName"/>
-
-    <rule ref="PEAR.Commenting.InlineComment"/>
-
-    <rule ref="PEAR.ControlStructures.MultiLineCondition"/>
-
-    <rule ref="PEAR.WhiteSpace.ObjectOperatorIndent"/>
-
-    <rule ref="MySource.PHP.EvalObjectFactory"/>
-    <rule ref="MySource.PHP.GetRequestData"/>
-    <!--
-    <rule ref="MySource.PHP.ReturnFunctionValue"/>
-    -->
-
-    <rule ref="Squiz.WhiteSpace.LogicalOperatorSpacing"/>
-    <rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
-    <rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EmptyLines">
-        <type>warning</type>
-    </rule>
-    <rule ref="Squiz.WhiteSpace.CastSpacing"/>
-    <rule ref="Squiz.WhiteSpace.LanguageConstructSpacing"/>
-    <!--
-    <rule ref="Squiz.WhiteSpace.MemberVarSpacing"/>
-    -->
-    <rule ref="Squiz.WhiteSpace.OperatorSpacing"/>
-
-    <rule ref="Squiz.Scope.StaticThisUsage"/>
 
 </ruleset>

From b0e9f7b5cd013d0880190b6fbfcffe14e3092321 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 18:45:19 +0400
Subject: [PATCH 15/40] Introduce console kernel class and handle cli update
 requests

---
 src/Commands/AdminCommands/ChatsCommand.php   |   2 +-
 src/Commands/AdminCommands/CleanupCommand.php |   4 +-
 .../AdminCommands/SendtoallCommand.php        |   6 +-
 .../AdminCommands/SendtochannelCommand.php    |   4 +-
 src/Commands/AdminCommands/WhoisCommand.php   |   2 +-
 src/Commands/Command.php                      |  10 +-
 src/Commands/SystemCommand.php                |   2 +-
 .../SystemCommands/GenericmessageCommand.php  |   4 +-
 src/Console/Kernel.php                        | 113 ++++++++++++++++
 src/Entities/Payments/PreCheckoutQuery.php    |   2 +-
 src/Entities/Payments/ShippingQuery.php       |   2 +-
 src/Http/Client.php                           | 124 +++++++++---------
 src/Http/Kernel.php                           |   4 +-
 src/Http/{ServerResponse.php => Response.php} |   2 +-
 src/Telegram.php                              |  79 ++---------
 tests/unit/Entities/ServerResponseTest.php    |  22 ++--
 16 files changed, 221 insertions(+), 161 deletions(-)
 create mode 100644 src/Console/Kernel.php
 rename src/Http/{ServerResponse.php => Response.php} (99%)

diff --git a/src/Commands/AdminCommands/ChatsCommand.php b/src/Commands/AdminCommands/ChatsCommand.php
index 5c7120895..c4a5ab7ff 100644
--- a/src/Commands/AdminCommands/ChatsCommand.php
+++ b/src/Commands/AdminCommands/ChatsCommand.php
@@ -45,7 +45,7 @@ class ChatsCommand extends AdminCommand
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Commands/AdminCommands/CleanupCommand.php b/src/Commands/AdminCommands/CleanupCommand.php
index 83af45906..82acf0dfc 100644
--- a/src/Commands/AdminCommands/CleanupCommand.php
+++ b/src/Commands/AdminCommands/CleanupCommand.php
@@ -326,7 +326,7 @@ private function getQueries($settings)
     /**
      * Execution if MySQL is required but not available
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function executeNoDb()
     {
@@ -345,7 +345,7 @@ public function executeNoDb()
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Commands/AdminCommands/SendtoallCommand.php b/src/Commands/AdminCommands/SendtoallCommand.php
index f9ddef97f..2f5d6d80b 100644
--- a/src/Commands/AdminCommands/SendtoallCommand.php
+++ b/src/Commands/AdminCommands/SendtoallCommand.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\Entities\Message;
-use Longman\TelegramBot\Http\ServerResponse;
+use Longman\TelegramBot\Http\Response;
 use Longman\TelegramBot\Http\Client;
 
 /**
@@ -48,7 +48,7 @@ class SendtoallCommand extends AdminCommand
     /**
      * Execute command
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
@@ -59,7 +59,7 @@ public function execute()
             return $this->replyToChat('Usage: ' . $this->getUsage());
         }
 
-        /** @var ServerResponse[] $results */
+        /** @var Response[] $results */
         $results = Client::sendToActiveChats(
             'sendMessage',     //callback function to execute (see Request.php methods)
             ['text' => $text], //Param to evaluate the request
diff --git a/src/Commands/AdminCommands/SendtochannelCommand.php b/src/Commands/AdminCommands/SendtochannelCommand.php
index 589e80574..608edec76 100644
--- a/src/Commands/AdminCommands/SendtochannelCommand.php
+++ b/src/Commands/AdminCommands/SendtochannelCommand.php
@@ -54,7 +54,7 @@ class SendtochannelCommand extends AdminCommand
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse|mixed
+     * @return \Longman\TelegramBot\Http\Response|mixed
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
@@ -275,7 +275,7 @@ public function execute()
      * @param \Longman\TelegramBot\Entities\Message $message
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     protected function sendBack(Message $message, array $data)
diff --git a/src/Commands/AdminCommands/WhoisCommand.php b/src/Commands/AdminCommands/WhoisCommand.php
index 3fc14b5cd..2090eea63 100644
--- a/src/Commands/AdminCommands/WhoisCommand.php
+++ b/src/Commands/AdminCommands/WhoisCommand.php
@@ -52,7 +52,7 @@ class WhoisCommand extends AdminCommand
     /**
      * Command execute method
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index 5fe6fc220..45f4809a9 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -143,7 +143,7 @@ public function setUpdate(Update $update = null)
     /**
      * Pre-execute command
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function preExecute()
@@ -176,7 +176,7 @@ public function preExecute()
     /**
      * Execute command
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     abstract public function execute();
@@ -184,7 +184,7 @@ abstract public function execute();
     /**
      * Execution if MySQL is required but not available
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function executeNoDb()
@@ -393,7 +393,7 @@ protected function removeNonPrivateMessage()
      * @param string $text
      * @param array  $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function replyToChat($text, array $data = [])
     {
@@ -413,7 +413,7 @@ public function replyToChat($text, array $data = [])
      * @param string $text
      * @param array  $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function replyToUser($text, array $data = [])
     {
diff --git a/src/Commands/SystemCommand.php b/src/Commands/SystemCommand.php
index fc3e8b8e4..fdeae34bd 100644
--- a/src/Commands/SystemCommand.php
+++ b/src/Commands/SystemCommand.php
@@ -20,7 +20,7 @@ abstract class SystemCommand extends Command
      * Although system commands should just work and return a successful ServerResponse,
      * each system command can override this method to add custom functionality.
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function execute()
     {
diff --git a/src/Commands/SystemCommands/GenericmessageCommand.php b/src/Commands/SystemCommands/GenericmessageCommand.php
index de434a31c..49e083b49 100644
--- a/src/Commands/SystemCommands/GenericmessageCommand.php
+++ b/src/Commands/SystemCommands/GenericmessageCommand.php
@@ -42,7 +42,7 @@ class GenericmessageCommand extends SystemCommand
     /**
      * Execution if MySQL is required but not available
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function executeNoDb()
     {
@@ -53,7 +53,7 @@ public function executeNoDb()
     /**
      * Execute command
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function execute()
diff --git a/src/Console/Kernel.php b/src/Console/Kernel.php
new file mode 100644
index 000000000..c94c56830
--- /dev/null
+++ b/src/Console/Kernel.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * This file is part of the TelegramBot package.
+ *
+ * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Longman\TelegramBot\Console;
+
+use Longman\TelegramBot\DB;
+use Longman\TelegramBot\Entities\Update;
+use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Response;
+use Longman\TelegramBot\Telegram;
+
+class Kernel
+{
+    /**
+     * The application implementation.
+     *
+     * @var \Longman\TelegramBot\Telegram
+     */
+    protected $app;
+
+    /**
+     * Create a new HTTP kernel instance.
+     *
+     * @param  \Longman\TelegramBot\Telegram $app
+     *
+     * @return void
+     */
+    public function __construct(Telegram $app)
+    {
+        $this->app = $app;
+    }
+
+    /**
+     * Handle an incoming HTTP request.
+     *
+     * @param  \Longman\TelegramBot\Http\Request $request
+     *
+     * @param null $limit
+     * @param null $timeout
+     * @return \Longman\TelegramBot\Http\Response
+     *
+     */
+    public function handle(Request $request, $limit = null, $timeout = null)
+    {
+        if (! DB::isDbConnected() && ! $this->app->getupdates_without_database) {
+            return new Response(
+                [
+                    'ok'          => false,
+                    'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
+                ],
+                $this->bot_username
+            );
+        }
+
+        $offset = 0;
+
+        //Take custom input into account.
+        if ($custom_input = $this->app->getCustomInput()) {
+            $response = new Response(json_decode($custom_input, true), $this->app->getBotUsername());
+        } else {
+            if (DB::isDbConnected()) {
+                //Get last update id from the database
+                $last_update = DB::selectTelegramUpdate(1);
+                $last_update = reset($last_update);
+
+                $this->app->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
+            }
+
+            if ($this->app->last_update_id !== null) {
+                $offset = $this->app->last_update_id + 1;    //As explained in the telegram bot API documentation
+            }
+
+            $response = Client::getUpdates(
+                [
+                    'offset'  => $offset,
+                    'limit'   => $limit,
+                    'timeout' => $timeout,
+                ]
+            );
+        }
+
+        if ($response->isOk()) {
+            $results = $response->getResult();
+
+            //Process all updates
+            /** @var Update $result */
+            foreach ($results as $result) {
+                $this->app->processUpdate($result);
+            }
+
+            if (! DB::isDbConnected() && ! $custom_input && $this->app->last_update_id !== null && $offset === 0) {
+                //Mark update(s) as read after handling
+                Client::getUpdates(
+                    [
+                        'offset'  => $this->app->last_update_id + 1,
+                        'limit'   => 1,
+                        'timeout' => $timeout,
+                    ]
+                );
+            }
+        }
+
+        return $response;
+    }
+}
diff --git a/src/Entities/Payments/PreCheckoutQuery.php b/src/Entities/Payments/PreCheckoutQuery.php
index d28c32022..dce13c925 100644
--- a/src/Entities/Payments/PreCheckoutQuery.php
+++ b/src/Entities/Payments/PreCheckoutQuery.php
@@ -48,7 +48,7 @@ public function subEntities()
      * @param bool $ok
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function answer($ok, array $data = [])
     {
diff --git a/src/Entities/Payments/ShippingQuery.php b/src/Entities/Payments/ShippingQuery.php
index 9948a7fd1..927a5763d 100644
--- a/src/Entities/Payments/ShippingQuery.php
+++ b/src/Entities/Payments/ShippingQuery.php
@@ -45,7 +45,7 @@ public function subEntities()
      * @param bool $ok
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function answer($ok, array $data = [])
     {
diff --git a/src/Http/Client.php b/src/Http/Client.php
index 2bad45a43..375672819 100644
--- a/src/Http/Client.php
+++ b/src/Http/Client.php
@@ -21,123 +21,123 @@
 /**
  * Class Client
  *
- * @method static ServerResponse getUpdates(array $data)              Use this method to receive incoming updates using long polling (wiki). An Array of Update
+ * @method static Response getUpdates(array $data)              Use this method to receive incoming updates using long polling (wiki). An Array of Update
  *     objects is returned.
- * @method static ServerResponse setWebhook(array $data)              Use this method to specify a url and receive incoming updates via an outgoing webhook.
+ * @method static Response setWebhook(array $data)              Use this method to specify a url and receive incoming updates via an outgoing webhook.
  *     Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url, containing a JSON-serialized Update. In case of an
  *     unsuccessful request, we will give up after a reasonable amount of attempts. Returns true.
- * @method static ServerResponse deleteWebhook()                      Use this method to remove webhook integration if you decide to switch back to getUpdates.
+ * @method static Response deleteWebhook()                      Use this method to remove webhook integration if you decide to switch back to getUpdates.
  *     Returns True on success. Requires no parameters.
- * @method static ServerResponse getWebhookInfo()                     Use this method to get current webhook status. Requires no parameters. On success,
+ * @method static Response getWebhookInfo()                     Use this method to get current webhook status. Requires no parameters. On success,
  *     returns a WebhookInfo object. If the bot is using getUpdates, will return an object with the url field empty.
- * @method static ServerResponse getMe()                              A simple method for testing your bot's auth token. Requires no parameters. Returns basic
+ * @method static Response getMe()                              A simple method for testing your bot's auth token. Requires no parameters. Returns basic
  *     information about the bot in form of a User object.
- * @method static ServerResponse forwardMessage(array $data)          Use this method to forward messages of any kind. On success, the sent Message is
+ * @method static Response forwardMessage(array $data)          Use this method to forward messages of any kind. On success, the sent Message is
  *     returned.
- * @method static ServerResponse sendPhoto(array $data)               Use this method to send photos. On success, the sent Message is returned.
- * @method static ServerResponse sendAudio(array $data)               Use this method to send audio files, if you want Telegram clients to display them in the
+ * @method static Response sendPhoto(array $data)               Use this method to send photos. On success, the sent Message is returned.
+ * @method static Response sendAudio(array $data)               Use this method to send audio files, if you want Telegram clients to display them in the
  *     music player. Your audio must be in the .mp3 format. On success, the sent Message is returned. Bots can currently send audio files of up to 50 MB in
  *     size, this limit may be changed in the future.
- * @method static ServerResponse sendDocument(array $data)            Use this method to send general files. On success, the sent Message is returned. Bots can
+ * @method static Response sendDocument(array $data)            Use this method to send general files. On success, the sent Message is returned. Bots can
  *     currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
- * @method static ServerResponse sendSticker(array $data)             Use this method to send .webp stickers. On success, the sent Message is returned.
- * @method static ServerResponse sendVideo(array $data)               Use this method to send video files, Telegram clients support mp4 videos (other formats
+ * @method static Response sendSticker(array $data)             Use this method to send .webp stickers. On success, the sent Message is returned.
+ * @method static Response sendVideo(array $data)               Use this method to send video files, Telegram clients support mp4 videos (other formats
  *     may be sent as Document). On success, the sent Message is returned. Bots can currently send video files of up to 50 MB in size, this limit may be
  *     changed in the future.
- * @method static ServerResponse sendVoice(array $data)               Use this method to send audio files, if you want Telegram clients to display the file as
+ * @method static Response sendVoice(array $data)               Use this method to send audio files, if you want Telegram clients to display the file as
  *     a playable voice message. For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as Audio or Document). On
  *     success, the sent Message is returned. Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
- * @method static ServerResponse sendVideoNote(array $data)           Use this method to send video messages. On success, the sent Message is returned.
- * @method static ServerResponse sendMediaGroup(array $data)          Use this method to send a group of photos or videos as an album. On success, an array of
+ * @method static Response sendVideoNote(array $data)           Use this method to send video messages. On success, the sent Message is returned.
+ * @method static Response sendMediaGroup(array $data)          Use this method to send a group of photos or videos as an album. On success, an array of
  *     the sent Messages is returned.
- * @method static ServerResponse sendLocation(array $data)            Use this method to send point on the map. On success, the sent Message is returned.
- * @method static ServerResponse editMessageLiveLocation(array $data) Use this method to edit live location messages sent by the bot or via the bot (for inline
+ * @method static Response sendLocation(array $data)            Use this method to send point on the map. On success, the sent Message is returned.
+ * @method static Response editMessageLiveLocation(array $data) Use this method to edit live location messages sent by the bot or via the bot (for inline
  *     bots). A location can be edited until its live_period expires or editing is explicitly disabled by a call to stopMessageLiveLocation. On success, if the
  *     edited message was sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse stopMessageLiveLocation(array $data) Use this method to stop updating a live location message sent by the bot or via the bot
+ * @method static Response stopMessageLiveLocation(array $data) Use this method to stop updating a live location message sent by the bot or via the bot
  *     (for inline bots) before live_period expires. On success, if the message was sent by the bot, the sent Message is returned, otherwise True is returned.
- * @method static ServerResponse sendVenue(array $data)               Use this method to send information about a venue. On success, the sent Message is
+ * @method static Response sendVenue(array $data)               Use this method to send information about a venue. On success, the sent Message is
  *     returned.
- * @method static ServerResponse sendContact(array $data)             Use this method to send phone contacts. On success, the sent Message is returned.
- * @method static ServerResponse sendChatAction(array $data)          Use this method when you need to tell the user that something is happening on the bot's
+ * @method static Response sendContact(array $data)             Use this method to send phone contacts. On success, the sent Message is returned.
+ * @method static Response sendChatAction(array $data)          Use this method when you need to tell the user that something is happening on the bot's
  *     side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). Returns True on success.
- * @method static ServerResponse getUserProfilePhotos(array $data)    Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos
+ * @method static Response getUserProfilePhotos(array $data)    Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos
  *     object.
- * @method static ServerResponse getFile(array $data)                 Use this method to get basic info about a file and prepare it for downloading. For the
+ * @method static Response getFile(array $data)                 Use this method to get basic info about a file and prepare it for downloading. For the
  *     moment, bots can download files of up to 20MB in size. On success, a File object is returned. The file can then be downloaded via the link
  *     https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> is taken from the response. It is guaranteed that the link will be valid for at
  *     least 1 hour. When the link expires, a new one can be requested by calling getFile again.
- * @method static ServerResponse kickChatMember(array $data)          Use this method to kick a user from a group, a supergroup or a channel. In the case of
+ * @method static Response kickChatMember(array $data)          Use this method to kick a user from a group, a supergroup or a channel. In the case of
  *     supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. The bot must be
  *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse unbanChatMember(array $data)         Use this method to unban a previously kicked user in a supergroup or channel. The user
+ * @method static Response unbanChatMember(array $data)         Use this method to unban a previously kicked user in a supergroup or channel. The user
  *     will not return to the group or channel automatically, but will be able to join via link, etc. The bot must be an administrator for this to work.
  *     Returns True on success.
- * @method static ServerResponse restrictChatMember(array $data)      Use this method to restrict a user in a supergroup. The bot must be an administrator in
+ * @method static Response restrictChatMember(array $data)      Use this method to restrict a user in a supergroup. The bot must be an administrator in
  *     the supergroup for this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift restrictions from a user.
  *     Returns True on success.
- * @method static ServerResponse promoteChatMember(array $data)       Use this method to promote or demote a user in a supergroup or a channel. The bot must be
+ * @method static Response promoteChatMember(array $data)       Use this method to promote or demote a user in a supergroup or a channel. The bot must be
  *     an administrator in the chat for this to work and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user.
  *     Returns True on success.
- * @method static ServerResponse exportChatInviteLink(array $data)    Use this method to export an invite link to a supergroup or a channel. The bot must be an
+ * @method static Response exportChatInviteLink(array $data)    Use this method to export an invite link to a supergroup or a channel. The bot must be an
  *     administrator in the chat for this to work and must have the appropriate admin rights. Returns exported invite link as String on success.
- * @method static ServerResponse setChatPhoto(array $data)            Use this method to set a new profile photo for the chat. Photos can't be changed for
+ * @method static Response setChatPhoto(array $data)            Use this method to set a new profile photo for the chat. Photos can't be changed for
  *     private chats. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse deleteChatPhoto(array $data)         Use this method to delete a chat photo. Photos can't be changed for private chats. The
+ * @method static Response deleteChatPhoto(array $data)         Use this method to delete a chat photo. Photos can't be changed for private chats. The
  *     bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse setChatTitle(array $data)            Use this method to change the title of a chat. Titles can't be changed for private chats.
+ * @method static Response setChatTitle(array $data)            Use this method to change the title of a chat. Titles can't be changed for private chats.
  *     The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse setChatDescription(array $data)      Use this method to change the description of a supergroup or a channel. The bot must be
+ * @method static Response setChatDescription(array $data)      Use this method to change the description of a supergroup or a channel. The bot must be
  *     an administrator in the chat for this to work and must have the appropriate admin rights. Returns True on success.
- * @method static ServerResponse pinChatMessage(array $data)          Use this method to pin a message in a supergroup or a channel. The bot must be an
+ * @method static Response pinChatMessage(array $data)          Use this method to pin a message in a supergroup or a channel. The bot must be an
  *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
  *     channel. Returns True on success.
- * @method static ServerResponse unpinChatMessage(array $data)        Use this method to unpin a message in a supergroup or a channel. The bot must be an
+ * @method static Response unpinChatMessage(array $data)        Use this method to unpin a message in a supergroup or a channel. The bot must be an
  *     administrator in the chat for this to work and must have the ‘can_pin_messages’ admin right in the supergroup or ‘can_edit_messages’ admin right in the
  *     channel. Returns True on success.
- * @method static ServerResponse leaveChat(array $data)               Use this method for your bot to leave a group, supergroup or channel. Returns True on
+ * @method static Response leaveChat(array $data)               Use this method for your bot to leave a group, supergroup or channel. Returns True on
  *     success.
- * @method static ServerResponse getChat(array $data)                 Use this method to get up to date information about the chat (current name of the user
+ * @method static Response getChat(array $data)                 Use this method to get up to date information about the chat (current name of the user
  *     for one-on-one conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
- * @method static ServerResponse getChatAdministrators(array $data)   Use this method to get a list of administrators in a chat. On success, returns an Array
+ * @method static Response getChatAdministrators(array $data)   Use this method to get a list of administrators in a chat. On success, returns an Array
  *     of ChatMember objects that contains information about all chat administrators except other bots. If the chat is a group or a supergroup and no
  *     administrators were appointed, only the creator will be returned.
- * @method static ServerResponse getChatMembersCount(array $data)     Use this method to get the number of members in a chat. Returns Int on success.
- * @method static ServerResponse getChatMember(array $data)           Use this method to get information about a member of a chat. Returns a ChatMember object
+ * @method static Response getChatMembersCount(array $data)     Use this method to get the number of members in a chat. Returns Int on success.
+ * @method static Response getChatMember(array $data)           Use this method to get information about a member of a chat. Returns a ChatMember object
  *     on success.
- * @method static ServerResponse setChatStickerSet(array $data)       Use this method to set a new group sticker set for a supergroup. The bot must be an
+ * @method static Response setChatStickerSet(array $data)       Use this method to set a new group sticker set for a supergroup. The bot must be an
  *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
  *     requests to check if the bot can use this method. Returns True on success.
- * @method static ServerResponse deleteChatStickerSet(array $data)    Use this method to delete a group sticker set from a supergroup. The bot must be an
+ * @method static Response deleteChatStickerSet(array $data)    Use this method to delete a group sticker set from a supergroup. The bot must be an
  *     administrator in the chat for this to work and must have the appropriate admin rights. Use the field can_set_sticker_set optionally returned in getChat
  *     requests to check if the bot can use this method. Returns True on success.
- * @method static ServerResponse answerCallbackQuery(array $data)     Use this method to send answers to callback queries sent from inline keyboards. The
+ * @method static Response answerCallbackQuery(array $data)     Use this method to send answers to callback queries sent from inline keyboards. The
  *     answer will be displayed to the user as a notification at the top of the chat screen or as an alert. On success, True is returned.
- * @method static ServerResponse answerInlineQuery(array $data)       Use this method to send answers to an inline query. On success, True is returned.
- * @method static ServerResponse editMessageText(array $data)         Use this method to edit text and game messages sent by the bot or via the bot (for inline
+ * @method static Response answerInlineQuery(array $data)       Use this method to send answers to an inline query. On success, True is returned.
+ * @method static Response editMessageText(array $data)         Use this method to edit text and game messages sent by the bot or via the bot (for inline
  *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse editMessageCaption(array $data)      Use this method to edit captions of messages sent by the bot or via the bot (for inline
+ * @method static Response editMessageCaption(array $data)      Use this method to edit captions of messages sent by the bot or via the bot (for inline
  *     bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse editMessageReplyMarkup(array $data)  Use this method to edit only the reply markup of messages sent by the bot or via the bot
+ * @method static Response editMessageReplyMarkup(array $data)  Use this method to edit only the reply markup of messages sent by the bot or via the bot
  *     (for inline bots). On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
- * @method static ServerResponse deleteMessage(array $data)           Use this method to delete a message, including service messages, with certain
+ * @method static Response deleteMessage(array $data)           Use this method to delete a message, including service messages, with certain
  *     limitations. Returns True on success.
- * @method static ServerResponse getStickerSet(array $data)           Use this method to get a sticker set. On success, a StickerSet object is returned.
- * @method static ServerResponse uploadStickerFile(array $data)       Use this method to upload a .png file with a sticker for later use in createNewStickerSet
+ * @method static Response getStickerSet(array $data)           Use this method to get a sticker set. On success, a StickerSet object is returned.
+ * @method static Response uploadStickerFile(array $data)       Use this method to upload a .png file with a sticker for later use in createNewStickerSet
  *     and addStickerToSet methods (can be used multiple times). Returns the uploaded File on success.
- * @method static ServerResponse createNewStickerSet(array $data)     Use this method to create new sticker set owned by a user. The bot will be able to edit
+ * @method static Response createNewStickerSet(array $data)     Use this method to create new sticker set owned by a user. The bot will be able to edit
  *     the created sticker set. Returns True on success.
- * @method static ServerResponse addStickerToSet(array $data)         Use this method to add a new sticker to a set created by the bot. Returns True on
+ * @method static Response addStickerToSet(array $data)         Use this method to add a new sticker to a set created by the bot. Returns True on
  *     success.
- * @method static ServerResponse setStickerPositionInSet(array $data) Use this method to move a sticker in a set created by the bot to a specific position.
+ * @method static Response setStickerPositionInSet(array $data) Use this method to move a sticker in a set created by the bot to a specific position.
  *     Returns True on success.
- * @method static ServerResponse deleteStickerFromSet(array $data)    Use this method to delete a sticker from a set created by the bot. Returns True on
+ * @method static Response deleteStickerFromSet(array $data)    Use this method to delete a sticker from a set created by the bot. Returns True on
  *     success.
- * @method static ServerResponse sendInvoice(array $data)             Use this method to send invoices. On success, the sent Message is returned.
- * @method static ServerResponse answerShippingQuery(array $data)     If you sent an invoice requesting a shipping address and the parameter is_flexible was
+ * @method static Response sendInvoice(array $data)             Use this method to send invoices. On success, the sent Message is returned.
+ * @method static Response answerShippingQuery(array $data)     If you sent an invoice requesting a shipping address and the parameter is_flexible was
  *     specified, the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is
  *     returned.
- * @method static ServerResponse answerPreCheckoutQuery(array $data)  Once the user has confirmed their payment and shipping details, the Bot API sends the
+ * @method static Response answerPreCheckoutQuery(array $data)  Once the user has confirmed their payment and shipping details, the Bot API sends the
  *     final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True
  *     is returned.
  */
@@ -503,7 +503,7 @@ public static function encodeFile($file)
      * @param string $action
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function send($action, array $data = [])
@@ -516,7 +516,7 @@ public static function send($action, array $data = [])
         if (defined('PHPUNIT_TESTSUITE')) {
             $fake_response = self::generateGeneralFakeServerResponse($data);
 
-            return new ServerResponse($fake_response, $bot_username);
+            return new Response($fake_response, $bot_username);
         }
 
         self::ensureNonEmptyData($data);
@@ -529,7 +529,7 @@ public static function send($action, array $data = [])
             throw new TelegramException('Telegram returned an invalid response! Please review your bot name and API key.');
         }
 
-        return new ServerResponse($response, $bot_username);
+        return new Response($response, $bot_username);
     }
 
     /**
@@ -588,7 +588,7 @@ private static function ensureValidAction($action)
      *
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function sendMessage(array $data)
@@ -613,7 +613,7 @@ public static function sendMessage(array $data)
      * @param string $action
      * @param array $data
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function __callStatic($action, array $data)
@@ -631,12 +631,12 @@ public static function __callStatic($action, array $data)
      * No request to telegram are sent, this function is used in commands that
      * don't need to fire a message after execution
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public static function emptyResponse()
     {
-        return new ServerResponse(['ok' => true, 'result' => true], null);
+        return new Response(['ok' => true, 'result' => true], null);
     }
 
     /**
diff --git a/src/Http/Kernel.php b/src/Http/Kernel.php
index 304852db8..841de5df2 100644
--- a/src/Http/Kernel.php
+++ b/src/Http/Kernel.php
@@ -37,9 +37,9 @@ public function __construct(Telegram $app)
     /**
      * Handle an incoming HTTP request.
      *
-     * @param  \Longman\TelegramBot\Request2 $request
+     * @param  \Longman\TelegramBot\Http\Request $request
      *
-     * @return \Longman\TelegramBot\Response
+     * @return \Longman\TelegramBot\Http\Response
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
diff --git a/src/Http/ServerResponse.php b/src/Http/Response.php
similarity index 99%
rename from src/Http/ServerResponse.php
rename to src/Http/Response.php
index 2202a785b..0b14c6297 100644
--- a/src/Http/ServerResponse.php
+++ b/src/Http/Response.php
@@ -24,7 +24,7 @@
  *
  * @todo method ResponseParameters getParameters()  Field which can help to automatically handle the error
  */
-class ServerResponse
+class Response
 {
     /**
      * ServerResponse constructor.
diff --git a/src/Telegram.php b/src/Telegram.php
index c243c0f42..ace48dabd 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -16,12 +16,12 @@
 use Exception;
 use Illuminate\Container\Container;
 use Longman\TelegramBot\Commands\Command;
+use Longman\TelegramBot\Console\Kernel as ConsoleKernel;
 use Longman\TelegramBot\Entities\Update;
 use Longman\TelegramBot\Exception\TelegramException;
-use Longman\TelegramBot\Http\Kernel;
 use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Kernel;
 use Longman\TelegramBot\Http\Request;
-use Longman\TelegramBot\Http\ServerResponse;
 use PDO;
 use RecursiveDirectoryIterator;
 use RecursiveIteratorIterator;
@@ -130,7 +130,7 @@ class Telegram extends Container
     /**
      * ServerResponse of the last Command execution
      *
-     * @var \Longman\TelegramBot\Http\ServerResponse
+     * @var \Longman\TelegramBot\Http\Response
      */
     protected $last_command_response;
 
@@ -153,7 +153,7 @@ class Telegram extends Container
      *
      * @var bool
      */
-    protected $getupdates_without_database = false;
+    public $getupdates_without_database = false;
 
     /**
      * Last update ID
@@ -161,7 +161,7 @@ class Telegram extends Container
      *
      * @var integer
      */
-    protected $last_update_id = null;
+    public $last_update_id = null;
 
     /**
      * Telegram constructor.
@@ -340,7 +340,7 @@ public function getCustomInput()
     /**
      * Get the ServerResponse of the last Command execution
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      */
     public function getLastCommandResponse()
     {
@@ -353,7 +353,7 @@ public function getLastCommandResponse()
      * @param int|null $limit
      * @param int|null $timeout
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function handleGetUpdates($limit = null, $timeout = null)
@@ -362,63 +362,10 @@ public function handleGetUpdates($limit = null, $timeout = null)
             throw new TelegramException('Bot Username is not defined!');
         }
 
-        if (! DB::isDbConnected() && ! $this->getupdates_without_database) {
-            return new ServerResponse(
-                [
-                    'ok'          => false,
-                    'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
-                ],
-                $this->bot_username
-            );
-        }
-
-        $offset = 0;
-
-        //Take custom input into account.
-        if ($custom_input = $this->getCustomInput()) {
-            $response = new ServerResponse(json_decode($custom_input, true), $this->bot_username);
-        } else {
-            if (DB::isDbConnected()) {
-                //Get last update id from the database
-                $last_update = DB::selectTelegramUpdate(1);
-                $last_update = reset($last_update);
-
-                $this->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
-            }
-
-            if ($this->last_update_id !== null) {
-                $offset = $this->last_update_id + 1;    //As explained in the telegram bot API documentation
-            }
+        /** @var \Longman\TelegramBot\Console\Kernel $kernel */
+        $kernel = $this->make(ConsoleKernel::class);
 
-            $response = Client::getUpdates(
-                [
-                    'offset'  => $offset,
-                    'limit'   => $limit,
-                    'timeout' => $timeout,
-                ]
-            );
-        }
-
-        if ($response->isOk()) {
-            $results = $response->getResult();
-
-            //Process all updates
-            /** @var Update $result */
-            foreach ($results as $result) {
-                $this->processUpdate($result);
-            }
-
-            if (! DB::isDbConnected() && ! $custom_input && $this->last_update_id !== null && $offset === 0) {
-                //Mark update(s) as read after handling
-                Client::getUpdates(
-                    [
-                        'offset'  => $this->last_update_id + 1,
-                        'limit'   => 1,
-                        'timeout' => $timeout,
-                    ]
-                );
-            }
-        }
+        $response = $kernel->handle(Request::capture(), $limit, $timeout);
 
         return $response;
     }
@@ -461,7 +408,7 @@ protected function getCommandFromType($type)
      *
      * @param \Longman\TelegramBot\Entities\Update $update
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function processUpdate(Update $update)
@@ -833,7 +780,7 @@ public function getBotId()
      */
     public function getVersion()
     {
-        return $this->version;
+        return self::VERSION;
     }
 
     /**
@@ -842,7 +789,7 @@ public function getVersion()
      * @param string $url
      * @param array $data Optional parameters.
      *
-     * @return \Longman\TelegramBot\Http\ServerResponse
+     * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function setWebhook($url, array $data = [])
diff --git a/tests/unit/Entities/ServerResponseTest.php b/tests/unit/Entities/ServerResponseTest.php
index 537edde51..56bf0f4e7 100644
--- a/tests/unit/Entities/ServerResponseTest.php
+++ b/tests/unit/Entities/ServerResponseTest.php
@@ -13,7 +13,7 @@
 namespace Longman\TelegramBot\Tests\Unit;
 
 use Longman\TelegramBot\Entities\Message;
-use Longman\TelegramBot\Http\ServerResponse;
+use Longman\TelegramBot\Http\Response;
 use Longman\TelegramBot\Http\Client;
 
 /**
@@ -42,7 +42,7 @@ public function sendMessageOk()
     public function testSendMessageOk()
     {
         $result = $this->sendMessageOk();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
         $server_result = $server->getResult();
 
         self::assertTrue($server->isOk());
@@ -76,7 +76,7 @@ public function sendMessageFail()
     public function testSendMessageFail()
     {
         $result = $this->sendMessageFail();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertFalse($server->isOk());
         self::assertNull($server->getResult());
@@ -92,7 +92,7 @@ public function setWebhookOk()
     public function testSetWebhookOk()
     {
         $result = $this->setWebhookOk();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertTrue($server->isOk());
         self::assertTrue($server->getResult());
@@ -112,7 +112,7 @@ public function setWebhookFail()
     public function testSetWebhookFail()
     {
         $result = $this->setWebhookFail();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertFalse($server->isOk());
         self::assertNull($server->getResult());
@@ -172,7 +172,7 @@ public function getUpdatesArray()
     public function testGetUpdatesArray()
     {
         $result = $this->getUpdatesArray();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertCount(4, $server->getResult());
         self::assertInstanceOf('\Longman\TelegramBot\Entities\Update', $server->getResult()[0]);
@@ -186,7 +186,7 @@ public function getUpdatesEmpty()
     public function testGetUpdatesEmpty()
     {
         $result = $this->getUpdatesEmpty();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertEmpty($server->getResult());
     }
@@ -221,7 +221,7 @@ public function getUserProfilePhotos()
     public function testGetUserProfilePhotos()
     {
         $result = $this->getUserProfilePhotos();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
         $server_result = $server->getResult();
 
         $photos = $server_result->getPhotos();
@@ -251,7 +251,7 @@ public function getFile()
     public function testGetFile()
     {
         $result = $this->getFile();
-        $server = new ServerResponse(json_decode($result, true), 'testbot');
+        $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertInstanceOf('\Longman\TelegramBot\Entities\File', $server->getResult());
     }
@@ -261,7 +261,7 @@ public function testSetGeneralTestFakeResponse()
         //setWebhook ok
         $fake_response = Client::generateGeneralFakeServerResponse();
 
-        $server = new ServerResponse($fake_response, 'testbot');
+        $server = new Response($fake_response, 'testbot');
 
         self::assertTrue($server->isOk());
         self::assertTrue($server->getResult());
@@ -271,7 +271,7 @@ public function testSetGeneralTestFakeResponse()
         //sendMessage ok
         $fake_response = Client::generateGeneralFakeServerResponse(['chat_id' => 123456789, 'text' => 'hello']);
 
-        $server = new ServerResponse($fake_response, 'testbot');
+        $server = new Response($fake_response, 'testbot');
 
         /** @var Message $server_result */
         $server_result = $server->getResult();

From be3f6059f3b68fffe15148c128c790a77671cd44 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 18:46:05 +0400
Subject: [PATCH 16/40] Update kernel class

---
 src/Console/Kernel.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/Console/Kernel.php b/src/Console/Kernel.php
index c94c56830..0baeff155 100644
--- a/src/Console/Kernel.php
+++ b/src/Console/Kernel.php
@@ -47,6 +47,7 @@ public function __construct(Telegram $app)
      * @param null $timeout
      * @return \Longman\TelegramBot\Http\Response
      *
+     * @throws \Longman\TelegramBot\Exception\TelegramException
      */
     public function handle(Request $request, $limit = null, $timeout = null)
     {

From cb8e07db3cb84eabad77f3862e86c4cdb3a70dcb Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 19:00:01 +0400
Subject: [PATCH 17/40] Remove empty response method from client

---
 src/Commands/Command.php                         |  7 ++++---
 src/Commands/SystemCommand.php                   |  3 ++-
 .../SystemCommands/GenericmessageCommand.php     |  5 +++--
 src/Console/Kernel.php                           | 13 ++++++-------
 src/Http/Client.php                              | 14 --------------
 src/Http/Response.php                            | 16 +++++++++++++++-
 src/Telegram.php                                 |  3 ++-
 .../CustomTestCommands/HiddenCommand.php         |  3 ++-
 .../CustomTestCommands/VisibleCommand.php        |  3 ++-
 9 files changed, 36 insertions(+), 31 deletions(-)

diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index 45f4809a9..2e4d32d59 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -17,6 +17,7 @@
 use Longman\TelegramBot\Entities\Message;
 use Longman\TelegramBot\Entities\Update;
 use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Response;
 use Longman\TelegramBot\Telegram;
 
 /**
@@ -167,7 +168,7 @@ public function preExecute()
                 ]);
             }
 
-            return Client::emptyResponse();
+            return new Response(['ok' => true, 'result' => true]);
         }
 
         return $this->execute();
@@ -404,7 +405,7 @@ public function replyToChat($text, array $data = [])
             ], $data));
         }
 
-        return Client::emptyResponse();
+        return new Response(['ok' => true, 'result' => true]);
     }
 
     /**
@@ -424,6 +425,6 @@ public function replyToUser($text, array $data = [])
             ], $data));
         }
 
-        return Client::emptyResponse();
+        return new Response(['ok' => true, 'result' => true]);
     }
 }
diff --git a/src/Commands/SystemCommand.php b/src/Commands/SystemCommand.php
index fdeae34bd..9d9774470 100644
--- a/src/Commands/SystemCommand.php
+++ b/src/Commands/SystemCommand.php
@@ -11,6 +11,7 @@
 namespace Longman\TelegramBot\Commands;
 
 use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Response;
 
 abstract class SystemCommand extends Command
 {
@@ -25,6 +26,6 @@ abstract class SystemCommand extends Command
     public function execute()
     {
         //System command, return empty ServerResponse by default
-        return Client::emptyResponse();
+        return new Response(['ok' => true, 'result' => true]);
     }
 }
diff --git a/src/Commands/SystemCommands/GenericmessageCommand.php b/src/Commands/SystemCommands/GenericmessageCommand.php
index 49e083b49..885cac1f1 100644
--- a/src/Commands/SystemCommands/GenericmessageCommand.php
+++ b/src/Commands/SystemCommands/GenericmessageCommand.php
@@ -13,6 +13,7 @@
 use Longman\TelegramBot\Commands\SystemCommand;
 use Longman\TelegramBot\Conversation;
 use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Response;
 
 /**
  * Generic message command
@@ -47,7 +48,7 @@ class GenericmessageCommand extends SystemCommand
     public function executeNoDb()
     {
         //Do nothing
-        return Client::emptyResponse();
+        return new Response(['ok' => true, 'result' => true]);
     }
 
     /**
@@ -69,6 +70,6 @@ public function execute()
             return $this->telegram->executeCommand($command);
         }
 
-        return Client::emptyResponse();
+        return new Response(['ok' => true, 'result' => true]);
     }
 }
diff --git a/src/Console/Kernel.php b/src/Console/Kernel.php
index 0baeff155..caa1966ae 100644
--- a/src/Console/Kernel.php
+++ b/src/Console/Kernel.php
@@ -11,7 +11,6 @@
 namespace Longman\TelegramBot\Console;
 
 use Longman\TelegramBot\DB;
-use Longman\TelegramBot\Entities\Update;
 use Longman\TelegramBot\Http\Client;
 use Longman\TelegramBot\Http\Request;
 use Longman\TelegramBot\Http\Response;
@@ -57,18 +56,18 @@ public function handle(Request $request, $limit = null, $timeout = null)
                     'ok'          => false,
                     'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
                 ],
-                $this->bot_username
+                $this->app->getBotUsername()
             );
         }
 
         $offset = 0;
 
-        //Take custom input into account.
+        // Take custom input into account.
         if ($custom_input = $this->app->getCustomInput()) {
             $response = new Response(json_decode($custom_input, true), $this->app->getBotUsername());
         } else {
             if (DB::isDbConnected()) {
-                //Get last update id from the database
+                // Get last update id from the database
                 $last_update = DB::selectTelegramUpdate(1);
                 $last_update = reset($last_update);
 
@@ -91,14 +90,14 @@ public function handle(Request $request, $limit = null, $timeout = null)
         if ($response->isOk()) {
             $results = $response->getResult();
 
-            //Process all updates
-            /** @var Update $result */
+            // Process all updates
+            /** @var \Longman\TelegramBot\Entities\Update $result */
             foreach ($results as $result) {
                 $this->app->processUpdate($result);
             }
 
             if (! DB::isDbConnected() && ! $custom_input && $this->app->last_update_id !== null && $offset === 0) {
-                //Mark update(s) as read after handling
+                // Mark update(s) as read after handling
                 Client::getUpdates(
                     [
                         'offset'  => $this->app->last_update_id + 1,
diff --git a/src/Http/Client.php b/src/Http/Client.php
index 375672819..4db9e9abd 100644
--- a/src/Http/Client.php
+++ b/src/Http/Client.php
@@ -625,20 +625,6 @@ public static function __callStatic($action, array $data)
         return call_user_func_array('static::send', $data);
     }
 
-    /**
-     * Return an empty Server Response
-     *
-     * No request to telegram are sent, this function is used in commands that
-     * don't need to fire a message after execution
-     *
-     * @return \Longman\TelegramBot\Http\Response
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function emptyResponse()
-    {
-        return new Response(['ok' => true, 'result' => true], null);
-    }
-
     /**
      * Send message to all active chats
      *
diff --git a/src/Http/Response.php b/src/Http/Response.php
index 0b14c6297..e9574eae0 100644
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -34,7 +34,7 @@ class Response
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
-    public function __construct(array $data, $bot_username)
+    public function __construct(array $data, $bot_username = '')
     {
         // Make sure we don't double-save the raw_data
         unset($data['raw_data']);
@@ -227,4 +227,18 @@ private function createResultObjects($result, $bot_username)
 
         return $results;
     }
+
+    /**
+     * Return an empty Server Response
+     *
+     * No request to telegram are sent, this function is used in commands that
+     * don't need to fire a message after execution
+     *
+     * @return \Longman\TelegramBot\Http\Response
+     * @throws \Longman\TelegramBot\Exception\TelegramException
+     */
+    public static function createEmpty()
+    {
+        return new static(['ok' => true, 'result' => true]);
+    }
 }
diff --git a/src/Telegram.php b/src/Telegram.php
index ace48dabd..77bdcbfa2 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -22,6 +22,7 @@
 use Longman\TelegramBot\Http\Client;
 use Longman\TelegramBot\Http\Kernel;
 use Longman\TelegramBot\Http\Request;
+use Longman\TelegramBot\Http\Response;
 use PDO;
 use RecursiveDirectoryIterator;
 use RecursiveIteratorIterator;
@@ -462,7 +463,7 @@ public function processUpdate(Update $update)
         if ($last_id && count($last_id) === 1) {
             TelegramLog::debug('Duplicate update received, processing aborted!');
 
-            return Client::emptyResponse();
+            return new Response(['ok' => true, 'result' => true]);
         }
 
         DB::insertRequest($this->update);
diff --git a/tests/unit/Commands/CustomTestCommands/HiddenCommand.php b/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
index 1b9a8b2de..c8c0489d1 100644
--- a/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
+++ b/tests/unit/Commands/CustomTestCommands/HiddenCommand.php
@@ -12,6 +12,7 @@
 
 use Longman\TelegramBot\Commands\UserCommand;
 use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Response;
 
 /**
  * Test "/hidden" command to test $show_in_help
@@ -51,6 +52,6 @@ class HiddenCommand extends UserCommand
      */
     public function execute()
     {
-        return Client::emptyResponse();
+        return new Response(['ok' => true, 'result' => true]);
     }
 }
diff --git a/tests/unit/Commands/CustomTestCommands/VisibleCommand.php b/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
index 870dd23b9..ad009f6a7 100644
--- a/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
+++ b/tests/unit/Commands/CustomTestCommands/VisibleCommand.php
@@ -12,6 +12,7 @@
 
 use Longman\TelegramBot\Commands\UserCommand;
 use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Response;
 
 /**
  * Test "/visible" command to test $show_in_help
@@ -51,6 +52,6 @@ class VisibleCommand extends UserCommand
      */
     public function execute()
     {
-        return Client::emptyResponse();
+        return new Response(['ok' => true, 'result' => true]);
     }
 }

From c863f7012774a74b2b7e105c983c4fbd91e123ff Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 19:11:36 +0400
Subject: [PATCH 18/40] Fix style

---
 src/Telegram.php | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/Telegram.php b/src/Telegram.php
index 77bdcbfa2..71b5bb5d9 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -417,14 +417,14 @@ public function processUpdate(Update $update)
         $this->update = $update;
         $this->last_update_id = $update->getUpdateId();
 
-        //If all else fails, it's a generic message.
+        // If all else fails, it's a generic message.
         $command = 'genericmessage';
 
         $update_type = $this->update->getUpdateType();
         if ($update_type === 'message') {
             $message = $this->update->getMessage();
 
-            //Load admin commands
+            // Load admin commands
             if ($this->isAdmin()) {
                 $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/AdminCommands', false);
             }
@@ -454,11 +454,11 @@ public function processUpdate(Update $update)
             $command = $this->getCommandFromType($update_type);
         }
 
-        //Make sure we have an up-to-date command list
-        //This is necessary to "require" all the necessary command files!
+        // Make sure we have an up-to-date command list
+        // This is necessary to "require" all the necessary command files!
         $this->getCommandsList();
 
-        //Make sure we don't try to process update that was already processed
+        // Make sure we don't try to process update that was already processed
         $last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
         if ($last_id && count($last_id) === 1) {
             TelegramLog::debug('Duplicate update received, processing aborted!');
@@ -485,24 +485,24 @@ public function executeCommand($command)
         $command_obj = $this->getCommandObject($command);
 
         if (! $command_obj || ! $command_obj->isEnabled()) {
-            //Failsafe in case the Generic command can't be found
+            // Failsafe in case the Generic command can't be found
             if ($command === 'generic') {
                 throw new TelegramException('Generic command missing!');
             }
 
-            //Handle a generic command or non existing one
+            // Handle a generic command or non existing one
             $this->last_command_response = $this->executeCommand('generic');
         } else {
-            //Botan.io integration, make sure only the actual command user executed is reported
+            // Botan.io integration, make sure only the actual command user executed is reported
             if ($this->botan_enabled) {
                 Botan::lock($command);
             }
 
-            //execute() method is executed after preExecute()
-            //This is to prevent executing a DB query without a valid connection
+            // execute() method is executed after preExecute()
+            // This is to prevent executing a DB query without a valid connection
             $this->last_command_response = $command_obj->preExecute();
 
-            //Botan.io integration, send report after executing the command
+            // Botan.io integration, send report after executing the command
             if ($this->botan_enabled) {
                 Botan::track($this->update, $command);
             }

From 1d4ae42cf5386d327d0a73cb9519bd5c19cb5acc Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 20:19:34 +0400
Subject: [PATCH 19/40] Change method of initializing container

---
 src/Http/Kernel.php         |  6 +-----
 src/Telegram.php            | 28 ++++++++++++++++++----------
 tests/unit/TelegramTest.php |  2 +-
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/src/Http/Kernel.php b/src/Http/Kernel.php
index 841de5df2..3e57579d1 100644
--- a/src/Http/Kernel.php
+++ b/src/Http/Kernel.php
@@ -49,10 +49,6 @@ public function handle(Request $request)
 
         $update = new Update($params->all(), $this->app->getBotUsername());
 
-        if ($response = $this->app->processUpdate($update)) {
-            return $response->isOk();
-        }
-
-        return $response;
+        return $this->app->processUpdate($update);
     }
 }
diff --git a/src/Telegram.php b/src/Telegram.php
index 71b5bb5d9..68ec45a3d 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -28,7 +28,7 @@
 use RecursiveIteratorIterator;
 use RegexIterator;
 
-class Telegram extends Container
+class Telegram
 {
     /**
      * Version
@@ -188,7 +188,7 @@ public function __construct($api_key, $bot_username = '')
             $this->bot_username = $bot_username;
         }
 
-        $this->registerBaseBindings();
+        $this->registerContainer();
 
         //Add default system commands path
         $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
@@ -197,17 +197,25 @@ public function __construct($api_key, $bot_username = '')
     }
 
     /**
-     * Register the basic bindings into the container.
+     * Register the container.
      *
      * @return void
      */
-    protected function registerBaseBindings()
+    protected function registerContainer()
     {
-        static::setInstance($this);
+        $this->container = Container::getInstance();
 
-        $this->instance('app', $this);
+        $this->container->instance(Telegram::class, $this);
+    }
 
-        $this->instance(Telegram::class, $this);
+    /**
+     * Get container instance.
+     *
+     * @return \Illuminate\Container\Container
+     */
+    public function getContainer()
+    {
+        return $this->container;
     }
 
     /**
@@ -364,7 +372,7 @@ public function handleGetUpdates($limit = null, $timeout = null)
         }
 
         /** @var \Longman\TelegramBot\Console\Kernel $kernel */
-        $kernel = $this->make(ConsoleKernel::class);
+        $kernel = $this->getContainer()->make(ConsoleKernel::class);
 
         $response = $kernel->handle(Request::capture(), $limit, $timeout);
 
@@ -374,7 +382,7 @@ public function handleGetUpdates($limit = null, $timeout = null)
     /**
      * Handle bot request from webhook
      *
-     * @return bool
+     * @return \Longman\TelegramBot\Http\Response
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
@@ -385,7 +393,7 @@ public function handle()
         }
 
         /** @var \Longman\TelegramBot\Http\Kernel $kernel */
-        $kernel = $this->make(Kernel::class);
+        $kernel = $this->getContainer()->make(Kernel::class);
 
         $response = $kernel->handle(Request::capture());
 
diff --git a/tests/unit/TelegramTest.php b/tests/unit/TelegramTest.php
index e45c63195..074c65071 100644
--- a/tests/unit/TelegramTest.php
+++ b/tests/unit/TelegramTest.php
@@ -149,7 +149,7 @@ public function testContainer()
     {
         $telegram = new Telegram(self::$dummy_api_key, 'testbot');
 
-        $this->assertInstanceOf(\Illuminate\Container\Container::class, $telegram);
+        $this->assertInstanceOf(\Illuminate\Container\Container::class, $telegram->getContainer());
     }
 
     public function testCustom()

From d568753beb0ed340c2ae7c558806656dbc417799 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 20:26:18 +0400
Subject: [PATCH 20/40] Remove git keep

---
 build/.gitkeep | 0
 composer.json  | 3 +++
 2 files changed, 3 insertions(+)
 delete mode 100644 build/.gitkeep

diff --git a/build/.gitkeep b/build/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/composer.json b/composer.json
index 2236dab8d..195137f76 100644
--- a/composer.json
+++ b/composer.json
@@ -61,6 +61,9 @@
         "test-cov": [
             "\"vendor/bin/phpunit\" --coverage-clover build/logs/clover.xml"
         ],
+        "test-cov-html": [
+            "\"vendor/bin/phpunit\" --coverage-html build/html"
+        ],
         "test-cov-upload": [
             "wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml"
         ]

From 1fe2c5db0dff32b65183938b8d69eef88d6fe585 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 20:26:33 +0400
Subject: [PATCH 21/40] Add gitignore file

---
 build/.gitignore | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 build/.gitignore

diff --git a/build/.gitignore b/build/.gitignore
new file mode 100644
index 000000000..d6b7ef32c
--- /dev/null
+++ b/build/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore

From 166b883c6b391c212ed93e688f1085b2615240c5 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 21:06:14 +0400
Subject: [PATCH 22/40] Add more tests

---
 src/Http/Response.php       | 14 --------------
 tests/unit/TelegramTest.php | 18 ++++++++++++++++++
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/src/Http/Response.php b/src/Http/Response.php
index e9574eae0..020a34074 100644
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -227,18 +227,4 @@ private function createResultObjects($result, $bot_username)
 
         return $results;
     }
-
-    /**
-     * Return an empty Server Response
-     *
-     * No request to telegram are sent, this function is used in commands that
-     * don't need to fire a message after execution
-     *
-     * @return \Longman\TelegramBot\Http\Response
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function createEmpty()
-    {
-        return new static(['ok' => true, 'result' => true]);
-    }
 }
diff --git a/tests/unit/TelegramTest.php b/tests/unit/TelegramTest.php
index 074c65071..2c8326f36 100644
--- a/tests/unit/TelegramTest.php
+++ b/tests/unit/TelegramTest.php
@@ -152,6 +152,24 @@ public function testContainer()
         $this->assertInstanceOf(\Illuminate\Container\Container::class, $telegram->getContainer());
     }
 
+    public function testHandleResponse()
+    {
+        $telegram = new Telegram(self::$dummy_api_key, 'testbot');
+
+        $response = $telegram->handle();
+
+        $this->assertInstanceOf(\Longman\TelegramBot\Http\Response::class, $response);
+    }
+
+    public function testHandleUpdatedResponse()
+    {
+        $telegram = new Telegram(self::$dummy_api_key, 'testbot');
+
+        $response = $telegram->handleGetUpdates();
+
+        $this->assertInstanceOf(\Longman\TelegramBot\Http\Response::class, $response);
+    }
+
     public function testCustom()
     {
         $telegram = new Telegram(self::$dummy_api_key, 'testbot');

From aadb9cc2c7ca96277cfed42fa56754678725db86 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sat, 21 Apr 2018 21:13:28 +0400
Subject: [PATCH 23/40] Fix failing test

---
 src/Http/Response.php                      | 4 ++--
 tests/unit/Entities/ServerResponseTest.php | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/Http/Response.php b/src/Http/Response.php
index 020a34074..400c9a528 100644
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -114,11 +114,11 @@ public function getOk()
     /**
      * Return result
      *
-     * @return mixed
+     * @return array
      */
     public function getResult()
     {
-        return isset($this->result) ? $this->result : null;
+        return isset($this->result) ? $this->result : [];
     }
 
     /**
diff --git a/tests/unit/Entities/ServerResponseTest.php b/tests/unit/Entities/ServerResponseTest.php
index 56bf0f4e7..155f21d7f 100644
--- a/tests/unit/Entities/ServerResponseTest.php
+++ b/tests/unit/Entities/ServerResponseTest.php
@@ -79,7 +79,7 @@ public function testSendMessageFail()
         $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertFalse($server->isOk());
-        self::assertNull($server->getResult());
+        self::assertEquals([], $server->getResult());
         self::assertEquals('400', $server->getErrorCode());
         self::assertEquals('Error: Bad Request: wrong chat id', $server->getDescription());
     }
@@ -115,7 +115,7 @@ public function testSetWebhookFail()
         $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertFalse($server->isOk());
-        self::assertNull($server->getResult());
+        self::assertEquals([], $server->getResult());
         self::assertEquals(400, $server->getErrorCode());
         self::assertEquals('Error: Bad request: htttps://domain.host.org/dir/hook.php', $server->getDescription());
     }

From 2cf497c9e5f4e26d3686f5dd7afcc3e0ecbe40e4 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:05:52 +0400
Subject: [PATCH 24/40] Add interface for commands

---
 src/Commands/CommandContract.php | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 src/Commands/CommandContract.php

diff --git a/src/Commands/CommandContract.php b/src/Commands/CommandContract.php
new file mode 100644
index 000000000..2b28679c2
--- /dev/null
+++ b/src/Commands/CommandContract.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * This file is part of the TelegramBot package.
+ *
+ * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Longman\TelegramBot\Commands;
+
+/**
+ * Command contract class
+ *
+ * Interface for commands
+ */
+interface CommandContract
+{
+
+}

From a9679668e1ccfdc634a3311f5752e7076e3fb5c9 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:06:15 +0400
Subject: [PATCH 25/40] Remove custom input

---
 src/Http/Client.php | 48 ++++++++-------------------------------------
 1 file changed, 8 insertions(+), 40 deletions(-)

diff --git a/src/Http/Client.php b/src/Http/Client.php
index 4db9e9abd..83193c5fe 100644
--- a/src/Http/Client.php
+++ b/src/Http/Client.php
@@ -164,13 +164,6 @@ class Client
      */
     private static $client;
 
-    /**
-     * Input value of the request
-     *
-     * @var string
-     */
-    private static $input;
-
     /**
      * Request limiter
      *
@@ -299,31 +292,6 @@ public static function setClient(GuzzleClient $client)
         self::$client = $client;
     }
 
-    /**
-     * Set input from custom input or stdin and return it
-     *
-     * @return string
-     * @throws \Longman\TelegramBot\Exception\TelegramException
-     */
-    public static function getInput()
-    {
-        // First check if a custom input has been set, else get the PHP input.
-        if (! ($input = self::$telegram->getCustomInput())) {
-            $input = file_get_contents('php://input');
-        }
-
-        // Make sure we have a string to work with.
-        if (! is_string($input)) {
-            throw new TelegramException('Input must be a string!');
-        }
-
-        self::$input = $input;
-
-        TelegramLog::update(self::$input);
-
-        return self::$input;
-    }
-
     /**
      * Generate general fake server response
      *
@@ -333,11 +301,11 @@ public static function getInput()
      */
     public static function generateGeneralFakeServerResponse(array $data = [])
     {
-        //PARAM BINDED IN PHPUNIT TEST FOR TestServerResponse.php
-        //Maybe this is not the best possible implementation
+        // PARAM BINDED IN PHPUNIT TEST FOR TestServerResponse.php
+        // Maybe this is not the best possible implementation
 
-        //No value set in $data ie testing setWebhook
-        //Provided $data['chat_id'] ie testing sendMessage
+        // No value set in $data ie testing setWebhook
+        // Provided $data['chat_id'] ie testing sendMessage
 
         $fake_response = ['ok' => true]; // :)
 
@@ -421,14 +389,14 @@ public static function execute($action, array $data = [])
             );
             $result = (string) $response->getBody();
 
-            //Logging getUpdates Update
+            // Logging getUpdates Update
             if ($action === 'getUpdates') {
                 TelegramLog::update($result);
             }
         } catch (RequestException $e) {
             $result = ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
         } finally {
-            //Logging verbose debug output
+            // Logging verbose debug output
             TelegramLog::endDebugLogTempStream('Verbose HTTP Request output:' . PHP_EOL . '%s' . PHP_EOL);
         }
 
@@ -596,11 +564,11 @@ public static function sendMessage(array $data)
         $text = $data['text'];
 
         do {
-            //Chop off and send the first message
+            // Chop off and send the first message
             $data['text'] = mb_substr($text, 0, 4096);
             $response = self::send('sendMessage', $data);
 
-            //Prepare the next message
+            // Prepare the next message
             $text = mb_substr($text, 4096);
         } while (mb_strlen($text, 'UTF-8') > 0);
 

From 5bc3aece45973477cd7024c9edae00326ee7f352 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:07:04 +0400
Subject: [PATCH 26/40] Reformat the file

---
 src/DB.php | 158 ++++++++++++++++++++++++++---------------------------
 1 file changed, 79 insertions(+), 79 deletions(-)

diff --git a/src/DB.php b/src/DB.php
index ebf2a2ead..f9968e940 100644
--- a/src/DB.php
+++ b/src/DB.php
@@ -57,10 +57,10 @@ class DB
     /**
      * Initialize
      *
-     * @param array    $credentials  Database connection details
-     * @param Telegram $telegram     Telegram object to connect with this object
-     * @param string   $table_prefix Table prefix
-     * @param string   $encoding     Database character encoding
+     * @param array $credentials Database connection details
+     * @param Telegram $telegram Telegram object to connect with this object
+     * @param string $table_prefix Table prefix
+     * @param string $encoding Database character encoding
      *
      * @return PDO PDO database object
      * @throws TelegramException
@@ -75,7 +75,7 @@ public static function initialize(
             throw new TelegramException('MySQL credentials not provided!');
         }
 
-        $dsn     = 'mysql:host=' . $credentials['host'] . ';dbname=' . $credentials['database'];
+        $dsn = 'mysql:host=' . $credentials['host'] . ';dbname=' . $credentials['database'];
         $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $encoding];
         try {
             $pdo = new PDO($dsn, $credentials['user'], $credentials['password'], $options);
@@ -84,10 +84,10 @@ public static function initialize(
             throw new TelegramException($e->getMessage());
         }
 
-        self::$pdo               = $pdo;
-        self::$telegram          = $telegram;
+        self::$pdo = $pdo;
+        self::$telegram = $telegram;
         self::$mysql_credentials = $credentials;
-        self::$table_prefix      = $table_prefix;
+        self::$table_prefix = $table_prefix;
 
         self::defineTables();
 
@@ -99,9 +99,9 @@ public static function initialize(
      *
      * Let you use the class with an external already existing Pdo Mysql connection.
      *
-     * @param PDO      $external_pdo_connection PDO database object
-     * @param Telegram $telegram                Telegram object to connect with this object
-     * @param string   $table_prefix            Table prefix
+     * @param PDO $external_pdo_connection PDO database object
+     * @param Telegram $telegram Telegram object to connect with this object
+     * @param string $table_prefix Table prefix
      *
      * @return PDO PDO database object
      * @throws TelegramException
@@ -115,10 +115,10 @@ public static function externalInitialize(
             throw new TelegramException('MySQL external connection not provided!');
         }
 
-        self::$pdo               = $external_pdo_connection;
-        self::$telegram          = $telegram;
+        self::$pdo = $external_pdo_connection;
+        self::$telegram = $telegram;
         self::$mysql_credentials = [];
-        self::$table_prefix      = $table_prefix;
+        self::$table_prefix = $table_prefix;
 
         self::defineTables();
 
@@ -144,7 +144,7 @@ protected static function defineTables()
         ];
         foreach ($tables as $table) {
             $table_name = 'TB_' . strtoupper($table);
-            if (!defined($table_name)) {
+            if (! defined($table_name)) {
                 define($table_name, self::$table_prefix . $table);
             }
         }
@@ -173,15 +173,15 @@ public static function getPdo()
     /**
      * Fetch update(s) from DB
      *
-     * @param int    $limit Limit the number of updates to fetch
-     * @param string $id    Check for unique update id
+     * @param int $limit Limit the number of updates to fetch
+     * @param string $id Check for unique update id
      *
      * @return array|bool Fetched data or false if not connected
      * @throws TelegramException
      */
     public static function selectTelegramUpdate($limit = null, $id = null)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -228,7 +228,7 @@ public static function selectTelegramUpdate($limit = null, $id = null)
      */
     public static function selectMessages($limit = null)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -275,13 +275,13 @@ protected static function getTimestamp($time = null)
      * @todo Find a better way, as json_* functions are very heavy
      *
      * @param array|null $entities
-     * @param mixed      $default
+     * @param mixed $default
      *
      * @return mixed
      */
     public static function entitiesArrayToJson($entities, $default = null)
     {
-        if (!is_array($entities)) {
+        if (! is_array($entities)) {
             return $default;
         }
 
@@ -322,7 +322,7 @@ public static function insertTelegramUpdate(
             throw new TelegramException('message_id, inline_query_id, chosen_inline_result_id, callback_query_id, edited_message_id are all null');
         }
 
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -351,16 +351,16 @@ public static function insertTelegramUpdate(
     /**
      * Insert users and save their connection to chats
      *
-     * @param User   $user
+     * @param User $user
      * @param string $date
-     * @param Chat   $chat
+     * @param Chat $chat
      *
      * @return bool If the insert was successful
      * @throws TelegramException
      */
     public static function insertUser(User $user, $date = null, Chat $chat = null)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -419,7 +419,7 @@ public static function insertUser(User $user, $date = null, Chat $chat = null)
     /**
      * Insert chat
      *
-     * @param Chat   $chat
+     * @param Chat $chat
      * @param string $date
      * @param string $migrate_to_chat_id
      *
@@ -428,7 +428,7 @@ public static function insertUser(User $user, $date = null, Chat $chat = null)
      */
     public static function insertChat(Chat $chat, $date = null, $migrate_to_chat_id = null)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -446,7 +446,7 @@ public static function insertChat(Chat $chat, $date = null, $migrate_to_chat_id
                     `updated_at`                     = VALUES(`updated_at`)
             ');
 
-            $chat_id   = $chat->getId();
+            $chat_id = $chat->getId();
             $chat_type = $chat->getType();
 
             if ($migrate_to_chat_id !== null) {
@@ -485,11 +485,11 @@ public static function insertChat(Chat $chat, $date = null, $migrate_to_chat_id
      */
     public static function insertRequest(Update $update)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
-        $update_id   = $update->getUpdateId();
+        $update_id = $update->getUpdateId();
         $update_type = $update->getUpdateType();
 
         // @todo Make this simpler: if ($message = $update->getMessage()) ...
@@ -498,7 +498,7 @@ public static function insertRequest(Update $update)
 
             if (self::insertMessageRequest($message)) {
                 $message_id = $message->getMessageId();
-                $chat_id    = $message->getChat()->getId();
+                $chat_id = $message->getChat()->getId();
 
                 return self::insertTelegramUpdate(
                     $update_id,
@@ -506,12 +506,12 @@ public static function insertRequest(Update $update)
                     $message_id
                 );
             }
-        } elseif ($update_type === 'edited_message') {
+        } else if ($update_type === 'edited_message') {
             $edited_message = $update->getEditedMessage();
 
             if (self::insertEditedMessageRequest($edited_message)) {
                 $edited_message_local_id = self::$pdo->lastInsertId();
-                $chat_id                 = $edited_message->getChat()->getId();
+                $chat_id = $edited_message->getChat()->getId();
 
                 return self::insertTelegramUpdate(
                     $update_id,
@@ -523,12 +523,12 @@ public static function insertRequest(Update $update)
                     $edited_message_local_id
                 );
             }
-        } elseif ($update_type === 'channel_post') {
+        } else if ($update_type === 'channel_post') {
             $channel_post = $update->getChannelPost();
 
             if (self::insertMessageRequest($channel_post)) {
                 $message_id = $channel_post->getMessageId();
-                $chat_id    = $channel_post->getChat()->getId();
+                $chat_id = $channel_post->getChat()->getId();
 
                 return self::insertTelegramUpdate(
                     $update_id,
@@ -536,12 +536,12 @@ public static function insertRequest(Update $update)
                     $message_id
                 );
             }
-        } elseif ($update_type === 'edited_channel_post') {
+        } else if ($update_type === 'edited_channel_post') {
             $edited_channel_post = $update->getEditedChannelPost();
 
             if (self::insertEditedMessageRequest($edited_channel_post)) {
                 $edited_channel_post_local_id = self::$pdo->lastInsertId();
-                $chat_id                      = $edited_channel_post->getChat()->getId();
+                $chat_id = $edited_channel_post->getChat()->getId();
 
                 return self::insertTelegramUpdate(
                     $update_id,
@@ -553,7 +553,7 @@ public static function insertRequest(Update $update)
                     $edited_channel_post_local_id
                 );
             }
-        } elseif ($update_type === 'inline_query') {
+        } else if ($update_type === 'inline_query') {
             $inline_query = $update->getInlineQuery();
 
             if (self::insertInlineQueryRequest($inline_query)) {
@@ -566,7 +566,7 @@ public static function insertRequest(Update $update)
                     $inline_query_id
                 );
             }
-        } elseif ($update_type === 'chosen_inline_result') {
+        } else if ($update_type === 'chosen_inline_result') {
             $chosen_inline_result = $update->getChosenInlineResult();
 
             if (self::insertChosenInlineResultRequest($chosen_inline_result)) {
@@ -580,7 +580,7 @@ public static function insertRequest(Update $update)
                     $chosen_inline_result_local_id
                 );
             }
-        } elseif ($update_type === 'callback_query') {
+        } else if ($update_type === 'callback_query') {
             $callback_query = $update->getCallbackQuery();
 
             if (self::insertCallbackQueryRequest($callback_query)) {
@@ -610,7 +610,7 @@ public static function insertRequest(Update $update)
      */
     public static function insertInlineQueryRequest(InlineQuery $inline_query)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -622,7 +622,7 @@ public static function insertInlineQueryRequest(InlineQuery $inline_query)
                 (:id, :user_id, :location, :query, :offset, :created_at)
             ');
 
-            $date    = self::getTimestamp();
+            $date = self::getTimestamp();
             $user_id = null;
 
             $user = $inline_query->getFrom();
@@ -654,7 +654,7 @@ public static function insertInlineQueryRequest(InlineQuery $inline_query)
      */
     public static function insertChosenInlineResultRequest(ChosenInlineResult $chosen_inline_result)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -666,7 +666,7 @@ public static function insertChosenInlineResultRequest(ChosenInlineResult $chose
                 (:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
             ');
 
-            $date    = self::getTimestamp();
+            $date = self::getTimestamp();
             $user_id = null;
 
             $user = $chosen_inline_result->getFrom();
@@ -698,7 +698,7 @@ public static function insertChosenInlineResultRequest(ChosenInlineResult $chose
      */
     public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -710,7 +710,7 @@ public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
                 (:id, :user_id, :chat_id, :message_id, :inline_message_id, :data, :created_at)
             ');
 
-            $date    = self::getTimestamp();
+            $date = self::getTimestamp();
             $user_id = null;
 
             $user = $callback_query->getFrom();
@@ -719,11 +719,11 @@ public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
                 self::insertUser($user, $date);
             }
 
-            $message    = $callback_query->getMessage();
-            $chat_id    = null;
+            $message = $callback_query->getMessage();
+            $chat_id = null;
             $message_id = null;
             if ($message instanceof Message) {
-                $chat_id    = $message->getChat()->getId();
+                $chat_id = $message->getChat()->getId();
                 $message_id = $message->getMessageId();
 
                 $is_message = self::$pdo->query('
@@ -767,7 +767,7 @@ public static function insertCallbackQueryRequest(CallbackQuery $callback_query)
      */
     public static function insertMessageRequest(Message $message)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -795,16 +795,16 @@ public static function insertMessageRequest(Message $message)
         if ($forward_from_chat instanceof Chat) {
             self::insertChat($forward_from_chat, $forward_date);
             $forward_from_chat = $forward_from_chat->getId();
-            $forward_date      = self::getTimestamp($message->getForwardDate());
+            $forward_date = self::getTimestamp($message->getForwardDate());
         }
 
         // New and left chat member
         $new_chat_members_ids = null;
-        $left_chat_member_id  = null;
+        $left_chat_member_id = null;
 
         $new_chat_members = $message->getNewChatMembers();
         $left_chat_member = $message->getLeftChatMember();
-        if (!empty($new_chat_members)) {
+        if (! empty($new_chat_members)) {
             foreach ($new_chat_members as $new_chat_member) {
                 if ($new_chat_member instanceof User) {
                     // Insert the new chat user
@@ -813,7 +813,7 @@ public static function insertMessageRequest(Message $message)
                 }
             }
             $new_chat_members_ids = implode(',', $new_chat_members_ids);
-        } elseif ($left_chat_member instanceof User) {
+        } else if ($left_chat_member instanceof User) {
             // Insert the left chat user
             self::insertUser($left_chat_member, $date, $chat);
             $left_chat_member_id = $left_chat_member->getId();
@@ -847,7 +847,7 @@ public static function insertMessageRequest(Message $message)
             }
             $chat_id = $chat->getId();
 
-            $reply_to_message    = $message->getReplyToMessage();
+            $reply_to_message = $message->getReplyToMessage();
             $reply_to_message_id = null;
             if ($reply_to_message instanceof ReplyToMessage) {
                 $reply_to_message_id = $reply_to_message->getMessageId();
@@ -915,7 +915,7 @@ public static function insertMessageRequest(Message $message)
      */
     public static function insertEditedMessageRequest(Message $edited_message)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -968,7 +968,7 @@ public static function insertEditedMessageRequest(Message $edited_message)
      */
     public static function selectChats($select_chats_params)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -984,7 +984,7 @@ public static function selectChats($select_chats_params)
             'text'        => null,
         ], $select_chats_params);
 
-        if (!$select['groups'] && !$select['users'] && !$select['supergroups'] && !$select['channels']) {
+        if (! $select['groups'] && ! $select['users'] && ! $select['supergroups'] && ! $select['channels']) {
             return false;
         }
 
@@ -1008,10 +1008,10 @@ public static function selectChats($select_chats_params)
             }
 
             // Building parts of query
-            $where  = [];
+            $where = [];
             $tokens = [];
 
-            if (!$select['groups'] || !$select['users'] || !$select['supergroups'] || !$select['channels']) {
+            if (! $select['groups'] || ! $select['users'] || ! $select['supergroups'] || ! $select['channels']) {
                 $chat_or_user = [];
 
                 $select['groups'] && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
@@ -1023,24 +1023,24 @@ public static function selectChats($select_chats_params)
             }
 
             if (null !== $select['date_from']) {
-                $where[]              = TB_CHAT . '.`updated_at` >= :date_from';
+                $where[] = TB_CHAT . '.`updated_at` >= :date_from';
                 $tokens[':date_from'] = $select['date_from'];
             }
 
             if (null !== $select['date_to']) {
-                $where[]            = TB_CHAT . '.`updated_at` <= :date_to';
+                $where[] = TB_CHAT . '.`updated_at` <= :date_to';
                 $tokens[':date_to'] = $select['date_to'];
             }
 
             if (null !== $select['chat_id']) {
-                $where[]            = TB_CHAT . '.`id` = :chat_id';
+                $where[] = TB_CHAT . '.`id` = :chat_id';
                 $tokens[':chat_id'] = $select['chat_id'];
             }
 
             if (null !== $select['text']) {
                 $text_like = '%' . strtolower($select['text']) . '%';
                 if ($select['users']) {
-                    $where[]          = '(
+                    $where[] = '(
                         LOWER(' . TB_CHAT . '.`title`) LIKE :text1
                         OR LOWER(' . TB_USER . '.`first_name`) LIKE :text2
                         OR LOWER(' . TB_USER . '.`last_name`) LIKE :text3
@@ -1051,12 +1051,12 @@ public static function selectChats($select_chats_params)
                     $tokens[':text3'] = $text_like;
                     $tokens[':text4'] = $text_like;
                 } else {
-                    $where[]         = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
+                    $where[] = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
                     $tokens[':text'] = $text_like;
                 }
             }
 
-            if (!empty($where)) {
+            if (! empty($where)) {
                 $query .= ' WHERE ' . implode(' AND ', $where);
             }
 
@@ -1075,14 +1075,14 @@ public static function selectChats($select_chats_params)
      * Get Telegram API request count for current chat / message
      *
      * @param integer $chat_id
-     * @param string  $inline_message_id
+     * @param string $inline_message_id
      *
      * @return array|bool Array containing TOTAL and CURRENT fields or false on invalid arguments
      * @throws TelegramException
      */
     public static function getTelegramRequestCount($chat_id = null, $inline_message_id = null)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -1093,7 +1093,7 @@ public static function getTelegramRequestCount($chat_id = null, $inline_message_
                 (SELECT COUNT(*) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_minute AND `chat_id` = :chat_id_2) AS LIMIT_PER_MINUTE
             ');
 
-            $date        = self::getTimestamp();
+            $date = self::getTimestamp();
             $date_minute = self::getTimestamp(strtotime('-1 minute'));
 
             $sth->bindValue(':chat_id_1', $chat_id);
@@ -1115,14 +1115,14 @@ public static function getTelegramRequestCount($chat_id = null, $inline_message_
      * Insert Telegram API request in db
      *
      * @param string $method
-     * @param array  $data
+     * @param array $data
      *
      * @return bool If the insert was successful
      * @throws TelegramException
      */
     public static function insertTelegramRequest($method, $data)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -1133,7 +1133,7 @@ public static function insertTelegramRequest($method, $data)
                 (:method, :chat_id, :inline_message_id, :created_at);
             ');
 
-            $chat_id           = isset($data['chat_id']) ? $data['chat_id'] : null;
+            $chat_id = isset($data['chat_id']) ? $data['chat_id'] : null;
             $inline_message_id = isset($data['inline_message_id']) ? $data['inline_message_id'] : null;
 
             $sth->bindValue(':chat_id', $chat_id);
@@ -1151,15 +1151,15 @@ public static function insertTelegramRequest($method, $data)
      * Bulk update the entries of any table
      *
      * @param string $table
-     * @param array  $fields_values
-     * @param array  $where_fields_values
+     * @param array $fields_values
+     * @param array $where_fields_values
      *
      * @return bool
      * @throws TelegramException
      */
     public static function update($table, array $fields_values, array $where_fields_values)
     {
-        if (empty($fields_values) || !self::isDbConnected()) {
+        if (empty($fields_values) || ! self::isDbConnected()) {
             return false;
         }
 
@@ -1169,15 +1169,15 @@ public static function update($table, array $fields_values, array $where_fields_
 
             // Fields with values to update
             foreach ($fields_values as $field => $value) {
-                $token          = ':' . count($tokens);
-                $fields[]       = "`{$field}` = {$token}";
+                $token = ':' . count($tokens);
+                $fields[] = "`{$field}` = {$token}";
                 $tokens[$token] = $value;
             }
 
             // Where conditions
             foreach ($where_fields_values as $field => $value) {
-                $token          = ':' . count($tokens);
-                $where[]        = "`{$field}` = {$token}";
+                $token = ':' . count($tokens);
+                $where[] = "`{$field}` = {$token}";
                 $tokens[$token] = $value;
             }
 

From 8a70d87e0e06f4e8d95700f40ea24ba70cd10e68 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:08:07 +0400
Subject: [PATCH 27/40] Add class constants for types

---
 src/Entities/Update.php | 46 ++++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 21 deletions(-)

diff --git a/src/Entities/Update.php b/src/Entities/Update.php
index 4ddb64bf7..98417d5f4 100644
--- a/src/Entities/Update.php
+++ b/src/Entities/Update.php
@@ -18,7 +18,9 @@
  *
  * @link https://core.telegram.org/bots/api#update
  *
- * @method int                 getUpdateId()           The update's unique identifier. Update identifiers start from a certain positive number and increase sequentially. This ID becomes especially handy if you’re using Webhooks, since it allows you to ignore repeated updates or to restore the correct update sequence, should they get out of order.
+ * @method int                 getUpdateId()           The update's unique identifier. Update identifiers start from a certain positive number and increase
+ *     sequentially. This ID becomes especially handy if you’re using Webhooks, since it allows you to ignore repeated updates or to restore the correct update
+ *     sequence, should they get out of order.
  * @method Message             getMessage()            Optional. New incoming message of any kind — text, photo, sticker, etc.
  * @method Message             getEditedMessage()      Optional. New version of a message that is known to the bot and was edited
  * @method Message             getChannelPost()        Optional. New post in the channel, can be any kind — text, photo, sticker, etc.
@@ -31,21 +33,31 @@
  */
 class Update extends Entity
 {
+    const TYPE_MESSAGE = 'message';
+    const TYPE_EDITED_MESSAGE = 'edited_message';
+    const TYPE_CHANNEL_POST = 'channel_post';
+    const TYPE_EDITED_CHANNEL_POST = 'edited_channel_post';
+    const TYPE_INLINE_QUERY = 'inline_query';
+    const TYPE_CHOSEN_INLINE_QUERY = 'chosen_inline_result';
+    const TYPE_CALLBACK_QUERY = 'callback_query';
+    const TYPE_SHIPPING_QUERY = 'shipping_query';
+    const TYPE_PRE_CHECKOUT_QUERY = 'pre_checkout_query';
+
     /**
      * {@inheritdoc}
      */
     protected function subEntities()
     {
         return [
-            'message'              => Message::class,
-            'edited_message'       => EditedMessage::class,
-            'channel_post'         => ChannelPost::class,
-            'edited_channel_post'  => EditedChannelPost::class,
-            'inline_query'         => InlineQuery::class,
-            'chosen_inline_result' => ChosenInlineResult::class,
-            'callback_query'       => CallbackQuery::class,
-            'shipping_query'       => ShippingQuery::class,
-            'pre_checkout_query'   => PreCheckoutQuery::class,
+            self::TYPE_MESSAGE             => Message::class,
+            self::TYPE_EDITED_MESSAGE      => EditedMessage::class,
+            self::TYPE_CHANNEL_POST        => ChannelPost::class,
+            self::TYPE_EDITED_CHANNEL_POST => EditedChannelPost::class,
+            self::TYPE_INLINE_QUERY        => InlineQuery::class,
+            self::TYPE_CHOSEN_INLINE_QUERY => ChosenInlineResult::class,
+            self::TYPE_CALLBACK_QUERY      => CallbackQuery::class,
+            self::TYPE_SHIPPING_QUERY      => ShippingQuery::class,
+            self::TYPE_PRE_CHECKOUT_QUERY  => PreCheckoutQuery::class,
         ];
     }
 
@@ -56,17 +68,8 @@ protected function subEntities()
      */
     public function getUpdateType()
     {
-        $types = [
-            'message',
-            'edited_message',
-            'channel_post',
-            'edited_channel_post',
-            'inline_query',
-            'chosen_inline_result',
-            'callback_query',
-            'shipping_query',
-            'pre_checkout_query',
-        ];
+        $types = array_keys($this->subEntities());
+
         foreach ($types as $type) {
             if ($this->getProperty($type)) {
                 return $type;
@@ -90,6 +93,7 @@ public function getUpdateContent()
             // Instead of just getting the property as an array,
             // use the __call method to get the correct Entity object.
             $method = 'get' . str_replace('_', '', ucwords($update_type, '_'));
+
             return $this->$method();
         }
 

From 70d55ff337aaa65e0a4c9a02c71176ed87fdbcd2 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:08:50 +0400
Subject: [PATCH 28/40] Ignore custom input

---
 src/Console/Kernel.php | 37 ++++++++++++++++---------------------
 1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/src/Console/Kernel.php b/src/Console/Kernel.php
index caa1966ae..85f6e3ab2 100644
--- a/src/Console/Kernel.php
+++ b/src/Console/Kernel.php
@@ -62,31 +62,26 @@ public function handle(Request $request, $limit = null, $timeout = null)
 
         $offset = 0;
 
-        // Take custom input into account.
-        if ($custom_input = $this->app->getCustomInput()) {
-            $response = new Response(json_decode($custom_input, true), $this->app->getBotUsername());
-        } else {
-            if (DB::isDbConnected()) {
-                // Get last update id from the database
-                $last_update = DB::selectTelegramUpdate(1);
-                $last_update = reset($last_update);
+        if (DB::isDbConnected()) {
+            // Get last update id from the database
+            $last_update = DB::selectTelegramUpdate(1);
+            $last_update = reset($last_update);
 
-                $this->app->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
-            }
-
-            if ($this->app->last_update_id !== null) {
-                $offset = $this->app->last_update_id + 1;    //As explained in the telegram bot API documentation
-            }
+            $this->app->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
+        }
 
-            $response = Client::getUpdates(
-                [
-                    'offset'  => $offset,
-                    'limit'   => $limit,
-                    'timeout' => $timeout,
-                ]
-            );
+        if ($this->app->last_update_id !== null) {
+            $offset = $this->app->last_update_id + 1;    //As explained in the telegram bot API documentation
         }
 
+        $response = Client::getUpdates(
+            [
+                'offset'  => $offset,
+                'limit'   => $limit,
+                'timeout' => $timeout,
+            ]
+        );
+
         if ($response->isOk()) {
             $results = $response->getResult();
 

From e3f13a1c8520664eac9bed0f1da60a1f050a8f92 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:09:05 +0400
Subject: [PATCH 29/40] Reformat the file

---
 src/Entities/Message.php | 31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/src/Entities/Message.php b/src/Entities/Message.php
index 0e592dc68..4ce8af13d 100644
--- a/src/Entities/Message.php
+++ b/src/Entities/Message.php
@@ -27,7 +27,8 @@
  * @method int               getForwardFromMessageId()  Optional. For forwarded channel posts, identifier of the original message in the channel
  * @method string            getForwardSignature()      Optional. For messages forwarded from channels, signature of the post author if present
  * @method int               getForwardDate()           Optional. For forwarded messages, date the original message was sent in Unix time
- * @method Message           getReplyToMessage()        Optional. For replies, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply.
+ * @method Message           getReplyToMessage()        Optional. For replies, the original message. Note that the Message object in this field will not
+ *     contain further reply_to_message fields even if it itself is a reply.
  * @method int               getEditDate()              Optional. Date the message was last edited in Unix time
  * @method string            getMediaGroupId()          Optional. The unique identifier of a media message group this message belongs to
  * @method string            getAuthorSignature()       Optional. Signature of the post author for messages in channels
@@ -41,15 +42,25 @@
  * @method Contact           getContact()               Optional. Message is a shared contact, information about the contact
  * @method Location          getLocation()              Optional. Message is a shared location, information about the location
  * @method Venue             getVenue()                 Optional. Message is a venue, information about the venue
- * @method User              getLeftChatMember()        Optional. A member was removed from the group, information about them (this member may be the bot itself)
+ * @method User              getLeftChatMember()        Optional. A member was removed from the group, information about them (this member may be the bot
+ *     itself)
  * @method string            getNewChatTitle()          Optional. A chat title was changed to this value
  * @method bool              getDeleteChatPhoto()       Optional. Service message: the chat photo was deleted
  * @method bool              getGroupChatCreated()      Optional. Service message: the group has been created
- * @method bool              getSupergroupChatCreated() Optional. Service message: the supergroup has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a supergroup when it is created. It can only be found in reply_to_message if someone replies to a very first message in a directly created supergroup.
- * @method bool              getChannelChatCreated()    Optional. Service message: the channel has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel.
- * @method int               getMigrateToChatId()       Optional. The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
- * @method int               getMigrateFromChatId()     Optional. The supergroup has been migrated from a group with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
- * @method Message           getPinnedMessage()         Optional. Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply.
+ * @method bool              getSupergroupChatCreated() Optional. Service message: the supergroup has been created. This field can't be received in a message
+ *     coming through updates, because bot can’t be a member of a supergroup when it is created. It can only be found in reply_to_message if someone replies to
+ *     a very first message in a directly created supergroup.
+ * @method bool              getChannelChatCreated()    Optional. Service message: the channel has been created. This field can't be received in a message
+ *     coming through updates, because bot can’t be a member of a channel when it is created. It can only be found in reply_to_message if someone replies to a
+ *     very first message in a channel.
+ * @method int               getMigrateToChatId()       Optional. The group has been migrated to a supergroup with the specified identifier. This number may be
+ *     greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64
+ *     bit integer or double-precision float type are safe for storing this identifier.
+ * @method int               getMigrateFromChatId()     Optional. The supergroup has been migrated from a group with the specified identifier. This number may
+ *     be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed
+ *     64 bit integer or double-precision float type are safe for storing this identifier.
+ * @method Message           getPinnedMessage()         Optional. Specified message was pinned. Note that the Message object in this field will not contain
+ *     further reply_to_message fields even if it is itself a reply.
  * @method Invoice           getInvoice()               Optional. Message is an invoice for a payment, information about the invoice.
  * @method SuccessfulPayment getSuccessfulPayment()     Optional. Message is a service message about a successful payment, information about the payment.
  * @method string            getConnectedWebsite()      Optional. The domain name of the website on which the user has logged in.
@@ -91,7 +102,7 @@ protected function subEntities()
     /**
      * Message constructor
      *
-     * @param array  $data
+     * @param array $data
      * @param string $bot_username
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -188,7 +199,7 @@ public function getFullCommand()
             return null;
         }
 
-        $no_EOL   = strtok($text, PHP_EOL);
+        $no_EOL = strtok($text, PHP_EOL);
         $no_space = strtok($text, ' ');
 
         //try to understand which separator \n or space divide /command from text
@@ -214,7 +225,7 @@ public function getCommand()
 
         //check if command is followed by bot username
         $split_cmd = explode('@', $full_command);
-        if (!isset($split_cmd[1])) {
+        if (! isset($split_cmd[1])) {
             //command is not followed by name
             return $full_command;
         }

From c04686e9f6af4008d15d5b70d4c4ac7a8af62389 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:09:39 +0400
Subject: [PATCH 30/40] Rename the method and use request class from container

---
 src/Commands/AdminCommands/ChatsCommand.php | 2 +-
 src/Commands/AdminCommands/DebugCommand.php | 9 +++++++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/Commands/AdminCommands/ChatsCommand.php b/src/Commands/AdminCommands/ChatsCommand.php
index c4a5ab7ff..c25709759 100644
--- a/src/Commands/AdminCommands/ChatsCommand.php
+++ b/src/Commands/AdminCommands/ChatsCommand.php
@@ -83,7 +83,7 @@ public function execute()
                 $chat = new Chat($result);
 
                 $whois = $chat->getId();
-                if ($this->telegram->getCommandObject('whois')) {
+                if ($this->telegram->createCommandObject('whois')) {
                     // We can't use '-' in command because part of it will become unclickable
                     $whois = '/whois' . str_replace('-', 'g', $chat->getId());
                 }
diff --git a/src/Commands/AdminCommands/DebugCommand.php b/src/Commands/AdminCommands/DebugCommand.php
index 3fd19bc8e..2c71d8d3a 100644
--- a/src/Commands/AdminCommands/DebugCommand.php
+++ b/src/Commands/AdminCommands/DebugCommand.php
@@ -10,9 +10,11 @@
 
 namespace Longman\TelegramBot\Commands\AdminCommands;
 
+use Exception;
 use Longman\TelegramBot\Commands\AdminCommand;
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Http\Client;
+use Longman\TelegramBot\Http\Request;
 
 /**
  * Admin "/debug" command
@@ -94,8 +96,11 @@ public function execute()
 
         $webhook_info_title = '*Webhook Info:*';
         try {
+            /** @var \Longman\TelegramBot\Http\Request $request */
+            $request = $this->getTelegram()->getContainer()->make(Request::class);
+
             // Check if we're actually using the Webhook method.
-            if (Client::getInput() === '') {
+            if (empty($request->json()->all())) {
                 $debug_info[] = $webhook_info_title . ' `Using getUpdates method, not Webhook.`';
             } else {
                 $webhook_info_result = json_decode(Client::getWebhookInfo(), true)['result'];
@@ -111,7 +116,7 @@ public function execute()
                     $webhook_info_result_str
                 );
             }
-        } catch (\Exception $e) {
+        } catch (Exception $e) {
             $debug_info[] = $webhook_info_title . sprintf(' `Failed to get webhook info! (%s)`', $e->getMessage());
         }
 

From a3261e95fe617d9b79ff34a909bbb3cdd995f9fe Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:10:02 +0400
Subject: [PATCH 31/40] Improve main application class

---
 src/Telegram.php | 66 ++++++++++++++++++++++++++++++------------------
 1 file changed, 42 insertions(+), 24 deletions(-)

diff --git a/src/Telegram.php b/src/Telegram.php
index 68ec45a3d..370c4e63a 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -267,7 +267,7 @@ public function getCommandsList()
 
         foreach ($this->commands_paths as $path) {
             try {
-                //Get all "*Command.php" files
+                // Get all "*Command.php" files
                 $files = new RegexIterator(
                     new RecursiveIteratorIterator(
                         new RecursiveDirectoryIterator($path)
@@ -286,7 +286,7 @@ public function getCommandsList()
 
                     require_once $file->getPathname();
 
-                    $command_obj = $this->getCommandObject($command);
+                    $command_obj = $this->createCommandObject($command);
                     if ($command_obj instanceof Command) {
                         $commands[$command_name] = $command_obj;
                     }
@@ -306,20 +306,24 @@ public function getCommandsList()
      *
      * @return \Longman\TelegramBot\Commands\Command|null
      */
-    public function getCommandObject($command)
+    public function createCommandObject($command)
     {
         $which = ['System'];
-        $this->isAdmin() && $which[] = 'Admin';
+        if ($this->isAdmin()) {
+            $which[] = 'Admin';
+        }
         $which[] = 'User';
 
+        $command_name = $this->ucfirstUnicode($command);
         foreach ($which as $auth) {
-            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command';
+            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $command_name . 'Command';
+
             if (class_exists($command_namespace)) {
                 return new $command_namespace($this, $this->update);
             }
         }
 
-        return null;
+        throw new TelegramException('Command ' . $command . ' does not found');
     }
 
     /**
@@ -359,13 +363,14 @@ public function getLastCommandResponse()
     /**
      * Handle getUpdates method
      *
+     * @param \Longman\TelegramBot\Http\Request|null $request
      * @param int|null $limit
      * @param int|null $timeout
      *
      * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
-    public function handleGetUpdates($limit = null, $timeout = null)
+    public function handleGetUpdates(Request $request = null, $limit = null, $timeout = null)
     {
         if (empty($this->bot_username)) {
             throw new TelegramException('Bot Username is not defined!');
@@ -374,7 +379,13 @@ public function handleGetUpdates($limit = null, $timeout = null)
         /** @var \Longman\TelegramBot\Console\Kernel $kernel */
         $kernel = $this->getContainer()->make(ConsoleKernel::class);
 
-        $response = $kernel->handle(Request::capture(), $limit, $timeout);
+        if (is_null($request)) {
+            $request = Request::capture();
+        }
+
+        $this->container->instance(Request::class, $request);
+
+        $response = $kernel->handle($request, $limit, $timeout);
 
         return $response;
     }
@@ -382,20 +393,27 @@ public function handleGetUpdates($limit = null, $timeout = null)
     /**
      * Handle bot request from webhook
      *
+     * @param \Longman\TelegramBot\Http\Request|null $request
      * @return \Longman\TelegramBot\Http\Response
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
-    public function handle()
+    public function handle(Request $request = null)
     {
-        if (empty($this->bot_username)) {
+        if (empty($this->getBotUsername())) {
             throw new TelegramException('Bot Username is not defined!');
         }
 
         /** @var \Longman\TelegramBot\Http\Kernel $kernel */
         $kernel = $this->getContainer()->make(Kernel::class);
 
-        $response = $kernel->handle(Request::capture());
+        if (is_null($request)) {
+            $request = Request::capture();
+        }
+
+        $this->container->instance(Request::class, $request);
+
+        $response = $kernel->handle($request);
 
         return $response;
     }
@@ -428,9 +446,9 @@ public function processUpdate(Update $update)
         // If all else fails, it's a generic message.
         $command = 'genericmessage';
 
-        $update_type = $this->update->getUpdateType();
-        if ($update_type === 'message') {
-            $message = $this->update->getMessage();
+        $update_type = $update->getUpdateType();
+        if ($update_type === Update::TYPE_MESSAGE) {
+            $message = $update->getMessage();
 
             // Load admin commands
             if ($this->isAdmin()) {
@@ -467,14 +485,14 @@ public function processUpdate(Update $update)
         $this->getCommandsList();
 
         // Make sure we don't try to process update that was already processed
-        $last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
+        $last_id = DB::selectTelegramUpdate(1, $update->getUpdateId());
         if ($last_id && count($last_id) === 1) {
             TelegramLog::debug('Duplicate update received, processing aborted!');
 
             return new Response(['ok' => true, 'result' => true]);
         }
 
-        DB::insertRequest($this->update);
+        DB::insertRequest($update);
 
         return $this->executeCommand($command);
     }
@@ -490,7 +508,7 @@ public function processUpdate(Update $update)
     public function executeCommand($command)
     {
         $command = strtolower($command);
-        $command_obj = $this->getCommandObject($command);
+        $command_obj = $this->createCommandObject($command);
 
         if (! $command_obj || ! $command_obj->isEnabled()) {
             // Failsafe in case the Generic command can't be found
@@ -796,30 +814,30 @@ public function getVersion()
      * Set Webhook for bot
      *
      * @param string $url
-     * @param array $data Optional parameters.
+     * @param array $parameters Optional parameters.
      *
      * @return \Longman\TelegramBot\Http\Response
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
-    public function setWebhook($url, array $data = [])
+    public function setWebhook($url, array $parameters = [])
     {
         if (empty($url)) {
             throw new TelegramException('Hook url is empty!');
         }
 
-        $data = array_intersect_key($data, array_flip([
+        $parameters = array_intersect_key($parameters, array_flip([
             'certificate',
             'max_connections',
             'allowed_updates',
         ]));
-        $data['url'] = $url;
+        $parameters['url'] = $url;
 
         // If the certificate is passed as a path, encode and add the file to the data array.
-        if (! empty($data['certificate']) && is_string($data['certificate'])) {
-            $data['certificate'] = Client::encodeFile($data['certificate']);
+        if (! empty($parameters['certificate']) && is_string($parameters['certificate'])) {
+            $parameters['certificate'] = Client::encodeFile($parameters['certificate']);
         }
 
-        $result = Client::setWebhook($data);
+        $result = Client::setWebhook($parameters);
 
         if (! $result->isOk()) {
             throw new TelegramException(

From 6b4a1cc94d83afafd5df0b1b306956c1954bf6fa Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:59:28 +0400
Subject: [PATCH 32/40] Improve response class and drop magic fields

---
 src/Http/Client.php   |   5 +-
 src/Http/Response.php | 133 +++++++++++++++++++-----------------------
 2 files changed, 64 insertions(+), 74 deletions(-)

diff --git a/src/Http/Client.php b/src/Http/Client.php
index 83193c5fe..ff7b55130 100644
--- a/src/Http/Client.php
+++ b/src/Http/Client.php
@@ -481,6 +481,7 @@ public static function send($action, array $data = [])
 
         $bot_username = self::$telegram->getBotUsername();
 
+        // @TODO: Refactor testing and remove this
         if (defined('PHPUNIT_TESTSUITE')) {
             $fake_response = self::generateGeneralFakeServerResponse($data);
 
@@ -491,7 +492,9 @@ public static function send($action, array $data = [])
 
         self::limitTelegramRequests($action, $data);
 
-        $response = json_decode(self::execute($action, $data), true);
+        $result = self::execute($action, $data);
+
+        $response = json_decode($result, true);
 
         if (null === $response) {
             throw new TelegramException('Telegram returned an invalid response! Please review your bot name and API key.');
diff --git a/src/Http/Response.php b/src/Http/Response.php
index 400c9a528..927a81b3f 100644
--- a/src/Http/Response.php
+++ b/src/Http/Response.php
@@ -18,7 +18,7 @@
 use Longman\TelegramBot\Entities\WebhookInfo;
 
 /**
- * Class ServerResponse
+ * Class Response
  *
  * @link https://core.telegram.org/bots/api#making-requests
  *
@@ -26,8 +26,29 @@
  */
 class Response
 {
+    /** @var bool */
+    protected $ok = false;
+
+    /** @var string */
+    protected $description;
+
+    /** @var array */
+    protected $result;
+
+    /** @var int */
+    protected $error_code;
+
+    /** @var array */
+    protected $parameters;
+
+    /** @var array */
+    protected $raw_data;
+
+    /** @var string */
+    protected $bot_username;
+
     /**
-     * ServerResponse constructor.
+     * Response constructor.
      *
      * @param array $data
      * @param string $bot_username
@@ -36,44 +57,31 @@ class Response
      */
     public function __construct(array $data, $bot_username = '')
     {
-        // Make sure we don't double-save the raw_data
-        unset($data['raw_data']);
-        $data['raw_data'] = $data;
+        $this->raw_data = $data;
 
-        $is_ok = isset($data['ok']) ? (bool) $data['ok'] : false;
-        $result = isset($data['result']) ? $data['result'] : null;
+        $this->ok = $data['ok'];
 
-        if ($is_ok && is_array($result)) {
-            if ($this->isAssoc($result)) {
-                $data['result'] = $this->createResultObject($result, $bot_username);
-            } else {
-                $data['result'] = $this->createResultObjects($result, $bot_username);
-            }
+        if (isset($data['description'])) {
+            $this->description = $data['description'];
         }
 
-        //Make sure we're not raw_data inception-ing
-        if (array_key_exists('raw_data', $data)) {
-            if ($data['raw_data'] === null) {
-                unset($data['raw_data']);
-            }
-        } else {
-            $data['raw_data'] = $data;
+        if (isset($data['error_code'])) {
+            $this->error_code = $data['error_code'];
         }
 
-        $data['bot_username'] = $bot_username;
+        if (isset($data['parameters'])) {
+            $this->parameters = $data['parameters'];
+        }
 
-        $this->assignMemberVariables($data);
-    }
+        $this->bot_username = $bot_username;
 
-    /**
-     * Helper to set member variables
-     *
-     * @param array $data
-     */
-    protected function assignMemberVariables(array $data)
-    {
-        foreach ($data as $key => $value) {
-            $this->$key = $value;
+        $result = isset($data['result']) ? $data['result'] : null;
+        if ($this->ok && is_array($result)) {
+            if ($this->isAssoc($result)) {
+                $this->result = $this->createResultObject($result, $bot_username);
+            } else {
+                $this->result = $this->createResultObjects($result, $bot_username);
+            }
         }
     }
 
@@ -98,17 +106,7 @@ protected function isAssoc(array $array)
      */
     public function isOk()
     {
-        return $this->getOk();
-    }
-
-    /**
-     * If response is ok
-     *
-     * @return bool
-     */
-    public function getOk()
-    {
-        return isset($this->ok) ? (bool) $this->ok : false;
+        return $this->ok;
     }
 
     /**
@@ -118,7 +116,7 @@ public function getOk()
      */
     public function getResult()
     {
-        return isset($this->result) ? $this->result : [];
+        return ! empty($this->result) ? $this->result : [];
     }
 
     /**
@@ -128,7 +126,7 @@ public function getResult()
      */
     public function getErrorCode()
     {
-        return isset($this->error_code) ? $this->error_code : null;
+        return ! empty($this->error_code) ? $this->error_code : null;
     }
 
     /**
@@ -138,29 +136,21 @@ public function getErrorCode()
      */
     public function getDescription()
     {
-        return isset($this->description) ? $this->description : null;
+        return ! empty($this->description) ? $this->description : null;
     }
 
     /**
-     * Print error
+     * Get error
      *
      * @see https://secure.php.net/manual/en/function.print-r.php
      *
-     * @param bool $return
-     *
-     * @return bool|string
+     * @return string
      */
-    public function printError($return = false)
+    public function getError()
     {
         $error = sprintf('Error N: %s, Description: %s', $this->getErrorCode(), $this->getDescription());
 
-        if ($return) {
-            return $error;
-        }
-
-        echo $error;
-
-        return true;
+        return $error;
     }
 
     /**
@@ -172,26 +162,23 @@ public function printError($return = false)
      * @return \Longman\TelegramBot\Entities\Chat|\Longman\TelegramBot\Entities\ChatMember|\Longman\TelegramBot\Entities\File|\Longman\TelegramBot\Entities\Message|\Longman\TelegramBot\Entities\User|\Longman\TelegramBot\Entities\UserProfilePhotos|\Longman\TelegramBot\Entities\WebhookInfo
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
-    private function createResultObject($result, $bot_username)
+    protected function createResultObject($result, $bot_username)
     {
-        // We don't need to save the raw_data of the response object!
-        $result['raw_data'] = null;
-
         $result_object_types = [
-            'total_count' => UserProfilePhotos::class, //Response from getUserProfilePhotos
-            'file_id'     => File::class,              //Response from getFile
-            'title'       => Chat::class,              //Response from getChat
-            'username'    => User::class,              //Response from getMe
-            'user'        => ChatMember::class,        //Response from getChatMember
-            'url'         => WebhookInfo::class,       //Response from getWebhookInfo
+            'total_count' => UserProfilePhotos::class, // Response from getUserProfilePhotos
+            'file_id'     => File::class,              // Response from getFile
+            'title'       => Chat::class,              // Response from getChat
+            'username'    => User::class,              // Response from getMe
+            'user'        => ChatMember::class,        // Response from getChatMember
+            'url'         => WebhookInfo::class,       // Response from getWebhookInfo
         ];
         foreach ($result_object_types as $type => $object_class) {
             if (isset($result[$type])) {
-                return new $object_class($result);
+                return new $object_class($result, $bot_username);
             }
         }
 
-        //Response from sendMessage
+        // Response from sendMessage
         return new Message($result, $bot_username);
     }
 
@@ -204,11 +191,11 @@ private function createResultObject($result, $bot_username)
      * @return null|\Longman\TelegramBot\Entities\ChatMember[]|\Longman\TelegramBot\Entities\Update[]
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
-    private function createResultObjects($result, $bot_username)
+    protected function createResultObjects($result, $bot_username)
     {
         $results = [];
         if (isset($result[0]['user'])) {
-            //Response from getChatAdministrators
+            // Response from getChatAdministrators
             foreach ($result as $user) {
                 // We don't need to save the raw_data of the response object!
                 $user['raw_data'] = null;
@@ -216,7 +203,7 @@ private function createResultObjects($result, $bot_username)
                 $results[] = new ChatMember($user);
             }
         } else {
-            //Get Update
+            // Get Update
             foreach ($result as $update) {
                 // We don't need to save the raw_data of the response object!
                 $update['raw_data'] = null;

From e09613bcd791e167d537e0bd0a40a66f49e85d03 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 01:59:50 +0400
Subject: [PATCH 33/40] Fix code style

---
 src/Commands/AdminCommands/DebugCommand.php | 10 ++++++++--
 src/Entities/Entity.php                     |  3 ++-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/Commands/AdminCommands/DebugCommand.php b/src/Commands/AdminCommands/DebugCommand.php
index 2c71d8d3a..f69734cf3 100644
--- a/src/Commands/AdminCommands/DebugCommand.php
+++ b/src/Commands/AdminCommands/DebugCommand.php
@@ -103,13 +103,19 @@ public function execute()
             if (empty($request->json()->all())) {
                 $debug_info[] = $webhook_info_title . ' `Using getUpdates method, not Webhook.`';
             } else {
-                $webhook_info_result = json_decode(Client::getWebhookInfo(), true)['result'];
+                /** @var \Longman\TelegramBot\Http\Response $response */
+                $response = Client::getWebhookInfo();
+
+                /** @var \Longman\TelegramBot\Entities\WebhookInfo $result */
+                $result = $response->getResult();
+
+                $webhook_info_result = $result->getRawData();
                 // Add a human-readable error date string if necessary.
                 if (isset($webhook_info_result['last_error_date'])) {
                     $webhook_info_result['last_error_date_string'] = date('Y-m-d H:i:s', $webhook_info_result['last_error_date']);
                 }
 
-                $webhook_info_result_str = json_encode($webhook_info_result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+                $webhook_info_result_str = json_encode($webhook_info_result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
                 $debug_info[] = $webhook_info_title;
                 $debug_info[] = sprintf(
                     '```' . PHP_EOL . '%s```',
diff --git a/src/Entities/Entity.php b/src/Entities/Entity.php
index 23e95a153..f7d853fd3 100644
--- a/src/Entities/Entity.php
+++ b/src/Entities/Entity.php
@@ -38,7 +38,7 @@ abstract class Entity
      */
     public function __construct($data, $bot_username = '')
     {
-        //Make sure we're not raw_data inception-ing
+        // Make sure we're not raw_data inception-ing
         if (array_key_exists('raw_data', $data)) {
             if ($data['raw_data'] === null) {
                 unset($data['raw_data']);
@@ -48,6 +48,7 @@ public function __construct($data, $bot_username = '')
         }
 
         $data['bot_username'] = $bot_username;
+
         $this->assignMemberVariables($data);
         $this->validate();
     }

From 84f9ffc535580bc2f8c91f2f86bc093be5530ae8 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 02:04:00 +0400
Subject: [PATCH 34/40] Fix failing tests

---
 src/Telegram.php                                            | 2 +-
 .../Entities/{ServerResponseTest.php => ResponseTest.php}   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
 rename tests/unit/Entities/{ServerResponseTest.php => ResponseTest.php} (98%)

diff --git a/src/Telegram.php b/src/Telegram.php
index 370c4e63a..3a87a6b37 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -323,7 +323,7 @@ public function createCommandObject($command)
             }
         }
 
-        throw new TelegramException('Command ' . $command . ' does not found');
+        return null;
     }
 
     /**
diff --git a/tests/unit/Entities/ServerResponseTest.php b/tests/unit/Entities/ResponseTest.php
similarity index 98%
rename from tests/unit/Entities/ServerResponseTest.php
rename to tests/unit/Entities/ResponseTest.php
index 155f21d7f..d39a1edc1 100644
--- a/tests/unit/Entities/ServerResponseTest.php
+++ b/tests/unit/Entities/ResponseTest.php
@@ -23,7 +23,7 @@
  * @license         http://opensource.org/licenses/mit-license.php  The MIT License (MIT)
  * @link            https://github.com/php-telegram-bot/core
  */
-class ServerResponseTest extends TestCase
+class ResponseTest extends TestCase
 {
     public function sendMessageOk()
     {
@@ -95,7 +95,7 @@ public function testSetWebhookOk()
         $server = new Response(json_decode($result, true), 'testbot');
 
         self::assertTrue($server->isOk());
-        self::assertTrue($server->getResult());
+        self::assertEquals([], $server->getResult());
         self::assertNull($server->getErrorCode());
         self::assertEquals('Webhook was set', $server->getDescription());
     }
@@ -264,7 +264,7 @@ public function testSetGeneralTestFakeResponse()
         $server = new Response($fake_response, 'testbot');
 
         self::assertTrue($server->isOk());
-        self::assertTrue($server->getResult());
+        self::assertEquals([], $server->getResult());
         self::assertNull($server->getErrorCode());
         self::assertEquals('', $server->getDescription());
 

From 806304c856b8ae11c76edecf259ec740f781536b Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 19:15:43 +0400
Subject: [PATCH 35/40] Add config class

---
 composer.json             |  1 +
 src/Config.php            | 63 +++++++++++++++++++++++++++++
 src/Telegram.php          | 42 +++++---------------
 tests/unit/ConfigTest.php | 84 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 159 insertions(+), 31 deletions(-)
 create mode 100644 src/Config.php
 create mode 100644 tests/unit/ConfigTest.php

diff --git a/composer.json b/composer.json
index 195137f76..5d0f1395c 100644
--- a/composer.json
+++ b/composer.json
@@ -30,6 +30,7 @@
         "illuminate/container": "5.4.*|5.5.*|5.6.*",
         "illuminate/support": "5.4.*|5.5.*|5.6.*",
         "illuminate/http": "5.4.*|5.5.*|5.6.*",
+        "illuminate/config": "5.4.*|5.5.*|5.6.*",
         "guzzlehttp/guzzle": "^6.3"
     },
     "require-dev": {
diff --git a/src/Config.php b/src/Config.php
new file mode 100644
index 000000000..4c11cf578
--- /dev/null
+++ b/src/Config.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * This file is part of the TelegramBot package.
+ *
+ * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Longman\TelegramBot;
+
+use Illuminate\Config\Repository;
+
+class Config extends Repository
+{
+    /**
+     * Config data.
+     *
+     * @var array
+     */
+    protected $data;
+
+    /**
+     * Create a new config instance.
+     *
+     * @param array $data
+     */
+    public function __construct(array $data)
+    {
+        $this->data = $data;
+    }
+
+    /**
+     * Get config parameter
+     *
+     * @param string $key
+     * @param mixed $default
+     * @return array|mixed|null
+     */
+    public function get($key = null, $default = null)
+    {
+        $array = $this->data;
+
+        if ($key === null) {
+            return $array;
+        }
+
+        if (array_key_exists($key, $array)) {
+            return $array[$key];
+        }
+
+        foreach (explode('.', $key) as $segment) {
+            if (is_array($array) && array_key_exists($segment, $array)) {
+                $array = $array[$segment];
+            } else {
+                return $default;
+            }
+        }
+
+        return $array;
+    }
+}
diff --git a/src/Telegram.php b/src/Telegram.php
index 3a87a6b37..ee2023669 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -65,13 +65,6 @@ class Telegram
      */
     protected $container;
 
-    /**
-     * Raw request data (json) for webhook methods
-     *
-     * @var string
-     */
-    protected $input;
-
     /**
      * Custom commands paths
      *
@@ -206,6 +199,17 @@ protected function registerContainer()
         $this->container = Container::getInstance();
 
         $this->container->instance(Telegram::class, $this);
+
+        $config = new Config([
+            'commands' => [
+                'paths' => [
+                    TB_BASE_COMMANDS_PATH . '/SystemCommands',
+                ],
+            ],
+        ]);
+        dump($config);
+        die;
+        $this->container->instance(Config::class, $config);
     }
 
     /**
@@ -326,30 +330,6 @@ public function createCommandObject($command)
         return null;
     }
 
-    /**
-     * Set custom input string for debug purposes
-     *
-     * @param string $input (json format)
-     *
-     * @return \Longman\TelegramBot\Telegram
-     */
-    public function setCustomInput($input)
-    {
-        $this->input = $input;
-
-        return $this;
-    }
-
-    /**
-     * Get custom input string for debug purposes
-     *
-     * @return string
-     */
-    public function getCustomInput()
-    {
-        return $this->input;
-    }
-
     /**
      * Get the ServerResponse of the last Command execution
      *
diff --git a/tests/unit/ConfigTest.php b/tests/unit/ConfigTest.php
new file mode 100644
index 000000000..cf2fc07af
--- /dev/null
+++ b/tests/unit/ConfigTest.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * This file is part of the TelegramBot package.
+ *
+ * (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Longman\TelegramBot\Tests\Unit;
+
+class ConfigTest extends AbstractTestCase
+{
+
+    /**
+     * @test
+     */
+    public function get_config_array()
+    {
+        $configData = [
+            'locales' => [
+                'ka' => [
+                    'name' => 'Georgian',
+                ],
+            ],
+        ];
+        $config = $this->getConfig($configData);
+
+        $this->assertEquals($configData, $config->get());
+    }
+
+    /**
+     * @test
+     */
+    public function set_get()
+    {
+        $config = [
+            'locales' => [
+                'ka' => [
+                    'name' => 'Georgian',
+                ],
+            ],
+        ];
+        $config = $this->getConfig($config);
+
+        $this->assertEquals('Georgian', $config->get('locales.ka.name'));
+    }
+
+    /**
+     * @test
+     */
+    public function get_default_value()
+    {
+        $config = [
+            'locales' => [
+                'ka' => [
+                    'name' => 'Georgian',
+                ],
+            ],
+        ];
+        $config = $this->getConfig($config);
+
+        $this->assertEquals('Thai', $config->get('locales.th.name', 'Thai'));
+    }
+
+    /**
+     * @test
+     */
+    public function table_name()
+    {
+        $config = [
+            'db' => [
+                'autosave' => true,
+                'connection' => 'mysql',
+                'texts_table' => 'texts',
+            ],
+        ];
+
+        $config = $this->getConfig($config);
+
+        $this->assertEquals('texts', $config->get('db.texts_table'));
+    }
+}

From 457da71973229e47e3a06aedef7f36461c545d2f Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 20:36:10 +0400
Subject: [PATCH 36/40] Introduce new Config class and move related functional
 from main app class

---
 src/Commands/AdminCommands/DebugCommand.php |  2 +
 src/Config.php                              | 97 +++++++++++++++------
 src/Telegram.php                            | 82 ++++++++---------
 tests/unit/ConfigTest.php                   | 96 +++++++++-----------
 4 files changed, 149 insertions(+), 128 deletions(-)

diff --git a/src/Commands/AdminCommands/DebugCommand.php b/src/Commands/AdminCommands/DebugCommand.php
index f69734cf3..3dc33ce3b 100644
--- a/src/Commands/AdminCommands/DebugCommand.php
+++ b/src/Commands/AdminCommands/DebugCommand.php
@@ -68,6 +68,8 @@ public function execute()
         $debug_info[] = sprintf('*Download path:* `%s`', $this->telegram->getDownloadPath() ?: '`_Not set_`');
         $debug_info[] = sprintf('*Upload path:* `%s`', $this->telegram->getUploadPath() ?: '`_Not set_`');
 
+        $config = $this->telegram->getConfig();
+
         // Commands paths.
         $debug_info[] = '*Commands paths:*';
         $debug_info[] = sprintf(
diff --git a/src/Config.php b/src/Config.php
index 4c11cf578..75a7f83b2 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -15,49 +15,96 @@
 class Config extends Repository
 {
     /**
-     * Config data.
+     * Add a single custom commands path
      *
-     * @var array
+     * @param string $path Custom commands path to add
+     * @param bool $before If the path should be prepended or appended to the list
+     *
+     * @return void
      */
-    protected $data;
+    public function addCommandsPath($path, $before = true)
+    {
+        $paths = $this->get('commands.paths', []);
+
+        if (! is_dir($path)) {
+            TelegramLog::error('Commands path "%s" does not exist.', $path);
+        } else if (! in_array($path, $paths, true)) {
+            if ($before) {
+                array_unshift($paths, $path);
+            } else {
+                $paths[] = $path;
+            }
+        }
+
+        $this->set('commands.paths', $paths);
+    }
 
     /**
-     * Create a new config instance.
+     * Add multiple custom commands paths
      *
-     * @param array $data
+     * @param array $paths Custom commands paths to add
+     * @param bool $before If the paths should be prepended or appended to the list
+     *
+     * @return void
      */
-    public function __construct(array $data)
+    public function addCommandsPaths(array $paths, $before = true)
     {
-        $this->data = $data;
+        foreach ($paths as $path) {
+            $this->addCommandsPath($path, $before);
+        }
     }
 
     /**
-     * Get config parameter
+     * Return the list of commands paths
      *
-     * @param string $key
-     * @param mixed $default
-     * @return array|mixed|null
+     * @return array
      */
-    public function get($key = null, $default = null)
+    public function getCommandsPaths()
     {
-        $array = $this->data;
+        return $this->get('commands.paths', []);
+    }
 
-        if ($key === null) {
-            return $array;
-        }
+    /**
+     * Enable a single Admin account
+     *
+     * @param integer $admin_id Single admin id
+     *
+     * @return void
+     */
+    public function addAdmin($admin_id)
+    {
+        $admins = $this->get('admins', []);
 
-        if (array_key_exists($key, $array)) {
-            return $array[$key];
+        if (! is_int($admin_id) || $admin_id <= 0) {
+            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
+        } else if (! in_array($admin_id, $admins, true)) {
+            $admins[] = $admin_id;
         }
 
-        foreach (explode('.', $key) as $segment) {
-            if (is_array($array) && array_key_exists($segment, $array)) {
-                $array = $array[$segment];
-            } else {
-                return $default;
-            }
+        $this->set('admins', $admins);
+    }
+
+    /**
+     * Enable a list of Admin Accounts
+     *
+     * @param array $admin_ids List of admin ids
+     *
+     * @return void
+     */
+    public function addAdmins(array $admin_ids)
+    {
+        foreach ($admin_ids as $admin_id) {
+            $this->addAdmin($admin_id);
         }
+    }
 
-        return $array;
+    /**
+     * Get list of admins
+     *
+     * @return array
+     */
+    public function getAdmins()
+    {
+        return $this->get('admins', []);
     }
 }
diff --git a/src/Telegram.php b/src/Telegram.php
index ee2023669..f31fa1860 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -65,13 +65,6 @@ class Telegram
      */
     protected $container;
 
-    /**
-     * Custom commands paths
-     *
-     * @var array
-     */
-    protected $commands_paths = [];
-
     /**
      * Current Update object
      *
@@ -114,13 +107,6 @@ class Telegram
      */
     protected $commands_config = [];
 
-    /**
-     * Admins list
-     *
-     * @var array
-     */
-    protected $admins_list = [];
-
     /**
      * ServerResponse of the last Command execution
      *
@@ -183,7 +169,9 @@ public function __construct($api_key, $bot_username = '')
 
         $this->registerContainer();
 
-        //Add default system commands path
+        $this->initializeConfig();
+
+        // Add default system commands path
         $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
 
         Client::initialize($this);
@@ -199,19 +187,30 @@ protected function registerContainer()
         $this->container = Container::getInstance();
 
         $this->container->instance(Telegram::class, $this);
+    }
+
+    /**
+     * Initialize config.
+     *
+     * @return void
+     */
+    protected function initializeConfig()
+    {
+        $config = new Config();
 
-        $config = new Config([
-            'commands' => [
-                'paths' => [
-                    TB_BASE_COMMANDS_PATH . '/SystemCommands',
-                ],
-            ],
-        ]);
-        dump($config);
-        die;
         $this->container->instance(Config::class, $config);
     }
 
+    /**
+     * Get config.
+     *
+     * @return \Longman\TelegramBot\Config
+     */
+    public function getConfig()
+    {
+        return $this->container->make(Config::class);
+    }
+
     /**
      * Get container instance.
      *
@@ -269,7 +268,8 @@ public function getCommandsList()
     {
         $commands = [];
 
-        foreach ($this->commands_paths as $path) {
+        $command_paths = $this->getConfig()->getCommandsPaths();
+        foreach ($command_paths as $path) {
             try {
                 // Get all "*Command.php" files
                 $files = new RegexIterator(
@@ -538,11 +538,7 @@ protected function sanitizeCommand($command)
      */
     public function enableAdmin($admin_id)
     {
-        if (! is_int($admin_id) || $admin_id <= 0) {
-            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
-        } else if (! in_array($admin_id, $this->admins_list, true)) {
-            $this->admins_list[] = $admin_id;
-        }
+        $this->getConfig()->addAdmin($admin_id);
 
         return $this;
     }
@@ -556,9 +552,7 @@ public function enableAdmin($admin_id)
      */
     public function enableAdmins(array $admin_ids)
     {
-        foreach ($admin_ids as $admin_id) {
-            $this->enableAdmin($admin_id);
-        }
+        $this->getConfig()->addAdmins($admin_ids);
 
         return $this;
     }
@@ -570,7 +564,7 @@ public function enableAdmins(array $admin_ids)
      */
     public function getAdminList()
     {
-        return $this->admins_list;
+        return $this->getConfig()->getAdmins();
     }
 
     /**
@@ -604,7 +598,8 @@ public function isAdmin($user_id = null)
             }
         }
 
-        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
+        $admins = $this->getConfig()->getAdmins();
+        return ($user_id === null) ? false : in_array($user_id, $admins, true);
     }
 
     /**
@@ -631,15 +626,7 @@ public function isDbEnabled()
      */
     public function addCommandsPath($path, $before = true)
     {
-        if (! is_dir($path)) {
-            TelegramLog::error('Commands path "%s" does not exist.', $path);
-        } else if (! in_array($path, $this->commands_paths, true)) {
-            if ($before) {
-                array_unshift($this->commands_paths, $path);
-            } else {
-                $this->commands_paths[] = $path;
-            }
-        }
+        $this->getConfig()->addCommandsPath($path, $before);
 
         return $this;
     }
@@ -654,9 +641,7 @@ public function addCommandsPath($path, $before = true)
      */
     public function addCommandsPaths(array $paths, $before = true)
     {
-        foreach ($paths as $path) {
-            $this->addCommandsPath($path, $before);
-        }
+        $this->getConfig()->addCommandsPaths($paths, $before);
 
         return $this;
     }
@@ -668,7 +653,8 @@ public function addCommandsPaths(array $paths, $before = true)
      */
     public function getCommandsPaths()
     {
-        return $this->commands_paths;
+
+        return $this->getConfig()->getCommandsPaths();
     }
 
     /**
diff --git a/tests/unit/ConfigTest.php b/tests/unit/ConfigTest.php
index cf2fc07af..1cb8ee240 100644
--- a/tests/unit/ConfigTest.php
+++ b/tests/unit/ConfigTest.php
@@ -10,75 +10,61 @@
 
 namespace Longman\TelegramBot\Tests\Unit;
 
-class ConfigTest extends AbstractTestCase
-{
+use Longman\TelegramBot\Config;
 
-    /**
-     * @test
-     */
-    public function get_config_array()
+class ConfigTest extends TestCase
+{
+    public function testAddCommandsPathsBefore()
     {
-        $configData = [
-            'locales' => [
-                'ka' => [
-                    'name' => 'Georgian',
-                ],
-            ],
-        ];
-        $config = $this->getConfig($configData);
+        $config = new Config();
 
-        $this->assertEquals($configData, $config->get());
-    }
-
-    /**
-     * @test
-     */
-    public function set_get()
-    {
-        $config = [
-            'locales' => [
-                'ka' => [
-                    'name' => 'Georgian',
-                ],
-            ],
+        $paths = [
+            '/tmp/php-telegram-bot-custom-commands-config-1',
+            '/tmp/php-telegram-bot-custom-commands-config-2',
+            '/tmp/php-telegram-bot-custom-commands-config-3',
         ];
-        $config = $this->getConfig($config);
+        foreach ($paths as $path) {
+            mkdir($path);
+        }
 
-        $this->assertEquals('Georgian', $config->get('locales.ka.name'));
+        $config->addCommandsPaths($paths);
+        foreach ($paths as $path) {
+            rmdir($path);
+        }
+
+        $this->assertEquals(array_reverse($paths), $config->getCommandsPaths());
     }
 
-    /**
-     * @test
-     */
-    public function get_default_value()
+    public function testAddCommandsPathsAfter()
     {
-        $config = [
-            'locales' => [
-                'ka' => [
-                    'name' => 'Georgian',
-                ],
-            ],
+        $config = new Config();
+
+        $paths = [
+            '/tmp/php-telegram-bot-custom-commands-config-1',
+            '/tmp/php-telegram-bot-custom-commands-config-2',
+            '/tmp/php-telegram-bot-custom-commands-config-3',
         ];
-        $config = $this->getConfig($config);
+        foreach ($paths as $path) {
+            mkdir($path);
+        }
+
+        $config->addCommandsPaths($paths, false);
+        foreach ($paths as $path) {
+            rmdir($path);
+        }
 
-        $this->assertEquals('Thai', $config->get('locales.th.name', 'Thai'));
+        $this->assertEquals($paths, $config->getCommandsPaths());
     }
 
-    /**
-     * @test
-     */
-    public function table_name()
+    public function testAddAdmins()
     {
-        $config = [
-            'db' => [
-                'autosave' => true,
-                'connection' => 'mysql',
-                'texts_table' => 'texts',
-            ],
-        ];
+        $config = new Config();
+
+        $admins = [1, 2, 3];
 
-        $config = $this->getConfig($config);
+        $config->addAdmins($admins);
 
-        $this->assertEquals('texts', $config->get('db.texts_table'));
+        $this->assertEquals($admins, $config->getAdmins());
     }
+
 }

From b18d216ea62bf68a31a831132441a8ba37c57fb7 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 20:36:37 +0400
Subject: [PATCH 37/40] Move botan integration in to separate namespace

---
 src/{ => Extensions/Botan}/Botan.php   | 43 +++++++++++++++++++++-----
 src/{ => Extensions/Botan}/BotanDB.php |  9 +++---
 src/Telegram.php                       | 16 +++-------
 3 files changed, 46 insertions(+), 22 deletions(-)
 rename src/{ => Extensions/Botan}/Botan.php (88%)
 rename src/{ => Extensions/Botan}/BotanDB.php (92%)

diff --git a/src/Botan.php b/src/Extensions/Botan/Botan.php
similarity index 88%
rename from src/Botan.php
rename to src/Extensions/Botan/Botan.php
index 03cc7201f..87ec177f8 100644
--- a/src/Botan.php
+++ b/src/Extensions/Botan/Botan.php
@@ -8,12 +8,13 @@
  * file that was distributed with this source code.
  */
 
-namespace Longman\TelegramBot;
+namespace Longman\TelegramBot\Extensions\Botan;
 
 use GuzzleHttp\Client;
 use GuzzleHttp\Exception\RequestException;
 use Longman\TelegramBot\Entities\Update;
 use Longman\TelegramBot\Exception\TelegramException;
+use Longman\TelegramBot\TelegramLog;
 
 /**
  * Class Botan
@@ -54,11 +55,18 @@ class Botan
      */
     public static $command = '';
 
+    /**
+     * Enabled
+     *
+     * @var bool
+     */
+    protected static $enabled = false;
+
     /**
      * Initialize Botan
      *
      * @param  string $token
-     * @param  array  $options
+     * @param  array $options
      *
      * @throws \Longman\TelegramBot\Exception\TelegramException
      */
@@ -74,7 +82,7 @@ public static function initializeBotan($token, array $options = [])
 
         $options = array_merge($options_default, $options);
 
-        if (!is_numeric($options['timeout'])) {
+        if (! is_numeric($options['timeout'])) {
             throw new TelegramException('Timeout must be a number!');
         }
 
@@ -102,7 +110,7 @@ public static function lock($command = '')
      * Track function
      *
      * @param \Longman\TelegramBot\Entities\Update $update
-     * @param string                               $command
+     * @param string $command
      *
      * @return bool|string
      * @throws \Longman\TelegramBot\Exception\TelegramException
@@ -145,7 +153,7 @@ public static function track(Update $update, $command = '')
                     if ($entity->getType() === 'bot_command' && $entity->getOffset() === 0) {
                         if ($command === 'generic') {
                             $command = 'Generic';
-                        } elseif ($command === 'genericmessage') {  // This should not happen as it equals normal message but leaving it as a fail-safe
+                        } else if ($command === 'genericmessage') {  // This should not happen as it equals normal message but leaving it as a fail-safe
                             $command = 'Generic Message';
                         } else {
                             $command = '/' . $command;
@@ -190,7 +198,7 @@ public static function track(Update $update, $command = '')
 
         $responseData = json_decode($result, true);
 
-        if (!$responseData || $responseData['status'] !== 'accepted') {
+        if (! $responseData || $responseData['status'] !== 'accepted') {
             TelegramLog::debug('Botan.io stats report failed: %s', $result ?: 'empty response');
 
             return false;
@@ -202,7 +210,7 @@ public static function track(Update $update, $command = '')
     /**
      * Url Shortener function
      *
-     * @param string  $url
+     * @param string $url
      * @param integer $user_id
      *
      * @return string
@@ -247,4 +255,25 @@ public static function shortenUrl($url, $user_id)
 
         return $result;
     }
+
+    /**
+     * Return enabled status
+     *
+     * @return bool
+     */
+    public static function isEnabled()
+    {
+        return self::$enabled;
+    }
+
+    /**
+     * Set enabled status
+     *
+     * @param $enabled bool
+     * @return void
+     */
+    public static function setEnabled($enabled)
+    {
+        self::$enabled = $enabled;
+    }
 }
diff --git a/src/BotanDB.php b/src/Extensions/Botan/BotanDB.php
similarity index 92%
rename from src/BotanDB.php
rename to src/Extensions/Botan/BotanDB.php
index 6e0093044..20f17afa7 100644
--- a/src/BotanDB.php
+++ b/src/Extensions/Botan/BotanDB.php
@@ -8,9 +8,10 @@
  * file that was distributed with this source code.
  */
 
-namespace Longman\TelegramBot;
+namespace Longman\TelegramBot\Extensions\Botan;
 
 use Exception;
+use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Exception\TelegramException;
 
 /**
@@ -23,7 +24,7 @@ class BotanDB extends DB
      */
     public static function initializeBotanDb()
     {
-        if (!defined('TB_BOTAN_SHORTENER')) {
+        if (! defined('TB_BOTAN_SHORTENER')) {
             define('TB_BOTAN_SHORTENER', self::$table_prefix . 'botan_shortener');
         }
     }
@@ -39,7 +40,7 @@ public static function initializeBotanDb()
      */
     public static function selectShortUrl($url, $user_id)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
@@ -75,7 +76,7 @@ public static function selectShortUrl($url, $user_id)
      */
     public static function insertShortUrl($url, $user_id, $short_url)
     {
-        if (!self::isDbConnected()) {
+        if (! self::isDbConnected()) {
             return false;
         }
 
diff --git a/src/Telegram.php b/src/Telegram.php
index f31fa1860..a4bf7f62f 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -19,6 +19,7 @@
 use Longman\TelegramBot\Console\Kernel as ConsoleKernel;
 use Longman\TelegramBot\Entities\Update;
 use Longman\TelegramBot\Exception\TelegramException;
+use Longman\TelegramBot\Extensions\Botan\Botan;
 use Longman\TelegramBot\Http\Client;
 use Longman\TelegramBot\Http\Kernel;
 use Longman\TelegramBot\Http\Request;
@@ -114,13 +115,6 @@ class Telegram
      */
     protected $last_command_response;
 
-    /**
-     * Botan.io integration
-     *
-     * @var boolean
-     */
-    protected $botan_enabled = false;
-
     /**
      * Check if runCommands() is running in this session
      *
@@ -500,7 +494,7 @@ public function executeCommand($command)
             $this->last_command_response = $this->executeCommand('generic');
         } else {
             // Botan.io integration, make sure only the actual command user executed is reported
-            if ($this->botan_enabled) {
+            if (Botan::isEnabled()) {
                 Botan::lock($command);
             }
 
@@ -509,7 +503,7 @@ public function executeCommand($command)
             $this->last_command_response = $command_obj->preExecute();
 
             // Botan.io integration, send report after executing the command
-            if ($this->botan_enabled) {
+            if (Botan::isEnabled()) {
                 Botan::track($this->update, $command);
             }
         }
@@ -872,7 +866,7 @@ protected function ucfirstUnicode($str, $encoding = 'UTF-8')
     public function enableBotan($token, array $options = [])
     {
         Botan::initializeBotan($token, $options);
-        $this->botan_enabled = true;
+        Botan::setEnabled(true);
 
         return $this;
     }
@@ -905,7 +899,7 @@ public function runCommands($commands)
         }
 
         $this->run_commands = true;
-        $this->botan_enabled = false;   // Force disable Botan.io integration, we don't want to track self-executed commands!
+        Botan::setEnabled(false);   // Force disable Botan.io integration, we don't want to track self-executed commands!
 
         $result = Client::getMe();
 

From 6227c407d2ec2b03f932ca935f61023b8640bc16 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 21:22:08 +0400
Subject: [PATCH 38/40] Improve config

---
 src/Config.php            | 48 +++++++++++++++++++++++++++++++++++++--
 tests/unit/ConfigTest.php | 23 ++++++++++++++++++-
 2 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/src/Config.php b/src/Config.php
index 75a7f83b2..bfb6690e5 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -27,7 +27,7 @@ public function addCommandsPath($path, $before = true)
         $paths = $this->get('commands.paths', []);
 
         if (! is_dir($path)) {
-            TelegramLog::error('Commands path "%s" does not exist.', $path);
+            Logger::error('Commands path "%s" does not exist.', $path);
         } else if (! in_array($path, $paths, true)) {
             if ($before) {
                 array_unshift($paths, $path);
@@ -76,7 +76,7 @@ public function addAdmin($admin_id)
         $admins = $this->get('admins', []);
 
         if (! is_int($admin_id) || $admin_id <= 0) {
-            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
+            Logger::error('Invalid value "%s" for admin.', $admin_id);
         } else if (! in_array($admin_id, $admins, true)) {
             $admins[] = $admin_id;
         }
@@ -107,4 +107,48 @@ public function getAdmins()
     {
         return $this->get('admins', []);
     }
+
+    /**
+     * Set custom upload path
+     *
+     * @param string $path Custom upload path
+     *
+     * @return void
+     */
+    public function setUploadPath($path)
+    {
+        $this->set('upload_path', $path);
+    }
+
+    /**
+     * Get custom upload path
+     *
+     * @return string
+     */
+    public function getUploadPath()
+    {
+        return $this->get('upload_path', '');
+    }
+
+    /**
+     * Set custom download path
+     *
+     * @param string $path Custom download path
+     *
+     * @return void
+     */
+    public function setDownloadPath($path)
+    {
+        $this->set('download_path', $path);
+    }
+
+    /**
+     * Get custom download path
+     *
+     * @return string
+     */
+    public function getDownloadPath()
+    {
+        return $this->get('download_path', '');
+    }
 }
diff --git a/tests/unit/ConfigTest.php b/tests/unit/ConfigTest.php
index 1cb8ee240..d283ea737 100644
--- a/tests/unit/ConfigTest.php
+++ b/tests/unit/ConfigTest.php
@@ -56,7 +56,7 @@ public function testAddCommandsPathsAfter()
         $this->assertEquals($paths, $config->getCommandsPaths());
     }
 
-    public function testAddAdmins()
+    public function testAdmins()
     {
         $config = new Config();
 
@@ -67,4 +67,25 @@ public function testAddAdmins()
         $this->assertEquals($admins, $config->getAdmins());
     }
 
+    public function testUploadPath()
+    {
+        $config = new Config();
+
+        $path = '/some/path';
+
+        $config->setUploadPath($path);
+
+        $this->assertEquals($path, $config->getUploadPath());
+    }
+
+    public function testDownloadPath()
+    {
+        $config = new Config();
+
+        $path = '/some/path';
+
+        $config->setDownloadPath($path);
+
+        $this->assertEquals($path, $config->getDownloadPath());
+    }
 }

From e550a76cd9cb88bb253a8919b3c368a5662a0c94 Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 21:22:22 +0400
Subject: [PATCH 39/40] Rename Logger class

---
 src/Commands/AdminCommands/CleanupCommand.php |  4 +-
 src/Commands/Command.php                      |  2 +-
 src/Console/Kernel.php                        |  4 +-
 src/DB.php                                    | 36 ++++++++++++--
 src/Entities/Entity.php                       |  2 +-
 src/Extensions/Botan/Botan.php                |  8 +--
 src/Http/Client.php                           | 12 ++---
 src/{TelegramLog.php => Logger.php}           | 16 +++---
 src/Telegram.php                              | 49 +++----------------
 tests/unit/TelegramLogTest.php                | 48 +++++++++---------
 10 files changed, 87 insertions(+), 94 deletions(-)
 rename src/{TelegramLog.php => Logger.php} (93%)

diff --git a/src/Commands/AdminCommands/CleanupCommand.php b/src/Commands/AdminCommands/CleanupCommand.php
index 82acf0dfc..d8d60a2f8 100644
--- a/src/Commands/AdminCommands/CleanupCommand.php
+++ b/src/Commands/AdminCommands/CleanupCommand.php
@@ -14,7 +14,7 @@
 use Longman\TelegramBot\DB;
 use Longman\TelegramBot\Exception\TelegramException;
 use Longman\TelegramBot\Http\Client;
-use Longman\TelegramBot\TelegramLog;
+use Longman\TelegramBot\Logger;
 use PDOException;
 
 /**
@@ -386,7 +386,7 @@ public function execute()
                 if ($dbq = $pdo->query($query)) {
                     $rows += $dbq->rowCount();
                 } else {
-                    TelegramLog::error('Error while executing query: ' . $query);
+                    Logger::error('Error while executing query: ' . $query);
                 }
             }
 
diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index 2e4d32d59..2aec66e69 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -149,7 +149,7 @@ public function setUpdate(Update $update = null)
      */
     public function preExecute()
     {
-        if ($this->need_mysql && !($this->telegram->isDbEnabled() && DB::isDbConnected())) {
+        if ($this->need_mysql && !(DB::isEnabled() && DB::isDbConnected())) {
             return $this->executeNoDb();
         }
 
diff --git a/src/Console/Kernel.php b/src/Console/Kernel.php
index 85f6e3ab2..fc6753005 100644
--- a/src/Console/Kernel.php
+++ b/src/Console/Kernel.php
@@ -71,7 +71,7 @@ public function handle(Request $request, $limit = null, $timeout = null)
         }
 
         if ($this->app->last_update_id !== null) {
-            $offset = $this->app->last_update_id + 1;    //As explained in the telegram bot API documentation
+            $offset = $this->app->last_update_id + 1;    // As explained in the telegram bot API documentation
         }
 
         $response = Client::getUpdates(
@@ -91,7 +91,7 @@ public function handle(Request $request, $limit = null, $timeout = null)
                 $this->app->processUpdate($result);
             }
 
-            if (! DB::isDbConnected() && ! $custom_input && $this->app->last_update_id !== null && $offset === 0) {
+            if (! DB::isDbConnected() && $this->app->last_update_id !== null && $offset === 0) {
                 // Mark update(s) as read after handling
                 Client::getUpdates(
                     [
diff --git a/src/DB.php b/src/DB.php
index f9968e940..d1a0707f2 100644
--- a/src/DB.php
+++ b/src/DB.php
@@ -31,28 +31,35 @@ class DB
      *
      * @var array
      */
-    static protected $mysql_credentials = [];
+    protected static $mysql_credentials = [];
 
     /**
      * PDO object
      *
      * @var PDO
      */
-    static protected $pdo;
+    protected static $pdo;
 
     /**
      * Table prefix
      *
      * @var string
      */
-    static protected $table_prefix;
+    protected static $table_prefix;
 
     /**
      * Telegram class object
      *
      * @var Telegram
      */
-    static protected $telegram;
+    protected static $telegram;
+
+    /**
+     * Enabled
+     *
+     * @var bool
+     */
+    protected static $enabled = false;
 
     /**
      * Initialize
@@ -1189,4 +1196,25 @@ public static function update($table, array $fields_values, array $where_fields_
             throw new TelegramException($e->getMessage());
         }
     }
+
+    /**
+     * Return enabled status
+     *
+     * @return bool
+     */
+    public static function isEnabled()
+    {
+        return self::$enabled;
+    }
+
+    /**
+     * Set enabled status
+     *
+     * @param $enabled bool
+     * @return void
+     */
+    public static function setEnabled($enabled)
+    {
+        self::$enabled = $enabled;
+    }
 }
diff --git a/src/Entities/Entity.php b/src/Entities/Entity.php
index f7d853fd3..b40298900 100644
--- a/src/Entities/Entity.php
+++ b/src/Entities/Entity.php
@@ -12,7 +12,7 @@
 
 use Exception;
 use Longman\TelegramBot\Entities\InlineQuery\InlineEntity;
-use Longman\TelegramBot\TelegramLog;
+use Longman\TelegramBot\Logger;
 
 /**
  * Class Entity
diff --git a/src/Extensions/Botan/Botan.php b/src/Extensions/Botan/Botan.php
index 87ec177f8..bbb899a06 100644
--- a/src/Extensions/Botan/Botan.php
+++ b/src/Extensions/Botan/Botan.php
@@ -14,7 +14,7 @@
 use GuzzleHttp\Exception\RequestException;
 use Longman\TelegramBot\Entities\Update;
 use Longman\TelegramBot\Exception\TelegramException;
-use Longman\TelegramBot\TelegramLog;
+use Longman\TelegramBot\Logger;
 
 /**
  * Class Botan
@@ -167,7 +167,7 @@ public static function track(Update $update, $command = '')
         }
 
         if (empty($event_name)) {
-            TelegramLog::error('Botan.io stats report failed, no suitable update object found!');
+            Logger::error('Botan.io stats report failed, no suitable update object found!');
 
             return false;
         }
@@ -199,7 +199,7 @@ public static function track(Update $update, $command = '')
         $responseData = json_decode($result, true);
 
         if (! $responseData || $responseData['status'] !== 'accepted') {
-            TelegramLog::debug('Botan.io stats report failed: %s', $result ?: 'empty response');
+            Logger::debug('Botan.io stats report failed: %s', $result ?: 'empty response');
 
             return false;
         }
@@ -246,7 +246,7 @@ public static function shortenUrl($url, $user_id)
         }
 
         if (filter_var($result, FILTER_VALIDATE_URL) === false) {
-            TelegramLog::debug('Botan.io URL shortening failed for "%s": %s', $url, $result ?: 'empty response');
+            Logger::debug('Botan.io URL shortening failed for "%s": %s', $url, $result ?: 'empty response');
 
             return $url;
         }
diff --git a/src/Http/Client.php b/src/Http/Client.php
index ff7b55130..76d4ea909 100644
--- a/src/Http/Client.php
+++ b/src/Http/Client.php
@@ -16,7 +16,7 @@
 use Longman\TelegramBot\Entities\File;
 use Longman\TelegramBot\Exception\TelegramException;
 use Longman\TelegramBot\Telegram;
-use Longman\TelegramBot\TelegramLog;
+use Longman\TelegramBot\Logger;
 
 /**
  * Class Client
@@ -380,7 +380,7 @@ public static function execute($action, array $data = [])
 
         $result = null;
         $request_params = self::setUpRequestParams($data);
-        $request_params['debug'] = TelegramLog::getDebugLogTempStream();
+        $request_params['debug'] = Logger::getDebugLogTempStream();
 
         try {
             $response = self::$client->post(
@@ -391,13 +391,13 @@ public static function execute($action, array $data = [])
 
             // Logging getUpdates Update
             if ($action === 'getUpdates') {
-                TelegramLog::update($result);
+                Logger::update($result);
             }
         } catch (RequestException $e) {
             $result = ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
         } finally {
             // Logging verbose debug output
-            TelegramLog::endDebugLogTempStream('Verbose HTTP Request output:' . PHP_EOL . '%s' . PHP_EOL);
+            Logger::endDebugLogTempStream('Verbose HTTP Request output:' . PHP_EOL . '%s' . PHP_EOL);
         }
 
         return $result;
@@ -427,7 +427,7 @@ public static function downloadFile(File $file)
             throw new TelegramException('Directory ' . $file_dir . ' can\'t be created');
         }
 
-        $debug_handle = TelegramLog::getDebugLogTempStream();
+        $debug_handle = Logger::getDebugLogTempStream();
 
         try {
             self::$client->get(
@@ -440,7 +440,7 @@ public static function downloadFile(File $file)
             return ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
         } finally {
             //Logging verbose debug output
-            TelegramLog::endDebugLogTempStream('Verbose HTTP File Download Request output:' . PHP_EOL . '%s' . PHP_EOL);
+            Logger::endDebugLogTempStream('Verbose HTTP File Download Request output:' . PHP_EOL . '%s' . PHP_EOL);
         }
     }
 
diff --git a/src/TelegramLog.php b/src/Logger.php
similarity index 93%
rename from src/TelegramLog.php
rename to src/Logger.php
index 57880711b..fe3830332 100644
--- a/src/TelegramLog.php
+++ b/src/Logger.php
@@ -13,9 +13,9 @@
 use Longman\TelegramBot\Exception\TelegramLogException;
 use Monolog\Formatter\LineFormatter;
 use Monolog\Handler\StreamHandler;
-use Monolog\Logger;
+use Monolog\Logger as MonologLogger;
 
-class TelegramLog
+class Logger
 {
     /**
      * Monolog instance
@@ -66,7 +66,7 @@ class TelegramLog
      *
      * @return \Monolog\Logger
      */
-    public static function initialize(Logger $external_monolog = null)
+    public static function initialize(MonologLogger $external_monolog = null)
     {
         if (self::$monolog === null) {
             if ($external_monolog !== null) {
@@ -81,7 +81,7 @@ public static function initialize(Logger $external_monolog = null)
                     }
                 }
             } else {
-                self::$monolog = new Logger('bot_log');
+                self::$monolog = new MonologLogger('bot_log');
             }
         }
 
@@ -107,7 +107,7 @@ public static function initErrorLog($path)
         self::$error_log_path = $path;
 
         return self::$monolog->pushHandler(
-            (new StreamHandler(self::$error_log_path, Logger::ERROR))
+            (new StreamHandler(self::$error_log_path, MonologLogger::ERROR))
                 ->setFormatter(new LineFormatter(null, null, true))
         );
     }
@@ -131,7 +131,7 @@ public static function initDebugLog($path)
         self::$debug_log_path = $path;
 
         return self::$monolog->pushHandler(
-            (new StreamHandler(self::$debug_log_path, Logger::DEBUG))
+            (new StreamHandler(self::$debug_log_path, MonologLogger::DEBUG))
                 ->setFormatter(new LineFormatter(null, null, true))
         );
     }
@@ -186,10 +186,10 @@ public static function initUpdateLog($path)
         self::$update_log_path = $path;
 
         if (self::$monolog_update === null) {
-            self::$monolog_update = new Logger('bot_update_log');
+            self::$monolog_update = new MonologLogger('bot_update_log');
 
             self::$monolog_update->pushHandler(
-                (new StreamHandler(self::$update_log_path, Logger::INFO))
+                (new StreamHandler(self::$update_log_path, MonologLogger::INFO))
                     ->setFormatter(new LineFormatter('%message%' . PHP_EOL))
             );
         }
diff --git a/src/Telegram.php b/src/Telegram.php
index a4bf7f62f..2bb53774c 100644
--- a/src/Telegram.php
+++ b/src/Telegram.php
@@ -73,27 +73,6 @@ class Telegram
      */
     protected $update;
 
-    /**
-     * Upload path
-     *
-     * @var string
-     */
-    protected $upload_path;
-
-    /**
-     * Download path
-     *
-     * @var string
-     */
-    protected $download_path;
-
-    /**
-     * MySQL integration
-     *
-     * @var boolean
-     */
-    protected $mysql_enabled = false;
-
     /**
      * PDO object
      *
@@ -228,8 +207,8 @@ public function getContainer()
     public function enableMySql(array $credential, $table_prefix = null, $encoding = 'utf8mb4')
     {
         $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
+        DB::setEnabled(true);
         ConversationDB::initializeConversation();
-        $this->mysql_enabled = true;
 
         return $this;
     }
@@ -246,8 +225,8 @@ public function enableMySql(array $credential, $table_prefix = null, $encoding =
     public function enableExternalMySql($external_pdo_connection, $table_prefix = null)
     {
         $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
+        DB::setEnabled(true);
         ConversationDB::initializeConversation();
-        $this->mysql_enabled = true;
 
         return $this;
     }
@@ -461,7 +440,7 @@ public function processUpdate(Update $update)
         // Make sure we don't try to process update that was already processed
         $last_id = DB::selectTelegramUpdate(1, $update->getUpdateId());
         if ($last_id && count($last_id) === 1) {
-            TelegramLog::debug('Duplicate update received, processing aborted!');
+            Logger::debug('Duplicate update received, processing aborted!');
 
             return new Response(['ok' => true, 'result' => true]);
         }
@@ -596,20 +575,6 @@ public function isAdmin($user_id = null)
         return ($user_id === null) ? false : in_array($user_id, $admins, true);
     }
 
-    /**
-     * Check if user required the db connection
-     *
-     * @return bool
-     */
-    public function isDbEnabled()
-    {
-        if ($this->mysql_enabled) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
     /**
      * Add a single custom commands path
      *
@@ -660,7 +625,7 @@ public function getCommandsPaths()
      */
     public function setUploadPath($path)
     {
-        $this->upload_path = $path;
+        $this->getConfig()->setUploadPath($path);
 
         return $this;
     }
@@ -672,7 +637,7 @@ public function setUploadPath($path)
      */
     public function getUploadPath()
     {
-        return $this->upload_path;
+        return $this->getConfig()->getUploadPath();
     }
 
     /**
@@ -684,7 +649,7 @@ public function getUploadPath()
      */
     public function setDownloadPath($path)
     {
-        $this->download_path = $path;
+        $this->getConfig()->setDownloadPath($path);
 
         return $this;
     }
@@ -696,7 +661,7 @@ public function setDownloadPath($path)
      */
     public function getDownloadPath()
     {
-        return $this->download_path;
+        return $this->getConfig()->getDownloadPath();
     }
 
     /**
diff --git a/tests/unit/TelegramLogTest.php b/tests/unit/TelegramLogTest.php
index 069e9dabd..a983975d9 100644
--- a/tests/unit/TelegramLogTest.php
+++ b/tests/unit/TelegramLogTest.php
@@ -10,7 +10,7 @@
 
 namespace Longman\TelegramBot\Tests\Unit;
 
-use Longman\TelegramBot\TelegramLog;
+use Longman\TelegramBot\Logger;
 use Monolog\Handler\StreamHandler;
 use Monolog\Logger;
 
@@ -36,7 +36,7 @@ class TelegramLogTest extends TestCase
     protected function setUp()
     {
         // Make sure no monolog instance is set before each test.
-        TestHelpers::setStaticProperty('Longman\TelegramBot\TelegramLog', 'monolog', null);
+        TestHelpers::setStaticProperty('Longman\TelegramBot\Logger', 'monolog', null);
     }
 
     protected function tearDown()
@@ -52,7 +52,7 @@ protected function tearDown()
      */
     public function testNewInstanceWithoutErrorPath()
     {
-        TelegramLog::initErrorLog('');
+        Logger::initErrorLog('');
     }
 
     /**
@@ -60,7 +60,7 @@ public function testNewInstanceWithoutErrorPath()
      */
     public function testNewInstanceWithoutDebugPath()
     {
-        TelegramLog::initDebugLog('');
+        Logger::initDebugLog('');
     }
 
     /**
@@ -68,17 +68,17 @@ public function testNewInstanceWithoutDebugPath()
      */
     public function testNewInstanceWithoutUpdatePath()
     {
-        TelegramLog::initUpdateLog('');
+        Logger::initUpdateLog('');
     }
 
     public function testErrorStream()
     {
         $file = self::$logfiles['error'];
         $this->assertFileNotExists($file);
-        TelegramLog::initErrorLog($file);
-        TelegramLog::error('my error');
-        TelegramLog::error('my 50% error');
-        TelegramLog::error('my %s error', 'placeholder');
+        Logger::initErrorLog($file);
+        Logger::error('my error');
+        Logger::error('my 50% error');
+        Logger::error('my %s error', 'placeholder');
         $this->assertFileExists($file);
         $error_log = file_get_contents($file);
         $this->assertContains('bot_log.ERROR: my error', $error_log);
@@ -90,10 +90,10 @@ public function testDebugStream()
     {
         $file = self::$logfiles['debug'];
         $this->assertFileNotExists($file);
-        TelegramLog::initDebugLog($file);
-        TelegramLog::debug('my debug');
-        TelegramLog::debug('my 50% debug');
-        TelegramLog::debug('my %s debug', 'placeholder');
+        Logger::initDebugLog($file);
+        Logger::debug('my debug');
+        Logger::debug('my 50% debug');
+        Logger::debug('my %s debug', 'placeholder');
         $this->assertFileExists($file);
         $debug_log = file_get_contents($file);
         $this->assertContains('bot_log.DEBUG: my debug', $debug_log);
@@ -105,10 +105,10 @@ public function testUpdateStream()
     {
         $file = self::$logfiles['update'];
         $this->assertFileNotExists($file);
-        TelegramLog::initUpdateLog($file);
-        TelegramLog::update('my update');
-        TelegramLog::update('my 50% update');
-        TelegramLog::update('my %s update', 'placeholder');
+        Logger::initUpdateLog($file);
+        Logger::update('my update');
+        Logger::update('my 50% update');
+        Logger::update('my %s update', 'placeholder');
         $this->assertFileExists($file);
         $debug_log = file_get_contents($file);
         $this->assertContains('my update', $debug_log);
@@ -125,13 +125,13 @@ public function testExternalStream()
         $external_monolog->pushHandler(new StreamHandler($file, Logger::ERROR));
         $external_monolog->pushHandler(new StreamHandler($file, Logger::DEBUG));
 
-        TelegramLog::initialize($external_monolog);
-        TelegramLog::error('my error');
-        TelegramLog::error('my 50% error');
-        TelegramLog::error('my %s error', 'placeholder');
-        TelegramLog::debug('my debug');
-        TelegramLog::debug('my 50% debug');
-        TelegramLog::debug('my %s debug', 'placeholder');
+        Logger::initialize($external_monolog);
+        Logger::error('my error');
+        Logger::error('my 50% error');
+        Logger::error('my %s error', 'placeholder');
+        Logger::debug('my debug');
+        Logger::debug('my 50% debug');
+        Logger::debug('my %s debug', 'placeholder');
 
         $this->assertFileExists($file);
         $file_contents = file_get_contents($file);

From 84977ea7793b89c3abc26dae8bc7f1a02cabc84a Mon Sep 17 00:00:00 2001
From: Avtandil Kikabidze <akalongman@gmail.com>
Date: Sun, 22 Apr 2018 21:24:10 +0400
Subject: [PATCH 40/40] Rename logger test

---
 tests/unit/{TelegramLogTest.php => LoggerTest.php} | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
 rename tests/unit/{TelegramLogTest.php => LoggerTest.php} (96%)

diff --git a/tests/unit/TelegramLogTest.php b/tests/unit/LoggerTest.php
similarity index 96%
rename from tests/unit/TelegramLogTest.php
rename to tests/unit/LoggerTest.php
index a983975d9..78fedb3ac 100644
--- a/tests/unit/TelegramLogTest.php
+++ b/tests/unit/LoggerTest.php
@@ -12,7 +12,7 @@
 
 use Longman\TelegramBot\Logger;
 use Monolog\Handler\StreamHandler;
-use Monolog\Logger;
+use Monolog\Logger as MonologLogger;
 
 /**
  * @package         TelegramTest
@@ -21,7 +21,7 @@
  * @license         http://opensource.org/licenses/mit-license.php  The MIT License (MIT)
  * @link            https://github.com/php-telegram-bot/core
  */
-class TelegramLogTest extends TestCase
+class LoggerTest extends TestCase
 {
     /**
      * @var array Dummy logfile paths
@@ -121,9 +121,9 @@ public function testExternalStream()
         $file = self::$logfiles['external'];
         $this->assertFileNotExists($file);
 
-        $external_monolog = new Logger('bot_update_log');
-        $external_monolog->pushHandler(new StreamHandler($file, Logger::ERROR));
-        $external_monolog->pushHandler(new StreamHandler($file, Logger::DEBUG));
+        $external_monolog = new MonologLogger('bot_update_log');
+        $external_monolog->pushHandler(new StreamHandler($file, MonologLogger::ERROR));
+        $external_monolog->pushHandler(new StreamHandler($file, MonologLogger::DEBUG));
 
         Logger::initialize($external_monolog);
         Logger::error('my error');
