code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

/**
 * Red BlueScreen.
 */
class BlueScreen
{
	/** @var string[] */
	public $info = array();

	/** @var callable[] */
	private $panels = array();

	/** @var string[] paths to be collapsed in stack trace (e.g. core libraries) */
	public $collapsePaths = array();

	public function __construct()
	{
		$this->collapsePaths[] = preg_match('#(.+/vendor)/tracy/tracy/src/Tracy$#', strtr(__DIR__, '\\', '/'), $m)
			? $m[1]
			: __DIR__;
	}

	/**
	 * Add custom panel.
	 * @param  callable
	 * @return self
	 */
	public function addPanel($panel)
	{
		if (!in_array($panel, $this->panels, TRUE)) {
			$this->panels[] = $panel;
		}
		return $this;
	}

	/**
	 * Renders blue screen.
	 * @param  \Exception|\Throwable
	 * @return void
	 */
	public function render($exception)
	{
		$panels = $this->panels;
		$info = array_filter($this->info);
		$source = Helpers::getSource();
		$sourceIsUrl = preg_match('#^https?://#', $source);
		$title = $exception instanceof \ErrorException
			? Helpers::errorTypeToString($exception->getSeverity())
			: Helpers::getClass($exception);
		$skipError = $sourceIsUrl && $exception instanceof \ErrorException && !empty($exception->skippable)
			? $source . (strpos($source, '?') ? '&' : '?') . '_tracy_skip_error'
			: NULL;

		require __DIR__ . '/assets/BlueScreen/bluescreen.phtml';
	}

	/**
	 * Returns syntax highlighted source code.
	 * @param  string
	 * @param  int
	 * @param  int
	 * @return string|NULL
	 */
	public static function highlightFile($file, $line, $lines = 15, array $vars = NULL)
	{
		$source = @file_get_contents($file); // @ file may not exist
		if ($source) {
			$source = static::highlightPhp($source, $line, $lines, $vars);
			if ($editor = Helpers::editorUri($file, $line)) {
				$source = substr_replace($source, ' data-tracy-href="' . htmlspecialchars($editor, ENT_QUOTES, 'UTF-8') . '"', 4, 0);
			}
			return $source;
		}
	}

	/**
	 * Returns syntax highlighted source code.
	 * @param  string
	 * @param  int
	 * @param  int
	 * @return string
	 */
	public static function highlightPhp($source, $line, $lines = 15, array $vars = NULL)
	{
		if (function_exists('ini_set')) {
			ini_set('highlight.comment', '#998; font-style: italic');
			ini_set('highlight.default', '#000');
			ini_set('highlight.html', '#06B');
			ini_set('highlight.keyword', '#D24; font-weight: bold');
			ini_set('highlight.string', '#080');
		}

		$source = str_replace(array("\r\n", "\r"), "\n", $source);
		$source = explode("\n", highlight_string($source, TRUE));
		$out = $source[0]; //
		$source = str_replace('
', "\n", $source[1]);
		$out .= static::highlightLine($source, $line, $lines);

		if ($vars) {
			$out = preg_replace_callback('#">\$(\w+)( )?#', function ($m) use ($vars) {
				return array_key_exists($m[1], $vars)
					? '" title="'
						. str_replace('"', '"', trim(strip_tags(Dumper::toHtml($vars[$m[1]], array(Dumper::DEPTH => 1)))))
						. $m[0]
					: $m[0];
			}, $out);
		}

		$out = str_replace(' ', ' ', $out);
		return "

$out

";
	}

	/**
	 * Returns highlighted line in HTML code.
	 * @return string
	 */
	public static function highlightLine($html, $line, $lines = 15)
	{
		$source = explode("\n", "\n" . str_replace("\r\n", "\n", $html));
		$out = '';
		$spans = 1;
		$start = $i = max(1, $line - floor($lines * 2 / 3));
		while (--$i >= 1) { // find last highlighted block
			if (preg_match('#.*(</?span[^>]*>)#', $source[$i], $m)) {
				if ($m[1] !== '') {
					$spans++;
					$out .= $m[1];
				}
				break;
			}
		}

		$source = array_slice($source, $start, $lines, TRUE);
		end($source);
		$numWidth = strlen((string) key($source));

		foreach ($source as $n => $s) {
			$spans += substr_count($s, '<span') - substr_count($s, '</span');
			$s = str_replace(array("\r", "\n"), array('', ''), $s);
			preg_match_all('#<[^>]+>#', $s, $tags);
			if ($n == $line) {
				$out .= sprintf(
					"%{$numWidth}s:    %s\n%s",
					$n,
					strip_tags($s),
					implode('', $tags[0])
				);
			} else {
				$out .= sprintf("%{$numWidth}s:    %s\n", $n, $s);
			}
		}
		$out .= str_repeat('', $spans) . '';
		return $out;
	}

	/**
	 * Should a file be collapsed in stack trace?
	 * @param  string
	 * @return bool
	 */
	public function isCollapsed($file)
	{
		$file = strtr($file, '\\', '/') . '/';
		foreach ($this->collapsePaths as $path) {
			$path = strtr($path, '\\', '/') . '/';
			if (strncmp($file, $path, strlen($path)) === 0) {
				return TRUE;
			}
		}
		return FALSE;
	}

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

use Tracy;
use ErrorException;

/**
 * Debugger: displays and logs errors.
 */
class Debugger
{
	const VERSION = '2.3.10';

	/** server modes {@link Debugger::enable()} */
	const
		DEVELOPMENT = FALSE,
		PRODUCTION = TRUE,
		DETECT = NULL;

	const COOKIE_SECRET = 'tracy-debug';

	/** @deprecated */
	public static $version = self::VERSION;

	/** @var bool in production mode is suppressed any debugging output */
	public static $productionMode = self::DETECT;

	/** @var bool whether to display debug bar in development mode */
	public static $showBar = TRUE;

	/** @var bool {@link Debugger::enable()} */
	private static $enabled = FALSE;

	/** @var string reserved memory; also prevents double rendering */
	private static $reserved;

	/** @var int initial output buffer level */
	private static $obLevel;

	/********************* errors and exceptions reporting ****************d*g**/

	/** @var bool|int determines whether any error will cause immediate death; if integer that it's matched against error severity */
	public static $strictMode = FALSE;

	/** @var bool disables the @ (shut-up) operator so that notices and warnings are no longer hidden */
	public static $scream = FALSE;

	/** @var array of callables specifies the functions that are automatically called after fatal error */
	public static $onFatalError = array();

	/********************* Debugger::dump() ****************d*g**/

	/** @var int  how many nested levels of array/object properties display {@link Debugger::dump()} */
	public static $maxDepth = 3;

	/** @var int  how long strings display {@link Debugger::dump()} */
	public static $maxLen = 150;

	/** @var bool display location? {@link Debugger::dump()} */
	public static $showLocation = FALSE;

	/********************* logging ****************d*g**/

	/** @var string name of the directory where errors should be logged */
	public static $logDirectory;

	/** @var int  log bluescreen in production mode for this error severity */
	public static $logSeverity = 0;

	/** @var string|array email(s) to which send error notifications */
	public static $email;

	/** {@link Debugger::log()} and {@link Debugger::fireLog()} */
	const
		DEBUG = ILogger::DEBUG,
		INFO = ILogger::INFO,
		WARNING = ILogger::WARNING,
		ERROR = ILogger::ERROR,
		EXCEPTION = ILogger::EXCEPTION,
		CRITICAL = ILogger::CRITICAL;

	/********************* misc ****************d*g**/

	/** @var int timestamp with microseconds of the start of the request */
	public static $time;

	/** @deprecated */
	public static $source;

	/** @var string URI pattern mask to open editor */
	public static $editor = 'editor://open/?file=%file&line=%line';

	/** @var string command to open browser (use 'start ""' in Windows) */
	public static $browser;

	/** @var string custom static error template */
	public static $errorTemplate;

	/** @var array */
	private static $cpuUsage;

	/********************* services ****************d*g**/

	/** @var BlueScreen */
	private static $blueScreen;

	/** @var Bar */
	private static $bar;

	/** @var ILogger */
	private static $logger;

	/** @var ILogger */
	private static $fireLogger;

	/**
	 * Static class - cannot be instantiated.
	 */
	final public function __construct()
	{
		throw new \LogicException;
	}

	/**
	 * Enables displaying or logging errors and exceptions.
	 * @param  mixed   production, development mode, autodetection or IP address(es) whitelist.
	 * @param  string  error log directory
	 * @param  string  administrator email; enables email sending in production mode
	 * @return void
	 */
	public static function enable($mode = NULL, $logDirectory = NULL, $email = NULL)
	{
		if ($mode !== NULL || self::$productionMode === NULL) {
			self::$productionMode = is_bool($mode) ? $mode : !self::detectDebugMode($mode);
		}

		self::$reserved = str_repeat('t', 3e5);
		self::$time = isset($_SERVER['REQUEST_TIME_FLOAT']) ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(TRUE);
		self::$obLevel = ob_get_level();
		self::$cpuUsage = !self::$productionMode && function_exists('getrusage') ? getrusage() : NULL;

		// logging configuration
		if ($email !== NULL) {
			self::$email = $email;
		}
		if ($logDirectory !== NULL) {
			self::$logDirectory = $logDirectory;
		}
		if (self::$logDirectory) {
			if (!is_dir(self::$logDirectory) || !preg_match('#([a-z]+:)?[/\\\\]#Ai', self::$logDirectory)) {
				self::$logDirectory = NULL;
				self::exceptionHandler(new \RuntimeException('Logging directory not found or is not absolute path.'));
			}
		}

		// php configuration
		if (function_exists('ini_set')) {
			ini_set('display_errors', !self::$productionMode); // or 'stderr'
			ini_set('html_errors', FALSE);
			ini_set('log_errors', FALSE);

		} elseif (ini_get('display_errors') != !self::$productionMode // intentionally ==
			&& ini_get('display_errors') !== (self::$productionMode ? 'stderr' : 'stdout')
		) {
			self::exceptionHandler(new \RuntimeException("Unable to set 'display_errors' because function ini_set() is disabled."));
		}
		error_reporting(E_ALL | E_STRICT);

		if (!self::$enabled) {
			register_shutdown_function(array(__CLASS__, 'shutdownHandler'));
			set_exception_handler(array(__CLASS__, 'exceptionHandler'));
			set_error_handler(array(__CLASS__, 'errorHandler'));

			array_map('class_exists', array('Tracy\Bar', 'Tracy\BlueScreen', 'Tracy\DefaultBarPanel', 'Tracy\Dumper',
				'Tracy\FireLogger', 'Tracy\Helpers', 'Tracy\Logger'));

			self::$enabled = TRUE;
		}
	}

	/**
	 * @return bool
	 */
	public static function isEnabled()
	{
		return self::$enabled;
	}

	/**
	 * Shutdown handler to catch fatal errors and execute of the planned activities.
	 * @return void
	 * @internal
	 */
	public static function shutdownHandler()
	{
		if (!self::$reserved) {
			return;
		}

		$error = error_get_last();
		if (in_array($error['type'], array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE, E_RECOVERABLE_ERROR, E_USER_ERROR), TRUE)) {
			self::exceptionHandler(
				Helpers::fixStack(new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line'])),
				FALSE
			);

		} elseif (self::$showBar && !connection_aborted() && !self::$productionMode && self::isHtmlMode()) {
			self::$reserved = NULL;
			self::removeOutputBuffers(FALSE);
			self::getBar()->render();
		}
	}

	/**
	 * Handler to catch uncaught exception.
	 * @param  \Exception|\Throwable
	 * @return void
	 * @internal
	 */
	public static function exceptionHandler($exception, $exit = TRUE)
	{
		if (!self::$reserved) {
			return;
		}
		self::$reserved = NULL;

		if (!headers_sent()) {
			$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
			$code = isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE ') !== FALSE ? 503 : 500;
			header("$protocol $code", TRUE, $code);
			if (self::isHtmlMode()) {
				header('Content-Type: text/html; charset=UTF-8');
			}
		}

		Helpers::improveException($exception);
		self::removeOutputBuffers(TRUE);

		if (self::$productionMode) {
			try {
				self::log($exception, self::EXCEPTION);
			} catch (\Throwable $e) {
			} catch (\Exception $e) {
			}

			if (self::isHtmlMode()) {
				$logged = empty($e);
				require self::$errorTemplate ?: __DIR__ . '/assets/Debugger/error.500.phtml';
			} elseif (PHP_SAPI === 'cli') {
				fwrite(STDERR, 'ERROR: application encountered an error and can not continue. '
					. (isset($e) ? "Unable to log error.\n" : "Error was logged.\n"));
			}

		} elseif (!connection_aborted() && self::isHtmlMode()) {
			self::getBlueScreen()->render($exception);
			if (self::$showBar) {
				self::getBar()->render();
			}

		} else {
			self::fireLog($exception);
			$s = get_class($exception) . ($exception->getMessage() === '' ? '' : ': ' . $exception->getMessage())
				. ' in ' . $exception->getFile() . ':' . $exception->getLine()
				. "\nStack trace:\n" . $exception->getTraceAsString();
			try {
				$file = self::log($exception, self::EXCEPTION);
				if ($file && !headers_sent()) {
					header("X-Tracy-Error-Log: $file");
				}
				echo "$s\n" . ($file ? "(stored in $file)\n" : '');
				if ($file && self::$browser) {
					exec(self::$browser . ' ' . escapeshellarg($file));
				}
			} catch (\Throwable $e) {
				echo "$s\nUnable to log error: {$e->getMessage()}\n";
			} catch (\Exception $e) {
				echo "$s\nUnable to log error: {$e->getMessage()}\n";
			}
		}

		try {
			$e = NULL;
			foreach (self::$onFatalError as $handler) {
				call_user_func($handler, $exception);
			}
		} catch (\Throwable $e) {
		} catch (\Exception $e) {
		}
		if ($e) {
			try {
				self::log($e, self::EXCEPTION);
			} catch (\Throwable $e) {
			} catch (\Exception $e) {
			}
		}

		if ($exit) {
			exit($exception instanceof \Error ? 255 : 254);
		}
	}

	/**
	 * Handler to catch warnings and notices.
	 * @return bool   FALSE to call normal error handler, NULL otherwise
	 * @throws ErrorException
	 * @internal
	 */
	public static function errorHandler($severity, $message, $file, $line, $context)
	{
		if (self::$scream) {
			error_reporting(E_ALL | E_STRICT);
		}

		if ($severity === E_RECOVERABLE_ERROR || $severity === E_USER_ERROR) {
			if (Helpers::findTrace(debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE), '*::__toString')) {
				$previous = isset($context['e']) && ($context['e'] instanceof \Exception || $context['e'] instanceof \Throwable) ? $context['e'] : NULL;
				$e = new ErrorException($message, 0, $severity, $file, $line, $previous);
				$e->context = $context;
				self::exceptionHandler($e);
			}

			$e = new ErrorException($message, 0, $severity, $file, $line);
			$e->context = $context;
			throw $e;

		} elseif (($severity & error_reporting()) !== $severity) {
			return FALSE; // calls normal error handler to fill-in error_get_last()

		} elseif (self::$productionMode && ($severity & self::$logSeverity) === $severity) {
			$e = new ErrorException($message, 0, $severity, $file, $line);
			$e->context = $context;
			try {
				self::log($e, self::ERROR);
			} catch (\Throwable $e) {
			} catch (\Exception $foo) {
			}
			return NULL;

		} elseif (!self::$productionMode && !isset($_GET['_tracy_skip_error'])
			&& (is_bool(self::$strictMode) ? self::$strictMode : ((self::$strictMode & $severity) === $severity))
		) {
			$e = new ErrorException($message, 0, $severity, $file, $line);
			$e->context = $context;
			$e->skippable = TRUE;
			self::exceptionHandler($e);
		}

		$message = 'PHP ' . Helpers::errorTypeToString($severity) . ": $message";
		$count = & self::getBar()->getPanel('Tracy:errors')->data["$file|$line|$message"];

		if ($count++) { // repeated error
			return NULL;

		} elseif (self::$productionMode) {
			try {
				self::log("$message in $file:$line", self::ERROR);
			} catch (\Throwable $e) {
			} catch (\Exception $foo) {
			}
			return NULL;

		} else {
			self::fireLog(new ErrorException($message, 0, $severity, $file, $line));
			return self::isHtmlMode() ? NULL : FALSE; // FALSE calls normal error handler
		}
	}

	private static function isHtmlMode()
	{
		return empty($_SERVER['HTTP_X_REQUESTED_WITH'])
			&& PHP_SAPI !== 'cli'
			&& !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list()));
	}

	private static function removeOutputBuffers($errorOccurred)
	{
		while (ob_get_level() > self::$obLevel) {
			$tmp = ob_get_status(TRUE);
			$status = end($tmp);
			if (in_array($status['name'], array('ob_gzhandler', 'zlib output compression'))) {
				break;
			}
			$fnc = $status['chunk_size'] || !$errorOccurred ? 'ob_end_flush' : 'ob_end_clean';
			if (!@$fnc()) { // @ may be not removable
				break;
			}
		}
	}

	/********************* services ****************d*g**/

	/**
	 * @return BlueScreen
	 */
	public static function getBlueScreen()
	{
		if (!self::$blueScreen) {
			self::$blueScreen = new BlueScreen;
			self::$blueScreen->info = array(
				'PHP ' . PHP_VERSION,
				isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : NULL,
				'Tracy ' . self::VERSION,
			);
		}
		return self::$blueScreen;
	}

	/**
	 * @return Bar
	 */
	public static function getBar()
	{
		if (!self::$bar) {
			self::$bar = new Bar;
			self::$bar->addPanel($info = new DefaultBarPanel('info'), 'Tracy:info');
			$info->cpuUsage = self::$cpuUsage;
			self::$bar->addPanel(new DefaultBarPanel('errors'), 'Tracy:errors'); // filled by errorHandler()
		}
		return self::$bar;
	}

	/**
	 * @return void
	 */
	public static function setLogger(ILogger $logger)
	{
		self::$logger = $logger;
	}

	/**
	 * @return ILogger
	 */
	public static function getLogger()
	{
		if (!self::$logger) {
			self::$logger = new Logger(self::$logDirectory, self::$email, self::getBlueScreen());
			self::$logger->directory = & self::$logDirectory; // back compatiblity
			self::$logger->email = & self::$email;
		}
		return self::$logger;
	}

	/**
	 * @return ILogger
	 */
	public static function getFireLogger()
	{
		if (!self::$fireLogger) {
			self::$fireLogger = new FireLogger;
		}
		return self::$fireLogger;
	}

	/********************* useful tools ****************d*g**/

	/**
	 * Dumps information about a variable in readable format.
	 * @tracySkipLocation
	 * @param  mixed  variable to dump
	 * @param  bool   return output instead of printing it? (bypasses $productionMode)
	 * @return mixed  variable itself or dump
	 */
	public static function dump($var, $return = FALSE)
	{
		if ($return) {
			ob_start(function () {});
			Dumper::dump($var, array(
				Dumper::DEPTH => self::$maxDepth,
				Dumper::TRUNCATE => self::$maxLen,
			));
			return ob_get_clean();

		} elseif (!self::$productionMode) {
			Dumper::dump($var, array(
				Dumper::DEPTH => self::$maxDepth,
				Dumper::TRUNCATE => self::$maxLen,
				Dumper::LOCATION => self::$showLocation,
			));
		}

		return $var;
	}

	/**
	 * Starts/stops stopwatch.
	 * @param  string  name
	 * @return float   elapsed seconds
	 */
	public static function timer($name = NULL)
	{
		static $time = array();
		$now = microtime(TRUE);
		$delta = isset($time[$name]) ? $now - $time[$name] : 0;
		$time[$name] = $now;
		return $delta;
	}

	/**
	 * Dumps information about a variable in Tracy Debug Bar.
	 * @tracySkipLocation
	 * @param  mixed  variable to dump
	 * @param  string optional title
	 * @param  array  dumper options
	 * @return mixed  variable itself
	 */
	public static function barDump($var, $title = NULL, array $options = NULL)
	{
		if (!self::$productionMode) {
			static $panel;
			if (!$panel) {
				self::getBar()->addPanel($panel = new DefaultBarPanel('dumps'));
			}
			$panel->data[] = array('title' => $title, 'dump' => Dumper::toHtml($var, (array) $options + array(
				Dumper::DEPTH => self::$maxDepth,
				Dumper::TRUNCATE => self::$maxLen,
				Dumper::LOCATION => self::$showLocation ?: Dumper::LOCATION_CLASS | Dumper::LOCATION_SOURCE,
			)));
		}
		return $var;
	}

	/**
	 * Logs message or exception.
	 * @param  string|\Exception|\Throwable
	 * @return mixed
	 */
	public static function log($message, $priority = ILogger::INFO)
	{
		return self::getLogger()->log($message, $priority);
	}

	/**
	 * Sends message to FireLogger console.
	 * @param  mixed   message to log
	 * @return bool    was successful?
	 */
	public static function fireLog($message)
	{
		if (!self::$productionMode) {
			return self::getFireLogger()->log($message);
		}
	}

	/**
	 * Detects debug mode by IP address.
	 * @param  string|array  IP addresses or computer names whitelist detection
	 * @return bool
	 */
	public static function detectDebugMode($list = NULL)
	{
		$addr = isset($_SERVER['REMOTE_ADDR'])
			? $_SERVER['REMOTE_ADDR']
			: php_uname('n');
		$secret = isset($_COOKIE[self::COOKIE_SECRET]) && is_string($_COOKIE[self::COOKIE_SECRET])
			? $_COOKIE[self::COOKIE_SECRET]
			: NULL;
		$list = is_string($list)
			? preg_split('#[,\s]+#', $list)
			: (array) $list;
		if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
			$list[] = '127.0.0.1';
			$list[] = '::1';
		}
		return in_array($addr, $list, TRUE) || in_array("$secret@$addr", $list, TRUE);
	}

}

repo_name: Cerx/ToDo

license: mit


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

/**
 * IBarPanel implementation helper.
 * @internal
 */
class DefaultBarPanel implements IBarPanel
{
	private $id;

	public $data;

	public function __construct($id)
	{
		$this->id = $id;
	}

	/**
	 * Renders HTML code for custom tab.
	 * @return string
	 */
	public function getTab()
	{
		ob_start(function () {});
		$data = $this->data;
		require __DIR__ . "/assets/Bar/{$this->id}.tab.phtml";
		return ob_get_clean();
	}

	/**
	 * Renders HTML code for custom panel.
	 * @return string
	 */
	public function getPanel()
	{
		ob_start(function () {});
		if (is_file(__DIR__ . "/assets/Bar/{$this->id}.panel.phtml")) {
			$data = $this->data;
			require __DIR__ . "/assets/Bar/{$this->id}.panel.phtml";
		}
		return ob_get_clean();
	}

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

use Tracy;

/**
 * Dumps a variable.
 */
class Dumper
{
	const
		DEPTH = 'depth', // how many nested levels of array/object properties display (defaults to 4)
		TRUNCATE = 'truncate', // how truncate long strings? (defaults to 150)
		COLLAPSE = 'collapse', // collapse top array/object or how big are collapsed? (defaults to 14)
		COLLAPSE_COUNT = 'collapsecount', // how big array/object are collapsed? (defaults to 7)
		LOCATION = 'location', // show location string? (defaults to 0)
		OBJECT_EXPORTERS = 'exporters', // custom exporters for objects (defaults to Dumper::$objectexporters)
		LIVE = 'live'; // will be rendered using JavaScript

	const
		LOCATION_SOURCE = 1, // shows where dump was called
		LOCATION_LINK = 2, // appends clickable anchor
		LOCATION_CLASS = 4; // shows where class is defined

	/** @var array */
	public static $terminalColors = array(
		'bool' => '1;33',
		'null' => '1;33',
		'number' => '1;32',
		'string' => '1;36',
		'array' => '1;31',
		'key' => '1;37',
		'object' => '1;31',
		'visibility' => '1;30',
		'resource' => '1;37',
		'indent' => '1;30',
	);

	/** @var array */
	public static $resources = array(
		'stream' => 'stream_get_meta_data',
		'stream-context' => 'stream_context_get_options',
		'curl' => 'curl_getinfo',
	);

	/** @var array */
	public static $objectExporters = array(
		'Closure' => 'Tracy\Dumper::exportClosure',
		'SplFileInfo' => 'Tracy\Dumper::exportSplFileInfo',
		'SplObjectStorage' => 'Tracy\Dumper::exportSplObjectStorage',
		'__PHP_Incomplete_Class' => 'Tracy\Dumper::exportPhpIncompleteClass',
	);

	/** @var string @internal */
	public static $livePrefix;

	/** @var array  */
	private static $liveStorage = array();

	/**
	 * Dumps variable to the output.
	 * @return mixed  variable
	 */
	public static function dump($var, array $options = NULL)
	{
		if (PHP_SAPI !== 'cli' && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list()))) {
			echo self::toHtml($var, $options);
		} elseif (self::detectColors()) {
			echo self::toTerminal($var, $options);
		} else {
			echo self::toText($var, $options);
		}
		return $var;
	}

	/**
	 * Dumps variable to HTML.
	 * @return string
	 */
	public static function toHtml($var, array $options = NULL)
	{
		$options = (array) $options + array(
			self::DEPTH => 4,
			self::TRUNCATE => 150,
			self::COLLAPSE => 14,
			self::COLLAPSE_COUNT => 7,
			self::OBJECT_EXPORTERS => NULL,
		);
		$loc = & $options[self::LOCATION];
		$loc = $loc === TRUE ? ~0 : (int) $loc;

		$options[self::OBJECT_EXPORTERS] = (array) $options[self::OBJECT_EXPORTERS] + self::$objectExporters;
		uksort($options[self::OBJECT_EXPORTERS], function ($a, $b) {
			return $b === '' || (class_exists($a, FALSE) && ($rc = new \ReflectionClass($a)) && $rc->isSubclassOf($b)) ? -1 : 1;
		});

		$live = !empty($options[self::LIVE]) && $var && (is_array($var) || is_object($var) || is_resource($var));
		list($file, $line, $code) = $loc ? self::findLocation() : NULL;
		$locAttrs = $file && $loc & self::LOCATION_SOURCE ? Helpers::formatHtml(
			' title="%in file % on line %" data-tracy-href="%"', "$code\n", $file, $line, Helpers::editorUri($file, $line)
		) : NULL;

		return '
" : '>')
			. ($live ? '' : self::dumpVar($var, $options))
			. ($file && $loc & self::LOCATION_LINK ? 'in ' . Helpers::editorLink($file, $line) . '' : '')
			. "
\n";
	}

	/**
	 * Dumps variable to plain text.
	 * @return string
	 */
	public static function toText($var, array $options = NULL)
	{
		return htmlspecialchars_decode(strip_tags(self::toHtml($var, $options)), ENT_QUOTES);
	}

	/**
	 * Dumps variable to x-terminal.
	 * @return string
	 */
	public static function toTerminal($var, array $options = NULL)
	{
		return htmlspecialchars_decode(strip_tags(preg_replace_callback('#|#', function ($m) {
			return "\033[" . (isset($m[1], Dumper::$terminalColors[$m[1]]) ? Dumper::$terminalColors[$m[1]] : '0') . 'm';
		}, self::toHtml($var, $options))), ENT_QUOTES);
	}

	/**
	 * Internal toHtml() dump implementation.
	 * @param  mixed  variable to dump
	 * @param  array  options
	 * @param  int    current recursion level
	 * @return string
	 */
	private static function dumpVar(& $var, array $options, $level = 0)
	{
		if (method_exists(__CLASS__, $m = 'dump' . gettype($var))) {
			return self::$m($var, $options, $level);
		} else {
			return "unknown type\n";
		}
	}

	private static function dumpNull()
	{
		return "NULL\n";
	}

	private static function dumpBoolean(& $var)
	{
		return '' . ($var ? 'TRUE' : 'FALSE') . "\n";
	}

	private static function dumpInteger(& $var)
	{
		return "$var\n";
	}

	private static function dumpDouble(& $var)
	{
		$var = is_finite($var)
			? ($tmp = json_encode($var)) . (strpos($tmp, '.') === FALSE ? '.0' : '')
			: str_replace('.0', '', var_export($var, TRUE)); // workaround for PHP 7.0.2
		return "$var\n";
	}

	private static function dumpString(& $var, $options)
	{
		return '"'
			. htmlspecialchars(self::encodeString($var, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8')
			. '"' . (strlen($var) > 1 ? ' (' . strlen($var) . ')' : '') . "\n";
	}

	private static function dumpArray(& $var, $options, $level)
	{
		static $marker;
		if ($marker === NULL) {
			$marker = uniqid("\x00", TRUE);
		}

		$out = 'array (';

		if (empty($var)) {
			return $out . ")\n";

		} elseif (isset($var[$marker])) {
			return $out . (count($var) - 1) . ") [ RECURSION ]\n";

		} elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH]) {
			$collapsed = $level ? count($var) >= $options[self::COLLAPSE_COUNT]
				: (is_int($options[self::COLLAPSE]) ? count($var) >= $options[self::COLLAPSE] : $options[self::COLLAPSE]);
			$out = ''
				. $out . count($var) . ")\n
';
			$var[$marker] = TRUE;
			foreach ($var as $k => & $v) {
				if ($k !== $marker) {
					$k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"';
					$out .= '   ' . str_repeat('|  ', $level) . ''
						. '' . $k . ' => '
						. self::dumpVar($v, $options, $level + 1);
				}
			}
			unset($var[$marker]);
			return $out . '
';

		} else {
			return $out . count($var) . ") [ ... ]\n";
		}
	}

	private static function dumpObject(& $var, $options, $level)
	{
		$fields = self::exportObject($var, $options[self::OBJECT_EXPORTERS]);
		$editor = NULL;
		if ($options[self::LOCATION] & self::LOCATION_CLASS) {
			$rc = $var instanceof \Closure ? new \ReflectionFunction($var) : new \ReflectionClass($var);
			$editor = Helpers::editorUri($rc->getFileName(), $rc->getStartLine());
		}
		$out = 'getFileName(), $rc->getStartLine(), $editor
			) : '')
			. '>' . htmlspecialchars(Helpers::getClass($var)) . ' #' . substr(md5(spl_object_hash($var)), 0, 4) . '';

		static $list = array();

		if (empty($fields)) {
			return $out . "\n";

		} elseif (in_array($var, $list, TRUE)) {
			return $out . " { RECURSION }\n";

		} elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH] || $var instanceof \Closure) {
			$collapsed = $level ? count($fields) >= $options[self::COLLAPSE_COUNT]
				: (is_int($options[self::COLLAPSE]) ? count($fields) >= $options[self::COLLAPSE] : $options[self::COLLAPSE]);
			$out = ''
				. $out . "\n
';
			$list[] = $var;
			foreach ($fields as $k => & $v) {
				$vis = '';
				if (isset($k[0]) && $k[0] === "\x00") {
					$vis = ' ' . ($k[1] === '*' ? 'protected' : 'private') . '';
					$k = substr($k, strrpos($k, "\x00") + 1);
				}
				$k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"';
				$out .= '   ' . str_repeat('|  ', $level) . ''
					. '' . $k . "$vis => "
					. self::dumpVar($v, $options, $level + 1);
			}
			array_pop($list);
			return $out . '
';

		} else {
			return $out . " { ... }\n";
		}
	}

	private static function dumpResource(& $var, $options, $level)
	{
		$type = get_resource_type($var);
		$out = '' . htmlSpecialChars($type, ENT_IGNORE, 'UTF-8') . ' resource '
			. '#' . intval($var) . '';
		if (isset(self::$resources[$type])) {
			$out = "$out\n
";
			foreach (call_user_func(self::$resources[$type], $var) as $k => $v) {
				$out .= '   ' . str_repeat('|  ', $level) . ''
					. '' . htmlSpecialChars($k, ENT_IGNORE, 'UTF-8') . ' => ' . self::dumpVar($v, $options, $level + 1);
			}
			return $out . '
';
		}
		return "$out\n";
	}

	/**
	 * @return mixed
	 */
	private static function toJson(& $var, $options, $level = 0)
	{
		if (is_bool($var) || is_null($var) || is_int($var)) {
			return $var;

		} elseif (is_float($var)) {
			return is_finite($var)
				? (strpos($tmp = json_encode($var), '.') ? $var : array('number' => "$tmp.0"))
				: array('type' => (string) $var);

		} elseif (is_string($var)) {
			return self::encodeString($var, $options[self::TRUNCATE]);

		} elseif (is_array($var)) {
			static $marker;
			if ($marker === NULL) {
				$marker = uniqid("\x00", TRUE);
			}
			if (isset($var[$marker]) || $level >= $options[self::DEPTH]) {
				return array(NULL);
			}
			$res = array();
			$var[$marker] = TRUE;
			foreach ($var as $k => & $v) {
				if ($k !== $marker) {
					$k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . self::encodeString($k, $options[self::TRUNCATE]) . '"';
					$res[] = array($k, self::toJson($v, $options, $level + 1));
				}
			}
			unset($var[$marker]);
			return $res;

		} elseif (is_object($var)) {
			$obj = & self::$liveStorage[spl_object_hash($var)];
			if ($obj && $obj['level'] <= $level) {
				return array('object' => $obj['id']);
			}

			if ($options[self::LOCATION] & self::LOCATION_CLASS) {
				$rc = $var instanceof \Closure ? new \ReflectionFunction($var) : new \ReflectionClass($var);
				$editor = Helpers::editorUri($rc->getFileName(), $rc->getStartLine());
			}
			static $counter = 1;
			$obj = $obj ?: array(
				'id' => self::$livePrefix . '0' . $counter++, // differentiate from resources
				'name' => Helpers::getClass($var),
				'editor' => empty($editor) ? NULL : array('file' => $rc->getFileName(), 'line' => $rc->getStartLine(), 'url' => $editor),
				'level' => $level,
				'object' => $var,
			);

			if ($level < $options[self::DEPTH] || !$options[self::DEPTH]) {
				$obj['level'] = $level;
				$obj['items'] = array();

				foreach (self::exportObject($var, $options[self::OBJECT_EXPORTERS]) as $k => $v) {
					$vis = 0;
					if (isset($k[0]) && $k[0] === "\x00") {
						$vis = $k[1] === '*' ? 1 : 2;
						$k = substr($k, strrpos($k, "\x00") + 1);
					}
					$k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . self::encodeString($k, $options[self::TRUNCATE]) . '"';
					$obj['items'][] = array($k, self::toJson($v, $options, $level + 1), $vis);
				}
			}
			return array('object' => $obj['id']);

		} elseif (is_resource($var)) {
			$obj = & self::$liveStorage[(string) $var];
			if (!$obj) {
				$type = get_resource_type($var);
				$obj = array('id' => self::$livePrefix . (int) $var, 'name' => $type . ' resource');
				if (isset(self::$resources[$type])) {
					foreach (call_user_func(self::$resources[$type], $var) as $k => $v) {
						$obj['items'][] = array($k, self::toJson($v, $options, $level + 1));
					}
				}
			}
			return array('resource' => $obj['id']);

		} else {
			return array('type' => 'unknown type');
		}
	}

	/** @return array  */
	public static function fetchLiveData()
	{
		$res = array();
		foreach (self::$liveStorage as $obj) {
			$id = $obj['id'];
			unset($obj['level'], $obj['object'], $obj['id']);
			$res[$id] = $obj;
		}
		self::$liveStorage = array();
		return $res;
	}

	/**
	 * @internal
	 * @return string UTF-8
	 */
	public static function encodeString($s, $maxLength = NULL)
	{
		static $table;
		if ($table === NULL) {
			foreach (array_merge(range("\x00", "\x1F"), range("\x7F", "\xFF")) as $ch) {
				$table[$ch] = '\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
			}
			$table['\\'] = '\\\\';
			$table["\r"] = '\r';
			$table["\n"] = '\n';
			$table["\t"] = '\t';
		}

		if (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $s) || preg_last_error()) {
			if ($shortened = ($maxLength && strlen($s) > $maxLength)) {
				$s = substr($s, 0, $maxLength);
			}
			$s = strtr($s, $table);

		} elseif ($shortened = ($maxLength && strlen(utf8_decode($s)) > $maxLength)) {
			if (function_exists('iconv_substr')) {
				$s = iconv_substr($s, 0, $maxLength, 'UTF-8');
			} else {
				$i = $len = 0;
				do {
					if (($s[$i] < "\x80" || $s[$i] >= "\xC0") && (++$len > $maxLength)) {
						$s = substr($s, 0, $i);
						break;
					}
				} while (isset($s[++$i]));
			}
		}

		return $s . (empty($shortened) ? '' : ' ... ');
	}

	/**
	 * @return array
	 */
	private static function exportObject($obj, array $exporters)
	{
		foreach ($exporters as $type => $dumper) {
			if (!$type || $obj instanceof $type) {
				return call_user_func($dumper, $obj);
			}
		}
		return (array) $obj;
	}

	/**
	 * @return array
	 */
	private static function exportClosure(\Closure $obj)
	{
		$rc = new \ReflectionFunction($obj);
		$res = array();
		foreach ($rc->getParameters() as $param) {
			$res[] = '$' . $param->getName();
		}
		return array(
			'file' => $rc->getFileName(),
			'line' => $rc->getStartLine(),
			'variables' => $rc->getStaticVariables(),
			'parameters' => implode(', ', $res),
		);
	}

	/**
	 * @return array
	 */
	private static function exportSplFileInfo(\SplFileInfo $obj)
	{
		return array('path' => $obj->getPathname());
	}

	/**
	 * @return array
	 */
	private static function exportSplObjectStorage(\SplObjectStorage $obj)
	{
		$res = array();
		foreach (clone $obj as $item) {
			$res[] = array('object' => $item, 'data' => $obj[$item]);
		}
		return $res;
	}

	/**
	 * @return array
	 */
	private static function exportPhpIncompleteClass(\__PHP_Incomplete_Class $obj)
	{
		$info = array('className' => NULL, 'private' => array(), 'protected' => array(), 'public' => array());
		foreach ((array) $obj as $name => $value) {
			if ($name === '__PHP_Incomplete_Class_Name') {
				$info['className'] = $value;
			} elseif (preg_match('#^\x0\*\x0(.+)\z#', $name, $m)) {
				$info['protected'][$m[1]] = $value;
			} elseif (preg_match('#^\x0(.+)\x0(.+)\z#', $name, $m)) {
				$info['private'][$m[1] . '::$' . $m[2]] = $value;
			} else {
				$info['public'][$name] = $value;
			}
		}
		return $info;
	}

	/**
	 * Finds the location where dump was called.
	 * @return array [file, line, code]
	 */
	private static function findLocation()
	{
		foreach (debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE) as $item) {
			if (isset($item['class']) && $item['class'] === __CLASS__) {
				$location = $item;
				continue;
			} elseif (isset($item['function'])) {
				try {
					$reflection = isset($item['class'])
						? new \ReflectionMethod($item['class'], $item['function'])
						: new \ReflectionFunction($item['function']);
					if ($reflection->isInternal() || preg_match('#\s@tracySkipLocation\s#', $reflection->getDocComment())) {
						$location = $item;
						continue;
					}
				} catch (\ReflectionException $e) {
				}
			}
			break;
		}

		if (isset($location['file'], $location['line']) && is_file($location['file'])) {
			$lines = file($location['file']);
			$line = $lines[$location['line'] - 1];
			return array(
				$location['file'],
				$location['line'],
				trim(preg_match('#\w*dump(er::\w+)?\(.*\)#i', $line, $m) ? $m[0] : $line),
			);
		}
	}

	/**
	 * @return bool
	 */
	private static function detectColors()
	{
		return self::$terminalColors &&
			(getenv('ConEmuANSI') === 'ON'
			|| getenv('ANSICON') !== FALSE
			|| getenv('term') === 'xterm-256color'
			|| (defined('STDOUT') && function_exists('posix_isatty') && posix_isatty(STDOUT)));
	}

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

use Tracy;

/**
 * FireLogger console logger.
 *
 * @see http://firelogger.binaryage.com
 */
class FireLogger implements ILogger
{
	/** @var int  */
	public $maxDepth = 3;

	/** @var int  */
	public $maxLength = 150;

	/** @var array  */
	private $payload = array('logs' => array());

	/**
	 * Sends message to FireLogger console.
	 * @param  mixed
	 * @return bool    was successful?
	 */
	public function log($message, $priority = self::DEBUG)
	{
		if (!isset($_SERVER['HTTP_X_FIRELOGGER']) || headers_sent()) {
			return FALSE;
		}

		$item = array(
			'name' => 'PHP',
			'level' => $priority,
			'order' => count($this->payload['logs']),
			'time' => str_pad(number_format((microtime(TRUE) - Debugger::$time) * 1000, 1, '.', ' '), 8, '0', STR_PAD_LEFT) . ' ms',
			'template' => '',
			'message' => '',
			'style' => 'background:#767ab6',
		);

		$args = func_get_args();
		if (isset($args[0]) && is_string($args[0])) {
			$item['template'] = array_shift($args);
		}

		if (isset($args[0]) && ($args[0] instanceof \Exception || $args[0] instanceof \Throwable)) {
			$e = array_shift($args);
			$trace = $e->getTrace();
			if (isset($trace[0]['class']) && $trace[0]['class'] === 'Tracy\Debugger'
				&& ($trace[0]['function'] === 'shutdownHandler' || $trace[0]['function'] === 'errorHandler')
			) {
				unset($trace[0]);
			}

			$file = str_replace(dirname(dirname(dirname($e->getFile()))), "\xE2\x80\xA6", $e->getFile());
			$item['template'] = ($e instanceof \ErrorException ? '' : Helpers::getClass($e) . ': ')
				. $e->getMessage() . ($e->getCode() ? ' #' . $e->getCode() : '') . ' in ' . $file . ':' . $e->getLine();
			$item['pathname'] = $e->getFile();
			$item['lineno'] = $e->getLine();

		} else {
			$trace = debug_backtrace();
			if (isset($trace[1]['class']) && $trace[1]['class'] === 'Tracy\Debugger'
				&& ($trace[1]['function'] === 'fireLog')
			) {
				unset($trace[0]);
			}

			foreach ($trace as $frame) {
				if (isset($frame['file']) && is_file($frame['file'])) {
					$item['pathname'] = $frame['file'];
					$item['lineno'] = $frame['line'];
					break;
				}
			}
		}

		$item['exc_info'] = array('', '', array());
		$item['exc_frames'] = array();

		foreach ($trace as $frame) {
			$frame += array('file' => NULL, 'line' => NULL, 'class' => NULL, 'type' => NULL, 'function' => NULL, 'object' => NULL, 'args' => NULL);
			$item['exc_info'][2][] = array($frame['file'], $frame['line'], "$frame[class]$frame[type]$frame[function]", $frame['object']);
			$item['exc_frames'][] = $frame['args'];
		}

		if (isset($args[0]) && in_array($args[0], array(self::DEBUG, self::INFO, self::WARNING, self::ERROR, self::CRITICAL), TRUE)) {
			$item['level'] = array_shift($args);
		}

		$item['args'] = $args;

		$this->payload['logs'][] = $this->jsonDump($item, -1);
		foreach (str_split(base64_encode(@json_encode($this->payload)), 4990) as $k => $v) { // intentionally @
			header("FireLogger-de11e-$k:$v");
		}
		return TRUE;
	}

	/**
	 * Dump implementation for JSON.
	 * @param  mixed  variable to dump
	 * @param  int    current recursion level
	 * @return string
	 */
	private function jsonDump(& $var, $level = 0)
	{
		if (is_bool($var) || is_null($var) || is_int($var) || is_float($var)) {
			return $var;

		} elseif (is_string($var)) {
			return Dumper::encodeString($var, $this->maxLength);

		} elseif (is_array($var)) {
			static $marker;
			if ($marker === NULL) {
				$marker = uniqid("\x00", TRUE);
			}
			if (isset($var[$marker])) {
				return "\xE2\x80\xA6RECURSION\xE2\x80\xA6";

			} elseif ($level < $this->maxDepth || !$this->maxDepth) {
				$var[$marker] = TRUE;
				$res = array();
				foreach ($var as $k => & $v) {
					if ($k !== $marker) {
						$res[$this->jsonDump($k)] = $this->jsonDump($v, $level + 1);
					}
				}
				unset($var[$marker]);
				return $res;

			} else {
				return " \xE2\x80\xA6 ";
			}

		} elseif (is_object($var)) {
			$arr = (array) $var;
			static $list = array();
			if (in_array($var, $list, TRUE)) {
				return "\xE2\x80\xA6RECURSION\xE2\x80\xA6";

			} elseif ($level < $this->maxDepth || !$this->maxDepth) {
				$list[] = $var;
				$res = array("\x00" => '(object) ' . Helpers::getClass($var));
				foreach ($arr as $k => & $v) {
					if (isset($k[0]) && $k[0] === "\x00") {
						$k = substr($k, strrpos($k, "\x00") + 1);
					}
					$res[$this->jsonDump($k)] = $this->jsonDump($v, $level + 1);
				}
				array_pop($list);
				return $res;

			} else {
				return " \xE2\x80\xA6 ";
			}

		} elseif (is_resource($var)) {
			return 'resource ' . get_resource_type($var);

		} else {
			return 'unknown type';
		}
	}

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

/**
 * Rendering helpers for Debugger.
 */
class Helpers
{

	/**
	 * Returns HTML link to editor.
	 * @return string
	 */
	public static function editorLink($file, $line = NULL)
	{
		if ($editor = self::editorUri($file, $line)) {
			$file = strtr($file, '\\', '/');
			if (preg_match('#(^[a-z]:)?/.{1,50}$#i', $file, $m) && strlen($file) > strlen($m[0])) {
				$file = '...' . $m[0];
			}
			$file = strtr($file, '/', DIRECTORY_SEPARATOR);
			return self::formatHtml('%%%',
				$editor,
				$file . ($line ? ":$line" : ''),
				rtrim(dirname($file), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR,
				basename($file),
				$line ? ":$line" : ''
			);
		} else {
			return self::formatHtml('%', $file . ($line ? ":$line" : ''));
		}
	}

	/**
	 * Returns link to editor.
	 * @return string
	 */
	public static function editorUri($file, $line = NULL)
	{
		if (Debugger::$editor && $file && is_file($file)) {
			return strtr(Debugger::$editor, array('%file' => rawurlencode($file), '%line' => $line ? (int) $line : 1));
		}
	}

	public static function formatHtml($mask)
	{
		$args = func_get_args();
		return preg_replace_callback('#%#', function () use (& $args, & $count) {
			return htmlspecialchars($args[++$count], ENT_IGNORE | ENT_QUOTES, 'UTF-8');
		}, $mask);
	}

	public static function findTrace(array $trace, $method, & $index = NULL)
	{
		$m = explode('::', $method);
		foreach ($trace as $i => $item) {
			if (isset($item['function']) && $item['function'] === end($m)
				&& isset($item['class']) === isset($m[1])
				&& (!isset($item['class']) || $item['class'] === $m[0] || $m[0] === '*' || is_subclass_of($item['class'], $m[0]))
			) {
				$index = $i;
				return $item;
			}
		}
	}

	/**
	 * @return string
	 */
	public static function getClass($obj)
	{
		return current(explode("\x00", get_class($obj)));
	}

	/** @internal */
	public static function fixStack($exception)
	{
		if (function_exists('xdebug_get_function_stack')) {
			$stack = array();
			foreach (array_slice(array_reverse(xdebug_get_function_stack()), 2, -1) as $row) {
				$frame = array(
					'file' => $row['file'],
					'line' => $row['line'],
					'function' => isset($row['function']) ? $row['function'] : '*unknown*',
					'args' => array(),
				);
				if (!empty($row['class'])) {
					$frame['type'] = isset($row['type']) && $row['type'] === 'dynamic' ? '->' : '::';
					$frame['class'] = $row['class'];
				}
				$stack[] = $frame;
			}
			$ref = new \ReflectionProperty('Exception', 'trace');
			$ref->setAccessible(TRUE);
			$ref->setValue($exception, $stack);
		}
		return $exception;
	}

	/** @internal */
	public static function fixEncoding($s)
	{
		if (PHP_VERSION_ID < 50400) {
			return @iconv('UTF-16', 'UTF-8//IGNORE', iconv('UTF-8', 'UTF-16//IGNORE', $s)); // intentionally @
		} else {
			return htmlspecialchars_decode(htmlspecialchars($s, ENT_NOQUOTES | ENT_IGNORE, 'UTF-8'), ENT_NOQUOTES);
		}
	}

	/** @internal */
	public static function errorTypeToString($type)
	{
		$types = array(
			E_ERROR => 'Fatal Error',
			E_USER_ERROR => 'User Error',
			E_RECOVERABLE_ERROR => 'Recoverable Error',
			E_CORE_ERROR => 'Core Error',
			E_COMPILE_ERROR => 'Compile Error',
			E_PARSE => 'Parse Error',
			E_WARNING => 'Warning',
			E_CORE_WARNING => 'Core Warning',
			E_COMPILE_WARNING => 'Compile Warning',
			E_USER_WARNING => 'User Warning',
			E_NOTICE => 'Notice',
			E_USER_NOTICE => 'User Notice',
			E_STRICT => 'Strict standards',
			E_DEPRECATED => 'Deprecated',
			E_USER_DEPRECATED => 'User Deprecated',
		);
		return isset($types[$type]) ? $types[$type] : 'Unknown error';
	}

	/** @internal */
	public static function getSource()
	{
		if (isset($_SERVER['REQUEST_URI'])) {
			return (!empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https://' : 'http://')
				. (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '')
				. $_SERVER['REQUEST_URI'];
		} else {
			return empty($_SERVER['argv']) ? 'CLI' : 'CLI: ' . implode(' ', $_SERVER['argv']);
		}
	}

	/** @internal */
	public static function improveException($e)
	{
		$message = $e->getMessage();
		if (!$e instanceof \Error && !$e instanceof \ErrorException) {
			// do nothing
		} elseif (preg_match('#^Call to undefined function (\S+\\\\)?(\w+)\(#', $message, $m)) {
			$funcs = get_defined_functions();
			$funcs = array_merge($funcs['internal'], $funcs['user']);
			$hint = self::getSuggestion($funcs, $m[1] . $m[2]) ?: self::getSuggestion($funcs, $m[2]);
			$message .= ", did you mean $hint()?";

		} elseif (preg_match('#^Call to undefined method (\S+)::(\w+)#', $message, $m)) {
			$hint = self::getSuggestion(get_class_methods($m[1]), $m[2]);
			$message .= ", did you mean $hint()?";

		} elseif (preg_match('#^Undefined variable: (\w+)#', $message, $m) && !empty($e->context)) {
			$hint = self::getSuggestion(array_keys($e->context), $m[1]);
			$message = "Undefined variable $$m[1], did you mean $$hint?";

		} elseif (preg_match('#^Undefined property: (\S+)::\$(\w+)#', $message, $m)) {
			$rc = new \ReflectionClass($m[1]);
			$items = array_diff($rc->getProperties(\ReflectionProperty::IS_PUBLIC), $rc->getProperties(\ReflectionProperty::IS_STATIC));
			$hint = self::getSuggestion($items, $m[2]);
			$message .= ", did you mean $$hint?";

		} elseif (preg_match('#^Access to undeclared static property: (\S+)::\$(\w+)#', $message, $m)) {
			$rc = new \ReflectionClass($m[1]);
			$items = array_intersect($rc->getProperties(\ReflectionProperty::IS_PUBLIC), $rc->getProperties(\ReflectionProperty::IS_STATIC));
			$hint = self::getSuggestion($items, $m[2]);
			$message .= ", did you mean $$hint?";
		}

		if (isset($hint)) {
			$ref = new \ReflectionProperty($e, 'message');
			$ref->setAccessible(TRUE);
			$ref->setValue($e, $message);
		}
	}

	/**
	 * Finds the best suggestion.
	 * @return string|NULL
	 * @internal
	 */
	public static function getSuggestion(array $items, $value)
	{
		$best = NULL;
		$min = (strlen($value) / 4 + 1) * 10 + .1;
		foreach (array_unique($items, SORT_REGULAR) as $item) {
			$item = is_object($item) ? $item->getName() : $item;
			if (($len = levenshtein($item, $value, 10, 11, 10)) > 0 && $len < $min) {
				$min = $len;
				$best = $item;
			}
		}
		return $best;
	}

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

/**
 * Custom output for Debugger.
 */
interface IBarPanel
{

	/**
	 * Renders HTML code for custom tab.
	 * @return string
	 */
	function getTab();

	/**
	 * Renders HTML code for custom panel.
	 * @return string
	 */
	function getPanel();

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

/**
 * Logger.
 */
interface ILogger
{
	const
		DEBUG = 'debug',
		INFO = 'info',
		WARNING = 'warning',
		ERROR = 'error',
		EXCEPTION = 'exception',
		CRITICAL = 'critical';

	function log($value, $priority = self::INFO);

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

/**
 * Logger.
 */
class Logger implements ILogger
{
	/** @var string name of the directory where errors should be logged */
	public $directory;

	/** @var string|array email or emails to which send error notifications */
	public $email;

	/** @var string sender of email notifications */
	public $fromEmail;

	/** @var mixed interval for sending email is 2 days */
	public $emailSnooze = '2 days';

	/** @var callable handler for sending emails */
	public $mailer;

	/** @var BlueScreen */
	private $blueScreen;

	public function __construct($directory, $email = NULL, BlueScreen $blueScreen = NULL)
	{
		$this->directory = $directory;
		$this->email = $email;
		$this->blueScreen = $blueScreen;
		$this->mailer = array($this, 'defaultMailer');
	}

	/**
	 * Logs message or exception to file and sends email notification.
	 * @param  string|\Exception|\Throwable
	 * @param  int   one of constant ILogger::INFO, WARNING, ERROR (sends email), EXCEPTION (sends email), CRITICAL (sends email)
	 * @return string logged error filename
	 */
	public function log($message, $priority = self::INFO)
	{
		if (!$this->directory) {
			throw new \LogicException('Directory is not specified.');
		} elseif (!is_dir($this->directory)) {
			throw new \RuntimeException("Directory '$this->directory' is not found or is not directory.");
		}

		$exceptionFile = $message instanceof \Exception || $message instanceof \Throwable
			? $this->getExceptionFile($message)
			: NULL;
		$line = $this->formatLogLine($message, $exceptionFile);
		$file = $this->directory . '/' . strtolower($priority ?: self::INFO) . '.log';

		if (!@file_put_contents($file, $line . PHP_EOL, FILE_APPEND | LOCK_EX)) { // @ is escalated to exception
			throw new \RuntimeException("Unable to write to log file '$file'. Is directory writable?");
		}

		if ($exceptionFile) {
			$this->logException($message, $exceptionFile);
		}

		if (in_array($priority, array(self::ERROR, self::EXCEPTION, self::CRITICAL), TRUE)) {
			$this->sendEmail($message);
		}

		return $exceptionFile;
	}

	/**
	 * @param  string|\Exception|\Throwable
	 * @return string
	 */
	protected function formatMessage($message)
	{
		if ($message instanceof \Exception || $message instanceof \Throwable) {
			while ($message) {
				$tmp[] = ($message instanceof \ErrorException
					? Helpers::errorTypeToString($message->getSeverity()) . ': ' . $message->getMessage()
					: Helpers::getClass($message) . ': ' . $message->getMessage()
				) . ' in ' . $message->getFile() . ':' . $message->getLine();
				$message = $message->getPrevious();
			}
			$message = implode($tmp, "\ncaused by ");

		} elseif (!is_string($message)) {
			$message = Dumper::toText($message);
		}

		return trim($message);
	}

	/**
	 * @param  string|\Exception|\Throwable
	 * @return string
	 */
	protected function formatLogLine($message, $exceptionFile = NULL)
	{
		return implode(' ', array(
			@date('[Y-m-d H-i-s]'), // @ timezone may not be set
			preg_replace('#\s*\r?\n\s*#', ' ', $this->formatMessage($message)),
			' @  ' . Helpers::getSource(),
			$exceptionFile ? ' @@  ' . basename($exceptionFile) : NULL,
		));
	}

	/**
	 * @param  \Exception|\Throwable
	 * @return string
	 */
	public function getExceptionFile($exception)
	{
		$dir = strtr($this->directory . '/', '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR);
		$hash = substr(md5(preg_replace('~(Resource id #)\d+~', '$1', $exception)), 0, 10);
		foreach (new \DirectoryIterator($this->directory) as $file) {
			if (strpos($file, $hash)) {
				return $dir . $file;
			}
		}
		return $dir . 'exception--' . @date('Y-m-d--H-i') . "--$hash.html"; // @ timezone may not be set
	}

	/**
	 * Logs exception to the file if file doesn't exist.
	 * @param  \Exception|\Throwable
	 * @return string logged error filename
	 */
	protected function logException($exception, $file = NULL)
	{
		$file = $file ?: $this->getExceptionFile($exception);
		if ($handle = @fopen($file, 'x')) { // @ file may already exist
			ob_start(); // double buffer prevents sending HTTP headers in some PHP
			ob_start(function ($buffer) use ($handle) { fwrite($handle, $buffer); }, 4096);
			$bs = $this->blueScreen ?: new BlueScreen;
			$bs->render($exception);
			ob_end_flush();
			ob_end_clean();
			fclose($handle);
		}
		return $file;
	}

	/**
	 * @param  string|\Exception|\Throwable
	 * @return void
	 */
	protected function sendEmail($message)
	{
		$snooze = is_numeric($this->emailSnooze)
			? $this->emailSnooze
			: @strtotime($this->emailSnooze) - time(); // @ timezone may not be set

		if ($this->email && $this->mailer
			&& @filemtime($this->directory . '/email-sent') + $snooze < time() // @ file may not exist
			&& @file_put_contents($this->directory . '/email-sent', 'sent') // @ file may not be writable
		) {
			call_user_func($this->mailer, $message, implode(', ', (array) $this->email));
		}
	}

	/**
	 * Default mailer.
	 * @param  string|\Exception|\Throwable
	 * @param  string
	 * @return void
	 * @internal
	 */
	public function defaultMailer($message, $email)
	{
		$host = preg_replace('#[^\w.-]+#', '', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : php_uname('n'));
		$parts = str_replace(
			array("\r\n", "\n"),
			array("\n", PHP_EOL),
			array(
				'headers' => implode("\n", array(
					'From: ' . ($this->fromEmail ?: "noreply@$host"),
					'X-Mailer: Tracy',
					'Content-Type: text/plain; charset=UTF-8',
					'Content-Transfer-Encoding: 8bit',
				)) . "\n",
				'subject' => "PHP: An error occurred on the server $host",
				'body' => $this->formatMessage($message) . "\n\nsource: " . Helpers::getSource(),
			)
		);

		mail($email, $parts['subject'], $parts['body'], $parts['headers']);
	}

}


code:
<?php

/**
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

/**
 * Debugger for outputs.
 */
class OutputDebugger
{
	const BOM = "\xEF\xBB\xBF";

	/** @var array of [file, line, output, stack] */
	private $list = array();

	public static function enable()
	{
		$me = new static;
		$me->start();
	}

	public function start()
	{
		foreach (get_included_files() as $file) {
			if (fread(fopen($file, 'r'), 3) === self::BOM) {
				$this->list[] = array($file, 1, self::BOM);
			}
		}
		ob_start(array($this, 'handler'), PHP_VERSION_ID >= 50400 ? 1 : 2);
	}

	/** @internal */
	public function handler($s, $phase)
	{
		$trace = debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE);
		if (isset($trace[0]['file'], $trace[0]['line'])) {
			$stack = $trace;
			unset($stack[0]['line'], $stack[0]['args']);
			$i = count($this->list);
			if ($i && $this->list[$i - 1][3] === $stack) {
				$this->list[$i - 1][2] .= $s;
			} else {
				$this->list[] = array($trace[0]['file'], $trace[0]['line'], $s, $stack);
			}
		}
		if ($phase === PHP_OUTPUT_HANDLER_FINAL) {
			return $this->renderHtml();
		}
	}

	private function renderHtml()
	{
		$res = '';
		foreach ($this->list as $item) {
			$stack = array();
			foreach (array_slice($item[3], 1) as $t) {
				$t += array('class' => '', 'type' => '', 'function' => '');
				$stack[] = "$t[class]$t[type]$t[function]()"
					. (isset($t['file'], $t['line']) ? ' in ' . basename($t['file']) . ":$t[line]" : '');
			}

			$res .= Helpers::editorLink($item[0], $item[1]) . ' '
				. ''
				. str_replace(self::BOM, '<big>BOM</big>', Dumper::toHtml($item[2]))
				. "
\n";
		}
		return $res . '';
	}

}


code:
/**
 * This file is part of the Tracy (https://tracy.nette.org)
 */

/* common styles */
#tracy-debug {
	display: none;
	direction: ltr;
}

body#tracy-debug {
	margin: 5px 5px 0;
	display: block;
}

body #tracy-debug {
	position: absolute;
	bottom: 0;
	right: 0;
}

#tracy-debug * {
	font: inherit;
	color: inherit;
	background: transparent;
	margin: 0;
	padding: 0;
	border: none;
	text-align: inherit;
	list-style: inherit;
	opacity: 1;
	border-radius: 0;
	box-shadow: none;
	text-shadow: none;
}

#tracy-debug b, #tracy-debug strong {
	font-weight: bold;
}

#tracy-debug i, #tracy-debug em {
	font-style: italic;
}

#tracy-debug a {
	color: #125EAE;
	text-decoration: none;
}

#tracy-debug .tracy-panel a {
	color: #125EAE;
	text-decoration: none;
}

#tracy-debug a:hover, #tracy-debug a:active, #tracy-debug a:focus {
	background-color: #125EAE;
	color: white;
}

#tracy-debug .tracy-panel h2, #tracy-debug .tracy-panel h3, #tracy-debug .tracy-panel p {
	margin: .4em 0;
}

#tracy-debug .tracy-panel table {
	border-collapse: collapse;
	background: #FDF5CE;
}

#tracy-debug .tracy-panel tr:nth-child(2n) td {
	background: #F7F0CB;
}

#tracy-debug .tracy-panel td, #tracy-debug .tracy-panel th {
	border: 1px solid #E6DFBF;
	padding: 2px 5px;
	vertical-align: top;
	text-align: left;
}

#tracy-debug .tracy-panel th {
	background: #F4F3F1;
	color: #655E5E;
	font-size: 90%;
	font-weight: bold;
}

#tracy-debug .tracy-panel pre, #tracy-debug .tracy-panel code {
	font: 9pt/1.5 Consolas, monospace;
}

#tracy-debug table .tracy-right {
	text-align: right;
}

/* bar */
#tracy-debug-bar {
	font: normal normal 13px/1.55 Tahoma, sans-serif;
	color: #333;
	border: 1px solid #c9c9c9;
	background: #EDEAE0 url('data:image/png;base64,R0lGODlhAQAUALMAAOzq4e/t5e7s4/Dt5vDu5e3r4vDu5uvp4O/t5AAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABABQAAAQM0EgySEAYi1LA+UcEADs=') top;
	background-size: 1em;
	position: fixed;
	right: 0;
	bottom: 0;

	min-width: 50px;
	white-space: nowrap;

	z-index: 30000;
	opacity: .9;
	transition: opacity 0.2s;

	border-radius: 3px;
	box-shadow: 1px 1px 10px rgba(0, 0, 0, .15);
}

#tracy-debug-bar:hover {
	opacity: 1;
	transition: opacity 0.1s;
}

#tracy-debug-bar ul {
	list-style: none none;
	clear: left;
}

#tracy-debug-bar li {
	float: left;
}

#tracy-debug-bar ul.tracy-previous li {
	opacity: .6;
	background: #F5F3EE;
}

#tracy-debug-bar ul.tracy-previous li:first-child {
	width: 4.1em;
	text-align: right;
}

#tracy-debug-bar img {
	vertical-align: bottom;
	position: relative;
	top: -2px;
}

#tracy-debug-bar svg {
	vertical-align: bottom;
	width: 1.23em;
	height: 1.55em;
}

#tracy-debug-bar .tracy-label {
	margin-left: .2em;
}

#tracy-debug-bar li > a, #tracy-debug-bar li > span {
	color: #000;
	display: block;
	padding: 0 .4em;
}

#tracy-debug-bar li > a:hover {
	color: black;
	background: #c3c1b8;
}

#tracy-debug-logo {
	cursor: move;
}

#tracy-debug-logo svg {
	width: 3.4em;
	margin: 0 .2em 0 .5em;
}

/* panels */
#tracy-debug .tracy-panel {
	font: normal normal 12px/1.5 sans-serif;
	background: white;
	color: #333;
	text-align: left;
	z-index: 20001;
}

#tracy-debug h1 {
	font: normal normal 23px/1.4 Tahoma, sans-serif;
	color: #575753;
	margin: -5px -5px 5px;
	padding: 0 25px 5px 5px;
	max-width: 700px;
	word-wrap: break-word;
}

#tracy-debug .tracy-mode-peek .tracy-inner, #tracy-debug .tracy-mode-float .tracy-inner {
	max-width: 700px;
	max-height: 500px;
	overflow: auto;
}

#tracy-debug .tracy-panel .tracy-icons {
	display: none;
}

#tracy-debug .tracy-mode-peek {
	display: none;
	position: fixed;
	right: 0;
	bottom: 0;
	padding: 10px;
	min-width: 150px;
	min-height: 50px;
	border-radius: 5px;
	box-shadow: 1px 1px 20px rgba(102, 102, 102, 0.36);
	border: 1px solid rgba(0, 0, 0, 0.1);
}

#tracy-debug .tracy-mode-peek h1 {
	cursor: move;
}

#tracy-debug .tracy-mode-float {
	position: fixed;
	right: 0;
	bottom: 0;
	padding: 10px;
	min-width: 150px;
	min-height: 50px;
	border-radius: 5px;
	opacity: .95;
	transition: opacity 0.2s;
	box-shadow: 1px 1px 30px rgba(102, 102, 102, 0.36);
	border: 1px solid rgba(0, 0, 0, 0.1);
}

#tracy-debug .tracy-focused {
	opacity: 1;
	transition: opacity 0.1s;
}

#tracy-debug .tracy-mode-float h1 {
	cursor: move;
}

#tracy-debug .tracy-mode-float .tracy-icons {
	display: block;
	position: absolute;
	top: 0;
	right: 5px;
	font-size: 18px;
}

#tracy-debug .tracy-icons a {
	color: #575753;
}

#tracy-debug .tracy-icons a:hover {
	color: white;
}

/* dump */
#tracy-debug pre.tracy-dump div {
	padding-left: 3ex;
}

#tracy-debug pre.tracy-dump div div {
	border-left: 1px solid rgba(0, 0, 0, .1);
	margin-left: .5ex;
}

#tracy-debug pre.tracy-dump {
	background: #FDF5CE;
	padding: .4em .7em;
	border: 1px dotted silver;
	overflow: auto;
}

#tracy-debug table pre.tracy-dump {
	padding: 0;
	margin: 0;
	border: none;
}

#tracy-debug .tracy-dump-array, #tracy-debug .tracy-dump-object {
	color: #C22;
}

#tracy-debug .tracy-dump-string {
	color: #35D;
}

#tracy-debug .tracy-dump-number {
	color: #090;
}

#tracy-debug .tracy-dump-null, #tracy-debug .tracy-dump-bool {
	color: #850;
}

#tracy-debug .tracy-dump-visibility, #tracy-debug .tracy-dump-hash {
	font-size: 85%; color: #999;
}

#tracy-debug .tracy-dump-indent {
	display: none;
}

@media print {
	#tracy-debug * {
		display: none;
	}
}


code:
/**
 * This file is part of the Tracy (https://tracy.nette.org)
 */

(function(){
	Tracy = window.Tracy || {};

	var Panel = Tracy.DebugPanel = function(id) {
		this.id = 'tracy-debug-panel-' + id;
		this.elem = document.getElementById(this.id);
		this.elem.Tracy = this.elem.Tracy || {};
	};

	Panel.PEEK = 'tracy-mode-peek';
	Panel.FLOAT = 'tracy-mode-float';
	Panel.WINDOW = 'tracy-mode-window';
	Panel.FOCUSED = 'tracy-focused';
	Panel.zIndex = 20000;

	Panel.prototype.init = function() {
		var _this = this, elem = this.elem;

		elem.Tracy.onMove = function(coords) {
			_this.moveConstrains(this, coords);
		};

		draggable(elem, {
			rightEdge: true,
			bottomEdge: true,
			handle: elem.querySelector('h1'),
			stop: function() {
				_this.toFloat();
			}
		});

		elem.addEventListener('mouseover', function(e) {
			if (isTargetChanged(e.relatedTarget, this)) {
				_this.focus();
			}
		});

		elem.addEventListener('mouseout', function(e) {
			if (isTargetChanged(e.relatedTarget, this)) {
				_this.blur();
			}
		});

		elem.addEventListener('click', function() {
			_this.oldPosition = getPosition(elem);
		});

		document.documentElement.addEventListener('click', function() {
			if (_this.oldPosition) {
				var pos = getPosition(elem);
				setPosition(elem, {
					right: pos.right - pos.width + _this.oldPosition.width,
					bottom: pos.bottom - pos.height + _this.oldPosition.height
				});
			}
			_this.oldPosition = null;
		});

		[].forEach.call(elem.querySelectorAll('.tracy-icons a'), function(a) {
			a.addEventListener('click', function(e) {
				if (this.rel === 'close') {
					_this.toPeek();
				} else {
					_this.toWindow();
				}
				e.preventDefault();
			});
		});

		this.restorePosition();
	};

	Panel.prototype.is = function(mode) {
		return this.elem.classList.contains(mode);
	};

	Panel.prototype.focus = function(callback) {
		var elem = this.elem;
		if (this.is(Panel.WINDOW)) {
			elem.Tracy.window.focus();
		} else {
			clearTimeout(elem.Tracy.displayTimeout);
			elem.Tracy.displayTimeout = setTimeout(function() {
				elem.classList.add(Panel.FOCUSED);
				elem.style.display = 'block';
				elem.style.zIndex = Panel.zIndex++;
				if (callback) {
					callback();
				}
			}, 50);
		}
	};

	Panel.prototype.blur = function() {
		var elem = this.elem;
		elem.classList.remove(Panel.FOCUSED);
		if (this.is(Panel.PEEK)) {
			clearTimeout(elem.Tracy.displayTimeout);
			elem.Tracy.displayTimeout = setTimeout(function() {
				elem.style.display = 'none';
			}, 50);
		}
	};

	Panel.prototype.toFloat = function() {
		this.elem.classList.remove(Panel.WINDOW);
		this.elem.classList.remove(Panel.PEEK);
		this.elem.classList.add(Panel.FLOAT);
		this.elem.style.display = 'block';
		this.reposition();
	};

	Panel.prototype.toPeek = function() {
		this.elem.classList.remove(Panel.WINDOW);
		this.elem.classList.remove(Panel.FLOAT);
		this.elem.classList.add(Panel.PEEK);
		this.elem.style.display = 'none';
		localStorage.removeItem(this.id); // delete position
	};

	Panel.prototype.toWindow = function() {
		var offset = getOffset(this.elem);
		offset.left += typeof window.screenLeft === 'number' ? window.screenLeft : (window.screenX + 10);
		offset.top += typeof window.screenTop === 'number' ? window.screenTop : (window.screenY + 50);

		var win = window.open('', this.id.replace(/-/g, '_'), 'left=' + offset.left + ',top=' + offset.top
			+ ',width=' + this.elem.offsetWidth + ',height=' + (this.elem.offsetHeight + 15) + ',resizable=yes,scrollbars=yes');
		if (!win) {
			return;
		}

		var doc = win.document;
		doc.write('<!DOCTYPE html><meta charset="utf-8"><style>'
			+ document.getElementById('tracy-debug-style').innerHTML
			+ '<\/style><script>'
			+ document.getElementById('tracy-debug-script').innerHTML
			+ '<\/script><body id="tracy-debug">'
		);
		doc.body.innerHTML = '<div class="tracy-panel tracy-mode-window" id="' + this.id + '">' + this.elem.innerHTML + '<\/div>';
		var winPanel = win.Tracy.Debug.getPanel(this.id);
		win.Tracy.Dumper.init();
		if (this.elem.querySelector('h1')) {
			doc.title = this.elem.querySelector('h1').innerHTML;
		}

		var _this = this;
		win.addEventListener('beforeunload', function() {
			_this.toPeek();
			win.close(); // forces closing, can be invoked by F5
		});

		doc.addEventListener('keyup', function(e) {
			if (e.keyCode === 27 && !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey) {
				win.close();
			}
		});

		localStorage.setItem(this.id, JSON.stringify({window: true}));
		this.elem.style.display = 'none';
		this.elem.classList.remove(Panel.FLOAT);
		this.elem.classList.remove(Panel.PEEK);
		this.elem.classList.add(Panel.WINDOW);
		this.elem.Tracy.window = win;
	};

	Panel.prototype.reposition = function() {
		if (!this.is(Panel.WINDOW)) {
			var pos = getPosition(this.elem);
			if (pos.width) { // is visible?
				setPosition(this.elem, {right: pos.right, bottom: pos.bottom});
				localStorage.setItem(this.id, JSON.stringify({right: pos.right, bottom: pos.bottom}));
			}
		}
	};

	Panel.prototype.moveConstrains = function(el, coords) { // forces constrained inside window
		var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
			height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
		coords.right = Math.min(Math.max(coords.right, -0.2 * el.offsetWidth), width - 0.8 * el.offsetWidth);
		coords.bottom = Math.min(Math.max(coords.bottom, -0.2 * el.offsetHeight), height - el.offsetHeight);
	};

	Panel.prototype.restorePosition = function() {
		var pos = JSON.parse(localStorage.getItem(this.id));
		if (!pos) {
			this.elem.classList.add(Panel.PEEK);
		} else if (pos.window) {
			this.toWindow();
		} else if (this.elem.querySelector('*')) {
			setPosition(this.elem, pos);
			this.toFloat();
		}
	};

	var Bar = Tracy.DebugBar = function() {
	};

	Bar.prototype.id = 'tracy-debug-bar';

	Bar.prototype.init = function() {
		var elem = document.getElementById(this.id), _this = this;

		elem.Tracy = {};
		elem.Tracy.onMove = function(coords) {
			_this.moveConstrains(this, coords);
		};

		draggable(elem, {
			rightEdge: true,
			bottomEdge: true,
			draggedClass: 'tracy-dragged',
			stop: function() {
				_this.savePosition();
			}
		});

		[].forEach.call(elem.querySelectorAll('a'), function(a) {
			a.addEventListener('click', function(e) {
				if (this.rel === 'close') {
					_this.close();

				} else if (this.rel) {
					var panel = Debug.getPanel(this.rel);
					if (e.shiftKey) {
						panel.toFloat();
						panel.toWindow();

					} else if (panel.is(Panel.FLOAT)) {
						panel.toPeek();

					} else {
						panel.toFloat();
						setPosition(panel.elem, {
							right: getPosition(panel.elem).right + Math.round(Math.random() * 100) + 20,
							bottom: getPosition(panel.elem).bottom + Math.round(Math.random() * 100) + 20
						});
						panel.reposition();
					}
				}
				e.preventDefault();
			});

			a.addEventListener('mouseover', function(e) {
				if (isTargetChanged(e.relatedTarget, this) && this.rel && this.rel !== 'close' && !elem.classList.contains('tracy-dragged')) {
					var panel = Debug.getPanel(this.rel), link = this;
					panel.focus(function() {
						if (panel.is(Panel.PEEK)) {
							var pos = getPosition(panel.elem);
							setPosition(panel.elem, {
								right: pos.right - getOffset(link).left + pos.width - getPosition(link).width - 4 + getOffset(panel.elem).left,
								bottom: pos.bottom - getOffset(elem).top + pos.height + 4 + getOffset(panel.elem).top
							});
						}
					});
				}
			});

			a.addEventListener('mouseout', function(e) {
				if (isTargetChanged(e.relatedTarget, this) && this.rel && this.rel !== 'close' && !elem.classList.contains('tracy-dragged')) {
					Debug.getPanel(this.rel).blur();
				}
			});
		});

		this.restorePosition();
	};

	Bar.prototype.close = function() {
		document.getElementById('tracy-debug').style.display = 'none';
	};

	Bar.prototype.moveConstrains = function(el, coords) { // forces constrained inside window
		var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
			height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
		coords.right = Math.min(Math.max(coords.right, 0), width - el.offsetWidth);
		coords.bottom = Math.min(Math.max(coords.bottom, 0), height - el.offsetHeight);
	};

	Bar.prototype.savePosition = function() {
		var pos = getPosition(document.getElementById(this.id));
		localStorage.setItem(this.id, JSON.stringify({right: pos.right, bottom: pos.bottom}));
	};

	Bar.prototype.restorePosition = function() {
		var pos = JSON.parse(localStorage.getItem(this.id));
		if (pos) {
			setPosition(document.getElementById(this.id), pos);
		}
	};

	var Debug = Tracy.Debug = {};

	Debug.init = function() {
		Debug.initResize();
		(new Bar).init();
		[].forEach.call(document.querySelectorAll('.tracy-panel'), function(panel) {
			Debug.getPanel(panel.id).init();
		});
	};

	Debug.getPanel = function(id) {
		return new Panel(id.replace('tracy-debug-panel-', ''));
	};

	Debug.initResize = function() {
		window.addEventListener('resize', function() {
			var bar = document.getElementById(Bar.prototype.id);
			setPosition(bar, {right: getPosition(bar).right, bottom: getPosition(bar).bottom});
			[].forEach.call(document.querySelectorAll('.tracy-panel'), function(panel) {
				Debug.getPanel(panel.id).reposition();
			});
		});
	};

	// emulate mouseenter & mouseleave
	function isTargetChanged(target, dest) {
		while (target) {
			if (target === dest) {
				return;
			}
			target = target.parentNode;
		}
		return true;
	}

	var dragging;

	function draggable(elem, options) {
		var dE = document.documentElement, started, pos, deltaX, deltaY;
		options = options || {};

		var onmousemove = function(e) {
			if (e.buttons === 0) {
				return onmouseup(e);
			}
			if (!started) {
				if (options.draggedClass) {
					elem.classList.add(options.draggedClass);
				}
				if (options.start) {
					options.start(e, elem);
				}
				started = true;
			}

			var pos = {};
			pos[options.rightEdge ? 'right' : 'left'] = options.rightEdge ? deltaX - e.clientX : e.clientX + deltaX;
			pos[options.bottomEdge ? 'bottom' : 'top'] = options.bottomEdge ? deltaY - e.clientY : e.clientY + deltaY;
			setPosition(elem, pos);
			return false;
		};

		var onmouseup = function(e) {
			if (started) {
				if (options.draggedClass) {
					elem.classList.remove(options.draggedClass);
				}
				if (options.stop) {
					options.stop(e, elem);
				}
			}
			dragging = null;
			dE.removeEventListener('mousemove', onmousemove);
			dE.removeEventListener('mouseup', onmouseup);
			return false;
		};

		(options.handle || elem).addEventListener('mousedown', function(e) {
			e.preventDefault();
			e.stopPropagation();

			if (dragging) { // missed mouseup out of window?
				return onmouseup(e);
			}

			pos = getPosition(elem);
			deltaX = options.rightEdge ? pos.right + e.clientX : pos.left - e.clientX;
			deltaY = options.bottomEdge ? pos.bottom + e.clientY : pos.top - e.clientY;
			dragging = true;
			started = false;
			dE.addEventListener('mousemove', onmousemove);
			dE.addEventListener('mouseup', onmouseup);
		});

		(options.handle || elem).addEventListener('click', function(e) {
			if (started) {
				e.stopImmediatePropagation();
			}
		});
	}

	// returns total offset for element
	function getOffset(elem) {
		var res = {left: elem.offsetLeft, top: elem.offsetTop};
		while (elem = elem.offsetParent) {
			res.left += elem.offsetLeft; res.top += elem.offsetTop;
		}
		return res;
	}

	// move to new position
	function setPosition(elem, coords) {
		if (elem.Tracy && elem.Tracy.onMove) {
			elem.Tracy.onMove.call(elem, coords);
		}
		for (var item in coords) {
			elem.style[item] = coords[item] + 'px';
		}
	}

	// returns current position
	function getPosition(elem) {
		return {
			left: elem.offsetLeft,
			top: elem.offsetTop,
			right: elem.style.right ? parseInt(elem.style.right, 10) : 0,
			bottom: elem.style.bottom ? parseInt(elem.style.bottom, 10) : 0,
			width: elem.offsetWidth,
			height: elem.offsetHeight
		};
	}

})();


code:
<?php

/**
 * Debug Bar screen template.
 *
 * It uses Font Awesome by Dave Gandy - http://fontawesome.io
 *
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 *
 * @param  array $panels
 * @param  array $info
 * @param  array $liveData
 * @return void
 */

namespace Tracy;

use Tracy;

?>

<?php ob_start() ?>

<?php foreach ($panels as $panel): if (!empty($panel['previous'])) continue ?>
	<div class="tracy-panel" id="tracy-debug-panel-<?php echo $panel['id'] ?>">
		<?php if ($panel['panel']): echo $panel['panel'] ?>

			¤
			×

		<?php endif ?>

<?php endforeach ?>

		<li id="tracy-debug-logo" title="Tracy Debugger <?php echo Debugger::VERSION, " \nhttps://tracy.nette.org" ?>">
			<svg viewBox="0 -10 1561 333"><path fill="#585755" d="m176 327h-57v-269h-119v-57h291v57h-115v269zm208-191h114c50 0 47-78 0-78h-114v78zm106-135c17 0 33 2 46 7 75 30 75 144 1 175-13 6-29 8-47 8h-27l132 74v68l-211-128v122h-57v-326h163zm300 57c-5 0-9 3-11 9l-56 156h135l-55-155c-2-7-6-10-13-10zm-86 222l-17 47h-61l102-285c20-56 107-56 126 0l102 285h-61l-17-47h-174zm410 47c-98 0-148-55-148-163v-2c0-107 50-161 149-161h118v57h-133c-26 0-45 8-58 25-12 17-19 44-19 81 0 71 26 106 77 106h133v57h-119zm270-145l-121-181h68l81 130 81-130h68l-121 178v148h-56v-145z"/></svg>

		<?php foreach ($panels as $panel): if (!$panel['tab']) continue; ?>
		<?php if (!empty($panel['previous'])) echo '

'; ?>

<?php if ($panel['panel']): ?><a href="#" rel="<?php echo $panel['id'] ?>"><?php echo trim($panel['tab']) ?><?php else: echo '', trim($panel['tab']), ''; endif ?>

		<?php endforeach ?>

×

<?php $output = ob_get_clean(); ?>


code:
<?php

/**
 * Debug Bar: panel "dumps" template.
 *
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

use Tracy;

?>

Dumps

<?php foreach ($data as $item): ?>
	<?php if ($item['title']):?>

<?php echo htmlspecialchars($item['title'], ENT_NOQUOTES, 'UTF-8') ?>

	<?php endif ?>

	<?php echo $item['dump'] ?>
<?php endforeach ?>


code:
<?php

/**
 * Debug Bar: panel "error" template.
 *
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

use Tracy;
?>

Errors

<?php foreach ($data as $item => $count): list($file, $line, $message) = explode('|', $item, 3) ?>

	<?php echo $count ? "$count\xC3\x97" : '' ?>

<?php echo htmlspecialchars($message, ENT_IGNORE, 'UTF-8'), ' in ', Helpers::editorLink($file, $line) ?>

<?php endforeach ?>


code:
<?php

/**
 * Debug Bar: panel "info" template.
 *
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

use Tracy;

if (isset($this->cpuUsage) && $this->time) {
	foreach (getrusage() as $key => $val) {
		$this->cpuUsage[$key] -= $val;
	}
	$userUsage = -round(($this->cpuUsage['ru_utime.tv_sec'] * 1e6 + $this->cpuUsage['ru_utime.tv_usec']) / $this->time / 10000);
	$systemUsage = -round(($this->cpuUsage['ru_stime.tv_sec'] * 1e6 + $this->cpuUsage['ru_stime.tv_usec']) / $this->time / 10000);
}

$info = array_filter(array(
	'Execution time' => str_replace(' ', ' ', number_format($this->time * 1000, 1, '.', ' ')) . ' ms',
	'CPU usage user + system' => isset($userUsage) ? (int) $userUsage . ' % + ' . (int) $systemUsage . ' %' : NULL,
	'Peak of allocated memory' => str_replace(' ', ' ', number_format(memory_get_peak_usage() / 1000000, 2, '.', ' ')) . ' MB',
	'Included files' => count(get_included_files()),
	'Classes + interfaces + traits' => count(get_declared_classes()) . ' + '
		. count(get_declared_interfaces()) . ' + ' . (PHP_VERSION_ID >= 50400 ? count(get_declared_traits()) : '0'),
	'Your IP' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL,
	'Server IP' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : NULL,
	'HHVM' => defined('HHVM_VERSION') ? HHVM_VERSION : NULL,
	'PHP' => PHP_VERSION,
	'Xdebug' => extension_loaded('xdebug') ? phpversion('xdebug') : NULL,
	'Tracy' => Debugger::VERSION,
	'Server' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : NULL,
) + (array) $this->data);

?>

System info

<?php foreach ($info as $key => $val): ?>

<?php if (iconv_strlen($val, 'UTF-8') > 25): ?>
	<?php echo htmlspecialchars($key, NULL, 'UTF-8') ?> <?php echo htmlspecialchars($val, NULL, 'UTF-8') ?>
<?php else: ?>
	<?php echo htmlspecialchars($key, NULL, 'UTF-8') ?>	<?php echo htmlspecialchars($val, NULL, 'UTF-8') ?>
<?php endif ?>

<?php endforeach ?>


code:
<?php

/**
 * Debug Bar: tab "info" template.
 *
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 */

namespace Tracy;

use Tracy;

$this->time = microtime(TRUE) - Debugger::$time;

?>

<svg viewBox="0 0 2048 2048"><path fill="#86bbf0" d="m640 1153.6v639.3h-256v-639.3z"/><path fill="#6ba9e6" d="m1024 254.68v1538.2h-256v-1538.2z"/><path fill="#4f96dc" d="m1408 897.57v894.3h-256v-894.3z"/><path fill="#3987d4" d="m1792 513.08v1279.8h-256v-1279.8z"/>
</svg><?php echo str_replace(' ', ' ', number_format($this->time * 1000, 1, '.', ' ')) ?> ms


code:
/**
 * This file is part of the Tracy (https://tracy.nette.org)
 */

html {
	overflow-y: scroll;
}

#tracy-bs {
	font: 9pt/1.5 Verdana, sans-serif;
	background: white;
	color: #333;
	position: absolute;
	z-index: 20000;
	left: 0;
	top: 0;
	width: 100%;
	text-align: left;
}

#tracy-bs * {
	font: inherit;
	color: inherit;
	background: transparent;
	border: none;
	margin: 0;
	padding: 0;
	text-align: inherit;
	text-indent: 0;
}

#tracy-bs b {
	font-weight: bold;
}

#tracy-bs i {
	font-style: italic;
}

#tracy-bs a {
	text-decoration: none;
	color: #328ADC;
	padding: 2px 4px;
	margin: -2px -4px;
}

#tracy-bs a:hover, #tracy-bs a:active, #tracy-bs a:focus {
	color: #085AA3;
}

#tracy-bs-toggle {
	position: absolute;
	right: .5em;
	top: .5em;
	text-decoration: none;
	background: #CD1818;
	color: white !important;
	padding: 3px;
}

#tracy-bs-error {
	background: #CD1818;
	color: white;
	font: 13pt/1.5 Verdana, sans-serif !important;
}

#tracy-bs-error a {
	color: white !important;
	opacity: 0;
	font-size: .7em;
}

#tracy-bs-error:hover a {
	opacity: .6;
}

#tracy-bs-error a:hover {
	opacity: 1;
}

#tracy-bs-ie-warning {
	background: black;
	margin: 1em;
	padding: .5em;
	text-align: center;
}

#tracy-bs h1 {
	font-size: 15pt;
	font-weight: normal;
	text-shadow: 1px 1px 2px rgba(0, 0, 0, .3);
	margin: .7em 0;
}

#tracy-bs h2 {
	font: 14pt/1.5 sans-serif !important;
	margin: .6em 0;
}

#tracy-bs h3 {
	font: bold 10pt/1.5 Verdana, sans-serif !important;
	margin: 1em 0;
	padding: 0;
}

#tracy-bs p, #tracy-bs pre {
	margin: .8em 0
}

#tracy-bs pre, #tracy-bs code, #tracy-bs table {
	font: 9pt/1.5 Consolas, monospace !important;
}

#tracy-bs pre, #tracy-bs table {
	background: #FDF5CE;
	padding: .4em .7em;
	border: 1px dotted silver;
	overflow: auto;
}

#tracy-bs table pre {
	padding: 0;
	margin: 0;
	border: none;
}

#tracy-bs table {
	border-collapse: collapse;
	width: 100%;
}

#tracy-bs td, #tracy-bs th {
	vertical-align: top;
	text-align: left;
	padding: 2px 6px;
	border: 1px solid #e6dfbf;
}

#tracy-bs th {
	font-weight: bold;
}

#tracy-bs tr > :first-child {
	width: 20%;
}

#tracy-bs tr:nth-child(2n), #tracy-bs tr:nth-child(2n) pre {
	background-color: #F7F0CB;
}

#tracy-bs ol {
	margin: 1em 0;
	padding-left: 2.5em;
}

#tracy-bs ul {
	font: 7pt/1.5 Verdana, sans-serif !important;
	padding: 2em 4em;
	margin: 1em 0 0;
	color: #777;
	background: #F6F5F3;
	border-top: 1px solid #DDD;
}

#tracy-bs-logo a {
	position: absolute;
	bottom: 0;
	right: 0;
	width: 100px;
	height: 50px;
	background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAUBAMAAAD/1DctAAAAMFBMVEWupZzj39rEvbTy8O3X0sz9/PvGwLu8tavQysHq6OS0rKP5+Pbd2dT29fPMxbzPx8DKErMJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACGUlEQVQoFX3TQWgTQRQA0MWLIJJDYehBTykhG5ERTx56K1u8eEhCYtomE7x5L4iLh0ViF7egewuFFqSIYE6hIHsIYQ6CQSg9CDKn4QsNCRlB59C74J/ZNHW1+An5+bOPyf6/s46oz2P+A0yIeZZ2ieEHi6TOnLKTxvWq+b52mxlVO3xnM1s7xLX1504XQH65OnW2dBqn7cCkYsFsfYsWpyY/2salmFTpEyzeR8zosYqMdiPDXdyU52K1wgEa/SjGpdEwUAxqvRfckQCDOyFearsEHe2grvkh/cFAHKvdtI3lcVceKQIOFpv+FOZaNPQBwJZLPp+hfrvT5JZXaUFsR8zqQc9qSgAharkfS5M/5F6nGJJAtXq/eLr3ucZpHccSxOOIPaQhtHohpCH2Xu6rLmQ0djnr4/+J3C6v+AW8/XWYxwYNdlhWj/P5fPSTQwVr0T9lGxdaBCqErNZaqYnEwbkjEB3NasGF3lPdrHa1nnxNOMgj0+neePUPjd2v/qVvUv29ifvc19huQ48qwXShy/9o8o3OSk0cs37mOFd0Ydgvsf/oZEnPVtggfd66lORn9mDyyzXU13SRtH2L6aR5T/snGAcZPfAXz5J1YlJWBEuxdMYqQecpBrlM49xAbmqyHA+xlA1FxBtqT2xmJoNXZlIt74ZBLeJ9ZGDqByNI7p543idzJ23vXEv7IgnsxiS+eNtwNbFdLq7+Bi4wQ0I4SVb9AAAAAElFTkSuQmCC') no-repeat;
	opacity: .6;
	padding: 0;
	margin: 0;
}

#tracy-bs-logo a:hover, #tracy-bs-logo a:active, #tracy-bs-logo a:focus {
	opacity: 1;
	transition: opacity 0.1s;
}

#tracy-bs div.panel {
	padding: 1px 25px;
}

#tracy-bs div.inner {
	background: #F4F3F1;
	padding: .1em 1em 1em;
	border-radius: 8px;
}

#tracy-bs .outer {
	overflow: auto;
}

/* source code */
#tracy-bs pre.php div {
	min-width: 100%;
	float: left;
	white-space: pre;
}

#tracy-bs .highlight {
	background: #CD1818;
	color: white;
	font-weight: bold;
	font-style: normal;
	display: block;
	padding: 0 .4em;
	margin: 0 -.4em;
}

#tracy-bs .line {
	color: #9F9C7F;
	font-weight: normal;
	font-style: normal;
}

#tracy-bs pre:hover span[title] {
	border-bottom: 1px solid rgba(0, 0, 0, 0.2);
}

#tracy-bs a[href^=editor\:] {
	color: inherit;
	border-bottom: 1px dotted rgba(0, 0, 0, .3);
}

#tracy-bs span[data-tracy-href] {
	border-bottom: 1px dotted rgba(0, 0, 0, .3);
}

/* toggle */
html.tracy-js #tracy-bs .tracy-collapsed {
	display: none;
}

html.tracy-js #tracy-bs .tracy-toggle.tracy-collapsed {
	display: inline;
}

#tracy-bs .tracy-toggle {
	cursor: pointer;
}

#tracy-bs .tracy-toggle:after {
	content: " ▼";
	opacity: .4;
}

#tracy-bs .tracy-toggle.tracy-collapsed:after {
	content: " ►";
	opacity: .4;
}

/* dump */
#tracy-bs .tracy-dump-array, #tracy-bs .tracy-dump-object {
	color: #C22;
}

#tracy-bs .tracy-dump-string {
	color: #35D;
}

#tracy-bs .tracy-dump-number {
	color: #090;
}

#tracy-bs .tracy-dump-null, #tracy-bs .tracy-dump-bool {
	color: #850;
}

#tracy-bs .tracy-dump-visibility, #tracy-bs .tracy-dump-hash {
	font-size: 85%;
	color: #998;
}

#tracy-bs .tracy-dump-indent {
	display: none;
}

#tracy-bs pre.tracy-dump div {
	padding-left: 3ex;
}

#tracy-bs pre.tracy-dump div div {
	border-left: 1px solid rgba(0, 0, 0, .1);
	margin-left: .5ex;
}

#tracy-bs .caused {
	float: right;
	padding: .3em .6em;
	background: #df8075;
	border-radius: 0 0 0 8px;
	white-space: nowrap;
}

#tracy-bs .caused a {
	color: white;
}


code:
/**
 * This file is part of the Tracy (https://tracy.nette.org)
 */

(function(){
	document.body.appendChild(document.getElementById('tracy-bs'));

	for (var i = 0, styles = []; i < document.styleSheets.length; i++) {
		var style = document.styleSheets[i];
		if (!style.ownerNode.classList.contains('tracy-debug')) {
			style.oldDisabled = style.disabled;
			style.disabled = true;
			styles.push(style);
		}
	}

	document.getElementById('tracy-bs-toggle').addEventListener('click', function(e) {
		var collapsed = this.classList.contains('tracy-collapsed');
		for (i = 0; i < styles.length; i++) {
			styles[i].disabled = collapsed ? true : styles[i].oldDisabled;
		}
	});

	document.addEventListener('keyup', function(e) {
		if (e.keyCode === 27 && !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey) { // ESC
			document.getElementById('tracy-bs-toggle').click();
		}
	});
})();


code:
<?php

/**
 * Debugger bluescreen template.
 *
 * This file is part of the Tracy (https://tracy.nette.org)
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
 *
 * @param  array $exception
 * @param  array $panels
 * @param  array $info
 * @param  string $title
 * @param  string $source
 * @param  bool $sourceIsUrl
 * @param  string $skipError
 * @return void
 */

namespace Tracy;

use Tracy;

$code = $exception->getCode() ? ' #' . $exception->getCode() : '';

?><!DOCTYPE html></script></style>
</xmp>
</address>
</audio></bdi></bdo>
</button></canvas>
</datalist></dfn>

</fieldset>

</form>

</hgroup></legend></map></menu></meter></object>
</optgroup></output></progress></q></rp></rt></ruby></s></samp>
</select></textarea></time></title>

</var></video>

	<meta charset="utf-8">
	<meta name="robots" content="noindex">
	<meta name="generator" content="Tracy by Nette Framework">

	<title><?php echo htmlspecialchars($title . ': ' . $exception->getMessage() . $code, ENT_IGNORE, 'UTF-8') ?></title>
	<?php if ($ex = $exception->getPrevious()): ?>

	<?php endif ?>

			<?php if ($exception->getMessage()): ?>
<?php echo htmlspecialchars($title . $code, ENT_IGNORE, 'UTF-8') ?>
<?php endif ?>

<?php echo htmlspecialchars($exception->getMessage() ?: $title . $code, ENT_IGNORE, 'UTF-8') ?>
			<a href="https://www.google.com/search?sourceid=tracy&q=<?php echo urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>" target="_blank" rel="noreferrer">search►
			<?php if ($skipError): ?><a href="<?php echo htmlSpecialChars($skipError, ENT_IGNORE | ENT_QUOTES, 'UTF-8') ?>">skip error►<?php endif ?>

		<?php if ($prev = $exception->getPrevious()): ?>

			Caused by <?php echo htmlspecialchars(Helpers::getClass($prev), ENT_NOQUOTES, 'UTF-8') ?>

		<?php endif ?>

		<?php $ex = $exception; $level = 0; ?>
		<?php do { ?>

			<?php if ($level++): ?>
			<div class="panel"<?php if ($level === 2) echo ' id="tracyCaused"' ?>>

<a data-tracy-ref="^+" class="tracy-toggle<?php echo ($collapsed = $level > 2) ? ' tracy-collapsed' : '' ?>">Caused by

			<div class="<?php echo $collapsed ? 'tracy-collapsed ' : '' ?>inner">

<?php echo htmlspecialchars(Helpers::getClass($ex) . ($ex->getCode() ? ' #' . $ex->getCode() : ''), ENT_NOQUOTES, 'UTF-8') ?>

<?php echo htmlspecialchars($ex->getMessage(), ENT_IGNORE, 'UTF-8') ?>

			<?php endif ?>

			<?php foreach ($panels as $panel): ?>
			<?php $panel = call_user_func($panel, $ex); if (empty($panel['tab']) || empty($panel['panel'])) continue; ?>
			<?php if (!empty($panel['bottom'])) { continue; } ?>

<?php echo htmlSpecialChars($panel['tab'], ENT_NOQUOTES, 'UTF-8') ?>

				<?php echo $panel['panel'] ?>

			<?php endforeach ?>

			<?php $stack = $ex->getTrace(); $expanded = NULL ?>
			<?php if ((!$exception instanceof \ErrorException || in_array($exception->getSeverity(), array(E_USER_NOTICE, E_USER_WARNING, E_USER_DEPRECATED))) && $this->isCollapsed($ex->getFile())) {
				foreach ($stack as $key => $row) {
					if (isset($row['file']) && !$this->isCollapsed($row['file'])) { $expanded = $key; break; }
				}
			} ?>

<a data-tracy-ref="^+" class="tracy-toggle<?php echo ($collapsed = $expanded !== NULL) ? ' tracy-collapsed' : '' ?>">Source file

			<div class="<?php echo $collapsed ? 'tracy-collapsed ' : '' ?>inner">

File: <?php echo Helpers::editorLink($ex->getFile(), $ex->getLine()) ?>

				<?php if (is_file($ex->getFile())): ?><?php echo self::highlightFile($ex->getFile(), $ex->getLine(), 15, $ex instanceof \ErrorException && isset($ex->context) ? $ex->context : NULL) ?><?php endif ?>

			<?php if (isset($stack[0]['class']) && $stack[0]['class'] === 'Tracy\Debugger' && ($stack[0]['function'] === 'shutdownHandler' || $stack[0]['function'] === 'errorHandler')) unset($stack[0]) ?>
			<?php if ($stack): ?>

Call stack

					<?php foreach ($stack as $key => $row): ?>

					<?php if (isset($row['file']) && is_file($row['file'])): ?>
						<?php echo Helpers::editorLink($row['file'], $row['line']) ?>
					<?php else: ?>
						inner-code<?php if (isset($row['line'])) echo ':', $row['line'] ?>
					<?php endif ?>

					<?php if (isset($row['file']) && is_file($row['file'])): ?><a data-tracy-ref="^p + .file" class="tracy-toggle<?php if ($expanded !== $key) echo ' tracy-collapsed' ?>">source  <?php endif ?>

					<?php
						if (isset($row['object'])) echo "";
						if (isset($row['class'])) echo htmlspecialchars($row['class'] . $row['type'], ENT_NOQUOTES, 'UTF-8');
						if (isset($row['object'])) echo '';
						echo htmlspecialchars($row['function'], ENT_NOQUOTES, 'UTF-8'), '(';
						if (!empty($row['args'])): ?>arguments<?php endif ?>)

					<?php if (isset($row['file']) && is_file($row['file'])): ?>
						<div class="<?php if ($expanded !== $key) echo 'tracy-collapsed ' ?>file"><?php echo self::highlightFile($row['file'], $row['line']) ?>

					<?php endif ?>

					<?php if (isset($row['object'])): ?>

<?php echo Dumper::toHtml($row['object'], array(Dumper::LIVE => TRUE)) ?>

					<?php endif ?>

					<?php if (!empty($row['args'])): ?>

						<?php
						try {
							$r = isset($row['class']) ? new \ReflectionMethod($row['class'], $row['function']) : new \ReflectionFunction($row['function']);
							$params = $r->getParameters();
						} catch (\Exception $e) {
							$params = array();
						}
						foreach ($row['args'] as $k => $v) {
							echo '
', htmlspecialchars(isset($params[$k]) ? '$' . $params[$k]->name : "#$k", ENT_IGNORE, 'UTF-8'), '	';
							echo Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE));
							echo "
\n";
						}
						?>

					<?php endif ?>

					<?php endforeach ?>

			<?php endif ?>

			<?php if ($ex instanceof \ErrorException && isset($ex->context) && is_array($ex->context)):?>

Variables

			<?php
			foreach ($ex->context as $k => $v) {
					echo '
$', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	', Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)), "
\n";
			}
			?>

			<?php endif ?>

		<?php } while ($ex = $ex->getPrevious()); ?>
		<?php while (--$level) echo '

' ?>

		<?php if (count((array) $exception) > count((array) new \Exception)):?>

Exception

		<?php echo Dumper::toHtml($exception, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)) ?>

		<?php endif ?>

		<?php $bottomPanels = array() ?>
		<?php foreach ($panels as $panel): ?>
		<?php $panel = call_user_func($panel, NULL); if (empty($panel['tab']) || empty($panel['panel'])) continue; ?>
		<?php if (!empty($panel['bottom'])) { $bottomPanels[] = $panel; continue; } ?>

<?php echo htmlSpecialChars($panel['tab'], ENT_NOQUOTES, 'UTF-8') ?>

			<?php echo $panel['panel'] ?>

		<?php endforeach ?>

Environment

$_SERVER

			<?php
			foreach ($_SERVER as $k => $v) echo '
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	', Dumper::toHtml($v), "
\n";
			?>

$_SESSION

			<?php if (empty($_SESSION)):?>

empty

			<?php else: ?>

			<?php
			foreach ($_SESSION as $k => $v) echo '
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	', $k === '__NF' ? 'Nette Session' : Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)), "
\n";
			?>

			<?php endif ?>

			<?php if (!empty($_SESSION['__NF']['DATA'])):?>

Nette Session

			<?php
			foreach ($_SESSION['__NF']['DATA'] as $k => $v) echo '
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	', Dumper::toHtml($v, array(Dumper::LOCATION => Dumper::LOCATION_CLASS, Dumper::LIVE => TRUE)), "
\n";
			?>

			<?php endif ?>

			<?php
			$list = get_defined_constants(TRUE);
			if (!empty($list['user'])):?>

Constants

			<?php
			foreach ($list['user'] as $k => $v) {
				echo '
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	';
				echo '', Dumper::toHtml($v), "
\n";
			}
			?>

			<?php endif ?>

Included files (<?php echo count(get_included_files()) ?>)

			<?php
			foreach (get_included_files() as $v) {
				echo '
', htmlspecialchars($v, ENT_IGNORE, 'UTF-8'), "
\n";
			}
			?>

Configuration options

			<?php ob_start(); @phpinfo(INFO_CONFIGURATION | INFO_MODULES); echo preg_replace('#^.+|.+\z#s', '', ob_get_clean()) // @ phpinfo can be disabled ?>

HTTP request

			<?php if (function_exists('apache_request_headers')): ?>

Headers

			<?php
			foreach (apache_request_headers() as $k => $v) echo '
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	', htmlspecialchars($v, ENT_IGNORE, 'UTF-8'), "
\n";
			?>

			<?php endif ?>

			<?php foreach (array('_GET', '_POST', '_COOKIE') as $name): ?>

$<?php echo htmlspecialchars($name, ENT_NOQUOTES, 'UTF-8') ?>

			<?php if (empty($GLOBALS[$name])):?>

empty

			<?php else: ?>

			<?php
			foreach ($GLOBALS[$name] as $k => $v) echo '
', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), '	', Dumper::toHtml($v), "
\n";
			?>

			<?php endif ?>
			<?php endforeach ?>

HTTP response

Headers

			<?php if (headers_list()): ?>

<?php
			foreach (headers_list() as $s) echo htmlspecialchars($s, ENT_IGNORE, 'UTF-8'), '
';
			?>

			<?php else: ?>

no headers

			<?php endif ?>

		<?php foreach ($bottomPanels as $panel): ?>

<?php echo htmlSpecialChars($panel['tab'], ENT_NOQUOTES, 'UTF-8') ?>

			<?php echo $panel['panel'] ?>

		<?php endforeach ?>

Report generated at <?php echo @date('Y/m/d H:i:s') // @ timezone may not be set ?>

<?php if ($sourceIsUrl): ?><a href="<?php echo htmlSpecialChars($source, ENT_IGNORE | ENT_QUOTES, 'UTF-8') ?>"><?php endif ?><?php echo htmlSpecialChars($source, ENT_IGNORE, 'UTF-8') ?><?php if ($sourceIsUrl): ?><?php endif ?>

			<?php foreach ($info as $item): ?>
<?php echo htmlSpecialChars($item, ENT_NOQUOTES, 'UTF-8') ?>
<?php endforeach ?>


code:
<?php

/**
 * Default error page.
 * @param  bool $logged
 */

namespace Tracy;

?>
<!DOCTYPE html></script></style></xmp>
<meta charset="utf-8">
<meta name=robots content=noindex>
<meta name=generator content="Tracy">
<title>Server Error</title>

Server Error

We're sorry! The server encountered an internal error and
	was unable to complete your request. Please try again later.

error 500<?php if (!$logged): ?>
Tracy is unable to log error.<?php endif ?>


code:
/**
 * This file is part of the Tracy (https://tracy.nette.org)
 */

/* toggle */
.tracy-collapsed {
	display: none;
}

.tracy-toggle.tracy-collapsed {
	display: inline;
}

.tracy-toggle {
	cursor: pointer;
}

.tracy-toggle:after {
	content: " ▼";
	opacity: .4;
}

.tracy-toggle.tracy-collapsed:after {
	content: " ►";
}

/* dump */
pre.tracy-dump {
	text-align: left;
	color: #444;
	background: white;
}

pre.tracy-dump div {
	padding-left: 3ex;
}

pre.tracy-dump div div {
	border-left: 1px solid rgba(0, 0, 0, .1);
	margin-left: .5ex;
}

.tracy-dump-array, .tracy-dump-object {
	color: #C22;
}

.tracy-dump-string {
	color: #35D;
}

.tracy-dump-number {
	color: #090;
}

.tracy-dump-null, .tracy-dump-bool {
	color: #850;
}

.tracy-dump-visibility, .tracy-dump-hash {
	font-size: 85%; color: #999;
}

.tracy-dump-indent {
	display: none;
}

span[data-tracy-href] {
	border-bottom: 1px dotted rgba(0, 0, 0, .2);
}