diff --git a/user/plugins/error/CHANGELOG.md b/user/plugins/error/CHANGELOG.md
new file mode 100644
index 0000000..80cd6cb
--- /dev/null
+++ b/user/plugins/error/CHANGELOG.md
@@ -0,0 +1,98 @@
+# v1.8.1
+## 08/28/2025
+
+1. [](#bugfix)
+ * Fixed an issue with error thrown during `bin/plugin error log` commands [#46](https://github.com/getgrav/grav-plugin-error/issues/46)
+ * Fixed output issue not showing all messages with log CLI command
+
+# v1.8.0
+## 09/07/2021
+
+1. [](#new)
+ * Require **Grav 1.7.0**
+ * Added support for `{% throw 404 'Not Found' %}` from twig template to show the error page
+1. [](#improved)
+ * Do not cache 404 error pages by default
+
+# v1.7.1
+## 10/08/2020
+
+1. [](#bugfix)
+ * Fixed error page being cached, fixes issue with non-existing resources which later become available
+
+# v1.7.0
+## 07/01/2020
+
+1. [](#new)
+ * Require Grav v1.6
+1. [](#bugfix)
+ * Added translated title programmatically [#40](https://github.com/getgrav/grav-plugin-error/pull/40)
+
+# v1.6.2
+## 05/09/2019
+
+1. [](#new)
+ * Fixed a few issues found by phpstan
+ * Added `ru` and `uk` translations [#36](https://github.com/getgrav/grav-plugin-error/pull/36)
+
+# v1.6.1
+## 03/09/2018
+
+1. [](#improved)
+ * Added Polish + Catalan translation
+ * Updated `README.md` to reference custom error pages
+
+# v1.6.0
+## 10/19/2016
+
+1. [](#improved)
+ * Added Croatian translation
+ * Improved `autoescape: true` support
+1. [](#bugfix)
+ * Fixed issue where template file for `error` page type is only available if page was not found
+
+# v1.5.1
+## 07/18/2016
+
+1. [](#improved)
+ * Added chinese and german translations
+1. [](#bugfix)
+ * Fixed issue with the Smartypants plugin running before Twig was processed
+
+# v1.5.0
+## 07/14/2015
+
+1. [](#improved)
+ * Translate some blueprint configuration options
+ * Allow translating the error message
+ * Added french, russian, romanian, danish, italian
+
+# v1.4.1
+## 12/11/2015
+
+1. [](#bugfix)
+ * Fixed CLI command for PHP 5.5 and lower
+
+# v1.4.0
+## 11/21/2015
+
+1. [](#new)
+ * Implemented CLI commands for the plugin
+
+# v1.3.0
+## 08/25/2015
+
+1. [](#improved)
+ * Added blueprints for Grav Admin plugin
+
+# v1.2.2
+## 01/06/2015
+
+1. [](#new)
+ * Added a default `error.json.twig` file
+
+# v1.2.1
+## 11/30/2014
+
+1. [](#new)
+ * ChangeLog started...
diff --git a/user/plugins/error/LICENSE b/user/plugins/error/LICENSE
new file mode 100644
index 0000000..484793a
--- /dev/null
+++ b/user/plugins/error/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Grav
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/user/plugins/error/README.md b/user/plugins/error/README.md
new file mode 100644
index 0000000..ef24726
--- /dev/null
+++ b/user/plugins/error/README.md
@@ -0,0 +1,93 @@
+# Grav Error Plugin
+
+
+
+`error` is a [Grav](http://github.com/getgrav/grav) Plugin and allows to redirect errors to nice output pages.
+
+This plugin is included in any package distributed that contains Grav. If you decide to clone Grav from GitHub you will most likely want to install this.
+
+# Installation
+
+Installing the Error plugin can be done in one of two ways. Our GPM (Grav Package Manager) installation method enables you to quickly and easily install the plugin with a simple terminal command, while the manual method enables you to do so via a zip file.
+
+## GPM Installation (Preferred)
+
+The simplest way to install this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm) through your system's Terminal (also called the command line). From the root of your Grav install type:
+
+ bin/gpm install error
+
+This will install the Error plugin into your `/user/plugins` directory within Grav. Its files can be found under `/your/site/grav/user/plugins/error`.
+
+## Manual Installation
+
+To install this plugin, just download the zip version of this repository and unzip it under `/your/site/grav/user/plugins`. Then, rename the folder to `error`. You can find these files either on [GitHub](https://github.com/getgrav/grav-plugin-error) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras).
+
+You should now have all the plugin files under
+
+ /your/site/grav/user/plugins/error
+
+>> NOTE: This plugin is a modular component for Grav which requires [Grav](http://github.com/getgrav/grav), the [Problems](https://github.com/getgrav/grav-plugin-problems) plugin, and a theme to be installed in order to operate.
+
+# Usage
+
+The `error` plugin doesn't require any configuration. The moment you install it, it is ready to use.
+
+Something you might want to do is to override the look and feel of the error page, and with Grav it is super easy.
+
+### Template
+
+Copy the template file [error.html.twig](templates/error.html.twig) into the `templates` folder of your custom theme and that is it.
+
+```
+/your/site/grav/user/themes/custom-theme/templates/error.html.twig
+```
+
+You can now edit the override and tweak it however you prefer.
+
+### Page
+
+Copy the page file [error.md](pages/error.md) into the `pages` folder of your user directory and that is it.
+
+```
+/your/site/grav/user/pages/error/error.md
+```
+
+You can now edit the override and tweak it however you prefer.
+
+# Custom error pages
+
+The configuration allows to specify pages different than `/error` for specific error codes. By default, the `404` error leads to the `/error` page. If you change that, make sure the page you point to has a `error` template (which means, its markdown file is `error.md` or in the page frontmatter you specify `template: error`.
+
+# CLI Usage
+The `error` plugin comes with a CLI command that outputs the `grav.log` in a beautified way, with possibility of limiting the amount of errors displayed, as well as include the trace in the output.
+
+### Commands
+
+| `bin/plugin error log` | |
+|------------------------|-----------------------------------------------------------------|
+| [ --limit N \| -l N ] | The amount of errors to display. Default is 5 |
+| [ --trace \| -t ] | When used, it will add the backtrace in the output of the error |
+
+
+# Updating
+
+As development for the Error plugin continues, new versions may become available that add additional features and functionality, improve compatibility with newer Grav releases, and generally provide a better user experience. Updating Error is easy, and can be done through Grav's GPM system, as well as manually.
+
+## GPM Update (Preferred)
+
+The simplest way to update this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm). You can do this with this by navigating to the root directory of your Grav install using your system's Terminal (also called command line) and typing the following:
+
+ bin/gpm update error
+
+This command will check your Grav install to see if your Error plugin is due for an update. If a newer release is found, you will be asked whether or not you wish to update. To continue, type `y` and hit enter. The plugin will automatically update and clear Grav's cache.
+
+## Manual Update
+
+Manually updating Error is pretty simple. Here is what you will need to do to get this done:
+
+* Delete the `your/site/user/plugins/error` directory.
+* Download the new version of the Error plugin from either [GitHub](https://github.com/getgrav/grav-plugin-error) or [GetGrav.org](http://getgrav.org/downloads/plugins#extras).
+* Unzip the zip file in `your/site/user/plugins` and rename the resulting folder to `error`.
+* Clear the Grav cache. The simplest way to do this is by going to the root Grav directory in terminal and typing `bin/grav clear-cache`.
+
+> Note: Any changes you have made to any of the files listed under this directory will also be removed and replaced by the new set. Any files located elsewhere (for example a YAML settings file placed in `user/config/plugins`) will remain intact.
diff --git a/user/plugins/error/assets/readme_1.png b/user/plugins/error/assets/readme_1.png
new file mode 100644
index 0000000..930b87b
Binary files /dev/null and b/user/plugins/error/assets/readme_1.png differ
diff --git a/user/plugins/error/blueprints.yaml b/user/plugins/error/blueprints.yaml
new file mode 100644
index 0000000..9525760
--- /dev/null
+++ b/user/plugins/error/blueprints.yaml
@@ -0,0 +1,36 @@
+name: Error
+version: 1.8.1
+description: Displays the error page.
+type: plugin
+slug: error
+icon: warning
+author:
+ name: Team Grav
+ email: devs@getgrav.org
+ url: http://getgrav.org
+homepage: https://github.com/getgrav/grav-plugin-error
+keywords: error, plugin, required
+bugs: https://github.com/getgrav/grav-plugin-error/issues
+license: MIT
+dependencies:
+ - { name: grav, version: '>=1.7.0' }
+
+form:
+ validation: strict
+ fields:
+ enabled:
+ type: toggle
+ label: PLUGIN_ADMIN.PLUGIN_STATUS
+ highlight: 1
+ default: 0
+ options:
+ 1: PLUGIN_ADMIN.ENABLED
+ 0: PLUGIN_ADMIN.DISABLED
+ validate:
+ type: bool
+
+ routes.404:
+ type: text
+ size: medium
+ label: PLUGIN_ERROR.ROUTE_404
+ default: '/error'
diff --git a/user/plugins/error/cli/LogCommand.php b/user/plugins/error/cli/LogCommand.php
new file mode 100644
index 0000000..583d231
--- /dev/null
+++ b/user/plugins/error/cli/LogCommand.php
@@ -0,0 +1,166 @@
+ 'green',
+ 'INFO' => 'cyan',
+ 'NOTICE' => 'yellow',
+ 'WARNING' => 'yellow',
+ 'ERROR' => 'red',
+ 'CRITICAL' => 'red',
+ 'ALERT' => 'red',
+ 'EMERGENCY' => 'magenta'
+ ];
+
+ /**
+ *
+ */
+ protected function configure()
+ {
+ $this->logfile = LOG_DIR . 'grav.log';
+ $this
+ ->setName("log")
+ ->setDescription("Outputs the Error Log")
+ ->addOption(
+ 'trace',
+ 't',
+ InputOption::VALUE_NONE,
+ 'Include the errors stack trace in the output'
+ )
+ ->addOption(
+ 'limit',
+ 'l',
+ InputArgument::OPTIONAL,
+ 'Outputs only the last X amount of errors. Use as --limit 10 / -l 10 [default 5]',
+ 5
+ )
+ ->setHelp('The log outputs the Errors Log in Console')
+ ;
+ }
+
+ /**
+ * @return int|null|void
+ */
+ protected function serve()
+ {
+ $this->options = [
+ 'trace' => $this->input->getOption('trace'),
+ 'limit' => $this->input->getOption('limit')
+ ];
+
+ if (!file_exists($this->logfile)) {
+ $this->output->writeln("\n" . "Log file not found." . "\n");
+ exit;
+ }
+
+ $log = file_get_contents($this->logfile);
+ $lines = explode("\n", $log);
+
+ if (!is_numeric($this->options['limit'])) {
+ $this->options['limit'] = 5;
+ }
+
+ $lines = array_slice($lines, -($this->options['limit'] + 1));
+
+ foreach ($lines as $line) {
+ $parsed = $this->parseLine($line);
+ if ($parsed !== null) {
+ $this->output->writeln($parsed);
+ }
+ }
+ }
+
+ /**
+ * @param string $line
+ *
+ * @return null|string
+ */
+ protected function parseLine($line)
+ {
+ // Skip empty lines
+ if (empty(trim($line))) {
+ return null;
+ }
+
+ $bit = explode(': ', $line);
+
+ // Check if we have at least the basic structure
+ if (count($bit) < 2) {
+ return null;
+ }
+
+ $line1 = explode('] ', $bit[0]);
+
+ if (!isset($line1[0]) || !$line1[0]) {
+ return null;
+ }
+
+ // Check if we have the log type
+ if (!isset($line1[1])) {
+ return null;
+ }
+
+ // Handle both formats: "Message - Trace" and just "Message"
+ $line2 = explode(' - ', $bit[1]);
+
+ $date = $line1[0] . ']';
+ $type = str_replace('grav.', '', $line1[1]);
+
+ // Check if the log type has a color defined
+ if (!isset($this->colors[$type])) {
+ $color = 'white'; // Default color for unknown types
+ } else {
+ $color = $this->colors[$type];
+ }
+
+ // Get the full message (everything after the log level)
+ // Join back with ': ' in case the message itself contains colons
+ $fullMessage = implode(': ', array_slice($bit, 1));
+
+ // If there's a dash separator, use the part before it, otherwise use the full message
+ if (count($line2) > 1) {
+ $error = $line2[0];
+ } else {
+ $error = $fullMessage;
+ }
+ $trace = implode(': ', array_slice($bit, 2));
+
+ $output = [];
+
+ $output[] = '';
+ $output[] = '' . $date . '';
+ $output[] = sprintf(' <%s>%s%s> ' . $error . '', $color, $type, $color);
+
+ if ($this->options['trace']) {
+ $output[] = ' TRACE: ';
+ $output[] = ' ' . $trace;
+ }
+
+ $output[] = '' . str_repeat('-', strlen($date)) . '';
+
+ return implode("\n", $output);
+ }
+}
+
diff --git a/user/plugins/error/composer.json b/user/plugins/error/composer.json
new file mode 100644
index 0000000..27ddfa9
--- /dev/null
+++ b/user/plugins/error/composer.json
@@ -0,0 +1,39 @@
+{
+ "name": "getgrav/grav-plugin-error",
+ "type": "grav-plugin",
+ "description": "Error plugin for Grav CMS",
+ "keywords": ["error", "plugin"],
+ "homepage": "https://github.com/getgrav/grav-plugin-error",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Team Grav",
+ "email": "devs@getgrav.org",
+ "homepage": "https://getgrav.org",
+ "role": "Developer"
+ }
+ ],
+ "support": {
+ "issues": "https://github.com/getgrav/grav-plugin-error/issues",
+ "irc": "https://chat.getgrav.org",
+ "forum": "https://getgrav.org/forum",
+ "docs": "https://github.com/getgrav/grav-plugin-error/blob/master/README.md"
+ },
+ "autoload": {
+ "psr-4": {
+ "Grav\\Plugin\\Console\\": "cli/"
+ },
+ "classmap": [
+ "error.php"
+ ]
+ },
+ "config": {
+ "platform": {
+ "php": "7.1.3"
+ }
+ },
+ "scripts": {
+ "test": "vendor/bin/codecept run unit",
+ "test-windows": "vendor\\bin\\codecept run unit"
+ }
+}
diff --git a/user/plugins/error/error.php b/user/plugins/error/error.php
new file mode 100644
index 0000000..edbaaff
--- /dev/null
+++ b/user/plugins/error/error.php
@@ -0,0 +1,117 @@
+ [
+ ['autoload', 100000],
+ ],
+ 'onPageNotFound' => [
+ ['onPageNotFound', 0]
+ ],
+ 'onGetPageTemplates' => [
+ ['onGetPageTemplates', 0]
+ ],
+ 'onTwigTemplatePaths' => [
+ ['onTwigTemplatePaths', -10]
+ ],
+ 'onDisplayErrorPage.404'=> [
+ ['onDisplayErrorPage404', -1]
+ ]
+ ];
+ }
+
+ /**
+ * [onPluginsInitialized:100000] Composer autoload.
+ *
+ * @return ClassLoader
+ */
+ public function autoload(): ClassLoader
+ {
+ return require __DIR__ . '/vendor/autoload.php';
+ }
+
+ /**
+ * @param Event $event
+ */
+ public function onDisplayErrorPage404(Event $event): void
+ {
+ if ($this->isAdmin()) {
+ return;
+ }
+
+ $event['page'] = $this->getErrorPage();
+ $event->stopPropagation();
+ }
+
+ /**
+ * Display error page if no page was found for the current route.
+ *
+ * @param Event $event
+ */
+ public function onPageNotFound(Event $event): void
+ {
+ $event->page = $this->getErrorPage();
+ $event->stopPropagation();
+ }
+
+ /**
+ * @return PageInterface
+ * @throws \Exception
+ */
+ public function getErrorPage(): PageInterface
+ {
+ /** @var Pages $pages */
+ $pages = $this->grav['pages'];
+
+ // Try to load user error page.
+ $page = $pages->dispatch($this->config->get('plugins.error.routes.404', '/error'), true);
+ if (!$page) {
+ // If none provided use built in error page.
+ $page = new Page;
+ $page->init(new \SplFileInfo(__DIR__ . '/pages/error.md'));
+ $page->title($this->grav['language']->translate('PLUGIN_ERROR.ERROR') . ' ' . $page->header()->http_response_code);
+
+ }
+
+ // Login page may not have the correct Cache-Control header set, force no-store for the proxies.
+ $cacheControl = $page->cacheControl();
+ if (!$cacheControl) {
+ $page->cacheControl('private, no-cache, must-revalidate');
+ }
+
+ return $page;
+ }
+
+ /**
+ * Add page template types.
+ */
+ public function onGetPageTemplates(Event $event): void
+ {
+ /** @var Types $types */
+ $types = $event->types;
+ $types->register('error');
+ }
+
+ /**
+ * Add current directory to twig lookup paths.
+ */
+ public function onTwigTemplatePaths(): void
+ {
+ $this->grav['twig']->twig_paths[] = __DIR__ . '/templates';
+ }
+}
diff --git a/user/plugins/error/error.yaml b/user/plugins/error/error.yaml
new file mode 100644
index 0000000..0a51d4c
--- /dev/null
+++ b/user/plugins/error/error.yaml
@@ -0,0 +1,3 @@
+enabled: true
+routes:
+ 404: '/error'
diff --git a/user/plugins/error/hebe.json b/user/plugins/error/hebe.json
new file mode 100644
index 0000000..3ca6ad8
--- /dev/null
+++ b/user/plugins/error/hebe.json
@@ -0,0 +1,15 @@
+{
+ "project":"grav-plugin-error",
+ "platforms":{
+ "grav":{
+ "nodes":{
+ "plugin":[
+ {
+ "source":"/",
+ "destination":"/user/plugins/error"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/user/plugins/error/languages.yaml b/user/plugins/error/languages.yaml
new file mode 100644
index 0000000..650e617
--- /dev/null
+++ b/user/plugins/error/languages.yaml
@@ -0,0 +1,55 @@
+en:
+ PLUGIN_ERROR:
+ ERROR: "Error"
+ ERROR_MESSAGE: "Woops. Looks like this page doesn't exist."
+ ROUTE_404: "404 Route"
+de:
+ PLUGIN_ERROR:
+ ERROR: "Fehler"
+ ERROR_MESSAGE: "Uuups. Sieht aus als ob diese Seite nicht existiert."
+hr:
+ PLUGIN_ERROR:
+ ERROR: "Greška"
+ ERROR_MESSAGE: "Uups. Izgleda da ova stranica ne postoji."
+ro:
+ PLUGIN_ERROR:
+ ERROR: "Eroare"
+ ERROR_MESSAGE: "Ooops. Se pare că pagina nu există."
+fr:
+ PLUGIN_ERROR:
+ ERROR: "Erreur"
+ ERROR_MESSAGE: "Oups. Il semble que cette page n’existe pas."
+it:
+ PLUGIN_ERROR:
+ ERROR: "Errore"
+ ERROR_MESSAGE: "Ooops. A quanto pare, questa pagina non esiste."
+ru:
+ PLUGIN_ERROR:
+ ERROR: "Ошибка"
+ ERROR_MESSAGE: "Упс. Похоже, этой страницы не существует."
+ ROUTE_404: "Маршрут 404"
+uk:
+ PLUGIN_ERROR:
+ ERROR: "Помилка"
+ ERROR_MESSAGE: "Упс. Схоже, цієї сторінки не існує."
+ ROUTE_404: "Маршрут 404"
+da:
+ PLUGIN_ERROR:
+ ERROR: "Fejl"
+ ERROR_MESSAGE: "Ups. Det ser ud til at siden ikke eksisterer."
+zh:
+ PLUGIN_ERROR:
+ ERROR: "错误"
+ ERROR_MESSAGE: "呃,似乎这个页面不存在。"
+cs:
+ PLUGIN_ERROR:
+ ERROR: "Chyba"
+ ERROR_MESSAGE: "A jéje. Vypadá to, že hledaná stránka tu není."
+pl:
+ PLUGIN_ERROR:
+ ERROR: "Błąd"
+ ERROR_MESSAGE: "Ups. Wygląda na to, że ta strona nie istnieje."
+ca:
+ PLUGIN_ERROR:
+ ERROR: "Error"
+ ERROR_MESSAGE: "Ups. Sembla que aquesta pàgina no existeix."
diff --git a/user/plugins/error/pages/error.md b/user/plugins/error/pages/error.md
new file mode 100644
index 0000000..e9b344b
--- /dev/null
+++ b/user/plugins/error/pages/error.md
@@ -0,0 +1,14 @@
+---
+title: Page not Found
+robots: noindex,nofollow
+template: error
+routable: false
+http_response_code: 404
+twig_first: true
+process:
+ twig: true
+expires: 0
+---
+
+{{ 'PLUGIN_ERROR.ERROR_MESSAGE'|t }}
+
diff --git a/user/plugins/error/templates/error.html.twig b/user/plugins/error/templates/error.html.twig
new file mode 100644
index 0000000..420702b
--- /dev/null
+++ b/user/plugins/error/templates/error.html.twig
@@ -0,0 +1,3 @@
+
{{ 'PLUGIN_ERROR.ERROR'|t }} {{ header.http_response_code }}
+
+{{ page.content|raw }}
diff --git a/user/plugins/error/templates/error.json.twig b/user/plugins/error/templates/error.json.twig
new file mode 100644
index 0000000..27472f1
--- /dev/null
+++ b/user/plugins/error/templates/error.json.twig
@@ -0,0 +1 @@
+{{ page.content|json_encode()|raw }}
\ No newline at end of file
diff --git a/user/plugins/error/vendor/autoload.php b/user/plugins/error/vendor/autoload.php
new file mode 100644
index 0000000..b30c4e0
--- /dev/null
+++ b/user/plugins/error/vendor/autoload.php
@@ -0,0 +1,7 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ * @see http://www.php-fig.org/psr/psr-0/
+ * @see http://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ // PSR-4
+ private $prefixLengthsPsr4 = array();
+ private $prefixDirsPsr4 = array();
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ private $prefixesPsr0 = array();
+ private $fallbackDirsPsr0 = array();
+
+ private $useIncludePath = false;
+ private $classMap = array();
+ private $classMapAuthoritative = false;
+ private $missingClasses = array();
+ private $apcuPrefix;
+
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
+ }
+
+ return array();
+ }
+
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 base directories
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return bool|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath.'\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ */
+function includeFile($file)
+{
+ include $file;
+}
diff --git a/user/plugins/error/vendor/composer/LICENSE b/user/plugins/error/vendor/composer/LICENSE
new file mode 100644
index 0000000..f27399a
--- /dev/null
+++ b/user/plugins/error/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/user/plugins/error/vendor/composer/autoload_classmap.php b/user/plugins/error/vendor/composer/autoload_classmap.php
new file mode 100644
index 0000000..71c4666
--- /dev/null
+++ b/user/plugins/error/vendor/composer/autoload_classmap.php
@@ -0,0 +1,10 @@
+ $baseDir . '/error.php',
+);
diff --git a/user/plugins/error/vendor/composer/autoload_namespaces.php b/user/plugins/error/vendor/composer/autoload_namespaces.php
new file mode 100644
index 0000000..b7fc012
--- /dev/null
+++ b/user/plugins/error/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,9 @@
+ array($baseDir . '/cli'),
+);
diff --git a/user/plugins/error/vendor/composer/autoload_real.php b/user/plugins/error/vendor/composer/autoload_real.php
new file mode 100644
index 0000000..ee6a4c0
--- /dev/null
+++ b/user/plugins/error/vendor/composer/autoload_real.php
@@ -0,0 +1,52 @@
+= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
+ if ($useStaticLoader) {
+ require_once __DIR__ . '/autoload_static.php';
+
+ call_user_func(\Composer\Autoload\ComposerStaticInit4e2f762c713c4d4aae8969c74f5623a3::getInitializer($loader));
+ } else {
+ $map = require __DIR__ . '/autoload_namespaces.php';
+ foreach ($map as $namespace => $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+ }
+
+ $loader->register(true);
+
+ return $loader;
+ }
+}
diff --git a/user/plugins/error/vendor/composer/autoload_static.php b/user/plugins/error/vendor/composer/autoload_static.php
new file mode 100644
index 0000000..11ca02a
--- /dev/null
+++ b/user/plugins/error/vendor/composer/autoload_static.php
@@ -0,0 +1,36 @@
+
+ array (
+ 'Grav\\Plugin\\Console\\' => 20,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'Grav\\Plugin\\Console\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/cli',
+ ),
+ );
+
+ public static $classMap = array (
+ 'Grav\\Plugin\\ErrorPlugin' => __DIR__ . '/../..' . '/error.php',
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInit4e2f762c713c4d4aae8969c74f5623a3::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit4e2f762c713c4d4aae8969c74f5623a3::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInit4e2f762c713c4d4aae8969c74f5623a3::$classMap;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/user/plugins/error/vendor/composer/installed.json b/user/plugins/error/vendor/composer/installed.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/user/plugins/error/vendor/composer/installed.json
@@ -0,0 +1 @@
+[]