public function run(Request $request = null)
    {
        \ini_set('display_errors', $this->config['debug'] ? 1 : 0);
        \ini_set('display_startup_errors', $this->config['debug'] ? 1 : 0);

        \date_default_timezone_set($this->config['timezone']);

        // map all routes
        foreach ($this->routes as $r => &$x) {
            if (isset($x['controller'])) {

                $this->router->map($x['method'], $r, $x['action'], $x['controller']);

            } else foreach ($x as &$xx) {

                $this->router->map($xx['method'], $r, $xx['action'], $xx['controller']);

            }
        }


        // dispatch
        try {
            try {

                $this->router->dispatch(
                        $request === null ? Request::createFromGlobals() : $request,
                        new class(
                                (new MultiControllerFactory(...$this->controller_factories))->close(),
                                $this->endobox,
                                $this->logger,
                                $this->config['app-namespace']) extends ControllerFactoryDecorator {

                            private $endobox;
                            private $logger;
                            private $namespace;

                            public function __construct(
                                    ControllerFactory $factory,
                                    BoxFactory $endobox,
                                    Logger $logger,
                                    string $namespace) {

                                parent::__construct($factory);
                                $this->endobox = $endobox;
                                $this->logger = $logger;
                                $this->namespace = $namespace;
                            }

                            public function create(string $type) : ?Controller {
                                return parent::create('\\' . $this->namespace . '\\controllers\\' . $type)
                                        ->setBoxFactory($this->endobox)
                                        ->setLogger($this->logger);
                            }

                        });

            } catch (\Klein\Exceptions\UnhandledException $e) {
                // TODO fix this mess with the stack trace being part of the message
                throw new \RuntimeException(\sprintf("%s: %s\n<pre>%s</pre>",
                        \get_class($e), $e->getMessage(), $e->getTraceAsString()), $e->getCode(), $e);
            }
        } catch (\Exception $e) {
            if ($this->config['catch-exceptions'] === false) {
                throw $e;
            }

            if ($this->config['debug'] === true) {
                die(self::formatException($e));
            }
            die();
        }

        return $this;
    }