public function handle($input, IResponse $response = null) : int
    {
        if ($response === null) {
            $response = new ConsoleResponse(new Compiler(new Lexer(), new Parser()));
        }

        try {
            $request = $this->requestParser->parse($input);

            if ($this->isInvokingHelpCommand($request)) {
                // We are going to execute the help command
                $compiledCommand = $this->getCompiledHelpCommand($request);
            } elseif ($this->isInvokingVersionCommand($request)) {
                // We are going to execute the version command
                $compiledCommand = new VersionCommand($this->applicationVersion);
            } elseif ($this->commandCollection->has($request->getCommandName())) {
                // We are going to execute the command that was entered
                $command = $this->commandCollection->get($request->getCommandName());
                $compiledCommand = $this->commandCompiler->compile($command, $request);
            } else {
                // We are defaulting to the about command
                $compiledCommand = new AboutCommand($this->commandCollection, new PaddingFormatter(),
                    $this->applicationVersion);
            }

            $statusCode = $compiledCommand->execute($response);

            if ($statusCode === null) {
                return StatusCodes::OK;
            }

            return $statusCode;
        } catch (InvalidArgumentException $ex) {
            $response->writeln("<error>{$ex->getMessage()}</error>");

            return StatusCodes::ERROR;
        } catch (Exception $ex) {
            $response->writeln("<fatal>{$ex->getMessage()}</fatal>");

            return StatusCodes::FATAL;
        } catch (Throwable $ex) {
            $response->writeln("<fatal>{$ex->getMessage()}</fatal>");

            return StatusCodes::FATAL;
        }
    }