فهرست منبع

added monolog

Piotr Labudda 8 سال پیش
والد
کامیت
486259ce80
98فایلهای تغییر یافته به همراه11723 افزوده شده و 0 حذف شده
  1. 126 0
      SE/se-lib/Vendor/Monolog.php
  2. 230 0
      SE/se-lib/Vendor/Monolog/ErrorHandler.php
  3. 78 0
      SE/se-lib/Vendor/Monolog/Formatter/ChromePHPFormatter.php
  4. 89 0
      SE/se-lib/Vendor/Monolog/Formatter/ElasticaFormatter.php
  5. 116 0
      SE/se-lib/Vendor/Monolog/Formatter/FlowdockFormatter.php
  6. 85 0
      SE/se-lib/Vendor/Monolog/Formatter/FluentdFormatter.php
  7. 36 0
      SE/se-lib/Vendor/Monolog/Formatter/FormatterInterface.php
  8. 138 0
      SE/se-lib/Vendor/Monolog/Formatter/GelfMessageFormatter.php
  9. 141 0
      SE/se-lib/Vendor/Monolog/Formatter/HtmlFormatter.php
  10. 208 0
      SE/se-lib/Vendor/Monolog/Formatter/JsonFormatter.php
  11. 179 0
      SE/se-lib/Vendor/Monolog/Formatter/LineFormatter.php
  12. 47 0
      SE/se-lib/Vendor/Monolog/Formatter/LogglyFormatter.php
  13. 166 0
      SE/se-lib/Vendor/Monolog/Formatter/LogstashFormatter.php
  14. 105 0
      SE/se-lib/Vendor/Monolog/Formatter/MongoDBFormatter.php
  15. 297 0
      SE/se-lib/Vendor/Monolog/Formatter/NormalizerFormatter.php
  16. 48 0
      SE/se-lib/Vendor/Monolog/Formatter/ScalarFormatter.php
  17. 113 0
      SE/se-lib/Vendor/Monolog/Formatter/WildfireFormatter.php
  18. 186 0
      SE/se-lib/Vendor/Monolog/Handler/AbstractHandler.php
  19. 66 0
      SE/se-lib/Vendor/Monolog/Handler/AbstractProcessingHandler.php
  20. 101 0
      SE/se-lib/Vendor/Monolog/Handler/AbstractSyslogHandler.php
  21. 148 0
      SE/se-lib/Vendor/Monolog/Handler/AmqpHandler.php
  22. 230 0
      SE/se-lib/Vendor/Monolog/Handler/BrowserConsoleHandler.php
  23. 117 0
      SE/se-lib/Vendor/Monolog/Handler/BufferHandler.php
  24. 211 0
      SE/se-lib/Vendor/Monolog/Handler/ChromePHPHandler.php
  25. 72 0
      SE/se-lib/Vendor/Monolog/Handler/CouchDBHandler.php
  26. 151 0
      SE/se-lib/Vendor/Monolog/Handler/CubeHandler.php
  27. 57 0
      SE/se-lib/Vendor/Monolog/Handler/Curl/Util.php
  28. 169 0
      SE/se-lib/Vendor/Monolog/Handler/DeduplicationHandler.php
  29. 45 0
      SE/se-lib/Vendor/Monolog/Handler/DoctrineCouchDBHandler.php
  30. 107 0
      SE/se-lib/Vendor/Monolog/Handler/DynamoDbHandler.php
  31. 128 0
      SE/se-lib/Vendor/Monolog/Handler/ElasticSearchHandler.php
  32. 82 0
      SE/se-lib/Vendor/Monolog/Handler/ErrorLogHandler.php
  33. 140 0
      SE/se-lib/Vendor/Monolog/Handler/FilterHandler.php
  34. 28 0
      SE/se-lib/Vendor/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php
  35. 59 0
      SE/se-lib/Vendor/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php
  36. 34 0
      SE/se-lib/Vendor/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php
  37. 163 0
      SE/se-lib/Vendor/Monolog/Handler/FingersCrossedHandler.php
  38. 195 0
      SE/se-lib/Vendor/Monolog/Handler/FirePHPHandler.php
  39. 126 0
      SE/se-lib/Vendor/Monolog/Handler/FleepHookHandler.php
  40. 127 0
      SE/se-lib/Vendor/Monolog/Handler/FlowdockHandler.php
  41. 73 0
      SE/se-lib/Vendor/Monolog/Handler/GelfHandler.php
  42. 104 0
      SE/se-lib/Vendor/Monolog/Handler/GroupHandler.php
  43. 90 0
      SE/se-lib/Vendor/Monolog/Handler/HandlerInterface.php
  44. 108 0
      SE/se-lib/Vendor/Monolog/Handler/HandlerWrapper.php
  45. 350 0
      SE/se-lib/Vendor/Monolog/Handler/HipChatHandler.php
  46. 69 0
      SE/se-lib/Vendor/Monolog/Handler/IFTTTHandler.php
  47. 55 0
      SE/se-lib/Vendor/Monolog/Handler/LogEntriesHandler.php
  48. 102 0
      SE/se-lib/Vendor/Monolog/Handler/LogglyHandler.php
  49. 67 0
      SE/se-lib/Vendor/Monolog/Handler/MailHandler.php
  50. 68 0
      SE/se-lib/Vendor/Monolog/Handler/MandrillHandler.php
  51. 21 0
      SE/se-lib/Vendor/Monolog/Handler/MissingExtensionException.php
  52. 59 0
      SE/se-lib/Vendor/Monolog/Handler/MongoDBHandler.php
  53. 185 0
      SE/se-lib/Vendor/Monolog/Handler/NativeMailerHandler.php
  54. 202 0
      SE/se-lib/Vendor/Monolog/Handler/NewRelicHandler.php
  55. 45 0
      SE/se-lib/Vendor/Monolog/Handler/NullHandler.php
  56. 242 0
      SE/se-lib/Vendor/Monolog/Handler/PHPConsoleHandler.php
  57. 56 0
      SE/se-lib/Vendor/Monolog/Handler/PsrHandler.php
  58. 185 0
      SE/se-lib/Vendor/Monolog/Handler/PushoverHandler.php
  59. 232 0
      SE/se-lib/Vendor/Monolog/Handler/RavenHandler.php
  60. 97 0
      SE/se-lib/Vendor/Monolog/Handler/RedisHandler.php
  61. 132 0
      SE/se-lib/Vendor/Monolog/Handler/RollbarHandler.php
  62. 178 0
      SE/se-lib/Vendor/Monolog/Handler/RotatingFileHandler.php
  63. 82 0
      SE/se-lib/Vendor/Monolog/Handler/SamplingHandler.php
  64. 294 0
      SE/se-lib/Vendor/Monolog/Handler/Slack/SlackRecord.php
  65. 215 0
      SE/se-lib/Vendor/Monolog/Handler/SlackHandler.php
  66. 115 0
      SE/se-lib/Vendor/Monolog/Handler/SlackWebhookHandler.php
  67. 80 0
      SE/se-lib/Vendor/Monolog/Handler/SlackbotHandler.php
  68. 346 0
      SE/se-lib/Vendor/Monolog/Handler/SocketHandler.php
  69. 176 0
      SE/se-lib/Vendor/Monolog/Handler/StreamHandler.php
  70. 99 0
      SE/se-lib/Vendor/Monolog/Handler/SwiftMailerHandler.php
  71. 67 0
      SE/se-lib/Vendor/Monolog/Handler/SyslogHandler.php
  72. 56 0
      SE/se-lib/Vendor/Monolog/Handler/SyslogUdp/UdpSocket.php
  73. 103 0
      SE/se-lib/Vendor/Monolog/Handler/SyslogUdpHandler.php
  74. 154 0
      SE/se-lib/Vendor/Monolog/Handler/TestHandler.php
  75. 61 0
      SE/se-lib/Vendor/Monolog/Handler/WhatFailureGroupHandler.php
  76. 95 0
      SE/se-lib/Vendor/Monolog/Handler/ZendMonitorHandler.php
  77. 700 0
      SE/se-lib/Vendor/Monolog/Logger.php
  78. 64 0
      SE/se-lib/Vendor/Monolog/Processor/GitProcessor.php
  79. 112 0
      SE/se-lib/Vendor/Monolog/Processor/IntrospectionProcessor.php
  80. 35 0
      SE/se-lib/Vendor/Monolog/Processor/MemoryPeakUsageProcessor.php
  81. 63 0
      SE/se-lib/Vendor/Monolog/Processor/MemoryProcessor.php
  82. 35 0
      SE/se-lib/Vendor/Monolog/Processor/MemoryUsageProcessor.php
  83. 63 0
      SE/se-lib/Vendor/Monolog/Processor/MercurialProcessor.php
  84. 31 0
      SE/se-lib/Vendor/Monolog/Processor/ProcessIdProcessor.php
  85. 48 0
      SE/se-lib/Vendor/Monolog/Processor/PsrLogMessageProcessor.php
  86. 44 0
      SE/se-lib/Vendor/Monolog/Processor/TagProcessor.php
  87. 46 0
      SE/se-lib/Vendor/Monolog/Processor/UidProcessor.php
  88. 113 0
      SE/se-lib/Vendor/Monolog/Processor/WebProcessor.php
  89. 134 0
      SE/se-lib/Vendor/Monolog/Registry.php
  90. 128 0
      SE/se-lib/Vendor/Psr/AbstractLogger.php
  91. 7 0
      SE/se-lib/Vendor/Psr/InvalidArgumentException.php
  92. 18 0
      SE/se-lib/Vendor/Psr/LogLevel.php
  93. 18 0
      SE/se-lib/Vendor/Psr/LoggerAwareInterface.php
  94. 26 0
      SE/se-lib/Vendor/Psr/LoggerAwareTrait.php
  95. 123 0
      SE/se-lib/Vendor/Psr/LoggerInterface.php
  96. 140 0
      SE/se-lib/Vendor/Psr/LoggerTrait.php
  97. 28 0
      SE/se-lib/Vendor/Psr/NullLogger.php
  98. 140 0
      SE/se-lib/Vendor/Psr/Test/LoggerInterfaceTest.php

+ 126 - 0
SE/se-lib/Vendor/Monolog.php

@@ -0,0 +1,126 @@
+<?php
+
+// namespace P5;
+
+use Monolog\Logger;
+
+require_once dirname(__FILE__) . DS . 'Psr/LoggerInterface.php';
+require_once dirname(__FILE__) . DS . 'Psr/AbstractLogger.php';
+
+require_once dirname(__FILE__) . DS . 'Psr/InvalidArgumentException.php';
+require_once dirname(__FILE__) . DS . 'Psr/LoggerAwareInterface.php';
+require_once dirname(__FILE__) . DS . 'Psr/LoggerAwareTrait.php';
+require_once dirname(__FILE__) . DS . 'Psr/LoggerTrait.php';
+require_once dirname(__FILE__) . DS . 'Psr/LogLevel.php';
+require_once dirname(__FILE__) . DS . 'Psr/NullLogger.php';
+// require_once dirname(__FILE__) . DS . 'Psr/Test/LoggerInterfaceTest.php';
+
+require_once dirname(__FILE__) . DS . 'Monolog/Formatter/FormatterInterface.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Formatter/NormalizerFormatter.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Formatter/JsonFormatter.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Formatter/LineFormatter.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Handler/HandlerInterface.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Handler/AbstractHandler.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Handler/AbstractProcessingHandler.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Handler/StreamHandler.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Handler/RotatingFileHandler.php';
+require_once dirname(__FILE__) . DS . 'Monolog/Logger.php';
+
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/AbstractSyslogHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/AmqpHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/BrowserConsoleHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/BufferHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/ChromePHPHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/CouchDBHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/CubeHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/Curl/Util.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/DeduplicationHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/DoctrineCouchDBHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/DynamoDbHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/ElasticSearchHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/ErrorLogHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FilterHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FingersCrossedHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FirePHPHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FleepHookHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/FlowdockHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/GelfHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/GroupHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/HandlerWrapper.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/HipChatHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/IFTTTHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/LogEntriesHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/LogglyHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/MailHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/MandrillHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/MissingExtensionException.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/MongoDBHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/NativeMailerHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/NewRelicHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/NullHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/PHPConsoleHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/PsrHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/PushoverHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/RavenHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/RedisHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/RollbarHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SamplingHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/Slack/SlackRecord.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SlackbotHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SlackHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SlackWebhookHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SocketHandler.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Handler/SwiftMailerHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SyslogHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SyslogUdp/UdpSocket.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/SyslogUdpHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/TestHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/WhatFailureGroupHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Handler/ZendMonitorHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/ErrorHandler.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/ChromePHPFormatter.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Formatter/ElasticaFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/FlowdockFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/FluentdFormatter.php';
+// // require_once dirname(__FILE__) . DS . 'Monolog/Formatter/GelfMessageFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/HtmlFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/LogglyFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/LogstashFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/MongoDBFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/ScalarFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Formatter/WildfireFormatter.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/GitProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/IntrospectionProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/MemoryPeakUsageProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/MemoryProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/MemoryUsageProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/MercurialProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/ProcessIdProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/PsrLogMessageProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/TagProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/UidProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Processor/WebProcessor.php';
+// require_once dirname(__FILE__) . DS . 'Monolog/Registry.php';
+
+class Vendor_Monolog extends Logger {
+
+	static function getFileLogger($logFile, $handlerLevel = Vendor_Monolog::DEBUG) {
+		$logger = new Vendor_Monolog('log');
+		$logger->pushHandler(new StreamHandler($logFile, $handlerLevel));
+		return $logger;
+	}
+
+	static function getJsonFileLogger($logFile, $handlerLevel = Vendor_Monolog::DEBUG) {
+		$formatter = new JsonFormatter();
+		// Create a handler
+		$stream = new StreamHandler($logFile, $handlerLevel);
+		$stream->setFormatter($formatter);
+		// bind it to a logger object
+		$securityLogger = new Vendor_Monolog('log');
+		$securityLogger->pushHandler($stream);
+	}
+
+}

+ 230 - 0
SE/se-lib/Vendor/Monolog/ErrorHandler.php

@@ -0,0 +1,230 @@
+<?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 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);
+
+        $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', get_class($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));
+        }
+
+        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'])
+            );
+
+            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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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;
+    }
+}

+ 85 - 0
SE/se-lib/Vendor/Monolog/Formatter/FluentdFormatter.php

@@ -0,0 +1,85 @@
+<?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;
+
+/**
+ * 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'],
+            'extra' => $record['extra'],
+        );
+
+        if (!$this->levelTag) {
+            $message['level'] = $record['level'];
+            $message['level_name'] = $record['level_name'];
+        }
+
+        return json_encode(array($tag, $record['datetime']->getTimestamp(), $message));
+    }
+
+    public function formatBatch(array $records)
+    {
+        $message = '';
+        foreach ($records as $record) {
+            $message .= $this->format($record);
+        }
+
+        return $message;
+    }
+}

+ 36 - 0
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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;
+    }
+}

+ 141 - 0
SE/se-lib/Vendor/Monolog/Formatter/HtmlFormatter.php

@@ -0,0 +1,141 @@
+<?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 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;spacing: 0;text-align: left;\">\n<th style=\"background: #cccccc\" width=\"100px\">$th:</th>\n<td style=\"padding: 4px;spacing: 0;text-align: left;background: #eeeeee\">".$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 json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+        }
+
+        return str_replace('\\/', '/', json_encode($data));
+    }
+}

+ 208 - 0
SE/se-lib/Vendor/Monolog/Formatter/JsonFormatter.php

@@ -0,0 +1,208 @@
+<?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 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)
+    {
+        if (is_array($data) || $data instanceof \Traversable) {
+            $normalized = array();
+
+            $count = 1;
+            foreach ($data as $key => $value) {
+                if ($count++ >= 1000) {
+                    $normalized['...'] = 'Over 1000 items, aborting normalization';
+                    break;
+                }
+                $normalized[$key] = $this->normalize($value);
+            }
+
+            return $normalized;
+        }
+
+        if ($data instanceof Exception || $data instanceof Throwable) {
+            return $this->normalizeException($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).' / '.get_class($e));
+        }
+
+        $data = array(
+            'class' => get_class($e),
+            'message' => $e->getMessage(),
+            'code' => $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'];
+                } elseif (isset($frame['function']) && $frame['function'] === '{closure}') {
+                    // We should again normalize the frames, because it might contain invalid items
+                    $data['trace'][] = $frame['function'];
+                } else {
+                    // We should again normalize the frames, because it might contain invalid items
+                    $data['trace'][] = $this->normalize($frame);
+                }
+            }
+        }
+
+        if ($previous = $e->getPrevious()) {
+            $data['previous'] = $this->normalizeException($previous);
+        }
+
+        return $data;
+    }
+}

+ 179 - 0
SE/se-lib/Vendor/Monolog/Formatter/LineFormatter.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\Formatter;
+
+/**
+ * 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).' / '.get_class($e));
+        }
+
+        $previousText = '';
+        if ($previous = $e->getPrevious()) {
+            do {
+                $previousText .= ', '.get_class($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
+            } while ($previous = $previous->getPrevious());
+        }
+
+        $str = '[object] ('.get_class($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('\\/', '/', @json_encode($data));
+    }
+
+    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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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;
+    }
+}

+ 105 - 0
SE/se-lib/Vendor/Monolog/Formatter/MongoDBFormatter.php

@@ -0,0 +1,105 @@
+<?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 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'] = get_class($value);
+
+        return $this->formatArray($objectVars, $nestingLevel);
+    }
+
+    protected function formatException(\Exception $exception, $nestingLevel)
+    {
+        $formattedException = array(
+            'class' => get_class($exception),
+            'message' => $exception->getMessage(),
+            'code' => $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());
+    }
+}

+ 297 - 0
SE/se-lib/Vendor/Monolog/Formatter/NormalizerFormatter.php

@@ -0,0 +1,297 @@
+<?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;
+
+/**
+ * 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)
+    {
+        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);
+            }
+
+            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)", get_class($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).' / '.get_class($e));
+        }
+
+        $data = array(
+            'class' => get_class($e),
+            'message' => $e->getMessage(),
+            'code' => $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)) {
+                $data['detail'] = $e->detail;
+            }
+        }
+
+        $trace = $e->getTrace();
+        foreach ($trace as $frame) {
+            if (isset($frame['file'])) {
+                $data['trace'][] = $frame['file'].':'.$frame['line'];
+            } elseif (isset($frame['function']) && $frame['function'] === '{closure}') {
+                // We should again normalize the frames, because it might contain invalid items
+                $data['trace'][] = $frame['function'];
+            } else {
+                // We should again normalize the frames, because it might contain invalid items
+                $data['trace'][] = $this->toJson($this->normalize($frame), true);
+            }
+        }
+
+        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)
+    {
+        // suppress json_encode errors since it's twitchy with some inputs
+        if ($ignoreErrors) {
+            return @$this->jsonEncode($data);
+        }
+
+        $json = $this->jsonEncode($data);
+
+        if ($json === false) {
+            $json = $this->handleJsonError(json_last_error(), $data);
+        }
+
+        return $json;
+    }
+
+    /**
+     * @param  mixed  $data
+     * @return string JSON encoded data or null on failure
+     */
+    private function jsonEncode($data)
+    {
+        if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+            return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+        }
+
+        return json_encode($data);
+    }
+
+    /**
+     * Handle a json_encode failure.
+     *
+     * If the failure is due to invalid string encoding, try to clean the
+     * input and encode again. If the second encoding attempt fails, the
+     * inital error is not encoding related or the input can't be cleaned then
+     * raise a descriptive exception.
+     *
+     * @param  int               $code return code of json_last_error function
+     * @param  mixed             $data data that was meant to be encoded
+     * @throws \RuntimeException if failure can't be corrected
+     * @return string            JSON encoded data after error correction
+     */
+    private function handleJsonError($code, $data)
+    {
+        if ($code !== JSON_ERROR_UTF8) {
+            $this->throwEncodeError($code, $data);
+        }
+
+        if (is_string($data)) {
+            $this->detectAndCleanUtf8($data);
+        } elseif (is_array($data)) {
+            array_walk_recursive($data, array($this, 'detectAndCleanUtf8'));
+        } else {
+            $this->throwEncodeError($code, $data);
+        }
+
+        $json = $this->jsonEncode($data);
+
+        if ($json === false) {
+            $this->throwEncodeError(json_last_error(), $data);
+        }
+
+        return $json;
+    }
+
+    /**
+     * Throws an exception according to a given code with a customized message
+     *
+     * @param  int               $code return code of json_last_error function
+     * @param  mixed             $data data that was meant to be encoded
+     * @throws \RuntimeException
+     */
+    private function throwEncodeError($code, $data)
+    {
+        switch ($code) {
+            case JSON_ERROR_DEPTH:
+                $msg = 'Maximum stack depth exceeded';
+                break;
+            case JSON_ERROR_STATE_MISMATCH:
+                $msg = 'Underflow or the modes mismatch';
+                break;
+            case JSON_ERROR_CTRL_CHAR:
+                $msg = 'Unexpected control character found';
+                break;
+            case JSON_ERROR_UTF8:
+                $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
+                break;
+            default:
+                $msg = 'Unknown error';
+        }
+
+        throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
+    }
+
+    /**
+     * Detect invalid UTF-8 string characters and convert to valid UTF-8.
+     *
+     * Valid UTF-8 input will be left unmodified, but strings containing
+     * invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed
+     * original encoding of ISO-8859-15. This conversion may result in
+     * incorrect output if the actual encoding was not ISO-8859-15, but it
+     * will be clean UTF-8 output and will not rely on expensive and fragile
+     * detection algorithms.
+     *
+     * Function converts the input in place in the passed variable so that it
+     * can be used as a callback for array_walk_recursive.
+     *
+     * @param mixed &$data Input to check and convert if needed
+     * @private
+     */
+    public function detectAndCleanUtf8(&$data)
+    {
+        if (is_string($data) && !preg_match('//u', $data)) {
+            $data = preg_replace_callback(
+                '/[\x80-\xFF]+/',
+                function ($m) { return utf8_encode($m[0]); },
+                $data
+            );
+            $data = str_replace(
+                array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'),
+                array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'),
+                $data
+            );
+        }
+    }
+}

+ 48 - 0
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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)
+    {
+        if (is_object($data) && !$data instanceof \DateTime) {
+            return $data;
+        }
+
+        return parent::normalize($data);
+    }
+}

+ 186 - 0
SE/se-lib/Vendor/Monolog/Handler/AbstractHandler.php

@@ -0,0 +1,186 @@
+<?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;
+
+/**
+ * Base Handler class providing the Handler structure
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+abstract class AbstractHandler implements HandlerInterface
+{
+    protected $level = Logger::DEBUG;
+    protected $bubble = true;
+
+    /**
+     * @var FormatterInterface
+     */
+    protected $formatter;
+    protected $processors = array();
+
+    /**
+     * @param int     $level  The minimum logging level at which this handler will be triggered
+     * @param Boolean $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  Boolean $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 Boolean 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
+        }
+    }
+
+    /**
+     * Gets the default formatter.
+     *
+     * @return FormatterInterface
+     */
+    protected function getDefaultFormatter()
+    {
+        return new LineFormatter();
+    }
+}

+ 66 - 0
SE/se-lib/Vendor/Monolog/Handler/AbstractProcessingHandler.php

@@ -0,0 +1,66 @@
+<?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 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
SE/se-lib/Vendor/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 Boolean $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
SE/se-lib/Vendor/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);
+    }
+}

+ 230 - 0
SE/se-lib/Vendor/Monolog/Handler/BrowserConsoleHandler.php

@@ -0,0 +1,230 @@
+<?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
+        self::$records[] = $record;
+
+        // Register shutdown handler if not already done
+        if (!self::$initialized) {
+            self::$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 = self::getResponseFormat();
+        if ($format === 'unknown') {
+            return;
+        }
+
+        if (count(self::$records)) {
+            if ($format === 'html') {
+                self::writeOutput('<script>' . self::generateScript() . '</script>');
+            } elseif ($format === 'js') {
+                self::writeOutput(self::generateScript());
+            }
+            self::reset();
+        }
+    }
+
+    /**
+     * Forget all logged records
+     */
+    public static function reset()
+    {
+        self::$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 (self::$records as $record) {
+            $context = self::dump('Context', $record['context']);
+            $extra = self::dump('Extra', $record['extra']);
+
+            if (empty($context) && empty($extra)) {
+                $script[] = self::call_array('log', self::handleStyles($record['formatted']));
+            } else {
+                $script = array_merge($script,
+                    array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))),
+                    $context,
+                    $extra,
+                    array(self::call('groupEnd'))
+                );
+            }
+        }
+
+        return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
+    }
+
+    private static function handleStyles($formatted)
+    {
+        $args = array(self::quote('font-weight: normal'));
+        $format = '%c' . $formatted;
+        preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
+
+        foreach (array_reverse($matches) as $match) {
+            $args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0]));
+            $args[] = '"font-weight: normal"';
+
+            $pos = $match[0][1];
+            $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
+        }
+
+        array_unshift($args, self::quote($format));
+
+        return $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[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title));
+        foreach ($dict as $key => $value) {
+            $value = json_encode($value);
+            if (empty($value)) {
+                $value = self::quote('');
+            }
+            $script[] = self::call('log', self::quote('%s: %o'), self::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 self::call_array($method, $args);
+    }
+
+    private static function call_array($method, array $args)
+    {
+        return 'c.' . $method . '(' . implode(', ', $args) . ');';
+    }
+}

+ 117 - 0
SE/se-lib/Vendor/Monolog/Handler/BufferHandler.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\Logger;
+
+/**
+ * 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 Boolean          $bubble          Whether the messages that are handled can bubble up the stack or not
+     * @param Boolean          $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();
+    }
+}

+ 211 - 0
SE/se-lib/Vendor/Monolog/Handler/ChromePHPHandler.php

@@ -0,0 +1,211 @@
+<?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;
+
+/**
+ * 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 256KB, so when we sent 240KB we stop sending
+     *
+     * @var Boolean
+     */
+    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 Boolean $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 = @json_encode(self::$json);
+        $data = base64_encode(utf8_encode($json));
+        if (strlen($data) > 240 * 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 = @json_encode(self::$json);
+            $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 Boolean
+     */
+    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
SE/se-lib/Vendor/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);
+    }
+}

+ 151 - 0
SE/se-lib/Vendor/Monolog/Handler/CubeHandler.php

@@ -0,0 +1,151 @@
+<?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 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(json_encode($data));
+        } else {
+            $this->writeUdp(json_encode($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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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 Boolean          $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
SE/se-lib/Vendor/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;
+    }
+}

+ 107 - 0
SE/se-lib/Vendor/Monolog/Handler/DynamoDbHandler.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\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 {
+            $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
SE/se-lib/Vendor/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 Boolean $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
SE/se-lib/Vendor/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 Boolean $bubble         Whether the messages that are handled can bubble up the stack or not
+     * @param Boolean $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);
+        }
+    }
+}

+ 140 - 0
SE/se-lib/Vendor/Monolog/Handler/FilterHandler.php

@@ -0,0 +1,140 @@
+<?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 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 Boolean
+     */
+    protected $bubble;
+
+    /**
+     * @param callable|HandlerInterface $handler        Handler or factory callable($record, $this).
+     * @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 Boolean                   $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;
+        }
+
+        // The same logic as in FingersCrossedHandler
+        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");
+            }
+        }
+
+        if ($this->processors) {
+            foreach ($this->processors as $processor) {
+                $record = call_user_func($processor, $record);
+            }
+        }
+
+        $this->handler->handle($record);
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function handleBatch(array $records)
+    {
+        $filtered = array();
+        foreach ($records as $record) {
+            if ($this->isHandling($record)) {
+                $filtered[] = $record;
+            }
+        }
+
+        $this->handler->handleBatch($filtered);
+    }
+}

+ 28 - 0
SE/se-lib/Vendor/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 Boolean
+     */
+    public function isHandlerActivated(array $record);
+}

+ 59 - 0
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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;
+    }
+}

+ 163 - 0
SE/se-lib/Vendor/Monolog/Handler/FingersCrossedHandler.php

@@ -0,0 +1,163 @@
+<?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;
+
+/**
+ * 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, $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 Boolean                         $bubble             Whether the messages that are handled can bubble up the stack or not
+     * @param Boolean                         $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;
+        }
+        if (!$this->handler instanceof HandlerInterface) {
+            $record = end($this->buffer) ?: null;
+
+            $this->handler = call_user_func($this->handler, $record, $this);
+            if (!$this->handler instanceof HandlerInterface) {
+                throw new \RuntimeException("The factory callable should return a HandlerInterface");
+            }
+        }
+        $this->handler->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->handler->handle($record);
+        }
+
+        return false === $this->bubble;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        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->handler->handleBatch($this->buffer);
+                $this->buffer = array();
+            }
+        }
+    }
+
+    /**
+     * Resets the state of the handler. Stops forwarding records to the wrapped handler.
+     */
+    public function reset()
+    {
+        $this->buffering = true;
+    }
+
+    /**
+     * 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();
+    }
+}

+ 195 - 0
SE/se-lib/Vendor/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 string
+     */
+    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 Boolean
+     */
+    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
SE/se-lib/Vendor/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);
+    }
+}

+ 127 - 0
SE/se-lib/Vendor/Monolog/Handler/FlowdockHandler.php

@@ -0,0 +1,127 @@
+<?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\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 json_encode($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;
+    }
+}

+ 73 - 0
SE/se-lib/Vendor/Monolog/Handler/GelfHandler.php

@@ -0,0 +1,73 @@
+<?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 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}
+     */
+    public function close()
+    {
+        $this->publisher = null;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $this->publisher->publish($record['formatted']);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new GelfMessageFormatter();
+    }
+}

+ 104 - 0
SE/se-lib/Vendor/Monolog/Handler/GroupHandler.php

@@ -0,0 +1,104 @@
+<?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;
+
+/**
+ * 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 Boolean $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) {
+                    $processed[] = call_user_func($processor, $record);
+                }
+            }
+            $records = $processed;
+        }
+
+        foreach ($this->handlers as $handler) {
+            $handler->handleBatch($records);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFormatter(FormatterInterface $formatter)
+    {
+        foreach ($this->handlers as $handler) {
+            $handler->setFormatter($formatter);
+        }
+
+        return $this;
+    }
+}

+ 90 - 0
SE/se-lib/Vendor/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 Boolean
+     */
+    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 Boolean 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();
+}

+ 108 - 0
SE/se-lib/Vendor/Monolog/Handler/HandlerWrapper.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 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
+{
+    /**
+     * @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();
+    }
+}

+ 350 - 0
SE/se-lib/Vendor/Monolog/Handler/HipChatHandler.php

@@ -0,0 +1,350 @@
+<?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)
+    {
+        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->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 $records
+     * @return array
+     */
+    private function combineRecords($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);
+    }
+}

+ 69 - 0
SE/se-lib/Vendor/Monolog/Handler/IFTTTHandler.php

@@ -0,0 +1,69 @@
+<?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;
+
+/**
+ * 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 Boolean $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 = json_encode($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);
+    }
+}

+ 55 - 0
SE/se-lib/Vendor/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)
+    {
+        if ($useSSL && !extension_loaded('openssl')) {
+            throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler');
+        }
+
+        $endpoint = $useSSL ? 'ssl://data.logentries.com:443' : 'data.logentries.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'];
+    }
+}

+ 102 - 0
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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 Boolean                 $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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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;
+    }
+}

+ 202 - 0
SE/se-lib/Vendor/Monolog/Handler/NewRelicHandler.php

@@ -0,0 +1,202 @@
+<?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;
+
+/**
+ * Class to record a log on a NewRelic application.
+ * Enabling New Relic High Security mode may prevent capture of useful information.
+ *
+ * @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) {
+            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, @json_encode($value));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter()
+    {
+        return new NormalizerFormatter();
+    }
+}

+ 45 - 0
SE/se-lib/Vendor/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;
+    }
+}

+ 242 - 0
SE/se-lib/Vendor/Monolog/Handler/PHPConsoleHandler.php

@@ -0,0 +1,242 @@
+<?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 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 .= ' ' . json_encode($this->connector->getDumper()->dump(array_filter($record['context'])));
+        }
+        $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%');
+    }
+}

+ 56 - 0
SE/se-lib/Vendor/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 Boolean         $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
SE/se-lib/Vendor/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 Boolean      $bubble            Whether the messages that are handled can bubble up the stack or not
+     * @param Boolean      $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 = (boolean) $value;
+    }
+}

+ 232 - 0
SE/se-lib/Vendor/Monolog/Handler/RavenHandler.php

@@ -0,0 +1,232 @@
+<?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 raven-php (https://github.com/getsentry/raven-php)
+ *
+ * @author Marc Abramowitz <marc@marc-abramowitz.com>
+ */
+class RavenHandler extends AbstractProcessingHandler
+{
+    /**
+     * Translates Monolog log levels to Raven log levels.
+     */
+    private $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)
+     */
+    private $release;
+
+    /**
+     * @var Raven_Client the client object that sends the message to the server
+     */
+    protected $ravenClient;
+
+    /**
+     * @var LineFormatter 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 Boolean      $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)
+    {
+        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 ($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['extra']['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('checksum', 'release', 'event_id');
+    }
+
+    /**
+     * @param string $value
+     * @return self
+     */
+    public function setRelease($value)
+    {
+        $this->release = $value;
+
+        return $this;
+    }
+}

+ 97 - 0
SE/se-lib/Vendor/Monolog/Handler/RedisHandler.php

@@ -0,0 +1,97 @@
+<?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                   $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) {
+            $this->redisClient->multi()
+                ->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();
+    }
+}

+ 132 - 0
SE/se-lib/Vendor/Monolog/Handler/RollbarHandler.php

@@ -0,0 +1,132 @@
+<?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();
+    }
+}

+ 178 - 0
SE/se-lib/Vendor/Monolog/Handler/RotatingFileHandler.php

@@ -0,0 +1,178 @@
+<?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 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 Boolean  $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 Boolean  $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 = $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();
+        }
+    }
+
+    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'], '*'),
+            $fileInfo['dirname'] . '/' . $this->filenameFormat
+        );
+        if (!empty($fileInfo['extension'])) {
+            $glob .= '.'.$fileInfo['extension'];
+        }
+
+        return $glob;
+    }
+}

+ 82 - 0
SE/se-lib/Vendor/Monolog/Handler/SamplingHandler.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;
+
+/**
+ * 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, $fingersCrossedHandler).
+     * @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->handler->isHandling($record);
+    }
+
+    public function handle(array $record)
+    {
+        if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
+            // The same logic as in FingersCrossedHandler
+            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");
+                }
+            }
+
+            if ($this->processors) {
+                foreach ($this->processors as $processor) {
+                    $record = call_user_func($processor, $record);
+                }
+            }
+
+            $this->handler->handle($record);
+        }
+
+        return false === $this->bubble;
+    }
+}

+ 294 - 0
SE/se-lib/Vendor/Monolog/Handler/Slack/SlackRecord.php

@@ -0,0 +1,294 @@
+<?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\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(
+                            ucfirst($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;
+
+        $hasSecondDimension = count(array_filter($normalized, 'is_array'));
+        $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric'));
+
+        return $hasSecondDimension || $hasNonNumericKeys
+            ? json_encode($normalized, $prettyPrintFlag)
+            : json_encode($normalized);
+    }
+
+    /**
+     * 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' => $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 ($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;
+    }
+}

+ 215 - 0
SE/se-lib/Vendor/Monolog/Handler/SlackHandler.php

@@ -0,0 +1,215 @@
+<?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\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;
+    }
+
+    /**
+     * {@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'] = json_encode($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;
+    }
+}

+ 115 - 0
SE/se-lib/Vendor/Monolog/Handler/SlackWebhookHandler.php

@@ -0,0 +1,115 @@
+<?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\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;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @param array $record
+     */
+    protected function write(array $record)
+    {
+        $postData = $this->slackRecord->getSlackData($record);
+        $postString = json_encode($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;
+    }
+}

+ 80 - 0
SE/se-lib/Vendor/Monolog/Handler/SlackbotHandler.php

@@ -0,0 +1,80 @@
+<?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
+ */
+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)
+    {
+        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);
+    }
+}

+ 346 - 0
SE/se-lib/Vendor/Monolog/Handler/SocketHandler.php

@@ -0,0 +1,346 @@
+<?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 $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 Boolean $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 = (boolean) $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;
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * 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
+     */
+    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();
+    }
+
+    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 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;
+    }
+}

+ 176 - 0
SE/se-lib/Vendor/Monolog/Handler/StreamHandler.php

@@ -0,0 +1,176 @@
+<?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 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 Boolean         $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 Boolean         $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 = $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;
+    }
+
+    /**
+     * 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: '.$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;
+    }
+
+    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) {
+                throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir));
+            }
+        }
+        $this->dirCreated = true;
+    }
+}

+ 99 - 0
SE/se-lib/Vendor/Monolog/Handler/SwiftMailerHandler.php

@@ -0,0 +1,99 @@
+<?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;
+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 Boolean                 $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));
+    }
+
+    /**
+     * 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 = new LineFormatter($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
SE/se-lib/Vendor/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 Boolean $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
SE/se-lib/Vendor/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);
+    }
+}

+ 103 - 0
SE/se-lib/Vendor/Monolog/Handler/SyslogUdpHandler.php

@@ -0,0 +1,103 @@
+<?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>
+ */
+class SyslogUdpHandler extends AbstractSyslogHandler
+{
+    protected $socket;
+    protected $ident;
+
+    /**
+     * @param string  $host
+     * @param int     $port
+     * @param mixed   $facility
+     * @param int     $level    The minimum logging level at which this handler will be triggered
+     * @param Boolean $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.
+     */
+    public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php')
+    {
+        parent::__construct($facility, $level, $bubble);
+
+        $this->ident = $ident;
+
+        $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)
+     */
+    protected function makeCommonSyslogHeader($severity)
+    {
+        $priority = $severity + $this->facility;
+
+        if (!$pid = getmypid()) {
+            $pid = '-';
+        }
+
+        if (!$hostname = gethostname()) {
+            $hostname = '-';
+        }
+
+        return "<$priority>1 " .
+            $this->getDateTime() . " " .
+            $hostname . " " .
+            $this->ident . " " .
+            $pid . " - - ";
+    }
+
+    protected function getDateTime()
+    {
+        return date(\DateTime::RFC3339);
+    }
+
+    /**
+     * Inject your own socket, mainly used for testing
+     */
+    public function setSocket($socket)
+    {
+        $this->socket = $socket;
+    }
+}

+ 154 - 0
SE/se-lib/Vendor/Monolog/Handler/TestHandler.php

@@ -0,0 +1,154 @@
+<?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;
+
+/**
+ * Used for testing purposes.
+ *
+ * It records all records and gives you access to them for verification.
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @method bool hasEmergency($record)
+ * @method bool hasAlert($record)
+ * @method bool hasCritical($record)
+ * @method bool hasError($record)
+ * @method bool hasWarning($record)
+ * @method bool hasNotice($record)
+ * @method bool hasInfo($record)
+ * @method bool hasDebug($record)
+ *
+ * @method bool hasEmergencyRecords()
+ * @method bool hasAlertRecords()
+ * @method bool hasCriticalRecords()
+ * @method bool hasErrorRecords()
+ * @method bool hasWarningRecords()
+ * @method bool hasNoticeRecords()
+ * @method bool hasInfoRecords()
+ * @method bool hasDebugRecords()
+ *
+ * @method bool hasEmergencyThatContains($message)
+ * @method bool hasAlertThatContains($message)
+ * @method bool hasCriticalThatContains($message)
+ * @method bool hasErrorThatContains($message)
+ * @method bool hasWarningThatContains($message)
+ * @method bool hasNoticeThatContains($message)
+ * @method bool hasInfoThatContains($message)
+ * @method bool hasDebugThatContains($message)
+ *
+ * @method bool hasEmergencyThatMatches($message)
+ * @method bool hasAlertThatMatches($message)
+ * @method bool hasCriticalThatMatches($message)
+ * @method bool hasErrorThatMatches($message)
+ * @method bool hasWarningThatMatches($message)
+ * @method bool hasNoticeThatMatches($message)
+ * @method bool hasInfoThatMatches($message)
+ * @method bool hasDebugThatMatches($message)
+ *
+ * @method bool hasEmergencyThatPasses($message)
+ * @method bool hasAlertThatPasses($message)
+ * @method bool hasCriticalThatPasses($message)
+ * @method bool hasErrorThatPasses($message)
+ * @method bool hasWarningThatPasses($message)
+ * @method bool hasNoticeThatPasses($message)
+ * @method bool hasInfoThatPasses($message)
+ * @method bool hasDebugThatPasses($message)
+ */
+class TestHandler extends AbstractProcessingHandler
+{
+    protected $records = array();
+    protected $recordsByLevel = array();
+
+    public function getRecords()
+    {
+        return $this->records;
+    }
+
+    public function clear()
+    {
+        $this->records = array();
+        $this->recordsByLevel = array();
+    }
+
+    public function hasRecords($level)
+    {
+        return isset($this->recordsByLevel[$level]);
+    }
+
+    public function hasRecord($record, $level)
+    {
+        if (is_array($record)) {
+            $record = $record['message'];
+        }
+
+        return $this->hasRecordThatPasses(function ($rec) use ($record) {
+            return $rec['message'] === $record;
+        }, $level);
+    }
+
+    public function hasRecordThatContains($message, $level)
+    {
+        return $this->hasRecordThatPasses(function ($rec) use ($message) {
+            return strpos($rec['message'], $message) !== false;
+        }, $level);
+    }
+
+    public function hasRecordThatMatches($regex, $level)
+    {
+        return $this->hasRecordThatPasses(function ($rec) use ($regex) {
+            return preg_match($regex, $rec['message']) > 0;
+        }, $level);
+    }
+
+    public function hasRecordThatPasses($predicate, $level)
+    {
+        if (!is_callable($predicate)) {
+            throw new \InvalidArgumentException("Expected a callable for hasRecordThatSucceeds");
+        }
+
+        if (!isset($this->recordsByLevel[$level])) {
+            return false;
+        }
+
+        foreach ($this->recordsByLevel[$level] as $i => $rec) {
+            if (call_user_func($predicate, $rec, $i)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $this->recordsByLevel[$record['level']][] = $record;
+        $this->records[] = $record;
+    }
+
+    public function __call($method, $args)
+    {
+        if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
+            $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
+            $level = constant('Monolog\Logger::' . strtoupper($matches[2]));
+            if (method_exists($this, $genericMethod)) {
+                $args[] = $level;
+
+                return call_user_func_array(array($this, $genericMethod), $args);
+            }
+        }
+
+        throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
+    }
+}

+ 61 - 0
SE/se-lib/Vendor/Monolog/Handler/WhatFailureGroupHandler.php

@@ -0,0 +1,61 @@
+<?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)
+    {
+        foreach ($this->handlers as $handler) {
+            try {
+                $handler->handleBatch($records);
+            } catch (\Exception $e) {
+                // What failure?
+            } catch (\Throwable $e) {
+                // What failure?
+            }
+        }
+    }
+}

+ 95 - 0
SE/se-lib/Vendor/Monolog/Handler/ZendMonitorHandler.php

@@ -0,0 +1,95 @@
+<?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>
+ */
+class ZendMonitorHandler extends AbstractProcessingHandler
+{
+    /**
+     * Monolog level / ZendMonitor Custom Event priority map
+     *
+     * @var array
+     */
+    protected $levelMap = array(
+        Logger::DEBUG     => 1,
+        Logger::INFO      => 2,
+        Logger::NOTICE    => 3,
+        Logger::WARNING   => 4,
+        Logger::ERROR     => 5,
+        Logger::CRITICAL  => 6,
+        Logger::ALERT     => 7,
+        Logger::EMERGENCY => 0,
+    );
+
+    /**
+     * 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 in order to use this handler');
+        }
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function write(array $record)
+    {
+        $this->writeZendMonitorCustomEvent(
+            $this->levelMap[$record['level']],
+            $record['message'],
+            $record['formatted']
+        );
+    }
+
+    /**
+     * Write a record to Zend Monitor
+     *
+     * @param int    $level
+     * @param string $message
+     * @param array  $formatted
+     */
+    protected function writeZendMonitorCustomEvent($level, $message, $formatted)
+    {
+        zend_monitor_custom_event($level, $message, $formatted);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDefaultFormatter()
+    {
+        return new NormalizerFormatter();
+    }
+
+    /**
+     * Get the level map
+     *
+     * @return array
+     */
+    public function getLevelMap()
+    {
+        return $this->levelMap;
+    }
+}

+ 700 - 0
SE/se-lib/Vendor/Monolog/Logger.php

@@ -0,0 +1,700 @@
+<?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;
+
+/**
+ * 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
+{
+    /**
+     * 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;
+
+    /**
+     * @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->handlers = $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 Boolean 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(null, 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(),
+        );
+
+        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);
+        }
+
+        return true;
+    }
+
+    /**
+     * Adds a log record at the DEBUG level.
+     *
+     * @param  string  $message The log message
+     * @param  array   $context The log context
+     * @return Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 number (monolog) or name (PSR-3)
+     * @return int
+     */
+    public static function toMonologLevel($level)
+    {
+        if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) {
+            return constant(__CLASS__.'::'.strtoupper($level));
+        }
+
+        return $level;
+    }
+
+    /**
+     * Checks whether the Logger has a handler that listens on the given level
+     *
+     * @param  int     $level
+     * @return Boolean
+     */
+    public function isHandling($level)
+    {
+        $record = array(
+            'level' => $level,
+        );
+
+        foreach ($this->handlers as $handler) {
+            if ($handler->isHandling($record)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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 Boolean 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
SE/se-lib/Vendor/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
+{
+    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 (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
SE/se-lib/Vendor/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
+{
+    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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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
+{
+    /**
+     * @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 = (boolean) $realUsage;
+        $this->useFormatting = (boolean) $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
SE/se-lib/Vendor/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
SE/se-lib/Vendor/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
+{
+    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
SE/se-lib/Vendor/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
+{
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        $record['extra']['process_id'] = getmypid();
+
+        return $record;
+    }
+}

+ 48 - 0
SE/se-lib/Vendor/Monolog/Processor/PsrLogMessageProcessor.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\Processor;
+
+/**
+ * Processes a record's message according to PSR-3 rules
+ *
+ * It replaces {foo} with the value from $context['foo']
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class PsrLogMessageProcessor
+{
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        if (false === strpos($record['message'], '{')) {
+            return $record;
+        }
+
+        $replacements = array();
+        foreach ($record['context'] as $key => $val) {
+            if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
+                $replacements['{'.$key.'}'] = $val;
+            } elseif (is_object($val)) {
+                $replacements['{'.$key.'}'] = '[object '.get_class($val).']';
+            } else {
+                $replacements['{'.$key.'}'] = '['.gettype($val).']';
+            }
+        }
+
+        $record['message'] = strtr($record['message'], $replacements);
+
+        return $record;
+    }
+}

+ 44 - 0
SE/se-lib/Vendor/Monolog/Processor/TagProcessor.php

@@ -0,0 +1,44 @@
+<?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 a tags array into record
+ *
+ * @author Martijn Riemers
+ */
+class TagProcessor
+{
+    private $tags;
+
+    public function __construct(array $tags = array())
+    {
+        $this->setTags($tags);
+    }
+
+    public function addTags(array $tags = array())
+    {
+        $this->tags = array_merge($this->tags, $tags);
+    }
+
+    public function setTags(array $tags = array())
+    {
+        $this->tags = $tags;
+    }
+
+    public function __invoke(array $record)
+    {
+        $record['extra']['tags'] = $this->tags;
+
+        return $record;
+    }
+}

+ 46 - 0
SE/se-lib/Vendor/Monolog/Processor/UidProcessor.php

@@ -0,0 +1,46 @@
+<?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 a unique identifier into records
+ *
+ * @author Simon Mönch <sm@webfactory.de>
+ */
+class UidProcessor
+{
+    private $uid;
+
+    public function __construct($length = 7)
+    {
+        if (!is_int($length) || $length > 32 || $length < 1) {
+            throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32');
+        }
+
+        $this->uid = substr(hash('md5', uniqid('', true)), 0, $length);
+    }
+
+    public function __invoke(array $record)
+    {
+        $record['extra']['uid'] = $this->uid;
+
+        return $record;
+    }
+
+    /**
+     * @return string
+     */
+    public function getUid()
+    {
+        return $this->uid;
+    }
+}

+ 113 - 0
SE/se-lib/Vendor/Monolog/Processor/WebProcessor.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\Processor;
+
+/**
+ * Injects url/method and remote IP of the current web request in all records
+ *
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class WebProcessor
+{
+    /**
+     * @var array|\ArrayAccess
+     */
+    protected $serverData;
+
+    /**
+     * Default fields
+     *
+     * Array is structured as [key in record.extra => key in $serverData]
+     *
+     * @var array
+     */
+    protected $extraFields = array(
+        'url'         => 'REQUEST_URI',
+        'ip'          => 'REMOTE_ADDR',
+        'http_method' => 'REQUEST_METHOD',
+        'server'      => 'SERVER_NAME',
+        'referrer'    => 'HTTP_REFERER',
+    );
+
+    /**
+     * @param array|\ArrayAccess $serverData  Array or object w/ ArrayAccess that provides access to the $_SERVER data
+     * @param array|null         $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer
+     */
+    public function __construct($serverData = null, array $extraFields = null)
+    {
+        if (null === $serverData) {
+            $this->serverData = &$_SERVER;
+        } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) {
+            $this->serverData = $serverData;
+        } else {
+            throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.');
+        }
+
+        if (null !== $extraFields) {
+            if (isset($extraFields[0])) {
+                foreach (array_keys($this->extraFields) as $fieldName) {
+                    if (!in_array($fieldName, $extraFields)) {
+                        unset($this->extraFields[$fieldName]);
+                    }
+                }
+            } else {
+                $this->extraFields = $extraFields;
+            }
+        }
+    }
+
+    /**
+     * @param  array $record
+     * @return array
+     */
+    public function __invoke(array $record)
+    {
+        // skip processing if for some reason request data
+        // is not present (CLI or wonky SAPIs)
+        if (!isset($this->serverData['REQUEST_URI'])) {
+            return $record;
+        }
+
+        $record['extra'] = $this->appendExtraFields($record['extra']);
+
+        return $record;
+    }
+
+    /**
+     * @param  string $extraName
+     * @param  string $serverName
+     * @return $this
+     */
+    public function addExtraField($extraName, $serverName)
+    {
+        $this->extraFields[$extraName] = $serverName;
+
+        return $this;
+    }
+
+    /**
+     * @param  array $extra
+     * @return array
+     */
+    private function appendExtraFields(array $extra)
+    {
+        foreach ($this->extraFields as $extraName => $serverName) {
+            $extra[$extraName] = isset($this->serverData[$serverName]) ? $this->serverData[$serverName] : null;
+        }
+
+        if (isset($this->serverData['UNIQUE_ID'])) {
+            $extra['unique_id'] = $this->serverData['UNIQUE_ID'];
+        }
+
+        return $extra;
+    }
+}

+ 134 - 0
SE/se-lib/Vendor/Monolog/Registry.php

@@ -0,0 +1,134 @@
+<?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 InvalidArgumentException;
+
+/**
+ * Monolog log registry
+ *
+ * Allows to get `Logger` instances in the global scope
+ * via static method calls on this class.
+ *
+ * <code>
+ * $application = new Monolog\Logger('application');
+ * $api = new Monolog\Logger('api');
+ *
+ * Monolog\Registry::addLogger($application);
+ * Monolog\Registry::addLogger($api);
+ *
+ * function testLogger()
+ * {
+ *     Monolog\Registry::api()->addError('Sent to $api Logger instance');
+ *     Monolog\Registry::application()->addError('Sent to $application Logger instance');
+ * }
+ * </code>
+ *
+ * @author Tomas Tatarko <tomas@tatarko.sk>
+ */
+class Registry
+{
+    /**
+     * List of all loggers in the registry (by named indexes)
+     *
+     * @var Logger[]
+     */
+    private static $loggers = array();
+
+    /**
+     * Adds new logging channel to the registry
+     *
+     * @param  Logger                    $logger    Instance of the logging channel
+     * @param  string|null               $name      Name of the logging channel ($logger->getName() by default)
+     * @param  bool                      $overwrite Overwrite instance in the registry if the given name already exists?
+     * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists
+     */
+    public static function addLogger(Logger $logger, $name = null, $overwrite = false)
+    {
+        $name = $name ?: $logger->getName();
+
+        if (isset(self::$loggers[$name]) && !$overwrite) {
+            throw new InvalidArgumentException('Logger with the given name already exists');
+        }
+
+        self::$loggers[$name] = $logger;
+    }
+
+    /**
+     * Checks if such logging channel exists by name or instance
+     *
+     * @param string|Logger $logger Name or logger instance
+     */
+    public static function hasLogger($logger)
+    {
+        if ($logger instanceof Logger) {
+            $index = array_search($logger, self::$loggers, true);
+
+            return false !== $index;
+        } else {
+            return isset(self::$loggers[$logger]);
+        }
+    }
+
+    /**
+     * Removes instance from registry by name or instance
+     *
+     * @param string|Logger $logger Name or logger instance
+     */
+    public static function removeLogger($logger)
+    {
+        if ($logger instanceof Logger) {
+            if (false !== ($idx = array_search($logger, self::$loggers, true))) {
+                unset(self::$loggers[$idx]);
+            }
+        } else {
+            unset(self::$loggers[$logger]);
+        }
+    }
+
+    /**
+     * Clears the registry
+     */
+    public static function clear()
+    {
+        self::$loggers = array();
+    }
+
+    /**
+     * Gets Logger instance from the registry
+     *
+     * @param  string                    $name Name of the requested Logger instance
+     * @throws \InvalidArgumentException If named Logger instance is not in the registry
+     * @return Logger                    Requested instance of Logger
+     */
+    public static function getInstance($name)
+    {
+        if (!isset(self::$loggers[$name])) {
+            throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name));
+        }
+
+        return self::$loggers[$name];
+    }
+
+    /**
+     * Gets Logger instance from the registry via static method call
+     *
+     * @param  string                    $name      Name of the requested Logger instance
+     * @param  array                     $arguments Arguments passed to static method call
+     * @throws \InvalidArgumentException If named Logger instance is not in the registry
+     * @return Logger                    Requested instance of Logger
+     */
+    public static function __callStatic($name, $arguments)
+    {
+        return self::getInstance($name);
+    }
+}

+ 128 - 0
SE/se-lib/Vendor/Psr/AbstractLogger.php

@@ -0,0 +1,128 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * This is a simple Logger implementation that other Loggers can inherit from.
+ *
+ * It simply delegates all log-level-specific methods to the `log` method to
+ * reduce boilerplate code that a simple Logger that does the same thing with
+ * messages regardless of the error level has to implement.
+ */
+abstract class AbstractLogger implements LoggerInterface
+{
+    /**
+     * System is unusable.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function emergency($message, array $context = array())
+    {
+        $this->log(LogLevel::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * Action must be taken immediately.
+     *
+     * Example: Entire website down, database unavailable, etc. This should
+     * trigger the SMS alerts and wake you up.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function alert($message, array $context = array())
+    {
+        $this->log(LogLevel::ALERT, $message, $context);
+    }
+
+    /**
+     * Critical conditions.
+     *
+     * Example: Application component unavailable, unexpected exception.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function critical($message, array $context = array())
+    {
+        $this->log(LogLevel::CRITICAL, $message, $context);
+    }
+
+    /**
+     * Runtime errors that do not require immediate action but should typically
+     * be logged and monitored.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function error($message, array $context = array())
+    {
+        $this->log(LogLevel::ERROR, $message, $context);
+    }
+
+    /**
+     * Exceptional occurrences that are not errors.
+     *
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
+     * that are not necessarily wrong.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function warning($message, array $context = array())
+    {
+        $this->log(LogLevel::WARNING, $message, $context);
+    }
+
+    /**
+     * Normal but significant events.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function notice($message, array $context = array())
+    {
+        $this->log(LogLevel::NOTICE, $message, $context);
+    }
+
+    /**
+     * Interesting events.
+     *
+     * Example: User logs in, SQL logs.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function info($message, array $context = array())
+    {
+        $this->log(LogLevel::INFO, $message, $context);
+    }
+
+    /**
+     * Detailed debug information.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function debug($message, array $context = array())
+    {
+        $this->log(LogLevel::DEBUG, $message, $context);
+    }
+}

+ 7 - 0
SE/se-lib/Vendor/Psr/InvalidArgumentException.php

@@ -0,0 +1,7 @@
+<?php
+
+namespace Psr\Log;
+
+class InvalidArgumentException extends \InvalidArgumentException
+{
+}

+ 18 - 0
SE/se-lib/Vendor/Psr/LogLevel.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Describes log levels.
+ */
+class LogLevel
+{
+    const EMERGENCY = 'emergency';
+    const ALERT     = 'alert';
+    const CRITICAL  = 'critical';
+    const ERROR     = 'error';
+    const WARNING   = 'warning';
+    const NOTICE    = 'notice';
+    const INFO      = 'info';
+    const DEBUG     = 'debug';
+}

+ 18 - 0
SE/se-lib/Vendor/Psr/LoggerAwareInterface.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Describes a logger-aware instance.
+ */
+interface LoggerAwareInterface
+{
+    /**
+     * Sets a logger instance on the object.
+     *
+     * @param LoggerInterface $logger
+     *
+     * @return void
+     */
+    public function setLogger(LoggerInterface $logger);
+}

+ 26 - 0
SE/se-lib/Vendor/Psr/LoggerAwareTrait.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Basic Implementation of LoggerAwareInterface.
+ */
+trait LoggerAwareTrait
+{
+    /**
+     * The logger instance.
+     *
+     * @var LoggerInterface
+     */
+    protected $logger;
+
+    /**
+     * Sets a logger.
+     *
+     * @param LoggerInterface $logger
+     */
+    public function setLogger(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
+    }
+}

+ 123 - 0
SE/se-lib/Vendor/Psr/LoggerInterface.php

@@ -0,0 +1,123 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * Describes a logger instance.
+ *
+ * The message MUST be a string or object implementing __toString().
+ *
+ * The message MAY contain placeholders in the form: {foo} where foo
+ * will be replaced by the context data in key "foo".
+ *
+ * The context array can contain arbitrary data. The only assumption that
+ * can be made by implementors is that if an Exception instance is given
+ * to produce a stack trace, it MUST be in a key named "exception".
+ *
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
+ * for the full interface specification.
+ */
+interface LoggerInterface
+{
+    /**
+     * System is unusable.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function emergency($message, array $context = array());
+
+    /**
+     * Action must be taken immediately.
+     *
+     * Example: Entire website down, database unavailable, etc. This should
+     * trigger the SMS alerts and wake you up.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function alert($message, array $context = array());
+
+    /**
+     * Critical conditions.
+     *
+     * Example: Application component unavailable, unexpected exception.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function critical($message, array $context = array());
+
+    /**
+     * Runtime errors that do not require immediate action but should typically
+     * be logged and monitored.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function error($message, array $context = array());
+
+    /**
+     * Exceptional occurrences that are not errors.
+     *
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
+     * that are not necessarily wrong.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function warning($message, array $context = array());
+
+    /**
+     * Normal but significant events.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function notice($message, array $context = array());
+
+    /**
+     * Interesting events.
+     *
+     * Example: User logs in, SQL logs.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function info($message, array $context = array());
+
+    /**
+     * Detailed debug information.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function debug($message, array $context = array());
+
+    /**
+     * Logs with an arbitrary level.
+     *
+     * @param mixed  $level
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function log($level, $message, array $context = array());
+}

+ 140 - 0
SE/se-lib/Vendor/Psr/LoggerTrait.php

@@ -0,0 +1,140 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * This is a simple Logger trait that classes unable to extend AbstractLogger
+ * (because they extend another class, etc) can include.
+ *
+ * It simply delegates all log-level-specific methods to the `log` method to
+ * reduce boilerplate code that a simple Logger that does the same thing with
+ * messages regardless of the error level has to implement.
+ */
+trait LoggerTrait
+{
+    /**
+     * System is unusable.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function emergency($message, array $context = array())
+    {
+        $this->log(LogLevel::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * Action must be taken immediately.
+     *
+     * Example: Entire website down, database unavailable, etc. This should
+     * trigger the SMS alerts and wake you up.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function alert($message, array $context = array())
+    {
+        $this->log(LogLevel::ALERT, $message, $context);
+    }
+
+    /**
+     * Critical conditions.
+     *
+     * Example: Application component unavailable, unexpected exception.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function critical($message, array $context = array())
+    {
+        $this->log(LogLevel::CRITICAL, $message, $context);
+    }
+
+    /**
+     * Runtime errors that do not require immediate action but should typically
+     * be logged and monitored.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function error($message, array $context = array())
+    {
+        $this->log(LogLevel::ERROR, $message, $context);
+    }
+
+    /**
+     * Exceptional occurrences that are not errors.
+     *
+     * Example: Use of deprecated APIs, poor use of an API, undesirable things
+     * that are not necessarily wrong.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function warning($message, array $context = array())
+    {
+        $this->log(LogLevel::WARNING, $message, $context);
+    }
+
+    /**
+     * Normal but significant events.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function notice($message, array $context = array())
+    {
+        $this->log(LogLevel::NOTICE, $message, $context);
+    }
+
+    /**
+     * Interesting events.
+     *
+     * Example: User logs in, SQL logs.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function info($message, array $context = array())
+    {
+        $this->log(LogLevel::INFO, $message, $context);
+    }
+
+    /**
+     * Detailed debug information.
+     *
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function debug($message, array $context = array())
+    {
+        $this->log(LogLevel::DEBUG, $message, $context);
+    }
+
+    /**
+     * Logs with an arbitrary level.
+     *
+     * @param mixed  $level
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    abstract public function log($level, $message, array $context = array());
+}

+ 28 - 0
SE/se-lib/Vendor/Psr/NullLogger.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace Psr\Log;
+
+/**
+ * This Logger can be used to avoid conditional log calls.
+ *
+ * Logging should always be optional, and if no logger is provided to your
+ * library creating a NullLogger instance to have something to throw logs at
+ * is a good way to avoid littering your code with `if ($this->logger) { }`
+ * blocks.
+ */
+class NullLogger extends AbstractLogger
+{
+    /**
+     * Logs with an arbitrary level.
+     *
+     * @param mixed  $level
+     * @param string $message
+     * @param array  $context
+     *
+     * @return void
+     */
+    public function log($level, $message, array $context = array())
+    {
+        // noop
+    }
+}

+ 140 - 0
SE/se-lib/Vendor/Psr/Test/LoggerInterfaceTest.php

@@ -0,0 +1,140 @@
+<?php
+
+namespace Psr\Log\Test;
+
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+/**
+ * Provides a base test class for ensuring compliance with the LoggerInterface.
+ *
+ * Implementors can extend the class and implement abstract methods to run this
+ * as part of their test suite.
+ */
+abstract class LoggerInterfaceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @return LoggerInterface
+     */
+    abstract public function getLogger();
+
+    /**
+     * This must return the log messages in order.
+     *
+     * The simple formatting of the messages is: "<LOG LEVEL> <MESSAGE>".
+     *
+     * Example ->error('Foo') would yield "error Foo".
+     *
+     * @return string[]
+     */
+    abstract public function getLogs();
+
+    public function testImplements()
+    {
+        $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
+    }
+
+    /**
+     * @dataProvider provideLevelsAndMessages
+     */
+    public function testLogsAtAllLevels($level, $message)
+    {
+        $logger = $this->getLogger();
+        $logger->{$level}($message, array('user' => 'Bob'));
+        $logger->log($level, $message, array('user' => 'Bob'));
+
+        $expected = array(
+            $level.' message of level '.$level.' with context: Bob',
+            $level.' message of level '.$level.' with context: Bob',
+        );
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function provideLevelsAndMessages()
+    {
+        return array(
+            LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
+            LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
+            LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
+            LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
+            LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
+            LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
+            LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
+            LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
+        );
+    }
+
+    /**
+     * @expectedException \Psr\Log\InvalidArgumentException
+     */
+    public function testThrowsOnInvalidLevel()
+    {
+        $logger = $this->getLogger();
+        $logger->log('invalid level', 'Foo');
+    }
+
+    public function testContextReplacement()
+    {
+        $logger = $this->getLogger();
+        $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
+
+        $expected = array('info {Message {nothing} Bob Bar a}');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testObjectCastToString()
+    {
+        if (method_exists($this, 'createPartialMock')) {
+            $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString'));
+        } else {
+            $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
+        }
+        $dummy->expects($this->once())
+            ->method('__toString')
+            ->will($this->returnValue('DUMMY'));
+
+        $this->getLogger()->warning($dummy);
+
+        $expected = array('warning DUMMY');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testContextCanContainAnything()
+    {
+        $context = array(
+            'bool' => true,
+            'null' => null,
+            'string' => 'Foo',
+            'int' => 0,
+            'float' => 0.5,
+            'nested' => array('with object' => new DummyTest),
+            'object' => new \DateTime,
+            'resource' => fopen('php://memory', 'r'),
+        );
+
+        $this->getLogger()->warning('Crazy context data', $context);
+
+        $expected = array('warning Crazy context data');
+        $this->assertEquals($expected, $this->getLogs());
+    }
+
+    public function testContextExceptionKeyCanBeExceptionOrOtherValues()
+    {
+        $logger = $this->getLogger();
+        $logger->warning('Random message', array('exception' => 'oops'));
+        $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
+
+        $expected = array(
+            'warning Random message',
+            'critical Uncaught Exception!'
+        );
+        $this->assertEquals($expected, $this->getLogs());
+    }
+}
+
+class DummyTest
+{
+    public function __toString()
+    {
+    }
+}