Преглед изворни кода

added framework for php-json-logger
added dependency ramsey/uuid for php-json-logger
added dependency monolog/monolog for php-json-logger

CauseFX пре 4 година
родитељ
комит
19b7b1e70d
100 измењених фајлова са 12264 додато и 8 уклоњено
  1. 2 1
      api/composer.json
  2. 241 1
      api/composer.lock
  3. 43 2
      api/vendor/composer/InstalledVersions.php
  4. 2 1
      api/vendor/composer/autoload_files.php
  5. 3 0
      api/vendor/composer/autoload_psr4.php
  6. 23 1
      api/vendor/composer/autoload_static.php
  7. 249 0
      api/vendor/composer/installed.json
  8. 43 2
      api/vendor/composer/installed.php
  9. 423 0
      api/vendor/monolog/monolog/CHANGELOG.md
  10. 19 0
      api/vendor/monolog/monolog/LICENSE
  11. 94 0
      api/vendor/monolog/monolog/README.md
  12. 58 0
      api/vendor/monolog/monolog/composer.json
  13. 16 0
      api/vendor/monolog/monolog/phpstan.neon.dist
  14. 239 0
      api/vendor/monolog/monolog/src/Monolog/ErrorHandler.php
  15. 78 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php
  16. 89 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php
  17. 116 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php
  18. 88 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php
  19. 36 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php
  20. 138 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php
  21. 142 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php
  22. 212 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php
  23. 181 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
  24. 47 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php
  25. 166 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php
  26. 107 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php
  27. 180 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php
  28. 48 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php
  29. 113 0
      api/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php
  30. 196 0
      api/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php
  31. 68 0
      api/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php
  32. 101 0
      api/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php
  33. 148 0
      api/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php
  34. 241 0
      api/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php
  35. 148 0
      api/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php
  36. 212 0
      api/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php
  37. 72 0
      api/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php
  38. 152 0
      api/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php
  39. 57 0
      api/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php
  40. 169 0
      api/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php
  41. 45 0
      api/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php
  42. 108 0
      api/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php
  43. 128 0
      api/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php
  44. 82 0
      api/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php
  45. 172 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php
  46. 28 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php
  47. 59 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php
  48. 34 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php
  49. 207 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php
  50. 195 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php
  51. 126 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php
  52. 128 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php
  53. 39 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php
  54. 63 0
      api/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php
  55. 65 0
      api/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php
  56. 117 0
      api/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php
  57. 90 0
      api/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php
  58. 116 0
      api/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php
  59. 367 0
      api/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php
  60. 70 0
      api/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php
  61. 62 0
      api/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php
  62. 55 0
      api/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php
  63. 102 0
      api/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php
  64. 67 0
      api/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php
  65. 68 0
      api/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php
  66. 21 0
      api/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php
  67. 59 0
      api/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php
  68. 185 0
      api/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php
  69. 205 0
      api/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php
  70. 45 0
      api/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php
  71. 243 0
      api/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php
  72. 40 0
      api/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php
  73. 73 0
      api/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php
  74. 56 0
      api/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php
  75. 185 0
      api/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php
  76. 234 0
      api/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php
  77. 98 0
      api/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php
  78. 144 0
      api/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php
  79. 191 0
      api/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php
  80. 113 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php
  81. 299 0
      api/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php
  82. 221 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php
  83. 121 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php
  84. 84 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php
  85. 385 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php
  86. 179 0
      api/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php
  87. 111 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php
  88. 67 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php
  89. 56 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php
  90. 124 0
      api/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php
  91. 72 0
      api/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php
  92. 101 0
      api/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php
  93. 796 0
      api/vendor/monolog/monolog/src/Monolog/Logger.php
  94. 64 0
      api/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php
  95. 112 0
      api/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php
  96. 35 0
      api/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php
  97. 63 0
      api/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php
  98. 35 0
      api/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php
  99. 63 0
      api/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php
  100. 31 0
      api/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php

+ 2 - 1
api/composer.json

@@ -16,6 +16,7 @@
     "slim/psr7": "^1.1",
     "zircote/swagger-php": "^3.0",
     "bogstag/oauth2-trakt": "^1.0",
-    "paquettg/php-html-parser": "^3.1"
+    "paquettg/php-html-parser": "^3.1",
+    "nekonomokochan/php-json-logger": "^1.3"
   }
 }

+ 241 - 1
api/composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "db7f63e80bb05dd9f7e63091879075a6",
+    "content-hash": "729002425d2f0941696f01fbb363589b",
     "packages": [
         {
             "name": "adldap2/adldap2",
@@ -973,6 +973,92 @@
             },
             "time": "2020-10-28T02:03:40+00:00"
         },
+        {
+            "name": "monolog/monolog",
+            "version": "1.26.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/monolog.git",
+                "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c6b00f05152ae2c9b04a448f99c7590beb6042f5",
+                "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5",
+                "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",
+                "php-amqplib/php-amqplib": "~2.4",
+                "php-console/php-console": "^3.1.3",
+                "phpstan/phpstan": "^0.12.59",
+                "phpunit/phpunit": "~4.5",
+                "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",
+            "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"
+            ],
+            "support": {
+                "issues": "https://github.com/Seldaek/monolog/issues",
+                "source": "https://github.com/Seldaek/monolog/tree/1.26.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/Seldaek",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-05-28T08:32:12+00:00"
+        },
         {
             "name": "myclabs/php-enum",
             "version": "1.8.0",
@@ -1033,6 +1119,55 @@
             ],
             "time": "2021-02-15T16:11:48+00:00"
         },
+        {
+            "name": "nekonomokochan/php-json-logger",
+            "version": "v1.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nekonomokochan/php-json-logger.git",
+                "reference": "6df126a82940a00d8ea2da6e0b7c58e3e57eb132"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nekonomokochan/php-json-logger/zipball/6df126a82940a00d8ea2da6e0b7c58e3e57eb132",
+                "reference": "6df126a82940a00d8ea2da6e0b7c58e3e57eb132",
+                "shasum": ""
+            },
+            "require": {
+                "monolog/monolog": "^1.24",
+                "php": "~7.1",
+                "ramsey/uuid": "^3.8"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^2.14",
+                "php": "~7.1",
+                "php-coveralls/php-coveralls": "^2.1",
+                "phpunit/phpcov": "^5.0",
+                "phpunit/phpunit": "^7.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Nekonomokochan\\PhpJsonLogger\\": "src/PhpJsonLogger"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "keitakn",
+                    "email": "keita.koga.work@gmail.com"
+                }
+            ],
+            "description": "LoggingLibrary for PHP. Output by JSON Format",
+            "support": {
+                "issues": "https://github.com/nekonomokochan/php-json-logger/issues",
+                "source": "https://github.com/nekonomokochan/php-json-logger/tree/feature/issue63"
+            },
+            "time": "2019-02-18T06:07:14+00:00"
+        },
         {
             "name": "nikic/fast-route",
             "version": "v1.3.0",
@@ -2173,6 +2308,111 @@
             },
             "time": "2019-03-08T08:55:37+00:00"
         },
+        {
+            "name": "ramsey/uuid",
+            "version": "3.9.6",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ramsey/uuid.git",
+                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/ffa80ab953edd85d5b6c004f96181a538aad35a3",
+                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
+                "php": "^5.4 | ^7.0 | ^8.0",
+                "symfony/polyfill-ctype": "^1.8"
+            },
+            "replace": {
+                "rhumsaa/uuid": "self.version"
+            },
+            "require-dev": {
+                "codeception/aspect-mock": "^1 | ^2",
+                "doctrine/annotations": "^1.2",
+                "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
+                "mockery/mockery": "^0.9.11 | ^1",
+                "moontoast/math": "^1.1",
+                "nikic/php-parser": "<=4.5.0",
+                "paragonie/random-lib": "^2",
+                "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
+                "php-parallel-lint/php-parallel-lint": "^1.3",
+                "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+                "squizlabs/php_codesniffer": "^3.5",
+                "yoast/phpunit-polyfills": "^1.0"
+            },
+            "suggest": {
+                "ext-ctype": "Provides support for PHP Ctype functions",
+                "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+                "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
+                "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+                "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+                "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+                "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+                "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Ramsey\\Uuid\\": "src/"
+                },
+                "files": [
+                    "src/functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ben Ramsey",
+                    "email": "ben@benramsey.com",
+                    "homepage": "https://benramsey.com"
+                },
+                {
+                    "name": "Marijn Huizendveld",
+                    "email": "marijn.huizendveld@gmail.com"
+                },
+                {
+                    "name": "Thibaud Fabre",
+                    "email": "thibaud@aztech.io"
+                }
+            ],
+            "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+            "homepage": "https://github.com/ramsey/uuid",
+            "keywords": [
+                "guid",
+                "identifier",
+                "uuid"
+            ],
+            "support": {
+                "issues": "https://github.com/ramsey/uuid/issues",
+                "rss": "https://github.com/ramsey/uuid/releases.atom",
+                "source": "https://github.com/ramsey/uuid",
+                "wiki": "https://github.com/ramsey/uuid/wiki"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/ramsey",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-09-25T23:07:42+00:00"
+        },
         {
             "name": "rmccue/requests",
             "version": "v1.8.0",

+ 43 - 2
api/vendor/composer/InstalledVersions.php

@@ -29,7 +29,7 @@ private static $installed = array (
     'aliases' => 
     array (
     ),
-    'reference' => 'f571aa755d372fc8205704b3cda8e1585aab0e3a',
+    'reference' => '55cb258deb19ead70294b137d89f4b9752e4e962',
     'name' => '__root__',
   ),
   'versions' => 
@@ -41,7 +41,7 @@ private static $installed = array (
       'aliases' => 
       array (
       ),
-      'reference' => 'f571aa755d372fc8205704b3cda8e1585aab0e3a',
+      'reference' => '55cb258deb19ead70294b137d89f4b9752e4e962',
     ),
     'adldap2/adldap2' => 
     array (
@@ -194,6 +194,15 @@ private static $installed = array (
       ),
       'reference' => 'badb01e62383430706433191b82506b6df24ad98',
     ),
+    'monolog/monolog' => 
+    array (
+      'pretty_version' => '1.26.1',
+      'version' => '1.26.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => 'c6b00f05152ae2c9b04a448f99c7590beb6042f5',
+    ),
     'myclabs/php-enum' => 
     array (
       'pretty_version' => '1.8.0',
@@ -203,6 +212,15 @@ private static $installed = array (
       ),
       'reference' => '46cf3d8498b095bd33727b13fd5707263af99421',
     ),
+    'nekonomokochan/php-json-logger' => 
+    array (
+      'pretty_version' => 'v1.3.1',
+      'version' => '1.3.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '6df126a82940a00d8ea2da6e0b7c58e3e57eb132',
+    ),
     'nikic/fast-route' => 
     array (
       'pretty_version' => 'v1.3.0',
@@ -377,6 +395,13 @@ private static $installed = array (
       ),
       'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
     ),
+    'psr/log-implementation' => 
+    array (
+      'provided' => 
+      array (
+        0 => '1.0.0',
+      ),
+    ),
     'psr/simple-cache' => 
     array (
       'pretty_version' => '1.0.1',
@@ -404,6 +429,22 @@ private static $installed = array (
       ),
       'reference' => '120b605dfeb996808c31b6477290a714d356e822',
     ),
+    'ramsey/uuid' => 
+    array (
+      'pretty_version' => '3.9.6',
+      'version' => '3.9.6.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => 'ffa80ab953edd85d5b6c004f96181a538aad35a3',
+    ),
+    'rhumsaa/uuid' => 
+    array (
+      'replaced' => 
+      array (
+        0 => '3.9.6',
+      ),
+    ),
     'rmccue/requests' => 
     array (
       'pretty_version' => 'v1.8.0',

+ 2 - 1
api/vendor/composer/autoload_files.php

@@ -10,10 +10,10 @@ return array(
     'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
     'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
+    '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
     '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
     '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
     '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
-    '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
     'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
     '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
     '253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
@@ -21,5 +21,6 @@ return array(
     'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
     'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',
     'caf31cc6ec7cf2241cb6f12c226c3846' => $vendorDir . '/tightenco/collect/src/Collect/Support/alias.php',
+    'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php',
     '0ccdf99b8f62f02c52cba55802e0c2e7' => $vendorDir . '/zircote/swagger-php/src/functions.php',
 );

+ 3 - 0
api/vendor/composer/autoload_psr4.php

@@ -18,6 +18,7 @@ return array(
     'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
     'Slim\\Psr7\\' => array($vendorDir . '/slim/psr7/src'),
     'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
+    'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'),
     'Pusher\\' => array($vendorDir . '/pusher/pusher-php-server/src'),
     'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
@@ -31,7 +32,9 @@ return array(
     'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
     'PHPHtmlParser\\' => array($vendorDir . '/paquettg/php-html-parser/src/PHPHtmlParser'),
     'OpenApi\\' => array($vendorDir . '/zircote/swagger-php/src'),
+    'Nekonomokochan\\PhpJsonLogger\\' => array($vendorDir . '/nekonomokochan/php-json-logger/src/PhpJsonLogger'),
     'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
+    'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
     'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-client/src'),
     'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
     'Kryptonit3\\Sonarr\\' => array($vendorDir . '/kryptonit3/sonarr/src'),

+ 23 - 1
api/vendor/composer/autoload_static.php

@@ -11,10 +11,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
         'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
+        '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
         '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
         '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
         '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
-        '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
         'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
         '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
         '253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
@@ -22,6 +22,7 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
         'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
         'caf31cc6ec7cf2241cb6f12c226c3846' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/alias.php',
+        'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php',
         '0ccdf99b8f62f02c52cba55802e0c2e7' => __DIR__ . '/..' . '/zircote/swagger-php/src/functions.php',
     );
 
@@ -44,6 +45,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             'Slim\\Psr7\\' => 10,
             'Slim\\' => 5,
         ),
+        'R' => 
+        array (
+            'Ramsey\\Uuid\\' => 12,
+        ),
         'P' => 
         array (
             'Pusher\\' => 7,
@@ -63,9 +68,14 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             'OpenApi\\' => 8,
         ),
+        'N' => 
+        array (
+            'Nekonomokochan\\PhpJsonLogger\\' => 29,
+        ),
         'M' => 
         array (
             'MyCLabs\\Enum\\' => 13,
+            'Monolog\\' => 8,
         ),
         'L' => 
         array (
@@ -166,6 +176,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/slim/slim/Slim',
         ),
+        'Ramsey\\Uuid\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/ramsey/uuid/src',
+        ),
         'Pusher\\' => 
         array (
             0 => __DIR__ . '/..' . '/pusher/pusher-php-server/src',
@@ -220,10 +234,18 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/zircote/swagger-php/src',
         ),
+        'Nekonomokochan\\PhpJsonLogger\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/nekonomokochan/php-json-logger/src/PhpJsonLogger',
+        ),
         'MyCLabs\\Enum\\' => 
         array (
             0 => __DIR__ . '/..' . '/myclabs/php-enum/src',
         ),
+        'Monolog\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog',
+        ),
         'League\\OAuth2\\Client\\' => 
         array (
             0 => __DIR__ . '/..' . '/league/oauth2-client/src',

+ 249 - 0
api/vendor/composer/installed.json

@@ -1015,6 +1015,95 @@
             },
             "install-path": "../league/oauth2-client"
         },
+        {
+            "name": "monolog/monolog",
+            "version": "1.26.1",
+            "version_normalized": "1.26.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/monolog.git",
+                "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c6b00f05152ae2c9b04a448f99c7590beb6042f5",
+                "reference": "c6b00f05152ae2c9b04a448f99c7590beb6042f5",
+                "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",
+                "php-amqplib/php-amqplib": "~2.4",
+                "php-console/php-console": "^3.1.3",
+                "phpstan/phpstan": "^0.12.59",
+                "phpunit/phpunit": "~4.5",
+                "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"
+            },
+            "time": "2021-05-28T08:32:12+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "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"
+            ],
+            "support": {
+                "issues": "https://github.com/Seldaek/monolog/issues",
+                "source": "https://github.com/Seldaek/monolog/tree/1.26.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/Seldaek",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../monolog/monolog"
+        },
         {
             "name": "myclabs/php-enum",
             "version": "1.8.0",
@@ -1078,6 +1167,58 @@
             ],
             "install-path": "../myclabs/php-enum"
         },
+        {
+            "name": "nekonomokochan/php-json-logger",
+            "version": "v1.3.1",
+            "version_normalized": "1.3.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nekonomokochan/php-json-logger.git",
+                "reference": "6df126a82940a00d8ea2da6e0b7c58e3e57eb132"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nekonomokochan/php-json-logger/zipball/6df126a82940a00d8ea2da6e0b7c58e3e57eb132",
+                "reference": "6df126a82940a00d8ea2da6e0b7c58e3e57eb132",
+                "shasum": ""
+            },
+            "require": {
+                "monolog/monolog": "^1.24",
+                "php": "~7.1",
+                "ramsey/uuid": "^3.8"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^2.14",
+                "php": "~7.1",
+                "php-coveralls/php-coveralls": "^2.1",
+                "phpunit/phpcov": "^5.0",
+                "phpunit/phpunit": "^7.5"
+            },
+            "time": "2019-02-18T06:07:14+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Nekonomokochan\\PhpJsonLogger\\": "src/PhpJsonLogger"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "keitakn",
+                    "email": "keita.koga.work@gmail.com"
+                }
+            ],
+            "description": "LoggingLibrary for PHP. Output by JSON Format",
+            "support": {
+                "issues": "https://github.com/nekonomokochan/php-json-logger/issues",
+                "source": "https://github.com/nekonomokochan/php-json-logger/tree/feature/issue63"
+            },
+            "install-path": "../nekonomokochan/php-json-logger"
+        },
         {
             "name": "nikic/fast-route",
             "version": "v1.3.0",
@@ -2256,6 +2397,114 @@
             "description": "A polyfill for getallheaders.",
             "install-path": "../ralouphie/getallheaders"
         },
+        {
+            "name": "ramsey/uuid",
+            "version": "3.9.6",
+            "version_normalized": "3.9.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ramsey/uuid.git",
+                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/ffa80ab953edd85d5b6c004f96181a538aad35a3",
+                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
+                "php": "^5.4 | ^7.0 | ^8.0",
+                "symfony/polyfill-ctype": "^1.8"
+            },
+            "replace": {
+                "rhumsaa/uuid": "self.version"
+            },
+            "require-dev": {
+                "codeception/aspect-mock": "^1 | ^2",
+                "doctrine/annotations": "^1.2",
+                "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
+                "mockery/mockery": "^0.9.11 | ^1",
+                "moontoast/math": "^1.1",
+                "nikic/php-parser": "<=4.5.0",
+                "paragonie/random-lib": "^2",
+                "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
+                "php-parallel-lint/php-parallel-lint": "^1.3",
+                "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+                "squizlabs/php_codesniffer": "^3.5",
+                "yoast/phpunit-polyfills": "^1.0"
+            },
+            "suggest": {
+                "ext-ctype": "Provides support for PHP Ctype functions",
+                "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+                "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
+                "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+                "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+                "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+                "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+                "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
+            },
+            "time": "2021-09-25T23:07:42+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Ramsey\\Uuid\\": "src/"
+                },
+                "files": [
+                    "src/functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ben Ramsey",
+                    "email": "ben@benramsey.com",
+                    "homepage": "https://benramsey.com"
+                },
+                {
+                    "name": "Marijn Huizendveld",
+                    "email": "marijn.huizendveld@gmail.com"
+                },
+                {
+                    "name": "Thibaud Fabre",
+                    "email": "thibaud@aztech.io"
+                }
+            ],
+            "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+            "homepage": "https://github.com/ramsey/uuid",
+            "keywords": [
+                "guid",
+                "identifier",
+                "uuid"
+            ],
+            "support": {
+                "issues": "https://github.com/ramsey/uuid/issues",
+                "rss": "https://github.com/ramsey/uuid/releases.atom",
+                "source": "https://github.com/ramsey/uuid",
+                "wiki": "https://github.com/ramsey/uuid/wiki"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/ramsey",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../ramsey/uuid"
+        },
         {
             "name": "rmccue/requests",
             "version": "v1.8.0",

+ 43 - 2
api/vendor/composer/installed.php

@@ -6,7 +6,7 @@
     'aliases' => 
     array (
     ),
-    'reference' => 'f571aa755d372fc8205704b3cda8e1585aab0e3a',
+    'reference' => '55cb258deb19ead70294b137d89f4b9752e4e962',
     'name' => '__root__',
   ),
   'versions' => 
@@ -18,7 +18,7 @@
       'aliases' => 
       array (
       ),
-      'reference' => 'f571aa755d372fc8205704b3cda8e1585aab0e3a',
+      'reference' => '55cb258deb19ead70294b137d89f4b9752e4e962',
     ),
     'adldap2/adldap2' => 
     array (
@@ -171,6 +171,15 @@
       ),
       'reference' => 'badb01e62383430706433191b82506b6df24ad98',
     ),
+    'monolog/monolog' => 
+    array (
+      'pretty_version' => '1.26.1',
+      'version' => '1.26.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => 'c6b00f05152ae2c9b04a448f99c7590beb6042f5',
+    ),
     'myclabs/php-enum' => 
     array (
       'pretty_version' => '1.8.0',
@@ -180,6 +189,15 @@
       ),
       'reference' => '46cf3d8498b095bd33727b13fd5707263af99421',
     ),
+    'nekonomokochan/php-json-logger' => 
+    array (
+      'pretty_version' => 'v1.3.1',
+      'version' => '1.3.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '6df126a82940a00d8ea2da6e0b7c58e3e57eb132',
+    ),
     'nikic/fast-route' => 
     array (
       'pretty_version' => 'v1.3.0',
@@ -354,6 +372,13 @@
       ),
       'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
     ),
+    'psr/log-implementation' => 
+    array (
+      'provided' => 
+      array (
+        0 => '1.0.0',
+      ),
+    ),
     'psr/simple-cache' => 
     array (
       'pretty_version' => '1.0.1',
@@ -381,6 +406,22 @@
       ),
       'reference' => '120b605dfeb996808c31b6477290a714d356e822',
     ),
+    'ramsey/uuid' => 
+    array (
+      'pretty_version' => '3.9.6',
+      'version' => '3.9.6.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => 'ffa80ab953edd85d5b6c004f96181a538aad35a3',
+    ),
+    'rhumsaa/uuid' => 
+    array (
+      'replaced' => 
+      array (
+        0 => '3.9.6',
+      ),
+    ),
     'rmccue/requests' => 
     array (
       'pretty_version' => 'v1.8.0',

+ 423 - 0
api/vendor/monolog/monolog/CHANGELOG.md

@@ -0,0 +1,423 @@
+### 1.26.1 (2021-05-28)
+
+  * Fixed PHP 8.1 deprecation warning
+
+### 1.26.0 (2020-12-14)
+
+  * Added $dateFormat and $removeUsedContextFields arguments to PsrLogMessageProcessor (backport from 2.x)
+
+### 1.25.5 (2020-07-23)
+
+  * Fixed array access on null in RavenHandler
+  * Fixed unique_id in WebProcessor not being disableable
+
+### 1.25.4 (2020-05-22)
+
+  * Fixed GitProcessor type error when there is no git repo present
+  * Fixed normalization of SoapFault objects containing deeply nested objects as "detail"
+  * Fixed support for relative paths in RotatingFileHandler
+
+### 1.25.3 (2019-12-20)
+
+  * Fixed formatting of resources in JsonFormatter
+  * Fixed RedisHandler failing to use MULTI properly when passed a proxied Redis instance (e.g. in Symfony with lazy services)
+  * Fixed FilterHandler triggering a notice when handleBatch was filtering all records passed to it
+  * Fixed Turkish locale messing up the conversion of level names to their constant values
+
+### 1.25.2 (2019-11-13)
+
+  * Fixed normalization of Traversables to avoid traversing them as not all of them are rewindable
+  * Fixed setFormatter/getFormatter to forward to the nested handler in FilterHandler, FingersCrossedHandler, BufferHandler and SamplingHandler
+  * Fixed BrowserConsoleHandler formatting when using multiple styles
+  * Fixed normalization of exception codes to be always integers even for PDOException which have them as numeric strings
+  * Fixed normalization of SoapFault objects containing non-strings as "detail"
+  * Fixed json encoding across all handlers to always attempt recovery of non-UTF-8 strings instead of failing the whole encoding
+
+### 1.25.1 (2019-09-06)
+
+  * Fixed forward-compatible interfaces to be compatible with Monolog 1.x too.
+
+### 1.25.0 (2019-09-06)
+
+  * Deprecated SlackbotHandler, use SlackWebhookHandler or SlackHandler instead
+  * Deprecated RavenHandler, use sentry/sentry 2.x and their Sentry\Monolog\Handler instead
+  * Deprecated HipChatHandler, migrate to Slack and use SlackWebhookHandler or SlackHandler instead
+  * Added forward-compatible interfaces and traits FormattableHandlerInterface, FormattableHandlerTrait, ProcessableHandlerInterface, ProcessableHandlerTrait. If you use modern PHP and want to make code compatible with Monolog 1 and 2 this can help. You will have to require at least Monolog 1.25 though.
+  * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler
+  * Fixed issue in GroupHandler and WhatFailureGroupHandler where setting multiple processors would duplicate records
+  * Fixed issue in SignalHandler restarting syscalls functionality
+  * Fixed normalizers handling of exception backtraces to avoid serializing arguments in some cases
+  * Fixed ZendMonitorHandler to work with the latest Zend Server versions
+  * Fixed ChromePHPHandler to avoid sending more data than latest Chrome versions allow in headers (4KB down from 256KB).
+
+### 1.24.0 (2018-11-05)
+
+  * BC Notice: If you are extending any of the Monolog's Formatters' `normalize` method, make sure you add the new `$depth = 0` argument to your function signature to avoid strict PHP warnings.
+  * Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors
+  * Added a `ProcessorInterface` as an optional way to label a class as being a processor (mostly useful for autowiring dependency containers)
+  * Added a way to log signals being received using Monolog\SignalHandler
+  * Added ability to customize error handling at the Logger level using Logger::setExceptionHandler
+  * Added InsightOpsHandler to migrate users of the LogEntriesHandler
+  * Added protection to NormalizerHandler against circular and very deep structures, it now stops normalizing at a depth of 9
+  * Added capture of stack traces to ErrorHandler when logging PHP errors
+  * Added RavenHandler support for a `contexts` context or extra key to forward that to Sentry's contexts
+  * Added forwarding of context info to FluentdFormatter
+  * Added SocketHandler::setChunkSize to override the default chunk size in case you must send large log lines to rsyslog for example
+  * Added ability to extend/override BrowserConsoleHandler
+  * Added SlackWebhookHandler::getWebhookUrl and SlackHandler::getToken to enable class extensibility
+  * Added SwiftMailerHandler::getSubjectFormatter to enable class extensibility
+  * Dropped official support for HHVM in test builds
+  * Fixed normalization of exception traces when call_user_func is used to avoid serializing objects and the data they contain
+  * Fixed naming of fields in Slack handler, all field names are now capitalized in all cases
+  * Fixed HipChatHandler bug where slack dropped messages randomly
+  * Fixed normalization of objects in Slack handlers
+  * Fixed support for PHP7's Throwable in NewRelicHandler
+  * Fixed race bug when StreamHandler sometimes incorrectly reported it failed to create a directory
+  * Fixed table row styling issues in HtmlFormatter
+  * Fixed RavenHandler dropping the message when logging exception
+  * Fixed WhatFailureGroupHandler skipping processors when using handleBatch
+    and implement it where possible
+  * Fixed display of anonymous class names
+
+### 1.23.0 (2017-06-19)
+
+  * Improved SyslogUdpHandler's support for RFC5424 and added optional `$ident` argument
+  * Fixed GelfHandler truncation to be per field and not per message
+  * Fixed compatibility issue with PHP <5.3.6
+  * Fixed support for headless Chrome in ChromePHPHandler
+  * Fixed support for latest Aws SDK in DynamoDbHandler
+  * Fixed support for SwiftMailer 6.0+ in SwiftMailerHandler
+
+### 1.22.1 (2017-03-13)
+
+  * Fixed lots of minor issues in the new Slack integrations
+  * Fixed support for allowInlineLineBreaks in LineFormatter when formatting exception backtraces
+
+### 1.22.0 (2016-11-26)
+
+  * Added SlackbotHandler and SlackWebhookHandler to set up Slack integration more easily
+  * Added MercurialProcessor to add mercurial revision and branch names to log records
+  * Added support for AWS SDK v3 in DynamoDbHandler
+  * Fixed fatal errors occuring when normalizing generators that have been fully consumed
+  * Fixed RollbarHandler to include a level (rollbar level), monolog_level (original name), channel and datetime (unix)
+  * Fixed RollbarHandler not flushing records automatically, calling close() explicitly is not necessary anymore
+  * Fixed SyslogUdpHandler to avoid sending empty frames
+  * Fixed a few PHP 7.0 and 7.1 compatibility issues
+
+### 1.21.0 (2016-07-29)
+
+  * Break: Reverted the addition of $context when the ErrorHandler handles regular php errors from 1.20.0 as it was causing issues
+  * Added support for more formats in RotatingFileHandler::setFilenameFormat as long as they have Y, m and d in order
+  * Added ability to format the main line of text the SlackHandler sends by explictly setting a formatter on the handler
+  * Added information about SoapFault instances in NormalizerFormatter
+  * Added $handleOnlyReportedErrors option on ErrorHandler::registerErrorHandler (default true) to allow logging of all errors no matter the error_reporting level
+
+### 1.20.0 (2016-07-02)
+
+  * Added FingersCrossedHandler::activate() to manually trigger the handler regardless of the activation policy
+  * Added StreamHandler::getUrl to retrieve the stream's URL
+  * Added ability to override addRow/addTitle in HtmlFormatter
+  * Added the $context to context information when the ErrorHandler handles a regular php error
+  * Deprecated RotatingFileHandler::setFilenameFormat to only support 3 formats: Y, Y-m and Y-m-d
+  * Fixed WhatFailureGroupHandler to work with PHP7 throwables
+  * Fixed a few minor bugs
+
+### 1.19.0 (2016-04-12)
+
+  * Break: StreamHandler will not close streams automatically that it does not own. If you pass in a stream (not a path/url), then it will not close it for you. You can retrieve those using getStream() if needed
+  * Added DeduplicationHandler to remove duplicate records from notifications across multiple requests, useful for email or other notifications on errors
+  * Added ability to use `%message%` and other LineFormatter replacements in the subject line of emails sent with NativeMailHandler and SwiftMailerHandler
+  * Fixed HipChatHandler handling of long messages
+
+### 1.18.2 (2016-04-02)
+
+  * Fixed ElasticaFormatter to use more precise dates
+  * Fixed GelfMessageFormatter sending too long messages
+
+### 1.18.1 (2016-03-13)
+
+  * Fixed SlackHandler bug where slack dropped messages randomly
+  * Fixed RedisHandler issue when using with the PHPRedis extension
+  * Fixed AmqpHandler content-type being incorrectly set when using with the AMQP extension
+  * Fixed BrowserConsoleHandler regression
+
+### 1.18.0 (2016-03-01)
+
+  * Added optional reduction of timestamp precision via `Logger->useMicrosecondTimestamps(false)`, disabling it gets you a bit of performance boost but reduces the precision to the second instead of microsecond
+  * Added possibility to skip some extra stack frames in IntrospectionProcessor if you have some library wrapping Monolog that is always adding frames
+  * Added `Logger->withName` to clone a logger (keeping all handlers) with a new name
+  * Added FluentdFormatter for the Fluentd unix socket protocol
+  * Added HandlerWrapper base class to ease the creation of handler wrappers, just extend it and override as needed
+  * Added support for replacing context sub-keys using `%context.*%` in LineFormatter
+  * Added support for `payload` context value in RollbarHandler
+  * Added setRelease to RavenHandler to describe the application version, sent with every log
+  * Added support for `fingerprint` context value in RavenHandler
+  * Fixed JSON encoding errors that would gobble up the whole log record, we now handle those more gracefully by dropping chars as needed
+  * Fixed write timeouts in SocketHandler and derivatives, set to 10sec by default, lower it with `setWritingTimeout()`
+  * Fixed PHP7 compatibility with regard to Exception/Throwable handling in a few places
+
+### 1.17.2 (2015-10-14)
+
+  * Fixed ErrorHandler compatibility with non-Monolog PSR-3 loggers
+  * Fixed SlackHandler handling to use slack functionalities better
+  * Fixed SwiftMailerHandler bug when sending multiple emails they all had the same id
+  * Fixed 5.3 compatibility regression
+
+### 1.17.1 (2015-08-31)
+
+  * Fixed RollbarHandler triggering PHP notices
+
+### 1.17.0 (2015-08-30)
+
+  * Added support for `checksum` and `release` context/extra values in RavenHandler
+  * Added better support for exceptions in RollbarHandler
+  * Added UidProcessor::getUid
+  * Added support for showing the resource type in NormalizedFormatter
+  * Fixed IntrospectionProcessor triggering PHP notices
+
+### 1.16.0 (2015-08-09)
+
+  * Added IFTTTHandler to notify ifttt.com triggers
+  * Added Logger::setHandlers() to allow setting/replacing all handlers
+  * Added $capSize in RedisHandler to cap the log size
+  * Fixed StreamHandler creation of directory to only trigger when the first log write happens
+  * Fixed bug in the handling of curl failures
+  * Fixed duplicate logging of fatal errors when both error and fatal error handlers are registered in monolog's ErrorHandler
+  * Fixed missing fatal errors records with handlers that need to be closed to flush log records
+  * Fixed TagProcessor::addTags support for associative arrays
+
+### 1.15.0 (2015-07-12)
+
+  * Added addTags and setTags methods to change a TagProcessor
+  * Added automatic creation of directories if they are missing for a StreamHandler to open a log file
+  * Added retry functionality to Loggly, Cube and Mandrill handlers so they retry up to 5 times in case of network failure
+  * Fixed process exit code being incorrectly reset to 0 if ErrorHandler::registerExceptionHandler was used
+  * Fixed HTML/JS escaping in BrowserConsoleHandler
+  * Fixed JSON encoding errors being silently suppressed (PHP 5.5+ only)
+
+### 1.14.0 (2015-06-19)
+
+  * Added PHPConsoleHandler to send record to Chrome's PHP Console extension and library
+  * Added support for objects implementing __toString in the NormalizerFormatter
+  * Added support for HipChat's v2 API in HipChatHandler
+  * Added Logger::setTimezone() to initialize the timezone monolog should use in case date.timezone isn't correct for your app
+  * Added an option to send formatted message instead of the raw record on PushoverHandler via ->useFormattedMessage(true)
+  * Fixed curl errors being silently suppressed
+
+### 1.13.1 (2015-03-09)
+
+  * Fixed regression in HipChat requiring a new token to be created
+
+### 1.13.0 (2015-03-05)
+
+  * Added Registry::hasLogger to check for the presence of a logger instance
+  * Added context.user support to RavenHandler
+  * Added HipChat API v2 support in the HipChatHandler
+  * Added NativeMailerHandler::addParameter to pass params to the mail() process
+  * Added context data to SlackHandler when $includeContextAndExtra is true
+  * Added ability to customize the Swift_Message per-email in SwiftMailerHandler
+  * Fixed SwiftMailerHandler to lazily create message instances if a callback is provided
+  * Fixed serialization of INF and NaN values in Normalizer and LineFormatter
+
+### 1.12.0 (2014-12-29)
+
+  * Break: HandlerInterface::isHandling now receives a partial record containing only a level key. This was always the intent and does not break any Monolog handler but is strictly speaking a BC break and you should check if you relied on any other field in your own handlers.
+  * Added PsrHandler to forward records to another PSR-3 logger
+  * Added SamplingHandler to wrap around a handler and include only every Nth record
+  * Added MongoDBFormatter to support better storage with MongoDBHandler (it must be enabled manually for now)
+  * Added exception codes in the output of most formatters
+  * Added LineFormatter::includeStacktraces to enable exception stack traces in logs (uses more than one line)
+  * Added $useShortAttachment to SlackHandler to minify attachment size and $includeExtra to append extra data
+  * Added $host to HipChatHandler for users of private instances
+  * Added $transactionName to NewRelicHandler and support for a transaction_name context value
+  * Fixed MandrillHandler to avoid outputing API call responses
+  * Fixed some non-standard behaviors in SyslogUdpHandler
+
+### 1.11.0 (2014-09-30)
+
+  * Break: The NewRelicHandler extra and context data are now prefixed with extra_ and context_ to avoid clashes. Watch out if you have scripts reading those from the API and rely on names
+  * Added WhatFailureGroupHandler to suppress any exception coming from the wrapped handlers and avoid chain failures if a logging service fails
+  * Added MandrillHandler to send emails via the Mandrillapp.com API
+  * Added SlackHandler to log records to a Slack.com account
+  * Added FleepHookHandler to log records to a Fleep.io account
+  * Added LogglyHandler::addTag to allow adding tags to an existing handler
+  * Added $ignoreEmptyContextAndExtra to LineFormatter to avoid empty [] at the end
+  * Added $useLocking to StreamHandler and RotatingFileHandler to enable flock() while writing
+  * Added support for PhpAmqpLib in the AmqpHandler
+  * Added FingersCrossedHandler::clear and BufferHandler::clear to reset them between batches in long running jobs
+  * Added support for adding extra fields from $_SERVER in the WebProcessor
+  * Fixed support for non-string values in PrsLogMessageProcessor
+  * Fixed SwiftMailer messages being sent with the wrong date in long running scripts
+  * Fixed minor PHP 5.6 compatibility issues
+  * Fixed BufferHandler::close being called twice
+
+### 1.10.0 (2014-06-04)
+
+  * Added Logger::getHandlers() and Logger::getProcessors() methods
+  * Added $passthruLevel argument to FingersCrossedHandler to let it always pass some records through even if the trigger level is not reached
+  * Added support for extra data in NewRelicHandler
+  * Added $expandNewlines flag to the ErrorLogHandler to create multiple log entries when a message has multiple lines
+
+### 1.9.1 (2014-04-24)
+
+  * Fixed regression in RotatingFileHandler file permissions
+  * Fixed initialization of the BufferHandler to make sure it gets flushed after receiving records
+  * Fixed ChromePHPHandler and FirePHPHandler's activation strategies to be more conservative
+
+### 1.9.0 (2014-04-20)
+
+  * Added LogEntriesHandler to send logs to a LogEntries account
+  * Added $filePermissions to tweak file mode on StreamHandler and RotatingFileHandler
+  * Added $useFormatting flag to MemoryProcessor to make it send raw data in bytes
+  * Added support for table formatting in FirePHPHandler via the table context key
+  * Added a TagProcessor to add tags to records, and support for tags in RavenHandler
+  * Added $appendNewline flag to the JsonFormatter to enable using it when logging to files
+  * Added sound support to the PushoverHandler
+  * Fixed multi-threading support in StreamHandler
+  * Fixed empty headers issue when ChromePHPHandler received no records
+  * Fixed default format of the ErrorLogHandler
+
+### 1.8.0 (2014-03-23)
+
+  * Break: the LineFormatter now strips newlines by default because this was a bug, set $allowInlineLineBreaks to true if you need them
+  * Added BrowserConsoleHandler to send logs to any browser's console via console.log() injection in the output
+  * Added FilterHandler to filter records and only allow those of a given list of levels through to the wrapped handler
+  * Added FlowdockHandler to send logs to a Flowdock account
+  * Added RollbarHandler to send logs to a Rollbar account
+  * Added HtmlFormatter to send prettier log emails with colors for each log level
+  * Added GitProcessor to add the current branch/commit to extra record data
+  * Added a Monolog\Registry class to allow easier global access to pre-configured loggers
+  * Added support for the new official graylog2/gelf-php lib for GelfHandler, upgrade if you can by replacing the mlehner/gelf-php requirement
+  * Added support for HHVM
+  * Added support for Loggly batch uploads
+  * Added support for tweaking the content type and encoding in NativeMailerHandler
+  * Added $skipClassesPartials to tweak the ignored classes in the IntrospectionProcessor
+  * Fixed batch request support in GelfHandler
+
+### 1.7.0 (2013-11-14)
+
+  * Added ElasticSearchHandler to send logs to an Elastic Search server
+  * Added DynamoDbHandler and ScalarFormatter to send logs to Amazon's Dynamo DB
+  * Added SyslogUdpHandler to send logs to a remote syslogd server
+  * Added LogglyHandler to send logs to a Loggly account
+  * Added $level to IntrospectionProcessor so it only adds backtraces when needed
+  * Added $version to LogstashFormatter to allow using the new v1 Logstash format
+  * Added $appName to NewRelicHandler
+  * Added configuration of Pushover notification retries/expiry
+  * Added $maxColumnWidth to NativeMailerHandler to change the 70 chars default
+  * Added chainability to most setters for all handlers
+  * Fixed RavenHandler batch processing so it takes the message from the record with highest priority
+  * Fixed HipChatHandler batch processing so it sends all messages at once
+  * Fixed issues with eAccelerator
+  * Fixed and improved many small things
+
+### 1.6.0 (2013-07-29)
+
+  * Added HipChatHandler to send logs to a HipChat chat room
+  * Added ErrorLogHandler to send logs to PHP's error_log function
+  * Added NewRelicHandler to send logs to NewRelic's service
+  * Added Monolog\ErrorHandler helper class to register a Logger as exception/error/fatal handler
+  * Added ChannelLevelActivationStrategy for the FingersCrossedHandler to customize levels by channel
+  * Added stack traces output when normalizing exceptions (json output & co)
+  * Added Monolog\Logger::API constant (currently 1)
+  * Added support for ChromePHP's v4.0 extension
+  * Added support for message priorities in PushoverHandler, see $highPriorityLevel and $emergencyLevel
+  * Added support for sending messages to multiple users at once with the PushoverHandler
+  * Fixed RavenHandler's support for batch sending of messages (when behind a Buffer or FingersCrossedHandler)
+  * Fixed normalization of Traversables with very large data sets, only the first 1000 items are shown now
+  * Fixed issue in RotatingFileHandler when an open_basedir restriction is active
+  * Fixed minor issues in RavenHandler and bumped the API to Raven 0.5.0
+  * Fixed SyslogHandler issue when many were used concurrently with different facilities
+
+### 1.5.0 (2013-04-23)
+
+  * Added ProcessIdProcessor to inject the PID in log records
+  * Added UidProcessor to inject a unique identifier to all log records of one request/run
+  * Added support for previous exceptions in the LineFormatter exception serialization
+  * Added Monolog\Logger::getLevels() to get all available levels
+  * Fixed ChromePHPHandler so it avoids sending headers larger than Chrome can handle
+
+### 1.4.1 (2013-04-01)
+
+  * Fixed exception formatting in the LineFormatter to be more minimalistic
+  * Fixed RavenHandler's handling of context/extra data, requires Raven client >0.1.0
+  * Fixed log rotation in RotatingFileHandler to work with long running scripts spanning multiple days
+  * Fixed WebProcessor array access so it checks for data presence
+  * Fixed Buffer, Group and FingersCrossed handlers to make use of their processors
+
+### 1.4.0 (2013-02-13)
+
+  * Added RedisHandler to log to Redis via the Predis library or the phpredis extension
+  * Added ZendMonitorHandler to log to the Zend Server monitor
+  * Added the possibility to pass arrays of handlers and processors directly in the Logger constructor
+  * Added `$useSSL` option to the PushoverHandler which is enabled by default
+  * Fixed ChromePHPHandler and FirePHPHandler issue when multiple instances are used simultaneously
+  * Fixed header injection capability in the NativeMailHandler
+
+### 1.3.1 (2013-01-11)
+
+  * Fixed LogstashFormatter to be usable with stream handlers
+  * Fixed GelfMessageFormatter levels on Windows
+
+### 1.3.0 (2013-01-08)
+
+  * Added PSR-3 compliance, the `Monolog\Logger` class is now an instance of `Psr\Log\LoggerInterface`
+  * Added PsrLogMessageProcessor that you can selectively enable for full PSR-3 compliance
+  * Added LogstashFormatter (combine with SocketHandler or StreamHandler to send logs to Logstash)
+  * Added PushoverHandler to send mobile notifications
+  * Added CouchDBHandler and DoctrineCouchDBHandler
+  * Added RavenHandler to send data to Sentry servers
+  * Added support for the new MongoClient class in MongoDBHandler
+  * Added microsecond precision to log records' timestamps
+  * Added `$flushOnOverflow` param to BufferHandler to flush by batches instead of losing
+    the oldest entries
+  * Fixed normalization of objects with cyclic references
+
+### 1.2.1 (2012-08-29)
+
+  * Added new $logopts arg to SyslogHandler to provide custom openlog options
+  * Fixed fatal error in SyslogHandler
+
+### 1.2.0 (2012-08-18)
+
+  * Added AmqpHandler (for use with AMQP servers)
+  * Added CubeHandler
+  * Added NativeMailerHandler::addHeader() to send custom headers in mails
+  * Added the possibility to specify more than one recipient in NativeMailerHandler
+  * Added the possibility to specify float timeouts in SocketHandler
+  * Added NOTICE and EMERGENCY levels to conform with RFC 5424
+  * Fixed the log records to use the php default timezone instead of UTC
+  * Fixed BufferHandler not being flushed properly on PHP fatal errors
+  * Fixed normalization of exotic resource types
+  * Fixed the default format of the SyslogHandler to avoid duplicating datetimes in syslog
+
+### 1.1.0 (2012-04-23)
+
+  * Added Monolog\Logger::isHandling() to check if a handler will
+    handle the given log level
+  * Added ChromePHPHandler
+  * Added MongoDBHandler
+  * Added GelfHandler (for use with Graylog2 servers)
+  * Added SocketHandler (for use with syslog-ng for example)
+  * Added NormalizerFormatter
+  * Added the possibility to change the activation strategy of the FingersCrossedHandler
+  * Added possibility to show microseconds in logs
+  * Added `server` and `referer` to WebProcessor output
+
+### 1.0.2 (2011-10-24)
+
+  * Fixed bug in IE with large response headers and FirePHPHandler
+
+### 1.0.1 (2011-08-25)
+
+  * Added MemoryPeakUsageProcessor and MemoryUsageProcessor
+  * Added Monolog\Logger::getName() to get a logger's channel name
+
+### 1.0.0 (2011-07-06)
+
+  * Added IntrospectionProcessor to get info from where the logger was called
+  * Fixed WebProcessor in CLI
+
+### 1.0.0-RC1 (2011-07-01)
+
+  * Initial release

+ 19 - 0
api/vendor/monolog/monolog/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2011-2016 Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 94 - 0
api/vendor/monolog/monolog/README.md

@@ -0,0 +1,94 @@
+# Monolog - Logging for PHP [![Build Status](https://img.shields.io/travis/Seldaek/monolog.svg)](https://travis-ci.org/Seldaek/monolog)
+
+[![Total Downloads](https://img.shields.io/packagist/dt/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog)
+[![Latest Stable Version](https://img.shields.io/packagist/v/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog)
+
+
+Monolog sends your logs to files, sockets, inboxes, databases and various
+web services. See the complete list of handlers below. Special handlers
+allow you to build advanced logging strategies.
+
+This library implements the [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+interface that you can type-hint against in your own libraries to keep
+a maximum of interoperability. You can also use it in your applications to
+make sure you can always use another compatible logger at a later time.
+As of 1.11.0 Monolog public APIs will also accept PSR-3 log levels.
+Internally Monolog still uses its own level scheme since it predates PSR-3.
+
+## Installation
+
+Install the latest version with
+
+```bash
+$ composer require monolog/monolog
+```
+
+## Basic Usage
+
+```php
+<?php
+
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+
+// create a log channel
+$log = new Logger('name');
+$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
+
+// add records to the log
+$log->addWarning('Foo');
+$log->addError('Bar');
+```
+
+## Documentation
+
+- [Usage Instructions](doc/01-usage.md)
+- [Handlers, Formatters and Processors](doc/02-handlers-formatters-processors.md)
+- [Utility classes](doc/03-utilities.md)
+- [Extending Monolog](doc/04-extending.md)
+
+## Third Party Packages
+
+Third party handlers, formatters and processors are
+[listed in the wiki](https://github.com/Seldaek/monolog/wiki/Third-Party-Packages). You
+can also add your own there if you publish one.
+
+## About
+
+### Requirements
+
+- Monolog works with PHP 5.3 or above, and is also tested to work with HHVM.
+
+### Submitting bugs and feature requests
+
+Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/monolog/issues)
+
+### Framework Integrations
+
+- Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+  can be used very easily with Monolog since it implements the interface.
+- [Symfony2](http://symfony.com) comes out of the box with Monolog.
+- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog.
+- [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog.
+- [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog.
+- [PPI](http://www.ppi.io/) comes out of the box with Monolog.
+- [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin.
+- [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer.
+- [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog.
+- [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) comes out of the box with Monolog.
+- [Nette Framework](http://nette.org/en/) can be used with Monolog via [Kdyby/Monolog](https://github.com/Kdyby/Monolog) extension.
+- [Proton Micro Framework](https://github.com/alexbilbie/Proton) comes out of the box with Monolog.
+
+### Author
+
+Jordi Boggiano - <j.boggiano@seld.be> - <http://twitter.com/seldaek><br />
+See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project.
+
+### License
+
+Monolog is licensed under the MIT License - see the `LICENSE` file for details
+
+### Acknowledgements
+
+This library is heavily inspired by Python's [Logbook](https://logbook.readthedocs.io/en/stable/)
+library, although most concepts have been adjusted to fit to the PHP world.

+ 58 - 0
api/vendor/monolog/monolog/composer.json

@@ -0,0 +1,58 @@
+{
+    "name": "monolog/monolog",
+    "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+    "keywords": ["log", "logging", "psr-3"],
+    "homepage": "http://github.com/Seldaek/monolog",
+    "type": "library",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Jordi Boggiano",
+            "email": "j.boggiano@seld.be",
+            "homepage": "http://seld.be"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.0",
+        "psr/log": "~1.0"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "~4.5",
+        "graylog2/gelf-php": "~1.0",
+        "sentry/sentry": "^0.13",
+        "ruflin/elastica": ">=0.90 <3.0",
+        "doctrine/couchdb": "~1.0@dev",
+        "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+        "php-amqplib/php-amqplib": "~2.4",
+        "swiftmailer/swiftmailer": "^5.3|^6.0",
+        "php-console/php-console": "^3.1.3",
+        "phpstan/phpstan": "^0.12.59"
+    },
+    "suggest": {
+        "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+        "sentry/sentry": "Allow sending log messages to a Sentry server",
+        "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+        "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+        "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+        "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+        "ext-mongo": "Allow sending log messages to a MongoDB server",
+        "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
+        "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+        "rollbar/rollbar": "Allow sending log messages to Rollbar",
+        "php-console/php-console": "Allow sending log messages to Google Chrome"
+    },
+    "autoload": {
+        "psr-4": {"Monolog\\": "src/Monolog"}
+    },
+    "autoload-dev": {
+        "psr-4": {"Monolog\\": "tests/Monolog"}
+    },
+    "provide": {
+        "psr/log-implementation": "1.0.0"
+    },
+    "scripts": {
+        "test": "vendor/bin/phpunit",
+        "phpstan": "vendor/bin/phpstan analyse"
+    },
+    "lock": false
+}

+ 16 - 0
api/vendor/monolog/monolog/phpstan.neon.dist

@@ -0,0 +1,16 @@
+parameters:
+    level: 3
+
+    paths:
+        - src/
+#        - tests/
+
+
+    ignoreErrors:
+        - '#zend_monitor_|ZEND_MONITOR_#'
+        - '#RollbarNotifier#'
+        - '#Predis\\Client#'
+        - '#^Cannot call method ltrim\(\) on int\|false.$#'
+        - '#^Access to an undefined property Raven_Client::\$context.$#'
+        - '#MongoDB\\(Client|Collection)#'
+        - '#Gelf\\IMessagePublisher#'

+ 239 - 0
api/vendor/monolog/monolog/src/Monolog/ErrorHandler.php

@@ -0,0 +1,239 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+use Monolog\Handler\AbstractHandler;
+
+/**
+ * Monolog error handler
+ *
+ * A facility to enable logging of runtime errors, exceptions and fatal errors.
+ *
+ * Quick setup: <code>ErrorHandler::register($logger);</code>
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class ErrorHandler
+{
+    private $logger;
+
+    private $previousExceptionHandler;
+    private $uncaughtExceptionLevel;
+
+    private $previousErrorHandler;
+    private $errorLevelMap;
+    private $handleOnlyReportedErrors;
+
+    private $hasFatalErrorHandler;
+    private $fatalLevel;
+    private $reservedMemory;
+    private $lastFatalTrace;
+    private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR);
+
+    public function __construct(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
+    }
+
+    /**
+     * Registers a new ErrorHandler for a given Logger
+     *
+     * By default it will handle errors, exceptions and fatal errors
+     *
+     * @param  LoggerInterface $logger
+     * @param  array|false     $errorLevelMap  an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
+     * @param  int|false       $exceptionLevel a LogLevel::* constant, or false to disable exception handling
+     * @param  int|false       $fatalLevel     a LogLevel::* constant, or false to disable fatal error handling
+     * @return ErrorHandler
+     */
+    public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null)
+    {
+        //Forces the autoloader to run for LogLevel. Fixes an autoload issue at compile-time on PHP5.3. See https://github.com/Seldaek/monolog/pull/929
+        class_exists('\\Psr\\Log\\LogLevel', true);
+
+        /** @phpstan-ignore-next-line */
+        $handler = new static($logger);
+        if ($errorLevelMap !== false) {
+            $handler->registerErrorHandler($errorLevelMap);
+        }
+        if ($exceptionLevel !== false) {
+            $handler->registerExceptionHandler($exceptionLevel);
+        }
+        if ($fatalLevel !== false) {
+            $handler->registerFatalHandler($fatalLevel);
+        }
+
+        return $handler;
+    }
+
+    public function registerExceptionHandler($level = null, $callPrevious = true)
+    {
+        $prev = set_exception_handler(array($this, 'handleException'));
+        $this->uncaughtExceptionLevel = $level;
+        if ($callPrevious && $prev) {
+            $this->previousExceptionHandler = $prev;
+        }
+    }
+
+    public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1, $handleOnlyReportedErrors = true)
+    {
+        $prev = set_error_handler(array($this, 'handleError'), $errorTypes);
+        $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
+        if ($callPrevious) {
+            $this->previousErrorHandler = $prev ?: true;
+        }
+
+        $this->handleOnlyReportedErrors = $handleOnlyReportedErrors;
+    }
+
+    public function registerFatalHandler($level = null, $reservedMemorySize = 20)
+    {
+        register_shutdown_function(array($this, 'handleFatalError'));
+
+        $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
+        $this->fatalLevel = $level;
+        $this->hasFatalErrorHandler = true;
+    }
+
+    protected function defaultErrorLevelMap()
+    {
+        return array(
+            E_ERROR             => LogLevel::CRITICAL,
+            E_WARNING           => LogLevel::WARNING,
+            E_PARSE             => LogLevel::ALERT,
+            E_NOTICE            => LogLevel::NOTICE,
+            E_CORE_ERROR        => LogLevel::CRITICAL,
+            E_CORE_WARNING      => LogLevel::WARNING,
+            E_COMPILE_ERROR     => LogLevel::ALERT,
+            E_COMPILE_WARNING   => LogLevel::WARNING,
+            E_USER_ERROR        => LogLevel::ERROR,
+            E_USER_WARNING      => LogLevel::WARNING,
+            E_USER_NOTICE       => LogLevel::NOTICE,
+            E_STRICT            => LogLevel::NOTICE,
+            E_RECOVERABLE_ERROR => LogLevel::ERROR,
+            E_DEPRECATED        => LogLevel::NOTICE,
+            E_USER_DEPRECATED   => LogLevel::NOTICE,
+        );
+    }
+
+    /**
+     * @private
+     */
+    public function handleException($e)
+    {
+        $this->logger->log(
+            $this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel,
+            sprintf('Uncaught Exception %s: "%s" at %s line %s', Utils::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()),
+            array('exception' => $e)
+        );
+
+        if ($this->previousExceptionHandler) {
+            call_user_func($this->previousExceptionHandler, $e);
+        }
+
+        exit(255);
+    }
+
+    /**
+     * @private
+     */
+    public function handleError($code, $message, $file = '', $line = 0, $context = array())
+    {
+        if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) {
+            return;
+        }
+
+        // fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries
+        if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) {
+            $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL;
+            $this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line));
+        } else {
+            // http://php.net/manual/en/function.debug-backtrace.php
+            // As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added.
+            // Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'.
+            $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS);
+            array_shift($trace); // Exclude handleError from trace
+            $this->lastFatalTrace = $trace;
+        }
+
+        if ($this->previousErrorHandler === true) {
+            return false;
+        } elseif ($this->previousErrorHandler) {
+            return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context);
+        }
+    }
+
+    /**
+     * @private
+     */
+    public function handleFatalError()
+    {
+        $this->reservedMemory = null;
+
+        $lastError = error_get_last();
+        if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) {
+            $this->logger->log(
+                $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel,
+                'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
+                array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace)
+            );
+
+            if ($this->logger instanceof Logger) {
+                foreach ($this->logger->getHandlers() as $handler) {
+                    if ($handler instanceof AbstractHandler) {
+                        $handler->close();
+                    }
+                }
+            }
+        }
+    }
+
+    private static function codeToString($code)
+    {
+        switch ($code) {
+            case E_ERROR:
+                return 'E_ERROR';
+            case E_WARNING:
+                return 'E_WARNING';
+            case E_PARSE:
+                return 'E_PARSE';
+            case E_NOTICE:
+                return 'E_NOTICE';
+            case E_CORE_ERROR:
+                return 'E_CORE_ERROR';
+            case E_CORE_WARNING:
+                return 'E_CORE_WARNING';
+            case E_COMPILE_ERROR:
+                return 'E_COMPILE_ERROR';
+            case E_COMPILE_WARNING:
+                return 'E_COMPILE_WARNING';
+            case E_USER_ERROR:
+                return 'E_USER_ERROR';
+            case E_USER_WARNING:
+                return 'E_USER_WARNING';
+            case E_USER_NOTICE:
+                return 'E_USER_NOTICE';
+            case E_STRICT:
+                return 'E_STRICT';
+            case E_RECOVERABLE_ERROR:
+                return 'E_RECOVERABLE_ERROR';
+            case E_DEPRECATED:
+                return 'E_DEPRECATED';
+            case E_USER_DEPRECATED:
+                return 'E_USER_DEPRECATED';
+        }
+
+        return 'Unknown PHP error';
+    }
+}

+ 78 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php

@@ -0,0 +1,78 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * Formats a log message according to the ChromePHP array format
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class ChromePHPFormatter implements FormatterInterface
+{
+    /**
+     * Translates Monolog log levels to Wildfire levels.
+     */
+    private $logLevels = array(
+        Logger::DEBUG     => 'log',
+        Logger::INFO      => 'info',
+        Logger::NOTICE    => 'info',
+        Logger::WARNING   => 'warn',
+        Logger::ERROR     => 'error',
+        Logger::CRITICAL  => 'error',
+        Logger::ALERT     => 'error',
+        Logger::EMERGENCY => 'error',
+    );
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        // Retrieve the line and file if set and remove them from the formatted extra
+        $backtrace = 'unknown';
+        if (isset($record['extra']['file'], $record['extra']['line'])) {
+            $backtrace = $record['extra']['file'].' : '.$record['extra']['line'];
+            unset($record['extra']['file'], $record['extra']['line']);
+        }
+
+        $message = array('message' => $record['message']);
+        if ($record['context']) {
+            $message['context'] = $record['context'];
+        }
+        if ($record['extra']) {
+            $message['extra'] = $record['extra'];
+        }
+        if (count($message) === 1) {
+            $message = reset($message);
+        }
+
+        return array(
+            $record['channel'],
+            $message,
+            $backtrace,
+            $this->logLevels[$record['level']],
+        );
+    }
+
+    public function formatBatch(array $records)
+    {
+        $formatted = array();
+
+        foreach ($records as $record) {
+            $formatted[] = $this->format($record);
+        }
+
+        return $formatted;
+    }
+}

+ 89 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php

@@ -0,0 +1,89 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Elastica\Document;
+
+/**
+ * Format a log message into an Elastica Document
+ *
+ * @author Jelle Vink <jelle.vink@gmail.com>
+ */
+class ElasticaFormatter extends NormalizerFormatter
+{
+    /**
+     * @var string Elastic search index name
+     */
+    protected $index;
+
+    /**
+     * @var string Elastic search document type
+     */
+    protected $type;
+
+    /**
+     * @param string $index Elastic Search index name
+     * @param string $type  Elastic Search document type
+     */
+    public function __construct($index, $type)
+    {
+        // elasticsearch requires a ISO 8601 format date with optional millisecond precision.
+        parent::__construct('Y-m-d\TH:i:s.uP');
+
+        $this->index = $index;
+        $this->type = $type;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        $record = parent::format($record);
+
+        return $this->getDocument($record);
+    }
+
+    /**
+     * Getter index
+     * @return string
+     */
+    public function getIndex()
+    {
+        return $this->index;
+    }
+
+    /**
+     * Getter type
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Convert a log message into an Elastica Document
+     *
+     * @param  array    $record Log message
+     * @return Document
+     */
+    protected function getDocument($record)
+    {
+        $document = new Document();
+        $document->setData($record);
+        $document->setType($this->type);
+        $document->setIndex($this->index);
+
+        return $document;
+    }
+}

+ 116 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php

@@ -0,0 +1,116 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * formats the record to be used in the FlowdockHandler
+ *
+ * @author Dominik Liebler <liebler.dominik@gmail.com>
+ */
+class FlowdockFormatter implements FormatterInterface
+{
+    /**
+     * @var string
+     */
+    private $source;
+
+    /**
+     * @var string
+     */
+    private $sourceEmail;
+
+    /**
+     * @param string $source
+     * @param string $sourceEmail
+     */
+    public function __construct($source, $sourceEmail)
+    {
+        $this->source = $source;
+        $this->sourceEmail = $sourceEmail;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        $tags = array(
+            '#logs',
+            '#' . strtolower($record['level_name']),
+            '#' . $record['channel'],
+        );
+
+        foreach ($record['extra'] as $value) {
+            $tags[] = '#' . $value;
+        }
+
+        $subject = sprintf(
+            'in %s: %s - %s',
+            $this->source,
+            $record['level_name'],
+            $this->getShortMessage($record['message'])
+        );
+
+        $record['flowdock'] = array(
+            'source' => $this->source,
+            'from_address' => $this->sourceEmail,
+            'subject' => $subject,
+            'content' => $record['message'],
+            'tags' => $tags,
+            'project' => $this->source,
+        );
+
+        return $record;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function formatBatch(array $records)
+    {
+        $formatted = array();
+
+        foreach ($records as $record) {
+            $formatted[] = $this->format($record);
+        }
+
+        return $formatted;
+    }
+
+    /**
+     * @param string $message
+     *
+     * @return string
+     */
+    public function getShortMessage($message)
+    {
+        static $hasMbString;
+
+        if (null === $hasMbString) {
+            $hasMbString = function_exists('mb_strlen');
+        }
+
+        $maxLength = 45;
+
+        if ($hasMbString) {
+            if (mb_strlen($message, 'UTF-8') > $maxLength) {
+                $message = mb_substr($message, 0, $maxLength - 4, 'UTF-8') . ' ...';
+            }
+        } else {
+            if (strlen($message) > $maxLength) {
+                $message = substr($message, 0, $maxLength - 4) . ' ...';
+            }
+        }
+
+        return $message;
+    }
+}

+ 88 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php

@@ -0,0 +1,88 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Utils;
+
+/**
+ * Class FluentdFormatter
+ *
+ * Serializes a log message to Fluentd unix socket protocol
+ *
+ * Fluentd config:
+ *
+ * <source>
+ *  type unix
+ *  path /var/run/td-agent/td-agent.sock
+ * </source>
+ *
+ * Monolog setup:
+ *
+ * $logger = new Monolog\Logger('fluent.tag');
+ * $fluentHandler = new Monolog\Handler\SocketHandler('unix:///var/run/td-agent/td-agent.sock');
+ * $fluentHandler->setFormatter(new Monolog\Formatter\FluentdFormatter());
+ * $logger->pushHandler($fluentHandler);
+ *
+ * @author Andrius Putna <fordnox@gmail.com>
+ */
+class FluentdFormatter implements FormatterInterface
+{
+    /**
+     * @var bool $levelTag should message level be a part of the fluentd tag
+     */
+    protected $levelTag = false;
+
+    public function __construct($levelTag = false)
+    {
+        if (!function_exists('json_encode')) {
+            throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s FluentdUnixFormatter');
+        }
+
+        $this->levelTag = (bool) $levelTag;
+    }
+
+    public function isUsingLevelsInTag()
+    {
+        return $this->levelTag;
+    }
+
+    public function format(array $record)
+    {
+        $tag = $record['channel'];
+        if ($this->levelTag) {
+            $tag .= '.' . strtolower($record['level_name']);
+        }
+
+        $message = array(
+            'message' => $record['message'],
+            'context' => $record['context'],
+            'extra' => $record['extra'],
+        );
+
+        if (!$this->levelTag) {
+            $message['level'] = $record['level'];
+            $message['level_name'] = $record['level_name'];
+        }
+
+        return Utils::jsonEncode(array($tag, $record['datetime']->getTimestamp(), $message));
+    }
+
+    public function formatBatch(array $records)
+    {
+        $message = '';
+        foreach ($records as $record) {
+            $message .= $this->format($record);
+        }
+
+        return $message;
+    }
+}

+ 36 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php

@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Interface for formatters
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface FormatterInterface
+{
+    /**
+     * Formats a log record.
+     *
+     * @param  array $record A record to format
+     * @return mixed The formatted record
+     */
+    public function format(array $record);
+
+    /**
+     * Formats a set of log records.
+     *
+     * @param  array $records A set of records to format
+     * @return mixed The formatted set of records
+     */
+    public function formatBatch(array $records);
+}

+ 138 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php

@@ -0,0 +1,138 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+use Gelf\Message;
+
+/**
+ * Serializes a log message to GELF
+ * @see http://www.graylog2.org/about/gelf
+ *
+ * @author Matt Lehner <mlehner@gmail.com>
+ */
+class GelfMessageFormatter extends NormalizerFormatter
+{
+    const DEFAULT_MAX_LENGTH = 32766;
+
+    /**
+     * @var string the name of the system for the Gelf log message
+     */
+    protected $systemName;
+
+    /**
+     * @var string a prefix for 'extra' fields from the Monolog record (optional)
+     */
+    protected $extraPrefix;
+
+    /**
+     * @var string a prefix for 'context' fields from the Monolog record (optional)
+     */
+    protected $contextPrefix;
+
+    /**
+     * @var int max length per field
+     */
+    protected $maxLength;
+
+    /**
+     * Translates Monolog log levels to Graylog2 log priorities.
+     */
+    private $logLevels = array(
+        Logger::DEBUG     => 7,
+        Logger::INFO      => 6,
+        Logger::NOTICE    => 5,
+        Logger::WARNING   => 4,
+        Logger::ERROR     => 3,
+        Logger::CRITICAL  => 2,
+        Logger::ALERT     => 1,
+        Logger::EMERGENCY => 0,
+    );
+
+    public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $maxLength = null)
+    {
+        parent::__construct('U.u');
+
+        $this->systemName = $systemName ?: gethostname();
+
+        $this->extraPrefix = $extraPrefix;
+        $this->contextPrefix = $contextPrefix;
+        $this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        $record = parent::format($record);
+
+        if (!isset($record['datetime'], $record['message'], $record['level'])) {
+            throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, '.var_export($record, true).' given');
+        }
+
+        $message = new Message();
+        $message
+            ->setTimestamp($record['datetime'])
+            ->setShortMessage((string) $record['message'])
+            ->setHost($this->systemName)
+            ->setLevel($this->logLevels[$record['level']]);
+
+        // message length + system name length + 200 for padding / metadata 
+        $len = 200 + strlen((string) $record['message']) + strlen($this->systemName);
+
+        if ($len > $this->maxLength) {
+            $message->setShortMessage(substr($record['message'], 0, $this->maxLength));
+        }
+
+        if (isset($record['channel'])) {
+            $message->setFacility($record['channel']);
+        }
+        if (isset($record['extra']['line'])) {
+            $message->setLine($record['extra']['line']);
+            unset($record['extra']['line']);
+        }
+        if (isset($record['extra']['file'])) {
+            $message->setFile($record['extra']['file']);
+            unset($record['extra']['file']);
+        }
+
+        foreach ($record['extra'] as $key => $val) {
+            $val = is_scalar($val) || null === $val ? $val : $this->toJson($val);
+            $len = strlen($this->extraPrefix . $key . $val);
+            if ($len > $this->maxLength) {
+                $message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength));
+                break;
+            }
+            $message->setAdditional($this->extraPrefix . $key, $val);
+        }
+
+        foreach ($record['context'] as $key => $val) {
+            $val = is_scalar($val) || null === $val ? $val : $this->toJson($val);
+            $len = strlen($this->contextPrefix . $key . $val);
+            if ($len > $this->maxLength) {
+                $message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength));
+                break;
+            }
+            $message->setAdditional($this->contextPrefix . $key, $val);
+        }
+
+        if (null === $message->getFile() && isset($record['context']['exception']['file'])) {
+            if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) {
+                $message->setFile($matches[1]);
+                $message->setLine($matches[2]);
+            }
+        }
+
+        return $message;
+    }
+}

+ 142 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php

@@ -0,0 +1,142 @@
+<?php
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Formats incoming records into an HTML table
+ *
+ * This is especially useful for html email logging
+ *
+ * @author Tiago Brito <tlfbrito@gmail.com>
+ */
+class HtmlFormatter extends NormalizerFormatter
+{
+    /**
+     * Translates Monolog log levels to html color priorities.
+     */
+    protected $logLevels = array(
+        Logger::DEBUG     => '#cccccc',
+        Logger::INFO      => '#468847',
+        Logger::NOTICE    => '#3a87ad',
+        Logger::WARNING   => '#c09853',
+        Logger::ERROR     => '#f0ad4e',
+        Logger::CRITICAL  => '#FF7708',
+        Logger::ALERT     => '#C12A19',
+        Logger::EMERGENCY => '#000000',
+    );
+
+    /**
+     * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+     */
+    public function __construct($dateFormat = null)
+    {
+        parent::__construct($dateFormat);
+    }
+
+    /**
+     * Creates an HTML table row
+     *
+     * @param  string $th       Row header content
+     * @param  string $td       Row standard cell content
+     * @param  bool   $escapeTd false if td content must not be html escaped
+     * @return string
+     */
+    protected function addRow($th, $td = ' ', $escapeTd = true)
+    {
+        $th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8');
+        if ($escapeTd) {
+            $td = '<pre>'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'</pre>';
+        }
+
+        return "<tr style=\"padding: 4px;text-align: left;\">\n<th style=\"vertical-align: top;background: #ccc;color: #000\" width=\"100\">$th:</th>\n<td style=\"padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000\">".$td."</td>\n</tr>";
+    }
+
+    /**
+     * Create a HTML h1 tag
+     *
+     * @param  string $title Text to be in the h1
+     * @param  int    $level Error level
+     * @return string
+     */
+    protected function addTitle($title, $level)
+    {
+        $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8');
+
+        return '<h1 style="background: '.$this->logLevels[$level].';color: #ffffff;padding: 5px;" class="monolog-output">'.$title.'</h1>';
+    }
+
+    /**
+     * Formats a log record.
+     *
+     * @param  array $record A record to format
+     * @return mixed The formatted record
+     */
+    public function format(array $record)
+    {
+        $output = $this->addTitle($record['level_name'], $record['level']);
+        $output .= '<table cellspacing="1" width="100%" class="monolog-output">';
+
+        $output .= $this->addRow('Message', (string) $record['message']);
+        $output .= $this->addRow('Time', $record['datetime']->format($this->dateFormat));
+        $output .= $this->addRow('Channel', $record['channel']);
+        if ($record['context']) {
+            $embeddedTable = '<table cellspacing="1" width="100%">';
+            foreach ($record['context'] as $key => $value) {
+                $embeddedTable .= $this->addRow($key, $this->convertToString($value));
+            }
+            $embeddedTable .= '</table>';
+            $output .= $this->addRow('Context', $embeddedTable, false);
+        }
+        if ($record['extra']) {
+            $embeddedTable = '<table cellspacing="1" width="100%">';
+            foreach ($record['extra'] as $key => $value) {
+                $embeddedTable .= $this->addRow($key, $this->convertToString($value));
+            }
+            $embeddedTable .= '</table>';
+            $output .= $this->addRow('Extra', $embeddedTable, false);
+        }
+
+        return $output.'</table>';
+    }
+
+    /**
+     * Formats a set of log records.
+     *
+     * @param  array $records A set of records to format
+     * @return mixed The formatted set of records
+     */
+    public function formatBatch(array $records)
+    {
+        $message = '';
+        foreach ($records as $record) {
+            $message .= $this->format($record);
+        }
+
+        return $message;
+    }
+
+    protected function convertToString($data)
+    {
+        if (null === $data || is_scalar($data)) {
+            return (string) $data;
+        }
+
+        $data = $this->normalize($data);
+        if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+            return Utils::jsonEncode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, true);
+        }
+
+        return str_replace('\\/', '/', Utils::jsonEncode($data, null, true));
+    }
+}

+ 212 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php

@@ -0,0 +1,212 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Exception;
+use Monolog\Utils;
+use Throwable;
+
+/**
+ * Encodes whatever record data is passed to it as json
+ *
+ * This can be useful to log to databases or remote APIs
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class JsonFormatter extends NormalizerFormatter
+{
+    const BATCH_MODE_JSON = 1;
+    const BATCH_MODE_NEWLINES = 2;
+
+    protected $batchMode;
+    protected $appendNewline;
+
+    /**
+     * @var bool
+     */
+    protected $includeStacktraces = false;
+
+    /**
+     * @param int $batchMode
+     * @param bool $appendNewline
+     */
+    public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
+    {
+        $this->batchMode = $batchMode;
+        $this->appendNewline = $appendNewline;
+    }
+
+    /**
+     * The batch mode option configures the formatting style for
+     * multiple records. By default, multiple records will be
+     * formatted as a JSON-encoded array. However, for
+     * compatibility with some API endpoints, alternative styles
+     * are available.
+     *
+     * @return int
+     */
+    public function getBatchMode()
+    {
+        return $this->batchMode;
+    }
+
+    /**
+     * True if newlines are appended to every formatted record
+     *
+     * @return bool
+     */
+    public function isAppendingNewlines()
+    {
+        return $this->appendNewline;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function formatBatch(array $records)
+    {
+        switch ($this->batchMode) {
+            case static::BATCH_MODE_NEWLINES:
+                return $this->formatBatchNewlines($records);
+
+            case static::BATCH_MODE_JSON:
+            default:
+                return $this->formatBatchJson($records);
+        }
+    }
+
+    /**
+     * @param bool $include
+     */
+    public function includeStacktraces($include = true)
+    {
+        $this->includeStacktraces = $include;
+    }
+
+    /**
+     * Return a JSON-encoded array of records.
+     *
+     * @param  array  $records
+     * @return string
+     */
+    protected function formatBatchJson(array $records)
+    {
+        return $this->toJson($this->normalize($records), true);
+    }
+
+    /**
+     * Use new lines to separate records instead of a
+     * JSON-encoded array.
+     *
+     * @param  array  $records
+     * @return string
+     */
+    protected function formatBatchNewlines(array $records)
+    {
+        $instance = $this;
+
+        $oldNewline = $this->appendNewline;
+        $this->appendNewline = false;
+        array_walk($records, function (&$value, $key) use ($instance) {
+            $value = $instance->format($value);
+        });
+        $this->appendNewline = $oldNewline;
+
+        return implode("\n", $records);
+    }
+
+    /**
+     * Normalizes given $data.
+     *
+     * @param mixed $data
+     *
+     * @return mixed
+     */
+    protected function normalize($data, $depth = 0)
+    {
+        if ($depth > 9) {
+            return 'Over 9 levels deep, aborting normalization';
+        }
+
+        if (is_array($data)) {
+            $normalized = array();
+
+            $count = 1;
+            foreach ($data as $key => $value) {
+                if ($count++ > 1000) {
+                    $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization';
+                    break;
+                }
+
+                $normalized[$key] = $this->normalize($value, $depth+1);
+            }
+
+            return $normalized;
+        }
+
+        if ($data instanceof Exception || $data instanceof Throwable) {
+            return $this->normalizeException($data);
+        }
+
+        if (is_resource($data)) {
+            return parent::normalize($data);
+        }
+
+        return $data;
+    }
+
+    /**
+     * Normalizes given exception with or without its own stack trace based on
+     * `includeStacktraces` property.
+     *
+     * @param Exception|Throwable $e
+     *
+     * @return array
+     */
+    protected function normalizeException($e)
+    {
+        // TODO 2.0 only check for Throwable
+        if (!$e instanceof Exception && !$e instanceof Throwable) {
+            throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
+        }
+
+        $data = array(
+            'class' => Utils::getClass($e),
+            'message' => $e->getMessage(),
+            'code' => (int) $e->getCode(),
+            'file' => $e->getFile().':'.$e->getLine(),
+        );
+
+        if ($this->includeStacktraces) {
+            $trace = $e->getTrace();
+            foreach ($trace as $frame) {
+                if (isset($frame['file'])) {
+                    $data['trace'][] = $frame['file'].':'.$frame['line'];
+                }
+            }
+        }
+
+        if ($previous = $e->getPrevious()) {
+            $data['previous'] = $this->normalizeException($previous);
+        }
+
+        return $data;
+    }
+}

+ 181 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php

@@ -0,0 +1,181 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Utils;
+
+/**
+ * Formats incoming records into a one-line string
+ *
+ * This is especially useful for logging to files
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class LineFormatter extends NormalizerFormatter
+{
+    const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
+
+    protected $format;
+    protected $allowInlineLineBreaks;
+    protected $ignoreEmptyContextAndExtra;
+    protected $includeStacktraces;
+
+    /**
+     * @param string $format                     The format of the message
+     * @param string $dateFormat                 The format of the timestamp: one supported by DateTime::format
+     * @param bool   $allowInlineLineBreaks      Whether to allow inline line breaks in log entries
+     * @param bool   $ignoreEmptyContextAndExtra
+     */
+    public function __construct($format = null, $dateFormat = null, $allowInlineLineBreaks = false, $ignoreEmptyContextAndExtra = false)
+    {
+        $this->format = $format ?: static::SIMPLE_FORMAT;
+        $this->allowInlineLineBreaks = $allowInlineLineBreaks;
+        $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra;
+        parent::__construct($dateFormat);
+    }
+
+    public function includeStacktraces($include = true)
+    {
+        $this->includeStacktraces = $include;
+        if ($this->includeStacktraces) {
+            $this->allowInlineLineBreaks = true;
+        }
+    }
+
+    public function allowInlineLineBreaks($allow = true)
+    {
+        $this->allowInlineLineBreaks = $allow;
+    }
+
+    public function ignoreEmptyContextAndExtra($ignore = true)
+    {
+        $this->ignoreEmptyContextAndExtra = $ignore;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        $vars = parent::format($record);
+
+        $output = $this->format;
+
+        foreach ($vars['extra'] as $var => $val) {
+            if (false !== strpos($output, '%extra.'.$var.'%')) {
+                $output = str_replace('%extra.'.$var.'%', $this->stringify($val), $output);
+                unset($vars['extra'][$var]);
+            }
+        }
+
+
+        foreach ($vars['context'] as $var => $val) {
+            if (false !== strpos($output, '%context.'.$var.'%')) {
+                $output = str_replace('%context.'.$var.'%', $this->stringify($val), $output);
+                unset($vars['context'][$var]);
+            }
+        }
+
+        if ($this->ignoreEmptyContextAndExtra) {
+            if (empty($vars['context'])) {
+                unset($vars['context']);
+                $output = str_replace('%context%', '', $output);
+            }
+
+            if (empty($vars['extra'])) {
+                unset($vars['extra']);
+                $output = str_replace('%extra%', '', $output);
+            }
+        }
+
+        foreach ($vars as $var => $val) {
+            if (false !== strpos($output, '%'.$var.'%')) {
+                $output = str_replace('%'.$var.'%', $this->stringify($val), $output);
+            }
+        }
+
+        // remove leftover %extra.xxx% and %context.xxx% if any
+        if (false !== strpos($output, '%')) {
+            $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output);
+        }
+
+        return $output;
+    }
+
+    public function formatBatch(array $records)
+    {
+        $message = '';
+        foreach ($records as $record) {
+            $message .= $this->format($record);
+        }
+
+        return $message;
+    }
+
+    public function stringify($value)
+    {
+        return $this->replaceNewlines($this->convertToString($value));
+    }
+
+    protected function normalizeException($e)
+    {
+        // TODO 2.0 only check for Throwable
+        if (!$e instanceof \Exception && !$e instanceof \Throwable) {
+            throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
+        }
+
+        $previousText = '';
+        if ($previous = $e->getPrevious()) {
+            do {
+                $previousText .= ', '.Utils::getClass($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
+            } while ($previous = $previous->getPrevious());
+        }
+
+        $str = '[object] ('.Utils::getClass($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')';
+        if ($this->includeStacktraces) {
+            $str .= "\n[stacktrace]\n".$e->getTraceAsString()."\n";
+        }
+
+        return $str;
+    }
+
+    protected function convertToString($data)
+    {
+        if (null === $data || is_bool($data)) {
+            return var_export($data, true);
+        }
+
+        if (is_scalar($data)) {
+            return (string) $data;
+        }
+
+        if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+            return $this->toJson($data, true);
+        }
+
+        return str_replace('\\/', '/', $this->toJson($data, true));
+    }
+
+    protected function replaceNewlines($str)
+    {
+        if ($this->allowInlineLineBreaks) {
+            if (0 === strpos($str, '{')) {
+                return str_replace(array('\r', '\n'), array("\r", "\n"), $str);
+            }
+
+            return $str;
+        }
+
+        return str_replace(array("\r\n", "\r", "\n"), ' ', $str);
+    }
+}

+ 47 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php

@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Encodes message information into JSON in a format compatible with Loggly.
+ *
+ * @author Adam Pancutt <adam@pancutt.com>
+ */
+class LogglyFormatter extends JsonFormatter
+{
+    /**
+     * Overrides the default batch mode to new lines for compatibility with the
+     * Loggly bulk API.
+     *
+     * @param int $batchMode
+     */
+    public function __construct($batchMode = self::BATCH_MODE_NEWLINES, $appendNewline = false)
+    {
+        parent::__construct($batchMode, $appendNewline);
+    }
+
+    /**
+     * Appends the 'timestamp' parameter for indexing by Loggly.
+     *
+     * @see https://www.loggly.com/docs/automated-parsing/#json
+     * @see \Monolog\Formatter\JsonFormatter::format()
+     */
+    public function format(array $record)
+    {
+        if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTime)) {
+            $record["timestamp"] = $record["datetime"]->format("Y-m-d\TH:i:s.uO");
+            // TODO 2.0 unset the 'datetime' parameter, retained for BC
+        }
+
+        return parent::format($record);
+    }
+}

+ 166 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php

@@ -0,0 +1,166 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Serializes a log message to Logstash Event Format
+ *
+ * @see http://logstash.net/
+ * @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb
+ *
+ * @author Tim Mower <timothy.mower@gmail.com>
+ */
+class LogstashFormatter extends NormalizerFormatter
+{
+    const V0 = 0;
+    const V1 = 1;
+
+    /**
+     * @var string the name of the system for the Logstash log message, used to fill the @source field
+     */
+    protected $systemName;
+
+    /**
+     * @var string an application name for the Logstash log message, used to fill the @type field
+     */
+    protected $applicationName;
+
+    /**
+     * @var string a prefix for 'extra' fields from the Monolog record (optional)
+     */
+    protected $extraPrefix;
+
+    /**
+     * @var string a prefix for 'context' fields from the Monolog record (optional)
+     */
+    protected $contextPrefix;
+
+    /**
+     * @var int logstash format version to use
+     */
+    protected $version;
+
+    /**
+     * @param string $applicationName the application that sends the data, used as the "type" field of logstash
+     * @param string $systemName      the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine
+     * @param string $extraPrefix     prefix for extra keys inside logstash "fields"
+     * @param string $contextPrefix   prefix for context keys inside logstash "fields", defaults to ctxt_
+     * @param int    $version         the logstash format version to use, defaults to 0
+     */
+    public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0)
+    {
+        // logstash requires a ISO 8601 format date with optional millisecond precision.
+        parent::__construct('Y-m-d\TH:i:s.uP');
+
+        $this->systemName = $systemName ?: gethostname();
+        $this->applicationName = $applicationName;
+        $this->extraPrefix = $extraPrefix;
+        $this->contextPrefix = $contextPrefix;
+        $this->version = $version;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        $record = parent::format($record);
+
+        if ($this->version === self::V1) {
+            $message = $this->formatV1($record);
+        } else {
+            $message = $this->formatV0($record);
+        }
+
+        return $this->toJson($message) . "\n";
+    }
+
+    protected function formatV0(array $record)
+    {
+        if (empty($record['datetime'])) {
+            $record['datetime'] = gmdate('c');
+        }
+        $message = array(
+            '@timestamp' => $record['datetime'],
+            '@source' => $this->systemName,
+            '@fields' => array(),
+        );
+        if (isset($record['message'])) {
+            $message['@message'] = $record['message'];
+        }
+        if (isset($record['channel'])) {
+            $message['@tags'] = array($record['channel']);
+            $message['@fields']['channel'] = $record['channel'];
+        }
+        if (isset($record['level'])) {
+            $message['@fields']['level'] = $record['level'];
+        }
+        if ($this->applicationName) {
+            $message['@type'] = $this->applicationName;
+        }
+        if (isset($record['extra']['server'])) {
+            $message['@source_host'] = $record['extra']['server'];
+        }
+        if (isset($record['extra']['url'])) {
+            $message['@source_path'] = $record['extra']['url'];
+        }
+        if (!empty($record['extra'])) {
+            foreach ($record['extra'] as $key => $val) {
+                $message['@fields'][$this->extraPrefix . $key] = $val;
+            }
+        }
+        if (!empty($record['context'])) {
+            foreach ($record['context'] as $key => $val) {
+                $message['@fields'][$this->contextPrefix . $key] = $val;
+            }
+        }
+
+        return $message;
+    }
+
+    protected function formatV1(array $record)
+    {
+        if (empty($record['datetime'])) {
+            $record['datetime'] = gmdate('c');
+        }
+        $message = array(
+            '@timestamp' => $record['datetime'],
+            '@version' => 1,
+            'host' => $this->systemName,
+        );
+        if (isset($record['message'])) {
+            $message['message'] = $record['message'];
+        }
+        if (isset($record['channel'])) {
+            $message['type'] = $record['channel'];
+            $message['channel'] = $record['channel'];
+        }
+        if (isset($record['level_name'])) {
+            $message['level'] = $record['level_name'];
+        }
+        if ($this->applicationName) {
+            $message['type'] = $this->applicationName;
+        }
+        if (!empty($record['extra'])) {
+            foreach ($record['extra'] as $key => $val) {
+                $message[$this->extraPrefix . $key] = $val;
+            }
+        }
+        if (!empty($record['context'])) {
+            foreach ($record['context'] as $key => $val) {
+                $message[$this->contextPrefix . $key] = $val;
+            }
+        }
+
+        return $message;
+    }
+}

+ 107 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php

@@ -0,0 +1,107 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Utils;
+
+/**
+ * Formats a record for use with the MongoDBHandler.
+ *
+ * @author Florian Plattner <me@florianplattner.de>
+ */
+class MongoDBFormatter implements FormatterInterface
+{
+    private $exceptionTraceAsString;
+    private $maxNestingLevel;
+
+    /**
+     * @param int  $maxNestingLevel        0 means infinite nesting, the $record itself is level 1, $record['context'] is 2
+     * @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings
+     */
+    public function __construct($maxNestingLevel = 3, $exceptionTraceAsString = true)
+    {
+        $this->maxNestingLevel = max($maxNestingLevel, 0);
+        $this->exceptionTraceAsString = (bool) $exceptionTraceAsString;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function format(array $record)
+    {
+        return $this->formatArray($record);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function formatBatch(array $records)
+    {
+        foreach ($records as $key => $record) {
+            $records[$key] = $this->format($record);
+        }
+
+        return $records;
+    }
+
+    protected function formatArray(array $record, $nestingLevel = 0)
+    {
+        if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) {
+            foreach ($record as $name => $value) {
+                if ($value instanceof \DateTime) {
+                    $record[$name] = $this->formatDate($value, $nestingLevel + 1);
+                } elseif ($value instanceof \Exception) {
+                    $record[$name] = $this->formatException($value, $nestingLevel + 1);
+                } elseif (is_array($value)) {
+                    $record[$name] = $this->formatArray($value, $nestingLevel + 1);
+                } elseif (is_object($value)) {
+                    $record[$name] = $this->formatObject($value, $nestingLevel + 1);
+                }
+            }
+        } else {
+            $record = '[...]';
+        }
+
+        return $record;
+    }
+
+    protected function formatObject($value, $nestingLevel)
+    {
+        $objectVars = get_object_vars($value);
+        $objectVars['class'] = Utils::getClass($value);
+
+        return $this->formatArray($objectVars, $nestingLevel);
+    }
+
+    protected function formatException(\Exception $exception, $nestingLevel)
+    {
+        $formattedException = array(
+            'class' => Utils::getClass($exception),
+            'message' => $exception->getMessage(),
+            'code' => (int) $exception->getCode(),
+            'file' => $exception->getFile() . ':' . $exception->getLine(),
+        );
+
+        if ($this->exceptionTraceAsString === true) {
+            $formattedException['trace'] = $exception->getTraceAsString();
+        } else {
+            $formattedException['trace'] = $exception->getTrace();
+        }
+
+        return $this->formatArray($formattedException, $nestingLevel);
+    }
+
+    protected function formatDate(\DateTime $value, $nestingLevel)
+    {
+        return new \MongoDate($value->getTimestamp());
+    }
+}

+ 180 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php

@@ -0,0 +1,180 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Exception;
+use Monolog\Utils;
+
+/**
+ * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class NormalizerFormatter implements FormatterInterface
+{
+    const SIMPLE_DATE = "Y-m-d H:i:s";
+
+    protected $dateFormat;
+
+    /**
+     * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+     */
+    public function __construct($dateFormat = null)
+    {
+        $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
+        if (!function_exists('json_encode')) {
+            throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        return $this->normalize($record);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function formatBatch(array $records)
+    {
+        foreach ($records as $key => $record) {
+            $records[$key] = $this->format($record);
+        }
+
+        return $records;
+    }
+
+    protected function normalize($data, $depth = 0)
+    {
+        if ($depth > 9) {
+            return 'Over 9 levels deep, aborting normalization';
+        }
+
+        if (null === $data || is_scalar($data)) {
+            if (is_float($data)) {
+                if (is_infinite($data)) {
+                    return ($data > 0 ? '' : '-') . 'INF';
+                }
+                if (is_nan($data)) {
+                    return 'NaN';
+                }
+            }
+
+            return $data;
+        }
+
+        if (is_array($data)) {
+            $normalized = array();
+
+            $count = 1;
+            foreach ($data as $key => $value) {
+                if ($count++ > 1000) {
+                    $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization';
+                    break;
+                }
+
+                $normalized[$key] = $this->normalize($value, $depth+1);
+            }
+
+            return $normalized;
+        }
+
+        if ($data instanceof \DateTime) {
+            return $data->format($this->dateFormat);
+        }
+
+        if (is_object($data)) {
+            // TODO 2.0 only check for Throwable
+            if ($data instanceof Exception || (PHP_VERSION_ID > 70000 && $data instanceof \Throwable)) {
+                return $this->normalizeException($data);
+            }
+
+            // non-serializable objects that implement __toString stringified
+            if (method_exists($data, '__toString') && !$data instanceof \JsonSerializable) {
+                $value = $data->__toString();
+            } else {
+                // the rest is json-serialized in some way
+                $value = $this->toJson($data, true);
+            }
+
+            return sprintf("[object] (%s: %s)", Utils::getClass($data), $value);
+        }
+
+        if (is_resource($data)) {
+            return sprintf('[resource] (%s)', get_resource_type($data));
+        }
+
+        return '[unknown('.gettype($data).')]';
+    }
+
+    protected function normalizeException($e)
+    {
+        // TODO 2.0 only check for Throwable
+        if (!$e instanceof Exception && !$e instanceof \Throwable) {
+            throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
+        }
+
+        $data = array(
+            'class' => Utils::getClass($e),
+            'message' => $e->getMessage(),
+            'code' => (int) $e->getCode(),
+            'file' => $e->getFile().':'.$e->getLine(),
+        );
+
+        if ($e instanceof \SoapFault) {
+            if (isset($e->faultcode)) {
+                $data['faultcode'] = $e->faultcode;
+            }
+
+            if (isset($e->faultactor)) {
+                $data['faultactor'] = $e->faultactor;
+            }
+
+            if (isset($e->detail)) {
+                if  (is_string($e->detail)) {
+                    $data['detail'] = $e->detail;
+                } elseif (is_object($e->detail) || is_array($e->detail)) {
+                    $data['detail'] = $this->toJson($e->detail, true);
+                }
+            }
+        }
+
+        $trace = $e->getTrace();
+        foreach ($trace as $frame) {
+            if (isset($frame['file'])) {
+                $data['trace'][] = $frame['file'].':'.$frame['line'];
+            }
+        }
+
+        if ($previous = $e->getPrevious()) {
+            $data['previous'] = $this->normalizeException($previous);
+        }
+
+        return $data;
+    }
+
+    /**
+     * Return the JSON representation of a value
+     *
+     * @param  mixed             $data
+     * @param  bool              $ignoreErrors
+     * @throws \RuntimeException if encoding fails and errors are not ignored
+     * @return string
+     */
+    protected function toJson($data, $ignoreErrors = false)
+    {
+        return Utils::jsonEncode($data, null, $ignoreErrors);
+    }
+}

+ 48 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php

@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Formats data into an associative array of scalar values.
+ * Objects and arrays will be JSON encoded.
+ *
+ * @author Andrew Lawson <adlawson@gmail.com>
+ */
+class ScalarFormatter extends NormalizerFormatter
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        foreach ($record as $key => $value) {
+            $record[$key] = $this->normalizeValue($value);
+        }
+
+        return $record;
+    }
+
+    /**
+     * @param  mixed $value
+     * @return mixed
+     */
+    protected function normalizeValue($value)
+    {
+        $normalized = $this->normalize($value);
+
+        if (is_array($normalized) || is_object($normalized)) {
+            return $this->toJson($normalized, true);
+        }
+
+        return $normalized;
+    }
+}

+ 113 - 0
api/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php

@@ -0,0 +1,113 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * Serializes a log message according to Wildfire's header requirements
+ *
+ * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Kirill chEbba Chebunin <iam@chebba.org>
+ */
+class WildfireFormatter extends NormalizerFormatter
+{
+    const TABLE = 'table';
+
+    /**
+     * Translates Monolog log levels to Wildfire levels.
+     */
+    private $logLevels = array(
+        Logger::DEBUG     => 'LOG',
+        Logger::INFO      => 'INFO',
+        Logger::NOTICE    => 'INFO',
+        Logger::WARNING   => 'WARN',
+        Logger::ERROR     => 'ERROR',
+        Logger::CRITICAL  => 'ERROR',
+        Logger::ALERT     => 'ERROR',
+        Logger::EMERGENCY => 'ERROR',
+    );
+
+    /**
+     * {@inheritdoc}
+     */
+    public function format(array $record)
+    {
+        // Retrieve the line and file if set and remove them from the formatted extra
+        $file = $line = '';
+        if (isset($record['extra']['file'])) {
+            $file = $record['extra']['file'];
+            unset($record['extra']['file']);
+        }
+        if (isset($record['extra']['line'])) {
+            $line = $record['extra']['line'];
+            unset($record['extra']['line']);
+        }
+
+        $record = $this->normalize($record);
+        $message = array('message' => $record['message']);
+        $handleError = false;
+        if ($record['context']) {
+            $message['context'] = $record['context'];
+            $handleError = true;
+        }
+        if ($record['extra']) {
+            $message['extra'] = $record['extra'];
+            $handleError = true;
+        }
+        if (count($message) === 1) {
+            $message = reset($message);
+        }
+
+        if (isset($record['context'][self::TABLE])) {
+            $type  = 'TABLE';
+            $label = $record['channel'] .': '. $record['message'];
+            $message = $record['context'][self::TABLE];
+        } else {
+            $type  = $this->logLevels[$record['level']];
+            $label = $record['channel'];
+        }
+
+        // Create JSON object describing the appearance of the message in the console
+        $json = $this->toJson(array(
+            array(
+                'Type'  => $type,
+                'File'  => $file,
+                'Line'  => $line,
+                'Label' => $label,
+            ),
+            $message,
+        ), $handleError);
+
+        // The message itself is a serialization of the above JSON object + it's length
+        return sprintf(
+            '%s|%s|',
+            strlen($json),
+            $json
+        );
+    }
+
+    public function formatBatch(array $records)
+    {
+        throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter');
+    }
+
+    protected function normalize($data, $depth = 0)
+    {
+        if (is_object($data) && !$data instanceof \DateTime) {
+            return $data;
+        }
+
+        return parent::normalize($data, $depth);
+    }
+}

+ 196 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php

@@ -0,0 +1,196 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+use Monolog\ResettableInterface;
+
+/**
+ * Base Handler class providing the Handler structure
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+abstract class AbstractHandler implements HandlerInterface, ResettableInterface
+{
+    protected $level = Logger::DEBUG;
+    protected $bubble = true;
+
+    /**
+     * @var FormatterInterface
+     */
+    protected $formatter;
+    protected $processors = array();
+
+    /**
+     * @param int|string $level  The minimum logging level at which this handler will be triggered
+     * @param bool       $bubble Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($level = Logger::DEBUG, $bubble = true)
+    {
+        $this->setLevel($level);
+        $this->bubble = $bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isHandling(array $record)
+    {
+        return $record['level'] >= $this->level;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        foreach ($records as $record) {
+            $this->handle($record);
+        }
+    }
+
+    /**
+     * Closes the handler.
+     *
+     * This will be called automatically when the object is destroyed
+     */
+    public function close()
+    {
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function pushProcessor($callback)
+    {
+        if (!is_callable($callback)) {
+            throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
+        }
+        array_unshift($this->processors, $callback);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function popProcessor()
+    {
+        if (!$this->processors) {
+            throw new \LogicException('You tried to pop from an empty processor stack.');
+        }
+
+        return array_shift($this->processors);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->formatter = $formatter;
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormatter()
+    {
+        if (!$this->formatter) {
+            $this->formatter = $this->getDefaultFormatter();
+        }
+
+        return $this->formatter;
+    }
+
+    /**
+     * Sets minimum logging level at which this handler will be triggered.
+     *
+     * @param  int|string $level Level or level name
+     * @return self
+     */
+    public function setLevel($level)
+    {
+        $this->level = Logger::toMonologLevel($level);
+
+        return $this;
+    }
+
+    /**
+     * Gets minimum logging level at which this handler will be triggered.
+     *
+     * @return int
+     */
+    public function getLevel()
+    {
+        return $this->level;
+    }
+
+    /**
+     * Sets the bubbling behavior.
+     *
+     * @param  bool $bubble true means that this handler allows bubbling.
+     *                      false means that bubbling is not permitted.
+     * @return self
+     */
+    public function setBubble($bubble)
+    {
+        $this->bubble = $bubble;
+
+        return $this;
+    }
+
+    /**
+     * Gets the bubbling behavior.
+     *
+     * @return bool true means that this handler allows bubbling.
+     *              false means that bubbling is not permitted.
+     */
+    public function getBubble()
+    {
+        return $this->bubble;
+    }
+
+    public function __destruct()
+    {
+        try {
+            $this->close();
+        } catch (\Exception $e) {
+            // do nothing
+        } catch (\Throwable $e) {
+            // do nothing
+        }
+    }
+
+    public function reset()
+    {
+        foreach ($this->processors as $processor) {
+            if ($processor instanceof ResettableInterface) {
+                $processor->reset();
+            }
+        }
+    }
+
+    /**
+     * Gets the default formatter.
+     *
+     * @return FormatterInterface
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter();
+    }
+}

+ 68 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php

@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\ResettableInterface;
+
+/**
+ * Base Handler class providing the Handler structure
+ *
+ * Classes extending it should (in most cases) only implement write($record)
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+abstract class AbstractProcessingHandler extends AbstractHandler
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        if (!$this->isHandling($record)) {
+            return false;
+        }
+
+        $record = $this->processRecord($record);
+
+        $record['formatted'] = $this->getFormatter()->format($record);
+
+        $this->write($record);
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * Writes the record down to the log of the implementing handler
+     *
+     * @param  array $record
+     * @return void
+     */
+    abstract protected function write(array $record);
+
+    /**
+     * Processes a record.
+     *
+     * @param  array $record
+     * @return array
+     */
+    protected function processRecord(array $record)
+    {
+        if ($this->processors) {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+        }
+
+        return $record;
+    }
+}

+ 101 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php

@@ -0,0 +1,101 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Common syslog functionality
+ */
+abstract class AbstractSyslogHandler extends AbstractProcessingHandler
+{
+    protected $facility;
+
+    /**
+     * Translates Monolog log levels to syslog log priorities.
+     */
+    protected $logLevels = array(
+        Logger::DEBUG     => LOG_DEBUG,
+        Logger::INFO      => LOG_INFO,
+        Logger::NOTICE    => LOG_NOTICE,
+        Logger::WARNING   => LOG_WARNING,
+        Logger::ERROR     => LOG_ERR,
+        Logger::CRITICAL  => LOG_CRIT,
+        Logger::ALERT     => LOG_ALERT,
+        Logger::EMERGENCY => LOG_EMERG,
+    );
+
+    /**
+     * List of valid log facility names.
+     */
+    protected $facilities = array(
+        'auth'     => LOG_AUTH,
+        'authpriv' => LOG_AUTHPRIV,
+        'cron'     => LOG_CRON,
+        'daemon'   => LOG_DAEMON,
+        'kern'     => LOG_KERN,
+        'lpr'      => LOG_LPR,
+        'mail'     => LOG_MAIL,
+        'news'     => LOG_NEWS,
+        'syslog'   => LOG_SYSLOG,
+        'user'     => LOG_USER,
+        'uucp'     => LOG_UUCP,
+    );
+
+    /**
+     * @param mixed $facility
+     * @param int   $level The minimum logging level at which this handler will be triggered
+     * @param bool  $bubble Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+
+        if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
+            $this->facilities['local0'] = LOG_LOCAL0;
+            $this->facilities['local1'] = LOG_LOCAL1;
+            $this->facilities['local2'] = LOG_LOCAL2;
+            $this->facilities['local3'] = LOG_LOCAL3;
+            $this->facilities['local4'] = LOG_LOCAL4;
+            $this->facilities['local5'] = LOG_LOCAL5;
+            $this->facilities['local6'] = LOG_LOCAL6;
+            $this->facilities['local7'] = LOG_LOCAL7;
+        } else {
+            $this->facilities['local0'] = 128; // LOG_LOCAL0
+            $this->facilities['local1'] = 136; // LOG_LOCAL1
+            $this->facilities['local2'] = 144; // LOG_LOCAL2
+            $this->facilities['local3'] = 152; // LOG_LOCAL3
+            $this->facilities['local4'] = 160; // LOG_LOCAL4
+            $this->facilities['local5'] = 168; // LOG_LOCAL5
+            $this->facilities['local6'] = 176; // LOG_LOCAL6
+            $this->facilities['local7'] = 184; // LOG_LOCAL7
+        }
+
+        // convert textual description of facility to syslog constant
+        if (array_key_exists(strtolower($facility), $this->facilities)) {
+            $facility = $this->facilities[strtolower($facility)];
+        } elseif (!in_array($facility, array_values($this->facilities), true)) {
+            throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given');
+        }
+
+        $this->facility = $facility;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%');
+    }
+}

+ 148 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php

@@ -0,0 +1,148 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\JsonFormatter;
+use PhpAmqpLib\Message\AMQPMessage;
+use PhpAmqpLib\Channel\AMQPChannel;
+use AMQPExchange;
+
+class AmqpHandler extends AbstractProcessingHandler
+{
+    /**
+     * @var AMQPExchange|AMQPChannel $exchange
+     */
+    protected $exchange;
+
+    /**
+     * @var string
+     */
+    protected $exchangeName;
+
+    /**
+     * @param AMQPExchange|AMQPChannel $exchange     AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use
+     * @param string                   $exchangeName
+     * @param int                      $level
+     * @param bool                     $bubble       Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true)
+    {
+        if ($exchange instanceof AMQPExchange) {
+            $exchange->setName($exchangeName);
+        } elseif ($exchange instanceof AMQPChannel) {
+            $this->exchangeName = $exchangeName;
+        } else {
+            throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required');
+        }
+        $this->exchange = $exchange;
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record)
+    {
+        $data = $record["formatted"];
+        $routingKey = $this->getRoutingKey($record);
+
+        if ($this->exchange instanceof AMQPExchange) {
+            $this->exchange->publish(
+                $data,
+                $routingKey,
+                0,
+                array(
+                    'delivery_mode' => 2,
+                    'content_type' => 'application/json',
+                )
+            );
+        } else {
+            $this->exchange->basic_publish(
+                $this->createAmqpMessage($data),
+                $this->exchangeName,
+                $routingKey
+            );
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function handleBatch(array $records)
+    {
+        if ($this->exchange instanceof AMQPExchange) {
+            parent::handleBatch($records);
+
+            return;
+        }
+
+        foreach ($records as $record) {
+            if (!$this->isHandling($record)) {
+                continue;
+            }
+
+            $record = $this->processRecord($record);
+            $data = $this->getFormatter()->format($record);
+
+            $this->exchange->batch_basic_publish(
+                $this->createAmqpMessage($data),
+                $this->exchangeName,
+                $this->getRoutingKey($record)
+            );
+        }
+
+        $this->exchange->publish_batch();
+    }
+
+    /**
+     * Gets the routing key for the AMQP exchange
+     *
+     * @param  array  $record
+     * @return string
+     */
+    protected function getRoutingKey(array $record)
+    {
+        $routingKey = sprintf(
+            '%s.%s',
+            // TODO 2.0 remove substr call
+            substr($record['level_name'], 0, 4),
+            $record['channel']
+        );
+
+        return strtolower($routingKey);
+    }
+
+    /**
+     * @param  string      $data
+     * @return AMQPMessage
+     */
+    private function createAmqpMessage($data)
+    {
+        return new AMQPMessage(
+            (string) $data,
+            array(
+                'delivery_mode' => 2,
+                'content_type' => 'application/json',
+            )
+        );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+    }
+}

+ 241 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php

@@ -0,0 +1,241 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Handler sending logs to browser's javascript console with no browser extension required
+ *
+ * @author Olivier Poitrey <rs@dailymotion.com>
+ */
+class BrowserConsoleHandler extends AbstractProcessingHandler
+{
+    protected static $initialized = false;
+    protected static $records = array();
+
+    /**
+     * {@inheritDoc}
+     *
+     * Formatted output may contain some formatting markers to be transferred to `console.log` using the %c format.
+     *
+     * Example of formatted string:
+     *
+     *     You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%');
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record)
+    {
+        // Accumulate records
+        static::$records[] = $record;
+
+        // Register shutdown handler if not already done
+        if (!static::$initialized) {
+            static::$initialized = true;
+            $this->registerShutdownFunction();
+        }
+    }
+
+    /**
+     * Convert records to javascript console commands and send it to the browser.
+     * This method is automatically called on PHP shutdown if output is HTML or Javascript.
+     */
+    public static function send()
+    {
+        $format = static::getResponseFormat();
+        if ($format === 'unknown') {
+            return;
+        }
+
+        if (count(static::$records)) {
+            if ($format === 'html') {
+                static::writeOutput('<script>' . static::generateScript() . '</script>');
+            } elseif ($format === 'js') {
+                static::writeOutput(static::generateScript());
+            }
+            static::resetStatic();
+        }
+    }
+
+    public function close()
+    {
+        self::resetStatic();
+    }
+
+    public function reset()
+    {
+        self::resetStatic();
+    }
+
+    /**
+     * Forget all logged records
+     */
+    public static function resetStatic()
+    {
+        static::$records = array();
+    }
+
+    /**
+     * Wrapper for register_shutdown_function to allow overriding
+     */
+    protected function registerShutdownFunction()
+    {
+        if (PHP_SAPI !== 'cli') {
+            register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
+        }
+    }
+
+    /**
+     * Wrapper for echo to allow overriding
+     *
+     * @param string $str
+     */
+    protected static function writeOutput($str)
+    {
+        echo $str;
+    }
+
+    /**
+     * Checks the format of the response
+     *
+     * If Content-Type is set to application/javascript or text/javascript -> js
+     * If Content-Type is set to text/html, or is unset -> html
+     * If Content-Type is anything else -> unknown
+     *
+     * @return string One of 'js', 'html' or 'unknown'
+     */
+    protected static function getResponseFormat()
+    {
+        // Check content type
+        foreach (headers_list() as $header) {
+            if (stripos($header, 'content-type:') === 0) {
+                // This handler only works with HTML and javascript outputs
+                // text/javascript is obsolete in favour of application/javascript, but still used
+                if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
+                    return 'js';
+                }
+                if (stripos($header, 'text/html') === false) {
+                    return 'unknown';
+                }
+                break;
+            }
+        }
+
+        return 'html';
+    }
+
+    private static function generateScript()
+    {
+        $script = array();
+        foreach (static::$records as $record) {
+            $context = static::dump('Context', $record['context']);
+            $extra = static::dump('Extra', $record['extra']);
+
+            if (empty($context) && empty($extra)) {
+                $script[] = static::call_array('log', static::handleStyles($record['formatted']));
+            } else {
+                $script = array_merge($script,
+                    array(static::call_array('groupCollapsed', static::handleStyles($record['formatted']))),
+                    $context,
+                    $extra,
+                    array(static::call('groupEnd'))
+                );
+            }
+        }
+
+        return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
+    }
+
+    private static function handleStyles($formatted)
+    {
+        $args = array();
+        $format = '%c' . $formatted;
+        preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
+
+        foreach (array_reverse($matches) as $match) {
+            $args[] = '"font-weight: normal"';
+            $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
+
+            $pos = $match[0][1];
+            $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
+        }
+
+        $args[] = static::quote('font-weight: normal');
+        $args[] = static::quote($format);
+
+        return array_reverse($args);
+    }
+
+    private static function handleCustomStyles($style, $string)
+    {
+        static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey');
+        static $labels = array();
+
+        return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) {
+            if (trim($m[1]) === 'autolabel') {
+                // Format the string as a label with consistent auto assigned background color
+                if (!isset($labels[$string])) {
+                    $labels[$string] = $colors[count($labels) % count($colors)];
+                }
+                $color = $labels[$string];
+
+                return "background-color: $color; color: white; border-radius: 3px; padding: 0 2px 0 2px";
+            }
+
+            return $m[1];
+        }, $style);
+    }
+
+    private static function dump($title, array $dict)
+    {
+        $script = array();
+        $dict = array_filter($dict);
+        if (empty($dict)) {
+            return $script;
+        }
+        $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title));
+        foreach ($dict as $key => $value) {
+            $value = json_encode($value);
+            if (empty($value)) {
+                $value = static::quote('');
+            }
+            $script[] = static::call('log', static::quote('%s: %o'), static::quote($key), $value);
+        }
+
+        return $script;
+    }
+
+    private static function quote($arg)
+    {
+        return '"' . addcslashes($arg, "\"\n\\") . '"';
+    }
+
+    private static function call()
+    {
+        $args = func_get_args();
+        $method = array_shift($args);
+
+        return static::call_array($method, $args);
+    }
+
+    private static function call_array($method, array $args)
+    {
+        return 'c.' . $method . '(' . implode(', ', $args) . ');';
+    }
+}

+ 148 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php

@@ -0,0 +1,148 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\ResettableInterface;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Buffers all records until closing the handler and then pass them as batch.
+ *
+ * This is useful for a MailHandler to send only one mail per request instead of
+ * sending one per log message.
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class BufferHandler extends AbstractHandler
+{
+    protected $handler;
+    protected $bufferSize = 0;
+    protected $bufferLimit;
+    protected $flushOnOverflow;
+    protected $buffer = array();
+    protected $initialized = false;
+
+    /**
+     * @param HandlerInterface $handler         Handler.
+     * @param int              $bufferLimit     How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+     * @param int              $level           The minimum logging level at which this handler will be triggered
+     * @param bool             $bubble          Whether the messages that are handled can bubble up the stack or not
+     * @param bool             $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
+     */
+    public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
+    {
+        parent::__construct($level, $bubble);
+        $this->handler = $handler;
+        $this->bufferLimit = (int) $bufferLimit;
+        $this->flushOnOverflow = $flushOnOverflow;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        if ($record['level'] < $this->level) {
+            return false;
+        }
+
+        if (!$this->initialized) {
+            // __destructor() doesn't get called on Fatal errors
+            register_shutdown_function(array($this, 'close'));
+            $this->initialized = true;
+        }
+
+        if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
+            if ($this->flushOnOverflow) {
+                $this->flush();
+            } else {
+                array_shift($this->buffer);
+                $this->bufferSize--;
+            }
+        }
+
+        if ($this->processors) {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+        }
+
+        $this->buffer[] = $record;
+        $this->bufferSize++;
+
+        return false === $this->bubble;
+    }
+
+    public function flush()
+    {
+        if ($this->bufferSize === 0) {
+            return;
+        }
+
+        $this->handler->handleBatch($this->buffer);
+        $this->clear();
+    }
+
+    public function __destruct()
+    {
+        // suppress the parent behavior since we already have register_shutdown_function()
+        // to call close(), and the reference contained there will prevent this from being
+        // GC'd until the end of the request
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        $this->flush();
+    }
+
+    /**
+     * Clears the buffer without flushing any messages down to the wrapped handler.
+     */
+    public function clear()
+    {
+        $this->bufferSize = 0;
+        $this->buffer = array();
+    }
+
+    public function reset()
+    {
+        $this->flush();
+
+        parent::reset();
+
+        if ($this->handler instanceof ResettableInterface) {
+            $this->handler->reset();
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->handler->setFormatter($formatter);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormatter()
+    {
+        return $this->handler->getFormatter();
+    }
+}

+ 212 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php

@@ -0,0 +1,212 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\ChromePHPFormatter;
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
+ *
+ * This also works out of the box with Firefox 43+
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ */
+class ChromePHPHandler extends AbstractProcessingHandler
+{
+    /**
+     * Version of the extension
+     */
+    const VERSION = '4.0';
+
+    /**
+     * Header name
+     */
+    const HEADER_NAME = 'X-ChromeLogger-Data';
+
+    /**
+     * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+)
+     */
+    const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}';
+
+    protected static $initialized = false;
+
+    /**
+     * Tracks whether we sent too much data
+     *
+     * Chrome limits the headers to 4KB, so when we sent 3KB we stop sending
+     *
+     * @var bool
+     */
+    protected static $overflowed = false;
+
+    protected static $json = array(
+        'version' => self::VERSION,
+        'columns' => array('label', 'log', 'backtrace', 'type'),
+        'rows' => array(),
+    );
+
+    protected static $sendHeaders = true;
+
+    /**
+     * @param int  $level  The minimum logging level at which this handler will be triggered
+     * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($level = Logger::DEBUG, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+        if (!function_exists('json_encode')) {
+            throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s ChromePHPHandler');
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        $messages = array();
+
+        foreach ($records as $record) {
+            if ($record['level'] < $this->level) {
+                continue;
+            }
+            $messages[] = $this->processRecord($record);
+        }
+
+        if (!empty($messages)) {
+            $messages = $this->getFormatter()->formatBatch($messages);
+            self::$json['rows'] = array_merge(self::$json['rows'], $messages);
+            $this->send();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new ChromePHPFormatter();
+    }
+
+    /**
+     * Creates & sends header for a record
+     *
+     * @see sendHeader()
+     * @see send()
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        self::$json['rows'][] = $record['formatted'];
+
+        $this->send();
+    }
+
+    /**
+     * Sends the log header
+     *
+     * @see sendHeader()
+     */
+    protected function send()
+    {
+        if (self::$overflowed || !self::$sendHeaders) {
+            return;
+        }
+
+        if (!self::$initialized) {
+            self::$initialized = true;
+
+            self::$sendHeaders = $this->headersAccepted();
+            if (!self::$sendHeaders) {
+                return;
+            }
+
+            self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
+        }
+
+        $json = Utils::jsonEncode(self::$json, null, true);
+        $data = base64_encode(utf8_encode($json));
+        if (strlen($data) > 3 * 1024) {
+            self::$overflowed = true;
+
+            $record = array(
+                'message' => 'Incomplete logs, chrome header size limit reached',
+                'context' => array(),
+                'level' => Logger::WARNING,
+                'level_name' => Logger::getLevelName(Logger::WARNING),
+                'channel' => 'monolog',
+                'datetime' => new \DateTime(),
+                'extra' => array(),
+            );
+            self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
+            $json = Utils::jsonEncode(self::$json, null, true);
+            $data = base64_encode(utf8_encode($json));
+        }
+
+        if (trim($data) !== '') {
+            $this->sendHeader(self::HEADER_NAME, $data);
+        }
+    }
+
+    /**
+     * Send header string to the client
+     *
+     * @param string $header
+     * @param string $content
+     */
+    protected function sendHeader($header, $content)
+    {
+        if (!headers_sent() && self::$sendHeaders) {
+            header(sprintf('%s: %s', $header, $content));
+        }
+    }
+
+    /**
+     * Verifies if the headers are accepted by the current user agent
+     *
+     * @return bool
+     */
+    protected function headersAccepted()
+    {
+        if (empty($_SERVER['HTTP_USER_AGENT'])) {
+            return false;
+        }
+
+        return preg_match(self::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']);
+    }
+
+    /**
+     * BC getter for the sendHeaders property that has been made static
+     */
+    public function __get($property)
+    {
+        if ('sendHeaders' !== $property) {
+            throw new \InvalidArgumentException('Undefined property '.$property);
+        }
+
+        return static::$sendHeaders;
+    }
+
+    /**
+     * BC setter for the sendHeaders property that has been made static
+     */
+    public function __set($property, $value)
+    {
+        if ('sendHeaders' !== $property) {
+            throw new \InvalidArgumentException('Undefined property '.$property);
+        }
+
+        static::$sendHeaders = $value;
+    }
+}

+ 72 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php

@@ -0,0 +1,72 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\JsonFormatter;
+use Monolog\Logger;
+
+/**
+ * CouchDB handler
+ *
+ * @author Markus Bachmann <markus.bachmann@bachi.biz>
+ */
+class CouchDBHandler extends AbstractProcessingHandler
+{
+    private $options;
+
+    public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true)
+    {
+        $this->options = array_merge(array(
+            'host'     => 'localhost',
+            'port'     => 5984,
+            'dbname'   => 'logger',
+            'username' => null,
+            'password' => null,
+        ), $options);
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record)
+    {
+        $basicAuth = null;
+        if ($this->options['username']) {
+            $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']);
+        }
+
+        $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname'];
+        $context = stream_context_create(array(
+            'http' => array(
+                'method'        => 'POST',
+                'content'       => $record['formatted'],
+                'ignore_errors' => true,
+                'max_redirects' => 0,
+                'header'        => 'Content-type: application/json',
+            ),
+        ));
+
+        if (false === @file_get_contents($url, null, $context)) {
+            throw new \RuntimeException(sprintf('Could not connect to %s', $url));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+    }
+}

+ 152 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php

@@ -0,0 +1,152 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Logs to Cube.
+ *
+ * @link http://square.github.com/cube/
+ * @author Wan Chen <kami@kamisama.me>
+ */
+class CubeHandler extends AbstractProcessingHandler
+{
+    private $udpConnection;
+    private $httpConnection;
+    private $scheme;
+    private $host;
+    private $port;
+    private $acceptedSchemes = array('http', 'udp');
+
+    /**
+     * Create a Cube handler
+     *
+     * @throws \UnexpectedValueException when given url is not a valid url.
+     *                                   A valid url must consist of three parts : protocol://host:port
+     *                                   Only valid protocols used by Cube are http and udp
+     */
+    public function __construct($url, $level = Logger::DEBUG, $bubble = true)
+    {
+        $urlInfo = parse_url($url);
+
+        if (!isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) {
+            throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
+        }
+
+        if (!in_array($urlInfo['scheme'], $this->acceptedSchemes)) {
+            throw new \UnexpectedValueException(
+                'Invalid protocol (' . $urlInfo['scheme']  . ').'
+                . ' Valid options are ' . implode(', ', $this->acceptedSchemes));
+        }
+
+        $this->scheme = $urlInfo['scheme'];
+        $this->host = $urlInfo['host'];
+        $this->port = $urlInfo['port'];
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * Establish a connection to an UDP socket
+     *
+     * @throws \LogicException           when unable to connect to the socket
+     * @throws MissingExtensionException when there is no socket extension
+     */
+    protected function connectUdp()
+    {
+        if (!extension_loaded('sockets')) {
+            throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler');
+        }
+
+        $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0);
+        if (!$this->udpConnection) {
+            throw new \LogicException('Unable to create a socket');
+        }
+
+        if (!socket_connect($this->udpConnection, $this->host, $this->port)) {
+            throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port);
+        }
+    }
+
+    /**
+     * Establish a connection to a http server
+     * @throws \LogicException when no curl extension
+     */
+    protected function connectHttp()
+    {
+        if (!extension_loaded('curl')) {
+            throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler');
+        }
+
+        $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put');
+
+        if (!$this->httpConnection) {
+            throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port);
+        }
+
+        curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST");
+        curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $date = $record['datetime'];
+
+        $data = array('time' => $date->format('Y-m-d\TH:i:s.uO'));
+        unset($record['datetime']);
+
+        if (isset($record['context']['type'])) {
+            $data['type'] = $record['context']['type'];
+            unset($record['context']['type']);
+        } else {
+            $data['type'] = $record['channel'];
+        }
+
+        $data['data'] = $record['context'];
+        $data['data']['level'] = $record['level'];
+
+        if ($this->scheme === 'http') {
+            $this->writeHttp(Utils::jsonEncode($data));
+        } else {
+            $this->writeUdp(Utils::jsonEncode($data));
+        }
+    }
+
+    private function writeUdp($data)
+    {
+        if (!$this->udpConnection) {
+            $this->connectUdp();
+        }
+
+        socket_send($this->udpConnection, $data, strlen($data), 0);
+    }
+
+    private function writeHttp($data)
+    {
+        if (!$this->httpConnection) {
+            $this->connectHttp();
+        }
+
+        curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
+        curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array(
+            'Content-Type: application/json',
+            'Content-Length: ' . strlen('['.$data.']'),
+        ));
+
+        Curl\Util::execute($this->httpConnection, 5, false);
+    }
+}

+ 57 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php

@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\Curl;
+
+class Util
+{
+    private static $retriableErrorCodes = array(
+        CURLE_COULDNT_RESOLVE_HOST,
+        CURLE_COULDNT_CONNECT,
+        CURLE_HTTP_NOT_FOUND,
+        CURLE_READ_ERROR,
+        CURLE_OPERATION_TIMEOUTED,
+        CURLE_HTTP_POST_ERROR,
+        CURLE_SSL_CONNECT_ERROR,
+    );
+
+    /**
+     * Executes a CURL request with optional retries and exception on failure
+     *
+     * @param  resource          $ch curl handler
+     * @throws \RuntimeException
+     */
+    public static function execute($ch, $retries = 5, $closeAfterDone = true)
+    {
+        while ($retries--) {
+            if (curl_exec($ch) === false) {
+                $curlErrno = curl_errno($ch);
+
+                if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) {
+                    $curlError = curl_error($ch);
+
+                    if ($closeAfterDone) {
+                        curl_close($ch);
+                    }
+
+                    throw new \RuntimeException(sprintf('Curl error (code %s): %s', $curlErrno, $curlError));
+                }
+
+                continue;
+            }
+
+            if ($closeAfterDone) {
+                curl_close($ch);
+            }
+            break;
+        }
+    }
+}

+ 169 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php

@@ -0,0 +1,169 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Simple handler wrapper that deduplicates log records across multiple requests
+ *
+ * It also includes the BufferHandler functionality and will buffer
+ * all messages until the end of the request or flush() is called.
+ *
+ * This works by storing all log records' messages above $deduplicationLevel
+ * to the file specified by $deduplicationStore. When further logs come in at the end of the
+ * request (or when flush() is called), all those above $deduplicationLevel are checked
+ * against the existing stored logs. If they match and the timestamps in the stored log is
+ * not older than $time seconds, the new log record is discarded. If no log record is new, the
+ * whole data set is discarded.
+ *
+ * This is mainly useful in combination with Mail handlers or things like Slack or HipChat handlers
+ * that send messages to people, to avoid spamming with the same message over and over in case of
+ * a major component failure like a database server being down which makes all requests fail in the
+ * same way.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class DeduplicationHandler extends BufferHandler
+{
+    /**
+     * @var string
+     */
+    protected $deduplicationStore;
+
+    /**
+     * @var int
+     */
+    protected $deduplicationLevel;
+
+    /**
+     * @var int
+     */
+    protected $time;
+
+    /**
+     * @var bool
+     */
+    private $gc = false;
+
+    /**
+     * @param HandlerInterface $handler            Handler.
+     * @param string           $deduplicationStore The file/path where the deduplication log should be kept
+     * @param int              $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes
+     * @param int              $time               The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through
+     * @param bool             $bubble             Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true)
+    {
+        parent::__construct($handler, 0, Logger::DEBUG, $bubble, false);
+
+        $this->deduplicationStore = $deduplicationStore === null ? sys_get_temp_dir() . '/monolog-dedup-' . substr(md5(__FILE__), 0, 20) .'.log' : $deduplicationStore;
+        $this->deduplicationLevel = Logger::toMonologLevel($deduplicationLevel);
+        $this->time = $time;
+    }
+
+    public function flush()
+    {
+        if ($this->bufferSize === 0) {
+            return;
+        }
+
+        $passthru = null;
+
+        foreach ($this->buffer as $record) {
+            if ($record['level'] >= $this->deduplicationLevel) {
+
+                $passthru = $passthru || !$this->isDuplicate($record);
+                if ($passthru) {
+                    $this->appendRecord($record);
+                }
+            }
+        }
+
+        // default of null is valid as well as if no record matches duplicationLevel we just pass through
+        if ($passthru === true || $passthru === null) {
+            $this->handler->handleBatch($this->buffer);
+        }
+
+        $this->clear();
+
+        if ($this->gc) {
+            $this->collectLogs();
+        }
+    }
+
+    private function isDuplicate(array $record)
+    {
+        if (!file_exists($this->deduplicationStore)) {
+            return false;
+        }
+
+        $store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+        if (!is_array($store)) {
+            return false;
+        }
+
+        $yesterday = time() - 86400;
+        $timestampValidity = $record['datetime']->getTimestamp() - $this->time;
+        $expectedMessage = preg_replace('{[\r\n].*}', '', $record['message']);
+
+        for ($i = count($store) - 1; $i >= 0; $i--) {
+            list($timestamp, $level, $message) = explode(':', $store[$i], 3);
+
+            if ($level === $record['level_name'] && $message === $expectedMessage && $timestamp > $timestampValidity) {
+                return true;
+            }
+
+            if ($timestamp < $yesterday) {
+                $this->gc = true;
+            }
+        }
+
+        return false;
+    }
+
+    private function collectLogs()
+    {
+        if (!file_exists($this->deduplicationStore)) {
+            return false;
+        }
+
+        $handle = fopen($this->deduplicationStore, 'rw+');
+        flock($handle, LOCK_EX);
+        $validLogs = array();
+
+        $timestampValidity = time() - $this->time;
+
+        while (!feof($handle)) {
+            $log = fgets($handle);
+            if (substr($log, 0, 10) >= $timestampValidity) {
+                $validLogs[] = $log;
+            }
+        }
+
+        ftruncate($handle, 0);
+        rewind($handle);
+        foreach ($validLogs as $log) {
+            fwrite($handle, $log);
+        }
+
+        flock($handle, LOCK_UN);
+        fclose($handle);
+
+        $this->gc = false;
+    }
+
+    private function appendRecord(array $record)
+    {
+        file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND);
+    }
+}

+ 45 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php

@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\NormalizerFormatter;
+use Doctrine\CouchDB\CouchDBClient;
+
+/**
+ * CouchDB handler for Doctrine CouchDB ODM
+ *
+ * @author Markus Bachmann <markus.bachmann@bachi.biz>
+ */
+class DoctrineCouchDBHandler extends AbstractProcessingHandler
+{
+    private $client;
+
+    public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true)
+    {
+        $this->client = $client;
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record)
+    {
+        $this->client->postDocument($record['formatted']);
+    }
+
+    protected function getDefaultFormatter()
+    {
+        return new NormalizerFormatter;
+    }
+}

+ 108 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php

@@ -0,0 +1,108 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Aws\Sdk;
+use Aws\DynamoDb\DynamoDbClient;
+use Aws\DynamoDb\Marshaler;
+use Monolog\Formatter\ScalarFormatter;
+use Monolog\Logger;
+
+/**
+ * Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/)
+ *
+ * @link https://github.com/aws/aws-sdk-php/
+ * @author Andrew Lawson <adlawson@gmail.com>
+ */
+class DynamoDbHandler extends AbstractProcessingHandler
+{
+    const DATE_FORMAT = 'Y-m-d\TH:i:s.uO';
+
+    /**
+     * @var DynamoDbClient
+     */
+    protected $client;
+
+    /**
+     * @var string
+     */
+    protected $table;
+
+    /**
+     * @var int
+     */
+    protected $version;
+
+    /**
+     * @var Marshaler
+     */
+    protected $marshaler;
+
+    /**
+     * @param DynamoDbClient $client
+     * @param string         $table
+     * @param int            $level
+     * @param bool           $bubble
+     */
+    public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true)
+    {
+        if (defined('Aws\Sdk::VERSION') && version_compare(Sdk::VERSION, '3.0', '>=')) {
+            $this->version = 3;
+            $this->marshaler = new Marshaler;
+        } else {
+            $this->version = 2;
+        }
+
+        $this->client = $client;
+        $this->table = $table;
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $filtered = $this->filterEmptyFields($record['formatted']);
+        if ($this->version === 3) {
+            $formatted = $this->marshaler->marshalItem($filtered);
+        } else {
+            /** @phpstan-ignore-next-line */
+            $formatted = $this->client->formatAttributes($filtered);
+        }
+
+        $this->client->putItem(array(
+            'TableName' => $this->table,
+            'Item' => $formatted,
+        ));
+    }
+
+    /**
+     * @param  array $record
+     * @return array
+     */
+    protected function filterEmptyFields(array $record)
+    {
+        return array_filter($record, function ($value) {
+            return !empty($value) || false === $value || 0 === $value;
+        });
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new ScalarFormatter(self::DATE_FORMAT);
+    }
+}

+ 128 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php

@@ -0,0 +1,128 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\ElasticaFormatter;
+use Monolog\Logger;
+use Elastica\Client;
+use Elastica\Exception\ExceptionInterface;
+
+/**
+ * Elastic Search handler
+ *
+ * Usage example:
+ *
+ *    $client = new \Elastica\Client();
+ *    $options = array(
+ *        'index' => 'elastic_index_name',
+ *        'type' => 'elastic_doc_type',
+ *    );
+ *    $handler = new ElasticSearchHandler($client, $options);
+ *    $log = new Logger('application');
+ *    $log->pushHandler($handler);
+ *
+ * @author Jelle Vink <jelle.vink@gmail.com>
+ */
+class ElasticSearchHandler extends AbstractProcessingHandler
+{
+    /**
+     * @var Client
+     */
+    protected $client;
+
+    /**
+     * @var array Handler config options
+     */
+    protected $options = array();
+
+    /**
+     * @param Client $client  Elastica Client object
+     * @param array  $options Handler configuration
+     * @param int    $level   The minimum logging level at which this handler will be triggered
+     * @param bool   $bubble  Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+        $this->client = $client;
+        $this->options = array_merge(
+            array(
+                'index'          => 'monolog',      // Elastic index name
+                'type'           => 'record',       // Elastic document type
+                'ignore_error'   => false,          // Suppress Elastica exceptions
+            ),
+            $options
+        );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record)
+    {
+        $this->bulkSend(array($record['formatted']));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        if ($formatter instanceof ElasticaFormatter) {
+            return parent::setFormatter($formatter);
+        }
+        throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter');
+    }
+
+    /**
+     * Getter options
+     * @return array
+     */
+    public function getOptions()
+    {
+        return $this->options;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new ElasticaFormatter($this->options['index'], $this->options['type']);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        $documents = $this->getFormatter()->formatBatch($records);
+        $this->bulkSend($documents);
+    }
+
+    /**
+     * Use Elasticsearch bulk API to send list of documents
+     * @param  array             $documents
+     * @throws \RuntimeException
+     */
+    protected function bulkSend(array $documents)
+    {
+        try {
+            $this->client->addDocuments($documents);
+        } catch (ExceptionInterface $e) {
+            if (!$this->options['ignore_error']) {
+                throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e);
+            }
+        }
+    }
+}

+ 82 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php

@@ -0,0 +1,82 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Stores to PHP error_log() handler.
+ *
+ * @author Elan Ruusamäe <glen@delfi.ee>
+ */
+class ErrorLogHandler extends AbstractProcessingHandler
+{
+    const OPERATING_SYSTEM = 0;
+    const SAPI = 4;
+
+    protected $messageType;
+    protected $expandNewlines;
+
+    /**
+     * @param int  $messageType    Says where the error should go.
+     * @param int  $level          The minimum logging level at which this handler will be triggered
+     * @param bool $bubble         Whether the messages that are handled can bubble up the stack or not
+     * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries
+     */
+    public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false)
+    {
+        parent::__construct($level, $bubble);
+
+        if (false === in_array($messageType, self::getAvailableTypes())) {
+            $message = sprintf('The given message type "%s" is not supported', print_r($messageType, true));
+            throw new \InvalidArgumentException($message);
+        }
+
+        $this->messageType = $messageType;
+        $this->expandNewlines = $expandNewlines;
+    }
+
+    /**
+     * @return array With all available types
+     */
+    public static function getAvailableTypes()
+    {
+        return array(
+            self::OPERATING_SYSTEM,
+            self::SAPI,
+        );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter('[%datetime%] %channel%.%level_name%: %message% %context% %extra%');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        if ($this->expandNewlines) {
+            $lines = preg_split('{[\r\n]+}', (string) $record['formatted']);
+            foreach ($lines as $line) {
+                error_log($line, $this->messageType);
+            }
+        } else {
+            error_log((string) $record['formatted'], $this->messageType);
+        }
+    }
+}

+ 172 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php

@@ -0,0 +1,172 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Simple handler wrapper that filters records based on a list of levels
+ *
+ * It can be configured with an exact list of levels to allow, or a min/max level.
+ *
+ * @author Hennadiy Verkh
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class FilterHandler extends AbstractHandler
+{
+    /**
+     * Handler or factory callable($record, $this)
+     *
+     * @var callable|\Monolog\Handler\HandlerInterface
+     */
+    protected $handler;
+
+    /**
+     * Minimum level for logs that are passed to handler
+     *
+     * @var int[]
+     */
+    protected $acceptedLevels;
+
+    /**
+     * Whether the messages that are handled can bubble up the stack or not
+     *
+     * @var bool
+     */
+    protected $bubble;
+
+    /**
+     * @param callable|HandlerInterface $handler        Handler or factory callable($record|null, $filterHandler).
+     * @param int|array                 $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
+     * @param int                       $maxLevel       Maximum level to accept, only used if $minLevelOrList is not an array
+     * @param bool                      $bubble         Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true)
+    {
+        $this->handler  = $handler;
+        $this->bubble   = $bubble;
+        $this->setAcceptedLevels($minLevelOrList, $maxLevel);
+
+        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+        }
+    }
+
+    /**
+     * @return array
+     */
+    public function getAcceptedLevels()
+    {
+        return array_flip($this->acceptedLevels);
+    }
+
+    /**
+     * @param int|string|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided
+     * @param int|string       $maxLevel       Maximum level or level name to accept, only used if $minLevelOrList is not an array
+     */
+    public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY)
+    {
+        if (is_array($minLevelOrList)) {
+            $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList);
+        } else {
+            $minLevelOrList = Logger::toMonologLevel($minLevelOrList);
+            $maxLevel = Logger::toMonologLevel($maxLevel);
+            $acceptedLevels = array_values(array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) {
+                return $level >= $minLevelOrList && $level <= $maxLevel;
+            }));
+        }
+        $this->acceptedLevels = array_flip($acceptedLevels);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isHandling(array $record)
+    {
+        return isset($this->acceptedLevels[$record['level']]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        if (!$this->isHandling($record)) {
+            return false;
+        }
+
+        if ($this->processors) {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+        }
+
+        $this->getHandler($record)->handle($record);
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        $filtered = array();
+        foreach ($records as $record) {
+            if ($this->isHandling($record)) {
+                $filtered[] = $record;
+            }
+        }
+
+        if (count($filtered) > 0) {
+            $this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered);
+        }
+    }
+
+    /**
+     * Return the nested handler
+     *
+     * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+     *
+     * @return HandlerInterface
+     */
+    public function getHandler(array $record = null)
+    {
+        if (!$this->handler instanceof HandlerInterface) {
+            $this->handler = call_user_func($this->handler, $record, $this);
+            if (!$this->handler instanceof HandlerInterface) {
+                throw new \RuntimeException("The factory callable should return a HandlerInterface");
+            }
+        }
+
+        return $this->handler;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->getHandler()->setFormatter($formatter);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormatter()
+    {
+        return $this->getHandler()->getFormatter();
+    }
+}

+ 28 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php

@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+/**
+ * Interface for activation strategies for the FingersCrossedHandler.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface ActivationStrategyInterface
+{
+    /**
+     * Returns whether the given record activates the handler.
+     *
+     * @param  array   $record
+     * @return bool
+     */
+    public function isHandlerActivated(array $record);
+}

+ 59 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php

@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+use Monolog\Logger;
+
+/**
+ * Channel and Error level based monolog activation strategy. Allows to trigger activation
+ * based on level per channel. e.g. trigger activation on level 'ERROR' by default, except
+ * for records of the 'sql' channel; those should trigger activation on level 'WARN'.
+ *
+ * Example:
+ *
+ * <code>
+ *   $activationStrategy = new ChannelLevelActivationStrategy(
+ *       Logger::CRITICAL,
+ *       array(
+ *           'request' => Logger::ALERT,
+ *           'sensitive' => Logger::ERROR,
+ *       )
+ *   );
+ *   $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy);
+ * </code>
+ *
+ * @author Mike Meessen <netmikey@gmail.com>
+ */
+class ChannelLevelActivationStrategy implements ActivationStrategyInterface
+{
+    private $defaultActionLevel;
+    private $channelToActionLevel;
+
+    /**
+     * @param int   $defaultActionLevel   The default action level to be used if the record's category doesn't match any
+     * @param array $channelToActionLevel An array that maps channel names to action levels.
+     */
+    public function __construct($defaultActionLevel, $channelToActionLevel = array())
+    {
+        $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel);
+        $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel);
+    }
+
+    public function isHandlerActivated(array $record)
+    {
+        if (isset($this->channelToActionLevel[$record['channel']])) {
+            return $record['level'] >= $this->channelToActionLevel[$record['channel']];
+        }
+
+        return $record['level'] >= $this->defaultActionLevel;
+    }
+}

+ 34 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php

@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+use Monolog\Logger;
+
+/**
+ * Error level based activation strategy.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class ErrorLevelActivationStrategy implements ActivationStrategyInterface
+{
+    private $actionLevel;
+
+    public function __construct($actionLevel)
+    {
+        $this->actionLevel = Logger::toMonologLevel($actionLevel);
+    }
+
+    public function isHandlerActivated(array $record)
+    {
+        return $record['level'] >= $this->actionLevel;
+    }
+}

+ 207 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php

@@ -0,0 +1,207 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
+use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
+use Monolog\Logger;
+use Monolog\ResettableInterface;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Buffers all records until a certain level is reached
+ *
+ * The advantage of this approach is that you don't get any clutter in your log files.
+ * Only requests which actually trigger an error (or whatever your actionLevel is) will be
+ * in the logs, but they will contain all records, not only those above the level threshold.
+ *
+ * You can find the various activation strategies in the
+ * Monolog\Handler\FingersCrossed\ namespace.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class FingersCrossedHandler extends AbstractHandler
+{
+    protected $handler;
+    protected $activationStrategy;
+    protected $buffering = true;
+    protected $bufferSize;
+    protected $buffer = array();
+    protected $stopBuffering;
+    protected $passthruLevel;
+
+    /**
+     * @param callable|HandlerInterface       $handler            Handler or factory callable($record|null, $fingersCrossedHandler).
+     * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
+     * @param int                             $bufferSize         How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+     * @param bool                            $bubble             Whether the messages that are handled can bubble up the stack or not
+     * @param bool                            $stopBuffering      Whether the handler should stop buffering after being triggered (default true)
+     * @param int                             $passthruLevel      Minimum level to always flush to handler on close, even if strategy not triggered
+     */
+    public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null)
+    {
+        if (null === $activationStrategy) {
+            $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
+        }
+
+        // convert simple int activationStrategy to an object
+        if (!$activationStrategy instanceof ActivationStrategyInterface) {
+            $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
+        }
+
+        $this->handler = $handler;
+        $this->activationStrategy = $activationStrategy;
+        $this->bufferSize = $bufferSize;
+        $this->bubble = $bubble;
+        $this->stopBuffering = $stopBuffering;
+
+        if ($passthruLevel !== null) {
+            $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
+        }
+
+        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isHandling(array $record)
+    {
+        return true;
+    }
+
+    /**
+     * Manually activate this logger regardless of the activation strategy
+     */
+    public function activate()
+    {
+        if ($this->stopBuffering) {
+            $this->buffering = false;
+        }
+        $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
+        $this->buffer = array();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        if ($this->processors) {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+        }
+
+        if ($this->buffering) {
+            $this->buffer[] = $record;
+            if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
+                array_shift($this->buffer);
+            }
+            if ($this->activationStrategy->isHandlerActivated($record)) {
+                $this->activate();
+            }
+        } else {
+            $this->getHandler($record)->handle($record);
+        }
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        $this->flushBuffer();
+    }
+
+    public function reset()
+    {
+        $this->flushBuffer();
+
+        parent::reset();
+
+        if ($this->getHandler() instanceof ResettableInterface) {
+            $this->getHandler()->reset();
+        }
+    }
+
+    /**
+     * Clears the buffer without flushing any messages down to the wrapped handler.
+     *
+     * It also resets the handler to its initial buffering state.
+     */
+    public function clear()
+    {
+        $this->buffer = array();
+        $this->reset();
+    }
+
+    /**
+     * Resets the state of the handler. Stops forwarding records to the wrapped handler.
+     */
+    private function flushBuffer()
+    {
+        if (null !== $this->passthruLevel) {
+            $level = $this->passthruLevel;
+            $this->buffer = array_filter($this->buffer, function ($record) use ($level) {
+                return $record['level'] >= $level;
+            });
+            if (count($this->buffer) > 0) {
+                $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
+            }
+        }
+
+        $this->buffer = array();
+        $this->buffering = true;
+    }
+
+    /**
+     * Return the nested handler
+     *
+     * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+     *
+     * @return HandlerInterface
+     */
+    public function getHandler(array $record = null)
+    {
+        if (!$this->handler instanceof HandlerInterface) {
+            $this->handler = call_user_func($this->handler, $record, $this);
+            if (!$this->handler instanceof HandlerInterface) {
+                throw new \RuntimeException("The factory callable should return a HandlerInterface");
+            }
+        }
+
+        return $this->handler;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->getHandler()->setFormatter($formatter);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormatter()
+    {
+        return $this->getHandler()->getFormatter();
+    }
+}

+ 195 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php

@@ -0,0 +1,195 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\WildfireFormatter;
+
+/**
+ * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
+ *
+ * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
+ */
+class FirePHPHandler extends AbstractProcessingHandler
+{
+    /**
+     * WildFire JSON header message format
+     */
+    const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
+
+    /**
+     * FirePHP structure for parsing messages & their presentation
+     */
+    const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
+
+    /**
+     * Must reference a "known" plugin, otherwise headers won't display in FirePHP
+     */
+    const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3';
+
+    /**
+     * Header prefix for Wildfire to recognize & parse headers
+     */
+    const HEADER_PREFIX = 'X-Wf';
+
+    /**
+     * Whether or not Wildfire vendor-specific headers have been generated & sent yet
+     */
+    protected static $initialized = false;
+
+    /**
+     * Shared static message index between potentially multiple handlers
+     * @var int
+     */
+    protected static $messageIndex = 1;
+
+    protected static $sendHeaders = true;
+
+    /**
+     * Base header creation function used by init headers & record headers
+     *
+     * @param  array  $meta    Wildfire Plugin, Protocol & Structure Indexes
+     * @param  string $message Log message
+     * @return array  Complete header string ready for the client as key and message as value
+     */
+    protected function createHeader(array $meta, $message)
+    {
+        $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta));
+
+        return array($header => $message);
+    }
+
+    /**
+     * Creates message header from record
+     *
+     * @see createHeader()
+     * @param  array  $record
+     * @return array
+     */
+    protected function createRecordHeader(array $record)
+    {
+        // Wildfire is extensible to support multiple protocols & plugins in a single request,
+        // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
+        return $this->createHeader(
+            array(1, 1, 1, self::$messageIndex++),
+            $record['formatted']
+        );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new WildfireFormatter();
+    }
+
+    /**
+     * Wildfire initialization headers to enable message parsing
+     *
+     * @see createHeader()
+     * @see sendHeader()
+     * @return array
+     */
+    protected function getInitHeaders()
+    {
+        // Initial payload consists of required headers for Wildfire
+        return array_merge(
+            $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI),
+            $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI),
+            $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI)
+        );
+    }
+
+    /**
+     * Send header string to the client
+     *
+     * @param string $header
+     * @param string $content
+     */
+    protected function sendHeader($header, $content)
+    {
+        if (!headers_sent() && self::$sendHeaders) {
+            header(sprintf('%s: %s', $header, $content));
+        }
+    }
+
+    /**
+     * Creates & sends header for a record, ensuring init headers have been sent prior
+     *
+     * @see sendHeader()
+     * @see sendInitHeaders()
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        if (!self::$sendHeaders) {
+            return;
+        }
+
+        // WildFire-specific headers must be sent prior to any messages
+        if (!self::$initialized) {
+            self::$initialized = true;
+
+            self::$sendHeaders = $this->headersAccepted();
+            if (!self::$sendHeaders) {
+                return;
+            }
+
+            foreach ($this->getInitHeaders() as $header => $content) {
+                $this->sendHeader($header, $content);
+            }
+        }
+
+        $header = $this->createRecordHeader($record);
+        if (trim(current($header)) !== '') {
+            $this->sendHeader(key($header), current($header));
+        }
+    }
+
+    /**
+     * Verifies if the headers are accepted by the current user agent
+     *
+     * @return bool
+     */
+    protected function headersAccepted()
+    {
+        if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) {
+            return true;
+        }
+
+        return isset($_SERVER['HTTP_X_FIREPHP_VERSION']);
+    }
+
+    /**
+     * BC getter for the sendHeaders property that has been made static
+     */
+    public function __get($property)
+    {
+        if ('sendHeaders' !== $property) {
+            throw new \InvalidArgumentException('Undefined property '.$property);
+        }
+
+        return static::$sendHeaders;
+    }
+
+    /**
+     * BC setter for the sendHeaders property that has been made static
+     */
+    public function __set($property, $value)
+    {
+        if ('sendHeaders' !== $property) {
+            throw new \InvalidArgumentException('Undefined property '.$property);
+        }
+
+        static::$sendHeaders = $value;
+    }
+}

+ 126 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php

@@ -0,0 +1,126 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Sends logs to Fleep.io using Webhook integrations
+ *
+ * You'll need a Fleep.io account to use this handler.
+ *
+ * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation
+ * @author Ando Roots <ando@sqroot.eu>
+ */
+class FleepHookHandler extends SocketHandler
+{
+    const FLEEP_HOST = 'fleep.io';
+
+    const FLEEP_HOOK_URI = '/hook/';
+
+    /**
+     * @var string Webhook token (specifies the conversation where logs are sent)
+     */
+    protected $token;
+
+    /**
+     * Construct a new Fleep.io Handler.
+     *
+     * For instructions on how to create a new web hook in your conversations
+     * see https://fleep.io/integrations/webhooks/
+     *
+     * @param  string                    $token  Webhook token
+     * @param  bool|int                  $level  The minimum logging level at which this handler will be triggered
+     * @param  bool                      $bubble Whether the messages that are handled can bubble up the stack or not
+     * @throws MissingExtensionException
+     */
+    public function __construct($token, $level = Logger::DEBUG, $bubble = true)
+    {
+        if (!extension_loaded('openssl')) {
+            throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler');
+        }
+
+        $this->token = $token;
+
+        $connectionString = 'ssl://' . self::FLEEP_HOST . ':443';
+        parent::__construct($connectionString, $level, $bubble);
+    }
+
+    /**
+     * Returns the default formatter to use with this handler
+     *
+     * Overloaded to remove empty context and extra arrays from the end of the log message.
+     *
+     * @return LineFormatter
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter(null, null, true, true);
+    }
+
+    /**
+     * Handles a log record
+     *
+     * @param array $record
+     */
+    public function write(array $record)
+    {
+        parent::write($record);
+        $this->closeSocket();
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param  array  $record
+     * @return string
+     */
+    protected function generateDataStream($record)
+    {
+        $content = $this->buildContent($record);
+
+        return $this->buildHeader($content) . $content;
+    }
+
+    /**
+     * Builds the header of the API Call
+     *
+     * @param  string $content
+     * @return string
+     */
+    private function buildHeader($content)
+    {
+        $header = "POST " . self::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n";
+        $header .= "Host: " . self::FLEEP_HOST . "\r\n";
+        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+        $header .= "Content-Length: " . strlen($content) . "\r\n";
+        $header .= "\r\n";
+
+        return $header;
+    }
+
+    /**
+     * Builds the body of API call
+     *
+     * @param  array  $record
+     * @return string
+     */
+    private function buildContent($record)
+    {
+        $dataArray = array(
+            'message' => $record['formatted'],
+        );
+
+        return http_build_query($dataArray);
+    }
+}

+ 128 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php

@@ -0,0 +1,128 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Formatter\FlowdockFormatter;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Sends notifications through the Flowdock push API
+ *
+ * This must be configured with a FlowdockFormatter instance via setFormatter()
+ *
+ * Notes:
+ * API token - Flowdock API token
+ *
+ * @author Dominik Liebler <liebler.dominik@gmail.com>
+ * @see https://www.flowdock.com/api/push
+ */
+class FlowdockHandler extends SocketHandler
+{
+    /**
+     * @var string
+     */
+    protected $apiToken;
+
+    /**
+     * @param string   $apiToken
+     * @param bool|int $level    The minimum logging level at which this handler will be triggered
+     * @param bool     $bubble   Whether the messages that are handled can bubble up the stack or not
+     *
+     * @throws MissingExtensionException if OpenSSL is missing
+     */
+    public function __construct($apiToken, $level = Logger::DEBUG, $bubble = true)
+    {
+        if (!extension_loaded('openssl')) {
+            throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler');
+        }
+
+        parent::__construct('ssl://api.flowdock.com:443', $level, $bubble);
+        $this->apiToken = $apiToken;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        if (!$formatter instanceof FlowdockFormatter) {
+            throw new \InvalidArgumentException('The FlowdockHandler requires an instance of Monolog\Formatter\FlowdockFormatter to function correctly');
+        }
+
+        return parent::setFormatter($formatter);
+    }
+
+    /**
+     * Gets the default formatter.
+     *
+     * @return FormatterInterface
+     */
+    protected function getDefaultFormatter()
+    {
+        throw new \InvalidArgumentException('The FlowdockHandler must be configured (via setFormatter) with an instance of Monolog\Formatter\FlowdockFormatter to function correctly');
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        parent::write($record);
+
+        $this->closeSocket();
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param  array  $record
+     * @return string
+     */
+    protected function generateDataStream($record)
+    {
+        $content = $this->buildContent($record);
+
+        return $this->buildHeader($content) . $content;
+    }
+
+    /**
+     * Builds the body of API call
+     *
+     * @param  array  $record
+     * @return string
+     */
+    private function buildContent($record)
+    {
+        return Utils::jsonEncode($record['formatted']['flowdock']);
+    }
+
+    /**
+     * Builds the header of the API Call
+     *
+     * @param  string $content
+     * @return string
+     */
+    private function buildHeader($content)
+    {
+        $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n";
+        $header .= "Host: api.flowdock.com\r\n";
+        $header .= "Content-Type: application/json\r\n";
+        $header .= "Content-Length: " . strlen($content) . "\r\n";
+        $header .= "\r\n";
+
+        return $header;
+    }
+}

+ 39 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php

@@ -0,0 +1,39 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Interface to describe loggers that have a formatter
+ *
+ * This interface is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface FormattableHandlerInterface
+{
+    /**
+     * Sets the formatter.
+     *
+     * @param  FormatterInterface $formatter
+     * @return HandlerInterface   self
+     */
+    public function setFormatter(FormatterInterface $formatter): HandlerInterface;
+
+    /**
+     * Gets the formatter.
+     *
+     * @return FormatterInterface
+     */
+    public function getFormatter(): FormatterInterface;
+}

+ 63 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php

@@ -0,0 +1,63 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Helper trait for implementing FormattableInterface
+ *
+ * This trait is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+trait FormattableHandlerTrait
+{
+    /**
+     * @var FormatterInterface
+     */
+    protected $formatter;
+
+    /**
+     * {@inheritdoc}
+     * @suppress PhanTypeMismatchReturn
+     */
+    public function setFormatter(FormatterInterface $formatter): HandlerInterface
+    {
+        $this->formatter = $formatter;
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormatter(): FormatterInterface
+    {
+        if (!$this->formatter) {
+            $this->formatter = $this->getDefaultFormatter();
+        }
+
+        return $this->formatter;
+    }
+
+    /**
+     * Gets the default formatter.
+     *
+     * Overwrite this if the LineFormatter is not a good default for your handler.
+     */
+    protected function getDefaultFormatter(): FormatterInterface
+    {
+        return new LineFormatter();
+    }
+}

+ 65 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php

@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Gelf\IMessagePublisher;
+use Gelf\PublisherInterface;
+use Gelf\Publisher;
+use InvalidArgumentException;
+use Monolog\Logger;
+use Monolog\Formatter\GelfMessageFormatter;
+
+/**
+ * Handler to send messages to a Graylog2 (http://www.graylog2.org) server
+ *
+ * @author Matt Lehner <mlehner@gmail.com>
+ * @author Benjamin Zikarsky <benjamin@zikarsky.de>
+ */
+class GelfHandler extends AbstractProcessingHandler
+{
+    /**
+     * @var Publisher|PublisherInterface|IMessagePublisher the publisher object that sends the message to the server
+     */
+    protected $publisher;
+
+    /**
+     * @param PublisherInterface|IMessagePublisher|Publisher $publisher a publisher object
+     * @param int                                            $level     The minimum logging level at which this handler will be triggered
+     * @param bool                                           $bubble    Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($publisher, $level = Logger::DEBUG, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+
+        if (!$publisher instanceof Publisher && !$publisher instanceof IMessagePublisher && !$publisher instanceof PublisherInterface) {
+            throw new InvalidArgumentException('Invalid publisher, expected a Gelf\Publisher, Gelf\IMessagePublisher or Gelf\PublisherInterface instance');
+        }
+
+        $this->publisher = $publisher;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $this->publisher->publish($record['formatted']);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new GelfMessageFormatter();
+    }
+}

+ 117 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php

@@ -0,0 +1,117 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\ResettableInterface;
+
+/**
+ * Forwards records to multiple handlers
+ *
+ * @author Lenar Lõhmus <lenar@city.ee>
+ */
+class GroupHandler extends AbstractHandler
+{
+    protected $handlers;
+
+    /**
+     * @param array $handlers Array of Handlers.
+     * @param bool  $bubble   Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct(array $handlers, $bubble = true)
+    {
+        foreach ($handlers as $handler) {
+            if (!$handler instanceof HandlerInterface) {
+                throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.');
+            }
+        }
+
+        $this->handlers = $handlers;
+        $this->bubble = $bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isHandling(array $record)
+    {
+        foreach ($this->handlers as $handler) {
+            if ($handler->isHandling($record)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        if ($this->processors) {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+        }
+
+        foreach ($this->handlers as $handler) {
+            $handler->handle($record);
+        }
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        if ($this->processors) {
+            $processed = array();
+            foreach ($records as $record) {
+                foreach ($this->processors as $processor) {
+                    $record = call_user_func($processor, $record);
+                }
+                $processed[] = $record;
+            }
+            $records = $processed;
+        }
+
+        foreach ($this->handlers as $handler) {
+            $handler->handleBatch($records);
+        }
+    }
+
+    public function reset()
+    {
+        parent::reset();
+
+        foreach ($this->handlers as $handler) {
+            if ($handler instanceof ResettableInterface) {
+                $handler->reset();
+            }
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        foreach ($this->handlers as $handler) {
+            $handler->setFormatter($formatter);
+        }
+
+        return $this;
+    }
+}

+ 90 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php

@@ -0,0 +1,90 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Interface that all Monolog Handlers must implement
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface HandlerInterface
+{
+    /**
+     * Checks whether the given record will be handled by this handler.
+     *
+     * This is mostly done for performance reasons, to avoid calling processors for nothing.
+     *
+     * Handlers should still check the record levels within handle(), returning false in isHandling()
+     * is no guarantee that handle() will not be called, and isHandling() might not be called
+     * for a given record.
+     *
+     * @param array $record Partial log record containing only a level key
+     *
+     * @return bool
+     */
+    public function isHandling(array $record);
+
+    /**
+     * Handles a record.
+     *
+     * All records may be passed to this method, and the handler should discard
+     * those that it does not want to handle.
+     *
+     * The return value of this function controls the bubbling process of the handler stack.
+     * Unless the bubbling is interrupted (by returning true), the Logger class will keep on
+     * calling further handlers in the stack with a given log record.
+     *
+     * @param  array   $record The record to handle
+     * @return bool true means that this handler handled the record, and that bubbling is not permitted.
+     *                        false means the record was either not processed or that this handler allows bubbling.
+     */
+    public function handle(array $record);
+
+    /**
+     * Handles a set of records at once.
+     *
+     * @param array $records The records to handle (an array of record arrays)
+     */
+    public function handleBatch(array $records);
+
+    /**
+     * Adds a processor in the stack.
+     *
+     * @param  callable $callback
+     * @return self
+     */
+    public function pushProcessor($callback);
+
+    /**
+     * Removes the processor on top of the stack and returns it.
+     *
+     * @return callable
+     */
+    public function popProcessor();
+
+    /**
+     * Sets the formatter.
+     *
+     * @param  FormatterInterface $formatter
+     * @return self
+     */
+    public function setFormatter(FormatterInterface $formatter);
+
+    /**
+     * Gets the formatter.
+     *
+     * @return FormatterInterface
+     */
+    public function getFormatter();
+}

+ 116 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php

@@ -0,0 +1,116 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\ResettableInterface;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * This simple wrapper class can be used to extend handlers functionality.
+ *
+ * Example: A custom filtering that can be applied to any handler.
+ *
+ * Inherit from this class and override handle() like this:
+ *
+ *   public function handle(array $record)
+ *   {
+ *        if ($record meets certain conditions) {
+ *            return false;
+ *        }
+ *        return $this->handler->handle($record);
+ *   }
+ *
+ * @author Alexey Karapetov <alexey@karapetov.com>
+ */
+class HandlerWrapper implements HandlerInterface, ResettableInterface
+{
+    /**
+     * @var HandlerInterface
+     */
+    protected $handler;
+
+    /**
+     * HandlerWrapper constructor.
+     * @param HandlerInterface $handler
+     */
+    public function __construct(HandlerInterface $handler)
+    {
+        $this->handler = $handler;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isHandling(array $record)
+    {
+        return $this->handler->isHandling($record);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        return $this->handler->handle($record);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        return $this->handler->handleBatch($records);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function pushProcessor($callback)
+    {
+        $this->handler->pushProcessor($callback);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function popProcessor()
+    {
+        return $this->handler->popProcessor();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->handler->setFormatter($formatter);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormatter()
+    {
+        return $this->handler->getFormatter();
+    }
+
+    public function reset()
+    {
+        if ($this->handler instanceof ResettableInterface) {
+            return $this->handler->reset();
+        }
+    }
+}

+ 367 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php

@@ -0,0 +1,367 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the hipchat api to a hipchat room
+ *
+ * Notes:
+ * API token - HipChat API token
+ * Room      - HipChat Room Id or name, where messages are sent
+ * Name      - Name used to send the message (from)
+ * notify    - Should the message trigger a notification in the clients
+ * version   - The API version to use (HipChatHandler::API_V1 | HipChatHandler::API_V2)
+ *
+ * @author Rafael Dohms <rafael@doh.ms>
+ * @see    https://www.hipchat.com/docs/api
+ */
+class HipChatHandler extends SocketHandler
+{
+    /**
+     * Use API version 1
+     */
+    const API_V1 = 'v1';
+
+    /**
+     * Use API version v2
+     */
+    const API_V2 = 'v2';
+
+    /**
+     * The maximum allowed length for the name used in the "from" field.
+     */
+    const MAXIMUM_NAME_LENGTH = 15;
+
+    /**
+     * The maximum allowed length for the message.
+     */
+    const MAXIMUM_MESSAGE_LENGTH = 9500;
+
+    /**
+     * @var string
+     */
+    private $token;
+
+    /**
+     * @var string
+     */
+    private $room;
+
+    /**
+     * @var string
+     */
+    private $name;
+
+    /**
+     * @var bool
+     */
+    private $notify;
+
+    /**
+     * @var string
+     */
+    private $format;
+
+    /**
+     * @var string
+     */
+    private $host;
+
+    /**
+     * @var string
+     */
+    private $version;
+
+    /**
+     * @param string $token   HipChat API Token
+     * @param string $room    The room that should be alerted of the message (Id or Name)
+     * @param string $name    Name used in the "from" field.
+     * @param bool   $notify  Trigger a notification in clients or not
+     * @param int    $level   The minimum logging level at which this handler will be triggered
+     * @param bool   $bubble  Whether the messages that are handled can bubble up the stack or not
+     * @param bool   $useSSL  Whether to connect via SSL.
+     * @param string $format  The format of the messages (default to text, can be set to html if you have html in the messages)
+     * @param string $host    The HipChat server hostname.
+     * @param string $version The HipChat API version (default HipChatHandler::API_V1)
+     */
+    public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1)
+    {
+        @trigger_error('The Monolog\Handler\HipChatHandler class is deprecated. You should migrate to Slack and the SlackWebhookHandler / SlackbotHandler, see https://www.atlassian.com/partnerships/slack', E_USER_DEPRECATED);
+
+        if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) {
+            throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.');
+        }
+
+        $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80';
+        parent::__construct($connectionString, $level, $bubble);
+
+        $this->token = $token;
+        $this->name = $name;
+        $this->notify = $notify;
+        $this->room = $room;
+        $this->format = $format;
+        $this->host = $host;
+        $this->version = $version;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param  array  $record
+     * @return string
+     */
+    protected function generateDataStream($record)
+    {
+        $content = $this->buildContent($record);
+
+        return $this->buildHeader($content) . $content;
+    }
+
+    /**
+     * Builds the body of API call
+     *
+     * @param  array  $record
+     * @return string
+     */
+    private function buildContent($record)
+    {
+        $dataArray = array(
+            'notify' => $this->version == self::API_V1 ?
+                ($this->notify ? 1 : 0) :
+                ($this->notify ? 'true' : 'false'),
+            'message' => $record['formatted'],
+            'message_format' => $this->format,
+            'color' => $this->getAlertColor($record['level']),
+        );
+
+        if (!$this->validateStringLength($dataArray['message'], static::MAXIMUM_MESSAGE_LENGTH)) {
+            if (function_exists('mb_substr')) {
+                $dataArray['message'] = mb_substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]';
+            } else {
+                $dataArray['message'] = substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]';
+            }
+        }
+
+        // if we are using the legacy API then we need to send some additional information
+        if ($this->version == self::API_V1) {
+            $dataArray['room_id'] = $this->room;
+        }
+
+        // append the sender name if it is set
+        // always append it if we use the v1 api (it is required in v1)
+        if ($this->version == self::API_V1 || $this->name !== null) {
+            $dataArray['from'] = (string) $this->name;
+        }
+
+        return http_build_query($dataArray);
+    }
+
+    /**
+     * Builds the header of the API Call
+     *
+     * @param  string $content
+     * @return string
+     */
+    private function buildHeader($content)
+    {
+        if ($this->version == self::API_V1) {
+            $header = "POST /v1/rooms/message?format=json&auth_token={$this->token} HTTP/1.1\r\n";
+        } else {
+            // needed for rooms with special (spaces, etc) characters in the name
+            $room = rawurlencode($this->room);
+            $header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n";
+        }
+
+        $header .= "Host: {$this->host}\r\n";
+        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+        $header .= "Content-Length: " . strlen($content) . "\r\n";
+        $header .= "\r\n";
+
+        return $header;
+    }
+
+    /**
+     * Assigns a color to each level of log records.
+     *
+     * @param  int    $level
+     * @return string
+     */
+    protected function getAlertColor($level)
+    {
+        switch (true) {
+            case $level >= Logger::ERROR:
+                return 'red';
+            case $level >= Logger::WARNING:
+                return 'yellow';
+            case $level >= Logger::INFO:
+                return 'green';
+            case $level == Logger::DEBUG:
+                return 'gray';
+            default:
+                return 'yellow';
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        parent::write($record);
+        $this->finalizeWrite();
+    }
+
+    /**
+     * Finalizes the request by reading some bytes and then closing the socket
+     *
+     * If we do not read some but close the socket too early, hipchat sometimes
+     * drops the request entirely.
+     */
+    protected function finalizeWrite()
+    {
+        $res = $this->getResource();
+        if (is_resource($res)) {
+            @fread($res, 2048);
+        }
+        $this->closeSocket();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        if (count($records) == 0) {
+            return true;
+        }
+
+        $batchRecords = $this->combineRecords($records);
+
+        $handled = false;
+        foreach ($batchRecords as $batchRecord) {
+            if ($this->isHandling($batchRecord)) {
+                $this->write($batchRecord);
+                $handled = true;
+            }
+        }
+
+        if (!$handled) {
+            return false;
+        }
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * Combines multiple records into one. Error level of the combined record
+     * will be the highest level from the given records. Datetime will be taken
+     * from the first record.
+     *
+     * @param array $records
+     * @return array
+     */
+    private function combineRecords(array $records)
+    {
+        $batchRecord = null;
+        $batchRecords = array();
+        $messages = array();
+        $formattedMessages = array();
+        $level = 0;
+        $levelName = null;
+        $datetime = null;
+
+        foreach ($records as $record) {
+            $record = $this->processRecord($record);
+
+            if ($record['level'] > $level) {
+                $level = $record['level'];
+                $levelName = $record['level_name'];
+            }
+
+            if (null === $datetime) {
+                $datetime = $record['datetime'];
+            }
+
+            $messages[] = $record['message'];
+            $messageStr = implode(PHP_EOL, $messages);
+            $formattedMessages[] = $this->getFormatter()->format($record);
+            $formattedMessageStr = implode('', $formattedMessages);
+
+            $batchRecord = array(
+                'message'   => $messageStr,
+                'formatted' => $formattedMessageStr,
+                'context'   => array(),
+                'extra'     => array(),
+            );
+
+            if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) {
+                // Pop the last message and implode the remaining messages
+                $lastMessage = array_pop($messages);
+                $lastFormattedMessage = array_pop($formattedMessages);
+                $batchRecord['message'] = implode(PHP_EOL, $messages);
+                $batchRecord['formatted'] = implode('', $formattedMessages);
+
+                $batchRecords[] = $batchRecord;
+                $messages = array($lastMessage);
+                $formattedMessages = array($lastFormattedMessage);
+
+                $batchRecord = null;
+            }
+        }
+
+        if (null !== $batchRecord) {
+            $batchRecords[] = $batchRecord;
+        }
+
+        // Set the max level and datetime for all records
+        foreach ($batchRecords as &$batchRecord) {
+            $batchRecord = array_merge(
+                $batchRecord,
+                array(
+                    'level'      => $level,
+                    'level_name' => $levelName,
+                    'datetime'   => $datetime,
+                )
+            );
+        }
+
+        return $batchRecords;
+    }
+
+    /**
+     * Validates the length of a string.
+     *
+     * If the `mb_strlen()` function is available, it will use that, as HipChat
+     * allows UTF-8 characters. Otherwise, it will fall back to `strlen()`.
+     *
+     * Note that this might cause false failures in the specific case of using
+     * a valid name with less than 16 characters, but 16 or more bytes, on a
+     * system where `mb_strlen()` is unavailable.
+     *
+     * @param string $str
+     * @param int    $length
+     *
+     * @return bool
+     */
+    private function validateStringLength($str, $length)
+    {
+        if (function_exists('mb_strlen')) {
+            return (mb_strlen($str) <= $length);
+        }
+
+        return (strlen($str) <= $length);
+    }
+}

+ 70 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php

@@ -0,0 +1,70 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * IFTTTHandler uses cURL to trigger IFTTT Maker actions
+ *
+ * Register a secret key and trigger/event name at https://ifttt.com/maker
+ *
+ * value1 will be the channel from monolog's Logger constructor,
+ * value2 will be the level name (ERROR, WARNING, ..)
+ * value3 will be the log record's message
+ *
+ * @author Nehal Patel <nehal@nehalpatel.me>
+ */
+class IFTTTHandler extends AbstractProcessingHandler
+{
+    private $eventName;
+    private $secretKey;
+
+    /**
+     * @param string $eventName The name of the IFTTT Maker event that should be triggered
+     * @param string $secretKey A valid IFTTT secret key
+     * @param int    $level     The minimum logging level at which this handler will be triggered
+     * @param bool   $bubble    Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bubble = true)
+    {
+        $this->eventName = $eventName;
+        $this->secretKey = $secretKey;
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function write(array $record)
+    {
+        $postData = array(
+            "value1" => $record["channel"],
+            "value2" => $record["level_name"],
+            "value3" => $record["message"],
+        );
+        $postString = Utils::jsonEncode($postData);
+
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey);
+        curl_setopt($ch, CURLOPT_POST, true);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
+            "Content-Type: application/json",
+        ));
+
+        Curl\Util::execute($ch);
+    }
+}

+ 62 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php

@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+ namespace Monolog\Handler;
+ 
+ use Monolog\Logger;
+
+/**
+ * Inspired on LogEntriesHandler.
+ *
+ * @author Robert Kaufmann III <rok3@rok3.me>
+ * @author Gabriel Machado <gabriel.ms1@hotmail.com>
+ */
+class InsightOpsHandler extends SocketHandler
+{
+    /**
+     * @var string
+     */
+    protected $logToken;
+
+    /**
+     * @param string $token  Log token supplied by InsightOps
+     * @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'.
+     * @param bool   $useSSL Whether or not SSL encryption should be used
+     * @param int    $level  The minimum logging level to trigger this handler
+     * @param bool   $bubble Whether or not messages that are handled should bubble up the stack.
+     *
+     * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
+     */
+    public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, $bubble = true)
+    {
+        if ($useSSL && !extension_loaded('openssl')) {
+            throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for InsightOpsHandler');
+        }
+
+        $endpoint = $useSSL
+            ? 'ssl://' . $region . '.data.logs.insight.rapid7.com:443'
+            : $region . '.data.logs.insight.rapid7.com:80';
+
+        parent::__construct($endpoint, $level, $bubble);
+        $this->logToken = $token;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param  array  $record
+     * @return string
+     */
+    protected function generateDataStream($record)
+    {
+        return $this->logToken . ' ' . $record['formatted'];
+    }
+}

+ 55 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php

@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * @author Robert Kaufmann III <rok3@rok3.me>
+ */
+class LogEntriesHandler extends SocketHandler
+{
+    /**
+     * @var string
+     */
+    protected $logToken;
+
+    /**
+     * @param string $token  Log token supplied by LogEntries
+     * @param bool   $useSSL Whether or not SSL encryption should be used.
+     * @param int    $level  The minimum logging level to trigger this handler
+     * @param bool   $bubble Whether or not messages that are handled should bubble up the stack.
+     *
+     * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
+     */
+    public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true, $host = 'data.logentries.com')
+    {
+        if ($useSSL && !extension_loaded('openssl')) {
+            throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler');
+        }
+
+        $endpoint = $useSSL ? 'ssl://' . $host . ':443' : $host . ':80';
+        parent::__construct($endpoint, $level, $bubble);
+        $this->logToken = $token;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param  array  $record
+     * @return string
+     */
+    protected function generateDataStream($record)
+    {
+        return $this->logToken . ' ' . $record['formatted'];
+    }
+}

+ 102 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php

@@ -0,0 +1,102 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LogglyFormatter;
+
+/**
+ * Sends errors to Loggly.
+ *
+ * @author Przemek Sobstel <przemek@sobstel.org>
+ * @author Adam Pancutt <adam@pancutt.com>
+ * @author Gregory Barchard <gregory@barchard.net>
+ */
+class LogglyHandler extends AbstractProcessingHandler
+{
+    const HOST = 'logs-01.loggly.com';
+    const ENDPOINT_SINGLE = 'inputs';
+    const ENDPOINT_BATCH = 'bulk';
+
+    protected $token;
+
+    protected $tag = array();
+
+    public function __construct($token, $level = Logger::DEBUG, $bubble = true)
+    {
+        if (!extension_loaded('curl')) {
+            throw new \LogicException('The curl extension is needed to use the LogglyHandler');
+        }
+
+        $this->token = $token;
+
+        parent::__construct($level, $bubble);
+    }
+
+    public function setTag($tag)
+    {
+        $tag = !empty($tag) ? $tag : array();
+        $this->tag = is_array($tag) ? $tag : array($tag);
+    }
+
+    public function addTag($tag)
+    {
+        if (!empty($tag)) {
+            $tag = is_array($tag) ? $tag : array($tag);
+            $this->tag = array_unique(array_merge($this->tag, $tag));
+        }
+    }
+
+    protected function write(array $record)
+    {
+        $this->send($record["formatted"], self::ENDPOINT_SINGLE);
+    }
+
+    public function handleBatch(array $records)
+    {
+        $level = $this->level;
+
+        $records = array_filter($records, function ($record) use ($level) {
+            return ($record['level'] >= $level);
+        });
+
+        if ($records) {
+            $this->send($this->getFormatter()->formatBatch($records), self::ENDPOINT_BATCH);
+        }
+    }
+
+    protected function send($data, $endpoint)
+    {
+        $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token);
+
+        $headers = array('Content-Type: application/json');
+
+        if (!empty($this->tag)) {
+            $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag);
+        }
+
+        $ch = curl_init();
+
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_POST, true);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+
+        Curl\Util::execute($ch);
+    }
+
+    protected function getDefaultFormatter()
+    {
+        return new LogglyFormatter();
+    }
+}

+ 67 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php

@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Base class for all mail handlers
+ *
+ * @author Gyula Sallai
+ */
+abstract class MailHandler extends AbstractProcessingHandler
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        $messages = array();
+
+        foreach ($records as $record) {
+            if ($record['level'] < $this->level) {
+                continue;
+            }
+            $messages[] = $this->processRecord($record);
+        }
+
+        if (!empty($messages)) {
+            $this->send((string) $this->getFormatter()->formatBatch($messages), $messages);
+        }
+    }
+
+    /**
+     * Send a mail with the given content
+     *
+     * @param string $content formatted email body to be sent
+     * @param array  $records the array of log records that formed this content
+     */
+    abstract protected function send($content, array $records);
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $this->send((string) $record['formatted'], array($record));
+    }
+
+    protected function getHighestRecord(array $records)
+    {
+        $highestRecord = null;
+        foreach ($records as $record) {
+            if ($highestRecord === null || $highestRecord['level'] < $record['level']) {
+                $highestRecord = $record;
+            }
+        }
+
+        return $highestRecord;
+    }
+}

+ 68 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php

@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * MandrillHandler uses cURL to send the emails to the Mandrill API
+ *
+ * @author Adam Nicholson <adamnicholson10@gmail.com>
+ */
+class MandrillHandler extends MailHandler
+{
+    protected $message;
+    protected $apiKey;
+
+    /**
+     * @param string                  $apiKey  A valid Mandrill API key
+     * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
+     * @param int                     $level   The minimum logging level at which this handler will be triggered
+     * @param bool                    $bubble  Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+
+        if (!$message instanceof \Swift_Message && is_callable($message)) {
+            $message = call_user_func($message);
+        }
+        if (!$message instanceof \Swift_Message) {
+            throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it');
+        }
+        $this->message = $message;
+        $this->apiKey = $apiKey;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function send($content, array $records)
+    {
+        $message = clone $this->message;
+        $message->setBody($content);
+        $message->setDate(time());
+
+        $ch = curl_init();
+
+        curl_setopt($ch, CURLOPT_URL, 'https://mandrillapp.com/api/1.0/messages/send-raw.json');
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
+            'key' => $this->apiKey,
+            'raw_message' => (string) $message,
+            'async' => false,
+        )));
+
+        Curl\Util::execute($ch);
+    }
+}

+ 21 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php

@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Exception can be thrown if an extension for an handler is missing
+ *
+ * @author  Christian Bergau <cbergau86@gmail.com>
+ */
+class MissingExtensionException extends \Exception
+{
+}

+ 59 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php

@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\NormalizerFormatter;
+
+/**
+ * Logs to a MongoDB database.
+ *
+ * usage example:
+ *
+ *   $log = new Logger('application');
+ *   $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod");
+ *   $log->pushHandler($mongodb);
+ *
+ * @author Thomas Tourlourat <thomas@tourlourat.com>
+ */
+class MongoDBHandler extends AbstractProcessingHandler
+{
+    protected $mongoCollection;
+
+    public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true)
+    {
+        if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo || $mongo instanceof \MongoDB\Client)) {
+            throw new \InvalidArgumentException('MongoClient, Mongo or MongoDB\Client instance required');
+        }
+
+        $this->mongoCollection = $mongo->selectCollection($database, $collection);
+
+        parent::__construct($level, $bubble);
+    }
+
+    protected function write(array $record)
+    {
+        if ($this->mongoCollection instanceof \MongoDB\Collection) {
+            $this->mongoCollection->insertOne($record["formatted"]);
+        } else {
+            $this->mongoCollection->save($record["formatted"]);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new NormalizerFormatter();
+    }
+}

+ 185 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php

@@ -0,0 +1,185 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * NativeMailerHandler uses the mail() function to send the emails
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Mark Garrett <mark@moderndeveloperllc.com>
+ */
+class NativeMailerHandler extends MailHandler
+{
+    /**
+     * The email addresses to which the message will be sent
+     * @var array
+     */
+    protected $to;
+
+    /**
+     * The subject of the email
+     * @var string
+     */
+    protected $subject;
+
+    /**
+     * Optional headers for the message
+     * @var array
+     */
+    protected $headers = array();
+
+    /**
+     * Optional parameters for the message
+     * @var array
+     */
+    protected $parameters = array();
+
+    /**
+     * The wordwrap length for the message
+     * @var int
+     */
+    protected $maxColumnWidth;
+
+    /**
+     * The Content-type for the message
+     * @var string
+     */
+    protected $contentType = 'text/plain';
+
+    /**
+     * The encoding for the message
+     * @var string
+     */
+    protected $encoding = 'utf-8';
+
+    /**
+     * @param string|array $to             The receiver of the mail
+     * @param string       $subject        The subject of the mail
+     * @param string       $from           The sender of the mail
+     * @param int          $level          The minimum logging level at which this handler will be triggered
+     * @param bool         $bubble         Whether the messages that are handled can bubble up the stack or not
+     * @param int          $maxColumnWidth The maximum column width that the message lines will have
+     */
+    public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70)
+    {
+        parent::__construct($level, $bubble);
+        $this->to = is_array($to) ? $to : array($to);
+        $this->subject = $subject;
+        $this->addHeader(sprintf('From: %s', $from));
+        $this->maxColumnWidth = $maxColumnWidth;
+    }
+
+    /**
+     * Add headers to the message
+     *
+     * @param  string|array $headers Custom added headers
+     * @return self
+     */
+    public function addHeader($headers)
+    {
+        foreach ((array) $headers as $header) {
+            if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) {
+                throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons');
+            }
+            $this->headers[] = $header;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Add parameters to the message
+     *
+     * @param  string|array $parameters Custom added parameters
+     * @return self
+     */
+    public function addParameter($parameters)
+    {
+        $this->parameters = array_merge($this->parameters, (array) $parameters);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function send($content, array $records)
+    {
+        $content = wordwrap($content, $this->maxColumnWidth);
+        $headers = ltrim(implode("\r\n", $this->headers) . "\r\n", "\r\n");
+        $headers .= 'Content-type: ' . $this->getContentType() . '; charset=' . $this->getEncoding() . "\r\n";
+        if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) {
+            $headers .= 'MIME-Version: 1.0' . "\r\n";
+        }
+
+        $subject = $this->subject;
+        if ($records) {
+            $subjectFormatter = new LineFormatter($this->subject);
+            $subject = $subjectFormatter->format($this->getHighestRecord($records));
+        }
+
+        $parameters = implode(' ', $this->parameters);
+        foreach ($this->to as $to) {
+            mail($to, $subject, $content, $headers, $parameters);
+        }
+    }
+
+    /**
+     * @return string $contentType
+     */
+    public function getContentType()
+    {
+        return $this->contentType;
+    }
+
+    /**
+     * @return string $encoding
+     */
+    public function getEncoding()
+    {
+        return $this->encoding;
+    }
+
+    /**
+     * @param  string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML
+     *                             messages.
+     * @return self
+     */
+    public function setContentType($contentType)
+    {
+        if (strpos($contentType, "\n") !== false || strpos($contentType, "\r") !== false) {
+            throw new \InvalidArgumentException('The content type can not contain newline characters to prevent email header injection');
+        }
+
+        $this->contentType = $contentType;
+
+        return $this;
+    }
+
+    /**
+     * @param  string $encoding
+     * @return self
+     */
+    public function setEncoding($encoding)
+    {
+        if (strpos($encoding, "\n") !== false || strpos($encoding, "\r") !== false) {
+            throw new \InvalidArgumentException('The encoding can not contain newline characters to prevent email header injection');
+        }
+
+        $this->encoding = $encoding;
+
+        return $this;
+    }
+}

+ 205 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php

@@ -0,0 +1,205 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Formatter\NormalizerFormatter;
+
+/**
+ * Class to record a log on a NewRelic application.
+ * Enabling New Relic High Security mode may prevent capture of useful information.
+ *
+ * This handler requires a NormalizerFormatter to function and expects an array in $record['formatted']
+ *
+ * @see https://docs.newrelic.com/docs/agents/php-agent
+ * @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security
+ */
+class NewRelicHandler extends AbstractProcessingHandler
+{
+    /**
+     * Name of the New Relic application that will receive logs from this handler.
+     *
+     * @var string
+     */
+    protected $appName;
+
+    /**
+     * Name of the current transaction
+     *
+     * @var string
+     */
+    protected $transactionName;
+
+    /**
+     * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
+     * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
+     *
+     * @var bool
+     */
+    protected $explodeArrays;
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $appName
+     * @param bool   $explodeArrays
+     * @param string $transactionName
+     */
+    public function __construct(
+        $level = Logger::ERROR,
+        $bubble = true,
+        $appName = null,
+        $explodeArrays = false,
+        $transactionName = null
+    ) {
+        parent::__construct($level, $bubble);
+
+        $this->appName       = $appName;
+        $this->explodeArrays = $explodeArrays;
+        $this->transactionName = $transactionName;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record)
+    {
+        if (!$this->isNewRelicEnabled()) {
+            throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
+        }
+
+        if ($appName = $this->getAppName($record['context'])) {
+            $this->setNewRelicAppName($appName);
+        }
+
+        if ($transactionName = $this->getTransactionName($record['context'])) {
+            $this->setNewRelicTransactionName($transactionName);
+            unset($record['formatted']['context']['transaction_name']);
+        }
+
+        if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) {
+            newrelic_notice_error($record['message'], $record['context']['exception']);
+            unset($record['formatted']['context']['exception']);
+        } else {
+            newrelic_notice_error($record['message']);
+        }
+
+        if (isset($record['formatted']['context']) && is_array($record['formatted']['context'])) {
+            foreach ($record['formatted']['context'] as $key => $parameter) {
+                if (is_array($parameter) && $this->explodeArrays) {
+                    foreach ($parameter as $paramKey => $paramValue) {
+                        $this->setNewRelicParameter('context_' . $key . '_' . $paramKey, $paramValue);
+                    }
+                } else {
+                    $this->setNewRelicParameter('context_' . $key, $parameter);
+                }
+            }
+        }
+
+        if (isset($record['formatted']['extra']) && is_array($record['formatted']['extra'])) {
+            foreach ($record['formatted']['extra'] as $key => $parameter) {
+                if (is_array($parameter) && $this->explodeArrays) {
+                    foreach ($parameter as $paramKey => $paramValue) {
+                        $this->setNewRelicParameter('extra_' . $key . '_' . $paramKey, $paramValue);
+                    }
+                } else {
+                    $this->setNewRelicParameter('extra_' . $key, $parameter);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks whether the NewRelic extension is enabled in the system.
+     *
+     * @return bool
+     */
+    protected function isNewRelicEnabled()
+    {
+        return extension_loaded('newrelic');
+    }
+
+    /**
+     * Returns the appname where this log should be sent. Each log can override the default appname, set in this
+     * handler's constructor, by providing the appname in it's context.
+     *
+     * @param  array       $context
+     * @return null|string
+     */
+    protected function getAppName(array $context)
+    {
+        if (isset($context['appname'])) {
+            return $context['appname'];
+        }
+
+        return $this->appName;
+    }
+
+    /**
+     * Returns the name of the current transaction. Each log can override the default transaction name, set in this
+     * handler's constructor, by providing the transaction_name in it's context
+     *
+     * @param array $context
+     *
+     * @return null|string
+     */
+    protected function getTransactionName(array $context)
+    {
+        if (isset($context['transaction_name'])) {
+            return $context['transaction_name'];
+        }
+
+        return $this->transactionName;
+    }
+
+    /**
+     * Sets the NewRelic application that should receive this log.
+     *
+     * @param string $appName
+     */
+    protected function setNewRelicAppName($appName)
+    {
+        newrelic_set_appname($appName);
+    }
+
+    /**
+     * Overwrites the name of the current transaction
+     *
+     * @param string $transactionName
+     */
+    protected function setNewRelicTransactionName($transactionName)
+    {
+        newrelic_name_transaction($transactionName);
+    }
+
+    /**
+     * @param string $key
+     * @param mixed  $value
+     */
+    protected function setNewRelicParameter($key, $value)
+    {
+        if (null === $value || is_scalar($value)) {
+            newrelic_add_custom_parameter($key, $value);
+        } else {
+            newrelic_add_custom_parameter($key, Utils::jsonEncode($value, null, true));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new NormalizerFormatter();
+    }
+}

+ 45 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php

@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Blackhole
+ *
+ * Any record it can handle will be thrown away. This can be used
+ * to put on top of an existing stack to override it temporarily.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class NullHandler extends AbstractHandler
+{
+    /**
+     * @param int $level The minimum logging level at which this handler will be triggered
+     */
+    public function __construct($level = Logger::DEBUG)
+    {
+        parent::__construct($level, false);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        if ($record['level'] < $this->level) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 243 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php

@@ -0,0 +1,243 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Exception;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+use Monolog\Utils;
+use PhpConsole\Connector;
+use PhpConsole\Handler;
+use PhpConsole\Helper;
+
+/**
+ * Monolog handler for Google Chrome extension "PHP Console"
+ *
+ * Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely
+ *
+ * Usage:
+ * 1. Install Google Chrome extension https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef
+ * 2. See overview https://github.com/barbushin/php-console#overview
+ * 3. Install PHP Console library https://github.com/barbushin/php-console#installation
+ * 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png)
+ *
+ *      $logger = new \Monolog\Logger('all', array(new \Monolog\Handler\PHPConsoleHandler()));
+ *      \Monolog\ErrorHandler::register($logger);
+ *      echo $undefinedVar;
+ *      $logger->addDebug('SELECT * FROM users', array('db', 'time' => 0.012));
+ *      PC::debug($_SERVER); // PHP Console debugger for any type of vars
+ *
+ * @author Sergey Barbushin https://www.linkedin.com/in/barbushin
+ */
+class PHPConsoleHandler extends AbstractProcessingHandler
+{
+    private $options = array(
+        'enabled' => true, // bool Is PHP Console server enabled
+        'classesPartialsTraceIgnore' => array('Monolog\\'), // array Hide calls of classes started with...
+        'debugTagsKeysInContext' => array(0, 'tag'), // bool Is PHP Console server enabled
+        'useOwnErrorsHandler' => false, // bool Enable errors handling
+        'useOwnExceptionsHandler' => false, // bool Enable exceptions handling
+        'sourcesBasePath' => null, // string Base path of all project sources to strip in errors source paths
+        'registerHelper' => true, // bool Register PhpConsole\Helper that allows short debug calls like PC::debug($var, 'ta.g.s')
+        'serverEncoding' => null, // string|null Server internal encoding
+        'headersLimit' => null, // int|null Set headers size limit for your web-server
+        'password' => null, // string|null Protect PHP Console connection by password
+        'enableSslOnlyMode' => false, // bool Force connection by SSL for clients with PHP Console installed
+        'ipMasks' => array(), // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1')
+        'enableEvalListener' => false, // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required)
+        'dumperDetectCallbacks' => false, // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings
+        'dumperLevelLimit' => 5, // int Maximum dumped vars array or object nested dump level
+        'dumperItemsCountLimit' => 100, // int Maximum dumped var same level array items or object properties number
+        'dumperItemSizeLimit' => 5000, // int Maximum length of any string or dumped array item
+        'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON
+        'detectDumpTraceAndSource' => false, // bool Autodetect and append trace data to debug
+        'dataStorage' => null, // PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ)
+    );
+
+    /** @var Connector */
+    private $connector;
+
+    /**
+     * @param  array          $options   See \Monolog\Handler\PHPConsoleHandler::$options for more details
+     * @param  Connector|null $connector Instance of \PhpConsole\Connector class (optional)
+     * @param  int            $level
+     * @param  bool           $bubble
+     * @throws Exception
+     */
+    public function __construct(array $options = array(), Connector $connector = null, $level = Logger::DEBUG, $bubble = true)
+    {
+        if (!class_exists('PhpConsole\Connector')) {
+            throw new Exception('PHP Console library not found. See https://github.com/barbushin/php-console#installation');
+        }
+        parent::__construct($level, $bubble);
+        $this->options = $this->initOptions($options);
+        $this->connector = $this->initConnector($connector);
+    }
+
+    private function initOptions(array $options)
+    {
+        $wrongOptions = array_diff(array_keys($options), array_keys($this->options));
+        if ($wrongOptions) {
+            throw new Exception('Unknown options: ' . implode(', ', $wrongOptions));
+        }
+
+        return array_replace($this->options, $options);
+    }
+
+    private function initConnector(Connector $connector = null)
+    {
+        if (!$connector) {
+            if ($this->options['dataStorage']) {
+                Connector::setPostponeStorage($this->options['dataStorage']);
+            }
+            $connector = Connector::getInstance();
+        }
+
+        if ($this->options['registerHelper'] && !Helper::isRegistered()) {
+            Helper::register();
+        }
+
+        if ($this->options['enabled'] && $connector->isActiveClient()) {
+            if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) {
+                $handler = Handler::getInstance();
+                $handler->setHandleErrors($this->options['useOwnErrorsHandler']);
+                $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']);
+                $handler->start();
+            }
+            if ($this->options['sourcesBasePath']) {
+                $connector->setSourcesBasePath($this->options['sourcesBasePath']);
+            }
+            if ($this->options['serverEncoding']) {
+                $connector->setServerEncoding($this->options['serverEncoding']);
+            }
+            if ($this->options['password']) {
+                $connector->setPassword($this->options['password']);
+            }
+            if ($this->options['enableSslOnlyMode']) {
+                $connector->enableSslOnlyMode();
+            }
+            if ($this->options['ipMasks']) {
+                $connector->setAllowedIpMasks($this->options['ipMasks']);
+            }
+            if ($this->options['headersLimit']) {
+                $connector->setHeadersLimit($this->options['headersLimit']);
+            }
+            if ($this->options['detectDumpTraceAndSource']) {
+                $connector->getDebugDispatcher()->detectTraceAndSource = true;
+            }
+            $dumper = $connector->getDumper();
+            $dumper->levelLimit = $this->options['dumperLevelLimit'];
+            $dumper->itemsCountLimit = $this->options['dumperItemsCountLimit'];
+            $dumper->itemSizeLimit = $this->options['dumperItemSizeLimit'];
+            $dumper->dumpSizeLimit = $this->options['dumperDumpSizeLimit'];
+            $dumper->detectCallbacks = $this->options['dumperDetectCallbacks'];
+            if ($this->options['enableEvalListener']) {
+                $connector->startEvalRequestsListener();
+            }
+        }
+
+        return $connector;
+    }
+
+    public function getConnector()
+    {
+        return $this->connector;
+    }
+
+    public function getOptions()
+    {
+        return $this->options;
+    }
+
+    public function handle(array $record)
+    {
+        if ($this->options['enabled'] && $this->connector->isActiveClient()) {
+            return parent::handle($record);
+        }
+
+        return !$this->bubble;
+    }
+
+    /**
+     * Writes the record down to the log of the implementing handler
+     *
+     * @param  array $record
+     * @return void
+     */
+    protected function write(array $record)
+    {
+        if ($record['level'] < Logger::NOTICE) {
+            $this->handleDebugRecord($record);
+        } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) {
+            $this->handleExceptionRecord($record);
+        } else {
+            $this->handleErrorRecord($record);
+        }
+    }
+
+    private function handleDebugRecord(array $record)
+    {
+        $tags = $this->getRecordTags($record);
+        $message = $record['message'];
+        if ($record['context']) {
+            $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true);
+        }
+        $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']);
+    }
+
+    private function handleExceptionRecord(array $record)
+    {
+        $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']);
+    }
+
+    private function handleErrorRecord(array $record)
+    {
+        $context = $record['context'];
+
+        $this->connector->getErrorsDispatcher()->dispatchError(
+            isset($context['code']) ? $context['code'] : null,
+            isset($context['message']) ? $context['message'] : $record['message'],
+            isset($context['file']) ? $context['file'] : null,
+            isset($context['line']) ? $context['line'] : null,
+            $this->options['classesPartialsTraceIgnore']
+        );
+    }
+
+    private function getRecordTags(array &$record)
+    {
+        $tags = null;
+        if (!empty($record['context'])) {
+            $context = & $record['context'];
+            foreach ($this->options['debugTagsKeysInContext'] as $key) {
+                if (!empty($context[$key])) {
+                    $tags = $context[$key];
+                    if ($key === 0) {
+                        array_shift($context);
+                    } else {
+                        unset($context[$key]);
+                    }
+                    break;
+                }
+            }
+        }
+
+        return $tags ?: strtolower($record['level_name']);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter('%message%');
+    }
+}

+ 40 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php

@@ -0,0 +1,40 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Processor\ProcessorInterface;
+
+/**
+ * Interface to describe loggers that have processors
+ *
+ * This interface is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface ProcessableHandlerInterface
+{
+    /**
+     * Adds a processor in the stack.
+     *
+     * @param  ProcessorInterface|callable $callback
+     * @return HandlerInterface            self
+     */
+    public function pushProcessor($callback): HandlerInterface;
+
+    /**
+     * Removes the processor on top of the stack and returns it.
+     *
+     * @throws \LogicException In case the processor stack is empty
+     * @return callable
+     */
+    public function popProcessor(): callable;
+}

+ 73 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php

@@ -0,0 +1,73 @@
+<?php declare(strict_types=1);
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\ResettableInterface;
+
+/**
+ * Helper trait for implementing ProcessableInterface
+ *
+ * This trait is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+trait ProcessableHandlerTrait
+{
+    /**
+     * @var callable[]
+     */
+    protected $processors = [];
+
+    /**
+     * {@inheritdoc}
+     * @suppress PhanTypeMismatchReturn
+     */
+    public function pushProcessor($callback): HandlerInterface
+    {
+        array_unshift($this->processors, $callback);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function popProcessor(): callable
+    {
+        if (!$this->processors) {
+            throw new \LogicException('You tried to pop from an empty processor stack.');
+        }
+
+        return array_shift($this->processors);
+    }
+
+    /**
+     * Processes a record.
+     */
+    protected function processRecord(array $record): array
+    {
+        foreach ($this->processors as $processor) {
+            $record = $processor($record);
+        }
+
+        return $record;
+    }
+
+    protected function resetProcessors(): void
+    {
+        foreach ($this->processors as $processor) {
+            if ($processor instanceof ResettableInterface) {
+                $processor->reset();
+            }
+        }
+    }
+}

+ 56 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php

@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Proxies log messages to an existing PSR-3 compliant logger.
+ *
+ * @author Michael Moussa <michael.moussa@gmail.com>
+ */
+class PsrHandler extends AbstractHandler
+{
+    /**
+     * PSR-3 compliant logger
+     *
+     * @var LoggerInterface
+     */
+    protected $logger;
+
+    /**
+     * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied
+     * @param int             $level  The minimum logging level at which this handler will be triggered
+     * @param bool            $bubble Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+
+        $this->logger = $logger;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function handle(array $record)
+    {
+        if (!$this->isHandling($record)) {
+            return false;
+        }
+
+        $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']);
+
+        return false === $this->bubble;
+    }
+}

+ 185 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php

@@ -0,0 +1,185 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the pushover api to mobile phones
+ *
+ * @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
+ * @see    https://www.pushover.net/api
+ */
+class PushoverHandler extends SocketHandler
+{
+    private $token;
+    private $users;
+    private $title;
+    private $user;
+    private $retry;
+    private $expire;
+
+    private $highPriorityLevel;
+    private $emergencyLevel;
+    private $useFormattedMessage = false;
+
+    /**
+     * All parameters that can be sent to Pushover
+     * @see https://pushover.net/api
+     * @var array
+     */
+    private $parameterNames = array(
+        'token' => true,
+        'user' => true,
+        'message' => true,
+        'device' => true,
+        'title' => true,
+        'url' => true,
+        'url_title' => true,
+        'priority' => true,
+        'timestamp' => true,
+        'sound' => true,
+        'retry' => true,
+        'expire' => true,
+        'callback' => true,
+    );
+
+    /**
+     * Sounds the api supports by default
+     * @see https://pushover.net/api#sounds
+     * @var array
+     */
+    private $sounds = array(
+        'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming',
+        'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb',
+        'persistent', 'echo', 'updown', 'none',
+    );
+
+    /**
+     * @param string       $token             Pushover api token
+     * @param string|array $users             Pushover user id or array of ids the message will be sent to
+     * @param string       $title             Title sent to the Pushover API
+     * @param int          $level             The minimum logging level at which this handler will be triggered
+     * @param bool         $bubble            Whether the messages that are handled can bubble up the stack or not
+     * @param bool         $useSSL            Whether to connect via SSL. Required when pushing messages to users that are not
+     *                                        the pushover.net app owner. OpenSSL is required for this option.
+     * @param int          $highPriorityLevel The minimum logging level at which this handler will start
+     *                                        sending "high priority" requests to the Pushover API
+     * @param int          $emergencyLevel    The minimum logging level at which this handler will start
+     *                                        sending "emergency" requests to the Pushover API
+     * @param int          $retry             The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
+     * @param int          $expire            The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
+     */
+    public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200)
+    {
+        $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80';
+        parent::__construct($connectionString, $level, $bubble);
+
+        $this->token = $token;
+        $this->users = (array) $users;
+        $this->title = $title ?: gethostname();
+        $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel);
+        $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel);
+        $this->retry = $retry;
+        $this->expire = $expire;
+    }
+
+    protected function generateDataStream($record)
+    {
+        $content = $this->buildContent($record);
+
+        return $this->buildHeader($content) . $content;
+    }
+
+    private function buildContent($record)
+    {
+        // Pushover has a limit of 512 characters on title and message combined.
+        $maxMessageLength = 512 - strlen($this->title);
+
+        $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message'];
+        $message = substr($message, 0, $maxMessageLength);
+
+        $timestamp = $record['datetime']->getTimestamp();
+
+        $dataArray = array(
+            'token' => $this->token,
+            'user' => $this->user,
+            'message' => $message,
+            'title' => $this->title,
+            'timestamp' => $timestamp,
+        );
+
+        if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) {
+            $dataArray['priority'] = 2;
+            $dataArray['retry'] = $this->retry;
+            $dataArray['expire'] = $this->expire;
+        } elseif (isset($record['level']) && $record['level'] >= $this->highPriorityLevel) {
+            $dataArray['priority'] = 1;
+        }
+
+        // First determine the available parameters
+        $context = array_intersect_key($record['context'], $this->parameterNames);
+        $extra = array_intersect_key($record['extra'], $this->parameterNames);
+
+        // Least important info should be merged with subsequent info
+        $dataArray = array_merge($extra, $context, $dataArray);
+
+        // Only pass sounds that are supported by the API
+        if (isset($dataArray['sound']) && !in_array($dataArray['sound'], $this->sounds)) {
+            unset($dataArray['sound']);
+        }
+
+        return http_build_query($dataArray);
+    }
+
+    private function buildHeader($content)
+    {
+        $header = "POST /1/messages.json HTTP/1.1\r\n";
+        $header .= "Host: api.pushover.net\r\n";
+        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+        $header .= "Content-Length: " . strlen($content) . "\r\n";
+        $header .= "\r\n";
+
+        return $header;
+    }
+
+    protected function write(array $record)
+    {
+        foreach ($this->users as $user) {
+            $this->user = $user;
+
+            parent::write($record);
+            $this->closeSocket();
+        }
+
+        $this->user = null;
+    }
+
+    public function setHighPriorityLevel($value)
+    {
+        $this->highPriorityLevel = $value;
+    }
+
+    public function setEmergencyLevel($value)
+    {
+        $this->emergencyLevel = $value;
+    }
+
+    /**
+     * Use the formatted message?
+     * @param bool $value
+     */
+    public function useFormattedMessage($value)
+    {
+        $this->useFormattedMessage = (bool) $value;
+    }
+}

+ 234 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php

@@ -0,0 +1,234 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+use Raven_Client;
+
+/**
+ * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server
+ * using sentry-php (https://github.com/getsentry/sentry-php)
+ *
+ * @author Marc Abramowitz <marc@marc-abramowitz.com>
+ */
+class RavenHandler extends AbstractProcessingHandler
+{
+    /**
+     * Translates Monolog log levels to Raven log levels.
+     */
+    protected $logLevels = array(
+        Logger::DEBUG     => Raven_Client::DEBUG,
+        Logger::INFO      => Raven_Client::INFO,
+        Logger::NOTICE    => Raven_Client::INFO,
+        Logger::WARNING   => Raven_Client::WARNING,
+        Logger::ERROR     => Raven_Client::ERROR,
+        Logger::CRITICAL  => Raven_Client::FATAL,
+        Logger::ALERT     => Raven_Client::FATAL,
+        Logger::EMERGENCY => Raven_Client::FATAL,
+    );
+
+    /**
+     * @var string should represent the current version of the calling
+     *             software. Can be any string (git commit, version number)
+     */
+    protected $release;
+
+    /**
+     * @var Raven_Client the client object that sends the message to the server
+     */
+    protected $ravenClient;
+
+    /**
+     * @var FormatterInterface The formatter to use for the logs generated via handleBatch()
+     */
+    protected $batchFormatter;
+
+    /**
+     * @param Raven_Client $ravenClient
+     * @param int          $level       The minimum logging level at which this handler will be triggered
+     * @param bool         $bubble      Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
+    {
+        @trigger_error('The Monolog\Handler\RavenHandler class is deprecated. You should rather upgrade to the sentry/sentry 2.x and use Sentry\Monolog\Handler, see https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php', E_USER_DEPRECATED);
+
+        parent::__construct($level, $bubble);
+
+        $this->ravenClient = $ravenClient;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        $level = $this->level;
+
+        // filter records based on their level
+        $records = array_filter($records, function ($record) use ($level) {
+            return $record['level'] >= $level;
+        });
+
+        if (!$records) {
+            return;
+        }
+
+        // the record with the highest severity is the "main" one
+        $record = array_reduce($records, function ($highest, $record) {
+            if (null === $highest || $record['level'] > $highest['level']) {
+                return $record;
+            }
+
+            return $highest;
+        });
+
+        // the other ones are added as a context item
+        $logs = array();
+        foreach ($records as $r) {
+            $logs[] = $this->processRecord($r);
+        }
+
+        if ($logs) {
+            $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs);
+        }
+
+        $this->handle($record);
+    }
+
+    /**
+     * Sets the formatter for the logs generated by handleBatch().
+     *
+     * @param FormatterInterface $formatter
+     */
+    public function setBatchFormatter(FormatterInterface $formatter)
+    {
+        $this->batchFormatter = $formatter;
+    }
+
+    /**
+     * Gets the formatter for the logs generated by handleBatch().
+     *
+     * @return FormatterInterface
+     */
+    public function getBatchFormatter()
+    {
+        if (!$this->batchFormatter) {
+            $this->batchFormatter = $this->getDefaultBatchFormatter();
+        }
+
+        return $this->batchFormatter;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $previousUserContext = false;
+        $options = array();
+        $options['level'] = $this->logLevels[$record['level']];
+        $options['tags'] = array();
+        if (!empty($record['extra']['tags'])) {
+            $options['tags'] = array_merge($options['tags'], $record['extra']['tags']);
+            unset($record['extra']['tags']);
+        }
+        if (!empty($record['context']['tags'])) {
+            $options['tags'] = array_merge($options['tags'], $record['context']['tags']);
+            unset($record['context']['tags']);
+        }
+        if (!empty($record['context']['fingerprint'])) {
+            $options['fingerprint'] = $record['context']['fingerprint'];
+            unset($record['context']['fingerprint']);
+        }
+        if (!empty($record['context']['logger'])) {
+            $options['logger'] = $record['context']['logger'];
+            unset($record['context']['logger']);
+        } else {
+            $options['logger'] = $record['channel'];
+        }
+        foreach ($this->getExtraParameters() as $key) {
+            foreach (array('extra', 'context') as $source) {
+                if (!empty($record[$source][$key])) {
+                    $options[$key] = $record[$source][$key];
+                    unset($record[$source][$key]);
+                }
+            }
+        }
+        if (!empty($record['context'])) {
+            $options['extra']['context'] = $record['context'];
+            if (!empty($record['context']['user'])) {
+                $previousUserContext = $this->ravenClient->context->user;
+                $this->ravenClient->user_context($record['context']['user']);
+                unset($options['extra']['context']['user']);
+            }
+        }
+        if (!empty($record['extra'])) {
+            $options['extra']['extra'] = $record['extra'];
+        }
+
+        if (!empty($this->release) && !isset($options['release'])) {
+            $options['release'] = $this->release;
+        }
+
+        if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) {
+            $options['message'] = $record['formatted'];
+            $this->ravenClient->captureException($record['context']['exception'], $options);
+        } else {
+            $this->ravenClient->captureMessage($record['formatted'], array(), $options);
+        }
+
+        if ($previousUserContext !== false) {
+            $this->ravenClient->user_context($previousUserContext);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter('[%channel%] %message%');
+    }
+
+    /**
+     * Gets the default formatter for the logs generated by handleBatch().
+     *
+     * @return FormatterInterface
+     */
+    protected function getDefaultBatchFormatter()
+    {
+        return new LineFormatter();
+    }
+
+    /**
+     * Gets extra parameters supported by Raven that can be found in "extra" and "context"
+     *
+     * @return array
+     */
+    protected function getExtraParameters()
+    {
+        return array('contexts', 'checksum', 'release', 'event_id');
+    }
+
+    /**
+     * @param string $value
+     * @return self
+     */
+    public function setRelease($value)
+    {
+        $this->release = $value;
+
+        return $this;
+    }
+}

+ 98 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php

@@ -0,0 +1,98 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Logs to a Redis key using rpush
+ *
+ * usage example:
+ *
+ *   $log = new Logger('application');
+ *   $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod");
+ *   $log->pushHandler($redis);
+ *
+ * @author Thomas Tourlourat <thomas@tourlourat.com>
+ */
+class RedisHandler extends AbstractProcessingHandler
+{
+    private $redisClient;
+    private $redisKey;
+    protected $capSize;
+
+    /**
+     * @param \Predis\Client|\Redis $redis   The redis instance
+     * @param string                $key     The key name to push records to
+     * @param int                   $level   The minimum logging level at which this handler will be triggered
+     * @param bool                  $bubble  Whether the messages that are handled can bubble up the stack or not
+     * @param int|false             $capSize Number of entries to limit list size to
+     */
+    public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false)
+    {
+        if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
+            throw new \InvalidArgumentException('Predis\Client or Redis instance required');
+        }
+
+        $this->redisClient = $redis;
+        $this->redisKey = $key;
+        $this->capSize = $capSize;
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record)
+    {
+        if ($this->capSize) {
+            $this->writeCapped($record);
+        } else {
+            $this->redisClient->rpush($this->redisKey, $record["formatted"]);
+        }
+    }
+
+    /**
+     * Write and cap the collection
+     * Writes the record to the redis list and caps its
+     *
+     * @param  array $record associative record array
+     * @return void
+     */
+    protected function writeCapped(array $record)
+    {
+        if ($this->redisClient instanceof \Redis) {
+            $mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1;
+            $this->redisClient->multi($mode)
+                ->rpush($this->redisKey, $record["formatted"])
+                ->ltrim($this->redisKey, -$this->capSize, -1)
+                ->exec();
+        } else {
+            $redisKey = $this->redisKey;
+            $capSize = $this->capSize;
+            $this->redisClient->transaction(function ($tx) use ($record, $redisKey, $capSize) {
+                $tx->rpush($redisKey, $record["formatted"]);
+                $tx->ltrim($redisKey, -$capSize, -1);
+            });
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter();
+    }
+}

+ 144 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php

@@ -0,0 +1,144 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use RollbarNotifier;
+use Exception;
+use Monolog\Logger;
+
+/**
+ * Sends errors to Rollbar
+ *
+ * If the context data contains a `payload` key, that is used as an array
+ * of payload options to RollbarNotifier's report_message/report_exception methods.
+ *
+ * Rollbar's context info will contain the context + extra keys from the log record
+ * merged, and then on top of that a few keys:
+ *
+ *  - level (rollbar level name)
+ *  - monolog_level (monolog level name, raw level, as rollbar only has 5 but monolog 8)
+ *  - channel
+ *  - datetime (unix timestamp)
+ *
+ * @author Paul Statezny <paulstatezny@gmail.com>
+ */
+class RollbarHandler extends AbstractProcessingHandler
+{
+    /**
+     * Rollbar notifier
+     *
+     * @var RollbarNotifier
+     */
+    protected $rollbarNotifier;
+
+    protected $levelMap = array(
+        Logger::DEBUG     => 'debug',
+        Logger::INFO      => 'info',
+        Logger::NOTICE    => 'info',
+        Logger::WARNING   => 'warning',
+        Logger::ERROR     => 'error',
+        Logger::CRITICAL  => 'critical',
+        Logger::ALERT     => 'critical',
+        Logger::EMERGENCY => 'critical',
+    );
+
+    /**
+     * Records whether any log records have been added since the last flush of the rollbar notifier
+     *
+     * @var bool
+     */
+    private $hasRecords = false;
+
+    protected $initialized = false;
+
+    /**
+     * @param RollbarNotifier $rollbarNotifier RollbarNotifier object constructed with valid token
+     * @param int             $level           The minimum logging level at which this handler will be triggered
+     * @param bool            $bubble          Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct(RollbarNotifier $rollbarNotifier, $level = Logger::ERROR, $bubble = true)
+    {
+        $this->rollbarNotifier = $rollbarNotifier;
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        if (!$this->initialized) {
+            // __destructor() doesn't get called on Fatal errors
+            register_shutdown_function(array($this, 'close'));
+            $this->initialized = true;
+        }
+
+        $context = $record['context'];
+        $payload = array();
+        if (isset($context['payload'])) {
+            $payload = $context['payload'];
+            unset($context['payload']);
+        }
+        $context = array_merge($context, $record['extra'], array(
+            'level' => $this->levelMap[$record['level']],
+            'monolog_level' => $record['level_name'],
+            'channel' => $record['channel'],
+            'datetime' => $record['datetime']->format('U'),
+        ));
+
+        if (isset($context['exception']) && $context['exception'] instanceof Exception) {
+            $payload['level'] = $context['level'];
+            $exception = $context['exception'];
+            unset($context['exception']);
+
+            $this->rollbarNotifier->report_exception($exception, $context, $payload);
+        } else {
+            $this->rollbarNotifier->report_message(
+                $record['message'],
+                $context['level'],
+                $context,
+                $payload
+            );
+        }
+
+        $this->hasRecords = true;
+    }
+
+    public function flush()
+    {
+        if ($this->hasRecords) {
+            $this->rollbarNotifier->flush();
+            $this->hasRecords = false;
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        $this->flush();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function reset()
+    {
+        $this->flush();
+
+        parent::reset();
+    }
+
+
+}

+ 191 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php

@@ -0,0 +1,191 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Stores logs to files that are rotated every day and a limited number of files are kept.
+ *
+ * This rotation is only intended to be used as a workaround. Using logrotate to
+ * handle the rotation is strongly encouraged when you can use it.
+ *
+ * @author Christophe Coevoet <stof@notk.org>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class RotatingFileHandler extends StreamHandler
+{
+    const FILE_PER_DAY = 'Y-m-d';
+    const FILE_PER_MONTH = 'Y-m';
+    const FILE_PER_YEAR = 'Y';
+
+    protected $filename;
+    protected $maxFiles;
+    protected $mustRotate;
+    protected $nextRotation;
+    protected $filenameFormat;
+    protected $dateFormat;
+
+    /**
+     * @param string   $filename
+     * @param int      $maxFiles       The maximal amount of files to keep (0 means unlimited)
+     * @param int      $level          The minimum logging level at which this handler will be triggered
+     * @param bool     $bubble         Whether the messages that are handled can bubble up the stack or not
+     * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
+     * @param bool     $useLocking     Try to lock log file before doing any writes
+     */
+    public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
+    {
+        $this->filename = Utils::canonicalizePath($filename);
+        $this->maxFiles = (int) $maxFiles;
+        $this->nextRotation = new \DateTime('tomorrow');
+        $this->filenameFormat = '{filename}-{date}';
+        $this->dateFormat = 'Y-m-d';
+
+        parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        parent::close();
+
+        if (true === $this->mustRotate) {
+            $this->rotate();
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function reset()
+    {
+        parent::reset();
+
+        if (true === $this->mustRotate) {
+            $this->rotate();
+        }
+    }
+
+    public function setFilenameFormat($filenameFormat, $dateFormat)
+    {
+        if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) {
+            trigger_error(
+                'Invalid date format - format must be one of '.
+                'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '.
+                'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '.
+                'date formats using slashes, underscores and/or dots instead of dashes.',
+                E_USER_DEPRECATED
+            );
+        }
+        if (substr_count($filenameFormat, '{date}') === 0) {
+            trigger_error(
+                'Invalid filename format - format should contain at least `{date}`, because otherwise rotating is impossible.',
+                E_USER_DEPRECATED
+            );
+        }
+        $this->filenameFormat = $filenameFormat;
+        $this->dateFormat = $dateFormat;
+        $this->url = $this->getTimedFilename();
+        $this->close();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        // on the first record written, if the log is new, we should rotate (once per day)
+        if (null === $this->mustRotate) {
+            $this->mustRotate = !file_exists($this->url);
+        }
+
+        if ($this->nextRotation < $record['datetime']) {
+            $this->mustRotate = true;
+            $this->close();
+        }
+
+        parent::write($record);
+    }
+
+    /**
+     * Rotates the files.
+     */
+    protected function rotate()
+    {
+        // update filename
+        $this->url = $this->getTimedFilename();
+        $this->nextRotation = new \DateTime('tomorrow');
+
+        // skip GC of old logs if files are unlimited
+        if (0 === $this->maxFiles) {
+            return;
+        }
+
+        $logFiles = glob($this->getGlobPattern());
+        if ($this->maxFiles >= count($logFiles)) {
+            // no files to remove
+            return;
+        }
+
+        // Sorting the files by name to remove the older ones
+        usort($logFiles, function ($a, $b) {
+            return strcmp($b, $a);
+        });
+
+        foreach (array_slice($logFiles, $this->maxFiles) as $file) {
+            if (is_writable($file)) {
+                // suppress errors here as unlink() might fail if two processes
+                // are cleaning up/rotating at the same time
+                set_error_handler(function ($errno, $errstr, $errfile, $errline) {});
+                unlink($file);
+                restore_error_handler();
+            }
+        }
+
+        $this->mustRotate = false;
+    }
+
+    protected function getTimedFilename()
+    {
+        $fileInfo = pathinfo($this->filename);
+        $timedFilename = str_replace(
+            array('{filename}', '{date}'),
+            array($fileInfo['filename'], date($this->dateFormat)),
+            $fileInfo['dirname'] . '/' . $this->filenameFormat
+        );
+
+        if (!empty($fileInfo['extension'])) {
+            $timedFilename .= '.'.$fileInfo['extension'];
+        }
+
+        return $timedFilename;
+    }
+
+    protected function getGlobPattern()
+    {
+        $fileInfo = pathinfo($this->filename);
+        $glob = str_replace(
+            array('{filename}', '{date}'),
+            array($fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'),
+            $fileInfo['dirname'] . '/' . $this->filenameFormat
+        );
+        if (!empty($fileInfo['extension'])) {
+            $glob .= '.'.$fileInfo['extension'];
+        }
+
+        return $glob;
+    }
+}

+ 113 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php

@@ -0,0 +1,113 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Sampling handler
+ *
+ * A sampled event stream can be useful for logging high frequency events in
+ * a production environment where you only need an idea of what is happening
+ * and are not concerned with capturing every occurrence. Since the decision to
+ * handle or not handle a particular event is determined randomly, the
+ * resulting sampled log is not guaranteed to contain 1/N of the events that
+ * occurred in the application, but based on the Law of large numbers, it will
+ * tend to be close to this ratio with a large number of attempts.
+ *
+ * @author Bryan Davis <bd808@wikimedia.org>
+ * @author Kunal Mehta <legoktm@gmail.com>
+ */
+class SamplingHandler extends AbstractHandler
+{
+    /**
+     * @var callable|HandlerInterface $handler
+     */
+    protected $handler;
+
+    /**
+     * @var int $factor
+     */
+    protected $factor;
+
+    /**
+     * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
+     * @param int                       $factor  Sample factor
+     */
+    public function __construct($handler, $factor)
+    {
+        parent::__construct();
+        $this->handler = $handler;
+        $this->factor = $factor;
+
+        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+        }
+    }
+
+    public function isHandling(array $record)
+    {
+        return $this->getHandler($record)->isHandling($record);
+    }
+
+    public function handle(array $record)
+    {
+        if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
+            if ($this->processors) {
+                foreach ($this->processors as $processor) {
+                    $record = call_user_func($processor, $record);
+                }
+            }
+
+            $this->getHandler($record)->handle($record);
+        }
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * Return the nested handler
+     *
+     * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+     *
+     * @return HandlerInterface
+     */
+    public function getHandler(array $record = null)
+    {
+        if (!$this->handler instanceof HandlerInterface) {
+            $this->handler = call_user_func($this->handler, $record, $this);
+            if (!$this->handler instanceof HandlerInterface) {
+                throw new \RuntimeException("The factory callable should return a HandlerInterface");
+            }
+        }
+
+        return $this->handler;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->getHandler()->setFormatter($formatter);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFormatter()
+    {
+        return $this->getHandler()->getFormatter();
+    }
+}

+ 299 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php

@@ -0,0 +1,299 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\Slack;
+
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Formatter\NormalizerFormatter;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Slack record utility helping to log to Slack webhooks or API.
+ *
+ * @author Greg Kedzierski <greg@gregkedzierski.com>
+ * @author Haralan Dobrev <hkdobrev@gmail.com>
+ * @see    https://api.slack.com/incoming-webhooks
+ * @see    https://api.slack.com/docs/message-attachments
+ */
+class SlackRecord
+{
+    const COLOR_DANGER = 'danger';
+
+    const COLOR_WARNING = 'warning';
+
+    const COLOR_GOOD = 'good';
+
+    const COLOR_DEFAULT = '#e3e4e6';
+
+    /**
+     * Slack channel (encoded ID or name)
+     * @var string|null
+     */
+    private $channel;
+
+    /**
+     * Name of a bot
+     * @var string|null
+     */
+    private $username;
+
+    /**
+     * User icon e.g. 'ghost', 'http://example.com/user.png'
+     * @var string
+     */
+    private $userIcon;
+
+    /**
+     * Whether the message should be added to Slack as attachment (plain text otherwise)
+     * @var bool
+     */
+    private $useAttachment;
+
+    /**
+     * Whether the the context/extra messages added to Slack as attachments are in a short style
+     * @var bool
+     */
+    private $useShortAttachment;
+
+    /**
+     * Whether the attachment should include context and extra data
+     * @var bool
+     */
+    private $includeContextAndExtra;
+
+    /**
+     * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2']
+     * @var array
+     */
+    private $excludeFields;
+
+    /**
+     * @var FormatterInterface
+     */
+    private $formatter;
+
+    /**
+     * @var NormalizerFormatter
+     */
+    private $normalizerFormatter;
+
+    public function __construct($channel = null, $username = null, $useAttachment = true, $userIcon = null, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null)
+    {
+        $this->channel = $channel;
+        $this->username = $username;
+        $this->userIcon = trim($userIcon, ':');
+        $this->useAttachment = $useAttachment;
+        $this->useShortAttachment = $useShortAttachment;
+        $this->includeContextAndExtra = $includeContextAndExtra;
+        $this->excludeFields = $excludeFields;
+        $this->formatter = $formatter;
+
+        if ($this->includeContextAndExtra) {
+            $this->normalizerFormatter = new NormalizerFormatter();
+        }
+    }
+
+    public function getSlackData(array $record)
+    {
+        $dataArray = array();
+        $record = $this->excludeFields($record);
+
+        if ($this->username) {
+            $dataArray['username'] = $this->username;
+        }
+
+        if ($this->channel) {
+            $dataArray['channel'] = $this->channel;
+        }
+
+        if ($this->formatter && !$this->useAttachment) {
+            $message = $this->formatter->format($record);
+        } else {
+            $message = $record['message'];
+        }
+
+        if ($this->useAttachment) {
+            $attachment = array(
+                'fallback'  => $message,
+                'text'      => $message,
+                'color'     => $this->getAttachmentColor($record['level']),
+                'fields'    => array(),
+                'mrkdwn_in' => array('fields'),
+                'ts'        => $record['datetime']->getTimestamp()
+            );
+
+            if ($this->useShortAttachment) {
+                $attachment['title'] = $record['level_name'];
+            } else {
+                $attachment['title'] = 'Message';
+                $attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name']);
+            }
+
+
+            if ($this->includeContextAndExtra) {
+                foreach (array('extra', 'context') as $key) {
+                    if (empty($record[$key])) {
+                        continue;
+                    }
+
+                    if ($this->useShortAttachment) {
+                        $attachment['fields'][] = $this->generateAttachmentField(
+                            $key,
+                            $record[$key]
+                        );
+                    } else {
+                        // Add all extra fields as individual fields in attachment
+                        $attachment['fields'] = array_merge(
+                            $attachment['fields'],
+                            $this->generateAttachmentFields($record[$key])
+                        );
+                    }
+                }
+            }
+
+            $dataArray['attachments'] = array($attachment);
+        } else {
+            $dataArray['text'] = $message;
+        }
+
+        if ($this->userIcon) {
+            if (filter_var($this->userIcon, FILTER_VALIDATE_URL)) {
+                $dataArray['icon_url'] = $this->userIcon;
+            } else {
+                $dataArray['icon_emoji'] = ":{$this->userIcon}:";
+            }
+        }
+
+        return $dataArray;
+    }
+
+    /**
+     * Returned a Slack message attachment color associated with
+     * provided level.
+     *
+     * @param  int    $level
+     * @return string
+     */
+    public function getAttachmentColor($level)
+    {
+        switch (true) {
+            case $level >= Logger::ERROR:
+                return self::COLOR_DANGER;
+            case $level >= Logger::WARNING:
+                return self::COLOR_WARNING;
+            case $level >= Logger::INFO:
+                return self::COLOR_GOOD;
+            default:
+                return self::COLOR_DEFAULT;
+        }
+    }
+
+    /**
+     * Stringifies an array of key/value pairs to be used in attachment fields
+     *
+     * @param array $fields
+     *
+     * @return string
+     */
+    public function stringify($fields)
+    {
+        $normalized = $this->normalizerFormatter->format($fields);
+        $prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128;
+        $flags = 0;
+        if (PHP_VERSION_ID >= 50400) {
+            $flags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
+        }
+
+        $hasSecondDimension = count(array_filter($normalized, 'is_array'));
+        $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric'));
+
+        return $hasSecondDimension || $hasNonNumericKeys
+            ? Utils::jsonEncode($normalized, $prettyPrintFlag | $flags)
+            : Utils::jsonEncode($normalized, $flags);
+    }
+
+    /**
+     * Sets the formatter
+     *
+     * @param FormatterInterface $formatter
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        $this->formatter = $formatter;
+    }
+
+    /**
+     * Generates attachment field
+     *
+     * @param string       $title
+     * @param string|array $value
+     *
+     * @return array
+     */
+    private function generateAttachmentField($title, $value)
+    {
+        $value = is_array($value)
+            ? sprintf('```%s```', $this->stringify($value))
+            : $value;
+
+        return array(
+            'title' => ucfirst($title),
+            'value' => $value,
+            'short' => false
+        );
+    }
+
+    /**
+     * Generates a collection of attachment fields from array
+     *
+     * @param array $data
+     *
+     * @return array
+     */
+    private function generateAttachmentFields(array $data)
+    {
+        $fields = array();
+        foreach ($this->normalizerFormatter->format($data) as $key => $value) {
+            $fields[] = $this->generateAttachmentField($key, $value);
+        }
+
+        return $fields;
+    }
+
+    /**
+     * Get a copy of record with fields excluded according to $this->excludeFields
+     *
+     * @param array $record
+     *
+     * @return array
+     */
+    private function excludeFields(array $record)
+    {
+        foreach ($this->excludeFields as $field) {
+            $keys = explode('.', $field);
+            $node = &$record;
+            $lastKey = end($keys);
+            foreach ($keys as $key) {
+                if (!isset($node[$key])) {
+                    break;
+                }
+                if ($lastKey === $key) {
+                    unset($node[$key]);
+                    break;
+                }
+                $node = &$node[$key];
+            }
+        }
+
+        return $record;
+    }
+}

+ 221 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php

@@ -0,0 +1,221 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Handler\Slack\SlackRecord;
+
+/**
+ * Sends notifications through Slack API
+ *
+ * @author Greg Kedzierski <greg@gregkedzierski.com>
+ * @see    https://api.slack.com/
+ */
+class SlackHandler extends SocketHandler
+{
+    /**
+     * Slack API token
+     * @var string
+     */
+    private $token;
+
+    /**
+     * Instance of the SlackRecord util class preparing data for Slack API.
+     * @var SlackRecord
+     */
+    private $slackRecord;
+
+    /**
+     * @param  string                    $token                  Slack API token
+     * @param  string                    $channel                Slack channel (encoded ID or name)
+     * @param  string|null               $username               Name of a bot
+     * @param  bool                      $useAttachment          Whether the message should be added to Slack as attachment (plain text otherwise)
+     * @param  string|null               $iconEmoji              The emoji name to use (or null)
+     * @param  int                       $level                  The minimum logging level at which this handler will be triggered
+     * @param  bool                      $bubble                 Whether the messages that are handled can bubble up the stack or not
+     * @param  bool                      $useShortAttachment     Whether the the context/extra messages added to Slack as attachments are in a short style
+     * @param  bool                      $includeContextAndExtra Whether the attachment should include context and extra data
+     * @param  array                     $excludeFields          Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2']
+     * @throws MissingExtensionException If no OpenSSL PHP extension configured
+     */
+    public function __construct($token, $channel, $username = null, $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array())
+    {
+        if (!extension_loaded('openssl')) {
+            throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler');
+        }
+
+        parent::__construct('ssl://slack.com:443', $level, $bubble);
+
+        $this->slackRecord = new SlackRecord(
+            $channel,
+            $username,
+            $useAttachment,
+            $iconEmoji,
+            $useShortAttachment,
+            $includeContextAndExtra,
+            $excludeFields,
+            $this->formatter
+        );
+
+        $this->token = $token;
+    }
+
+    public function getSlackRecord()
+    {
+        return $this->slackRecord;
+    }
+
+    public function getToken()
+    {
+        return $this->token;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param  array  $record
+     * @return string
+     */
+    protected function generateDataStream($record)
+    {
+        $content = $this->buildContent($record);
+
+        return $this->buildHeader($content) . $content;
+    }
+
+    /**
+     * Builds the body of API call
+     *
+     * @param  array  $record
+     * @return string
+     */
+    private function buildContent($record)
+    {
+        $dataArray = $this->prepareContentData($record);
+
+        return http_build_query($dataArray);
+    }
+
+    /**
+     * Prepares content data
+     *
+     * @param  array $record
+     * @return array
+     */
+    protected function prepareContentData($record)
+    {
+        $dataArray = $this->slackRecord->getSlackData($record);
+        $dataArray['token'] = $this->token;
+
+        if (!empty($dataArray['attachments'])) {
+            $dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']);
+        }
+
+        return $dataArray;
+    }
+
+    /**
+     * Builds the header of the API Call
+     *
+     * @param  string $content
+     * @return string
+     */
+    private function buildHeader($content)
+    {
+        $header = "POST /api/chat.postMessage HTTP/1.1\r\n";
+        $header .= "Host: slack.com\r\n";
+        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+        $header .= "Content-Length: " . strlen($content) . "\r\n";
+        $header .= "\r\n";
+
+        return $header;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        parent::write($record);
+        $this->finalizeWrite();
+    }
+
+    /**
+     * Finalizes the request by reading some bytes and then closing the socket
+     *
+     * If we do not read some but close the socket too early, slack sometimes
+     * drops the request entirely.
+     */
+    protected function finalizeWrite()
+    {
+        $res = $this->getResource();
+        if (is_resource($res)) {
+            @fread($res, 2048);
+        }
+        $this->closeSocket();
+    }
+
+    /**
+     * Returned a Slack message attachment color associated with
+     * provided level.
+     *
+     * @param  int    $level
+     * @return string
+     * @deprecated Use underlying SlackRecord instead
+     */
+    protected function getAttachmentColor($level)
+    {
+        trigger_error(
+            'SlackHandler::getAttachmentColor() is deprecated. Use underlying SlackRecord instead.',
+            E_USER_DEPRECATED
+        );
+
+        return $this->slackRecord->getAttachmentColor($level);
+    }
+
+    /**
+     * Stringifies an array of key/value pairs to be used in attachment fields
+     *
+     * @param  array  $fields
+     * @return string
+     * @deprecated Use underlying SlackRecord instead
+     */
+    protected function stringify($fields)
+    {
+        trigger_error(
+            'SlackHandler::stringify() is deprecated. Use underlying SlackRecord instead.',
+            E_USER_DEPRECATED
+        );
+
+        return $this->slackRecord->stringify($fields);
+    }
+
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        parent::setFormatter($formatter);
+        $this->slackRecord->setFormatter($formatter);
+
+        return $this;
+    }
+
+    public function getFormatter()
+    {
+        $formatter = parent::getFormatter();
+        $this->slackRecord->setFormatter($formatter);
+
+        return $formatter;
+    }
+}

+ 121 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php

@@ -0,0 +1,121 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Handler\Slack\SlackRecord;
+
+/**
+ * Sends notifications through Slack Webhooks
+ *
+ * @author Haralan Dobrev <hkdobrev@gmail.com>
+ * @see    https://api.slack.com/incoming-webhooks
+ */
+class SlackWebhookHandler extends AbstractProcessingHandler
+{
+    /**
+     * Slack Webhook token
+     * @var string
+     */
+    private $webhookUrl;
+
+    /**
+     * Instance of the SlackRecord util class preparing data for Slack API.
+     * @var SlackRecord
+     */
+    private $slackRecord;
+
+    /**
+     * @param  string      $webhookUrl             Slack Webhook URL
+     * @param  string|null $channel                Slack channel (encoded ID or name)
+     * @param  string|null $username               Name of a bot
+     * @param  bool        $useAttachment          Whether the message should be added to Slack as attachment (plain text otherwise)
+     * @param  string|null $iconEmoji              The emoji name to use (or null)
+     * @param  bool        $useShortAttachment     Whether the the context/extra messages added to Slack as attachments are in a short style
+     * @param  bool        $includeContextAndExtra Whether the attachment should include context and extra data
+     * @param  int         $level                  The minimum logging level at which this handler will be triggered
+     * @param  bool        $bubble                 Whether the messages that are handled can bubble up the stack or not
+     * @param  array       $excludeFields          Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2']
+     */
+    public function __construct($webhookUrl, $channel = null, $username = null, $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeContextAndExtra = false, $level = Logger::CRITICAL, $bubble = true, array $excludeFields = array())
+    {
+        parent::__construct($level, $bubble);
+
+        $this->webhookUrl = $webhookUrl;
+
+        $this->slackRecord = new SlackRecord(
+            $channel,
+            $username,
+            $useAttachment,
+            $iconEmoji,
+            $useShortAttachment,
+            $includeContextAndExtra,
+            $excludeFields,
+            $this->formatter
+        );
+    }
+
+    public function getSlackRecord()
+    {
+        return $this->slackRecord;
+    }
+
+    public function getWebhookUrl()
+    {
+        return $this->webhookUrl;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        $postData = $this->slackRecord->getSlackData($record);
+        $postString = Utils::jsonEncode($postData);
+
+        $ch = curl_init();
+        $options = array(
+            CURLOPT_URL => $this->webhookUrl,
+            CURLOPT_POST => true,
+            CURLOPT_RETURNTRANSFER => true,
+            CURLOPT_HTTPHEADER => array('Content-type: application/json'),
+            CURLOPT_POSTFIELDS => $postString
+        );
+        if (defined('CURLOPT_SAFE_UPLOAD')) {
+            $options[CURLOPT_SAFE_UPLOAD] = true;
+        }
+
+        curl_setopt_array($ch, $options);
+
+        Curl\Util::execute($ch);
+    }
+
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        parent::setFormatter($formatter);
+        $this->slackRecord->setFormatter($formatter);
+
+        return $this;
+    }
+
+    public function getFormatter()
+    {
+        $formatter = parent::getFormatter();
+        $this->slackRecord->setFormatter($formatter);
+
+        return $formatter;
+    }
+}

+ 84 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php

@@ -0,0 +1,84 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through Slack's Slackbot
+ *
+ * @author     Haralan Dobrev <hkdobrev@gmail.com>
+ * @see        https://slack.com/apps/A0F81R8ET-slackbot
+ * @deprecated According to Slack the API used on this handler it is deprecated.
+ *             Therefore this handler will be removed on 2.x
+ *             Slack suggests to use webhooks instead. Please contact slack for more information.
+ */
+class SlackbotHandler extends AbstractProcessingHandler
+{
+    /**
+     * The slug of the Slack team
+     * @var string
+     */
+    private $slackTeam;
+
+    /**
+     * Slackbot token
+     * @var string
+     */
+    private $token;
+
+    /**
+     * Slack channel name
+     * @var string
+     */
+    private $channel;
+
+    /**
+     * @param  string $slackTeam Slack team slug
+     * @param  string $token     Slackbot token
+     * @param  string $channel   Slack channel (encoded ID or name)
+     * @param  int    $level     The minimum logging level at which this handler will be triggered
+     * @param  bool   $bubble    Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true)
+    {
+        @trigger_error('SlackbotHandler is deprecated and will be removed on 2.x', E_USER_DEPRECATED);
+        parent::__construct($level, $bubble);
+
+        $this->slackTeam = $slackTeam;
+        $this->token = $token;
+        $this->channel = $channel;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        $slackbotUrl = sprintf(
+            'https://%s.slack.com/services/hooks/slackbot?token=%s&channel=%s',
+            $this->slackTeam,
+            $this->token,
+            $this->channel
+        );
+
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $slackbotUrl);
+        curl_setopt($ch, CURLOPT_POST, true);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $record['message']);
+
+        Curl\Util::execute($ch);
+    }
+}

+ 385 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php

@@ -0,0 +1,385 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Stores to any socket - uses fsockopen() or pfsockopen().
+ *
+ * @author Pablo de Leon Belloc <pablolb@gmail.com>
+ * @see    http://php.net/manual/en/function.fsockopen.php
+ */
+class SocketHandler extends AbstractProcessingHandler
+{
+    private $connectionString;
+    private $connectionTimeout;
+    private $resource;
+    private $timeout = 0;
+    private $writingTimeout = 10;
+    private $lastSentBytes = null;
+    private $chunkSize = null;
+    private $persistent = false;
+    private $errno;
+    private $errstr;
+    private $lastWritingAt;
+
+    /**
+     * @param string $connectionString Socket connection string
+     * @param int    $level            The minimum logging level at which this handler will be triggered
+     * @param bool   $bubble           Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+        $this->connectionString = $connectionString;
+        $this->connectionTimeout = (float) ini_get('default_socket_timeout');
+    }
+
+    /**
+     * Connect (if necessary) and write to the socket
+     *
+     * @param array $record
+     *
+     * @throws \UnexpectedValueException
+     * @throws \RuntimeException
+     */
+    protected function write(array $record)
+    {
+        $this->connectIfNotConnected();
+        $data = $this->generateDataStream($record);
+        $this->writeToSocket($data);
+    }
+
+    /**
+     * We will not close a PersistentSocket instance so it can be reused in other requests.
+     */
+    public function close()
+    {
+        if (!$this->isPersistent()) {
+            $this->closeSocket();
+        }
+    }
+
+    /**
+     * Close socket, if open
+     */
+    public function closeSocket()
+    {
+        if (is_resource($this->resource)) {
+            fclose($this->resource);
+            $this->resource = null;
+        }
+    }
+
+    /**
+     * Set socket connection to nbe persistent. It only has effect before the connection is initiated.
+     *
+     * @param bool $persistent
+     */
+    public function setPersistent($persistent)
+    {
+        $this->persistent = (bool) $persistent;
+    }
+
+    /**
+     * Set connection timeout.  Only has effect before we connect.
+     *
+     * @param float $seconds
+     *
+     * @see http://php.net/manual/en/function.fsockopen.php
+     */
+    public function setConnectionTimeout($seconds)
+    {
+        $this->validateTimeout($seconds);
+        $this->connectionTimeout = (float) $seconds;
+    }
+
+    /**
+     * Set write timeout. Only has effect before we connect.
+     *
+     * @param float $seconds
+     *
+     * @see http://php.net/manual/en/function.stream-set-timeout.php
+     */
+    public function setTimeout($seconds)
+    {
+        $this->validateTimeout($seconds);
+        $this->timeout = (float) $seconds;
+    }
+
+    /**
+     * Set writing timeout. Only has effect during connection in the writing cycle.
+     *
+     * @param float $seconds 0 for no timeout
+     */
+    public function setWritingTimeout($seconds)
+    {
+        $this->validateTimeout($seconds);
+        $this->writingTimeout = (float) $seconds;
+    }
+
+    /**
+     * Set chunk size. Only has effect during connection in the writing cycle.
+     *
+     * @param float $bytes
+     */
+    public function setChunkSize($bytes)
+    {
+        $this->chunkSize = $bytes;
+    }
+
+    /**
+     * Get current connection string
+     *
+     * @return string
+     */
+    public function getConnectionString()
+    {
+        return $this->connectionString;
+    }
+
+    /**
+     * Get persistent setting
+     *
+     * @return bool
+     */
+    public function isPersistent()
+    {
+        return $this->persistent;
+    }
+
+    /**
+     * Get current connection timeout setting
+     *
+     * @return float
+     */
+    public function getConnectionTimeout()
+    {
+        return $this->connectionTimeout;
+    }
+
+    /**
+     * Get current in-transfer timeout
+     *
+     * @return float
+     */
+    public function getTimeout()
+    {
+        return $this->timeout;
+    }
+
+    /**
+     * Get current local writing timeout
+     *
+     * @return float
+     */
+    public function getWritingTimeout()
+    {
+        return $this->writingTimeout;
+    }
+
+    /**
+     * Get current chunk size
+     *
+     * @return float
+     */
+    public function getChunkSize()
+    {
+        return $this->chunkSize;
+    }
+
+    /**
+     * Check to see if the socket is currently available.
+     *
+     * UDP might appear to be connected but might fail when writing.  See http://php.net/fsockopen for details.
+     *
+     * @return bool
+     */
+    public function isConnected()
+    {
+        return is_resource($this->resource)
+            && !feof($this->resource);  // on TCP - other party can close connection.
+    }
+
+    /**
+     * Wrapper to allow mocking
+     */
+    protected function pfsockopen()
+    {
+        return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
+    }
+
+    /**
+     * Wrapper to allow mocking
+     */
+    protected function fsockopen()
+    {
+        return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
+    }
+
+    /**
+     * Wrapper to allow mocking
+     *
+     * @see http://php.net/manual/en/function.stream-set-timeout.php
+     */
+    protected function streamSetTimeout()
+    {
+        $seconds = floor($this->timeout);
+        $microseconds = round(($this->timeout - $seconds) * 1e6);
+
+        return stream_set_timeout($this->resource, $seconds, $microseconds);
+    }
+
+    /**
+     * Wrapper to allow mocking
+     *
+     * @see http://php.net/manual/en/function.stream-set-chunk-size.php
+     */
+    protected function streamSetChunkSize()
+    {
+        return stream_set_chunk_size($this->resource, $this->chunkSize);
+    }
+
+    /**
+     * Wrapper to allow mocking
+     */
+    protected function fwrite($data)
+    {
+        return @fwrite($this->resource, $data);
+    }
+
+    /**
+     * Wrapper to allow mocking
+     */
+    protected function streamGetMetadata()
+    {
+        return stream_get_meta_data($this->resource);
+    }
+
+    private function validateTimeout($value)
+    {
+        $ok = filter_var($value, FILTER_VALIDATE_FLOAT);
+        if ($ok === false || $value < 0) {
+            throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)");
+        }
+    }
+
+    private function connectIfNotConnected()
+    {
+        if ($this->isConnected()) {
+            return;
+        }
+        $this->connect();
+    }
+
+    protected function generateDataStream($record)
+    {
+        return (string) $record['formatted'];
+    }
+
+    /**
+     * @return resource|null
+     */
+    protected function getResource()
+    {
+        return $this->resource;
+    }
+
+    private function connect()
+    {
+        $this->createSocketResource();
+        $this->setSocketTimeout();
+        $this->setStreamChunkSize();
+    }
+
+    private function createSocketResource()
+    {
+        if ($this->isPersistent()) {
+            $resource = $this->pfsockopen();
+        } else {
+            $resource = $this->fsockopen();
+        }
+        if (!$resource) {
+            throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
+        }
+        $this->resource = $resource;
+    }
+
+    private function setSocketTimeout()
+    {
+        if (!$this->streamSetTimeout()) {
+            throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()");
+        }
+    }
+
+    private function setStreamChunkSize()
+    {
+        if ($this->chunkSize && !$this->streamSetChunkSize()) {
+            throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()");
+        }
+    }
+
+    private function writeToSocket($data)
+    {
+        $length = strlen($data);
+        $sent = 0;
+        $this->lastSentBytes = $sent;
+        while ($this->isConnected() && $sent < $length) {
+            if (0 == $sent) {
+                $chunk = $this->fwrite($data);
+            } else {
+                $chunk = $this->fwrite(substr($data, $sent));
+            }
+            if ($chunk === false) {
+                throw new \RuntimeException("Could not write to socket");
+            }
+            $sent += $chunk;
+            $socketInfo = $this->streamGetMetadata();
+            if ($socketInfo['timed_out']) {
+                throw new \RuntimeException("Write timed-out");
+            }
+
+            if ($this->writingIsTimedOut($sent)) {
+                throw new \RuntimeException("Write timed-out, no data sent for `{$this->writingTimeout}` seconds, probably we got disconnected (sent $sent of $length)");
+            }
+        }
+        if (!$this->isConnected() && $sent < $length) {
+            throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
+        }
+    }
+
+    private function writingIsTimedOut($sent)
+    {
+        $writingTimeout = (int) floor($this->writingTimeout);
+        if (0 === $writingTimeout) {
+            return false;
+        }
+
+        if ($sent !== $this->lastSentBytes) {
+            $this->lastWritingAt = time();
+            $this->lastSentBytes = $sent;
+
+            return false;
+        } else {
+            usleep(100);
+        }
+
+        if ((time() - $this->lastWritingAt) >= $writingTimeout) {
+            $this->closeSocket();
+
+            return true;
+        }
+
+        return false;
+    }
+}

+ 179 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php

@@ -0,0 +1,179 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Stores to any stream resource
+ *
+ * Can be used to store into php://stderr, remote and local files, etc.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class StreamHandler extends AbstractProcessingHandler
+{
+    protected $stream;
+    protected $url;
+    private $errorMessage;
+    protected $filePermission;
+    protected $useLocking;
+    private $dirCreated;
+
+    /**
+     * @param resource|string $stream
+     * @param int             $level          The minimum logging level at which this handler will be triggered
+     * @param bool            $bubble         Whether the messages that are handled can bubble up the stack or not
+     * @param int|null        $filePermission Optional file permissions (default (0644) are only for owner read/write)
+     * @param bool            $useLocking     Try to lock log file before doing any writes
+     *
+     * @throws \Exception                If a missing directory is not buildable
+     * @throws \InvalidArgumentException If stream is not a resource or string
+     */
+    public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
+    {
+        parent::__construct($level, $bubble);
+        if (is_resource($stream)) {
+            $this->stream = $stream;
+        } elseif (is_string($stream)) {
+            $this->url = Utils::canonicalizePath($stream);
+        } else {
+            throw new \InvalidArgumentException('A stream must either be a resource or a string.');
+        }
+
+        $this->filePermission = $filePermission;
+        $this->useLocking = $useLocking;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        if ($this->url && is_resource($this->stream)) {
+            fclose($this->stream);
+        }
+        $this->stream = null;
+        $this->dirCreated = null;
+    }
+
+    /**
+     * Return the currently active stream if it is open
+     *
+     * @return resource|null
+     */
+    public function getStream()
+    {
+        return $this->stream;
+    }
+
+    /**
+     * Return the stream URL if it was configured with a URL and not an active resource
+     *
+     * @return string|null
+     */
+    public function getUrl()
+    {
+        return $this->url;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        if (!is_resource($this->stream)) {
+            if (null === $this->url || '' === $this->url) {
+                throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
+            }
+            $this->createDir();
+            $this->errorMessage = null;
+            set_error_handler(array($this, 'customErrorHandler'));
+            $this->stream = fopen($this->url, 'a');
+            if ($this->filePermission !== null) {
+                @chmod($this->url, $this->filePermission);
+            }
+            restore_error_handler();
+            if (!is_resource($this->stream)) {
+                $this->stream = null;
+
+                throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url));
+            }
+        }
+
+        if ($this->useLocking) {
+            // ignoring errors here, there's not much we can do about them
+            flock($this->stream, LOCK_EX);
+        }
+
+        $this->streamWrite($this->stream, $record);
+
+        if ($this->useLocking) {
+            flock($this->stream, LOCK_UN);
+        }
+    }
+
+    /**
+     * Write to stream
+     * @param resource $stream
+     * @param array $record
+     */
+    protected function streamWrite($stream, array $record)
+    {
+        fwrite($stream, (string) $record['formatted']);
+    }
+
+    private function customErrorHandler($code, $msg)
+    {
+        $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
+    }
+
+    /**
+     * @param string $stream
+     *
+     * @return null|string
+     */
+    private function getDirFromStream($stream)
+    {
+        $pos = strpos($stream, '://');
+        if ($pos === false) {
+            return dirname($stream);
+        }
+
+        if ('file://' === substr($stream, 0, 7)) {
+            return dirname(substr($stream, 7));
+        }
+
+        return null;
+    }
+
+    private function createDir()
+    {
+        // Do not try to create dir if it has already been tried.
+        if ($this->dirCreated) {
+            return;
+        }
+
+        $dir = $this->getDirFromStream($this->url);
+        if (null !== $dir && !is_dir($dir)) {
+            $this->errorMessage = null;
+            set_error_handler(array($this, 'customErrorHandler'));
+            $status = mkdir($dir, 0777, true);
+            restore_error_handler();
+            if (false === $status && !is_dir($dir)) {
+                throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir));
+            }
+        }
+        $this->dirCreated = true;
+    }
+}

+ 111 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php

@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\LineFormatter;
+use Swift;
+
+/**
+ * SwiftMailerHandler uses Swift_Mailer to send the emails
+ *
+ * @author Gyula Sallai
+ */
+class SwiftMailerHandler extends MailHandler
+{
+    protected $mailer;
+    private $messageTemplate;
+
+    /**
+     * @param \Swift_Mailer           $mailer  The mailer to use
+     * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
+     * @param int                     $level   The minimum logging level at which this handler will be triggered
+     * @param bool                    $bubble  Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true)
+    {
+        parent::__construct($level, $bubble);
+
+        $this->mailer = $mailer;
+        $this->messageTemplate = $message;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function send($content, array $records)
+    {
+        $this->mailer->send($this->buildMessage($content, $records));
+    }
+
+    /**
+     * Gets the formatter for the Swift_Message subject.
+     *
+     * @param  string             $format The format of the subject
+     * @return FormatterInterface
+     */
+    protected function getSubjectFormatter($format)
+    {
+        return new LineFormatter($format);
+    }
+
+    /**
+     * Creates instance of Swift_Message to be sent
+     *
+     * @param  string         $content formatted email body to be sent
+     * @param  array          $records Log records that formed the content
+     * @return \Swift_Message
+     */
+    protected function buildMessage($content, array $records)
+    {
+        $message = null;
+        if ($this->messageTemplate instanceof \Swift_Message) {
+            $message = clone $this->messageTemplate;
+            $message->generateId();
+        } elseif (is_callable($this->messageTemplate)) {
+            $message = call_user_func($this->messageTemplate, $content, $records);
+        }
+
+        if (!$message instanceof \Swift_Message) {
+            throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it');
+        }
+
+        if ($records) {
+            $subjectFormatter = $this->getSubjectFormatter($message->getSubject());
+            $message->setSubject($subjectFormatter->format($this->getHighestRecord($records)));
+        }
+
+        $message->setBody($content);
+        if (version_compare(Swift::VERSION, '6.0.0', '>=')) {
+            $message->setDate(new \DateTimeImmutable());
+        } else {
+            $message->setDate(time());
+        }
+
+        return $message;
+    }
+
+    /**
+     * BC getter, to be removed in 2.0
+     */
+    public function __get($name)
+    {
+        if ($name === 'message') {
+            trigger_error('SwiftMailerHandler->message is deprecated, use ->buildMessage() instead to retrieve the message', E_USER_DEPRECATED);
+
+            return $this->buildMessage(null, array());
+        }
+
+        throw new \InvalidArgumentException('Invalid property '.$name);
+    }
+}

+ 67 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php

@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Logs to syslog service.
+ *
+ * usage example:
+ *
+ *   $log = new Logger('application');
+ *   $syslog = new SyslogHandler('myfacility', 'local6');
+ *   $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
+ *   $syslog->setFormatter($formatter);
+ *   $log->pushHandler($syslog);
+ *
+ * @author Sven Paulus <sven@karlsruhe.org>
+ */
+class SyslogHandler extends AbstractSyslogHandler
+{
+    protected $ident;
+    protected $logopts;
+
+    /**
+     * @param string $ident
+     * @param mixed  $facility
+     * @param int    $level    The minimum logging level at which this handler will be triggered
+     * @param bool   $bubble   Whether the messages that are handled can bubble up the stack or not
+     * @param int    $logopts  Option flags for the openlog() call, defaults to LOG_PID
+     */
+    public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID)
+    {
+        parent::__construct($facility, $level, $bubble);
+
+        $this->ident = $ident;
+        $this->logopts = $logopts;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        closelog();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        if (!openlog($this->ident, $this->logopts, $this->facility)) {
+            throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"');
+        }
+        syslog($this->logLevels[$record['level']], (string) $record['formatted']);
+    }
+}

+ 56 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php

@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\SyslogUdp;
+
+class UdpSocket
+{
+    const DATAGRAM_MAX_LENGTH = 65023;
+
+    protected $ip;
+    protected $port;
+    protected $socket;
+
+    public function __construct($ip, $port = 514)
+    {
+        $this->ip = $ip;
+        $this->port = $port;
+        $this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+    }
+
+    public function write($line, $header = "")
+    {
+        $this->send($this->assembleMessage($line, $header));
+    }
+
+    public function close()
+    {
+        if (is_resource($this->socket)) {
+            socket_close($this->socket);
+            $this->socket = null;
+        }
+    }
+
+    protected function send($chunk)
+    {
+        if (!is_resource($this->socket)) {
+            throw new \LogicException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore');
+        }
+        socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port);
+    }
+
+    protected function assembleMessage($line, $header)
+    {
+        $chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header);
+
+        return $header . substr($line, 0, $chunkSize);
+    }
+}

+ 124 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php

@@ -0,0 +1,124 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Handler\SyslogUdp\UdpSocket;
+
+/**
+ * A Handler for logging to a remote syslogd server.
+ *
+ * @author Jesper Skovgaard Nielsen <nulpunkt@gmail.com>
+ * @author Dominik Kukacka <dominik.kukacka@gmail.com>
+ */
+class SyslogUdpHandler extends AbstractSyslogHandler
+{
+    const RFC3164 = 0;
+    const RFC5424 = 1;
+
+    private $dateFormats = array(
+        self::RFC3164 => 'M d H:i:s',
+        self::RFC5424 => \DateTime::RFC3339,
+    );
+
+    protected $socket;
+    protected $ident;
+    protected $rfc;
+
+    /**
+     * @param string $host
+     * @param int    $port
+     * @param mixed  $facility
+     * @param int    $level    The minimum logging level at which this handler will be triggered
+     * @param bool   $bubble   Whether the messages that are handled can bubble up the stack or not
+     * @param string $ident    Program name or tag for each log message.
+     * @param int    $rfc      RFC to format the message for.
+     */
+    public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php', $rfc = self::RFC5424)
+    {
+        parent::__construct($facility, $level, $bubble);
+
+        $this->ident = $ident;
+        $this->rfc = $rfc;
+
+        $this->socket = new UdpSocket($host, $port ?: 514);
+    }
+
+    protected function write(array $record)
+    {
+        $lines = $this->splitMessageIntoLines($record['formatted']);
+
+        $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']]);
+
+        foreach ($lines as $line) {
+            $this->socket->write($line, $header);
+        }
+    }
+
+    public function close()
+    {
+        $this->socket->close();
+    }
+
+    private function splitMessageIntoLines($message)
+    {
+        if (is_array($message)) {
+            $message = implode("\n", $message);
+        }
+
+        return preg_split('/$\R?^/m', $message, -1, PREG_SPLIT_NO_EMPTY);
+    }
+
+    /**
+     * Make common syslog header (see rfc5424 or rfc3164)
+     */
+    protected function makeCommonSyslogHeader($severity)
+    {
+        $priority = $severity + $this->facility;
+
+        if (!$pid = getmypid()) {
+            $pid = '-';
+        }
+
+        if (!$hostname = gethostname()) {
+            $hostname = '-';
+        }
+
+        $date = $this->getDateTime();
+
+        if ($this->rfc === self::RFC3164) {
+            return "<$priority>" .
+                $date . " " .
+                $hostname . " " .
+                $this->ident . "[" . $pid . "]: ";
+        } else {
+            return "<$priority>1 " .
+                $date . " " .
+                $hostname . " " .
+                $this->ident . " " .
+                $pid . " - - ";
+        }
+    }
+
+    protected function getDateTime()
+    {
+        return date($this->dateFormats[$this->rfc]);
+    }
+
+    /**
+     * Inject your own socket, mainly used for testing
+     */
+    public function setSocket($socket)
+    {
+        $this->socket = $socket;
+    }
+}

+ 72 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php

@@ -0,0 +1,72 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Forwards records to multiple handlers suppressing failures of each handler
+ * and continuing through to give every handler a chance to succeed.
+ *
+ * @author Craig D'Amelio <craig@damelio.ca>
+ */
+class WhatFailureGroupHandler extends GroupHandler
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function handle(array $record)
+    {
+        if ($this->processors) {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+        }
+
+        foreach ($this->handlers as $handler) {
+            try {
+                $handler->handle($record);
+            } catch (\Exception $e) {
+                // What failure?
+            } catch (\Throwable $e) {
+                // What failure?
+            }
+        }
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        if ($this->processors) {
+            $processed = array();
+            foreach ($records as $record) {
+                foreach ($this->processors as $processor) {
+                    $record = call_user_func($processor, $record);
+                }
+                $processed[] = $record;
+            }
+            $records = $processed;
+        }
+
+        foreach ($this->handlers as $handler) {
+            try {
+                $handler->handleBatch($records);
+            } catch (\Exception $e) {
+                // What failure?
+            } catch (\Throwable $e) {
+                // What failure?
+            }
+        }
+    }
+}

+ 101 - 0
api/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php

@@ -0,0 +1,101 @@
+<?php
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\NormalizerFormatter;
+use Monolog\Logger;
+
+/**
+ * Handler sending logs to Zend Monitor
+ *
+ * @author  Christian Bergau <cbergau86@gmail.com>
+ * @author  Jason Davis <happydude@jasondavis.net>
+ */
+class ZendMonitorHandler extends AbstractProcessingHandler
+{
+    /**
+     * Monolog level / ZendMonitor Custom Event priority map
+     *
+     * @var array
+     */
+    protected $levelMap = array();
+
+    /**
+     * Construct
+     *
+     * @param  int                       $level
+     * @param  bool                      $bubble
+     * @throws MissingExtensionException
+     */
+    public function __construct($level = Logger::DEBUG, $bubble = true)
+    {
+        if (!function_exists('zend_monitor_custom_event')) {
+            throw new MissingExtensionException(
+                'You must have Zend Server installed with Zend Monitor enabled in order to use this handler'
+            );
+        }
+        //zend monitor constants are not defined if zend monitor is not enabled.
+        $this->levelMap = array(
+            Logger::DEBUG     => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+            Logger::INFO      => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+            Logger::NOTICE    => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+            Logger::WARNING   => \ZEND_MONITOR_EVENT_SEVERITY_WARNING,
+            Logger::ERROR     => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+            Logger::CRITICAL  => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+            Logger::ALERT     => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+            Logger::EMERGENCY => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+        );
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $this->writeZendMonitorCustomEvent(
+            Logger::getLevelName($record['level']),
+            $record['message'],
+            $record['formatted'],
+            $this->levelMap[$record['level']]
+        );
+    }
+
+    /**
+     * Write to Zend Monitor Events
+     * @param string $type Text displayed in "Class Name (custom)" field
+     * @param string $message Text displayed in "Error String"
+     * @param mixed $formatted Displayed in Custom Variables tab
+     * @param int $severity Set the event severity level (-1,0,1)
+     */
+    protected function writeZendMonitorCustomEvent($type, $message, $formatted, $severity)
+    {
+        zend_monitor_custom_event($type, $message, $formatted, $severity);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDefaultFormatter()
+    {
+        return new NormalizerFormatter();
+    }
+
+    /**
+     * Get the level map
+     *
+     * @return array
+     */
+    public function getLevelMap()
+    {
+        return $this->levelMap;
+    }
+}

+ 796 - 0
api/vendor/monolog/monolog/src/Monolog/Logger.php

@@ -0,0 +1,796 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Monolog\Handler\HandlerInterface;
+use Monolog\Handler\StreamHandler;
+use Psr\Log\LoggerInterface;
+use Psr\Log\InvalidArgumentException;
+use Exception;
+
+/**
+ * Monolog log channel
+ *
+ * It contains a stack of Handlers and a stack of Processors,
+ * and uses them to store records that are added to it.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class Logger implements LoggerInterface, ResettableInterface
+{
+    /**
+     * Detailed debug information
+     */
+    const DEBUG = 100;
+
+    /**
+     * Interesting events
+     *
+     * Examples: User logs in, SQL logs.
+     */
+    const INFO = 200;
+
+    /**
+     * Uncommon events
+     */
+    const NOTICE = 250;
+
+    /**
+     * Exceptional occurrences that are not errors
+     *
+     * Examples: Use of deprecated APIs, poor use of an API,
+     * undesirable things that are not necessarily wrong.
+     */
+    const WARNING = 300;
+
+    /**
+     * Runtime errors
+     */
+    const ERROR = 400;
+
+    /**
+     * Critical conditions
+     *
+     * Example: Application component unavailable, unexpected exception.
+     */
+    const CRITICAL = 500;
+
+    /**
+     * Action must be taken immediately
+     *
+     * Example: Entire website down, database unavailable, etc.
+     * This should trigger the SMS alerts and wake you up.
+     */
+    const ALERT = 550;
+
+    /**
+     * Urgent alert.
+     */
+    const EMERGENCY = 600;
+
+    /**
+     * Monolog API version
+     *
+     * This is only bumped when API breaks are done and should
+     * follow the major version of the library
+     *
+     * @var int
+     */
+    const API = 1;
+
+    /**
+     * Logging levels from syslog protocol defined in RFC 5424
+     *
+     * @var array $levels Logging levels
+     */
+    protected static $levels = array(
+        self::DEBUG     => 'DEBUG',
+        self::INFO      => 'INFO',
+        self::NOTICE    => 'NOTICE',
+        self::WARNING   => 'WARNING',
+        self::ERROR     => 'ERROR',
+        self::CRITICAL  => 'CRITICAL',
+        self::ALERT     => 'ALERT',
+        self::EMERGENCY => 'EMERGENCY',
+    );
+
+    /**
+     * @var \DateTimeZone
+     */
+    protected static $timezone;
+
+    /**
+     * @var string
+     */
+    protected $name;
+
+    /**
+     * The handler stack
+     *
+     * @var HandlerInterface[]
+     */
+    protected $handlers;
+
+    /**
+     * Processors that will process all log records
+     *
+     * To process records of a single handler instead, add the processor on that specific handler
+     *
+     * @var callable[]
+     */
+    protected $processors;
+
+    /**
+     * @var bool
+     */
+    protected $microsecondTimestamps = true;
+
+    /**
+     * @var callable
+     */
+    protected $exceptionHandler;
+
+    /**
+     * @param string             $name       The logging channel
+     * @param HandlerInterface[] $handlers   Optional stack of handlers, the first one in the array is called first, etc.
+     * @param callable[]         $processors Optional array of processors
+     */
+    public function __construct($name, array $handlers = array(), array $processors = array())
+    {
+        $this->name = $name;
+        $this->setHandlers($handlers);
+        $this->processors = $processors;
+    }
+
+    /**
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Return a new cloned instance with the name changed
+     *
+     * @return static
+     */
+    public function withName($name)
+    {
+        $new = clone $this;
+        $new->name = $name;
+
+        return $new;
+    }
+
+    /**
+     * Pushes a handler on to the stack.
+     *
+     * @param  HandlerInterface $handler
+     * @return $this
+     */
+    public function pushHandler(HandlerInterface $handler)
+    {
+        array_unshift($this->handlers, $handler);
+
+        return $this;
+    }
+
+    /**
+     * Pops a handler from the stack
+     *
+     * @return HandlerInterface
+     */
+    public function popHandler()
+    {
+        if (!$this->handlers) {
+            throw new \LogicException('You tried to pop from an empty handler stack.');
+        }
+
+        return array_shift($this->handlers);
+    }
+
+    /**
+     * Set handlers, replacing all existing ones.
+     *
+     * If a map is passed, keys will be ignored.
+     *
+     * @param  HandlerInterface[] $handlers
+     * @return $this
+     */
+    public function setHandlers(array $handlers)
+    {
+        $this->handlers = array();
+        foreach (array_reverse($handlers) as $handler) {
+            $this->pushHandler($handler);
+        }
+
+        return $this;
+    }
+
+    /**
+     * @return HandlerInterface[]
+     */
+    public function getHandlers()
+    {
+        return $this->handlers;
+    }
+
+    /**
+     * Adds a processor on to the stack.
+     *
+     * @param  callable $callback
+     * @return $this
+     */
+    public function pushProcessor($callback)
+    {
+        if (!is_callable($callback)) {
+            throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
+        }
+        array_unshift($this->processors, $callback);
+
+        return $this;
+    }
+
+    /**
+     * Removes the processor on top of the stack and returns it.
+     *
+     * @return callable
+     */
+    public function popProcessor()
+    {
+        if (!$this->processors) {
+            throw new \LogicException('You tried to pop from an empty processor stack.');
+        }
+
+        return array_shift($this->processors);
+    }
+
+    /**
+     * @return callable[]
+     */
+    public function getProcessors()
+    {
+        return $this->processors;
+    }
+
+    /**
+     * Control the use of microsecond resolution timestamps in the 'datetime'
+     * member of new records.
+     *
+     * Generating microsecond resolution timestamps by calling
+     * microtime(true), formatting the result via sprintf() and then parsing
+     * the resulting string via \DateTime::createFromFormat() can incur
+     * a measurable runtime overhead vs simple usage of DateTime to capture
+     * a second resolution timestamp in systems which generate a large number
+     * of log events.
+     *
+     * @param bool $micro True to use microtime() to create timestamps
+     */
+    public function useMicrosecondTimestamps($micro)
+    {
+        $this->microsecondTimestamps = (bool) $micro;
+    }
+
+    /**
+     * Adds a log record.
+     *
+     * @param  int     $level   The logging level
+     * @param  string  $message The log message
+     * @param  array   $context The log context
+     * @return bool Whether the record has been processed
+     */
+    public function addRecord($level, $message, array $context = array())
+    {
+        if (!$this->handlers) {
+            $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG));
+        }
+
+        $levelName = static::getLevelName($level);
+
+        // check if any handler will handle this message so we can return early and save cycles
+        $handlerKey = null;
+        reset($this->handlers);
+        while ($handler = current($this->handlers)) {
+            if ($handler->isHandling(array('level' => $level))) {
+                $handlerKey = key($this->handlers);
+                break;
+            }
+
+            next($this->handlers);
+        }
+
+        if (null === $handlerKey) {
+            return false;
+        }
+
+        if (!static::$timezone) {
+            static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC');
+        }
+
+        // php7.1+ always has microseconds enabled, so we do not need this hack
+        if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) {
+            $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
+        } else {
+            $ts = new \DateTime('now', static::$timezone);
+        }
+        $ts->setTimezone(static::$timezone);
+
+        $record = array(
+            'message' => (string) $message,
+            'context' => $context,
+            'level' => $level,
+            'level_name' => $levelName,
+            'channel' => $this->name,
+            'datetime' => $ts,
+            'extra' => array(),
+        );
+
+        try {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+
+            while ($handler = current($this->handlers)) {
+                if (true === $handler->handle($record)) {
+                    break;
+                }
+
+                next($this->handlers);
+            }
+        } catch (Exception $e) {
+            $this->handleException($e, $record);
+        }
+
+        return true;
+    }
+
+    /**
+     * Ends a log cycle and frees all resources used by handlers.
+     *
+     * Closing a Handler means flushing all buffers and freeing any open resources/handles.
+     * Handlers that have been closed should be able to accept log records again and re-open
+     * themselves on demand, but this may not always be possible depending on implementation.
+     *
+     * This is useful at the end of a request and will be called automatically on every handler
+     * when they get destructed.
+     */
+    public function close()
+    {
+        foreach ($this->handlers as $handler) {
+            if (method_exists($handler, 'close')) {
+                $handler->close();
+            }
+        }
+    }
+
+    /**
+     * Ends a log cycle and resets all handlers and processors to their initial state.
+     *
+     * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal
+     * state, and getting it back to a state in which it can receive log records again.
+     *
+     * This is useful in case you want to avoid logs leaking between two requests or jobs when you
+     * have a long running process like a worker or an application server serving multiple requests
+     * in one process.
+     */
+    public function reset()
+    {
+        foreach ($this->handlers as $handler) {
+            if ($handler instanceof ResettableInterface) {
+                $handler->reset();
+            }
+        }
+
+        foreach ($this->processors as $processor) {
+            if ($processor instanceof ResettableInterface) {
+                $processor->reset();
+            }
+        }
+    }
+
+    /**
+     * Adds a log record at the DEBUG level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addDebug($message, array $context = array())
+    {
+        return $this->addRecord(static::DEBUG, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the INFO level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addInfo($message, array $context = array())
+    {
+        return $this->addRecord(static::INFO, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the NOTICE level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addNotice($message, array $context = array())
+    {
+        return $this->addRecord(static::NOTICE, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the WARNING level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addWarning($message, array $context = array())
+    {
+        return $this->addRecord(static::WARNING, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the ERROR level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addError($message, array $context = array())
+    {
+        return $this->addRecord(static::ERROR, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the CRITICAL level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addCritical($message, array $context = array())
+    {
+        return $this->addRecord(static::CRITICAL, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the ALERT level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addAlert($message, array $context = array())
+    {
+        return $this->addRecord(static::ALERT, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the EMERGENCY level.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function addEmergency($message, array $context = array())
+    {
+        return $this->addRecord(static::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * Gets all supported logging levels.
+     *
+     * @return array Assoc array with human-readable level names => level codes.
+     */
+    public static function getLevels()
+    {
+        return array_flip(static::$levels);
+    }
+
+    /**
+     * Gets the name of the logging level.
+     *
+     * @param  int    $level
+     * @return string
+     */
+    public static function getLevelName($level)
+    {
+        if (!isset(static::$levels[$level])) {
+            throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels)));
+        }
+
+        return static::$levels[$level];
+    }
+
+    /**
+     * Converts PSR-3 levels to Monolog ones if necessary
+     *
+     * @param string|int $level Level number (monolog) or name (PSR-3)
+     * @return int
+     */
+    public static function toMonologLevel($level)
+    {
+        if (is_string($level)) {
+            // Contains chars of all log levels and avoids using strtoupper() which may have
+            // strange results depending on locale (for example, "i" will become "İ")
+            $upper = strtr($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY');
+            if (defined(__CLASS__.'::'.$upper)) {
+                return constant(__CLASS__ . '::' . $upper);
+            }
+        }
+
+        return $level;
+    }
+
+    /**
+     * Checks whether the Logger has a handler that listens on the given level
+     *
+     * @param  int     $level
+     * @return bool
+     */
+    public function isHandling($level)
+    {
+        $record = array(
+            'level' => $level,
+        );
+
+        foreach ($this->handlers as $handler) {
+            if ($handler->isHandling($record)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Set a custom exception handler
+     *
+     * @param  callable $callback
+     * @return $this
+     */
+    public function setExceptionHandler($callback)
+    {
+        if (!is_callable($callback)) {
+            throw new \InvalidArgumentException('Exception handler must be valid callable (callback or object with an __invoke method), '.var_export($callback, true).' given');
+        }
+        $this->exceptionHandler = $callback;
+
+        return $this;
+    }
+
+    /**
+     * @return callable
+     */
+    public function getExceptionHandler()
+    {
+        return $this->exceptionHandler;
+    }
+
+    /**
+     * Delegates exception management to the custom exception handler,
+     * or throws the exception if no custom handler is set.
+     */
+    protected function handleException(Exception $e, array $record)
+    {
+        if (!$this->exceptionHandler) {
+            throw $e;
+        }
+
+        call_user_func($this->exceptionHandler, $e, $record);
+    }
+
+    /**
+     * Adds a log record at an arbitrary level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  mixed   $level   The log level
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function log($level, $message, array $context = array())
+    {
+        $level = static::toMonologLevel($level);
+
+        return $this->addRecord($level, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the DEBUG level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function debug($message, array $context = array())
+    {
+        return $this->addRecord(static::DEBUG, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the INFO level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function info($message, array $context = array())
+    {
+        return $this->addRecord(static::INFO, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the NOTICE level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function notice($message, array $context = array())
+    {
+        return $this->addRecord(static::NOTICE, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the WARNING level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function warn($message, array $context = array())
+    {
+        return $this->addRecord(static::WARNING, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the WARNING level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function warning($message, array $context = array())
+    {
+        return $this->addRecord(static::WARNING, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the ERROR level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function err($message, array $context = array())
+    {
+        return $this->addRecord(static::ERROR, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the ERROR level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function error($message, array $context = array())
+    {
+        return $this->addRecord(static::ERROR, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the CRITICAL level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function crit($message, array $context = array())
+    {
+        return $this->addRecord(static::CRITICAL, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the CRITICAL level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function critical($message, array $context = array())
+    {
+        return $this->addRecord(static::CRITICAL, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the ALERT level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function alert($message, array $context = array())
+    {
+        return $this->addRecord(static::ALERT, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the EMERGENCY level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function emerg($message, array $context = array())
+    {
+        return $this->addRecord(static::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * Adds a log record at the EMERGENCY level.
+     *
+     * This method allows for compatibility with common interfaces.
+     *
+     * @param  string $message The log message
+     * @param  array  $context The log context
+     * @return bool   Whether the record has been processed
+     */
+    public function emergency($message, array $context = array())
+    {
+        return $this->addRecord(static::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * Set the timezone to be used for the timestamp of log records.
+     *
+     * This is stored globally for all Logger instances
+     *
+     * @param \DateTimeZone $tz Timezone object
+     */
+    public static function setTimezone(\DateTimeZone $tz)
+    {
+        self::$timezone = $tz;
+    }
+}

+ 64 - 0
api/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php

@@ -0,0 +1,64 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects Git branch and Git commit SHA in all records
+ *
+ * @author Nick Otter
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class GitProcessor implements ProcessorInterface
+{
+    private $level;
+    private static $cache;
+
+    public function __construct($level = Logger::DEBUG)
+    {
+        $this->level = Logger::toMonologLevel($level);
+    }
+
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        // return if the level is not high enough
+        if ($record['level'] < $this->level) {
+            return $record;
+        }
+
+        $record['extra']['git'] = self::getGitInfo();
+
+        return $record;
+    }
+
+    private static function getGitInfo()
+    {
+        if (self::$cache) {
+            return self::$cache;
+        }
+
+        $branches = `git branch -v --no-abbrev`;
+        if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
+            return self::$cache = array(
+                'branch' => $matches[1],
+                'commit' => $matches[2],
+            );
+        }
+
+        return self::$cache = array();
+    }
+}

+ 112 - 0
api/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php

@@ -0,0 +1,112 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects line/file:class/function where the log message came from
+ *
+ * Warning: This only works if the handler processes the logs directly.
+ * If you put the processor on a handler that is behind a FingersCrossedHandler
+ * for example, the processor will only be called once the trigger level is reached,
+ * and all the log records will have the same file/line/.. data from the call that
+ * triggered the FingersCrossedHandler.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class IntrospectionProcessor implements ProcessorInterface
+{
+    private $level;
+
+    private $skipClassesPartials;
+
+    private $skipStackFramesCount;
+
+    private $skipFunctions = array(
+        'call_user_func',
+        'call_user_func_array',
+    );
+
+    public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array(), $skipStackFramesCount = 0)
+    {
+        $this->level = Logger::toMonologLevel($level);
+        $this->skipClassesPartials = array_merge(array('Monolog\\'), $skipClassesPartials);
+        $this->skipStackFramesCount = $skipStackFramesCount;
+    }
+
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        // return if the level is not high enough
+        if ($record['level'] < $this->level) {
+            return $record;
+        }
+
+        /*
+        * http://php.net/manual/en/function.debug-backtrace.php
+        * As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added.
+        * Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'.
+        */
+        $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS);
+
+        // skip first since it's always the current method
+        array_shift($trace);
+        // the call_user_func call is also skipped
+        array_shift($trace);
+
+        $i = 0;
+
+        while ($this->isTraceClassOrSkippedFunction($trace, $i)) {
+            if (isset($trace[$i]['class'])) {
+                foreach ($this->skipClassesPartials as $part) {
+                    if (strpos($trace[$i]['class'], $part) !== false) {
+                        $i++;
+                        continue 2;
+                    }
+                }
+            } elseif (in_array($trace[$i]['function'], $this->skipFunctions)) {
+                $i++;
+                continue;
+            }
+
+            break;
+        }
+
+        $i += $this->skipStackFramesCount;
+
+        // we should have the call source now
+        $record['extra'] = array_merge(
+            $record['extra'],
+            array(
+                'file'      => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null,
+                'line'      => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
+                'class'     => isset($trace[$i]['class']) ? $trace[$i]['class'] : null,
+                'function'  => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
+            )
+        );
+
+        return $record;
+    }
+
+    private function isTraceClassOrSkippedFunction(array $trace, $index)
+    {
+        if (!isset($trace[$index])) {
+            return false;
+        }
+
+        return isset($trace[$index]['class']) || in_array($trace[$index]['function'], $this->skipFunctions);
+    }
+}

+ 35 - 0
api/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php

@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects memory_get_peak_usage in all records
+ *
+ * @see Monolog\Processor\MemoryProcessor::__construct() for options
+ * @author Rob Jensen
+ */
+class MemoryPeakUsageProcessor extends MemoryProcessor
+{
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        $bytes = memory_get_peak_usage($this->realUsage);
+        $formatted = $this->formatBytes($bytes);
+
+        $record['extra']['memory_peak_usage'] = $formatted;
+
+        return $record;
+    }
+}

+ 63 - 0
api/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php

@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Some methods that are common for all memory processors
+ *
+ * @author Rob Jensen
+ */
+abstract class MemoryProcessor implements ProcessorInterface
+{
+    /**
+     * @var bool If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported.
+     */
+    protected $realUsage;
+
+    /**
+     * @var bool If true, then format memory size to human readable string (MB, KB, B depending on size)
+     */
+    protected $useFormatting;
+
+    /**
+     * @param bool $realUsage     Set this to true to get the real size of memory allocated from system.
+     * @param bool $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size)
+     */
+    public function __construct($realUsage = true, $useFormatting = true)
+    {
+        $this->realUsage = (bool) $realUsage;
+        $this->useFormatting = (bool) $useFormatting;
+    }
+
+    /**
+     * Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is
+     *
+     * @param  int        $bytes
+     * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as is
+     */
+    protected function formatBytes($bytes)
+    {
+        $bytes = (int) $bytes;
+
+        if (!$this->useFormatting) {
+            return $bytes;
+        }
+
+        if ($bytes > 1024 * 1024) {
+            return round($bytes / 1024 / 1024, 2).' MB';
+        } elseif ($bytes > 1024) {
+            return round($bytes / 1024, 2).' KB';
+        }
+
+        return $bytes . ' B';
+    }
+}

+ 35 - 0
api/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php

@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects memory_get_usage in all records
+ *
+ * @see Monolog\Processor\MemoryProcessor::__construct() for options
+ * @author Rob Jensen
+ */
+class MemoryUsageProcessor extends MemoryProcessor
+{
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        $bytes = memory_get_usage($this->realUsage);
+        $formatted = $this->formatBytes($bytes);
+
+        $record['extra']['memory_usage'] = $formatted;
+
+        return $record;
+    }
+}

+ 63 - 0
api/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php

@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jonathan A. Schweder <jonathanschweder@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects Hg branch and Hg revision number in all records
+ *
+ * @author Jonathan A. Schweder <jonathanschweder@gmail.com>
+ */
+class MercurialProcessor implements ProcessorInterface
+{
+    private $level;
+    private static $cache;
+
+    public function __construct($level = Logger::DEBUG)
+    {
+        $this->level = Logger::toMonologLevel($level);
+    }
+
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        // return if the level is not high enough
+        if ($record['level'] < $this->level) {
+            return $record;
+        }
+
+        $record['extra']['hg'] = self::getMercurialInfo();
+
+        return $record;
+    }
+
+    private static function getMercurialInfo()
+    {
+        if (self::$cache) {
+            return self::$cache;
+        }
+
+        $result = explode(' ', trim(`hg id -nb`));
+        if (count($result) >= 3) {
+            return self::$cache = array(
+                'branch' => $result[1],
+                'revision' => $result[2],
+            );
+        }
+
+        return self::$cache = array();
+    }
+}

+ 31 - 0
api/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php

@@ -0,0 +1,31 @@
+<?php
+
+/*
+ * This file is part of the Monolog package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Adds value of getmypid into records
+ *
+ * @author Andreas Hörnicke
+ */
+class ProcessIdProcessor implements ProcessorInterface
+{
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        $record['extra']['process_id'] = getmypid();
+
+        return $record;
+    }
+}

Неке датотеке нису приказане због велике количине промена