havocera 1 anno fa
parent
commit
17d3d24b6d
100 ha cambiato i file con 13950 aggiunte e 0 eliminazioni
  1. 25 0
      vendor/autoload.php
  2. 120 0
      vendor/bin/var-dump-server
  3. 5 0
      vendor/bin/var-dump-server.bat
  4. 585 0
      vendor/composer/ClassLoader.php
  5. 359 0
      vendor/composer/InstalledVersions.php
  6. 21 0
      vendor/composer/LICENSE
  7. 15 0
      vendor/composer/autoload_classmap.php
  8. 16 0
      vendor/composer/autoload_files.php
  9. 10 0
      vendor/composer/autoload_namespaces.php
  10. 31 0
      vendor/composer/autoload_psr4.php
  11. 50 0
      vendor/composer/autoload_real.php
  12. 179 0
      vendor/composer/autoload_static.php
  13. 1536 0
      vendor/composer/installed.json
  14. 239 0
      vendor/composer/installed.php
  15. 26 0
      vendor/composer/platform_check.php
  16. 19 0
      vendor/doctrine/annotations/LICENSE
  17. 24 0
      vendor/doctrine/annotations/README.md
  18. 72 0
      vendor/doctrine/annotations/composer.json
  19. 252 0
      vendor/doctrine/annotations/docs/en/annotations.rst
  20. 443 0
      vendor/doctrine/annotations/docs/en/custom.rst
  21. 110 0
      vendor/doctrine/annotations/docs/en/index.rst
  22. 6 0
      vendor/doctrine/annotations/docs/en/sidebar.rst
  23. 57 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php
  24. 21 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php
  25. 15 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php
  26. 69 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php
  27. 43 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php
  28. 13 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/NamedArgumentConstructor.php
  29. 13 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.php
  30. 101 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php
  31. 167 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php
  32. 389 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php
  33. 190 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php
  34. 266 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php
  35. 143 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php
  36. 1506 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
  37. 315 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.php
  38. 178 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php
  39. 100 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php
  40. 14 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/NamedArgumentConstructorAnnotation.php
  41. 92 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php
  42. 232 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php
  43. 80 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php
  44. 114 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php
  45. 206 0
      vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php
  46. 15 0
      vendor/doctrine/annotations/psalm.xml
  47. 19 0
      vendor/doctrine/deprecations/LICENSE
  48. 154 0
      vendor/doctrine/deprecations/README.md
  49. 32 0
      vendor/doctrine/deprecations/composer.json
  50. 266 0
      vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php
  51. 66 0
      vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php
  52. 22 0
      vendor/doctrine/deprecations/phpcs.xml
  53. 19 0
      vendor/doctrine/lexer/LICENSE
  54. 9 0
      vendor/doctrine/lexer/README.md
  55. 14 0
      vendor/doctrine/lexer/UPGRADE.md
  56. 56 0
      vendor/doctrine/lexer/composer.json
  57. 346 0
      vendor/doctrine/lexer/src/AbstractLexer.php
  58. 145 0
      vendor/doctrine/lexer/src/Token.php
  59. 10 0
      vendor/league/flysystem-cached-adapter/.editorconfig
  60. 4 0
      vendor/league/flysystem-cached-adapter/.gitignore
  61. 7 0
      vendor/league/flysystem-cached-adapter/.php_cs
  62. 34 0
      vendor/league/flysystem-cached-adapter/.scrutinizer.yml
  63. 29 0
      vendor/league/flysystem-cached-adapter/.travis.yml
  64. 19 0
      vendor/league/flysystem-cached-adapter/LICENSE
  65. 2 0
      vendor/league/flysystem-cached-adapter/clover/.gitignore
  66. 30 0
      vendor/league/flysystem-cached-adapter/composer.json
  67. 6 0
      vendor/league/flysystem-cached-adapter/phpspec.yml
  68. 3 0
      vendor/league/flysystem-cached-adapter/phpunit.php
  69. 29 0
      vendor/league/flysystem-cached-adapter/phpunit.xml
  70. 20 0
      vendor/league/flysystem-cached-adapter/readme.md
  71. 435 0
      vendor/league/flysystem-cached-adapter/spec/CachedAdapterSpec.php
  72. 101 0
      vendor/league/flysystem-cached-adapter/src/CacheInterface.php
  73. 346 0
      vendor/league/flysystem-cached-adapter/src/CachedAdapter.php
  74. 418 0
      vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php
  75. 115 0
      vendor/league/flysystem-cached-adapter/src/Storage/Adapter.php
  76. 59 0
      vendor/league/flysystem-cached-adapter/src/Storage/Memcached.php
  77. 22 0
      vendor/league/flysystem-cached-adapter/src/Storage/Memory.php
  78. 171 0
      vendor/league/flysystem-cached-adapter/src/Storage/Noop.php
  79. 62 0
      vendor/league/flysystem-cached-adapter/src/Storage/PhpRedis.php
  80. 75 0
      vendor/league/flysystem-cached-adapter/src/Storage/Predis.php
  81. 59 0
      vendor/league/flysystem-cached-adapter/src/Storage/Psr6Cache.php
  82. 60 0
      vendor/league/flysystem-cached-adapter/src/Storage/Stash.php
  83. 104 0
      vendor/league/flysystem-cached-adapter/tests/AdapterCacheTests.php
  84. 16 0
      vendor/league/flysystem-cached-adapter/tests/InspectionTests.php
  85. 35 0
      vendor/league/flysystem-cached-adapter/tests/MemcachedTests.php
  86. 255 0
      vendor/league/flysystem-cached-adapter/tests/MemoryCacheTests.php
  87. 35 0
      vendor/league/flysystem-cached-adapter/tests/NoopCacheTests.php
  88. 45 0
      vendor/league/flysystem-cached-adapter/tests/PhpRedisTests.php
  89. 55 0
      vendor/league/flysystem-cached-adapter/tests/PredisTests.php
  90. 45 0
      vendor/league/flysystem-cached-adapter/tests/Psr6CacheTest.php
  91. 43 0
      vendor/league/flysystem-cached-adapter/tests/StashTest.php
  92. 76 0
      vendor/league/flysystem/CODE_OF_CONDUCT.md
  93. 19 0
      vendor/league/flysystem/LICENSE
  94. 16 0
      vendor/league/flysystem/SECURITY.md
  95. 68 0
      vendor/league/flysystem/composer.json
  96. 19 0
      vendor/league/flysystem/deprecations.md
  97. 72 0
      vendor/league/flysystem/src/Adapter/AbstractAdapter.php
  98. 705 0
      vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php
  99. 12 0
      vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php
  100. 584 0
      vendor/league/flysystem/src/Adapter/Ftp.php

+ 25 - 0
vendor/autoload.php

@@ -0,0 +1,25 @@
+<?php
+
+// autoload.php @generated by Composer
+
+if (PHP_VERSION_ID < 50600) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, $err);
+        } elseif (!headers_sent()) {
+            echo $err;
+        }
+    }
+    trigger_error(
+        $err,
+        E_USER_ERROR
+    );
+}
+
+require_once __DIR__ . '/composer/autoload_real.php';
+
+return ComposerAutoloaderInitc5816a8f99b96cf0f2cbda034ad106d7::getLoader();

+ 120 - 0
vendor/bin/var-dump-server

@@ -0,0 +1,120 @@
+#!/usr/bin/env php
+<?php
+
+/**
+ * Proxy PHP file generated by Composer
+ *
+ * This file includes the referenced bin path (../symfony/var-dumper/Resources/bin/var-dump-server)
+ * using a stream wrapper to prevent the shebang from being output on PHP<8
+ *
+ * @generated
+ */
+
+namespace Composer;
+
+$GLOBALS['_composer_bin_dir'] = __DIR__;
+$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
+
+if (PHP_VERSION_ID < 80000) {
+    if (!class_exists('Composer\BinProxyWrapper')) {
+        /**
+         * @internal
+         */
+        final class BinProxyWrapper
+        {
+            private $handle;
+            private $position;
+            private $realpath;
+
+            public function stream_open($path, $mode, $options, &$opened_path)
+            {
+                // get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
+                $opened_path = substr($path, 17);
+                $this->realpath = realpath($opened_path) ?: $opened_path;
+                $opened_path = $this->realpath;
+                $this->handle = fopen($this->realpath, $mode);
+                $this->position = 0;
+
+                return (bool) $this->handle;
+            }
+
+            public function stream_read($count)
+            {
+                $data = fread($this->handle, $count);
+
+                if ($this->position === 0) {
+                    $data = preg_replace('{^#!.*\r?\n}', '', $data);
+                }
+
+                $this->position += strlen($data);
+
+                return $data;
+            }
+
+            public function stream_cast($castAs)
+            {
+                return $this->handle;
+            }
+
+            public function stream_close()
+            {
+                fclose($this->handle);
+            }
+
+            public function stream_lock($operation)
+            {
+                return $operation ? flock($this->handle, $operation) : true;
+            }
+
+            public function stream_seek($offset, $whence)
+            {
+                if (0 === fseek($this->handle, $offset, $whence)) {
+                    $this->position = ftell($this->handle);
+                    return true;
+                }
+
+                return false;
+            }
+
+            public function stream_tell()
+            {
+                return $this->position;
+            }
+
+            public function stream_eof()
+            {
+                return feof($this->handle);
+            }
+
+            public function stream_stat()
+            {
+                return array();
+            }
+
+            public function stream_set_option($option, $arg1, $arg2)
+            {
+                return true;
+            }
+
+            public function url_stat($path, $flags)
+            {
+                $path = substr($path, 17);
+                if (file_exists($path)) {
+                    return stat($path);
+                }
+
+                return false;
+            }
+        }
+    }
+
+    if (
+        (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
+        || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
+    ) {
+        include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server');
+        exit(0);
+    }
+}
+
+include __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server';

+ 5 - 0
vendor/bin/var-dump-server.bat

@@ -0,0 +1,5 @@
+@ECHO OFF
+setlocal DISABLEDELAYEDEXPANSION
+SET BIN_TARGET=%~dp0/var-dump-server
+SET COMPOSER_RUNTIME_BIN_DIR=%~dp0
+php "%BIN_TARGET%" %*

+ 585 - 0
vendor/composer/ClassLoader.php

@@ -0,0 +1,585 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace 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 <fabien@symfony.com>
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ * @see    https://www.php-fig.org/psr/psr-0/
+ * @see    https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+    /** @var \Closure(string):void */
+    private static $includeFile;
+
+    /** @var ?string */
+    private $vendorDir;
+
+    // PSR-4
+    /**
+     * @var array[]
+     * @psalm-var array<string, array<string, int>>
+     */
+    private $prefixLengthsPsr4 = array();
+    /**
+     * @var array[]
+     * @psalm-var array<string, array<int, string>>
+     */
+    private $prefixDirsPsr4 = array();
+    /**
+     * @var array[]
+     * @psalm-var array<string, string>
+     */
+    private $fallbackDirsPsr4 = array();
+
+    // PSR-0
+    /**
+     * @var array[]
+     * @psalm-var array<string, array<string, string[]>>
+     */
+    private $prefixesPsr0 = array();
+    /**
+     * @var array[]
+     * @psalm-var array<string, string>
+     */
+    private $fallbackDirsPsr0 = array();
+
+    /** @var bool */
+    private $useIncludePath = false;
+
+    /**
+     * @var string[]
+     * @psalm-var array<string, string>
+     */
+    private $classMap = array();
+
+    /** @var bool */
+    private $classMapAuthoritative = false;
+
+    /**
+     * @var bool[]
+     * @psalm-var array<string, bool>
+     */
+    private $missingClasses = array();
+
+    /** @var ?string */
+    private $apcuPrefix;
+
+    /**
+     * @var self[]
+     */
+    private static $registeredLoaders = array();
+
+    /**
+     * @param ?string $vendorDir
+     */
+    public function __construct($vendorDir = null)
+    {
+        $this->vendorDir = $vendorDir;
+        self::initializeIncludeClosure();
+    }
+
+    /**
+     * @return string[]
+     */
+    public function getPrefixes()
+    {
+        if (!empty($this->prefixesPsr0)) {
+            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+        }
+
+        return array();
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return array<string, array<int, string>>
+     */
+    public function getPrefixesPsr4()
+    {
+        return $this->prefixDirsPsr4;
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return array<string, string>
+     */
+    public function getFallbackDirs()
+    {
+        return $this->fallbackDirsPsr0;
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return array<string, string>
+     */
+    public function getFallbackDirsPsr4()
+    {
+        return $this->fallbackDirsPsr4;
+    }
+
+    /**
+     * @return string[] Array of classname => path
+     * @psalm-return array<string, string>
+     */
+    public function getClassMap()
+    {
+        return $this->classMap;
+    }
+
+    /**
+     * @param string[] $classMap Class to filename map
+     * @psalm-param array<string, string> $classMap
+     *
+     * @return void
+     */
+    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 string[]|string $paths   The PSR-0 root directories
+     * @param bool            $prepend Whether to prepend the directories
+     *
+     * @return void
+     */
+    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 string[]|string $paths   The PSR-4 base directories
+     * @param bool            $prepend Whether to prepend the directories
+     *
+     * @throws \InvalidArgumentException
+     *
+     * @return void
+     */
+    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 string[]|string $paths  The PSR-0 base directories
+     *
+     * @return void
+     */
+    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 string[]|string $paths  The PSR-4 base directories
+     *
+     * @throws \InvalidArgumentException
+     *
+     * @return void
+     */
+    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
+     *
+     * @return void
+     */
+    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
+     *
+     * @return void
+     */
+    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
+     *
+     * @return void
+     */
+    public function setApcuPrefix($apcuPrefix)
+    {
+        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $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
+     *
+     * @return void
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+        if (null === $this->vendorDir) {
+            return;
+        }
+
+        if ($prepend) {
+            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+        } else {
+            unset(self::$registeredLoaders[$this->vendorDir]);
+            self::$registeredLoaders[$this->vendorDir] = $this;
+        }
+    }
+
+    /**
+     * Unregisters this instance as an autoloader.
+     *
+     * @return void
+     */
+    public function unregister()
+    {
+        spl_autoload_unregister(array($this, 'loadClass'));
+
+        if (null !== $this->vendorDir) {
+            unset(self::$registeredLoaders[$this->vendorDir]);
+        }
+    }
+
+    /**
+     * Loads the given class or interface.
+     *
+     * @param  string    $class The name of the class
+     * @return true|null True if loaded, null otherwise
+     */
+    public function loadClass($class)
+    {
+        if ($file = $this->findFile($class)) {
+            $includeFile = self::$includeFile;
+            $includeFile($file);
+
+            return true;
+        }
+
+        return null;
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Returns the currently registered loaders indexed by their corresponding vendor directories.
+     *
+     * @return self[]
+     */
+    public static function getRegisteredLoaders()
+    {
+        return self::$registeredLoaders;
+    }
+
+    /**
+     * @param  string       $class
+     * @param  string       $ext
+     * @return string|false
+     */
+    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;
+    }
+
+    /**
+     * @return void
+     */
+    private static function initializeIncludeClosure()
+    {
+        if (self::$includeFile !== null) {
+            return;
+        }
+
+        /**
+         * Scope isolated include.
+         *
+         * Prevents access to $this/self from included files.
+         *
+         * @param  string $file
+         * @return void
+         */
+        self::$includeFile = \Closure::bind(static function($file) {
+            include $file;
+        }, null, null);
+    }
+}

+ 359 - 0
vendor/composer/InstalledVersions.php

@@ -0,0 +1,359 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ *
+ * @final
+ */
+class InstalledVersions
+{
+    /**
+     * @var mixed[]|null
+     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
+     */
+    private static $installed;
+
+    /**
+     * @var bool|null
+     */
+    private static $canGetVendors;
+
+    /**
+     * @var array[]
+     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+     */
+    private static $installedByVendor = array();
+
+    /**
+     * Returns a list of all package names which are present, either by being installed, replaced or provided
+     *
+     * @return string[]
+     * @psalm-return list<string>
+     */
+    public static function getInstalledPackages()
+    {
+        $packages = array();
+        foreach (self::getInstalled() as $installed) {
+            $packages[] = array_keys($installed['versions']);
+        }
+
+        if (1 === \count($packages)) {
+            return $packages[0];
+        }
+
+        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+    }
+
+    /**
+     * Returns a list of all package names with a specific type e.g. 'library'
+     *
+     * @param  string   $type
+     * @return string[]
+     * @psalm-return list<string>
+     */
+    public static function getInstalledPackagesByType($type)
+    {
+        $packagesByType = array();
+
+        foreach (self::getInstalled() as $installed) {
+            foreach ($installed['versions'] as $name => $package) {
+                if (isset($package['type']) && $package['type'] === $type) {
+                    $packagesByType[] = $name;
+                }
+            }
+        }
+
+        return $packagesByType;
+    }
+
+    /**
+     * Checks whether the given package is installed
+     *
+     * This also returns true if the package name is provided or replaced by another package
+     *
+     * @param  string $packageName
+     * @param  bool   $includeDevRequirements
+     * @return bool
+     */
+    public static function isInstalled($packageName, $includeDevRequirements = true)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (isset($installed['versions'][$packageName])) {
+                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks whether the given package satisfies a version constraint
+     *
+     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+     *
+     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+     *
+     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
+     * @param  string        $packageName
+     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+     * @return bool
+     */
+    public static function satisfies(VersionParser $parser, $packageName, $constraint)
+    {
+        $constraint = $parser->parseConstraints((string) $constraint);
+        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+        return $provided->matches($constraint);
+    }
+
+    /**
+     * Returns a version constraint representing all the range(s) which are installed for a given package
+     *
+     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+     * whether a given version of a package is installed, and not just whether it exists
+     *
+     * @param  string $packageName
+     * @return string Version constraint usable with composer/semver
+     */
+    public static function getVersionRanges($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            $ranges = array();
+            if (isset($installed['versions'][$packageName]['pretty_version'])) {
+                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+            }
+            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+            }
+            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+            }
+            if (array_key_exists('provided', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+            }
+
+            return implode(' || ', $ranges);
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+     */
+    public static function getVersion($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['version'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['version'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+     */
+    public static function getPrettyVersion($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['pretty_version'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+     */
+    public static function getReference($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['reference'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['reference'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+     */
+    public static function getInstallPath($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @return array
+     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
+     */
+    public static function getRootPackage()
+    {
+        $installed = self::getInstalled();
+
+        return $installed[0]['root'];
+    }
+
+    /**
+     * Returns the raw installed.php data for custom implementations
+     *
+     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+     * @return array[]
+     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
+     */
+    public static function getRawData()
+    {
+        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+        if (null === self::$installed) {
+            // only require the installed.php file if this file is loaded from its dumped location,
+            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+            if (substr(__DIR__, -8, 1) !== 'C') {
+                self::$installed = include __DIR__ . '/installed.php';
+            } else {
+                self::$installed = array();
+            }
+        }
+
+        return self::$installed;
+    }
+
+    /**
+     * Returns the raw data of all installed.php which are currently loaded for custom implementations
+     *
+     * @return array[]
+     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+     */
+    public static function getAllRawData()
+    {
+        return self::getInstalled();
+    }
+
+    /**
+     * Lets you reload the static array from another file
+     *
+     * This is only useful for complex integrations in which a project needs to use
+     * this class but then also needs to execute another project's autoloader in process,
+     * and wants to ensure both projects have access to their version of installed.php.
+     *
+     * A typical case would be PHPUnit, where it would need to make sure it reads all
+     * the data it needs from this class, then call reload() with
+     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+     * the project in which it runs can then also use this class safely, without
+     * interference between PHPUnit's dependencies and the project's dependencies.
+     *
+     * @param  array[] $data A vendor/composer/installed.php data set
+     * @return void
+     *
+     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
+     */
+    public static function reload($data)
+    {
+        self::$installed = $data;
+        self::$installedByVendor = array();
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
+     */
+    private static function getInstalled()
+    {
+        if (null === self::$canGetVendors) {
+            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+        }
+
+        $installed = array();
+
+        if (self::$canGetVendors) {
+            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+                if (isset(self::$installedByVendor[$vendorDir])) {
+                    $installed[] = self::$installedByVendor[$vendorDir];
+                } elseif (is_file($vendorDir.'/composer/installed.php')) {
+                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                    $required = require $vendorDir.'/composer/installed.php';
+                    $installed[] = self::$installedByVendor[$vendorDir] = $required;
+                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+                        self::$installed = $installed[count($installed) - 1];
+                    }
+                }
+            }
+        }
+
+        if (null === self::$installed) {
+            // only require the installed.php file if this file is loaded from its dumped location,
+            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+            if (substr(__DIR__, -8, 1) !== 'C') {
+                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                $required = require __DIR__ . '/installed.php';
+                self::$installed = $required;
+            } else {
+                self::$installed = array();
+            }
+        }
+
+        if (self::$installed !== array()) {
+            $installed[] = self::$installed;
+        }
+
+        return $installed;
+    }
+}

+ 21 - 0
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.
+

+ 15 - 0
vendor/composer/autoload_classmap.php

@@ -0,0 +1,15 @@
+<?php
+
+// autoload_classmap.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+    'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
+    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
+    'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
+    'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
+    'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
+    'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
+);

+ 16 - 0
vendor/composer/autoload_files.php

@@ -0,0 +1,16 @@
+<?php
+
+// autoload_files.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+    '9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
+    '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php',
+    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
+    '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
+    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
+    '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
+    'cc25fa796cd7d2989f16cf9daf45371d' => $vendorDir . '/thans/tp-jwt-auth/src/helper.php',
+);

+ 10 - 0
vendor/composer/autoload_namespaces.php

@@ -0,0 +1,10 @@
+<?php
+
+// autoload_namespaces.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+    '' => array($baseDir . '/extend'),
+);

+ 31 - 0
vendor/composer/autoload_psr4.php

@@ -0,0 +1,31 @@
+<?php
+
+// autoload_psr4.php @generated by Composer
+
+$vendorDir = dirname(__DIR__);
+$baseDir = dirname($vendorDir);
+
+return array(
+    'think\\trace\\' => array($vendorDir . '/topthink/think-trace/src'),
+    'think\\annotation\\' => array($vendorDir . '/topthink/think-annotation/src'),
+    'think\\' => array($vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-filesystem/src'),
+    'thans\\jwt\\' => array($vendorDir . '/thans/tp-jwt-auth/src'),
+    'app\\' => array($baseDir . '/app'),
+    'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
+    'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
+    'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
+    'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
+    'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
+    'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
+    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
+    'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
+    'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
+    'PhpDocReader\\' => array($vendorDir . '/php-di/phpdoc-reader/src/PhpDocReader'),
+    'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'),
+    'League\\Flysystem\\Cached\\' => array($vendorDir . '/league/flysystem-cached-adapter/src'),
+    'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'),
+    'Lcobucci\\JWT\\' => array($vendorDir . '/qeq66/jwt/src'),
+    'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'),
+    'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/src'),
+    'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
+);

+ 50 - 0
vendor/composer/autoload_real.php

@@ -0,0 +1,50 @@
+<?php
+
+// autoload_real.php @generated by Composer
+
+class ComposerAutoloaderInitc5816a8f99b96cf0f2cbda034ad106d7
+{
+    private static $loader;
+
+    public static function loadClassLoader($class)
+    {
+        if ('Composer\Autoload\ClassLoader' === $class) {
+            require __DIR__ . '/ClassLoader.php';
+        }
+    }
+
+    /**
+     * @return \Composer\Autoload\ClassLoader
+     */
+    public static function getLoader()
+    {
+        if (null !== self::$loader) {
+            return self::$loader;
+        }
+
+        require __DIR__ . '/platform_check.php';
+
+        spl_autoload_register(array('ComposerAutoloaderInitc5816a8f99b96cf0f2cbda034ad106d7', 'loadClassLoader'), true, true);
+        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
+        spl_autoload_unregister(array('ComposerAutoloaderInitc5816a8f99b96cf0f2cbda034ad106d7', 'loadClassLoader'));
+
+        require __DIR__ . '/autoload_static.php';
+        call_user_func(\Composer\Autoload\ComposerStaticInitc5816a8f99b96cf0f2cbda034ad106d7::getInitializer($loader));
+
+        $loader->register(true);
+
+        $filesToLoad = \Composer\Autoload\ComposerStaticInitc5816a8f99b96cf0f2cbda034ad106d7::$files;
+        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
+            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+                require $file;
+            }
+        }, null, null);
+        foreach ($filesToLoad as $fileIdentifier => $file) {
+            $requireFile($fileIdentifier, $file);
+        }
+
+        return $loader;
+    }
+}

+ 179 - 0
vendor/composer/autoload_static.php

@@ -0,0 +1,179 @@
+<?php
+
+// autoload_static.php @generated by Composer
+
+namespace Composer\Autoload;
+
+class ComposerStaticInitc5816a8f99b96cf0f2cbda034ad106d7
+{
+    public static $files = array (
+        '9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
+        '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php',
+        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
+        '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
+        'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
+        '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
+        'cc25fa796cd7d2989f16cf9daf45371d' => __DIR__ . '/..' . '/thans/tp-jwt-auth/src/helper.php',
+    );
+
+    public static $prefixLengthsPsr4 = array (
+        't' => 
+        array (
+            'think\\trace\\' => 12,
+            'think\\annotation\\' => 17,
+            'think\\' => 6,
+            'thans\\jwt\\' => 10,
+        ),
+        'a' => 
+        array (
+            'app\\' => 4,
+        ),
+        'S' => 
+        array (
+            'Symfony\\Polyfill\\Php80\\' => 23,
+            'Symfony\\Polyfill\\Php72\\' => 23,
+            'Symfony\\Polyfill\\Mbstring\\' => 26,
+            'Symfony\\Component\\VarDumper\\' => 28,
+        ),
+        'P' => 
+        array (
+            'Psr\\SimpleCache\\' => 16,
+            'Psr\\Log\\' => 8,
+            'Psr\\Http\\Message\\' => 17,
+            'Psr\\Container\\' => 14,
+            'Psr\\Cache\\' => 10,
+            'PhpDocReader\\' => 13,
+        ),
+        'L' => 
+        array (
+            'League\\MimeTypeDetection\\' => 25,
+            'League\\Flysystem\\Cached\\' => 24,
+            'League\\Flysystem\\' => 17,
+            'Lcobucci\\JWT\\' => 13,
+        ),
+        'D' => 
+        array (
+            'Doctrine\\Deprecations\\' => 22,
+            'Doctrine\\Common\\Lexer\\' => 22,
+            'Doctrine\\Common\\Annotations\\' => 28,
+        ),
+    );
+
+    public static $prefixDirsPsr4 = array (
+        'think\\trace\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/topthink/think-trace/src',
+        ),
+        'think\\annotation\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/topthink/think-annotation/src',
+        ),
+        'think\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/topthink/think-helper/src',
+            1 => __DIR__ . '/..' . '/topthink/think-orm/src',
+            2 => __DIR__ . '/..' . '/topthink/framework/src/think',
+            3 => __DIR__ . '/..' . '/topthink/think-filesystem/src',
+        ),
+        'thans\\jwt\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/thans/tp-jwt-auth/src',
+        ),
+        'app\\' => 
+        array (
+            0 => __DIR__ . '/../..' . '/app',
+        ),
+        'Symfony\\Polyfill\\Php80\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
+        ),
+        'Symfony\\Polyfill\\Php72\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-php72',
+        ),
+        'Symfony\\Polyfill\\Mbstring\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
+        ),
+        'Symfony\\Component\\VarDumper\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/var-dumper',
+        ),
+        'Psr\\SimpleCache\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/simple-cache/src',
+        ),
+        'Psr\\Log\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
+        ),
+        'Psr\\Http\\Message\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/http-message/src',
+        ),
+        'Psr\\Container\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/container/src',
+        ),
+        'Psr\\Cache\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/cache/src',
+        ),
+        'PhpDocReader\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/php-di/phpdoc-reader/src/PhpDocReader',
+        ),
+        'League\\MimeTypeDetection\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/league/mime-type-detection/src',
+        ),
+        'League\\Flysystem\\Cached\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/league/flysystem-cached-adapter/src',
+        ),
+        'League\\Flysystem\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/league/flysystem/src',
+        ),
+        'Lcobucci\\JWT\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/qeq66/jwt/src',
+        ),
+        'Doctrine\\Deprecations\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations',
+        ),
+        'Doctrine\\Common\\Lexer\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/doctrine/lexer/src',
+        ),
+        'Doctrine\\Common\\Annotations\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/doctrine/annotations/lib/Doctrine/Common/Annotations',
+        ),
+    );
+
+    public static $fallbackDirsPsr0 = array (
+        0 => __DIR__ . '/../..' . '/extend',
+    );
+
+    public static $classMap = array (
+        'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
+        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+        'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
+        'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
+        'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
+        'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
+    );
+
+    public static function getInitializer(ClassLoader $loader)
+    {
+        return \Closure::bind(function () use ($loader) {
+            $loader->prefixLengthsPsr4 = ComposerStaticInitc5816a8f99b96cf0f2cbda034ad106d7::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInitc5816a8f99b96cf0f2cbda034ad106d7::$prefixDirsPsr4;
+            $loader->fallbackDirsPsr0 = ComposerStaticInitc5816a8f99b96cf0f2cbda034ad106d7::$fallbackDirsPsr0;
+            $loader->classMap = ComposerStaticInitc5816a8f99b96cf0f2cbda034ad106d7::$classMap;
+
+        }, null, ClassLoader::class);
+    }
+}

+ 1536 - 0
vendor/composer/installed.json

@@ -0,0 +1,1536 @@
+{
+    "packages": [
+        {
+            "name": "doctrine/annotations",
+            "version": "1.14.3",
+            "version_normalized": "1.14.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/annotations.git",
+                "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af",
+                "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/lexer": "^1 || ^2",
+                "ext-tokenizer": "*",
+                "php": "^7.1 || ^8.0",
+                "psr/cache": "^1 || ^2 || ^3"
+            },
+            "require-dev": {
+                "doctrine/cache": "^1.11 || ^2.0",
+                "doctrine/coding-standard": "^9 || ^10",
+                "phpstan/phpstan": "~1.4.10 || ^1.8.0",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+                "symfony/cache": "^4.4 || ^5.4 || ^6",
+                "vimeo/psalm": "^4.10"
+            },
+            "suggest": {
+                "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
+            },
+            "time": "2023-02-01T09:20:38+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "Docblock Annotations Parser",
+            "homepage": "https://www.doctrine-project.org/projects/annotations.html",
+            "keywords": [
+                "annotations",
+                "docblock",
+                "parser"
+            ],
+            "support": {
+                "issues": "https://github.com/doctrine/annotations/issues",
+                "source": "https://github.com/doctrine/annotations/tree/1.14.3"
+            },
+            "install-path": "../doctrine/annotations"
+        },
+        {
+            "name": "doctrine/deprecations",
+            "version": "v1.0.0",
+            "version_normalized": "1.0.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/deprecations.git",
+                "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+                "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1|^8.0"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^9",
+                "phpunit/phpunit": "^7.5|^8.5|^9.5",
+                "psr/log": "^1|^2|^3"
+            },
+            "suggest": {
+                "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
+            },
+            "time": "2022-05-02T15:47:09+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
+            "homepage": "https://www.doctrine-project.org/",
+            "support": {
+                "issues": "https://github.com/doctrine/deprecations/issues",
+                "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
+            },
+            "install-path": "../doctrine/deprecations"
+        },
+        {
+            "name": "doctrine/lexer",
+            "version": "2.1.0",
+            "version_normalized": "2.1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/lexer.git",
+                "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
+                "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/deprecations": "^1.0",
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^9 || ^10",
+                "phpstan/phpstan": "^1.3",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+                "psalm/plugin-phpunit": "^0.18.3",
+                "vimeo/psalm": "^4.11 || ^5.0"
+            },
+            "time": "2022-12-14T08:49:07+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\Lexer\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
+            "homepage": "https://www.doctrine-project.org/projects/lexer.html",
+            "keywords": [
+                "annotations",
+                "docblock",
+                "lexer",
+                "parser",
+                "php"
+            ],
+            "support": {
+                "issues": "https://github.com/doctrine/lexer/issues",
+                "source": "https://github.com/doctrine/lexer/tree/2.1.0"
+            },
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../doctrine/lexer"
+        },
+        {
+            "name": "league/flysystem",
+            "version": "1.1.10",
+            "version_normalized": "1.1.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/flysystem.git",
+                "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1",
+                "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1",
+                "shasum": ""
+            },
+            "require": {
+                "ext-fileinfo": "*",
+                "league/mime-type-detection": "^1.3",
+                "php": "^7.2.5 || ^8.0"
+            },
+            "conflict": {
+                "league/flysystem-sftp": "<1.0.6"
+            },
+            "require-dev": {
+                "phpspec/prophecy": "^1.11.1",
+                "phpunit/phpunit": "^8.5.8"
+            },
+            "suggest": {
+                "ext-ftp": "Allows you to use FTP server storage",
+                "ext-openssl": "Allows you to use FTPS server storage",
+                "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
+                "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
+                "league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
+                "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
+                "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
+                "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
+                "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
+                "league/flysystem-webdav": "Allows you to use WebDAV storage",
+                "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
+                "spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
+                "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
+            },
+            "time": "2022-10-04T09:16:37+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "League\\Flysystem\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Frank de Jonge",
+                    "email": "info@frenky.net"
+                }
+            ],
+            "description": "Filesystem abstraction: Many filesystems, one API.",
+            "keywords": [
+                "Cloud Files",
+                "WebDAV",
+                "abstraction",
+                "aws",
+                "cloud",
+                "copy.com",
+                "dropbox",
+                "file systems",
+                "files",
+                "filesystem",
+                "filesystems",
+                "ftp",
+                "rackspace",
+                "remote",
+                "s3",
+                "sftp",
+                "storage"
+            ],
+            "support": {
+                "issues": "https://github.com/thephpleague/flysystem/issues",
+                "source": "https://github.com/thephpleague/flysystem/tree/1.1.10"
+            },
+            "funding": [
+                {
+                    "url": "https://offset.earth/frankdejonge",
+                    "type": "other"
+                }
+            ],
+            "install-path": "../league/flysystem"
+        },
+        {
+            "name": "league/flysystem-cached-adapter",
+            "version": "1.1.0",
+            "version_normalized": "1.1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/flysystem-cached-adapter.git",
+                "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff",
+                "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff",
+                "shasum": ""
+            },
+            "require": {
+                "league/flysystem": "~1.0",
+                "psr/cache": "^1.0.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "~0.9",
+                "phpspec/phpspec": "^3.4",
+                "phpunit/phpunit": "^5.7",
+                "predis/predis": "~1.0",
+                "tedivm/stash": "~0.12"
+            },
+            "suggest": {
+                "ext-phpredis": "Pure C implemented extension for PHP"
+            },
+            "time": "2020-07-25T15:56:04+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "League\\Flysystem\\Cached\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "frankdejonge",
+                    "email": "info@frenky.net"
+                }
+            ],
+            "description": "An adapter decorator to enable meta-data caching.",
+            "support": {
+                "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues",
+                "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master"
+            },
+            "install-path": "../league/flysystem-cached-adapter"
+        },
+        {
+            "name": "league/mime-type-detection",
+            "version": "1.11.0",
+            "version_normalized": "1.11.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/mime-type-detection.git",
+                "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
+                "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
+                "shasum": ""
+            },
+            "require": {
+                "ext-fileinfo": "*",
+                "php": "^7.2 || ^8.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3.2",
+                "phpstan/phpstan": "^0.12.68",
+                "phpunit/phpunit": "^8.5.8 || ^9.3"
+            },
+            "time": "2022-04-17T13:12:02+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "League\\MimeTypeDetection\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Frank de Jonge",
+                    "email": "info@frankdejonge.nl"
+                }
+            ],
+            "description": "Mime-type detection for Flysystem",
+            "support": {
+                "issues": "https://github.com/thephpleague/mime-type-detection/issues",
+                "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/frankdejonge",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/league/flysystem",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../league/mime-type-detection"
+        },
+        {
+            "name": "php-di/phpdoc-reader",
+            "version": "2.2.1",
+            "version_normalized": "2.2.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHP-DI/PhpDocReader.git",
+                "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c",
+                "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.0"
+            },
+            "require-dev": {
+                "mnapoli/hard-mode": "~0.3.0",
+                "phpunit/phpunit": "^8.5|^9.0"
+            },
+            "time": "2020-10-12T12:39:22+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "PhpDocReader\\": "src/PhpDocReader"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)",
+            "keywords": [
+                "phpdoc",
+                "reflection"
+            ],
+            "support": {
+                "issues": "https://github.com/PHP-DI/PhpDocReader/issues",
+                "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1"
+            },
+            "install-path": "../php-di/phpdoc-reader"
+        },
+        {
+            "name": "psr/cache",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/cache.git",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "time": "2016-08-06T20:24:11+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Cache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for caching libraries",
+            "keywords": [
+                "cache",
+                "psr",
+                "psr-6"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/cache/tree/master"
+            },
+            "install-path": "../psr/cache"
+        },
+        {
+            "name": "psr/container",
+            "version": "1.1.1",
+            "version_normalized": "1.1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/container.git",
+                "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf",
+                "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.0"
+            },
+            "time": "2021-03-05T17:36:06+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Container\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common Container Interface (PHP FIG PSR-11)",
+            "homepage": "https://github.com/php-fig/container",
+            "keywords": [
+                "PSR-11",
+                "container",
+                "container-interface",
+                "container-interop",
+                "psr"
+            ],
+            "support": {
+                "issues": "https://github.com/php-fig/container/issues",
+                "source": "https://github.com/php-fig/container/tree/1.1.1"
+            },
+            "install-path": "../psr/container"
+        },
+        {
+            "name": "psr/http-message",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-message.git",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "time": "2016-08-06T14:39:51+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP messages",
+            "homepage": "https://github.com/php-fig/http-message",
+            "keywords": [
+                "http",
+                "http-message",
+                "psr",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-message/tree/master"
+            },
+            "install-path": "../psr/http-message"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.1.4",
+            "version_normalized": "1.1.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "time": "2021-05-03T11:20:27+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "Psr/Log/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/log/tree/1.1.4"
+            },
+            "install-path": "../psr/log"
+        },
+        {
+            "name": "psr/simple-cache",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/simple-cache.git",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "time": "2017-10-23T01:57:42+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\SimpleCache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for simple caching",
+            "keywords": [
+                "cache",
+                "caching",
+                "psr",
+                "psr-16",
+                "simple-cache"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/simple-cache/tree/master"
+            },
+            "install-path": "../psr/simple-cache"
+        },
+        {
+            "name": "qeq66/jwt",
+            "version": "3.3.5",
+            "version_normalized": "3.3.5.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/qeq66/jwt.git",
+                "reference": "bd2fa6c51704dc18c61026c852c789224d7190a0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/qeq66/jwt/zipball/bd2fa6c51704dc18c61026c852c789224d7190a0",
+                "reference": "bd2fa6c51704dc18c61026c852c789224d7190a0",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "ext-openssl": "*",
+                "php": ">=5.6"
+            },
+            "require-dev": {
+                "mikey179/vfsstream": "~1.5",
+                "phpmd/phpmd": "~2.2",
+                "phpunit/php-invoker": "~1.1",
+                "phpunit/phpunit": "^5.7 || ^7.3",
+                "squizlabs/php_codesniffer": "~2.3"
+            },
+            "time": "2022-07-11T08:31:22+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Lcobucci\\JWT\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Luís Otávio Cobucci Oblonczyk",
+                    "email": "lcobucci@gmail.com",
+                    "role": "Developer"
+                }
+            ],
+            "description": "A simple library to work with JSON Web Token and JSON Web Signature",
+            "keywords": [
+                "JWS",
+                "jwt"
+            ],
+            "support": {
+                "source": "https://github.com/qeq66/jwt/tree/3.3.5"
+            },
+            "install-path": "../qeq66/jwt"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.27.0",
+            "version_normalized": "1.27.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+                "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "provide": {
+                "ext-mbstring": "*"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "time": "2022-11-03T14:55:06+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.27-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/polyfill-mbstring"
+        },
+        {
+            "name": "symfony/polyfill-php72",
+            "version": "v1.27.0",
+            "version_normalized": "1.27.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php72.git",
+                "reference": "869329b1e9894268a8a61dabb69153029b7a8c97"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97",
+                "reference": "869329b1e9894268a8a61dabb69153029b7a8c97",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "time": "2022-11-03T14:55:06+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.27-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php72\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/polyfill-php72"
+        },
+        {
+            "name": "symfony/polyfill-php80",
+            "version": "v1.27.0",
+            "version_normalized": "1.27.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+                "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "time": "2022-11-03T14:55:06+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.27-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php80\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ion Bazan",
+                    "email": "ion.bazan@gmail.com"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/polyfill-php80"
+        },
+        {
+            "name": "symfony/var-dumper",
+            "version": "v4.4.47",
+            "version_normalized": "4.4.47.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/var-dumper.git",
+                "reference": "1069c7a3fca74578022fab6f81643248d02f8e63"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63",
+                "reference": "1069c7a3fca74578022fab6f81643248d02f8e63",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.3",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php72": "~1.5",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
+                "symfony/console": "<3.4"
+            },
+            "require-dev": {
+                "ext-iconv": "*",
+                "symfony/console": "^3.4|^4.0|^5.0",
+                "symfony/process": "^4.4|^5.0",
+                "twig/twig": "^1.43|^2.13|^3.0.4"
+            },
+            "suggest": {
+                "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
+                "ext-intl": "To show region name in time zone dump",
+                "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
+            },
+            "time": "2022-10-03T15:15:11+00:00",
+            "bin": [
+                "Resources/bin/var-dump-server"
+            ],
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "Resources/functions/dump.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Component\\VarDumper\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Provides mechanisms for walking through any arbitrary PHP variable",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "debug",
+                "dump"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/var-dumper/tree/v4.4.47"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/var-dumper"
+        },
+        {
+            "name": "thans/tp-jwt-auth",
+            "version": "v1.3.1",
+            "version_normalized": "1.3.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/QThans/jwt-auth.git",
+                "reference": "ab5efcc0fd920df81fea2c404c34bb967ef13aba"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/QThans/jwt-auth/zipball/ab5efcc0fd920df81fea2c404c34bb967ef13aba",
+                "reference": "ab5efcc0fd920df81fea2c404c34bb967ef13aba",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0 || ^8.0",
+                "qeq66/jwt": "3.3.*",
+                "topthink/framework": "^5.1.10 || ^6.0.0"
+            },
+            "time": "2022-11-01T02:44:23+00:00",
+            "type": "library",
+            "extra": {
+                "think": {
+                    "services": [
+                        "thans\\jwt\\Service"
+                    ],
+                    "config": {
+                        "jwt": "config/config.php"
+                    }
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "src/helper.php"
+                ],
+                "psr-4": {
+                    "thans\\jwt\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Thans",
+                    "email": "360641274@qq.com"
+                }
+            ],
+            "description": "thinkphp  jwt auth composer",
+            "support": {
+                "issues": "https://github.com/QThans/jwt-auth/issues",
+                "source": "https://github.com/QThans/jwt-auth/tree/v1.3.1"
+            },
+            "install-path": "../thans/tp-jwt-auth"
+        },
+        {
+            "name": "topthink/framework",
+            "version": "v6.1.2",
+            "version_normalized": "6.1.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/framework.git",
+                "reference": "67235be5b919aaaf1de5aed9839f65d8e766aca3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/framework/zipball/67235be5b919aaaf1de5aed9839f65d8e766aca3",
+                "reference": "67235be5b919aaaf1de5aed9839f65d8e766aca3",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "ext-mbstring": "*",
+                "php": ">=7.2.5",
+                "psr/container": "~1.0",
+                "psr/http-message": "^1.0",
+                "psr/log": "~1.0",
+                "psr/simple-cache": "^1.0",
+                "topthink/think-helper": "^3.1.1",
+                "topthink/think-orm": "^2.0|^3.0"
+            },
+            "require-dev": {
+                "guzzlehttp/psr7": "^2.1.0",
+                "mikey179/vfsstream": "^1.6",
+                "mockery/mockery": "^1.2",
+                "phpunit/phpunit": "^7.0"
+            },
+            "time": "2023-02-08T02:24:01+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "files": [],
+                "psr-4": {
+                    "think\\": "src/think/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "liu21st",
+                    "email": "liu21st@gmail.com"
+                },
+                {
+                    "name": "yunwuxin",
+                    "email": "448901948@qq.com"
+                }
+            ],
+            "description": "The ThinkPHP Framework.",
+            "homepage": "http://thinkphp.cn/",
+            "keywords": [
+                "framework",
+                "orm",
+                "thinkphp"
+            ],
+            "support": {
+                "issues": "https://github.com/top-think/framework/issues",
+                "source": "https://github.com/top-think/framework/tree/v6.1.2"
+            },
+            "install-path": "../topthink/framework"
+        },
+        {
+            "name": "topthink/think-annotation",
+            "version": "v1.0.0",
+            "version_normalized": "1.0.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-annotation.git",
+                "reference": "fa45ccc7e6e8a9ee5f46461bd0fff2a1b93401d8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-annotation/zipball/fa45ccc7e6e8a9ee5f46461bd0fff2a1b93401d8",
+                "reference": "fa45ccc7e6e8a9ee5f46461bd0fff2a1b93401d8",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/annotations": "^1.6",
+                "php-di/phpdoc-reader": "^2.1",
+                "topthink/framework": "^6.0"
+            },
+            "time": "2019-06-24T09:11:21+00:00",
+            "type": "library",
+            "extra": {
+                "think": {
+                    "services": [
+                        "think\\annotation\\Service"
+                    ],
+                    "config": {
+                        "annotation": "src/config.php"
+                    }
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "think\\annotation\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "yunwuxin",
+                    "email": "448901948@qq.com"
+                }
+            ],
+            "description": "Annotation For ThinkPHP6",
+            "support": {
+                "issues": "https://github.com/top-think/think-annotation/issues",
+                "source": "https://github.com/top-think/think-annotation/tree/master"
+            },
+            "install-path": "../topthink/think-annotation"
+        },
+        {
+            "name": "topthink/think-filesystem",
+            "version": "v1.0.3",
+            "version_normalized": "1.0.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-filesystem.git",
+                "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-filesystem/zipball/29f19f140a9267c717fecd7ccb22c84c2d72382e",
+                "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e",
+                "shasum": ""
+            },
+            "require": {
+                "league/flysystem": "^1.1.4",
+                "league/flysystem-cached-adapter": "^1.0",
+                "php": ">=7.2.5",
+                "topthink/framework": "^6.1|^8.0"
+            },
+            "require-dev": {
+                "mikey179/vfsstream": "^1.6",
+                "mockery/mockery": "^1.2",
+                "phpunit/phpunit": "^8.0"
+            },
+            "time": "2023-02-08T01:25:15+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "think\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "yunwuxin",
+                    "email": "448901948@qq.com"
+                }
+            ],
+            "description": "The ThinkPHP6.1 Filesystem Package",
+            "support": {
+                "issues": "https://github.com/top-think/think-filesystem/issues",
+                "source": "https://github.com/top-think/think-filesystem/tree/v1.0.3"
+            },
+            "install-path": "../topthink/think-filesystem"
+        },
+        {
+            "name": "topthink/think-helper",
+            "version": "v3.1.6",
+            "version_normalized": "3.1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-helper.git",
+                "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff",
+                "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5"
+            },
+            "time": "2021-12-15T04:27:55+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "src/helper.php"
+                ],
+                "psr-4": {
+                    "think\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "yunwuxin",
+                    "email": "448901948@qq.com"
+                }
+            ],
+            "description": "The ThinkPHP6 Helper Package",
+            "support": {
+                "issues": "https://github.com/top-think/think-helper/issues",
+                "source": "https://github.com/top-think/think-helper/tree/v3.1.6"
+            },
+            "install-path": "../topthink/think-helper"
+        },
+        {
+            "name": "topthink/think-orm",
+            "version": "v2.0.60",
+            "version_normalized": "2.0.60.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-orm.git",
+                "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-orm/zipball/8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46",
+                "reference": "8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "ext-pdo": "*",
+                "php": ">=7.1.0",
+                "psr/log": "^1.0|^2.0",
+                "psr/simple-cache": "^1.0|^2.0",
+                "topthink/think-helper": "^3.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7|^8|^9.5"
+            },
+            "time": "2023-03-19T04:51:56+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "stubs/load_stubs.php"
+                ],
+                "psr-4": {
+                    "think\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "liu21st",
+                    "email": "liu21st@gmail.com"
+                }
+            ],
+            "description": "think orm",
+            "keywords": [
+                "database",
+                "orm"
+            ],
+            "support": {
+                "issues": "https://github.com/top-think/think-orm/issues",
+                "source": "https://github.com/top-think/think-orm/tree/v2.0.60"
+            },
+            "install-path": "../topthink/think-orm"
+        },
+        {
+            "name": "topthink/think-trace",
+            "version": "v1.6",
+            "version_normalized": "1.6.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/top-think/think-trace.git",
+                "reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/top-think/think-trace/zipball/136cd5d97e8bdb780e4b5c1637c588ed7ca3e142",
+                "reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1.0",
+                "topthink/framework": "^6.0|^8.0"
+            },
+            "time": "2023-02-07T08:36:32+00:00",
+            "type": "library",
+            "extra": {
+                "think": {
+                    "services": [
+                        "think\\trace\\Service"
+                    ],
+                    "config": {
+                        "trace": "src/config.php"
+                    }
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "think\\trace\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "liu21st",
+                    "email": "liu21st@gmail.com"
+                }
+            ],
+            "description": "thinkphp debug trace",
+            "support": {
+                "issues": "https://github.com/top-think/think-trace/issues",
+                "source": "https://github.com/top-think/think-trace/tree/v1.6"
+            },
+            "install-path": "../topthink/think-trace"
+        }
+    ],
+    "dev": true,
+    "dev-package-names": [
+        "symfony/polyfill-mbstring",
+        "symfony/polyfill-php72",
+        "symfony/polyfill-php80",
+        "symfony/var-dumper",
+        "topthink/think-trace"
+    ]
+}

+ 239 - 0
vendor/composer/installed.php

@@ -0,0 +1,239 @@
+<?php return array(
+    'root' => array(
+        'name' => 'topthink/think',
+        'pretty_version' => 'dev-master',
+        'version' => 'dev-master',
+        'reference' => '5e67d13ebbbd4bf85641c0e7fd74c7d1fa73659b',
+        'type' => 'project',
+        'install_path' => __DIR__ . '/../../',
+        'aliases' => array(),
+        'dev' => true,
+    ),
+    'versions' => array(
+        'doctrine/annotations' => array(
+            'pretty_version' => '1.14.3',
+            'version' => '1.14.3.0',
+            'reference' => 'fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../doctrine/annotations',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'doctrine/deprecations' => array(
+            'pretty_version' => 'v1.0.0',
+            'version' => '1.0.0.0',
+            'reference' => '0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../doctrine/deprecations',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'doctrine/lexer' => array(
+            'pretty_version' => '2.1.0',
+            'version' => '2.1.0.0',
+            'reference' => '39ab8fcf5a51ce4b85ca97c7a7d033eb12831124',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../doctrine/lexer',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'league/flysystem' => array(
+            'pretty_version' => '1.1.10',
+            'version' => '1.1.10.0',
+            'reference' => '3239285c825c152bcc315fe0e87d6b55f5972ed1',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../league/flysystem',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'league/flysystem-cached-adapter' => array(
+            'pretty_version' => '1.1.0',
+            'version' => '1.1.0.0',
+            'reference' => 'd1925efb2207ac4be3ad0c40b8277175f99ffaff',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../league/flysystem-cached-adapter',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'league/mime-type-detection' => array(
+            'pretty_version' => '1.11.0',
+            'version' => '1.11.0.0',
+            'reference' => 'ff6248ea87a9f116e78edd6002e39e5128a0d4dd',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../league/mime-type-detection',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'php-di/phpdoc-reader' => array(
+            'pretty_version' => '2.2.1',
+            'version' => '2.2.1.0',
+            'reference' => '66daff34cbd2627740ffec9469ffbac9f8c8185c',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../php-di/phpdoc-reader',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/cache' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/cache',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/container' => array(
+            'pretty_version' => '1.1.1',
+            'version' => '1.1.1.0',
+            'reference' => '8622567409010282b7aeebe4bb841fe98b58dcaf',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/container',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/http-message' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/http-message',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/log' => array(
+            'pretty_version' => '1.1.4',
+            'version' => '1.1.4.0',
+            'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/log',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/simple-cache' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/simple-cache',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'qeq66/jwt' => array(
+            'pretty_version' => '3.3.5',
+            'version' => '3.3.5.0',
+            'reference' => 'bd2fa6c51704dc18c61026c852c789224d7190a0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../qeq66/jwt',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'symfony/polyfill-mbstring' => array(
+            'pretty_version' => 'v1.27.0',
+            'version' => '1.27.0.0',
+            'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'symfony/polyfill-php72' => array(
+            'pretty_version' => 'v1.27.0',
+            'version' => '1.27.0.0',
+            'reference' => '869329b1e9894268a8a61dabb69153029b7a8c97',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/polyfill-php72',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'symfony/polyfill-php80' => array(
+            'pretty_version' => 'v1.27.0',
+            'version' => '1.27.0.0',
+            'reference' => '7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/polyfill-php80',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'symfony/var-dumper' => array(
+            'pretty_version' => 'v4.4.47',
+            'version' => '4.4.47.0',
+            'reference' => '1069c7a3fca74578022fab6f81643248d02f8e63',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/var-dumper',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+        'thans/tp-jwt-auth' => array(
+            'pretty_version' => 'v1.3.1',
+            'version' => '1.3.1.0',
+            'reference' => 'ab5efcc0fd920df81fea2c404c34bb967ef13aba',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../thans/tp-jwt-auth',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'topthink/framework' => array(
+            'pretty_version' => 'v6.1.2',
+            'version' => '6.1.2.0',
+            'reference' => '67235be5b919aaaf1de5aed9839f65d8e766aca3',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/framework',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'topthink/think' => array(
+            'pretty_version' => 'dev-master',
+            'version' => 'dev-master',
+            'reference' => '5e67d13ebbbd4bf85641c0e7fd74c7d1fa73659b',
+            'type' => 'project',
+            'install_path' => __DIR__ . '/../../',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'topthink/think-annotation' => array(
+            'pretty_version' => 'v1.0.0',
+            'version' => '1.0.0.0',
+            'reference' => 'fa45ccc7e6e8a9ee5f46461bd0fff2a1b93401d8',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/think-annotation',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'topthink/think-filesystem' => array(
+            'pretty_version' => 'v1.0.3',
+            'version' => '1.0.3.0',
+            'reference' => '29f19f140a9267c717fecd7ccb22c84c2d72382e',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/think-filesystem',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'topthink/think-helper' => array(
+            'pretty_version' => 'v3.1.6',
+            'version' => '3.1.6.0',
+            'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/think-helper',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'topthink/think-orm' => array(
+            'pretty_version' => 'v2.0.60',
+            'version' => '2.0.60.0',
+            'reference' => '8bc34a4307fa27186c0e96a9b3de3cb23aa1ed46',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/think-orm',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'topthink/think-trace' => array(
+            'pretty_version' => 'v1.6',
+            'version' => '1.6.0.0',
+            'reference' => '136cd5d97e8bdb780e4b5c1637c588ed7ca3e142',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../topthink/think-trace',
+            'aliases' => array(),
+            'dev_requirement' => true,
+        ),
+    ),
+);

+ 26 - 0
vendor/composer/platform_check.php

@@ -0,0 +1,26 @@
+<?php
+
+// platform_check.php @generated by Composer
+
+$issues = array();
+
+if (!(PHP_VERSION_ID >= 70205)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+        } elseif (!headers_sent()) {
+            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+        }
+    }
+    trigger_error(
+        'Composer detected issues in your platform: ' . implode(' ', $issues),
+        E_USER_ERROR
+    );
+}

+ 19 - 0
vendor/doctrine/annotations/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2006-2013 Doctrine Project
+
+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.

+ 24 - 0
vendor/doctrine/annotations/README.md

@@ -0,0 +1,24 @@
+⚠️ PHP 8 introduced
+[attributes](https://www.php.net/manual/en/language.attributes.overview.php),
+which are a native replacement for annotations. As such, this library is
+considered feature complete, and should receive exclusively bugfixes and
+security fixes.
+
+# Doctrine Annotations
+
+[![Build Status](https://github.com/doctrine/annotations/workflows/Continuous%20Integration/badge.svg?label=build)](https://github.com/doctrine/persistence/actions)
+[![Dependency Status](https://www.versioneye.com/package/php--doctrine--annotations/badge.png)](https://www.versioneye.com/package/php--doctrine--annotations)
+[![Reference Status](https://www.versioneye.com/php/doctrine:annotations/reference_badge.svg)](https://www.versioneye.com/php/doctrine:annotations/references)
+[![Total Downloads](https://poser.pugx.org/doctrine/annotations/downloads.png)](https://packagist.org/packages/doctrine/annotations)
+[![Latest Stable Version](https://img.shields.io/packagist/v/doctrine/annotations.svg?label=stable)](https://packagist.org/packages/doctrine/annotations)
+
+Docblock Annotations Parser library (extracted from [Doctrine Common](https://github.com/doctrine/common)).
+
+## Documentation
+
+See the [doctrine-project website](https://www.doctrine-project.org/projects/doctrine-annotations/en/latest/index.html).
+
+## Contributing
+
+When making a pull request, make sure your changes follow the
+[Coding Standard Guidelines](https://www.doctrine-project.org/projects/doctrine-coding-standard/en/current/reference/index.html#introduction).

+ 72 - 0
vendor/doctrine/annotations/composer.json

@@ -0,0 +1,72 @@
+{
+    "name": "doctrine/annotations",
+    "description": "Docblock Annotations Parser",
+    "license": "MIT",
+    "type": "library",
+    "keywords": [
+        "annotations",
+        "docblock",
+        "parser"
+    ],
+    "authors": [
+        {
+            "name": "Guilherme Blanco",
+            "email": "guilhermeblanco@gmail.com"
+        },
+        {
+            "name": "Roman Borschel",
+            "email": "roman@code-factory.org"
+        },
+        {
+            "name": "Benjamin Eberlei",
+            "email": "kontakt@beberlei.de"
+        },
+        {
+            "name": "Jonathan Wage",
+            "email": "jonwage@gmail.com"
+        },
+        {
+            "name": "Johannes Schmitt",
+            "email": "schmittjoh@gmail.com"
+        }
+    ],
+    "homepage": "https://www.doctrine-project.org/projects/annotations.html",
+    "require": {
+        "php": "^7.1 || ^8.0",
+        "ext-tokenizer": "*",
+        "doctrine/lexer": "^1 || ^2",
+        "psr/cache": "^1 || ^2 || ^3"
+    },
+    "require-dev": {
+        "doctrine/cache": "^1.11 || ^2.0",
+        "doctrine/coding-standard": "^9 || ^10",
+        "phpstan/phpstan": "~1.4.10 || ^1.8.0",
+        "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+        "symfony/cache": "^4.4 || ^5.4 || ^6",
+        "vimeo/psalm": "^4.10"
+    },
+    "suggest": {
+        "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
+    },
+    "autoload": {
+        "psr-4": {
+            "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Doctrine\\Performance\\Common\\Annotations\\": "tests/Doctrine/Performance/Common/Annotations",
+            "Doctrine\\Tests\\Common\\Annotations\\": "tests/Doctrine/Tests/Common/Annotations"
+        },
+        "files": [
+            "tests/Doctrine/Tests/Common/Annotations/Fixtures/functions.php",
+            "tests/Doctrine/Tests/Common/Annotations/Fixtures/SingleClassLOC1000.php"
+        ]
+    },
+    "config": {
+        "allow-plugins": {
+            "dealerdirect/phpcodesniffer-composer-installer": true
+        },
+        "sort-packages": true
+    }
+}

+ 252 - 0
vendor/doctrine/annotations/docs/en/annotations.rst

@@ -0,0 +1,252 @@
+Handling Annotations
+====================
+
+There are several different approaches to handling annotations in PHP.
+Doctrine Annotations maps docblock annotations to PHP classes. Because
+not all docblock annotations are used for metadata purposes a filter is
+applied to ignore or skip classes that are not Doctrine annotations.
+
+Take a look at the following code snippet:
+
+.. code-block:: php
+
+    namespace MyProject\Entities;
+
+    use Doctrine\ORM\Mapping AS ORM;
+    use Symfony\Component\Validator\Constraints AS Assert;
+
+    /**
+     * @author Benjamin Eberlei
+     * @ORM\Entity
+     * @MyProject\Annotations\Foobarable
+     */
+    class User
+    {
+        /**
+         * @ORM\Id @ORM\Column @ORM\GeneratedValue
+         * @dummy
+         * @var int
+         */
+        private $id;
+
+        /**
+         * @ORM\Column(type="string")
+         * @Assert\NotEmpty
+         * @Assert\Email
+         * @var string
+         */
+        private $email;
+    }
+
+In this snippet you can see a variety of different docblock annotations:
+
+- Documentation annotations such as ``@var`` and ``@author``. These
+  annotations are ignored and never considered for throwing an
+  exception due to wrongly used annotations.
+- Annotations imported through use statements. The statement ``use
+  Doctrine\ORM\Mapping AS ORM`` makes all classes under that namespace
+  available as ``@ORM\ClassName``. Same goes for the import of
+  ``@Assert``.
+- The ``@dummy`` annotation. It is not a documentation annotation and
+  not ignored. For Doctrine Annotations it is not entirely clear how
+  to handle this annotation. Depending on the configuration an exception
+  (unknown annotation) will be thrown when parsing this annotation.
+- The fully qualified annotation ``@MyProject\Annotations\Foobarable``.
+  This is transformed directly into the given class name.
+
+How are these annotations loaded? From looking at the code you could
+guess that the ORM Mapping, Assert Validation and the fully qualified
+annotation can just be loaded using
+the defined PHP autoloaders. This is not the case however: For error
+handling reasons every check for class existence inside the
+``AnnotationReader`` sets the second parameter $autoload
+of ``class_exists($name, $autoload)`` to false. To work flawlessly the
+``AnnotationReader`` requires silent autoloaders which many autoloaders are
+not. Silent autoloading is NOT part of the `PSR-0 specification
+<https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md>`_
+for autoloading.
+
+This is why Doctrine Annotations uses its own autoloading mechanism
+through a global registry. If you are wondering about the annotation
+registry being global, there is no other way to solve the architectural
+problems of autoloading annotation classes in a straightforward fashion.
+Additionally if you think about PHP autoloading then you recognize it is
+a global as well.
+
+To anticipate the configuration section, making the above PHP class work
+with Doctrine Annotations requires this setup:
+
+.. code-block:: php
+
+    use Doctrine\Common\Annotations\AnnotationReader;
+    use Doctrine\Common\Annotations\AnnotationRegistry;
+
+    AnnotationRegistry::registerFile("/path/to/doctrine/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php");
+    AnnotationRegistry::registerAutoloadNamespace("Symfony\Component\Validator\Constraint", "/path/to/symfony/src");
+    AnnotationRegistry::registerAutoloadNamespace("MyProject\Annotations", "/path/to/myproject/src");
+
+    $reader = new AnnotationReader();
+    AnnotationReader::addGlobalIgnoredName('dummy');
+
+The second block with the annotation registry calls registers all the
+three different annotation namespaces that are used.
+Doctrine Annotations saves all its annotations in a single file, that is
+why ``AnnotationRegistry#registerFile`` is used in contrast to
+``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0
+compatible loading mechanism for class to file names.
+
+In the third block, we create the actual ``AnnotationReader`` instance.
+Note that we also add ``dummy`` to the global list of ignored
+annotations for which we do not throw exceptions. Setting this is
+necessary in our example case, otherwise ``@dummy`` would trigger an
+exception to be thrown during the parsing of the docblock of
+``MyProject\Entities\User#id``.
+
+Setup and Configuration
+-----------------------
+
+To use the annotations library is simple, you just need to create a new
+``AnnotationReader`` instance:
+
+.. code-block:: php
+
+    $reader = new \Doctrine\Common\Annotations\AnnotationReader();
+
+This creates a simple annotation reader with no caching other than in
+memory (in php arrays). Since parsing docblocks can be expensive you
+should cache this process by using a caching reader.
+
+To cache annotations, you can create a ``Doctrine\Common\Annotations\PsrCachedReader``.
+This reader decorates the original reader and stores all annotations in a PSR-6
+cache:
+
+.. code-block:: php
+
+    use Doctrine\Common\Annotations\AnnotationReader;
+    use Doctrine\Common\Annotations\PsrCachedReader;
+
+    $cache = ... // instantiate a PSR-6 Cache pool
+
+    $reader = new PsrCachedReader(
+        new AnnotationReader(),
+        $cache,
+        $debug = true
+    );
+
+The ``debug`` flag is used here as well to invalidate the cache files
+when the PHP class with annotations changed and should be used during
+development.
+
+.. warning ::
+
+    The ``AnnotationReader`` works and caches under the
+    assumption that all annotations of a doc-block are processed at
+    once. That means that annotation classes that do not exist and
+    aren't loaded and cannot be autoloaded (using the
+    AnnotationRegistry) would never be visible and not accessible if a
+    cache is used unless the cache is cleared and the annotations
+    requested again, this time with all annotations defined.
+
+By default the annotation reader returns a list of annotations with
+numeric indexes. If you want your annotations to be indexed by their
+class name you can wrap the reader in an ``IndexedReader``:
+
+.. code-block:: php
+
+    use Doctrine\Common\Annotations\AnnotationReader;
+    use Doctrine\Common\Annotations\IndexedReader;
+
+    $reader = new IndexedReader(new AnnotationReader());
+
+.. warning::
+
+    You should never wrap the indexed reader inside a cached reader,
+    only the other way around. This way you can re-use the cache with
+    indexed or numeric keys, otherwise your code may experience failures
+    due to caching in a numerical or indexed format.
+
+Registering Annotations
+~~~~~~~~~~~~~~~~~~~~~~~
+
+As explained in the introduction, Doctrine Annotations uses its own
+autoloading mechanism to determine if a given annotation has a
+corresponding PHP class that can be autoloaded. For annotation
+autoloading you have to configure the
+``Doctrine\Common\Annotations\AnnotationRegistry``. There are three
+different mechanisms to configure annotation autoloading:
+
+- Calling ``AnnotationRegistry#registerFile($file)`` to register a file
+  that contains one or more annotation classes.
+- Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs =
+  null)`` to register that the given namespace contains annotations and
+  that their base directory is located at the given $dirs or in the
+  include path if ``NULL`` is passed. The given directories should *NOT*
+  be the directory where classes of the namespace are in, but the base
+  directory of the root namespace. The AnnotationRegistry uses a
+  namespace to directory separator approach to resolve the correct path.
+- Calling ``AnnotationRegistry#registerLoader($callable)`` to register
+  an autoloader callback. The callback accepts the class as first and
+  only parameter and has to return ``true`` if the corresponding file
+  was found and included.
+
+.. note::
+
+    Loaders have to fail silently, if a class is not found even if it
+    matches for example the namespace prefix of that loader. Never is a
+    loader to throw a warning or exception if the loading failed
+    otherwise parsing doc block annotations will become a huge pain.
+
+A sample loader callback could look like:
+
+.. code-block:: php
+
+    use Doctrine\Common\Annotations\AnnotationRegistry;
+    use Symfony\Component\ClassLoader\UniversalClassLoader;
+
+    AnnotationRegistry::registerLoader(function($class) {
+        $file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php";
+
+        if (file_exists("/my/base/path/" . $file)) {
+            // file_exists() makes sure that the loader fails silently
+            require "/my/base/path/" . $file;
+        }
+    });
+
+    $loader = new UniversalClassLoader();
+    AnnotationRegistry::registerLoader(array($loader, "loadClass"));
+
+
+Ignoring missing exceptions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default an exception is thrown from the ``AnnotationReader`` if an
+annotation was found that:
+
+- is not part of the list of ignored "documentation annotations";
+- was not imported through a use statement;
+- is not a fully qualified class that exists.
+
+You can disable this behavior for specific names if your docblocks do
+not follow strict requirements:
+
+.. code-block:: php
+
+    $reader = new \Doctrine\Common\Annotations\AnnotationReader();
+    AnnotationReader::addGlobalIgnoredName('foo');
+
+PHP Imports
+~~~~~~~~~~~
+
+By default the annotation reader parses the use-statement of a php file
+to gain access to the import rules and register them for the annotation
+processing. Only if you are using PHP Imports can you validate the
+correct usage of annotations and throw exceptions if you misspelled an
+annotation. This mechanism is enabled by default.
+
+To ease the upgrade path, we still allow you to disable this mechanism.
+Note however that we will remove this in future versions:
+
+.. code-block:: php
+
+    $reader = new \Doctrine\Common\Annotations\AnnotationReader();
+    $reader->setEnabledPhpImports(false);

+ 443 - 0
vendor/doctrine/annotations/docs/en/custom.rst

@@ -0,0 +1,443 @@
+Custom Annotation Classes
+=========================
+
+If you want to define your own annotations, you just have to group them
+in a namespace and register this namespace in the ``AnnotationRegistry``.
+Annotation classes have to contain a class-level docblock with the text
+``@Annotation``:
+
+.. code-block:: php
+
+    namespace MyCompany\Annotations;
+
+    /** @Annotation */
+    class Bar
+    {
+        // some code
+    }
+
+Inject annotation values
+------------------------
+
+The annotation parser checks if the annotation constructor has arguments,
+if so then it will pass the value array, otherwise it will try to inject
+values into public properties directly:
+
+
+.. code-block:: php
+
+    namespace MyCompany\Annotations;
+
+    /**
+     * @Annotation
+     *
+     * Some Annotation using a constructor
+     */
+    class Bar
+    {
+        private $foo;
+
+        public function __construct(array $values)
+        {
+            $this->foo = $values['foo'];
+        }
+    }
+
+    /**
+     * @Annotation
+     *
+     * Some Annotation without a constructor
+     */
+    class Foo
+    {
+        public $bar;
+    }
+
+Optional: Constructors with Named Parameters
+--------------------------------------------
+
+Starting with Annotations v1.11 a new annotation instantiation strategy
+is available that aims at compatibility of Annotation classes with the PHP 8
+attribute feature. You need to declare a constructor with regular parameter 
+names that match the named arguments in the annotation syntax.
+
+To enable this feature, you can tag your annotation class with 
+``@NamedArgumentConstructor`` (available from v1.12) or implement the
+``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation`` interface
+(available from v1.11 and deprecated as of v1.12).
+When using the ``@NamedArgumentConstructor`` tag, the first argument of the
+constructor is considered as the default one.
+
+
+Usage with the ``@NamedArgumentConstructor`` tag
+
+.. code-block:: php
+
+    namespace MyCompany\Annotations;
+
+    /** 
+     * @Annotation 
+     * @NamedArgumentConstructor
+     */
+    class Bar implements NamedArgumentConstructorAnnotation
+    {
+        private $foo;
+
+        public function __construct(string $foo)
+        {
+            $this->foo = $foo;
+        }
+    }
+
+    /** Usable with @Bar(foo="baz") */
+    /** Usable with @Bar("baz") */
+
+In combination with PHP 8's constructor property promotion feature
+you can simplify this to:
+
+.. code-block:: php
+
+    namespace MyCompany\Annotations;
+
+    /** 
+     * @Annotation 
+     * @NamedArgumentConstructor
+     */
+    class Bar implements NamedArgumentConstructorAnnotation
+    {
+        public function __construct(private string $foo) {}
+    }
+
+
+Usage with the 
+``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation``
+interface (v1.11, deprecated as of v1.12):
+.. code-block:: php
+
+    namespace MyCompany\Annotations;
+
+    use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation;
+
+    /** @Annotation */
+    class Bar implements NamedArgumentConstructorAnnotation
+    {
+        private $foo;
+
+        public function __construct(private string $foo) {}
+    }
+
+    /** Usable with @Bar(foo="baz") */
+
+Annotation Target
+-----------------
+
+``@Target`` indicates the kinds of class elements to which an annotation
+type is applicable. Then you could define one or more targets:
+
+-  ``CLASS`` Allowed in class docblocks
+-  ``PROPERTY`` Allowed in property docblocks
+-  ``METHOD`` Allowed in the method docblocks
+-  ``FUNCTION`` Allowed in function dockblocks
+-  ``ALL`` Allowed in class, property, method and function docblocks
+-  ``ANNOTATION`` Allowed inside other annotations
+
+If the annotations is not allowed in the current context, an
+``AnnotationException`` is thrown.
+
+.. code-block:: php
+
+    namespace MyCompany\Annotations;
+
+    /**
+     * @Annotation
+     * @Target({"METHOD","PROPERTY"})
+     */
+    class Bar
+    {
+        // some code
+    }
+
+    /**
+     * @Annotation
+     * @Target("CLASS")
+     */
+    class Foo
+    {
+        // some code
+    }
+
+Attribute types
+---------------
+
+The annotation parser checks the given parameters using the phpdoc
+annotation ``@var``, The data type could be validated using the ``@var``
+annotation on the annotation properties or using the ``@Attributes`` and
+``@Attribute`` annotations.
+
+If the data type does not match you get an ``AnnotationException``
+
+.. code-block:: php
+
+    namespace MyCompany\Annotations;
+
+    /**
+     * @Annotation
+     * @Target({"METHOD","PROPERTY"})
+     */
+    class Bar
+    {
+        /** @var mixed */
+        public $mixed;
+
+        /** @var boolean */
+        public $boolean;
+
+        /** @var bool */
+        public $bool;
+
+        /** @var float */
+        public $float;
+
+        /** @var string */
+        public $string;
+
+        /** @var integer */
+        public $integer;
+
+        /** @var array */
+        public $array;
+
+        /** @var SomeAnnotationClass */
+        public $annotation;
+
+        /** @var array<integer> */
+        public $arrayOfIntegers;
+
+        /** @var array<SomeAnnotationClass> */
+        public $arrayOfAnnotations;
+    }
+
+    /**
+     * @Annotation
+     * @Target({"METHOD","PROPERTY"})
+     * @Attributes({
+     *   @Attribute("stringProperty", type = "string"),
+     *   @Attribute("annotProperty",  type = "SomeAnnotationClass"),
+     * })
+     */
+    class Foo
+    {
+        public function __construct(array $values)
+        {
+            $this->stringProperty = $values['stringProperty'];
+            $this->annotProperty = $values['annotProperty'];
+        }
+
+        // some code
+    }
+
+Annotation Required
+-------------------
+
+``@Required`` indicates that the field must be specified when the
+annotation is used. If it is not used you get an ``AnnotationException``
+stating that this value can not be null.
+
+Declaring a required field:
+
+.. code-block:: php
+
+    /**
+     * @Annotation
+     * @Target("ALL")
+     */
+    class Foo
+    {
+        /** @Required */
+        public $requiredField;
+    }
+
+Usage:
+
+.. code-block:: php
+
+    /** @Foo(requiredField="value") */
+    public $direction;                  // Valid
+
+     /** @Foo */
+    public $direction;                  // Required field missing, throws an AnnotationException
+
+
+Enumerated values
+-----------------
+
+- An annotation property marked with ``@Enum`` is a field that accepts a
+  fixed set of scalar values.
+- You should use ``@Enum`` fields any time you need to represent fixed
+  values.
+- The annotation parser checks the given value and throws an
+  ``AnnotationException`` if the value does not match.
+
+
+Declaring an enumerated property:
+
+.. code-block:: php
+
+    /**
+     * @Annotation
+     * @Target("ALL")
+     */
+    class Direction
+    {
+        /**
+         * @Enum({"NORTH", "SOUTH", "EAST", "WEST"})
+         */
+        public $value;
+    }
+
+Annotation usage:
+
+.. code-block:: php
+
+    /** @Direction("NORTH") */
+    public $direction;                  // Valid value
+
+     /** @Direction("NORTHEAST") */
+    public $direction;                  // Invalid value, throws an AnnotationException
+
+
+Constants
+---------
+
+The use of constants and class constants is available on the annotations
+parser.
+
+The following usages are allowed:
+
+.. code-block:: php
+
+    namespace MyCompany\Entity;
+
+    use MyCompany\Annotations\Foo;
+    use MyCompany\Annotations\Bar;
+    use MyCompany\Entity\SomeClass;
+
+    /**
+     * @Foo(PHP_EOL)
+     * @Bar(Bar::FOO)
+     * @Foo({SomeClass::FOO, SomeClass::BAR})
+     * @Bar({SomeClass::FOO_KEY = SomeClass::BAR_VALUE})
+     */
+    class User
+    {
+    }
+
+
+Be careful with constants and the cache !
+
+.. note::
+
+    The cached reader will not re-evaluate each time an annotation is
+    loaded from cache. When a constant is changed the cache must be
+    cleaned.
+
+
+Usage
+-----
+
+Using the library API is simple. Using the annotations described in the
+previous section, you can now annotate other classes with your
+annotations:
+
+.. code-block:: php
+
+    namespace MyCompany\Entity;
+
+    use MyCompany\Annotations\Foo;
+    use MyCompany\Annotations\Bar;
+
+    /**
+     * @Foo(bar="foo")
+     * @Bar(foo="bar")
+     */
+    class User
+    {
+    }
+
+Now we can write a script to get the annotations above:
+
+.. code-block:: php
+
+    $reflClass = new ReflectionClass('MyCompany\Entity\User');
+    $classAnnotations = $reader->getClassAnnotations($reflClass);
+
+    foreach ($classAnnotations AS $annot) {
+        if ($annot instanceof \MyCompany\Annotations\Foo) {
+            echo $annot->bar; // prints "foo";
+        } else if ($annot instanceof \MyCompany\Annotations\Bar) {
+            echo $annot->foo; // prints "bar";
+        }
+    }
+
+You have a complete API for retrieving annotation class instances from a
+class, property or method docblock:
+
+
+Reader API
+~~~~~~~~~~
+
+Access all annotations of a class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getClassAnnotations(\ReflectionClass $class);
+
+Access one annotation of a class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getClassAnnotation(\ReflectionClass $class, $annotationName);
+
+Access all annotations of a method
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getMethodAnnotations(\ReflectionMethod $method);
+
+Access one annotation of a method
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getMethodAnnotation(\ReflectionMethod $method, $annotationName);
+
+Access all annotations of a property
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getPropertyAnnotations(\ReflectionProperty $property);
+
+Access one annotation of a property
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName);
+
+Access all annotations of a function
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getFunctionAnnotations(\ReflectionFunction $property);
+
+Access one annotation of a function
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code-block:: php
+
+    public function getFunctionAnnotation(\ReflectionFunction $property, $annotationName);

+ 110 - 0
vendor/doctrine/annotations/docs/en/index.rst

@@ -0,0 +1,110 @@
+Deprecation notice
+==================
+
+PHP 8 introduced `attributes
+<https://www.php.net/manual/en/language.attributes.overview.php>`_,
+which are a native replacement for annotations. As such, this library is
+considered feature complete, and should receive exclusively bugfixes and
+security fixes.
+
+Introduction
+============
+
+Doctrine Annotations allows to implement custom annotation
+functionality for PHP classes and functions.
+
+.. code-block:: php
+
+    class Foo
+    {
+        /**
+         * @MyAnnotation(myProperty="value")
+         */
+        private $bar;
+    }
+
+Annotations aren't implemented in PHP itself which is why this component
+offers a way to use the PHP doc-blocks as a place for the well known
+annotation syntax using the ``@`` char.
+
+Annotations in Doctrine are used for the ORM configuration to build the
+class mapping, but it can be used in other projects for other purposes
+too.
+
+Installation
+============
+
+You can install the Annotation component with composer:
+
+.. code-block::
+
+    $ composer require doctrine/annotations
+
+Create an annotation class
+==========================
+
+An annotation class is a representation of the later used annotation
+configuration in classes. The annotation class of the previous example
+looks like this:
+
+.. code-block:: php
+
+    /**
+     * @Annotation
+     */
+    final class MyAnnotation
+    {
+        public $myProperty;
+    }
+
+The annotation class is declared as an annotation by ``@Annotation``.
+
+:ref:`Read more about custom annotations. <custom>`
+
+Reading annotations
+===================
+
+The access to the annotations happens by reflection of the class or function
+containing them. There are multiple reader-classes implementing the
+``Doctrine\Common\Annotations\Reader`` interface, that can access the
+annotations of a class. A common one is
+``Doctrine\Common\Annotations\AnnotationReader``:
+
+.. code-block:: php
+
+    use Doctrine\Common\Annotations\AnnotationReader;
+    use Doctrine\Common\Annotations\AnnotationRegistry;
+
+    // Deprecated and will be removed in 2.0 but currently needed
+    AnnotationRegistry::registerLoader('class_exists');
+
+    $reflectionClass = new ReflectionClass(Foo::class);
+    $property = $reflectionClass->getProperty('bar');
+
+    $reader = new AnnotationReader();
+    $myAnnotation = $reader->getPropertyAnnotation(
+        $property,
+        MyAnnotation::class
+    );
+
+    echo $myAnnotation->myProperty; // result: "value"
+
+Note that ``AnnotationRegistry::registerLoader('class_exists')`` only works
+if you already have an autoloader configured (i.e. composer autoloader).
+Otherwise, :ref:`please take a look to the other annotation autoload mechanisms <annotations>`.
+
+A reader has multiple methods to access the annotations of a class or
+function.
+
+:ref:`Read more about handling annotations. <annotations>`
+
+IDE Support
+-----------
+
+Some IDEs already provide support for annotations:
+
+- Eclipse via the `Symfony2 Plugin <https://github.com/pulse00/Symfony-2-Eclipse-Plugin>`_
+- PhpStorm via the `PHP Annotations Plugin <https://plugins.jetbrains.com/plugin/7320-php-annotations>`_ or the `Symfony Plugin <https://plugins.jetbrains.com/plugin/7219-symfony-support>`_
+
+.. _Read more about handling annotations.: annotations
+.. _Read more about custom annotations.: custom

+ 6 - 0
vendor/doctrine/annotations/docs/en/sidebar.rst

@@ -0,0 +1,6 @@
+.. toctree::
+    :depth: 3
+
+    index
+    annotations
+    custom

+ 57 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use BadMethodCallException;
+
+use function sprintf;
+
+/**
+ * Annotations class.
+ */
+class Annotation
+{
+    /**
+     * Value property. Common among all derived classes.
+     *
+     * @var mixed
+     */
+    public $value;
+
+    /** @param array<string, mixed> $data Key-value for properties to be defined in this class. */
+    final public function __construct(array $data)
+    {
+        foreach ($data as $key => $value) {
+            $this->$key = $value;
+        }
+    }
+
+    /**
+     * Error handler for unknown property accessor in Annotation class.
+     *
+     * @param string $name Unknown property name.
+     *
+     * @throws BadMethodCallException
+     */
+    public function __get($name)
+    {
+        throw new BadMethodCallException(
+            sprintf("Unknown property '%s' on annotation '%s'.", $name, static::class)
+        );
+    }
+
+    /**
+     * Error handler for unknown property mutator in Annotation class.
+     *
+     * @param string $name  Unknown property name.
+     * @param mixed  $value Property value.
+     *
+     * @throws BadMethodCallException
+     */
+    public function __set($name, $value)
+    {
+        throw new BadMethodCallException(
+            sprintf("Unknown property '%s' on annotation '%s'.", $name, static::class)
+        );
+    }
+}

+ 21 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check the attribute type during the parsing process.
+ *
+ * @Annotation
+ */
+final class Attribute
+{
+    /** @var string */
+    public $name;
+
+    /** @var string */
+    public $type;
+
+    /** @var bool */
+    public $required = false;
+}

+ 15 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check the types of all declared attributes during the parsing process.
+ *
+ * @Annotation
+ */
+final class Attributes
+{
+    /** @var array<Attribute> */
+    public $value;
+}

+ 69 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+use InvalidArgumentException;
+
+use function get_class;
+use function gettype;
+use function in_array;
+use function is_object;
+use function is_scalar;
+use function sprintf;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check the available values during the parsing process.
+ *
+ * @Annotation
+ * @Attributes({
+ *    @Attribute("value",   required = true,  type = "array"),
+ *    @Attribute("literal", required = false, type = "array")
+ * })
+ */
+final class Enum
+{
+    /** @phpstan-var list<scalar> */
+    public $value;
+
+    /**
+     * Literal target declaration.
+     *
+     * @var mixed[]
+     */
+    public $literal;
+
+    /**
+     * @phpstan-param array{literal?: mixed[], value: list<scalar>} $values
+     *
+     * @throws InvalidArgumentException
+     */
+    public function __construct(array $values)
+    {
+        if (! isset($values['literal'])) {
+            $values['literal'] = [];
+        }
+
+        foreach ($values['value'] as $var) {
+            if (! is_scalar($var)) {
+                throw new InvalidArgumentException(sprintf(
+                    '@Enum supports only scalar values "%s" given.',
+                    is_object($var) ? get_class($var) : gettype($var)
+                ));
+            }
+        }
+
+        foreach ($values['literal'] as $key => $var) {
+            if (! in_array($key, $values['value'])) {
+                throw new InvalidArgumentException(sprintf(
+                    'Undefined enumerator value "%s" for literal "%s".',
+                    $key,
+                    $var
+                ));
+            }
+        }
+
+        $this->value   = $values['value'];
+        $this->literal = $values['literal'];
+    }
+}

+ 43 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+use RuntimeException;
+
+use function is_array;
+use function is_string;
+use function json_encode;
+use function sprintf;
+
+/**
+ * Annotation that can be used to signal to the parser to ignore specific
+ * annotations during the parsing process.
+ *
+ * @Annotation
+ */
+final class IgnoreAnnotation
+{
+    /** @phpstan-var list<string> */
+    public $names;
+
+    /**
+     * @phpstan-param array{value: string|list<string>} $values
+     *
+     * @throws RuntimeException
+     */
+    public function __construct(array $values)
+    {
+        if (is_string($values['value'])) {
+            $values['value'] = [$values['value']];
+        }
+
+        if (! is_array($values['value'])) {
+            throw new RuntimeException(sprintf(
+                '@IgnoreAnnotation expects either a string name, or an array of strings, but got %s.',
+                json_encode($values['value'])
+            ));
+        }
+
+        $this->names = $values['value'];
+    }
+}

+ 13 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/NamedArgumentConstructor.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that indicates that the annotated class should be constructed with a named argument call.
+ *
+ * @Annotation
+ * @Target("CLASS")
+ */
+final class NamedArgumentConstructor
+{
+}

+ 13 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check if that attribute is required during the parsing process.
+ *
+ * @Annotation
+ */
+final class Required
+{
+}

+ 101 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php

@@ -0,0 +1,101 @@
+<?php
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+use InvalidArgumentException;
+
+use function array_keys;
+use function get_class;
+use function gettype;
+use function implode;
+use function is_array;
+use function is_object;
+use function is_string;
+use function sprintf;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check the annotation target during the parsing process.
+ *
+ * @Annotation
+ */
+final class Target
+{
+    public const TARGET_CLASS      = 1;
+    public const TARGET_METHOD     = 2;
+    public const TARGET_PROPERTY   = 4;
+    public const TARGET_ANNOTATION = 8;
+    public const TARGET_FUNCTION   = 16;
+    public const TARGET_ALL        = 31;
+
+    /** @var array<string, int> */
+    private static $map = [
+        'ALL'        => self::TARGET_ALL,
+        'CLASS'      => self::TARGET_CLASS,
+        'METHOD'     => self::TARGET_METHOD,
+        'PROPERTY'   => self::TARGET_PROPERTY,
+        'FUNCTION'   => self::TARGET_FUNCTION,
+        'ANNOTATION' => self::TARGET_ANNOTATION,
+    ];
+
+    /** @phpstan-var list<string> */
+    public $value;
+
+    /**
+     * Targets as bitmask.
+     *
+     * @var int
+     */
+    public $targets;
+
+    /**
+     * Literal target declaration.
+     *
+     * @var string
+     */
+    public $literal;
+
+    /**
+     * @phpstan-param array{value?: string|list<string>} $values
+     *
+     * @throws InvalidArgumentException
+     */
+    public function __construct(array $values)
+    {
+        if (! isset($values['value'])) {
+            $values['value'] = null;
+        }
+
+        if (is_string($values['value'])) {
+            $values['value'] = [$values['value']];
+        }
+
+        if (! is_array($values['value'])) {
+            throw new InvalidArgumentException(
+                sprintf(
+                    '@Target expects either a string value, or an array of strings, "%s" given.',
+                    is_object($values['value']) ? get_class($values['value']) : gettype($values['value'])
+                )
+            );
+        }
+
+        $bitmask = 0;
+        foreach ($values['value'] as $literal) {
+            if (! isset(self::$map[$literal])) {
+                throw new InvalidArgumentException(
+                    sprintf(
+                        'Invalid Target "%s". Available targets: [%s]',
+                        $literal,
+                        implode(', ', array_keys(self::$map))
+                    )
+                );
+            }
+
+            $bitmask |= self::$map[$literal];
+        }
+
+        $this->targets = $bitmask;
+        $this->value   = $values['value'];
+        $this->literal = implode(', ', $this->value);
+    }
+}

+ 167 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php

@@ -0,0 +1,167 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use Exception;
+use Throwable;
+
+use function get_class;
+use function gettype;
+use function implode;
+use function is_object;
+use function sprintf;
+
+/**
+ * Description of AnnotationException
+ */
+class AnnotationException extends Exception
+{
+    /**
+     * Creates a new AnnotationException describing a Syntax error.
+     *
+     * @param string $message Exception message
+     *
+     * @return AnnotationException
+     */
+    public static function syntaxError($message)
+    {
+        return new self('[Syntax Error] ' . $message);
+    }
+
+    /**
+     * Creates a new AnnotationException describing a Semantical error.
+     *
+     * @param string $message Exception message
+     *
+     * @return AnnotationException
+     */
+    public static function semanticalError($message)
+    {
+        return new self('[Semantical Error] ' . $message);
+    }
+
+    /**
+     * Creates a new AnnotationException describing an error which occurred during
+     * the creation of the annotation.
+     *
+     * @param string $message
+     *
+     * @return AnnotationException
+     */
+    public static function creationError($message, ?Throwable $previous = null)
+    {
+        return new self('[Creation Error] ' . $message, 0, $previous);
+    }
+
+    /**
+     * Creates a new AnnotationException describing a type error.
+     *
+     * @param string $message
+     *
+     * @return AnnotationException
+     */
+    public static function typeError($message)
+    {
+        return new self('[Type Error] ' . $message);
+    }
+
+    /**
+     * Creates a new AnnotationException describing a constant semantical error.
+     *
+     * @param string $identifier
+     * @param string $context
+     *
+     * @return AnnotationException
+     */
+    public static function semanticalErrorConstants($identifier, $context = null)
+    {
+        return self::semanticalError(sprintf(
+            "Couldn't find constant %s%s.",
+            $identifier,
+            $context ? ', ' . $context : ''
+        ));
+    }
+
+    /**
+     * Creates a new AnnotationException describing an type error of an attribute.
+     *
+     * @param string $attributeName
+     * @param string $annotationName
+     * @param string $context
+     * @param string $expected
+     * @param mixed  $actual
+     *
+     * @return AnnotationException
+     */
+    public static function attributeTypeError($attributeName, $annotationName, $context, $expected, $actual)
+    {
+        return self::typeError(sprintf(
+            'Attribute "%s" of @%s declared on %s expects %s, but got %s.',
+            $attributeName,
+            $annotationName,
+            $context,
+            $expected,
+            is_object($actual) ? 'an instance of ' . get_class($actual) : gettype($actual)
+        ));
+    }
+
+    /**
+     * Creates a new AnnotationException describing an required error of an attribute.
+     *
+     * @param string $attributeName
+     * @param string $annotationName
+     * @param string $context
+     * @param string $expected
+     *
+     * @return AnnotationException
+     */
+    public static function requiredError($attributeName, $annotationName, $context, $expected)
+    {
+        return self::typeError(sprintf(
+            'Attribute "%s" of @%s declared on %s expects %s. This value should not be null.',
+            $attributeName,
+            $annotationName,
+            $context,
+            $expected
+        ));
+    }
+
+    /**
+     * Creates a new AnnotationException describing a invalid enummerator.
+     *
+     * @param string $attributeName
+     * @param string $annotationName
+     * @param string $context
+     * @param mixed  $given
+     * @phpstan-param list<string>        $available
+     *
+     * @return AnnotationException
+     */
+    public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
+    {
+        return new self(sprintf(
+            '[Enum Error] Attribute "%s" of @%s declared on %s accepts only [%s], but got %s.',
+            $attributeName,
+            $annotationName,
+            $context,
+            implode(', ', $available),
+            is_object($given) ? get_class($given) : $given
+        ));
+    }
+
+    /** @return AnnotationException */
+    public static function optimizerPlusSaveComments()
+    {
+        return new self(
+            'You have to enable opcache.save_comments=1 or zend_optimizerplus.save_comments=1.'
+        );
+    }
+
+    /** @return AnnotationException */
+    public static function optimizerPlusLoadComments()
+    {
+        return new self(
+            'You have to enable opcache.load_comments=1 or zend_optimizerplus.load_comments=1.'
+        );
+    }
+}

+ 389 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php

@@ -0,0 +1,389 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation;
+use Doctrine\Common\Annotations\Annotation\Target;
+use ReflectionClass;
+use ReflectionFunction;
+use ReflectionMethod;
+use ReflectionProperty;
+
+use function array_merge;
+use function class_exists;
+use function extension_loaded;
+use function ini_get;
+
+/**
+ * A reader for docblock annotations.
+ */
+class AnnotationReader implements Reader
+{
+    /**
+     * Global map for imports.
+     *
+     * @var array<string, class-string>
+     */
+    private static $globalImports = [
+        'ignoreannotation' => Annotation\IgnoreAnnotation::class,
+    ];
+
+    /**
+     * A list with annotations that are not causing exceptions when not resolved to an annotation class.
+     *
+     * The names are case sensitive.
+     *
+     * @var array<string, true>
+     */
+    private static $globalIgnoredNames = ImplicitlyIgnoredAnnotationNames::LIST;
+
+    /**
+     * A list with annotations that are not causing exceptions when not resolved to an annotation class.
+     *
+     * The names are case sensitive.
+     *
+     * @var array<string, true>
+     */
+    private static $globalIgnoredNamespaces = [];
+
+    /**
+     * Add a new annotation to the globally ignored annotation names with regard to exception handling.
+     *
+     * @param string $name
+     */
+    public static function addGlobalIgnoredName($name)
+    {
+        self::$globalIgnoredNames[$name] = true;
+    }
+
+    /**
+     * Add a new annotation to the globally ignored annotation namespaces with regard to exception handling.
+     *
+     * @param string $namespace
+     */
+    public static function addGlobalIgnoredNamespace($namespace)
+    {
+        self::$globalIgnoredNamespaces[$namespace] = true;
+    }
+
+    /**
+     * Annotations parser.
+     *
+     * @var DocParser
+     */
+    private $parser;
+
+    /**
+     * Annotations parser used to collect parsing metadata.
+     *
+     * @var DocParser
+     */
+    private $preParser;
+
+    /**
+     * PHP parser used to collect imports.
+     *
+     * @var PhpParser
+     */
+    private $phpParser;
+
+    /**
+     * In-memory cache mechanism to store imported annotations per class.
+     *
+     * @psalm-var array<'class'|'function', array<string, array<string, class-string>>>
+     */
+    private $imports = [];
+
+    /**
+     * In-memory cache mechanism to store ignored annotations per class.
+     *
+     * @psalm-var array<'class'|'function', array<string, array<string, true>>>
+     */
+    private $ignoredAnnotationNames = [];
+
+    /**
+     * Initializes a new AnnotationReader.
+     *
+     * @throws AnnotationException
+     */
+    public function __construct(?DocParser $parser = null)
+    {
+        if (
+            extension_loaded('Zend Optimizer+') && (ini_get('zend_optimizerplus.save_comments') === '0' ||
+            ini_get('opcache.save_comments') === '0')
+        ) {
+            throw AnnotationException::optimizerPlusSaveComments();
+        }
+
+        if (extension_loaded('Zend OPcache') && ini_get('opcache.save_comments') === 0) {
+            throw AnnotationException::optimizerPlusSaveComments();
+        }
+
+        // Make sure that the IgnoreAnnotation annotation is loaded
+        class_exists(IgnoreAnnotation::class);
+
+        $this->parser = $parser ?: new DocParser();
+
+        $this->preParser = new DocParser();
+
+        $this->preParser->setImports(self::$globalImports);
+        $this->preParser->setIgnoreNotImportedAnnotations(true);
+        $this->preParser->setIgnoredAnnotationNames(self::$globalIgnoredNames);
+
+        $this->phpParser = new PhpParser();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotations(ReflectionClass $class)
+    {
+        $this->parser->setTarget(Target::TARGET_CLASS);
+        $this->parser->setImports($this->getImports($class));
+        $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
+        $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
+
+        return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotation(ReflectionClass $class, $annotationName)
+    {
+        $annotations = $this->getClassAnnotations($class);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof $annotationName) {
+                return $annotation;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotations(ReflectionProperty $property)
+    {
+        $class   = $property->getDeclaringClass();
+        $context = 'property ' . $class->getName() . '::$' . $property->getName();
+
+        $this->parser->setTarget(Target::TARGET_PROPERTY);
+        $this->parser->setImports($this->getPropertyImports($property));
+        $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
+        $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
+
+        return $this->parser->parse($property->getDocComment(), $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
+    {
+        $annotations = $this->getPropertyAnnotations($property);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof $annotationName) {
+                return $annotation;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotations(ReflectionMethod $method)
+    {
+        $class   = $method->getDeclaringClass();
+        $context = 'method ' . $class->getName() . '::' . $method->getName() . '()';
+
+        $this->parser->setTarget(Target::TARGET_METHOD);
+        $this->parser->setImports($this->getMethodImports($method));
+        $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
+        $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
+
+        return $this->parser->parse($method->getDocComment(), $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
+    {
+        $annotations = $this->getMethodAnnotations($method);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof $annotationName) {
+                return $annotation;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Gets the annotations applied to a function.
+     *
+     * @phpstan-return list<object> An array of Annotations.
+     */
+    public function getFunctionAnnotations(ReflectionFunction $function): array
+    {
+        $context = 'function ' . $function->getName();
+
+        $this->parser->setTarget(Target::TARGET_FUNCTION);
+        $this->parser->setImports($this->getImports($function));
+        $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($function));
+        $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);
+
+        return $this->parser->parse($function->getDocComment(), $context);
+    }
+
+    /**
+     * Gets a function annotation.
+     *
+     * @return object|null The Annotation or NULL, if the requested annotation does not exist.
+     */
+    public function getFunctionAnnotation(ReflectionFunction $function, string $annotationName)
+    {
+        $annotations = $this->getFunctionAnnotations($function);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof $annotationName) {
+                return $annotation;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the ignored annotations for the given class or function.
+     *
+     * @param ReflectionClass|ReflectionFunction $reflection
+     *
+     * @return array<string, true>
+     */
+    private function getIgnoredAnnotationNames($reflection): array
+    {
+        $type = $reflection instanceof ReflectionClass ? 'class' : 'function';
+        $name = $reflection->getName();
+
+        if (isset($this->ignoredAnnotationNames[$type][$name])) {
+            return $this->ignoredAnnotationNames[$type][$name];
+        }
+
+        $this->collectParsingMetadata($reflection);
+
+        return $this->ignoredAnnotationNames[$type][$name];
+    }
+
+    /**
+     * Retrieves imports for a class or a function.
+     *
+     * @param ReflectionClass|ReflectionFunction $reflection
+     *
+     * @return array<string, class-string>
+     */
+    private function getImports($reflection): array
+    {
+        $type = $reflection instanceof ReflectionClass ? 'class' : 'function';
+        $name = $reflection->getName();
+
+        if (isset($this->imports[$type][$name])) {
+            return $this->imports[$type][$name];
+        }
+
+        $this->collectParsingMetadata($reflection);
+
+        return $this->imports[$type][$name];
+    }
+
+    /**
+     * Retrieves imports for methods.
+     *
+     * @return array<string, class-string>
+     */
+    private function getMethodImports(ReflectionMethod $method)
+    {
+        $class        = $method->getDeclaringClass();
+        $classImports = $this->getImports($class);
+
+        $traitImports = [];
+
+        foreach ($class->getTraits() as $trait) {
+            if (
+                ! $trait->hasMethod($method->getName())
+                || $trait->getFileName() !== $method->getFileName()
+            ) {
+                continue;
+            }
+
+            $traitImports = array_merge($traitImports, $this->phpParser->parseUseStatements($trait));
+        }
+
+        return array_merge($classImports, $traitImports);
+    }
+
+    /**
+     * Retrieves imports for properties.
+     *
+     * @return array<string, class-string>
+     */
+    private function getPropertyImports(ReflectionProperty $property)
+    {
+        $class        = $property->getDeclaringClass();
+        $classImports = $this->getImports($class);
+
+        $traitImports = [];
+
+        foreach ($class->getTraits() as $trait) {
+            if (! $trait->hasProperty($property->getName())) {
+                continue;
+            }
+
+            $traitImports = array_merge($traitImports, $this->phpParser->parseUseStatements($trait));
+        }
+
+        return array_merge($classImports, $traitImports);
+    }
+
+    /**
+     * Collects parsing metadata for a given class or function.
+     *
+     * @param ReflectionClass|ReflectionFunction $reflection
+     */
+    private function collectParsingMetadata($reflection): void
+    {
+        $type = $reflection instanceof ReflectionClass ? 'class' : 'function';
+        $name = $reflection->getName();
+
+        $ignoredAnnotationNames = self::$globalIgnoredNames;
+        $annotations            = $this->preParser->parse($reflection->getDocComment(), $type . ' ' . $name);
+
+        foreach ($annotations as $annotation) {
+            if (! ($annotation instanceof IgnoreAnnotation)) {
+                continue;
+            }
+
+            foreach ($annotation->names as $annot) {
+                $ignoredAnnotationNames[$annot] = true;
+            }
+        }
+
+        $this->imports[$type][$name] = array_merge(
+            self::$globalImports,
+            $this->phpParser->parseUseStatements($reflection),
+            [
+                '__NAMESPACE__' => $reflection->getNamespaceName(),
+                'self' => $name,
+            ]
+        );
+
+        $this->ignoredAnnotationNames[$type][$name] = $ignoredAnnotationNames;
+    }
+}

+ 190 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php

@@ -0,0 +1,190 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use function array_key_exists;
+use function array_merge;
+use function class_exists;
+use function in_array;
+use function is_file;
+use function str_replace;
+use function stream_resolve_include_path;
+use function strpos;
+
+use const DIRECTORY_SEPARATOR;
+
+final class AnnotationRegistry
+{
+    /**
+     * A map of namespaces to use for autoloading purposes based on a PSR-0 convention.
+     *
+     * Contains the namespace as key and an array of directories as value. If the value is NULL
+     * the include path is used for checking for the corresponding file.
+     *
+     * This autoloading mechanism does not utilize the PHP autoloading but implements autoloading on its own.
+     *
+     * @var string[][]|string[]|null[]
+     */
+    private static $autoloadNamespaces = [];
+
+    /**
+     * A map of autoloader callables.
+     *
+     * @var callable[]
+     */
+    private static $loaders = [];
+
+    /**
+     * An array of classes which cannot be found
+     *
+     * @var null[] indexed by class name
+     */
+    private static $failedToAutoload = [];
+
+    /**
+     * Whenever registerFile() was used. Disables use of standard autoloader.
+     *
+     * @var bool
+     */
+    private static $registerFileUsed = false;
+
+    public static function reset(): void
+    {
+        self::$autoloadNamespaces = [];
+        self::$loaders            = [];
+        self::$failedToAutoload   = [];
+        self::$registerFileUsed   = false;
+    }
+
+    /**
+     * Registers file.
+     *
+     * @deprecated This method is deprecated and will be removed in
+     *             doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
+     */
+    public static function registerFile(string $file): void
+    {
+        self::$registerFileUsed = true;
+
+        require_once $file;
+    }
+
+    /**
+     * Adds a namespace with one or many directories to look for files or null for the include path.
+     *
+     * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
+     *
+     * @deprecated This method is deprecated and will be removed in
+     *             doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
+     *
+     * @phpstan-param string|list<string>|null $dirs
+     */
+    public static function registerAutoloadNamespace(string $namespace, $dirs = null): void
+    {
+        self::$autoloadNamespaces[$namespace] = $dirs;
+    }
+
+    /**
+     * Registers multiple namespaces.
+     *
+     * Loading of this namespaces will be done with a PSR-0 namespace loading algorithm.
+     *
+     * @deprecated This method is deprecated and will be removed in
+     *             doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
+     *
+     * @param string[][]|string[]|null[] $namespaces indexed by namespace name
+     */
+    public static function registerAutoloadNamespaces(array $namespaces): void
+    {
+        self::$autoloadNamespaces = array_merge(self::$autoloadNamespaces, $namespaces);
+    }
+
+    /**
+     * Registers an autoloading callable for annotations, much like spl_autoload_register().
+     *
+     * NOTE: These class loaders HAVE to be silent when a class was not found!
+     * IMPORTANT: Loaders have to return true if they loaded a class that could contain the searched annotation class.
+     *
+     * @deprecated This method is deprecated and will be removed in
+     *             doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
+     */
+    public static function registerLoader(callable $callable): void
+    {
+        // Reset our static cache now that we have a new loader to work with
+        self::$failedToAutoload = [];
+        self::$loaders[]        = $callable;
+    }
+
+    /**
+     * Registers an autoloading callable for annotations, if it is not already registered
+     *
+     * @deprecated This method is deprecated and will be removed in
+     *             doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
+     */
+    public static function registerUniqueLoader(callable $callable): void
+    {
+        if (in_array($callable, self::$loaders, true)) {
+            return;
+        }
+
+        self::registerLoader($callable);
+    }
+
+    /**
+     * Autoloads an annotation class silently.
+     */
+    public static function loadAnnotationClass(string $class): bool
+    {
+        if (class_exists($class, false)) {
+            return true;
+        }
+
+        if (array_key_exists($class, self::$failedToAutoload)) {
+            return false;
+        }
+
+        foreach (self::$autoloadNamespaces as $namespace => $dirs) {
+            if (strpos($class, $namespace) !== 0) {
+                continue;
+            }
+
+            $file = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
+
+            if ($dirs === null) {
+                $path = stream_resolve_include_path($file);
+                if ($path) {
+                    require $path;
+
+                    return true;
+                }
+            } else {
+                foreach ((array) $dirs as $dir) {
+                    if (is_file($dir . DIRECTORY_SEPARATOR . $file)) {
+                        require $dir . DIRECTORY_SEPARATOR . $file;
+
+                        return true;
+                    }
+                }
+            }
+        }
+
+        foreach (self::$loaders as $loader) {
+            if ($loader($class) === true) {
+                return true;
+            }
+        }
+
+        if (
+            self::$loaders === [] &&
+            self::$autoloadNamespaces === [] &&
+            self::$registerFileUsed === false &&
+            class_exists($class)
+        ) {
+            return true;
+        }
+
+        self::$failedToAutoload[$class] = null;
+
+        return false;
+    }
+}

+ 266 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php

@@ -0,0 +1,266 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Cache\Cache;
+use ReflectionClass;
+use ReflectionMethod;
+use ReflectionProperty;
+
+use function array_map;
+use function array_merge;
+use function assert;
+use function filemtime;
+use function max;
+use function time;
+
+/**
+ * A cache aware annotation reader.
+ *
+ * @deprecated the CachedReader is deprecated and will be removed
+ *             in version 2.0.0 of doctrine/annotations. Please use the
+ *             {@see \Doctrine\Common\Annotations\PsrCachedReader} instead.
+ */
+final class CachedReader implements Reader
+{
+    /** @var Reader */
+    private $delegate;
+
+    /** @var Cache */
+    private $cache;
+
+    /** @var bool */
+    private $debug;
+
+    /** @var array<string, array<object>> */
+    private $loadedAnnotations = [];
+
+    /** @var int[] */
+    private $loadedFilemtimes = [];
+
+    /** @param bool $debug */
+    public function __construct(Reader $reader, Cache $cache, $debug = false)
+    {
+        $this->delegate = $reader;
+        $this->cache    = $cache;
+        $this->debug    = (bool) $debug;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotations(ReflectionClass $class)
+    {
+        $cacheKey = $class->getName();
+
+        if (isset($this->loadedAnnotations[$cacheKey])) {
+            return $this->loadedAnnotations[$cacheKey];
+        }
+
+        $annots = $this->fetchFromCache($cacheKey, $class);
+        if ($annots === false) {
+            $annots = $this->delegate->getClassAnnotations($class);
+            $this->saveToCache($cacheKey, $annots);
+        }
+
+        return $this->loadedAnnotations[$cacheKey] = $annots;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotation(ReflectionClass $class, $annotationName)
+    {
+        foreach ($this->getClassAnnotations($class) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotations(ReflectionProperty $property)
+    {
+        $class    = $property->getDeclaringClass();
+        $cacheKey = $class->getName() . '$' . $property->getName();
+
+        if (isset($this->loadedAnnotations[$cacheKey])) {
+            return $this->loadedAnnotations[$cacheKey];
+        }
+
+        $annots = $this->fetchFromCache($cacheKey, $class);
+        if ($annots === false) {
+            $annots = $this->delegate->getPropertyAnnotations($property);
+            $this->saveToCache($cacheKey, $annots);
+        }
+
+        return $this->loadedAnnotations[$cacheKey] = $annots;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
+    {
+        foreach ($this->getPropertyAnnotations($property) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotations(ReflectionMethod $method)
+    {
+        $class    = $method->getDeclaringClass();
+        $cacheKey = $class->getName() . '#' . $method->getName();
+
+        if (isset($this->loadedAnnotations[$cacheKey])) {
+            return $this->loadedAnnotations[$cacheKey];
+        }
+
+        $annots = $this->fetchFromCache($cacheKey, $class);
+        if ($annots === false) {
+            $annots = $this->delegate->getMethodAnnotations($method);
+            $this->saveToCache($cacheKey, $annots);
+        }
+
+        return $this->loadedAnnotations[$cacheKey] = $annots;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
+    {
+        foreach ($this->getMethodAnnotations($method) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Clears loaded annotations.
+     *
+     * @return void
+     */
+    public function clearLoadedAnnotations()
+    {
+        $this->loadedAnnotations = [];
+        $this->loadedFilemtimes  = [];
+    }
+
+    /**
+     * Fetches a value from the cache.
+     *
+     * @param string $cacheKey The cache key.
+     *
+     * @return mixed The cached value or false when the value is not in cache.
+     */
+    private function fetchFromCache($cacheKey, ReflectionClass $class)
+    {
+        $data = $this->cache->fetch($cacheKey);
+        if ($data !== false) {
+            if (! $this->debug || $this->isCacheFresh($cacheKey, $class)) {
+                return $data;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Saves a value to the cache.
+     *
+     * @param string $cacheKey The cache key.
+     * @param mixed  $value    The value.
+     *
+     * @return void
+     */
+    private function saveToCache($cacheKey, $value)
+    {
+        $this->cache->save($cacheKey, $value);
+        if (! $this->debug) {
+            return;
+        }
+
+        $this->cache->save('[C]' . $cacheKey, time());
+    }
+
+    /**
+     * Checks if the cache is fresh.
+     *
+     * @param string $cacheKey
+     *
+     * @return bool
+     */
+    private function isCacheFresh($cacheKey, ReflectionClass $class)
+    {
+        $lastModification = $this->getLastModification($class);
+        if ($lastModification === 0) {
+            return true;
+        }
+
+        return $this->cache->fetch('[C]' . $cacheKey) >= $lastModification;
+    }
+
+    /**
+     * Returns the time the class was last modified, testing traits and parents
+     */
+    private function getLastModification(ReflectionClass $class): int
+    {
+        $filename = $class->getFileName();
+
+        if (isset($this->loadedFilemtimes[$filename])) {
+            return $this->loadedFilemtimes[$filename];
+        }
+
+        $parent = $class->getParentClass();
+
+        $lastModification =  max(array_merge(
+            [$filename ? filemtime($filename) : 0],
+            array_map(function (ReflectionClass $reflectionTrait): int {
+                return $this->getTraitLastModificationTime($reflectionTrait);
+            }, $class->getTraits()),
+            array_map(function (ReflectionClass $class): int {
+                return $this->getLastModification($class);
+            }, $class->getInterfaces()),
+            $parent ? [$this->getLastModification($parent)] : []
+        ));
+
+        assert($lastModification !== false);
+
+        return $this->loadedFilemtimes[$filename] = $lastModification;
+    }
+
+    private function getTraitLastModificationTime(ReflectionClass $reflectionTrait): int
+    {
+        $fileName = $reflectionTrait->getFileName();
+
+        if (isset($this->loadedFilemtimes[$fileName])) {
+            return $this->loadedFilemtimes[$fileName];
+        }
+
+        $lastModificationTime = max(array_merge(
+            [$fileName ? filemtime($fileName) : 0],
+            array_map(function (ReflectionClass $reflectionTrait): int {
+                return $this->getTraitLastModificationTime($reflectionTrait);
+            }, $reflectionTrait->getTraits())
+        ));
+
+        assert($lastModificationTime !== false);
+
+        return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
+    }
+}

+ 143 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php

@@ -0,0 +1,143 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Lexer\AbstractLexer;
+
+use function ctype_alpha;
+use function is_numeric;
+use function str_replace;
+use function stripos;
+use function strlen;
+use function strpos;
+use function strtolower;
+use function substr;
+
+/**
+ * Simple lexer for docblock annotations.
+ *
+ * @template-extends AbstractLexer<DocLexer::T_*, string>
+ */
+final class DocLexer extends AbstractLexer
+{
+    public const T_NONE    = 1;
+    public const T_INTEGER = 2;
+    public const T_STRING  = 3;
+    public const T_FLOAT   = 4;
+
+    // All tokens that are also identifiers should be >= 100
+    public const T_IDENTIFIER          = 100;
+    public const T_AT                  = 101;
+    public const T_CLOSE_CURLY_BRACES  = 102;
+    public const T_CLOSE_PARENTHESIS   = 103;
+    public const T_COMMA               = 104;
+    public const T_EQUALS              = 105;
+    public const T_FALSE               = 106;
+    public const T_NAMESPACE_SEPARATOR = 107;
+    public const T_OPEN_CURLY_BRACES   = 108;
+    public const T_OPEN_PARENTHESIS    = 109;
+    public const T_TRUE                = 110;
+    public const T_NULL                = 111;
+    public const T_COLON               = 112;
+    public const T_MINUS               = 113;
+
+    /** @var array<string, self::T*> */
+    protected $noCase = [
+        '@'  => self::T_AT,
+        ','  => self::T_COMMA,
+        '('  => self::T_OPEN_PARENTHESIS,
+        ')'  => self::T_CLOSE_PARENTHESIS,
+        '{'  => self::T_OPEN_CURLY_BRACES,
+        '}'  => self::T_CLOSE_CURLY_BRACES,
+        '='  => self::T_EQUALS,
+        ':'  => self::T_COLON,
+        '-'  => self::T_MINUS,
+        '\\' => self::T_NAMESPACE_SEPARATOR,
+    ];
+
+    /** @var array<string, self::T*> */
+    protected $withCase = [
+        'true'  => self::T_TRUE,
+        'false' => self::T_FALSE,
+        'null'  => self::T_NULL,
+    ];
+
+    /**
+     * Whether the next token starts immediately, or if there were
+     * non-captured symbols before that
+     */
+    public function nextTokenIsAdjacent(): bool
+    {
+        return $this->token === null
+            || ($this->lookahead !== null
+                && ($this->lookahead['position'] - $this->token['position']) === strlen($this->token['value']));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getCatchablePatterns()
+    {
+        return [
+            '[a-z_\\\][a-z0-9_\:\\\]*[a-z_][a-z0-9_]*',
+            '(?:[+-]?[0-9]+(?:[\.][0-9]+)*)(?:[eE][+-]?[0-9]+)?',
+            '"(?:""|[^"])*+"',
+        ];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getNonCatchablePatterns()
+    {
+        return ['\s+', '\*+', '(.)'];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getType(&$value)
+    {
+        $type = self::T_NONE;
+
+        if ($value[0] === '"') {
+            $value = str_replace('""', '"', substr($value, 1, strlen($value) - 2));
+
+            return self::T_STRING;
+        }
+
+        if (isset($this->noCase[$value])) {
+            return $this->noCase[$value];
+        }
+
+        if ($value[0] === '_' || $value[0] === '\\' || ctype_alpha($value[0])) {
+            return self::T_IDENTIFIER;
+        }
+
+        $lowerValue = strtolower($value);
+
+        if (isset($this->withCase[$lowerValue])) {
+            return $this->withCase[$lowerValue];
+        }
+
+        // Checking numeric value
+        if (is_numeric($value)) {
+            return strpos($value, '.') !== false || stripos($value, 'e') !== false
+                ? self::T_FLOAT : self::T_INTEGER;
+        }
+
+        return $type;
+    }
+
+    /** @return array{value: int|string, type:self::T_*|null, position:int} */
+    public function peek(): ?array
+    {
+        $token = parent::peek();
+
+        if ($token === null) {
+            return null;
+        }
+
+        return (array) $token;
+    }
+}

+ 1506 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php

@@ -0,0 +1,1506 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Annotations\Annotation\Attribute;
+use Doctrine\Common\Annotations\Annotation\Attributes;
+use Doctrine\Common\Annotations\Annotation\Enum;
+use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
+use Doctrine\Common\Annotations\Annotation\Target;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionProperty;
+use RuntimeException;
+use stdClass;
+use Throwable;
+
+use function array_keys;
+use function array_map;
+use function array_pop;
+use function array_values;
+use function class_exists;
+use function constant;
+use function count;
+use function defined;
+use function explode;
+use function gettype;
+use function implode;
+use function in_array;
+use function interface_exists;
+use function is_array;
+use function is_object;
+use function json_encode;
+use function ltrim;
+use function preg_match;
+use function reset;
+use function rtrim;
+use function sprintf;
+use function stripos;
+use function strlen;
+use function strpos;
+use function strrpos;
+use function strtolower;
+use function substr;
+use function trim;
+
+use const PHP_VERSION_ID;
+
+/**
+ * A parser for docblock annotations.
+ *
+ * It is strongly discouraged to change the default annotation parsing process.
+ */
+final class DocParser
+{
+    /**
+     * An array of all valid tokens for a class name.
+     *
+     * @phpstan-var list<int>
+     */
+    private static $classIdentifiers = [
+        DocLexer::T_IDENTIFIER,
+        DocLexer::T_TRUE,
+        DocLexer::T_FALSE,
+        DocLexer::T_NULL,
+    ];
+
+    /**
+     * The lexer.
+     *
+     * @var DocLexer
+     */
+    private $lexer;
+
+    /**
+     * Current target context.
+     *
+     * @var int
+     */
+    private $target;
+
+    /**
+     * Doc parser used to collect annotation target.
+     *
+     * @var DocParser
+     */
+    private static $metadataParser;
+
+    /**
+     * Flag to control if the current annotation is nested or not.
+     *
+     * @var bool
+     */
+    private $isNestedAnnotation = false;
+
+    /**
+     * Hashmap containing all use-statements that are to be used when parsing
+     * the given doc block.
+     *
+     * @var array<string, class-string>
+     */
+    private $imports = [];
+
+    /**
+     * This hashmap is used internally to cache results of class_exists()
+     * look-ups.
+     *
+     * @var array<class-string, bool>
+     */
+    private $classExists = [];
+
+    /**
+     * Whether annotations that have not been imported should be ignored.
+     *
+     * @var bool
+     */
+    private $ignoreNotImportedAnnotations = false;
+
+    /**
+     * An array of default namespaces if operating in simple mode.
+     *
+     * @var string[]
+     */
+    private $namespaces = [];
+
+    /**
+     * A list with annotations that are not causing exceptions when not resolved to an annotation class.
+     *
+     * The names must be the raw names as used in the class, not the fully qualified
+     *
+     * @var bool[] indexed by annotation name
+     */
+    private $ignoredAnnotationNames = [];
+
+    /**
+     * A list with annotations in namespaced format
+     * that are not causing exceptions when not resolved to an annotation class.
+     *
+     * @var bool[] indexed by namespace name
+     */
+    private $ignoredAnnotationNamespaces = [];
+
+    /** @var string */
+    private $context = '';
+
+    /**
+     * Hash-map for caching annotation metadata.
+     *
+     * @var array<class-string, mixed[]>
+     */
+    private static $annotationMetadata = [
+        Annotation\Target::class => [
+            'is_annotation'                  => true,
+            'has_constructor'                => true,
+            'has_named_argument_constructor' => false,
+            'properties'                     => [],
+            'targets_literal'                => 'ANNOTATION_CLASS',
+            'targets'                        => Target::TARGET_CLASS,
+            'default_property'               => 'value',
+            'attribute_types'                => [
+                'value'  => [
+                    'required'   => false,
+                    'type'       => 'array',
+                    'array_type' => 'string',
+                    'value'      => 'array<string>',
+                ],
+            ],
+        ],
+        Annotation\Attribute::class => [
+            'is_annotation'                  => true,
+            'has_constructor'                => false,
+            'has_named_argument_constructor' => false,
+            'targets_literal'                => 'ANNOTATION_ANNOTATION',
+            'targets'                        => Target::TARGET_ANNOTATION,
+            'default_property'               => 'name',
+            'properties'                     => [
+                'name'      => 'name',
+                'type'      => 'type',
+                'required'  => 'required',
+            ],
+            'attribute_types'                => [
+                'value'  => [
+                    'required'  => true,
+                    'type'      => 'string',
+                    'value'     => 'string',
+                ],
+                'type'  => [
+                    'required'  => true,
+                    'type'      => 'string',
+                    'value'     => 'string',
+                ],
+                'required'  => [
+                    'required'  => false,
+                    'type'      => 'boolean',
+                    'value'     => 'boolean',
+                ],
+            ],
+        ],
+        Annotation\Attributes::class => [
+            'is_annotation'                  => true,
+            'has_constructor'                => false,
+            'has_named_argument_constructor' => false,
+            'targets_literal'                => 'ANNOTATION_CLASS',
+            'targets'                        => Target::TARGET_CLASS,
+            'default_property'               => 'value',
+            'properties'                     => ['value' => 'value'],
+            'attribute_types'                => [
+                'value' => [
+                    'type'      => 'array',
+                    'required'  => true,
+                    'array_type' => Annotation\Attribute::class,
+                    'value'     => 'array<' . Annotation\Attribute::class . '>',
+                ],
+            ],
+        ],
+        Annotation\Enum::class => [
+            'is_annotation'                  => true,
+            'has_constructor'                => true,
+            'has_named_argument_constructor' => false,
+            'targets_literal'                => 'ANNOTATION_PROPERTY',
+            'targets'                        => Target::TARGET_PROPERTY,
+            'default_property'               => 'value',
+            'properties'                     => ['value' => 'value'],
+            'attribute_types'                => [
+                'value' => [
+                    'type'      => 'array',
+                    'required'  => true,
+                ],
+                'literal' => [
+                    'type'      => 'array',
+                    'required'  => false,
+                ],
+            ],
+        ],
+        Annotation\NamedArgumentConstructor::class => [
+            'is_annotation'                  => true,
+            'has_constructor'                => false,
+            'has_named_argument_constructor' => false,
+            'targets_literal'                => 'ANNOTATION_CLASS',
+            'targets'                        => Target::TARGET_CLASS,
+            'default_property'               => null,
+            'properties'                     => [],
+            'attribute_types'                => [],
+        ],
+    ];
+
+    /**
+     * Hash-map for handle types declaration.
+     *
+     * @var array<string, string>
+     */
+    private static $typeMap = [
+        'float'     => 'double',
+        'bool'      => 'boolean',
+        // allow uppercase Boolean in honor of George Boole
+        'Boolean'   => 'boolean',
+        'int'       => 'integer',
+    ];
+
+    /**
+     * Constructs a new DocParser.
+     */
+    public function __construct()
+    {
+        $this->lexer = new DocLexer();
+    }
+
+    /**
+     * Sets the annotation names that are ignored during the parsing process.
+     *
+     * The names are supposed to be the raw names as used in the class, not the
+     * fully qualified class names.
+     *
+     * @param bool[] $names indexed by annotation name
+     *
+     * @return void
+     */
+    public function setIgnoredAnnotationNames(array $names)
+    {
+        $this->ignoredAnnotationNames = $names;
+    }
+
+    /**
+     * Sets the annotation namespaces that are ignored during the parsing process.
+     *
+     * @param bool[] $ignoredAnnotationNamespaces indexed by annotation namespace name
+     *
+     * @return void
+     */
+    public function setIgnoredAnnotationNamespaces($ignoredAnnotationNamespaces)
+    {
+        $this->ignoredAnnotationNamespaces = $ignoredAnnotationNamespaces;
+    }
+
+    /**
+     * Sets ignore on not-imported annotations.
+     *
+     * @param bool $bool
+     *
+     * @return void
+     */
+    public function setIgnoreNotImportedAnnotations($bool)
+    {
+        $this->ignoreNotImportedAnnotations = (bool) $bool;
+    }
+
+    /**
+     * Sets the default namespaces.
+     *
+     * @param string $namespace
+     *
+     * @return void
+     *
+     * @throws RuntimeException
+     */
+    public function addNamespace($namespace)
+    {
+        if ($this->imports) {
+            throw new RuntimeException('You must either use addNamespace(), or setImports(), but not both.');
+        }
+
+        $this->namespaces[] = $namespace;
+    }
+
+    /**
+     * Sets the imports.
+     *
+     * @param array<string, class-string> $imports
+     *
+     * @return void
+     *
+     * @throws RuntimeException
+     */
+    public function setImports(array $imports)
+    {
+        if ($this->namespaces) {
+            throw new RuntimeException('You must either use addNamespace(), or setImports(), but not both.');
+        }
+
+        $this->imports = $imports;
+    }
+
+    /**
+     * Sets current target context as bitmask.
+     *
+     * @param int $target
+     *
+     * @return void
+     */
+    public function setTarget($target)
+    {
+        $this->target = $target;
+    }
+
+    /**
+     * Parses the given docblock string for annotations.
+     *
+     * @param string $input   The docblock string to parse.
+     * @param string $context The parsing context.
+     *
+     * @phpstan-return list<object> Array of annotations. If no annotations are found, an empty array is returned.
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    public function parse($input, $context = '')
+    {
+        $pos = $this->findInitialTokenPosition($input);
+        if ($pos === null) {
+            return [];
+        }
+
+        $this->context = $context;
+
+        $this->lexer->setInput(trim(substr($input, $pos), '* /'));
+        $this->lexer->moveNext();
+
+        return $this->Annotations();
+    }
+
+    /**
+     * Finds the first valid annotation
+     *
+     * @param string $input The docblock string to parse
+     */
+    private function findInitialTokenPosition($input): ?int
+    {
+        $pos = 0;
+
+        // search for first valid annotation
+        while (($pos = strpos($input, '@', $pos)) !== false) {
+            $preceding = substr($input, $pos - 1, 1);
+
+            // if the @ is preceded by a space, a tab or * it is valid
+            if ($pos === 0 || $preceding === ' ' || $preceding === '*' || $preceding === "\t") {
+                return $pos;
+            }
+
+            $pos++;
+        }
+
+        return null;
+    }
+
+    /**
+     * Attempts to match the given token with the current lookahead token.
+     * If they match, updates the lookahead token; otherwise raises a syntax error.
+     *
+     * @param int $token Type of token.
+     *
+     * @return bool True if tokens match; false otherwise.
+     *
+     * @throws AnnotationException
+     */
+    private function match(int $token): bool
+    {
+        if (! $this->lexer->isNextToken($token)) {
+            throw $this->syntaxError($this->lexer->getLiteral($token));
+        }
+
+        return $this->lexer->moveNext();
+    }
+
+    /**
+     * Attempts to match the current lookahead token with any of the given tokens.
+     *
+     * If any of them matches, this method updates the lookahead token; otherwise
+     * a syntax error is raised.
+     *
+     * @phpstan-param list<mixed[]> $tokens
+     *
+     * @throws AnnotationException
+     */
+    private function matchAny(array $tokens): bool
+    {
+        if (! $this->lexer->isNextTokenAny($tokens)) {
+            throw $this->syntaxError(implode(' or ', array_map([$this->lexer, 'getLiteral'], $tokens)));
+        }
+
+        return $this->lexer->moveNext();
+    }
+
+    /**
+     * Generates a new syntax error.
+     *
+     * @param string       $expected Expected string.
+     * @param mixed[]|null $token    Optional token.
+     */
+    private function syntaxError(string $expected, ?array $token = null): AnnotationException
+    {
+        if ($token === null) {
+            $token = $this->lexer->lookahead;
+        }
+
+        $message  = sprintf('Expected %s, got ', $expected);
+        $message .= $this->lexer->lookahead === null
+            ? 'end of string'
+            : sprintf("'%s' at position %s", $token['value'], $token['position']);
+
+        if (strlen($this->context)) {
+            $message .= ' in ' . $this->context;
+        }
+
+        $message .= '.';
+
+        return AnnotationException::syntaxError($message);
+    }
+
+    /**
+     * Attempts to check if a class exists or not. This never goes through the PHP autoloading mechanism
+     * but uses the {@link AnnotationRegistry} to load classes.
+     *
+     * @param class-string $fqcn
+     */
+    private function classExists(string $fqcn): bool
+    {
+        if (isset($this->classExists[$fqcn])) {
+            return $this->classExists[$fqcn];
+        }
+
+        // first check if the class already exists, maybe loaded through another AnnotationReader
+        if (class_exists($fqcn, false)) {
+            return $this->classExists[$fqcn] = true;
+        }
+
+        // final check, does this class exist?
+        return $this->classExists[$fqcn] = AnnotationRegistry::loadAnnotationClass($fqcn);
+    }
+
+    /**
+     * Collects parsing metadata for a given annotation class
+     *
+     * @param class-string $name The annotation name
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function collectAnnotationMetadata(string $name): void
+    {
+        if (self::$metadataParser === null) {
+            self::$metadataParser = new self();
+
+            self::$metadataParser->setIgnoreNotImportedAnnotations(true);
+            self::$metadataParser->setIgnoredAnnotationNames($this->ignoredAnnotationNames);
+            self::$metadataParser->setImports([
+                'enum'                     => Enum::class,
+                'target'                   => Target::class,
+                'attribute'                => Attribute::class,
+                'attributes'               => Attributes::class,
+                'namedargumentconstructor' => NamedArgumentConstructor::class,
+            ]);
+
+            // Make sure that annotations from metadata are loaded
+            class_exists(Enum::class);
+            class_exists(Target::class);
+            class_exists(Attribute::class);
+            class_exists(Attributes::class);
+            class_exists(NamedArgumentConstructor::class);
+        }
+
+        $class      = new ReflectionClass($name);
+        $docComment = $class->getDocComment();
+
+        // Sets default values for annotation metadata
+        $constructor = $class->getConstructor();
+        $metadata    = [
+            'default_property' => null,
+            'has_constructor'  => $constructor !== null && $constructor->getNumberOfParameters() > 0,
+            'constructor_args' => [],
+            'properties'       => [],
+            'property_types'   => [],
+            'attribute_types'  => [],
+            'targets_literal'  => null,
+            'targets'          => Target::TARGET_ALL,
+            'is_annotation'    => strpos($docComment, '@Annotation') !== false,
+        ];
+
+        $metadata['has_named_argument_constructor'] = $metadata['has_constructor']
+            && $class->implementsInterface(NamedArgumentConstructorAnnotation::class);
+
+        // verify that the class is really meant to be an annotation
+        if ($metadata['is_annotation']) {
+            self::$metadataParser->setTarget(Target::TARGET_CLASS);
+
+            foreach (self::$metadataParser->parse($docComment, 'class @' . $name) as $annotation) {
+                if ($annotation instanceof Target) {
+                    $metadata['targets']         = $annotation->targets;
+                    $metadata['targets_literal'] = $annotation->literal;
+
+                    continue;
+                }
+
+                if ($annotation instanceof NamedArgumentConstructor) {
+                    $metadata['has_named_argument_constructor'] = $metadata['has_constructor'];
+                    if ($metadata['has_named_argument_constructor']) {
+                        // choose the first argument as the default property
+                        $metadata['default_property'] = $constructor->getParameters()[0]->getName();
+                    }
+                }
+
+                if (! ($annotation instanceof Attributes)) {
+                    continue;
+                }
+
+                foreach ($annotation->value as $attribute) {
+                    $this->collectAttributeTypeMetadata($metadata, $attribute);
+                }
+            }
+
+            // if not has a constructor will inject values into public properties
+            if ($metadata['has_constructor'] === false) {
+                // collect all public properties
+                foreach ($class->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
+                    $metadata['properties'][$property->name] = $property->name;
+
+                    $propertyComment = $property->getDocComment();
+                    if ($propertyComment === false) {
+                        continue;
+                    }
+
+                    $attribute = new Attribute();
+
+                    $attribute->required = (strpos($propertyComment, '@Required') !== false);
+                    $attribute->name     = $property->name;
+                    $attribute->type     = (strpos($propertyComment, '@var') !== false &&
+                        preg_match('/@var\s+([^\s]+)/', $propertyComment, $matches))
+                        ? $matches[1]
+                        : 'mixed';
+
+                    $this->collectAttributeTypeMetadata($metadata, $attribute);
+
+                    // checks if the property has @Enum
+                    if (strpos($propertyComment, '@Enum') === false) {
+                        continue;
+                    }
+
+                    $context = 'property ' . $class->name . '::$' . $property->name;
+
+                    self::$metadataParser->setTarget(Target::TARGET_PROPERTY);
+
+                    foreach (self::$metadataParser->parse($propertyComment, $context) as $annotation) {
+                        if (! $annotation instanceof Enum) {
+                            continue;
+                        }
+
+                        $metadata['enum'][$property->name]['value']   = $annotation->value;
+                        $metadata['enum'][$property->name]['literal'] = (! empty($annotation->literal))
+                            ? $annotation->literal
+                            : $annotation->value;
+                    }
+                }
+
+                // choose the first property as default property
+                $metadata['default_property'] = reset($metadata['properties']);
+            } elseif ($metadata['has_named_argument_constructor']) {
+                foreach ($constructor->getParameters() as $parameter) {
+                    if ($parameter->isVariadic()) {
+                        break;
+                    }
+
+                    $metadata['constructor_args'][$parameter->getName()] = [
+                        'position' => $parameter->getPosition(),
+                        'default' => $parameter->isOptional() ? $parameter->getDefaultValue() : null,
+                    ];
+                }
+            }
+        }
+
+        self::$annotationMetadata[$name] = $metadata;
+    }
+
+    /**
+     * Collects parsing metadata for a given attribute.
+     *
+     * @param mixed[] $metadata
+     */
+    private function collectAttributeTypeMetadata(array &$metadata, Attribute $attribute): void
+    {
+        // handle internal type declaration
+        $type = self::$typeMap[$attribute->type] ?? $attribute->type;
+
+        // handle the case if the property type is mixed
+        if ($type === 'mixed') {
+            return;
+        }
+
+        // Evaluate type
+        $pos = strpos($type, '<');
+        if ($pos !== false) {
+            // Checks if the property has array<type>
+            $arrayType = substr($type, $pos + 1, -1);
+            $type      = 'array';
+
+            if (isset(self::$typeMap[$arrayType])) {
+                $arrayType = self::$typeMap[$arrayType];
+            }
+
+            $metadata['attribute_types'][$attribute->name]['array_type'] = $arrayType;
+        } else {
+            // Checks if the property has type[]
+            $pos = strrpos($type, '[');
+            if ($pos !== false) {
+                $arrayType = substr($type, 0, $pos);
+                $type      = 'array';
+
+                if (isset(self::$typeMap[$arrayType])) {
+                    $arrayType = self::$typeMap[$arrayType];
+                }
+
+                $metadata['attribute_types'][$attribute->name]['array_type'] = $arrayType;
+            }
+        }
+
+        $metadata['attribute_types'][$attribute->name]['type']     = $type;
+        $metadata['attribute_types'][$attribute->name]['value']    = $attribute->type;
+        $metadata['attribute_types'][$attribute->name]['required'] = $attribute->required;
+    }
+
+    /**
+     * Annotations ::= Annotation {[ "*" ]* [Annotation]}*
+     *
+     * @phpstan-return list<object>
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function Annotations(): array
+    {
+        $annotations = [];
+
+        while ($this->lexer->lookahead !== null) {
+            if ($this->lexer->lookahead['type'] !== DocLexer::T_AT) {
+                $this->lexer->moveNext();
+                continue;
+            }
+
+            // make sure the @ is preceded by non-catchable pattern
+            if (
+                $this->lexer->token !== null &&
+                $this->lexer->lookahead['position'] === $this->lexer->token['position'] + strlen(
+                    $this->lexer->token['value']
+                )
+            ) {
+                $this->lexer->moveNext();
+                continue;
+            }
+
+            // make sure the @ is followed by either a namespace separator, or
+            // an identifier token
+            $peek = $this->lexer->glimpse();
+            if (
+                ($peek === null)
+                || ($peek['type'] !== DocLexer::T_NAMESPACE_SEPARATOR && ! in_array(
+                    $peek['type'],
+                    self::$classIdentifiers,
+                    true
+                ))
+                || $peek['position'] !== $this->lexer->lookahead['position'] + 1
+            ) {
+                $this->lexer->moveNext();
+                continue;
+            }
+
+            $this->isNestedAnnotation = false;
+            $annot                    = $this->Annotation();
+            if ($annot === false) {
+                continue;
+            }
+
+            $annotations[] = $annot;
+        }
+
+        return $annotations;
+    }
+
+    /**
+     * Annotation     ::= "@" AnnotationName MethodCall
+     * AnnotationName ::= QualifiedName | SimpleName
+     * QualifiedName  ::= NameSpacePart "\" {NameSpacePart "\"}* SimpleName
+     * NameSpacePart  ::= identifier | null | false | true
+     * SimpleName     ::= identifier | null | false | true
+     *
+     * @return object|false False if it is not a valid annotation.
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function Annotation()
+    {
+        $this->match(DocLexer::T_AT);
+
+        // check if we have an annotation
+        $name = $this->Identifier();
+
+        if (
+            $this->lexer->isNextToken(DocLexer::T_MINUS)
+            && $this->lexer->nextTokenIsAdjacent()
+        ) {
+            // Annotations with dashes, such as "@foo-" or "@foo-bar", are to be discarded
+            return false;
+        }
+
+        // only process names which are not fully qualified, yet
+        // fully qualified names must start with a \
+        $originalName = $name;
+
+        if ($name[0] !== '\\') {
+            $pos          = strpos($name, '\\');
+            $alias        = ($pos === false) ? $name : substr($name, 0, $pos);
+            $found        = false;
+            $loweredAlias = strtolower($alias);
+
+            if ($this->namespaces) {
+                foreach ($this->namespaces as $namespace) {
+                    if ($this->classExists($namespace . '\\' . $name)) {
+                        $name  = $namespace . '\\' . $name;
+                        $found = true;
+                        break;
+                    }
+                }
+            } elseif (isset($this->imports[$loweredAlias])) {
+                $namespace = ltrim($this->imports[$loweredAlias], '\\');
+                $name      = ($pos !== false)
+                    ? $namespace . substr($name, $pos)
+                    : $namespace;
+                $found     = $this->classExists($name);
+            } elseif (
+                ! isset($this->ignoredAnnotationNames[$name])
+                && isset($this->imports['__NAMESPACE__'])
+                && $this->classExists($this->imports['__NAMESPACE__'] . '\\' . $name)
+            ) {
+                $name  = $this->imports['__NAMESPACE__'] . '\\' . $name;
+                $found = true;
+            } elseif (! isset($this->ignoredAnnotationNames[$name]) && $this->classExists($name)) {
+                $found = true;
+            }
+
+            if (! $found) {
+                if ($this->isIgnoredAnnotation($name)) {
+                    return false;
+                }
+
+                throw AnnotationException::semanticalError(sprintf(
+                    <<<'EXCEPTION'
+The annotation "@%s" in %s was never imported. Did you maybe forget to add a "use" statement for this annotation?
+EXCEPTION
+                    ,
+                    $name,
+                    $this->context
+                ));
+            }
+        }
+
+        $name = ltrim($name, '\\');
+
+        if (! $this->classExists($name)) {
+            throw AnnotationException::semanticalError(sprintf(
+                'The annotation "@%s" in %s does not exist, or could not be auto-loaded.',
+                $name,
+                $this->context
+            ));
+        }
+
+        // at this point, $name contains the fully qualified class name of the
+        // annotation, and it is also guaranteed that this class exists, and
+        // that it is loaded
+
+        // collects the metadata annotation only if there is not yet
+        if (! isset(self::$annotationMetadata[$name])) {
+            $this->collectAnnotationMetadata($name);
+        }
+
+        // verify that the class is really meant to be an annotation and not just any ordinary class
+        if (self::$annotationMetadata[$name]['is_annotation'] === false) {
+            if ($this->isIgnoredAnnotation($originalName) || $this->isIgnoredAnnotation($name)) {
+                return false;
+            }
+
+            throw AnnotationException::semanticalError(sprintf(
+                <<<'EXCEPTION'
+The class "%s" is not annotated with @Annotation.
+Are you sure this class can be used as annotation?
+If so, then you need to add @Annotation to the _class_ doc comment of "%s".
+If it is indeed no annotation, then you need to add @IgnoreAnnotation("%s") to the _class_ doc comment of %s.
+EXCEPTION
+                ,
+                $name,
+                $name,
+                $originalName,
+                $this->context
+            ));
+        }
+
+        //if target is nested annotation
+        $target = $this->isNestedAnnotation ? Target::TARGET_ANNOTATION : $this->target;
+
+        // Next will be nested
+        $this->isNestedAnnotation = true;
+
+        //if annotation does not support current target
+        if ((self::$annotationMetadata[$name]['targets'] & $target) === 0 && $target) {
+            throw AnnotationException::semanticalError(
+                sprintf(
+                    <<<'EXCEPTION'
+Annotation @%s is not allowed to be declared on %s. You may only use this annotation on these code elements: %s.
+EXCEPTION
+                    ,
+                    $originalName,
+                    $this->context,
+                    self::$annotationMetadata[$name]['targets_literal']
+                )
+            );
+        }
+
+        $arguments = $this->MethodCall();
+        $values    = $this->resolvePositionalValues($arguments, $name);
+
+        if (isset(self::$annotationMetadata[$name]['enum'])) {
+            // checks all declared attributes
+            foreach (self::$annotationMetadata[$name]['enum'] as $property => $enum) {
+                // checks if the attribute is a valid enumerator
+                if (isset($values[$property]) && ! in_array($values[$property], $enum['value'])) {
+                    throw AnnotationException::enumeratorError(
+                        $property,
+                        $name,
+                        $this->context,
+                        $enum['literal'],
+                        $values[$property]
+                    );
+                }
+            }
+        }
+
+        // checks all declared attributes
+        foreach (self::$annotationMetadata[$name]['attribute_types'] as $property => $type) {
+            if (
+                $property === self::$annotationMetadata[$name]['default_property']
+                && ! isset($values[$property]) && isset($values['value'])
+            ) {
+                $property = 'value';
+            }
+
+            // handle a not given attribute or null value
+            if (! isset($values[$property])) {
+                if ($type['required']) {
+                    throw AnnotationException::requiredError(
+                        $property,
+                        $originalName,
+                        $this->context,
+                        'a(n) ' . $type['value']
+                    );
+                }
+
+                continue;
+            }
+
+            if ($type['type'] === 'array') {
+                // handle the case of a single value
+                if (! is_array($values[$property])) {
+                    $values[$property] = [$values[$property]];
+                }
+
+                // checks if the attribute has array type declaration, such as "array<string>"
+                if (isset($type['array_type'])) {
+                    foreach ($values[$property] as $item) {
+                        if (gettype($item) !== $type['array_type'] && ! $item instanceof $type['array_type']) {
+                            throw AnnotationException::attributeTypeError(
+                                $property,
+                                $originalName,
+                                $this->context,
+                                'either a(n) ' . $type['array_type'] . ', or an array of ' . $type['array_type'] . 's',
+                                $item
+                            );
+                        }
+                    }
+                }
+            } elseif (gettype($values[$property]) !== $type['type'] && ! $values[$property] instanceof $type['type']) {
+                throw AnnotationException::attributeTypeError(
+                    $property,
+                    $originalName,
+                    $this->context,
+                    'a(n) ' . $type['value'],
+                    $values[$property]
+                );
+            }
+        }
+
+        if (self::$annotationMetadata[$name]['has_named_argument_constructor']) {
+            if (PHP_VERSION_ID >= 80000) {
+                foreach ($values as $property => $value) {
+                    if (! isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {
+                        throw AnnotationException::creationError(sprintf(
+                            <<<'EXCEPTION'
+The annotation @%s declared on %s does not have a property named "%s"
+that can be set through its named arguments constructor.
+Available named arguments: %s
+EXCEPTION
+                            ,
+                            $originalName,
+                            $this->context,
+                            $property,
+                            implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))
+                        ));
+                    }
+                }
+
+                return $this->instantiateAnnotiation($originalName, $this->context, $name, $values);
+            }
+
+            $positionalValues = [];
+            foreach (self::$annotationMetadata[$name]['constructor_args'] as $property => $parameter) {
+                $positionalValues[$parameter['position']] = $parameter['default'];
+            }
+
+            foreach ($values as $property => $value) {
+                if (! isset(self::$annotationMetadata[$name]['constructor_args'][$property])) {
+                    throw AnnotationException::creationError(sprintf(
+                        <<<'EXCEPTION'
+The annotation @%s declared on %s does not have a property named "%s"
+that can be set through its named arguments constructor.
+Available named arguments: %s
+EXCEPTION
+                        ,
+                        $originalName,
+                        $this->context,
+                        $property,
+                        implode(', ', array_keys(self::$annotationMetadata[$name]['constructor_args']))
+                    ));
+                }
+
+                $positionalValues[self::$annotationMetadata[$name]['constructor_args'][$property]['position']] = $value;
+            }
+
+            return $this->instantiateAnnotiation($originalName, $this->context, $name, $positionalValues);
+        }
+
+        // check if the annotation expects values via the constructor,
+        // or directly injected into public properties
+        if (self::$annotationMetadata[$name]['has_constructor'] === true) {
+            return $this->instantiateAnnotiation($originalName, $this->context, $name, [$values]);
+        }
+
+        $instance = $this->instantiateAnnotiation($originalName, $this->context, $name, []);
+
+        foreach ($values as $property => $value) {
+            if (! isset(self::$annotationMetadata[$name]['properties'][$property])) {
+                if ($property !== 'value') {
+                    throw AnnotationException::creationError(sprintf(
+                        <<<'EXCEPTION'
+The annotation @%s declared on %s does not have a property named "%s".
+Available properties: %s
+EXCEPTION
+                        ,
+                        $originalName,
+                        $this->context,
+                        $property,
+                        implode(', ', self::$annotationMetadata[$name]['properties'])
+                    ));
+                }
+
+                // handle the case if the property has no annotations
+                $property = self::$annotationMetadata[$name]['default_property'];
+                if (! $property) {
+                    throw AnnotationException::creationError(sprintf(
+                        'The annotation @%s declared on %s does not accept any values, but got %s.',
+                        $originalName,
+                        $this->context,
+                        json_encode($values)
+                    ));
+                }
+            }
+
+            $instance->{$property} = $value;
+        }
+
+        return $instance;
+    }
+
+    /**
+     * MethodCall ::= ["(" [Values] ")"]
+     *
+     * @return mixed[]
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function MethodCall(): array
+    {
+        $values = [];
+
+        if (! $this->lexer->isNextToken(DocLexer::T_OPEN_PARENTHESIS)) {
+            return $values;
+        }
+
+        $this->match(DocLexer::T_OPEN_PARENTHESIS);
+
+        if (! $this->lexer->isNextToken(DocLexer::T_CLOSE_PARENTHESIS)) {
+            $values = $this->Values();
+        }
+
+        $this->match(DocLexer::T_CLOSE_PARENTHESIS);
+
+        return $values;
+    }
+
+    /**
+     * Values ::= Array | Value {"," Value}* [","]
+     *
+     * @return mixed[]
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function Values(): array
+    {
+        $values = [$this->Value()];
+
+        while ($this->lexer->isNextToken(DocLexer::T_COMMA)) {
+            $this->match(DocLexer::T_COMMA);
+
+            if ($this->lexer->isNextToken(DocLexer::T_CLOSE_PARENTHESIS)) {
+                break;
+            }
+
+            $token = $this->lexer->lookahead;
+            $value = $this->Value();
+
+            $values[] = $value;
+        }
+
+        $namedArguments      = [];
+        $positionalArguments = [];
+        foreach ($values as $k => $value) {
+            if (is_object($value) && $value instanceof stdClass) {
+                $namedArguments[$value->name] = $value->value;
+            } else {
+                $positionalArguments[$k] = $value;
+            }
+        }
+
+        return ['named_arguments' => $namedArguments, 'positional_arguments' => $positionalArguments];
+    }
+
+    /**
+     * Constant ::= integer | string | float | boolean
+     *
+     * @return mixed
+     *
+     * @throws AnnotationException
+     */
+    private function Constant()
+    {
+        $identifier = $this->Identifier();
+
+        if (! defined($identifier) && strpos($identifier, '::') !== false && $identifier[0] !== '\\') {
+            [$className, $const] = explode('::', $identifier);
+
+            $pos          = strpos($className, '\\');
+            $alias        = ($pos === false) ? $className : substr($className, 0, $pos);
+            $found        = false;
+            $loweredAlias = strtolower($alias);
+
+            switch (true) {
+                case ! empty($this->namespaces):
+                    foreach ($this->namespaces as $ns) {
+                        if (class_exists($ns . '\\' . $className) || interface_exists($ns . '\\' . $className)) {
+                            $className = $ns . '\\' . $className;
+                            $found     = true;
+                            break;
+                        }
+                    }
+
+                    break;
+
+                case isset($this->imports[$loweredAlias]):
+                    $found     = true;
+                    $className = ($pos !== false)
+                        ? $this->imports[$loweredAlias] . substr($className, $pos)
+                        : $this->imports[$loweredAlias];
+                    break;
+
+                default:
+                    if (isset($this->imports['__NAMESPACE__'])) {
+                        $ns = $this->imports['__NAMESPACE__'];
+
+                        if (class_exists($ns . '\\' . $className) || interface_exists($ns . '\\' . $className)) {
+                            $className = $ns . '\\' . $className;
+                            $found     = true;
+                        }
+                    }
+
+                    break;
+            }
+
+            if ($found) {
+                $identifier = $className . '::' . $const;
+            }
+        }
+
+        /**
+         * Checks if identifier ends with ::class and remove the leading backslash if it exists.
+         */
+        if (
+            $this->identifierEndsWithClassConstant($identifier) &&
+            ! $this->identifierStartsWithBackslash($identifier)
+        ) {
+            return substr($identifier, 0, $this->getClassConstantPositionInIdentifier($identifier));
+        }
+
+        if ($this->identifierEndsWithClassConstant($identifier) && $this->identifierStartsWithBackslash($identifier)) {
+            return substr($identifier, 1, $this->getClassConstantPositionInIdentifier($identifier) - 1);
+        }
+
+        if (! defined($identifier)) {
+            throw AnnotationException::semanticalErrorConstants($identifier, $this->context);
+        }
+
+        return constant($identifier);
+    }
+
+    private function identifierStartsWithBackslash(string $identifier): bool
+    {
+        return $identifier[0] === '\\';
+    }
+
+    private function identifierEndsWithClassConstant(string $identifier): bool
+    {
+        return $this->getClassConstantPositionInIdentifier($identifier) === strlen($identifier) - strlen('::class');
+    }
+
+    /** @return int|false */
+    private function getClassConstantPositionInIdentifier(string $identifier)
+    {
+        return stripos($identifier, '::class');
+    }
+
+    /**
+     * Identifier ::= string
+     *
+     * @throws AnnotationException
+     */
+    private function Identifier(): string
+    {
+        // check if we have an annotation
+        if (! $this->lexer->isNextTokenAny(self::$classIdentifiers)) {
+            throw $this->syntaxError('namespace separator or identifier');
+        }
+
+        $this->lexer->moveNext();
+
+        $className = $this->lexer->token['value'];
+
+        while (
+            $this->lexer->lookahead !== null &&
+            $this->lexer->lookahead['position'] === ($this->lexer->token['position'] +
+            strlen($this->lexer->token['value'])) &&
+            $this->lexer->isNextToken(DocLexer::T_NAMESPACE_SEPARATOR)
+        ) {
+            $this->match(DocLexer::T_NAMESPACE_SEPARATOR);
+            $this->matchAny(self::$classIdentifiers);
+
+            $className .= '\\' . $this->lexer->token['value'];
+        }
+
+        return $className;
+    }
+
+    /**
+     * Value ::= PlainValue | FieldAssignment
+     *
+     * @return mixed
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function Value()
+    {
+        $peek = $this->lexer->glimpse();
+
+        if ($peek['type'] === DocLexer::T_EQUALS) {
+            return $this->FieldAssignment();
+        }
+
+        return $this->PlainValue();
+    }
+
+    /**
+     * PlainValue ::= integer | string | float | boolean | Array | Annotation
+     *
+     * @return mixed
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function PlainValue()
+    {
+        if ($this->lexer->isNextToken(DocLexer::T_OPEN_CURLY_BRACES)) {
+            return $this->Arrayx();
+        }
+
+        if ($this->lexer->isNextToken(DocLexer::T_AT)) {
+            return $this->Annotation();
+        }
+
+        if ($this->lexer->isNextToken(DocLexer::T_IDENTIFIER)) {
+            return $this->Constant();
+        }
+
+        switch ($this->lexer->lookahead['type']) {
+            case DocLexer::T_STRING:
+                $this->match(DocLexer::T_STRING);
+
+                return $this->lexer->token['value'];
+
+            case DocLexer::T_INTEGER:
+                $this->match(DocLexer::T_INTEGER);
+
+                return (int) $this->lexer->token['value'];
+
+            case DocLexer::T_FLOAT:
+                $this->match(DocLexer::T_FLOAT);
+
+                return (float) $this->lexer->token['value'];
+
+            case DocLexer::T_TRUE:
+                $this->match(DocLexer::T_TRUE);
+
+                return true;
+
+            case DocLexer::T_FALSE:
+                $this->match(DocLexer::T_FALSE);
+
+                return false;
+
+            case DocLexer::T_NULL:
+                $this->match(DocLexer::T_NULL);
+
+                return null;
+
+            default:
+                throw $this->syntaxError('PlainValue');
+        }
+    }
+
+    /**
+     * FieldAssignment ::= FieldName "=" PlainValue
+     * FieldName ::= identifier
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function FieldAssignment(): stdClass
+    {
+        $this->match(DocLexer::T_IDENTIFIER);
+        $fieldName = $this->lexer->token['value'];
+
+        $this->match(DocLexer::T_EQUALS);
+
+        $item        = new stdClass();
+        $item->name  = $fieldName;
+        $item->value = $this->PlainValue();
+
+        return $item;
+    }
+
+    /**
+     * Array ::= "{" ArrayEntry {"," ArrayEntry}* [","] "}"
+     *
+     * @return mixed[]
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function Arrayx(): array
+    {
+        $array = $values = [];
+
+        $this->match(DocLexer::T_OPEN_CURLY_BRACES);
+
+        // If the array is empty, stop parsing and return.
+        if ($this->lexer->isNextToken(DocLexer::T_CLOSE_CURLY_BRACES)) {
+            $this->match(DocLexer::T_CLOSE_CURLY_BRACES);
+
+            return $array;
+        }
+
+        $values[] = $this->ArrayEntry();
+
+        while ($this->lexer->isNextToken(DocLexer::T_COMMA)) {
+            $this->match(DocLexer::T_COMMA);
+
+            // optional trailing comma
+            if ($this->lexer->isNextToken(DocLexer::T_CLOSE_CURLY_BRACES)) {
+                break;
+            }
+
+            $values[] = $this->ArrayEntry();
+        }
+
+        $this->match(DocLexer::T_CLOSE_CURLY_BRACES);
+
+        foreach ($values as $value) {
+            [$key, $val] = $value;
+
+            if ($key !== null) {
+                $array[$key] = $val;
+            } else {
+                $array[] = $val;
+            }
+        }
+
+        return $array;
+    }
+
+    /**
+     * ArrayEntry ::= Value | KeyValuePair
+     * KeyValuePair ::= Key ("=" | ":") PlainValue | Constant
+     * Key ::= string | integer | Constant
+     *
+     * @phpstan-return array{mixed, mixed}
+     *
+     * @throws AnnotationException
+     * @throws ReflectionException
+     */
+    private function ArrayEntry(): array
+    {
+        $peek = $this->lexer->glimpse();
+
+        if (
+            $peek['type'] === DocLexer::T_EQUALS
+                || $peek['type'] === DocLexer::T_COLON
+        ) {
+            if ($this->lexer->isNextToken(DocLexer::T_IDENTIFIER)) {
+                $key = $this->Constant();
+            } else {
+                $this->matchAny([DocLexer::T_INTEGER, DocLexer::T_STRING]);
+                $key = $this->lexer->token['value'];
+            }
+
+            $this->matchAny([DocLexer::T_EQUALS, DocLexer::T_COLON]);
+
+            return [$key, $this->PlainValue()];
+        }
+
+        return [null, $this->Value()];
+    }
+
+    /**
+     * Checks whether the given $name matches any ignored annotation name or namespace
+     */
+    private function isIgnoredAnnotation(string $name): bool
+    {
+        if ($this->ignoreNotImportedAnnotations || isset($this->ignoredAnnotationNames[$name])) {
+            return true;
+        }
+
+        foreach (array_keys($this->ignoredAnnotationNamespaces) as $ignoredAnnotationNamespace) {
+            $ignoredAnnotationNamespace = rtrim($ignoredAnnotationNamespace, '\\') . '\\';
+
+            if (stripos(rtrim($name, '\\') . '\\', $ignoredAnnotationNamespace) === 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Resolve positional arguments (without name) to named ones
+     *
+     * @param array<string,mixed> $arguments
+     *
+     * @return array<string,mixed>
+     */
+    private function resolvePositionalValues(array $arguments, string $name): array
+    {
+        $positionalArguments = $arguments['positional_arguments'] ?? [];
+        $values              = $arguments['named_arguments'] ?? [];
+
+        if (
+            self::$annotationMetadata[$name]['has_named_argument_constructor']
+            && self::$annotationMetadata[$name]['default_property'] !== null
+        ) {
+            // We must ensure that we don't have positional arguments after named ones
+            $positions    = array_keys($positionalArguments);
+            $lastPosition = null;
+            foreach ($positions as $position) {
+                if (
+                    ($lastPosition === null && $position !== 0) ||
+                    ($lastPosition !== null && $position !== $lastPosition + 1)
+                ) {
+                    throw $this->syntaxError('Positional arguments after named arguments is not allowed');
+                }
+
+                $lastPosition = $position;
+            }
+
+            foreach (self::$annotationMetadata[$name]['constructor_args'] as $property => $parameter) {
+                $position = $parameter['position'];
+                if (isset($values[$property]) || ! isset($positionalArguments[$position])) {
+                    continue;
+                }
+
+                $values[$property] = $positionalArguments[$position];
+            }
+        } else {
+            if (count($positionalArguments) > 0 && ! isset($values['value'])) {
+                if (count($positionalArguments) === 1) {
+                    $value = array_pop($positionalArguments);
+                } else {
+                    $value = array_values($positionalArguments);
+                }
+
+                $values['value'] = $value;
+            }
+        }
+
+        return $values;
+    }
+
+    /**
+     * Try to instantiate the annotation and catch and process any exceptions related to failure
+     *
+     * @param class-string        $name
+     * @param array<string,mixed> $arguments
+     *
+     * @return object
+     *
+     * @throws AnnotationException
+     */
+    private function instantiateAnnotiation(string $originalName, string $context, string $name, array $arguments)
+    {
+        try {
+            return new $name(...$arguments);
+        } catch (Throwable $exception) {
+            throw AnnotationException::creationError(
+                sprintf(
+                    'An error occurred while instantiating the annotation @%s declared on %s: "%s".',
+                    $originalName,
+                    $context,
+                    $exception->getMessage()
+                ),
+                $exception
+            );
+        }
+    }
+}

+ 315 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.php

@@ -0,0 +1,315 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use InvalidArgumentException;
+use ReflectionClass;
+use ReflectionMethod;
+use ReflectionProperty;
+use RuntimeException;
+
+use function chmod;
+use function file_put_contents;
+use function filemtime;
+use function gettype;
+use function is_dir;
+use function is_file;
+use function is_int;
+use function is_writable;
+use function mkdir;
+use function rename;
+use function rtrim;
+use function serialize;
+use function sha1;
+use function sprintf;
+use function strtr;
+use function tempnam;
+use function uniqid;
+use function unlink;
+use function var_export;
+
+/**
+ * File cache reader for annotations.
+ *
+ * @deprecated the FileCacheReader is deprecated and will be removed
+ *             in version 2.0.0 of doctrine/annotations. Please use the
+ *             {@see \Doctrine\Common\Annotations\PsrCachedReader} instead.
+ */
+class FileCacheReader implements Reader
+{
+    /** @var Reader */
+    private $reader;
+
+    /** @var string */
+    private $dir;
+
+    /** @var bool */
+    private $debug;
+
+    /** @phpstan-var array<string, list<object>> */
+    private $loadedAnnotations = [];
+
+    /** @var array<string, string> */
+    private $classNameHashes = [];
+
+    /** @var int */
+    private $umask;
+
+    /**
+     * @param string $cacheDir
+     * @param bool   $debug
+     * @param int    $umask
+     *
+     * @throws InvalidArgumentException
+     */
+    public function __construct(Reader $reader, $cacheDir, $debug = false, $umask = 0002)
+    {
+        if (! is_int($umask)) {
+            throw new InvalidArgumentException(sprintf(
+                'The parameter umask must be an integer, was: %s',
+                gettype($umask)
+            ));
+        }
+
+        $this->reader = $reader;
+        $this->umask  = $umask;
+
+        if (! is_dir($cacheDir) && ! @mkdir($cacheDir, 0777 & (~$this->umask), true)) {
+            throw new InvalidArgumentException(sprintf(
+                'The directory "%s" does not exist and could not be created.',
+                $cacheDir
+            ));
+        }
+
+        $this->dir   = rtrim($cacheDir, '\\/');
+        $this->debug = $debug;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotations(ReflectionClass $class)
+    {
+        if (! isset($this->classNameHashes[$class->name])) {
+            $this->classNameHashes[$class->name] = sha1($class->name);
+        }
+
+        $key = $this->classNameHashes[$class->name];
+
+        if (isset($this->loadedAnnotations[$key])) {
+            return $this->loadedAnnotations[$key];
+        }
+
+        $path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
+        if (! is_file($path)) {
+            $annot = $this->reader->getClassAnnotations($class);
+            $this->saveCacheFile($path, $annot);
+
+            return $this->loadedAnnotations[$key] = $annot;
+        }
+
+        $filename = $class->getFilename();
+        if (
+            $this->debug
+            && $filename !== false
+            && filemtime($path) < filemtime($filename)
+        ) {
+            @unlink($path);
+
+            $annot = $this->reader->getClassAnnotations($class);
+            $this->saveCacheFile($path, $annot);
+
+            return $this->loadedAnnotations[$key] = $annot;
+        }
+
+        return $this->loadedAnnotations[$key] = include $path;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotations(ReflectionProperty $property)
+    {
+        $class = $property->getDeclaringClass();
+        if (! isset($this->classNameHashes[$class->name])) {
+            $this->classNameHashes[$class->name] = sha1($class->name);
+        }
+
+        $key = $this->classNameHashes[$class->name] . '$' . $property->getName();
+
+        if (isset($this->loadedAnnotations[$key])) {
+            return $this->loadedAnnotations[$key];
+        }
+
+        $path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
+        if (! is_file($path)) {
+            $annot = $this->reader->getPropertyAnnotations($property);
+            $this->saveCacheFile($path, $annot);
+
+            return $this->loadedAnnotations[$key] = $annot;
+        }
+
+        $filename = $class->getFilename();
+        if (
+            $this->debug
+            && $filename !== false
+            && filemtime($path) < filemtime($filename)
+        ) {
+            @unlink($path);
+
+            $annot = $this->reader->getPropertyAnnotations($property);
+            $this->saveCacheFile($path, $annot);
+
+            return $this->loadedAnnotations[$key] = $annot;
+        }
+
+        return $this->loadedAnnotations[$key] = include $path;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotations(ReflectionMethod $method)
+    {
+        $class = $method->getDeclaringClass();
+        if (! isset($this->classNameHashes[$class->name])) {
+            $this->classNameHashes[$class->name] = sha1($class->name);
+        }
+
+        $key = $this->classNameHashes[$class->name] . '#' . $method->getName();
+
+        if (isset($this->loadedAnnotations[$key])) {
+            return $this->loadedAnnotations[$key];
+        }
+
+        $path = $this->dir . '/' . strtr($key, '\\', '-') . '.cache.php';
+        if (! is_file($path)) {
+            $annot = $this->reader->getMethodAnnotations($method);
+            $this->saveCacheFile($path, $annot);
+
+            return $this->loadedAnnotations[$key] = $annot;
+        }
+
+        $filename = $class->getFilename();
+        if (
+            $this->debug
+            && $filename !== false
+            && filemtime($path) < filemtime($filename)
+        ) {
+            @unlink($path);
+
+            $annot = $this->reader->getMethodAnnotations($method);
+            $this->saveCacheFile($path, $annot);
+
+            return $this->loadedAnnotations[$key] = $annot;
+        }
+
+        return $this->loadedAnnotations[$key] = include $path;
+    }
+
+    /**
+     * Saves the cache file.
+     *
+     * @param string $path
+     * @param mixed  $data
+     *
+     * @return void
+     */
+    private function saveCacheFile($path, $data)
+    {
+        if (! is_writable($this->dir)) {
+            throw new InvalidArgumentException(sprintf(
+                <<<'EXCEPTION'
+The directory "%s" is not writable. Both the webserver and the console user need access.
+You can manage access rights for multiple users with "chmod +a".
+If your system does not support this, check out the acl package.,
+EXCEPTION
+                ,
+                $this->dir
+            ));
+        }
+
+        $tempfile = tempnam($this->dir, uniqid('', true));
+
+        if ($tempfile === false) {
+            throw new RuntimeException(sprintf('Unable to create tempfile in directory: %s', $this->dir));
+        }
+
+        @chmod($tempfile, 0666 & (~$this->umask));
+
+        $written = file_put_contents(
+            $tempfile,
+            '<?php return unserialize(' . var_export(serialize($data), true) . ');'
+        );
+
+        if ($written === false) {
+            throw new RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
+        }
+
+        @chmod($tempfile, 0666 & (~$this->umask));
+
+        if (rename($tempfile, $path) === false) {
+            @unlink($tempfile);
+
+            throw new RuntimeException(sprintf('Unable to rename %s to %s', $tempfile, $path));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotation(ReflectionClass $class, $annotationName)
+    {
+        $annotations = $this->getClassAnnotations($class);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof $annotationName) {
+                return $annotation;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
+    {
+        $annotations = $this->getMethodAnnotations($method);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof $annotationName) {
+                return $annotation;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
+    {
+        $annotations = $this->getPropertyAnnotations($property);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof $annotationName) {
+                return $annotation;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Clears loaded annotations.
+     *
+     * @return void
+     */
+    public function clearLoadedAnnotations()
+    {
+        $this->loadedAnnotations = [];
+    }
+}

+ 178 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/ImplicitlyIgnoredAnnotationNames.php

@@ -0,0 +1,178 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ *  A list of annotations that are implicitly ignored during the parsing process.
+ *
+ *  All names are case sensitive.
+ */
+final class ImplicitlyIgnoredAnnotationNames
+{
+    private const Reserved = [
+        'Annotation'               => true,
+        'Attribute'                => true,
+        'Attributes'               => true,
+        /* Can we enable this? 'Enum' => true, */
+        'Required'                 => true,
+        'Target'                   => true,
+        'NamedArgumentConstructor' => true,
+    ];
+
+    private const WidelyUsedNonStandard = [
+        'fix'      => true,
+        'fixme'    => true,
+        'override' => true,
+    ];
+
+    private const PhpDocumentor1 = [
+        'abstract'   => true,
+        'access'     => true,
+        'code'       => true,
+        'deprec'     => true,
+        'endcode'    => true,
+        'exception'  => true,
+        'final'      => true,
+        'ingroup'    => true,
+        'inheritdoc' => true,
+        'inheritDoc' => true,
+        'magic'      => true,
+        'name'       => true,
+        'private'    => true,
+        'static'     => true,
+        'staticvar'  => true,
+        'staticVar'  => true,
+        'toc'        => true,
+        'tutorial'   => true,
+        'throw'      => true,
+    ];
+
+    private const PhpDocumentor2 = [
+        'api'            => true,
+        'author'         => true,
+        'category'       => true,
+        'copyright'      => true,
+        'deprecated'     => true,
+        'example'        => true,
+        'filesource'     => true,
+        'global'         => true,
+        'ignore'         => true,
+        /* Can we enable this? 'index' => true, */
+        'internal'       => true,
+        'license'        => true,
+        'link'           => true,
+        'method'         => true,
+        'package'        => true,
+        'param'          => true,
+        'property'       => true,
+        'property-read'  => true,
+        'property-write' => true,
+        'return'         => true,
+        'see'            => true,
+        'since'          => true,
+        'source'         => true,
+        'subpackage'     => true,
+        'throws'         => true,
+        'todo'           => true,
+        'TODO'           => true,
+        'usedby'         => true,
+        'uses'           => true,
+        'var'            => true,
+        'version'        => true,
+    ];
+
+    private const PHPUnit = [
+        'author'                         => true,
+        'after'                          => true,
+        'afterClass'                     => true,
+        'backupGlobals'                  => true,
+        'backupStaticAttributes'         => true,
+        'before'                         => true,
+        'beforeClass'                    => true,
+        'codeCoverageIgnore'             => true,
+        'codeCoverageIgnoreStart'        => true,
+        'codeCoverageIgnoreEnd'          => true,
+        'covers'                         => true,
+        'coversDefaultClass'             => true,
+        'coversNothing'                  => true,
+        'dataProvider'                   => true,
+        'depends'                        => true,
+        'doesNotPerformAssertions'       => true,
+        'expectedException'              => true,
+        'expectedExceptionCode'          => true,
+        'expectedExceptionMessage'       => true,
+        'expectedExceptionMessageRegExp' => true,
+        'group'                          => true,
+        'large'                          => true,
+        'medium'                         => true,
+        'preserveGlobalState'            => true,
+        'requires'                       => true,
+        'runTestsInSeparateProcesses'    => true,
+        'runInSeparateProcess'           => true,
+        'small'                          => true,
+        'test'                           => true,
+        'testdox'                        => true,
+        'testWith'                       => true,
+        'ticket'                         => true,
+        'uses'                           => true,
+    ];
+
+    private const PhpCheckStyle = ['SuppressWarnings' => true];
+
+    private const PhpStorm = ['noinspection' => true];
+
+    private const PEAR = ['package_version' => true];
+
+    private const PlainUML = [
+        'startuml' => true,
+        'enduml'   => true,
+    ];
+
+    private const Symfony = ['experimental' => true];
+
+    private const PhpCodeSniffer = [
+        'codingStandardsIgnoreStart' => true,
+        'codingStandardsIgnoreEnd'   => true,
+    ];
+
+    private const SlevomatCodingStandard = ['phpcsSuppress' => true];
+
+    private const Phan = ['suppress' => true];
+
+    private const Rector = ['noRector' => true];
+
+    private const StaticAnalysis = [
+        // PHPStan, Psalm
+        'extends' => true,
+        'implements' => true,
+        'readonly' => true,
+        'template' => true,
+        'use' => true,
+
+        // Psalm
+        'pure' => true,
+        'immutable' => true,
+    ];
+
+    public const LIST = self::Reserved
+        + self::WidelyUsedNonStandard
+        + self::PhpDocumentor1
+        + self::PhpDocumentor2
+        + self::PHPUnit
+        + self::PhpCheckStyle
+        + self::PhpStorm
+        + self::PEAR
+        + self::PlainUML
+        + self::Symfony
+        + self::SlevomatCodingStandard
+        + self::PhpCodeSniffer
+        + self::Phan
+        + self::Rector
+        + self::StaticAnalysis;
+
+    private function __construct()
+    {
+    }
+}

+ 100 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php

@@ -0,0 +1,100 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use ReflectionClass;
+use ReflectionMethod;
+use ReflectionProperty;
+
+use function call_user_func_array;
+use function get_class;
+
+/**
+ * Allows the reader to be used in-place of Doctrine's reader.
+ */
+class IndexedReader implements Reader
+{
+    /** @var Reader */
+    private $delegate;
+
+    public function __construct(Reader $reader)
+    {
+        $this->delegate = $reader;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotations(ReflectionClass $class)
+    {
+        $annotations = [];
+        foreach ($this->delegate->getClassAnnotations($class) as $annot) {
+            $annotations[get_class($annot)] = $annot;
+        }
+
+        return $annotations;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotation(ReflectionClass $class, $annotationName)
+    {
+        return $this->delegate->getClassAnnotation($class, $annotationName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotations(ReflectionMethod $method)
+    {
+        $annotations = [];
+        foreach ($this->delegate->getMethodAnnotations($method) as $annot) {
+            $annotations[get_class($annot)] = $annot;
+        }
+
+        return $annotations;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
+    {
+        return $this->delegate->getMethodAnnotation($method, $annotationName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotations(ReflectionProperty $property)
+    {
+        $annotations = [];
+        foreach ($this->delegate->getPropertyAnnotations($property) as $annot) {
+            $annotations[get_class($annot)] = $annot;
+        }
+
+        return $annotations;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
+    {
+        return $this->delegate->getPropertyAnnotation($property, $annotationName);
+    }
+
+    /**
+     * Proxies all methods to the delegate.
+     *
+     * @param string  $method
+     * @param mixed[] $args
+     *
+     * @return mixed
+     */
+    public function __call($method, $args)
+    {
+        return call_user_func_array([$this->delegate, $method], $args);
+    }
+}

+ 14 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/NamedArgumentConstructorAnnotation.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * Marker interface for PHP7/PHP8 compatible support
+ * for named arguments (and constructor property promotion).
+ *
+ * @deprecated Implementing this interface is deprecated
+ *             Use the Annotation @NamedArgumentConstructor instead
+ */
+interface NamedArgumentConstructorAnnotation
+{
+}

+ 92 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use ReflectionClass;
+use ReflectionFunction;
+use SplFileObject;
+
+use function is_file;
+use function method_exists;
+use function preg_quote;
+use function preg_replace;
+
+/**
+ * Parses a file for namespaces/use/class declarations.
+ */
+final class PhpParser
+{
+    /**
+     * Parses a class.
+     *
+     * @deprecated use parseUseStatements instead
+     *
+     * @param ReflectionClass $class A <code>ReflectionClass</code> object.
+     *
+     * @return array<string, class-string> A list with use statements in the form (Alias => FQN).
+     */
+    public function parseClass(ReflectionClass $class)
+    {
+        return $this->parseUseStatements($class);
+    }
+
+    /**
+     * Parse a class or function for use statements.
+     *
+     * @param ReflectionClass|ReflectionFunction $reflection
+     *
+     * @psalm-return array<string, string> a list with use statements in the form (Alias => FQN).
+     */
+    public function parseUseStatements($reflection): array
+    {
+        if (method_exists($reflection, 'getUseStatements')) {
+            return $reflection->getUseStatements();
+        }
+
+        $filename = $reflection->getFileName();
+
+        if ($filename === false) {
+            return [];
+        }
+
+        $content = $this->getFileContent($filename, $reflection->getStartLine());
+
+        if ($content === null) {
+            return [];
+        }
+
+        $namespace = preg_quote($reflection->getNamespaceName());
+        $content   = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
+        $tokenizer = new TokenParser('<?php ' . $content);
+
+        return $tokenizer->parseUseStatements($reflection->getNamespaceName());
+    }
+
+    /**
+     * Gets the content of the file right up to the given line number.
+     *
+     * @param string $filename   The name of the file to load.
+     * @param int    $lineNumber The number of lines to read from file.
+     *
+     * @return string|null The content of the file or null if the file does not exist.
+     */
+    private function getFileContent($filename, $lineNumber)
+    {
+        if (! is_file($filename)) {
+            return null;
+        }
+
+        $content = '';
+        $lineCnt = 0;
+        $file    = new SplFileObject($filename);
+        while (! $file->eof()) {
+            if ($lineCnt++ === $lineNumber) {
+                break;
+            }
+
+            $content .= $file->fgets();
+        }
+
+        return $content;
+    }
+}

+ 232 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php

@@ -0,0 +1,232 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use Psr\Cache\CacheItemPoolInterface;
+use ReflectionClass;
+use ReflectionMethod;
+use ReflectionProperty;
+use Reflector;
+
+use function array_map;
+use function array_merge;
+use function assert;
+use function filemtime;
+use function max;
+use function rawurlencode;
+use function time;
+
+/**
+ * A cache aware annotation reader.
+ */
+final class PsrCachedReader implements Reader
+{
+    /** @var Reader */
+    private $delegate;
+
+    /** @var CacheItemPoolInterface */
+    private $cache;
+
+    /** @var bool */
+    private $debug;
+
+    /** @var array<string, array<object>> */
+    private $loadedAnnotations = [];
+
+    /** @var int[] */
+    private $loadedFilemtimes = [];
+
+    public function __construct(Reader $reader, CacheItemPoolInterface $cache, bool $debug = false)
+    {
+        $this->delegate = $reader;
+        $this->cache    = $cache;
+        $this->debug    = (bool) $debug;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotations(ReflectionClass $class)
+    {
+        $cacheKey = $class->getName();
+
+        if (isset($this->loadedAnnotations[$cacheKey])) {
+            return $this->loadedAnnotations[$cacheKey];
+        }
+
+        $annots = $this->fetchFromCache($cacheKey, $class, 'getClassAnnotations', $class);
+
+        return $this->loadedAnnotations[$cacheKey] = $annots;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotation(ReflectionClass $class, $annotationName)
+    {
+        foreach ($this->getClassAnnotations($class) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotations(ReflectionProperty $property)
+    {
+        $class    = $property->getDeclaringClass();
+        $cacheKey = $class->getName() . '$' . $property->getName();
+
+        if (isset($this->loadedAnnotations[$cacheKey])) {
+            return $this->loadedAnnotations[$cacheKey];
+        }
+
+        $annots = $this->fetchFromCache($cacheKey, $class, 'getPropertyAnnotations', $property);
+
+        return $this->loadedAnnotations[$cacheKey] = $annots;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
+    {
+        foreach ($this->getPropertyAnnotations($property) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotations(ReflectionMethod $method)
+    {
+        $class    = $method->getDeclaringClass();
+        $cacheKey = $class->getName() . '#' . $method->getName();
+
+        if (isset($this->loadedAnnotations[$cacheKey])) {
+            return $this->loadedAnnotations[$cacheKey];
+        }
+
+        $annots = $this->fetchFromCache($cacheKey, $class, 'getMethodAnnotations', $method);
+
+        return $this->loadedAnnotations[$cacheKey] = $annots;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
+    {
+        foreach ($this->getMethodAnnotations($method) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    public function clearLoadedAnnotations(): void
+    {
+        $this->loadedAnnotations = [];
+        $this->loadedFilemtimes  = [];
+    }
+
+    /** @return mixed[] */
+    private function fetchFromCache(
+        string $cacheKey,
+        ReflectionClass $class,
+        string $method,
+        Reflector $reflector
+    ): array {
+        $cacheKey = rawurlencode($cacheKey);
+
+        $item = $this->cache->getItem($cacheKey);
+        if (($this->debug && ! $this->refresh($cacheKey, $class)) || ! $item->isHit()) {
+            $this->cache->save($item->set($this->delegate->{$method}($reflector)));
+        }
+
+        return $item->get();
+    }
+
+    /**
+     * Used in debug mode to check if the cache is fresh.
+     *
+     * @return bool Returns true if the cache was fresh, or false if the class
+     * being read was modified since writing to the cache.
+     */
+    private function refresh(string $cacheKey, ReflectionClass $class): bool
+    {
+        $lastModification = $this->getLastModification($class);
+        if ($lastModification === 0) {
+            return true;
+        }
+
+        $item = $this->cache->getItem('[C]' . $cacheKey);
+        if ($item->isHit() && $item->get() >= $lastModification) {
+            return true;
+        }
+
+        $this->cache->save($item->set(time()));
+
+        return false;
+    }
+
+    /**
+     * Returns the time the class was last modified, testing traits and parents
+     */
+    private function getLastModification(ReflectionClass $class): int
+    {
+        $filename = $class->getFileName();
+
+        if (isset($this->loadedFilemtimes[$filename])) {
+            return $this->loadedFilemtimes[$filename];
+        }
+
+        $parent = $class->getParentClass();
+
+        $lastModification =  max(array_merge(
+            [$filename ? filemtime($filename) : 0],
+            array_map(function (ReflectionClass $reflectionTrait): int {
+                return $this->getTraitLastModificationTime($reflectionTrait);
+            }, $class->getTraits()),
+            array_map(function (ReflectionClass $class): int {
+                return $this->getLastModification($class);
+            }, $class->getInterfaces()),
+            $parent ? [$this->getLastModification($parent)] : []
+        ));
+
+        assert($lastModification !== false);
+
+        return $this->loadedFilemtimes[$filename] = $lastModification;
+    }
+
+    private function getTraitLastModificationTime(ReflectionClass $reflectionTrait): int
+    {
+        $fileName = $reflectionTrait->getFileName();
+
+        if (isset($this->loadedFilemtimes[$fileName])) {
+            return $this->loadedFilemtimes[$fileName];
+        }
+
+        $lastModificationTime = max(array_merge(
+            [$fileName ? filemtime($fileName) : 0],
+            array_map(function (ReflectionClass $reflectionTrait): int {
+                return $this->getTraitLastModificationTime($reflectionTrait);
+            }, $reflectionTrait->getTraits())
+        ));
+
+        assert($lastModificationTime !== false);
+
+        return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
+    }
+}

+ 80 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php

@@ -0,0 +1,80 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use ReflectionClass;
+use ReflectionMethod;
+use ReflectionProperty;
+
+/**
+ * Interface for annotation readers.
+ */
+interface Reader
+{
+    /**
+     * Gets the annotations applied to a class.
+     *
+     * @param ReflectionClass $class The ReflectionClass of the class from which
+     * the class annotations should be read.
+     *
+     * @return array<object> An array of Annotations.
+     */
+    public function getClassAnnotations(ReflectionClass $class);
+
+    /**
+     * Gets a class annotation.
+     *
+     * @param ReflectionClass $class          The ReflectionClass of the class from which
+     *          the class annotations should be read.
+     * @param class-string<T> $annotationName The name of the annotation.
+     *
+     * @return T|null The Annotation or NULL, if the requested annotation does not exist.
+     *
+     * @template T
+     */
+    public function getClassAnnotation(ReflectionClass $class, $annotationName);
+
+    /**
+     * Gets the annotations applied to a method.
+     *
+     * @param ReflectionMethod $method The ReflectionMethod of the method from which
+     * the annotations should be read.
+     *
+     * @return array<object> An array of Annotations.
+     */
+    public function getMethodAnnotations(ReflectionMethod $method);
+
+    /**
+     * Gets a method annotation.
+     *
+     * @param ReflectionMethod $method         The ReflectionMethod to read the annotations from.
+     * @param class-string<T>  $annotationName The name of the annotation.
+     *
+     * @return T|null The Annotation or NULL, if the requested annotation does not exist.
+     *
+     * @template T
+     */
+    public function getMethodAnnotation(ReflectionMethod $method, $annotationName);
+
+    /**
+     * Gets the annotations applied to a property.
+     *
+     * @param ReflectionProperty $property The ReflectionProperty of the property
+     * from which the annotations should be read.
+     *
+     * @return array<object> An array of Annotations.
+     */
+    public function getPropertyAnnotations(ReflectionProperty $property);
+
+    /**
+     * Gets a property annotation.
+     *
+     * @param ReflectionProperty $property       The ReflectionProperty to read the annotations from.
+     * @param class-string<T>    $annotationName The name of the annotation.
+     *
+     * @return T|null The Annotation or NULL, if the requested annotation does not exist.
+     *
+     * @template T
+     */
+    public function getPropertyAnnotation(ReflectionProperty $property, $annotationName);
+}

+ 114 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php

@@ -0,0 +1,114 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use ReflectionClass;
+use ReflectionMethod;
+use ReflectionProperty;
+
+/**
+ * Simple Annotation Reader.
+ *
+ * This annotation reader is intended to be used in projects where you have
+ * full-control over all annotations that are available.
+ *
+ * @deprecated Deprecated in favour of using AnnotationReader
+ */
+class SimpleAnnotationReader implements Reader
+{
+    /** @var DocParser */
+    private $parser;
+
+    /**
+     * Initializes a new SimpleAnnotationReader.
+     */
+    public function __construct()
+    {
+        $this->parser = new DocParser();
+        $this->parser->setIgnoreNotImportedAnnotations(true);
+    }
+
+    /**
+     * Adds a namespace in which we will look for annotations.
+     *
+     * @param string $namespace
+     *
+     * @return void
+     */
+    public function addNamespace($namespace)
+    {
+        $this->parser->addNamespace($namespace);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotations(ReflectionClass $class)
+    {
+        return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotations(ReflectionMethod $method)
+    {
+        return $this->parser->parse(
+            $method->getDocComment(),
+            'method ' . $method->getDeclaringClass()->name . '::' . $method->getName() . '()'
+        );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotations(ReflectionProperty $property)
+    {
+        return $this->parser->parse(
+            $property->getDocComment(),
+            'property ' . $property->getDeclaringClass()->name . '::$' . $property->getName()
+        );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotation(ReflectionClass $class, $annotationName)
+    {
+        foreach ($this->getClassAnnotations($class) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getMethodAnnotation(ReflectionMethod $method, $annotationName)
+    {
+        foreach ($this->getMethodAnnotations($method) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getPropertyAnnotation(ReflectionProperty $property, $annotationName)
+    {
+        foreach ($this->getPropertyAnnotations($property) as $annot) {
+            if ($annot instanceof $annotationName) {
+                return $annot;
+            }
+        }
+
+        return null;
+    }
+}

+ 206 - 0
vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php

@@ -0,0 +1,206 @@
+<?php
+
+namespace Doctrine\Common\Annotations;
+
+use function array_merge;
+use function count;
+use function explode;
+use function strtolower;
+use function token_get_all;
+
+use const PHP_VERSION_ID;
+use const T_AS;
+use const T_COMMENT;
+use const T_DOC_COMMENT;
+use const T_NAME_FULLY_QUALIFIED;
+use const T_NAME_QUALIFIED;
+use const T_NAMESPACE;
+use const T_NS_SEPARATOR;
+use const T_STRING;
+use const T_USE;
+use const T_WHITESPACE;
+
+/**
+ * Parses a file for namespaces/use/class declarations.
+ */
+class TokenParser
+{
+    /**
+     * The token list.
+     *
+     * @phpstan-var list<mixed[]>
+     */
+    private $tokens;
+
+    /**
+     * The number of tokens.
+     *
+     * @var int
+     */
+    private $numTokens;
+
+    /**
+     * The current array pointer.
+     *
+     * @var int
+     */
+    private $pointer = 0;
+
+    /** @param string $contents */
+    public function __construct($contents)
+    {
+        $this->tokens = token_get_all($contents);
+
+        // The PHP parser sets internal compiler globals for certain things. Annoyingly, the last docblock comment it
+        // saw gets stored in doc_comment. When it comes to compile the next thing to be include()d this stored
+        // doc_comment becomes owned by the first thing the compiler sees in the file that it considers might have a
+        // docblock. If the first thing in the file is a class without a doc block this would cause calls to
+        // getDocBlock() on said class to return our long lost doc_comment. Argh.
+        // To workaround, cause the parser to parse an empty docblock. Sure getDocBlock() will return this, but at least
+        // it's harmless to us.
+        token_get_all("<?php\n/**\n *\n */");
+
+        $this->numTokens = count($this->tokens);
+    }
+
+    /**
+     * Gets the next non whitespace and non comment token.
+     *
+     * @param bool $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped.
+     * If FALSE then only whitespace and normal comments are skipped.
+     *
+     * @return mixed[]|string|null The token if exists, null otherwise.
+     */
+    public function next($docCommentIsComment = true)
+    {
+        for ($i = $this->pointer; $i < $this->numTokens; $i++) {
+            $this->pointer++;
+            if (
+                $this->tokens[$i][0] === T_WHITESPACE ||
+                $this->tokens[$i][0] === T_COMMENT ||
+                ($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)
+            ) {
+                continue;
+            }
+
+            return $this->tokens[$i];
+        }
+
+        return null;
+    }
+
+    /**
+     * Parses a single use statement.
+     *
+     * @return array<string, string> A list with all found class names for a use statement.
+     */
+    public function parseUseStatement()
+    {
+        $groupRoot     = '';
+        $class         = '';
+        $alias         = '';
+        $statements    = [];
+        $explicitAlias = false;
+        while (($token = $this->next())) {
+            if (! $explicitAlias && $token[0] === T_STRING) {
+                $class .= $token[1];
+                $alias  = $token[1];
+            } elseif ($explicitAlias && $token[0] === T_STRING) {
+                $alias = $token[1];
+            } elseif (
+                PHP_VERSION_ID >= 80000 &&
+                ($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
+            ) {
+                $class .= $token[1];
+
+                $classSplit = explode('\\', $token[1]);
+                $alias      = $classSplit[count($classSplit) - 1];
+            } elseif ($token[0] === T_NS_SEPARATOR) {
+                $class .= '\\';
+                $alias  = '';
+            } elseif ($token[0] === T_AS) {
+                $explicitAlias = true;
+                $alias         = '';
+            } elseif ($token === ',') {
+                $statements[strtolower($alias)] = $groupRoot . $class;
+                $class                          = '';
+                $alias                          = '';
+                $explicitAlias                  = false;
+            } elseif ($token === ';') {
+                $statements[strtolower($alias)] = $groupRoot . $class;
+                break;
+            } elseif ($token === '{') {
+                $groupRoot = $class;
+                $class     = '';
+            } elseif ($token === '}') {
+                continue;
+            } else {
+                break;
+            }
+        }
+
+        return $statements;
+    }
+
+    /**
+     * Gets all use statements.
+     *
+     * @param string $namespaceName The namespace name of the reflected class.
+     *
+     * @return array<string, string> A list with all found use statements.
+     */
+    public function parseUseStatements($namespaceName)
+    {
+        $statements = [];
+        while (($token = $this->next())) {
+            if ($token[0] === T_USE) {
+                $statements = array_merge($statements, $this->parseUseStatement());
+                continue;
+            }
+
+            if ($token[0] !== T_NAMESPACE || $this->parseNamespace() !== $namespaceName) {
+                continue;
+            }
+
+            // Get fresh array for new namespace. This is to prevent the parser to collect the use statements
+            // for a previous namespace with the same name. This is the case if a namespace is defined twice
+            // or if a namespace with the same name is commented out.
+            $statements = [];
+        }
+
+        return $statements;
+    }
+
+    /**
+     * Gets the namespace.
+     *
+     * @return string The found namespace.
+     */
+    public function parseNamespace()
+    {
+        $name = '';
+        while (
+            ($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR || (
+            PHP_VERSION_ID >= 80000 &&
+            ($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
+            ))
+        ) {
+            $name .= $token[1];
+        }
+
+        return $name;
+    }
+
+    /**
+     * Gets the class name.
+     *
+     * @return string The found class name.
+     */
+    public function parseClass()
+    {
+        // Namespaces and class names are tokenized the same: T_STRINGs
+        // separated by T_NS_SEPARATOR so we can use one function to provide
+        // both.
+        return $this->parseNamespace();
+    }
+}

+ 15 - 0
vendor/doctrine/annotations/psalm.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<psalm
+    errorLevel="7"
+    resolveFromConfigFile="true"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="https://getpsalm.org/schema/config"
+    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
+>
+    <projectFiles>
+        <directory name="lib/Doctrine/Common/Annotations" />
+        <ignoreFiles>
+            <directory name="vendor" />
+        </ignoreFiles>
+    </projectFiles>
+</psalm>

+ 19 - 0
vendor/doctrine/deprecations/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2020-2021 Doctrine Project
+
+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.

+ 154 - 0
vendor/doctrine/deprecations/README.md

@@ -0,0 +1,154 @@
+# Doctrine Deprecations
+
+A small (side-effect free by default) layer on top of
+`trigger_error(E_USER_DEPRECATED)` or PSR-3 logging.
+
+- no side-effects by default, making it a perfect fit for libraries that don't know how the error handler works they operate under
+- options to avoid having to rely on error handlers global state by using PSR-3 logging
+- deduplicate deprecation messages to avoid excessive triggering and reduce overhead
+
+We recommend to collect Deprecations using a PSR logger instead of relying on
+the global error handler.
+
+## Usage from consumer perspective:
+
+Enable Doctrine deprecations to be sent to a PSR3 logger:
+
+```php
+\Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
+```
+
+Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)`
+messages.
+
+```php
+\Doctrine\Deprecations\Deprecation::enableWithTriggerError();
+```
+
+If you only want to enable deprecation tracking, without logging or calling `trigger_error` then call:
+
+```php
+\Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
+```
+
+Tracking is enabled with all three modes and provides access to all triggered
+deprecations and their individual count:
+
+```php
+$deprecations = \Doctrine\Deprecations\Deprecation::getTriggeredDeprecations();
+
+foreach ($deprecations as $identifier => $count) {
+    echo $identifier . " was triggered " . $count . " times\n";
+}
+```
+
+### Suppressing Specific Deprecations
+
+Disable triggering about specific deprecations:
+
+```php
+\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier");
+```
+
+Disable all deprecations from a package
+
+```php
+\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm");
+```
+
+### Other Operations
+
+When used within PHPUnit or other tools that could collect multiple instances of the same deprecations
+the deduplication can be disabled:
+
+```php
+\Doctrine\Deprecations\Deprecation::withoutDeduplication();
+```
+
+Disable deprecation tracking again:
+
+```php
+\Doctrine\Deprecations\Deprecation::disable();
+```
+
+## Usage from a library/producer perspective:
+
+When you want to unconditionally trigger a deprecation even when called
+from the library itself then the `trigger` method is the way to go:
+
+```php
+\Doctrine\Deprecations\Deprecation::trigger(
+    "doctrine/orm",
+    "https://link/to/deprecations-description",
+    "message"
+);
+```
+
+If variable arguments are provided at the end, they are used with `sprintf` on
+the message.
+
+```php
+\Doctrine\Deprecations\Deprecation::trigger(
+    "doctrine/orm",
+    "https://github.com/doctrine/orm/issue/1234",
+    "message %s %d",
+    "foo",
+    1234
+);
+```
+
+When you want to trigger a deprecation only when it is called by a function
+outside of the current package, but not trigger when the package itself is the cause,
+then use:
+
+```php
+\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside(
+    "doctrine/orm",
+    "https://link/to/deprecations-description",
+    "message"
+);
+```
+
+Based on the issue link each deprecation message is only triggered once per
+request.
+
+A limited stacktrace is included in the deprecation message to find the
+offending location.
+
+Note: A producer/library should never call `Deprecation::enableWith` methods
+and leave the decision how to handle deprecations to application and
+frameworks.
+
+## Usage in PHPUnit tests
+
+There is a `VerifyDeprecations` trait that you can use to make assertions on
+the occurrence of deprecations within a test.
+
+```php
+use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
+
+class MyTest extends TestCase
+{
+    use VerifyDeprecations;
+
+    public function testSomethingDeprecation()
+    {
+        $this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
+
+        triggerTheCodeWithDeprecation();
+    }
+
+    public function testSomethingDeprecationFixed()
+    {
+        $this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
+
+        triggerTheCodeWithoutDeprecation();
+    }
+}
+```
+
+## What is a deprecation identifier?
+
+An identifier for deprecations is just a link to any resource, most often a
+Github Issue or Pull Request explaining the deprecation and potentially its
+alternative.

+ 32 - 0
vendor/doctrine/deprecations/composer.json

@@ -0,0 +1,32 @@
+{
+    "name": "doctrine/deprecations",
+    "type": "library",
+    "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
+    "homepage": "https://www.doctrine-project.org/",
+    "license": "MIT",
+    "require": {
+        "php": "^7.1|^8.0"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "^7.5|^8.5|^9.5",
+        "psr/log": "^1|^2|^3",
+        "doctrine/coding-standard": "^9"
+    },
+    "suggest": {
+        "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
+    },
+    "autoload": {
+        "psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"}
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "DeprecationTests\\": "test_fixtures/src",
+            "Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo"
+        }
+    },
+    "config": {
+        "allow-plugins": {
+            "dealerdirect/phpcodesniffer-composer-installer": true
+        }
+    }
+}

+ 266 - 0
vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php

@@ -0,0 +1,266 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Deprecations;
+
+use Psr\Log\LoggerInterface;
+
+use function array_key_exists;
+use function array_reduce;
+use function debug_backtrace;
+use function sprintf;
+use function strpos;
+use function strrpos;
+use function substr;
+use function trigger_error;
+
+use const DEBUG_BACKTRACE_IGNORE_ARGS;
+use const DIRECTORY_SEPARATOR;
+use const E_USER_DEPRECATED;
+
+/**
+ * Manages Deprecation logging in different ways.
+ *
+ * By default triggered exceptions are not logged.
+ *
+ * To enable different deprecation logging mechanisms you can call the
+ * following methods:
+ *
+ *  - Minimal collection of deprecations via getTriggeredDeprecations()
+ *    \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
+ *
+ *  - Uses @trigger_error with E_USER_DEPRECATED
+ *    \Doctrine\Deprecations\Deprecation::enableWithTriggerError();
+ *
+ *  - Sends deprecation messages via a PSR-3 logger
+ *    \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
+ *
+ * Packages that trigger deprecations should use the `trigger()` or
+ * `triggerIfCalledFromOutside()` methods.
+ */
+class Deprecation
+{
+    private const TYPE_NONE               = 0;
+    private const TYPE_TRACK_DEPRECATIONS = 1;
+    private const TYPE_TRIGGER_ERROR      = 2;
+    private const TYPE_PSR_LOGGER         = 4;
+
+    /** @var int */
+    private static $type = self::TYPE_NONE;
+
+    /** @var LoggerInterface|null */
+    private static $logger;
+
+    /** @var array<string,bool> */
+    private static $ignoredPackages = [];
+
+    /** @var array<string,int> */
+    private static $ignoredLinks = [];
+
+    /** @var bool */
+    private static $deduplication = true;
+
+    /**
+     * Trigger a deprecation for the given package and identfier.
+     *
+     * The link should point to a Github issue or Wiki entry detailing the
+     * deprecation. It is additionally used to de-duplicate the trigger of the
+     * same deprecation during a request.
+     *
+     * @param mixed $args
+     */
+    public static function trigger(string $package, string $link, string $message, ...$args): void
+    {
+        if (self::$type === self::TYPE_NONE) {
+            return;
+        }
+
+        if (array_key_exists($link, self::$ignoredLinks)) {
+            self::$ignoredLinks[$link]++;
+        } else {
+            self::$ignoredLinks[$link] = 1;
+        }
+
+        if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
+            return;
+        }
+
+        if (isset(self::$ignoredPackages[$package])) {
+            return;
+        }
+
+        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
+
+        $message = sprintf($message, ...$args);
+
+        self::delegateTriggerToBackend($message, $backtrace, $link, $package);
+    }
+
+    /**
+     * Trigger a deprecation for the given package and identifier when called from outside.
+     *
+     * "Outside" means we assume that $package is currently installed as a
+     * dependency and the caller is not a file in that package. When $package
+     * is installed as a root package then deprecations triggered from the
+     * tests folder are also considered "outside".
+     *
+     * This deprecation method assumes that you are using Composer to install
+     * the dependency and are using the default /vendor/ folder and not a
+     * Composer plugin to change the install location. The assumption is also
+     * that $package is the exact composer packge name.
+     *
+     * Compared to {@link trigger()} this method causes some overhead when
+     * deprecation tracking is enabled even during deduplication, because it
+     * needs to call {@link debug_backtrace()}
+     *
+     * @param mixed $args
+     */
+    public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void
+    {
+        if (self::$type === self::TYPE_NONE) {
+            return;
+        }
+
+        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
+
+        // first check that the caller is not from a tests folder, in which case we always let deprecations pass
+        if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
+            $path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR;
+
+            if (strpos($backtrace[0]['file'], $path) === false) {
+                return;
+            }
+
+            if (strpos($backtrace[1]['file'], $path) !== false) {
+                return;
+            }
+        }
+
+        if (array_key_exists($link, self::$ignoredLinks)) {
+            self::$ignoredLinks[$link]++;
+        } else {
+            self::$ignoredLinks[$link] = 1;
+        }
+
+        if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
+            return;
+        }
+
+        if (isset(self::$ignoredPackages[$package])) {
+            return;
+        }
+
+        $message = sprintf($message, ...$args);
+
+        self::delegateTriggerToBackend($message, $backtrace, $link, $package);
+    }
+
+    /**
+     * @param array<mixed> $backtrace
+     */
+    private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void
+    {
+        if ((self::$type & self::TYPE_PSR_LOGGER) > 0) {
+            $context = [
+                'file' => $backtrace[0]['file'],
+                'line' => $backtrace[0]['line'],
+                'package' => $package,
+                'link' => $link,
+            ];
+
+            self::$logger->notice($message, $context);
+        }
+
+        if (! ((self::$type & self::TYPE_TRIGGER_ERROR) > 0)) {
+            return;
+        }
+
+        $message .= sprintf(
+            ' (%s:%d called by %s:%d, %s, package %s)',
+            self::basename($backtrace[0]['file']),
+            $backtrace[0]['line'],
+            self::basename($backtrace[1]['file']),
+            $backtrace[1]['line'],
+            $link,
+            $package
+        );
+
+        @trigger_error($message, E_USER_DEPRECATED);
+    }
+
+    /**
+     * A non-local-aware version of PHPs basename function.
+     */
+    private static function basename(string $filename): string
+    {
+        $pos = strrpos($filename, DIRECTORY_SEPARATOR);
+
+        if ($pos === false) {
+            return $filename;
+        }
+
+        return substr($filename, $pos + 1);
+    }
+
+    public static function enableTrackingDeprecations(): void
+    {
+        self::$type |= self::TYPE_TRACK_DEPRECATIONS;
+    }
+
+    public static function enableWithTriggerError(): void
+    {
+        self::$type |= self::TYPE_TRIGGER_ERROR;
+    }
+
+    public static function enableWithPsrLogger(LoggerInterface $logger): void
+    {
+        self::$type  |= self::TYPE_PSR_LOGGER;
+        self::$logger = $logger;
+    }
+
+    public static function withoutDeduplication(): void
+    {
+        self::$deduplication = false;
+    }
+
+    public static function disable(): void
+    {
+        self::$type          = self::TYPE_NONE;
+        self::$logger        = null;
+        self::$deduplication = true;
+
+        foreach (self::$ignoredLinks as $link => $count) {
+            self::$ignoredLinks[$link] = 0;
+        }
+    }
+
+    public static function ignorePackage(string $packageName): void
+    {
+        self::$ignoredPackages[$packageName] = true;
+    }
+
+    public static function ignoreDeprecations(string ...$links): void
+    {
+        foreach ($links as $link) {
+            self::$ignoredLinks[$link] = 0;
+        }
+    }
+
+    public static function getUniqueTriggeredDeprecationsCount(): int
+    {
+        return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) {
+            return $carry + $count;
+        }, 0);
+    }
+
+    /**
+     * Returns each triggered deprecation link identifier and the amount of occurrences.
+     *
+     * @return array<string,int>
+     */
+    public static function getTriggeredDeprecations(): array
+    {
+        return self::$ignoredLinks;
+    }
+}

+ 66 - 0
vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php

@@ -0,0 +1,66 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Deprecations\PHPUnit;
+
+use Doctrine\Deprecations\Deprecation;
+
+use function sprintf;
+
+trait VerifyDeprecations
+{
+    /** @var array<string,int> */
+    private $doctrineDeprecationsExpectations = [];
+
+    /** @var array<string,int> */
+    private $doctrineNoDeprecationsExpectations = [];
+
+    public function expectDeprecationWithIdentifier(string $identifier): void
+    {
+        $this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
+    }
+
+    public function expectNoDeprecationWithIdentifier(string $identifier): void
+    {
+        $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
+    }
+
+    /**
+     * @before
+     */
+    public function enableDeprecationTracking(): void
+    {
+        Deprecation::enableTrackingDeprecations();
+    }
+
+    /**
+     * @after
+     */
+    public function verifyDeprecationsAreTriggered(): void
+    {
+        foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) {
+            $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
+
+            $this->assertTrue(
+                $actualCount > $expectation,
+                sprintf(
+                    "Expected deprecation with identifier '%s' was not triggered by code executed in test.",
+                    $identifier
+                )
+            );
+        }
+
+        foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) {
+            $actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
+
+            $this->assertTrue(
+                $actualCount === $expectation,
+                sprintf(
+                    "Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.",
+                    $identifier
+                )
+            );
+        }
+    }
+}

+ 22 - 0
vendor/doctrine/deprecations/phpcs.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<ruleset>
+    <arg name="basepath" value="."/>
+    <arg name="extensions" value="php"/>
+    <arg name="parallel" value="80"/>
+    <arg name="cache" value=".phpcs-cache"/>
+    <arg name="colors"/>
+
+    <!-- Ignore warnings, show progress of the run and show sniff names -->
+    <arg value="nps"/>
+
+    <config name="php_version" value="70100"/>
+
+    <!-- Directories to be checked -->
+    <file>lib</file>
+    <file>tests</file>
+
+    <!-- Include full Doctrine Coding Standard -->
+    <rule ref="Doctrine">
+        <exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint" />
+    </rule>
+</ruleset>

+ 19 - 0
vendor/doctrine/lexer/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2006-2018 Doctrine Project
+
+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.

+ 9 - 0
vendor/doctrine/lexer/README.md

@@ -0,0 +1,9 @@
+# Doctrine Lexer
+
+[![Build Status](https://github.com/doctrine/lexer/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/lexer/actions)
+
+Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
+
+This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL).
+
+https://www.doctrine-project.org/projects/lexer.html

+ 14 - 0
vendor/doctrine/lexer/UPGRADE.md

@@ -0,0 +1,14 @@
+Note about upgrading: Doctrine uses static and runtime mechanisms to raise
+awareness about deprecated code.
+
+- Use of `@deprecated` docblock that is detected by IDEs (like PHPStorm) or
+  Static Analysis tools (like Psalm, phpstan)
+- Use of our low-overhead runtime deprecation API, details:
+  https://github.com/doctrine/deprecations/
+
+# Upgrade to 2.0.0
+
+`AbstractLexer::glimpse()` and `AbstractLexer::peek()` now return
+instances of `Doctrine\Common\Lexer\Token`, which is an array-like class
+Using it as an array is deprecated in favor of using properties of that class.
+Using `count()` on it is deprecated with no replacement.

+ 56 - 0
vendor/doctrine/lexer/composer.json

@@ -0,0 +1,56 @@
+{
+    "name": "doctrine/lexer",
+    "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
+    "license": "MIT",
+    "type": "library",
+    "keywords": [
+        "php",
+        "parser",
+        "lexer",
+        "annotations",
+        "docblock"
+    ],
+    "authors": [
+        {
+            "name": "Guilherme Blanco",
+            "email": "guilhermeblanco@gmail.com"
+        },
+        {
+            "name": "Roman Borschel",
+            "email": "roman@code-factory.org"
+        },
+        {
+            "name": "Johannes Schmitt",
+            "email": "schmittjoh@gmail.com"
+        }
+    ],
+    "homepage": "https://www.doctrine-project.org/projects/lexer.html",
+    "require": {
+        "php": "^7.1 || ^8.0",
+        "doctrine/deprecations": "^1.0"
+    },
+    "require-dev": {
+        "doctrine/coding-standard": "^9 || ^10",
+        "phpstan/phpstan": "^1.3",
+        "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+        "psalm/plugin-phpunit": "^0.18.3",
+        "vimeo/psalm": "^4.11 || ^5.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Doctrine\\Common\\Lexer\\": "src"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Doctrine\\Tests\\Common\\Lexer\\": "tests"
+        }
+    },
+    "config": {
+        "allow-plugins": {
+            "composer/package-versions-deprecated": true,
+            "dealerdirect/phpcodesniffer-composer-installer": true
+        },
+        "sort-packages": true
+    }
+}

+ 346 - 0
vendor/doctrine/lexer/src/AbstractLexer.php

@@ -0,0 +1,346 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Common\Lexer;
+
+use ReflectionClass;
+use UnitEnum;
+
+use function get_class;
+use function implode;
+use function preg_split;
+use function sprintf;
+use function substr;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+use const PREG_SPLIT_NO_EMPTY;
+use const PREG_SPLIT_OFFSET_CAPTURE;
+
+/**
+ * Base class for writing simple lexers, i.e. for creating small DSLs.
+ *
+ * @template T of UnitEnum|string|int
+ * @template V of string|int
+ */
+abstract class AbstractLexer
+{
+    /**
+     * Lexer original input string.
+     *
+     * @var string
+     */
+    private $input;
+
+    /**
+     * Array of scanned tokens.
+     *
+     * @var list<Token<T, V>>
+     */
+    private $tokens = [];
+
+    /**
+     * Current lexer position in input string.
+     *
+     * @var int
+     */
+    private $position = 0;
+
+    /**
+     * Current peek of current lexer position.
+     *
+     * @var int
+     */
+    private $peek = 0;
+
+    /**
+     * The next token in the input.
+     *
+     * @var mixed[]|null
+     * @psalm-var Token<T, V>|null
+     */
+    public $lookahead;
+
+    /**
+     * The last matched/seen token.
+     *
+     * @var mixed[]|null
+     * @psalm-var Token<T, V>|null
+     */
+    public $token;
+
+    /**
+     * Composed regex for input parsing.
+     *
+     * @var string|null
+     */
+    private $regex;
+
+    /**
+     * Sets the input data to be tokenized.
+     *
+     * The Lexer is immediately reset and the new input tokenized.
+     * Any unprocessed tokens from any previous input are lost.
+     *
+     * @param string $input The input to be tokenized.
+     *
+     * @return void
+     */
+    public function setInput($input)
+    {
+        $this->input  = $input;
+        $this->tokens = [];
+
+        $this->reset();
+        $this->scan($input);
+    }
+
+    /**
+     * Resets the lexer.
+     *
+     * @return void
+     */
+    public function reset()
+    {
+        $this->lookahead = null;
+        $this->token     = null;
+        $this->peek      = 0;
+        $this->position  = 0;
+    }
+
+    /**
+     * Resets the peek pointer to 0.
+     *
+     * @return void
+     */
+    public function resetPeek()
+    {
+        $this->peek = 0;
+    }
+
+    /**
+     * Resets the lexer position on the input to the given position.
+     *
+     * @param int $position Position to place the lexical scanner.
+     *
+     * @return void
+     */
+    public function resetPosition($position = 0)
+    {
+        $this->position = $position;
+    }
+
+    /**
+     * Retrieve the original lexer's input until a given position.
+     *
+     * @param int $position
+     *
+     * @return string
+     */
+    public function getInputUntilPosition($position)
+    {
+        return substr($this->input, 0, $position);
+    }
+
+    /**
+     * Checks whether a given token matches the current lookahead.
+     *
+     * @param T $type
+     *
+     * @return bool
+     *
+     * @psalm-assert-if-true !=null $this->lookahead
+     */
+    public function isNextToken($type)
+    {
+        return $this->lookahead !== null && $this->lookahead->isA($type);
+    }
+
+    /**
+     * Checks whether any of the given tokens matches the current lookahead.
+     *
+     * @param list<T> $types
+     *
+     * @return bool
+     *
+     * @psalm-assert-if-true !=null $this->lookahead
+     */
+    public function isNextTokenAny(array $types)
+    {
+        return $this->lookahead !== null && $this->lookahead->isA(...$types);
+    }
+
+    /**
+     * Moves to the next token in the input string.
+     *
+     * @return bool
+     *
+     * @psalm-assert-if-true !null $this->lookahead
+     */
+    public function moveNext()
+    {
+        $this->peek      = 0;
+        $this->token     = $this->lookahead;
+        $this->lookahead = isset($this->tokens[$this->position])
+            ? $this->tokens[$this->position++] : null;
+
+        return $this->lookahead !== null;
+    }
+
+    /**
+     * Tells the lexer to skip input tokens until it sees a token with the given value.
+     *
+     * @param T $type The token type to skip until.
+     *
+     * @return void
+     */
+    public function skipUntil($type)
+    {
+        while ($this->lookahead !== null && ! $this->lookahead->isA($type)) {
+            $this->moveNext();
+        }
+    }
+
+    /**
+     * Checks if given value is identical to the given token.
+     *
+     * @param string     $value
+     * @param int|string $token
+     *
+     * @return bool
+     */
+    public function isA($value, $token)
+    {
+        return $this->getType($value) === $token;
+    }
+
+    /**
+     * Moves the lookahead token forward.
+     *
+     * @return mixed[]|null The next token or NULL if there are no more tokens ahead.
+     * @psalm-return Token<T, V>|null
+     */
+    public function peek()
+    {
+        if (isset($this->tokens[$this->position + $this->peek])) {
+            return $this->tokens[$this->position + $this->peek++];
+        }
+
+        return null;
+    }
+
+    /**
+     * Peeks at the next token, returns it and immediately resets the peek.
+     *
+     * @return mixed[]|null The next token or NULL if there are no more tokens ahead.
+     * @psalm-return Token<T, V>|null
+     */
+    public function glimpse()
+    {
+        $peek       = $this->peek();
+        $this->peek = 0;
+
+        return $peek;
+    }
+
+    /**
+     * Scans the input string for tokens.
+     *
+     * @param string $input A query string.
+     *
+     * @return void
+     */
+    protected function scan($input)
+    {
+        if (! isset($this->regex)) {
+            $this->regex = sprintf(
+                '/(%s)|%s/%s',
+                implode(')|(', $this->getCatchablePatterns()),
+                implode('|', $this->getNonCatchablePatterns()),
+                $this->getModifiers()
+            );
+        }
+
+        $flags   = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
+        $matches = preg_split($this->regex, $input, -1, $flags);
+
+        if ($matches === false) {
+            // Work around https://bugs.php.net/78122
+            $matches = [[$input, 0]];
+        }
+
+        foreach ($matches as $match) {
+            // Must remain before 'value' assignment since it can change content
+            $firstMatch = $match[0];
+            $type       = $this->getType($firstMatch);
+
+            $this->tokens[] = new Token(
+                $firstMatch,
+                $type,
+                $match[1]
+            );
+        }
+    }
+
+    /**
+     * Gets the literal for a given token.
+     *
+     * @param T $token
+     *
+     * @return int|string
+     */
+    public function getLiteral($token)
+    {
+        if ($token instanceof UnitEnum) {
+            return get_class($token) . '::' . $token->name;
+        }
+
+        $className = static::class;
+
+        $reflClass = new ReflectionClass($className);
+        $constants = $reflClass->getConstants();
+
+        foreach ($constants as $name => $value) {
+            if ($value === $token) {
+                return $className . '::' . $name;
+            }
+        }
+
+        return $token;
+    }
+
+    /**
+     * Regex modifiers
+     *
+     * @return string
+     */
+    protected function getModifiers()
+    {
+        return 'iu';
+    }
+
+    /**
+     * Lexical catchable patterns.
+     *
+     * @return string[]
+     */
+    abstract protected function getCatchablePatterns();
+
+    /**
+     * Lexical non-catchable patterns.
+     *
+     * @return string[]
+     */
+    abstract protected function getNonCatchablePatterns();
+
+    /**
+     * Retrieve token type. Also processes the token value if necessary.
+     *
+     * @param string $value
+     *
+     * @return T|null
+     *
+     * @param-out V $value
+     */
+    abstract protected function getType(&$value);
+}

+ 145 - 0
vendor/doctrine/lexer/src/Token.php

@@ -0,0 +1,145 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Common\Lexer;
+
+use ArrayAccess;
+use Doctrine\Deprecations\Deprecation;
+use ReturnTypeWillChange;
+use UnitEnum;
+
+use function in_array;
+
+/**
+ * @template T of UnitEnum|string|int
+ * @template V of string|int
+ * @implements ArrayAccess<string,mixed>
+ */
+final class Token implements ArrayAccess
+{
+    /**
+     * The string value of the token in the input string
+     *
+     * @readonly
+     * @var V
+     */
+    public $value;
+
+    /**
+     * The type of the token (identifier, numeric, string, input parameter, none)
+     *
+     * @readonly
+     * @var T|null
+     */
+    public $type;
+
+    /**
+     * The position of the token in the input string
+     *
+     * @readonly
+     * @var int
+     */
+    public $position;
+
+    /**
+     * @param V      $value
+     * @param T|null $type
+     */
+    public function __construct($value, $type, int $position)
+    {
+        $this->value    = $value;
+        $this->type     = $type;
+        $this->position = $position;
+    }
+
+    /** @param T ...$types */
+    public function isA(...$types): bool
+    {
+        return in_array($this->type, $types, true);
+    }
+
+    /**
+     * @deprecated Use the value, type or position property instead
+     * {@inheritDoc}
+     */
+    public function offsetExists($offset): bool
+    {
+        Deprecation::trigger(
+            'doctrine/lexer',
+            'https://github.com/doctrine/lexer/pull/79',
+            'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead',
+            self::class
+        );
+
+        return in_array($offset, ['value', 'type', 'position'], true);
+    }
+
+    /**
+     * @deprecated Use the value, type or position property instead
+     * {@inheritDoc}
+     *
+     * @param O $offset
+     *
+     * @return mixed
+     * @psalm-return (
+     *     O is 'value'
+     *     ? V
+     *     : (
+     *         O is 'type'
+     *         ? T|null
+     *         : (
+     *             O is 'position'
+     *             ? int
+     *             : mixed
+     *         )
+     *     )
+     * )
+     *
+     * @template O of array-key
+     */
+    #[ReturnTypeWillChange]
+    public function offsetGet($offset)
+    {
+        Deprecation::trigger(
+            'doctrine/lexer',
+            'https://github.com/doctrine/lexer/pull/79',
+            'Accessing %s properties via ArrayAccess is deprecated, use the value, type or position property instead',
+            self::class
+        );
+
+        return $this->$offset;
+    }
+
+    /**
+     * @deprecated no replacement planned
+     * {@inheritDoc}
+     */
+    public function offsetSet($offset, $value): void
+    {
+        Deprecation::trigger(
+            'doctrine/lexer',
+            'https://github.com/doctrine/lexer/pull/79',
+            'Setting %s properties via ArrayAccess is deprecated',
+            self::class
+        );
+
+        $this->$offset = $value;
+    }
+
+    /**
+     * @deprecated no replacement planned
+     * {@inheritDoc}
+     */
+    public function offsetUnset($offset): void
+    {
+        Deprecation::trigger(
+            'doctrine/lexer',
+            'https://github.com/doctrine/lexer/pull/79',
+            'Setting %s properties via ArrayAccess is deprecated',
+            self::class
+        );
+
+        $this->$offset = null;
+    }
+}

+ 10 - 0
vendor/league/flysystem-cached-adapter/.editorconfig

@@ -0,0 +1,10 @@
+; top-most EditorConfig file
+root = true
+
+; Unix-style newlines
+[*]
+end_of_line = LF
+
+[*.php]
+indent_style = space
+indent_size = 4

+ 4 - 0
vendor/league/flysystem-cached-adapter/.gitignore

@@ -0,0 +1,4 @@
+coverage
+coverage.xml
+composer.lock
+vendor

+ 7 - 0
vendor/league/flysystem-cached-adapter/.php_cs

@@ -0,0 +1,7 @@
+<?php
+
+return Symfony\CS\Config\Config::create()
+    ->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
+    ->fixers(['-yoda_conditions', 'ordered_use', 'short_array_syntax'])
+    ->finder(Symfony\CS\Finder\DefaultFinder::create()
+        ->in(__DIR__.'/src/'));

+ 34 - 0
vendor/league/flysystem-cached-adapter/.scrutinizer.yml

@@ -0,0 +1,34 @@
+filter:
+    paths: [src/*]
+checks:
+    php:
+        code_rating: true
+        remove_extra_empty_lines: true
+        remove_php_closing_tag: true
+        remove_trailing_whitespace: true
+        fix_use_statements:
+            remove_unused: true
+            preserve_multiple: false
+            preserve_blanklines: true
+            order_alphabetically: true
+        fix_php_opening_tag: true
+        fix_linefeed: true
+        fix_line_ending: true
+        fix_identation_4spaces: true
+        fix_doc_comments: true
+tools:
+    external_code_coverage:
+        timeout: 900
+        runs: 6
+    php_code_coverage: false
+    php_code_sniffer:
+        config:
+            standard: PSR2
+        filter:
+            paths: ['src']
+    php_loc:
+        enabled: true
+        excluded_dirs: [vendor, spec, stubs]
+    php_cpd:
+        enabled: true
+        excluded_dirs: [vendor, spec, stubs]

+ 29 - 0
vendor/league/flysystem-cached-adapter/.travis.yml

@@ -0,0 +1,29 @@
+language: php
+
+php:
+  - 5.5
+  - 5.6
+  - 7.0
+  - 7.1
+  - 7.2
+
+matrix:
+  allow_failures:
+  - php: 5.5
+
+env:
+  - COMPOSER_OPTS=""
+  - COMPOSER_OPTS="--prefer-lowest"
+
+install:
+  - if [[ "${TRAVIS_PHP_VERSION}" == "5.5" ]]; then composer require phpunit/phpunit:^4.8.36 phpspec/phpspec:^2 --prefer-dist --update-with-dependencies; fi
+  - if [[ "${TRAVIS_PHP_VERSION}" == "7.2" ]]; then composer require phpunit/phpunit:^6.0 --prefer-dist --update-with-dependencies; fi
+  - travis_retry composer update --prefer-dist $COMPOSER_OPTS
+
+script:
+  - vendor/bin/phpspec run
+  - vendor/bin/phpunit
+
+after_script:
+  - wget https://scrutinizer-ci.com/ocular.phar'
+  - php ocular.phar code-coverage:upload --format=php-clover ./clover/phpunit.xml'

+ 19 - 0
vendor/league/flysystem-cached-adapter/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2015 Frank de Jonge
+
+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.

+ 2 - 0
vendor/league/flysystem-cached-adapter/clover/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 30 - 0
vendor/league/flysystem-cached-adapter/composer.json

@@ -0,0 +1,30 @@
+{
+    "name": "league/flysystem-cached-adapter",
+    "description": "An adapter decorator to enable meta-data caching.",
+    "autoload": {
+        "psr-4": {
+            "League\\Flysystem\\Cached\\": "src/"
+        }
+    },
+    "require": {
+        "league/flysystem": "~1.0",
+        "psr/cache": "^1.0.0"
+    },
+    "require-dev": {
+        "phpspec/phpspec": "^3.4",
+        "phpunit/phpunit": "^5.7",
+        "mockery/mockery": "~0.9",
+        "predis/predis": "~1.0",
+        "tedivm/stash": "~0.12"
+    },
+    "suggest": {
+      "ext-phpredis": "Pure C implemented extension for PHP"
+    },
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "frankdejonge",
+            "email": "info@frenky.net"
+        }
+    ]
+}

+ 6 - 0
vendor/league/flysystem-cached-adapter/phpspec.yml

@@ -0,0 +1,6 @@
+---
+suites:
+      cached_adapter_suite:
+        namespace: League\Flysystem\Cached
+        psr4_prefix: League\Flysystem\Cached
+formatter.name: pretty

+ 3 - 0
vendor/league/flysystem-cached-adapter/phpunit.php

@@ -0,0 +1,3 @@
+<?php
+
+include __DIR__.'/vendor/autoload.php';

+ 29 - 0
vendor/league/flysystem-cached-adapter/phpunit.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         bootstrap="./phpunit.php"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnFailure="false"
+         syntaxCheck="true"
+         verbose="true"
+>
+    <testsuites>
+        <testsuite name="flysystem/tests">
+            <directory suffix=".php">./tests/</directory>
+        </testsuite>
+    </testsuites>
+    <filter>
+        <whitelist>
+            <directory suffix=".php">./src/</directory>
+        </whitelist>
+    </filter>
+    <logging>
+        <log type="coverage-text" target="php://stdout" showUncoveredFiles="true"/>
+        <log type="coverage-html" target="coverage" showUncoveredFiles="true"/>
+        <log type="coverage-clover" target="clover/phpunit.xml" showUncoveredFiles="true"/>
+    </logging>
+</phpunit>

+ 20 - 0
vendor/league/flysystem-cached-adapter/readme.md

@@ -0,0 +1,20 @@
+# Flysystem Cached CachedAdapter
+
+[![Author](http://img.shields.io/badge/author-@frankdejonge-blue.svg?style=flat-square)](https://twitter.com/frankdejonge)
+[![Build Status](https://img.shields.io/travis/thephpleague/flysystem-cached-adapter/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/flysystem-cached-adapter)
+[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/flysystem-cached-adapter.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/flysystem-cached-adapter/code-structure)
+[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/flysystem-cached-adapter.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/flysystem-cached-adapter)
+[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
+[![Packagist Version](https://img.shields.io/packagist/v/league/flysystem-cached-adapter.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-cached-adapter)
+[![Total Downloads](https://img.shields.io/packagist/dt/league/flysystem-cached-adapter.svg?style=flat-square)](https://packagist.org/packages/league/flysystem-cached-adapter)
+
+
+The adapter decorator caches metadata and directory listings.
+
+```bash
+composer require league/flysystem-cached-adapter
+```
+
+## Usage
+
+[Check out the docs.](https://flysystem.thephpleague.com/docs/advanced/caching/)

+ 435 - 0
vendor/league/flysystem-cached-adapter/spec/CachedAdapterSpec.php

@@ -0,0 +1,435 @@
+<?php
+
+namespace spec\League\Flysystem\Cached;
+
+use League\Flysystem\AdapterInterface;
+use League\Flysystem\Cached\CacheInterface;
+use League\Flysystem\Config;
+use PhpSpec\ObjectBehavior;
+
+class CachedAdapterSpec extends ObjectBehavior
+{
+    /**
+     * @var AdapterInterface
+     */
+    private $adapter;
+
+    /**
+     * @var CacheInterface
+     */
+    private $cache;
+
+    public function let(AdapterInterface $adapter, CacheInterface $cache)
+    {
+        $this->adapter = $adapter;
+        $this->cache = $cache;
+        $this->cache->load()->shouldBeCalled();
+        $this->beConstructedWith($adapter, $cache);
+    }
+
+    public function it_is_initializable()
+    {
+        $this->shouldHaveType('League\Flysystem\Cached\CachedAdapter');
+        $this->shouldHaveType('League\Flysystem\AdapterInterface');
+    }
+
+    public function it_should_forward_read_streams()
+    {
+        $path = 'path.txt';
+        $response = ['path' => $path];
+        $this->adapter->readStream($path)->willReturn($response);
+        $this->readStream($path)->shouldbe($response);
+    }
+
+    public function it_should_cache_writes()
+    {
+        $type = 'file';
+        $path = 'path.txt';
+        $contents = 'contents';
+        $config = new Config();
+        $response = compact('path', 'contents', 'type');
+        $this->adapter->write($path, $contents, $config)->willReturn($response);
+        $this->cache->updateObject($path, $response, true)->shouldBeCalled();
+        $this->write($path, $contents, $config)->shouldBe($response);
+    }
+
+    public function it_should_cache_streamed_writes()
+    {
+        $type = 'file';
+        $path = 'path.txt';
+        $stream = tmpfile();
+        $config = new Config();
+        $response = compact('path', 'stream', 'type');
+        $this->adapter->writeStream($path, $stream, $config)->willReturn($response);
+        $this->cache->updateObject($path, ['contents' => false] + $response, true)->shouldBeCalled();
+        $this->writeStream($path, $stream, $config)->shouldBe($response);
+        fclose($stream);
+    }
+
+    public function it_should_cache_streamed_updates()
+    {
+        $type = 'file';
+        $path = 'path.txt';
+        $stream = tmpfile();
+        $config = new Config();
+        $response = compact('path', 'stream', 'type');
+        $this->adapter->updateStream($path, $stream, $config)->willReturn($response);
+        $this->cache->updateObject($path, ['contents' => false] + $response, true)->shouldBeCalled();
+        $this->updateStream($path, $stream, $config)->shouldBe($response);
+        fclose($stream);
+    }
+
+    public function it_should_ignore_failed_writes()
+    {
+        $path = 'path.txt';
+        $contents = 'contents';
+        $config = new Config();
+        $this->adapter->write($path, $contents, $config)->willReturn(false);
+        $this->write($path, $contents, $config)->shouldBe(false);
+    }
+
+    public function it_should_ignore_failed_streamed_writes()
+    {
+        $path = 'path.txt';
+        $contents = tmpfile();
+        $config = new Config();
+        $this->adapter->writeStream($path, $contents, $config)->willReturn(false);
+        $this->writeStream($path, $contents, $config)->shouldBe(false);
+        fclose($contents);
+    }
+
+    public function it_should_cache_updated()
+    {
+        $type = 'file';
+        $path = 'path.txt';
+        $contents = 'contents';
+        $config = new Config();
+        $response = compact('path', 'contents', 'type');
+        $this->adapter->update($path, $contents, $config)->willReturn($response);
+        $this->cache->updateObject($path, $response, true)->shouldBeCalled();
+        $this->update($path, $contents, $config)->shouldBe($response);
+    }
+
+    public function it_should_ignore_failed_updates()
+    {
+        $path = 'path.txt';
+        $contents = 'contents';
+        $config = new Config();
+        $this->adapter->update($path, $contents, $config)->willReturn(false);
+        $this->update($path, $contents, $config)->shouldBe(false);
+    }
+
+    public function it_should_ignore_failed_streamed_updates()
+    {
+        $path = 'path.txt';
+        $contents = tmpfile();
+        $config = new Config();
+        $this->adapter->updateStream($path, $contents, $config)->willReturn(false);
+        $this->updateStream($path, $contents, $config)->shouldBe(false);
+        fclose($contents);
+    }
+
+    public function it_should_cache_renames()
+    {
+        $old = 'old.txt';
+        $new = 'new.txt';
+        $this->adapter->rename($old, $new)->willReturn(true);
+        $this->cache->rename($old, $new)->shouldBeCalled();
+        $this->rename($old, $new)->shouldBe(true);
+    }
+
+    public function it_should_ignore_rename_fails()
+    {
+        $old = 'old.txt';
+        $new = 'new.txt';
+        $this->adapter->rename($old, $new)->willReturn(false);
+        $this->rename($old, $new)->shouldBe(false);
+    }
+
+    public function it_should_cache_copies()
+    {
+        $old = 'old.txt';
+        $new = 'new.txt';
+        $this->adapter->copy($old, $new)->willReturn(true);
+        $this->cache->copy($old, $new)->shouldBeCalled();
+        $this->copy($old, $new)->shouldBe(true);
+    }
+
+    public function it_should_ignore_copy_fails()
+    {
+        $old = 'old.txt';
+        $new = 'new.txt';
+        $this->adapter->copy($old, $new)->willReturn(false);
+        $this->copy($old, $new)->shouldBe(false);
+    }
+
+    public function it_should_cache_deletes()
+    {
+        $delete = 'delete.txt';
+        $this->adapter->delete($delete)->willReturn(true);
+        $this->cache->delete($delete)->shouldBeCalled();
+        $this->delete($delete)->shouldBe(true);
+    }
+
+    public function it_should_ignore_delete_fails()
+    {
+        $delete = 'delete.txt';
+        $this->adapter->delete($delete)->willReturn(false);
+        $this->delete($delete)->shouldBe(false);
+    }
+
+    public function it_should_cache_dir_deletes()
+    {
+        $delete = 'delete';
+        $this->adapter->deleteDir($delete)->willReturn(true);
+        $this->cache->deleteDir($delete)->shouldBeCalled();
+        $this->deleteDir($delete)->shouldBe(true);
+    }
+
+    public function it_should_ignore_delete_dir_fails()
+    {
+        $delete = 'delete';
+        $this->adapter->deleteDir($delete)->willReturn(false);
+        $this->deleteDir($delete)->shouldBe(false);
+    }
+
+    public function it_should_cache_dir_creates()
+    {
+        $dirname = 'dirname';
+        $config = new Config();
+        $response = ['path' => $dirname, 'type' => 'dir'];
+        $this->adapter->createDir($dirname, $config)->willReturn($response);
+        $this->cache->updateObject($dirname, $response, true)->shouldBeCalled();
+        $this->createDir($dirname, $config)->shouldBe($response);
+    }
+
+    public function it_should_ignore_create_dir_fails()
+    {
+        $dirname = 'dirname';
+        $config = new Config();
+        $this->adapter->createDir($dirname, $config)->willReturn(false);
+        $this->createDir($dirname, $config)->shouldBe(false);
+    }
+
+    public function it_should_cache_set_visibility()
+    {
+        $path = 'path.txt';
+        $visibility = AdapterInterface::VISIBILITY_PUBLIC;
+        $this->adapter->setVisibility($path, $visibility)->willReturn(true);
+        $this->cache->updateObject($path, ['path' => $path, 'visibility' => $visibility], true)->shouldBeCalled();
+        $this->setVisibility($path, $visibility)->shouldBe(true);
+    }
+
+    public function it_should_ignore_set_visibility_fails()
+    {
+        $dirname = 'delete';
+        $visibility = AdapterInterface::VISIBILITY_PUBLIC;
+        $this->adapter->setVisibility($dirname, $visibility)->willReturn(false);
+        $this->setVisibility($dirname, $visibility)->shouldBe(false);
+    }
+
+    public function it_should_indicate_missing_files()
+    {
+        $this->cache->has($path = 'path.txt')->willReturn(false);
+        $this->has($path)->shouldBe(false);
+    }
+
+    public function it_should_indicate_file_existance()
+    {
+        $this->cache->has($path = 'path.txt')->willReturn(true);
+        $this->has($path)->shouldBe(true);
+    }
+
+    public function it_should_cache_missing_files()
+    {
+        $this->cache->has($path = 'path.txt')->willReturn(null);
+        $this->adapter->has($path)->willReturn(false);
+        $this->cache->storeMiss($path)->shouldBeCalled();
+        $this->has($path)->shouldBe(false);
+    }
+
+    public function it_should_delete_when_metadata_is_missing()
+    {
+        $path = 'path.txt';
+        $this->cache->has($path)->willReturn(true);
+        $this->cache->getSize($path)->willReturn(['path' => $path]);
+        $this->adapter->getSize($path)->willReturn($response = ['path' => $path, 'size' => 1024]);
+        $this->cache->updateObject($path, $response, true)->shouldBeCalled();
+        $this->getSize($path)->shouldBe($response);
+    }
+
+    public function it_should_cache_has()
+    {
+        $this->cache->has($path = 'path.txt')->willReturn(null);
+        $this->adapter->has($path)->willReturn(true);
+        $this->cache->updateObject($path, compact('path'), true)->shouldBeCalled();
+        $this->has($path)->shouldBe(true);
+    }
+
+    public function it_should_list_cached_contents()
+    {
+        $this->cache->isComplete($dirname = 'dirname', $recursive = true)->willReturn(true);
+        $response = [['path' => 'path.txt']];
+        $this->cache->listContents($dirname, $recursive)->willReturn($response);
+        $this->listContents($dirname, $recursive)->shouldBe($response);
+    }
+
+    public function it_should_ignore_failed_list_contents()
+    {
+        $this->cache->isComplete($dirname = 'dirname', $recursive = true)->willReturn(false);
+        $this->adapter->listContents($dirname, $recursive)->willReturn(false);
+        $this->listContents($dirname, $recursive)->shouldBe(false);
+    }
+
+    public function it_should_cache_contents_listings()
+    {
+        $this->cache->isComplete($dirname = 'dirname', $recursive = true)->willReturn(false);
+        $response = [['path' => 'path.txt']];
+        $this->adapter->listContents($dirname, $recursive)->willReturn($response);
+        $this->cache->storeContents($dirname, $response, $recursive)->shouldBeCalled();
+        $this->listContents($dirname, $recursive)->shouldBe($response);
+    }
+
+    public function it_should_use_cached_visibility()
+    {
+        $this->make_it_use_getter_cache('getVisibility', 'path.txt', [
+            'path' => 'path.txt',
+            'visibility' => AdapterInterface::VISIBILITY_PUBLIC,
+        ]);
+    }
+
+    public function it_should_cache_get_visibility()
+    {
+        $path = 'path.txt';
+        $response = ['visibility' => AdapterInterface::VISIBILITY_PUBLIC, 'path' => $path];
+        $this->make_it_cache_getter('getVisibility', $path, $response);
+    }
+
+    public function it_should_ignore_failed_get_visibility()
+    {
+        $path = 'path.txt';
+        $this->make_it_ignore_failed_getter('getVisibility', $path);
+    }
+
+    public function it_should_use_cached_timestamp()
+    {
+        $this->make_it_use_getter_cache('getTimestamp', 'path.txt', [
+            'path' => 'path.txt',
+            'timestamp' => 1234,
+        ]);
+    }
+
+    public function it_should_cache_timestamps()
+    {
+        $this->make_it_cache_getter('getTimestamp', 'path.txt', [
+            'path' => 'path.txt',
+            'timestamp' => 1234,
+        ]);
+    }
+
+    public function it_should_ignore_failed_get_timestamps()
+    {
+        $this->make_it_ignore_failed_getter('getTimestamp', 'path.txt');
+    }
+
+    public function it_should_cache_get_metadata()
+    {
+        $path = 'path.txt';
+        $response = ['visibility' => AdapterInterface::VISIBILITY_PUBLIC, 'path' => $path];
+        $this->make_it_cache_getter('getMetadata', $path, $response);
+    }
+
+    public function it_should_use_cached_metadata()
+    {
+        $this->make_it_use_getter_cache('getMetadata', 'path.txt', [
+            'path' => 'path.txt',
+            'timestamp' => 1234,
+        ]);
+    }
+
+    public function it_should_ignore_failed_get_metadata()
+    {
+        $this->make_it_ignore_failed_getter('getMetadata', 'path.txt');
+    }
+
+    public function it_should_cache_get_size()
+    {
+        $path = 'path.txt';
+        $response = ['size' => 1234, 'path' => $path];
+        $this->make_it_cache_getter('getSize', $path, $response);
+    }
+
+    public function it_should_use_cached_size()
+    {
+        $this->make_it_use_getter_cache('getSize', 'path.txt', [
+            'path' => 'path.txt',
+            'size' => 1234,
+        ]);
+    }
+
+    public function it_should_ignore_failed_get_size()
+    {
+        $this->make_it_ignore_failed_getter('getSize', 'path.txt');
+    }
+
+    public function it_should_cache_get_mimetype()
+    {
+        $path = 'path.txt';
+        $response = ['mimetype' => 'text/plain', 'path' => $path];
+        $this->make_it_cache_getter('getMimetype', $path, $response);
+    }
+
+    public function it_should_use_cached_mimetype()
+    {
+        $this->make_it_use_getter_cache('getMimetype', 'path.txt', [
+            'path' => 'path.txt',
+            'mimetype' => 'text/plain',
+        ]);
+    }
+
+    public function it_should_ignore_failed_get_mimetype()
+    {
+        $this->make_it_ignore_failed_getter('getMimetype', 'path.txt');
+    }
+
+    public function it_should_cache_reads()
+    {
+        $path = 'path.txt';
+        $response = ['path' => $path, 'contents' => 'contents'];
+        $this->make_it_cache_getter('read', $path, $response);
+    }
+
+    public function it_should_use_cached_file_contents()
+    {
+        $this->make_it_use_getter_cache('read', 'path.txt', [
+            'path' => 'path.txt',
+            'contents' => 'contents'
+        ]);
+    }
+
+    public function it_should_ignore_failed_reads()
+    {
+        $this->make_it_ignore_failed_getter('read', 'path.txt');
+    }
+
+    protected function make_it_use_getter_cache($method, $path, $response)
+    {
+        $this->cache->{$method}($path)->willReturn($response);
+        $this->{$method}($path)->shouldBe($response);
+    }
+
+    protected function make_it_cache_getter($method, $path, $response)
+    {
+        $this->cache->{$method}($path)->willReturn(false);
+        $this->adapter->{$method}($path)->willReturn($response);
+        $this->cache->updateObject($path, $response, true)->shouldBeCalled();
+        $this->{$method}($path)->shouldBe($response);
+    }
+
+    protected function make_it_ignore_failed_getter($method, $path)
+    {
+        $this->cache->{$method}($path)->willReturn(false);
+        $this->adapter->{$method}($path)->willReturn(false);
+        $this->{$method}($path)->shouldBe(false);
+    }
+}

+ 101 - 0
vendor/league/flysystem-cached-adapter/src/CacheInterface.php

@@ -0,0 +1,101 @@
+<?php
+
+namespace League\Flysystem\Cached;
+
+use League\Flysystem\ReadInterface;
+
+interface CacheInterface extends ReadInterface
+{
+    /**
+     * Check whether the directory listing of a given directory is complete.
+     *
+     * @param string $dirname
+     * @param bool   $recursive
+     *
+     * @return bool
+     */
+    public function isComplete($dirname, $recursive);
+
+    /**
+     * Set a directory to completely listed.
+     *
+     * @param string $dirname
+     * @param bool   $recursive
+     */
+    public function setComplete($dirname, $recursive);
+
+    /**
+     * Store the contents of a directory.
+     *
+     * @param string $directory
+     * @param array  $contents
+     * @param bool   $recursive
+     */
+    public function storeContents($directory, array $contents, $recursive);
+
+    /**
+     * Flush the cache.
+     */
+    public function flush();
+
+    /**
+     * Autosave trigger.
+     */
+    public function autosave();
+
+    /**
+     * Store the cache.
+     */
+    public function save();
+
+    /**
+     * Load the cache.
+     */
+    public function load();
+
+    /**
+     * Rename a file.
+     *
+     * @param string $path
+     * @param string $newpath
+     */
+    public function rename($path, $newpath);
+
+    /**
+     * Copy a file.
+     *
+     * @param string $path
+     * @param string $newpath
+     */
+    public function copy($path, $newpath);
+
+    /**
+     * Delete an object from cache.
+     *
+     * @param string $path object path
+     */
+    public function delete($path);
+
+    /**
+     * Delete all objects from from a directory.
+     *
+     * @param string $dirname directory path
+     */
+    public function deleteDir($dirname);
+
+    /**
+     * Update the metadata for an object.
+     *
+     * @param string $path     object path
+     * @param array  $object   object metadata
+     * @param bool   $autosave whether to trigger the autosave routine
+     */
+    public function updateObject($path, array $object, $autosave = false);
+
+    /**
+     * Store object hit miss.
+     *
+     * @param string $path
+     */
+    public function storeMiss($path);
+}

+ 346 - 0
vendor/league/flysystem-cached-adapter/src/CachedAdapter.php

@@ -0,0 +1,346 @@
+<?php
+
+namespace League\Flysystem\Cached;
+
+use League\Flysystem\AdapterInterface;
+use League\Flysystem\Config;
+
+class CachedAdapter implements AdapterInterface
+{
+    /**
+     * @var AdapterInterface
+     */
+    private $adapter;
+
+    /**
+     * @var CacheInterface
+     */
+    private $cache;
+
+    /**
+     * Constructor.
+     *
+     * @param AdapterInterface $adapter
+     * @param CacheInterface   $cache
+     */
+    public function __construct(AdapterInterface $adapter, CacheInterface $cache)
+    {
+        $this->adapter = $adapter;
+        $this->cache = $cache;
+        $this->cache->load();
+    }
+
+    /**
+     * Get the underlying Adapter implementation.
+     *
+     * @return AdapterInterface
+     */
+    public function getAdapter()
+    {
+        return $this->adapter;
+    }
+
+    /**
+     * Get the used Cache implementation.
+     *
+     * @return CacheInterface
+     */
+    public function getCache()
+    {
+        return $this->cache;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function write($path, $contents, Config $config)
+    {
+        $result = $this->adapter->write($path, $contents, $config);
+
+        if ($result !== false) {
+            $result['type'] = 'file';
+            $this->cache->updateObject($path, $result + compact('path', 'contents'), true);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function writeStream($path, $resource, Config $config)
+    {
+        $result = $this->adapter->writeStream($path, $resource, $config);
+
+        if ($result !== false) {
+            $result['type'] = 'file';
+            $contents = false;
+            $this->cache->updateObject($path, $result + compact('path', 'contents'), true);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function update($path, $contents, Config $config)
+    {
+        $result = $this->adapter->update($path, $contents, $config);
+
+        if ($result !== false) {
+            $result['type'] = 'file';
+            $this->cache->updateObject($path, $result + compact('path', 'contents'), true);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function updateStream($path, $resource, Config $config)
+    {
+        $result = $this->adapter->updateStream($path, $resource, $config);
+
+        if ($result !== false) {
+            $result['type'] = 'file';
+            $contents = false;
+            $this->cache->updateObject($path, $result + compact('path', 'contents'), true);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rename($path, $newPath)
+    {
+        $result = $this->adapter->rename($path, $newPath);
+
+        if ($result !== false) {
+            $this->cache->rename($path, $newPath);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function copy($path, $newpath)
+    {
+        $result = $this->adapter->copy($path, $newpath);
+
+        if ($result !== false) {
+            $this->cache->copy($path, $newpath);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete($path)
+    {
+        $result = $this->adapter->delete($path);
+
+        if ($result !== false) {
+            $this->cache->delete($path);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteDir($dirname)
+    {
+        $result = $this->adapter->deleteDir($dirname);
+
+        if ($result !== false) {
+            $this->cache->deleteDir($dirname);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function createDir($dirname, Config $config)
+    {
+        $result = $this->adapter->createDir($dirname, $config);
+
+        if ($result !== false) {
+            $type = 'dir';
+            $path = $dirname;
+            $this->cache->updateObject($dirname, compact('path', 'type'), true);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setVisibility($path, $visibility)
+    {
+        $result = $this->adapter->setVisibility($path, $visibility);
+
+        if ($result !== false) {
+            $this->cache->updateObject($path, compact('path', 'visibility'), true);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function has($path)
+    {
+        $cacheHas = $this->cache->has($path);
+
+        if ($cacheHas !== null) {
+            return $cacheHas;
+        }
+
+        $adapterResponse = $this->adapter->has($path);
+
+        if (! $adapterResponse) {
+            $this->cache->storeMiss($path);
+        } else {
+            $cacheEntry = is_array($adapterResponse) ? $adapterResponse : compact('path');
+            $this->cache->updateObject($path, $cacheEntry, true);
+        }
+
+        return $adapterResponse;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function read($path)
+    {
+        return $this->callWithFallback('contents', $path, 'read');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function readStream($path)
+    {
+        return $this->adapter->readStream($path);
+    }
+
+    /**
+     * Get the path prefix.
+     *
+     * @return string|null path prefix or null if pathPrefix is empty
+     */
+    public function getPathPrefix()
+    {
+        return $this->adapter->getPathPrefix();
+    }
+
+    /**
+     * Prefix a path.
+     *
+     * @param string $path
+     *
+     * @return string prefixed path
+     */
+    public function applyPathPrefix($path)
+    {
+        return $this->adapter->applyPathPrefix($path);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function listContents($directory = '', $recursive = false)
+    {
+        if ($this->cache->isComplete($directory, $recursive)) {
+            return $this->cache->listContents($directory, $recursive);
+        }
+
+        $result = $this->adapter->listContents($directory, $recursive);
+
+        if ($result !== false) {
+            $this->cache->storeContents($directory, $result, $recursive);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMetadata($path)
+    {
+        return $this->callWithFallback(null, $path, 'getMetadata');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSize($path)
+    {
+        return $this->callWithFallback('size', $path, 'getSize');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimetype($path)
+    {
+        return $this->callWithFallback('mimetype', $path, 'getMimetype');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTimestamp($path)
+    {
+        return $this->callWithFallback('timestamp', $path, 'getTimestamp');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getVisibility($path)
+    {
+        return $this->callWithFallback('visibility', $path, 'getVisibility');
+    }
+
+    /**
+     * Call a method and cache the response.
+     *
+     * @param string $property
+     * @param string $path
+     * @param string $method
+     *
+     * @return mixed
+     */
+    protected function callWithFallback($property, $path, $method)
+    {
+        $result = $this->cache->{$method}($path);
+
+        if ($result !== false && ($property === null || array_key_exists($property, $result))) {
+            return $result;
+        }
+
+        $result = $this->adapter->{$method}($path);
+
+        if ($result) {
+            $object = $result + compact('path');
+            $this->cache->updateObject($path, $object, true);
+        }
+
+        return $result;
+    }
+}

+ 418 - 0
vendor/league/flysystem-cached-adapter/src/Storage/AbstractCache.php

@@ -0,0 +1,418 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+use League\Flysystem\Cached\CacheInterface;
+use League\Flysystem\Util;
+
+abstract class AbstractCache implements CacheInterface
+{
+    /**
+     * @var bool
+     */
+    protected $autosave = true;
+
+    /**
+     * @var array
+     */
+    protected $cache = [];
+
+    /**
+     * @var array
+     */
+    protected $complete = [];
+
+    /**
+     * Destructor.
+     */
+    public function __destruct()
+    {
+        if (! $this->autosave) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Get the autosave setting.
+     *
+     * @return bool autosave
+     */
+    public function getAutosave()
+    {
+        return $this->autosave;
+    }
+
+    /**
+     * Get the autosave setting.
+     *
+     * @param bool $autosave
+     */
+    public function setAutosave($autosave)
+    {
+        $this->autosave = $autosave;
+    }
+
+    /**
+     * Store the contents listing.
+     *
+     * @param string $directory
+     * @param array  $contents
+     * @param bool   $recursive
+     *
+     * @return array contents listing
+     */
+    public function storeContents($directory, array $contents, $recursive = false)
+    {
+        $directories = [$directory];
+
+        foreach ($contents as $object) {
+            $this->updateObject($object['path'], $object);
+            $object = $this->cache[$object['path']];
+
+            if ($recursive && $this->pathIsInDirectory($directory, $object['path'])) {
+                $directories[] = $object['dirname'];
+            }
+        }
+
+        foreach (array_unique($directories) as $directory) {
+            $this->setComplete($directory, $recursive);
+        }
+
+        $this->autosave();
+    }
+
+    /**
+     * Update the metadata for an object.
+     *
+     * @param string $path     object path
+     * @param array  $object   object metadata
+     * @param bool   $autosave whether to trigger the autosave routine
+     */
+    public function updateObject($path, array $object, $autosave = false)
+    {
+        if (! $this->has($path)) {
+            $this->cache[$path] = Util::pathinfo($path);
+        }
+
+        $this->cache[$path] = array_merge($this->cache[$path], $object);
+
+        if ($autosave) {
+            $this->autosave();
+        }
+
+        $this->ensureParentDirectories($path);
+    }
+
+    /**
+     * Store object hit miss.
+     *
+     * @param string $path
+     */
+    public function storeMiss($path)
+    {
+        $this->cache[$path] = false;
+        $this->autosave();
+    }
+
+    /**
+     * Get the contents listing.
+     *
+     * @param string $dirname
+     * @param bool   $recursive
+     *
+     * @return array contents listing
+     */
+    public function listContents($dirname = '', $recursive = false)
+    {
+        $result = [];
+
+        foreach ($this->cache as $object) {
+            if ($object === false) {
+                continue;
+            }
+            if ($object['dirname'] === $dirname) {
+                $result[] = $object;
+            } elseif ($recursive && $this->pathIsInDirectory($dirname, $object['path'])) {
+                $result[] = $object;
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function has($path)
+    {
+        if ($path !== false && array_key_exists($path, $this->cache)) {
+            return $this->cache[$path] !== false;
+        }
+
+        if ($this->isComplete(Util::dirname($path), false)) {
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function read($path)
+    {
+        if (isset($this->cache[$path]['contents']) && $this->cache[$path]['contents'] !== false) {
+            return $this->cache[$path];
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function readStream($path)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rename($path, $newpath)
+    {
+        if ($this->has($path)) {
+            $object = $this->cache[$path];
+            unset($this->cache[$path]);
+            $object['path'] = $newpath;
+            $object = array_merge($object, Util::pathinfo($newpath));
+            $this->cache[$newpath] = $object;
+            $this->autosave();
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function copy($path, $newpath)
+    {
+        if ($this->has($path)) {
+            $object = $this->cache[$path];
+            $object = array_merge($object, Util::pathinfo($newpath));
+            $this->updateObject($newpath, $object, true);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete($path)
+    {
+        $this->storeMiss($path);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteDir($dirname)
+    {
+        foreach ($this->cache as $path => $object) {
+            if ($this->pathIsInDirectory($dirname, $path) || $path === $dirname) {
+                unset($this->cache[$path]);
+            }
+        }
+
+        unset($this->complete[$dirname]);
+
+        $this->autosave();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimetype($path)
+    {
+        if (isset($this->cache[$path]['mimetype'])) {
+            return $this->cache[$path];
+        }
+
+        if (! $result = $this->read($path)) {
+            return false;
+        }
+
+        $mimetype = Util::guessMimeType($path, $result['contents']);
+        $this->cache[$path]['mimetype'] = $mimetype;
+
+        return $this->cache[$path];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSize($path)
+    {
+        if (isset($this->cache[$path]['size'])) {
+            return $this->cache[$path];
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTimestamp($path)
+    {
+        if (isset($this->cache[$path]['timestamp'])) {
+            return $this->cache[$path];
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getVisibility($path)
+    {
+        if (isset($this->cache[$path]['visibility'])) {
+            return $this->cache[$path];
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMetadata($path)
+    {
+        if (isset($this->cache[$path]['type'])) {
+            return $this->cache[$path];
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isComplete($dirname, $recursive)
+    {
+        if (! array_key_exists($dirname, $this->complete)) {
+            return false;
+        }
+
+        if ($recursive && $this->complete[$dirname] !== 'recursive') {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setComplete($dirname, $recursive)
+    {
+        $this->complete[$dirname] = $recursive ? 'recursive' : true;
+    }
+
+    /**
+     * Filter the contents from a listing.
+     *
+     * @param array $contents object listing
+     *
+     * @return array filtered contents
+     */
+    public function cleanContents(array $contents)
+    {
+        $cachedProperties = array_flip([
+            'path', 'dirname', 'basename', 'extension', 'filename',
+            'size', 'mimetype', 'visibility', 'timestamp', 'type',
+            'md5',
+        ]);
+
+        foreach ($contents as $path => $object) {
+            if (is_array($object)) {
+                $contents[$path] = array_intersect_key($object, $cachedProperties);
+            }
+        }
+
+        return $contents;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function flush()
+    {
+        $this->cache = [];
+        $this->complete = [];
+        $this->autosave();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function autosave()
+    {
+        if ($this->autosave) {
+            $this->save();
+        }
+    }
+
+    /**
+     * Retrieve serialized cache data.
+     *
+     * @return string serialized data
+     */
+    public function getForStorage()
+    {
+        $cleaned = $this->cleanContents($this->cache);
+
+        return json_encode([$cleaned, $this->complete]);
+    }
+
+    /**
+     * Load from serialized cache data.
+     *
+     * @param string $json
+     */
+    public function setFromStorage($json)
+    {
+        list($cache, $complete) = json_decode($json, true);
+
+        if (json_last_error() === JSON_ERROR_NONE && is_array($cache) && is_array($complete)) {
+            $this->cache = $cache;
+            $this->complete = $complete;
+        }
+    }
+
+    /**
+     * Ensure parent directories of an object.
+     *
+     * @param string $path object path
+     */
+    public function ensureParentDirectories($path)
+    {
+        $object = $this->cache[$path];
+
+        while ($object['dirname'] !== '' && ! isset($this->cache[$object['dirname']])) {
+            $object = Util::pathinfo($object['dirname']);
+            $object['type'] = 'dir';
+            $this->cache[$object['path']] = $object;
+        }
+    }
+
+    /**
+     * Determines if the path is inside the directory.
+     *
+     * @param string $directory
+     * @param string $path
+     *
+     * @return bool
+     */
+    protected function pathIsInDirectory($directory, $path)
+    {
+        return $directory === '' || strpos($path, $directory . '/') === 0;
+    }
+}

+ 115 - 0
vendor/league/flysystem-cached-adapter/src/Storage/Adapter.php

@@ -0,0 +1,115 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+use League\Flysystem\AdapterInterface;
+use League\Flysystem\Config;
+
+class Adapter extends AbstractCache
+{
+    /**
+     * @var AdapterInterface An adapter
+     */
+    protected $adapter;
+
+    /**
+     * @var string the file to cache to
+     */
+    protected $file;
+
+    /**
+     * @var int|null seconds until cache expiration
+     */
+    protected $expire = null;
+
+    /**
+     * Constructor.
+     *
+     * @param AdapterInterface $adapter adapter
+     * @param string           $file    the file to cache to
+     * @param int|null         $expire  seconds until cache expiration
+     */
+    public function __construct(AdapterInterface $adapter, $file, $expire = null)
+    {
+        $this->adapter = $adapter;
+        $this->file = $file;
+        $this->setExpire($expire);
+    }
+
+    /**
+     * Set the expiration time in seconds.
+     *
+     * @param int $expire relative expiration time
+     */
+    protected function setExpire($expire)
+    {
+        if ($expire) {
+            $this->expire = $this->getTime($expire);
+        }
+    }
+
+    /**
+     * Get expiration time in seconds.
+     *
+     * @param int $time relative expiration time
+     *
+     * @return int actual expiration time
+     */
+    protected function getTime($time = 0)
+    {
+        return intval(microtime(true)) + $time;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setFromStorage($json)
+    {
+        list($cache, $complete, $expire) = json_decode($json, true);
+
+        if (! $expire || $expire > $this->getTime()) {
+            $this->cache = is_array($cache) ? $cache : [];
+            $this->complete = is_array($complete) ? $complete : [];
+        } else {
+            $this->adapter->delete($this->file);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        if ($this->adapter->has($this->file)) {
+            $file = $this->adapter->read($this->file);
+            if ($file && !empty($file['contents'])) {
+                $this->setFromStorage($file['contents']);
+            }
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getForStorage()
+    {
+        $cleaned = $this->cleanContents($this->cache);
+
+        return json_encode([$cleaned, $this->complete, $this->expire]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        $config = new Config();
+        $contents = $this->getForStorage();
+
+        if ($this->adapter->has($this->file)) {
+            $this->adapter->update($this->file, $contents, $config);
+        } else {
+            $this->adapter->write($this->file, $contents, $config);
+        }
+    }
+}

+ 59 - 0
vendor/league/flysystem-cached-adapter/src/Storage/Memcached.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+use Memcached as NativeMemcached;
+
+class Memcached extends AbstractCache
+{
+    /**
+     * @var string storage key
+     */
+    protected $key;
+
+    /**
+     * @var int|null seconds until cache expiration
+     */
+    protected $expire;
+
+    /**
+     * @var \Memcached Memcached instance
+     */
+    protected $memcached;
+
+    /**
+     * Constructor.
+     *
+     * @param \Memcached $memcached
+     * @param string     $key       storage key
+     * @param int|null   $expire    seconds until cache expiration
+     */
+    public function __construct(NativeMemcached $memcached, $key = 'flysystem', $expire = null)
+    {
+        $this->key = $key;
+        $this->expire = $expire;
+        $this->memcached = $memcached;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        $contents = $this->memcached->get($this->key);
+
+        if ($contents !== false) {
+            $this->setFromStorage($contents);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        $contents = $this->getForStorage();
+        $expiration = $this->expire === null ? 0 : time() + $this->expire;
+        $this->memcached->set($this->key, $contents, $expiration);
+    }
+}

+ 22 - 0
vendor/league/flysystem-cached-adapter/src/Storage/Memory.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+class Memory extends AbstractCache
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        // There is nothing to save
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        // There is nothing to load
+    }
+}

+ 171 - 0
vendor/league/flysystem-cached-adapter/src/Storage/Noop.php

@@ -0,0 +1,171 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+class Noop extends AbstractCache
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected $autosave = false;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function updateObject($path, array $object, $autosave = false)
+    {
+        return $object;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isComplete($dirname, $recursive)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setComplete($dirname, $recursive)
+    {
+        //
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function copy($path, $newpath)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rename($path, $newpath)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function storeContents($directory, array $contents, $recursive = false)
+    {
+        return $contents;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function storeMiss($path)
+    {
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function flush()
+    {
+        //
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function autosave()
+    {
+        //
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        //
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        //
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function has($path)
+    {
+        return;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function read($path)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function readStream($path)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function listContents($directory = '', $recursive = false)
+    {
+        return [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMetadata($path)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSize($path)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getMimetype($path)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getTimestamp($path)
+    {
+        return false;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getVisibility($path)
+    {
+        return false;
+    }
+}

+ 62 - 0
vendor/league/flysystem-cached-adapter/src/Storage/PhpRedis.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+use Redis;
+
+class PhpRedis extends AbstractCache
+{
+    /**
+     * @var Redis PhpRedis Client
+     */
+    protected $client;
+
+    /**
+     * @var string storage key
+     */
+    protected $key;
+
+    /**
+     * @var int|null seconds until cache expiration
+     */
+    protected $expire;
+
+    /**
+     * Constructor.
+     *
+     * @param Redis|null $client phpredis client
+     * @param string     $key    storage key
+     * @param int|null   $expire seconds until cache expiration
+     */
+    public function __construct(Redis $client = null, $key = 'flysystem', $expire = null)
+    {
+        $this->client = $client ?: new Redis();
+        $this->key = $key;
+        $this->expire = $expire;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        $contents = $this->client->get($this->key);
+
+        if ($contents !== false) {
+            $this->setFromStorage($contents);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        $contents = $this->getForStorage();
+        $this->client->set($this->key, $contents);
+
+        if ($this->expire !== null) {
+            $this->client->expire($this->key, $this->expire);
+        }
+    }
+}

+ 75 - 0
vendor/league/flysystem-cached-adapter/src/Storage/Predis.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+use Predis\Client;
+
+class Predis extends AbstractCache
+{
+    /**
+     * @var \Predis\Client Predis Client
+     */
+    protected $client;
+
+    /**
+     * @var string storage key
+     */
+    protected $key;
+
+    /**
+     * @var int|null seconds until cache expiration
+     */
+    protected $expire;
+
+    /**
+     * Constructor.
+     *
+     * @param \Predis\Client $client predis client
+     * @param string         $key    storage key
+     * @param int|null       $expire seconds until cache expiration
+     */
+    public function __construct(Client $client = null, $key = 'flysystem', $expire = null)
+    {
+        $this->client = $client ?: new Client();
+        $this->key = $key;
+        $this->expire = $expire;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        if (($contents = $this->executeCommand('get', [$this->key])) !== null) {
+            $this->setFromStorage($contents);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        $contents = $this->getForStorage();
+        $this->executeCommand('set', [$this->key, $contents]);
+
+        if ($this->expire !== null) {
+            $this->executeCommand('expire', [$this->key, $this->expire]);
+        }
+    }
+
+    /**
+     * Execute a Predis command.
+     *
+     * @param string $name
+     * @param array  $arguments
+     *
+     * @return string
+     */
+    protected function executeCommand($name, array $arguments)
+    {
+        $command = $this->client->createCommand($name, $arguments);
+
+        return $this->client->executeCommand($command);
+    }
+}

+ 59 - 0
vendor/league/flysystem-cached-adapter/src/Storage/Psr6Cache.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+use Psr\Cache\CacheItemPoolInterface;
+
+class Psr6Cache extends AbstractCache
+{
+    /**
+     * @var CacheItemPoolInterface
+     */
+    private $pool;
+
+    /**
+     * @var string storage key
+     */
+    protected $key;
+
+    /**
+     * @var int|null seconds until cache expiration
+     */
+    protected $expire;
+
+    /**
+     * Constructor.
+     *
+     * @param CacheItemPoolInterface $pool
+     * @param string                 $key    storage key
+     * @param int|null               $expire seconds until cache expiration
+     */
+    public function __construct(CacheItemPoolInterface $pool, $key = 'flysystem', $expire = null)
+    {
+        $this->pool = $pool;
+        $this->key = $key;
+        $this->expire = $expire;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        $item = $this->pool->getItem($this->key);
+        $item->set($this->getForStorage());
+        $item->expiresAfter($this->expire);
+        $this->pool->save($item);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        $item = $this->pool->getItem($this->key);
+        if ($item->isHit()) {
+            $this->setFromStorage($item->get());
+        }
+    }
+}

+ 60 - 0
vendor/league/flysystem-cached-adapter/src/Storage/Stash.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace League\Flysystem\Cached\Storage;
+
+use Stash\Pool;
+
+class Stash extends AbstractCache
+{
+    /**
+     * @var string storage key
+     */
+    protected $key;
+
+    /**
+     * @var int|null seconds until cache expiration
+     */
+    protected $expire;
+
+    /**
+     * @var \Stash\Pool Stash pool instance
+     */
+    protected $pool;
+
+    /**
+     * Constructor.
+     *
+     * @param \Stash\Pool $pool
+     * @param string      $key    storage key
+     * @param int|null    $expire seconds until cache expiration
+     */
+    public function __construct(Pool $pool, $key = 'flysystem', $expire = null)
+    {
+        $this->key = $key;
+        $this->expire = $expire;
+        $this->pool = $pool;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function load()
+    {
+        $item = $this->pool->getItem($this->key);
+        $contents = $item->get();
+
+        if ($item->isMiss() === false) {
+            $this->setFromStorage($contents);
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save()
+    {
+        $contents = $this->getForStorage();
+        $item = $this->pool->getItem($this->key);
+        $item->set($contents, $this->expire);
+    }
+}

+ 104 - 0
vendor/league/flysystem-cached-adapter/tests/AdapterCacheTests.php

@@ -0,0 +1,104 @@
+<?php
+
+use League\Flysystem\Cached\Storage\Adapter;
+use PHPUnit\Framework\TestCase;
+
+class AdapterCacheTests extends TestCase
+{
+    public function testLoadFail()
+    {
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(false);
+        $cache = new Adapter($adapter, 'file.json', 10);
+        $cache->load();
+        $this->assertFalse($cache->isComplete('', false));
+    }
+
+    public function testLoadExpired()
+    {
+        $response = ['contents' => json_encode([[], ['' => true], 1234567890]), 'path' => 'file.json'];
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(true);
+        $adapter->shouldReceive('read')->once()->with('file.json')->andReturn($response);
+        $adapter->shouldReceive('delete')->once()->with('file.json');
+        $cache = new Adapter($adapter, 'file.json', 10);
+        $cache->load();
+        $this->assertFalse($cache->isComplete('', false));
+    }
+
+    public function testLoadSuccess()
+    {
+        $response = ['contents' => json_encode([[], ['' => true], 9876543210]), 'path' => 'file.json'];
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(true);
+        $adapter->shouldReceive('read')->once()->with('file.json')->andReturn($response);
+        $cache = new Adapter($adapter, 'file.json', 10);
+        $cache->load();
+        $this->assertTrue($cache->isComplete('', false));
+    }
+
+    public function testSaveExists()
+    {
+        $response = json_encode([[], [], null]);
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(true);
+        $adapter->shouldReceive('update')->once()->with('file.json', $response, Mockery::any());
+        $cache = new Adapter($adapter, 'file.json', null);
+        $cache->save();
+    }
+
+    public function testSaveNew()
+    {
+        $response = json_encode([[], [], null]);
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(false);
+        $adapter->shouldReceive('write')->once()->with('file.json', $response, Mockery::any());
+        $cache = new Adapter($adapter, 'file.json', null);
+        $cache->save();
+    }
+
+    public function testStoreContentsRecursive()
+    {
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $adapter->shouldReceive('has')->once()->with('file.json')->andReturn(false);
+        $adapter->shouldReceive('write')->once()->with('file.json', Mockery::any(), Mockery::any());
+
+        $cache = new Adapter($adapter, 'file.json', null);
+
+        $contents = [
+            ['path' => 'foo/bar', 'dirname' => 'foo'],
+            ['path' => 'afoo/bang', 'dirname' => 'afoo'],
+        ];
+
+        $cache->storeContents('foo', $contents, true);
+
+        $this->assertTrue($cache->isComplete('foo', true));
+        $this->assertFalse($cache->isComplete('afoo', true));
+    }
+
+    public function testDeleteDir()
+    {
+        $cache_data = [
+            'foo' => ['path' => 'foo', 'type' => 'dir', 'dirname' => ''],
+            'foo/bar' => ['path' => 'foo/bar', 'type' => 'file', 'dirname' => 'foo'],
+            'foobaz' => ['path' => 'foobaz', 'type' => 'file', 'dirname' => ''],
+        ];
+
+        $response = [
+            'contents' => json_encode([$cache_data, [], null]),
+            'path' => 'file.json',
+        ];
+
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $adapter->shouldReceive('has')->zeroOrMoreTimes()->with('file.json')->andReturn(true);
+        $adapter->shouldReceive('read')->once()->with('file.json')->andReturn($response);
+        $adapter->shouldReceive('update')->once()->with('file.json', Mockery::any(), Mockery::any())->andReturn(true);
+
+        $cache = new Adapter($adapter, 'file.json', null);
+        $cache->load();
+
+        $cache->deleteDir('foo', true);
+
+        $this->assertSame(1, count($cache->listContents('', true)));
+    }
+}

+ 16 - 0
vendor/league/flysystem-cached-adapter/tests/InspectionTests.php

@@ -0,0 +1,16 @@
+<?php
+
+use League\Flysystem\Cached\CachedAdapter;
+use PHPUnit\Framework\TestCase;
+
+class InspectionTests extends TestCase {
+
+    public function testGetAdapter()
+    {
+        $adapter = Mockery::mock('League\Flysystem\AdapterInterface');
+        $cache = Mockery::mock('League\Flysystem\Cached\CacheInterface');
+        $cache->shouldReceive('load')->once();
+        $cached_adapter = new CachedAdapter($adapter, $cache);
+        $this->assertInstanceOf('League\Flysystem\AdapterInterface', $cached_adapter->getAdapter());
+    }
+}

+ 35 - 0
vendor/league/flysystem-cached-adapter/tests/MemcachedTests.php

@@ -0,0 +1,35 @@
+<?php
+
+use League\Flysystem\Cached\Storage\Memcached;
+use PHPUnit\Framework\TestCase;
+
+class MemcachedTests extends TestCase
+{
+    public function testLoadFail()
+    {
+        $client = Mockery::mock('Memcached');
+        $client->shouldReceive('get')->once()->andReturn(false);
+        $cache = new Memcached($client);
+        $cache->load();
+        $this->assertFalse($cache->isComplete('', false));
+    }
+
+    public function testLoadSuccess()
+    {
+        $response = json_encode([[], ['' => true]]);
+        $client = Mockery::mock('Memcached');
+        $client->shouldReceive('get')->once()->andReturn($response);
+        $cache = new Memcached($client);
+        $cache->load();
+        $this->assertTrue($cache->isComplete('', false));
+    }
+
+    public function testSave()
+    {
+        $response = json_encode([[], []]);
+        $client = Mockery::mock('Memcached');
+        $client->shouldReceive('set')->once()->andReturn($response);
+        $cache = new Memcached($client);
+        $cache->save();
+    }
+}

+ 255 - 0
vendor/league/flysystem-cached-adapter/tests/MemoryCacheTests.php

@@ -0,0 +1,255 @@
+<?php
+
+use League\Flysystem\Cached\Storage\Memory;
+use League\Flysystem\Util;
+use PHPUnit\Framework\TestCase;
+
+class MemoryCacheTests extends TestCase
+{
+    public function testAutosave()
+    {
+        $cache = new Memory();
+        $cache->setAutosave(true);
+        $this->assertTrue($cache->getAutosave());
+        $cache->setAutosave(false);
+        $this->assertFalse($cache->getAutosave());
+    }
+
+    public function testCacheMiss()
+    {
+        $cache = new Memory();
+        $cache->storeMiss('path.txt');
+        $this->assertFalse($cache->has('path.txt'));
+    }
+
+    public function testIsComplete()
+    {
+        $cache = new Memory();
+        $this->assertFalse($cache->isComplete('dirname', false));
+        $cache->setComplete('dirname', false);
+        $this->assertFalse($cache->isComplete('dirname', true));
+        $cache->setComplete('dirname', true);
+        $this->assertTrue($cache->isComplete('dirname', true));
+    }
+
+    public function testCleanContents()
+    {
+        $cache = new Memory();
+        $input = [[
+            'path'       => 'path.txt',
+            'visibility' => 'public',
+            'invalid'    => 'thing',
+        ]];
+
+        $expected = [[
+            'path'       => 'path.txt',
+            'visibility' => 'public',
+        ]];
+
+        $output = $cache->cleanContents($input);
+        $this->assertEquals($expected, $output);
+    }
+
+    public function testGetForStorage()
+    {
+        $cache = new Memory();
+        $input = [[
+            'path'       => 'path.txt',
+            'visibility' => 'public',
+            'type'       => 'file',
+        ]];
+
+        $cache->storeContents('', $input, true);
+        $contents = $cache->listContents('', true);
+        $cached = [];
+        foreach ($contents as $item) {
+            $cached[$item['path']] = $item;
+        }
+
+        $this->assertEquals(json_encode([$cached, ['' => 'recursive']]), $cache->getForStorage());
+    }
+
+    public function testParentCompleteIsUsedDuringHas()
+    {
+        $cache = new Memory();
+        $cache->setComplete('dirname', false);
+        $this->assertFalse($cache->has('dirname/path.txt'));
+    }
+
+    public function testFlush()
+    {
+        $cache = new Memory();
+        $cache->setComplete('dirname', true);
+        $cache->updateObject('path.txt', [
+            'path'       => 'path.txt',
+            'visibility' => 'public',
+        ]);
+        $cache->flush();
+        $this->assertFalse($cache->isComplete('dirname', true));
+        $this->assertNull($cache->has('path.txt'));
+    }
+
+    public function testSetFromStorage()
+    {
+        $cache = new Memory();
+        $json = [[
+            'path.txt' => ['path' => 'path.txt', 'type' => 'file'],
+        ], ['dirname' => 'recursive']];
+        $jsonString = json_encode($json);
+        $cache->setFromStorage($jsonString);
+        $this->assertTrue($cache->has('path.txt'));
+        $this->assertTrue($cache->isComplete('dirname', true));
+    }
+
+    public function testGetMetadataFail()
+    {
+        $cache = new Memory();
+        $this->assertFalse($cache->getMetadata('path.txt'));
+    }
+
+    public function metaGetterProvider()
+    {
+        return [
+            ['getTimestamp', 'timestamp', 12344],
+            ['getMimetype', 'mimetype', 'text/plain'],
+            ['getSize', 'size', 12],
+            ['getVisibility', 'visibility', 'private'],
+            ['read', 'contents', '__contents__'],
+        ];
+    }
+
+    /**
+     * @dataProvider metaGetterProvider
+     *
+     * @param $method
+     * @param $key
+     * @param $value
+     */
+    public function testMetaGetters($method, $key, $value)
+    {
+        $cache = new Memory();
+        $this->assertFalse($cache->{$method}('path.txt'));
+        $cache->updateObject('path.txt', $object = [
+                'path' => 'path.txt',
+                'type' => 'file',
+                $key   => $value,
+            ] + Util::pathinfo('path.txt'), true);
+        $this->assertEquals($object, $cache->{$method}('path.txt'));
+        $this->assertEquals($object, $cache->getMetadata('path.txt'));
+    }
+
+    public function testGetDerivedMimetype()
+    {
+        $cache = new Memory();
+        $cache->updateObject('path.txt', [
+            'contents' => 'something',
+        ]);
+        $response = $cache->getMimetype('path.txt');
+        $this->assertEquals('text/plain', $response['mimetype']);
+    }
+
+    public function testCopyFail()
+    {
+        $cache = new Memory();
+        $cache->copy('one', 'two');
+        $this->assertNull($cache->has('two'));
+        $this->assertNull($cache->load());
+    }
+
+    public function testStoreContents()
+    {
+        $cache = new Memory();
+        $cache->storeContents('dirname', [
+            ['path' => 'dirname', 'type' => 'dir'],
+            ['path' => 'dirname/nested', 'type' => 'dir'],
+            ['path' => 'dirname/nested/deep', 'type' => 'dir'],
+            ['path' => 'other/nested/deep', 'type' => 'dir'],
+        ], true);
+
+        $this->isTrue($cache->isComplete('other/nested', true));
+    }
+
+    public function testDelete()
+    {
+        $cache = new Memory();
+        $cache->updateObject('path.txt', ['type' => 'file']);
+        $this->assertTrue($cache->has('path.txt'));
+        $cache->delete('path.txt');
+        $this->assertFalse($cache->has('path.txt'));
+    }
+
+    public function testDeleteDir()
+    {
+        $cache = new Memory();
+        $cache->storeContents('dirname', [
+            ['path' => 'dirname/path.txt', 'type' => 'file'],
+        ]);
+        $this->assertTrue($cache->isComplete('dirname', false));
+        $this->assertTrue($cache->has('dirname/path.txt'));
+        $cache->deleteDir('dirname');
+        $this->assertFalse($cache->isComplete('dirname', false));
+        $this->assertNull($cache->has('dirname/path.txt'));
+    }
+
+    public function testReadStream()
+    {
+        $cache = new Memory();
+        $this->assertFalse($cache->readStream('path.txt'));
+    }
+
+    public function testRename()
+    {
+        $cache = new Memory();
+        $cache->updateObject('path.txt', ['type' => 'file']);
+        $cache->rename('path.txt', 'newpath.txt');
+        $this->assertTrue($cache->has('newpath.txt'));
+    }
+
+    public function testCopy()
+    {
+        $cache = new Memory();
+        $cache->updateObject('path.txt', ['type' => 'file']);
+        $cache->copy('path.txt', 'newpath.txt');
+        $this->assertTrue($cache->has('newpath.txt'));
+    }
+
+    public function testComplextListContents()
+    {
+        $cache = new Memory();
+        $cache->storeContents('', [
+            ['path' => 'dirname', 'type' => 'dir'],
+            ['path' => 'dirname/file.txt', 'type' => 'file'],
+            ['path' => 'other', 'type' => 'dir'],
+            ['path' => 'other/file.txt', 'type' => 'file'],
+            ['path' => 'other/nested/file.txt', 'type' => 'file'],
+        ]);
+
+        $this->assertCount(3, $cache->listContents('other', true));
+    }
+
+    public function testComplextListContentsWithDeletedFile()
+    {
+        $cache = new Memory();
+        $cache->storeContents('', [
+            ['path' => 'dirname', 'type' => 'dir'],
+            ['path' => 'dirname/file.txt', 'type' => 'file'],
+            ['path' => 'other', 'type' => 'dir'],
+            ['path' => 'other/file.txt', 'type' => 'file'],
+            ['path' => 'other/another_file.txt', 'type' => 'file'],
+        ]);
+
+        $cache->delete('other/another_file.txt');
+        $this->assertCount(4, $cache->listContents('', true));
+    }
+
+    public function testCacheMissIfContentsIsFalse()
+    {
+        $cache = new Memory();
+        $cache->updateObject('path.txt', [
+            'path'     => 'path.txt',
+            'contents' => false,
+        ], true);
+
+        $this->assertFalse($cache->read('path.txt'));
+    }
+}

+ 35 - 0
vendor/league/flysystem-cached-adapter/tests/NoopCacheTests.php

@@ -0,0 +1,35 @@
+<?php
+
+use League\Flysystem\Cached\Storage\Noop;
+use PHPUnit\Framework\TestCase;
+
+class NoopCacheTests extends TestCase
+{
+    public function testNoop()
+    {
+        $cache = new Noop();
+        $this->assertEquals($cache, $cache->storeMiss('file.txt'));
+        $this->assertNull($cache->setComplete('', false));
+        $this->assertNull($cache->load());
+        $this->assertNull($cache->flush());
+        $this->assertNull($cache->has('path.txt'));
+        $this->assertNull($cache->autosave());
+        $this->assertFalse($cache->isComplete('', false));
+        $this->assertFalse($cache->read('something'));
+        $this->assertFalse($cache->readStream('something'));
+        $this->assertFalse($cache->getMetadata('something'));
+        $this->assertFalse($cache->getMimetype('something'));
+        $this->assertFalse($cache->getSize('something'));
+        $this->assertFalse($cache->getTimestamp('something'));
+        $this->assertFalse($cache->getVisibility('something'));
+        $this->assertEmpty($cache->listContents('', false));
+        $this->assertFalse($cache->rename('', ''));
+        $this->assertFalse($cache->copy('', ''));
+        $this->assertNull($cache->save());
+        $object = ['path' => 'path.ext'];
+        $this->assertEquals($object, $cache->updateObject('path.txt', $object));
+        $this->assertEquals([['path' => 'some/file.txt']], $cache->storeContents('unknwon', [
+            ['path' => 'some/file.txt'],
+        ], false));
+    }
+}

+ 45 - 0
vendor/league/flysystem-cached-adapter/tests/PhpRedisTests.php

@@ -0,0 +1,45 @@
+<?php
+
+use League\Flysystem\Cached\Storage\PhpRedis;
+use PHPUnit\Framework\TestCase;
+
+class PhpRedisTests extends TestCase
+{
+    public function testLoadFail()
+    {
+        $client = Mockery::mock('Redis');
+        $client->shouldReceive('get')->with('flysystem')->once()->andReturn(false);
+        $cache = new PhpRedis($client);
+        $cache->load();
+        $this->assertFalse($cache->isComplete('', false));
+    }
+
+    public function testLoadSuccess()
+    {
+        $response = json_encode([[], ['' => true]]);
+        $client = Mockery::mock('Redis');
+        $client->shouldReceive('get')->with('flysystem')->once()->andReturn($response);
+        $cache = new PhpRedis($client);
+        $cache->load();
+        $this->assertTrue($cache->isComplete('', false));
+    }
+
+    public function testSave()
+    {
+        $data = json_encode([[], []]);
+        $client = Mockery::mock('Redis');
+        $client->shouldReceive('set')->with('flysystem', $data)->once();
+        $cache = new PhpRedis($client);
+        $cache->save();
+    }
+
+    public function testSaveWithExpire()
+    {
+        $data = json_encode([[], []]);
+        $client = Mockery::mock('Redis');
+        $client->shouldReceive('set')->with('flysystem', $data)->once();
+        $client->shouldReceive('expire')->with('flysystem', 20)->once();
+        $cache = new PhpRedis($client, 'flysystem', 20);
+        $cache->save();
+    }
+}

+ 55 - 0
vendor/league/flysystem-cached-adapter/tests/PredisTests.php

@@ -0,0 +1,55 @@
+<?php
+
+use League\Flysystem\Cached\Storage\Predis;
+use PHPUnit\Framework\TestCase;
+
+class PredisTests extends TestCase
+{
+    public function testLoadFail()
+    {
+        $client = Mockery::mock('Predis\Client');
+        $command = Mockery::mock('Predis\Command\CommandInterface');
+        $client->shouldReceive('createCommand')->with('get', ['flysystem'])->once()->andReturn($command);
+        $client->shouldReceive('executeCommand')->with($command)->andReturn(null);
+        $cache = new Predis($client);
+        $cache->load();
+        $this->assertFalse($cache->isComplete('', false));
+    }
+
+    public function testLoadSuccess()
+    {
+        $response = json_encode([[], ['' => true]]);
+        $client = Mockery::mock('Predis\Client');
+        $command = Mockery::mock('Predis\Command\CommandInterface');
+        $client->shouldReceive('createCommand')->with('get', ['flysystem'])->once()->andReturn($command);
+        $client->shouldReceive('executeCommand')->with($command)->andReturn($response);
+        $cache = new Predis($client);
+        $cache->load();
+        $this->assertTrue($cache->isComplete('', false));
+    }
+
+    public function testSave()
+    {
+        $data = json_encode([[], []]);
+        $client = Mockery::mock('Predis\Client');
+        $command = Mockery::mock('Predis\Command\CommandInterface');
+        $client->shouldReceive('createCommand')->with('set', ['flysystem', $data])->once()->andReturn($command);
+        $client->shouldReceive('executeCommand')->with($command)->once();
+        $cache = new Predis($client);
+        $cache->save();
+    }
+
+    public function testSaveWithExpire()
+    {
+        $data = json_encode([[], []]);
+        $client = Mockery::mock('Predis\Client');
+        $command = Mockery::mock('Predis\Command\CommandInterface');
+        $client->shouldReceive('createCommand')->with('set', ['flysystem', $data])->once()->andReturn($command);
+        $client->shouldReceive('executeCommand')->with($command)->once();
+        $expireCommand = Mockery::mock('Predis\Command\CommandInterface');
+        $client->shouldReceive('createCommand')->with('expire', ['flysystem', 20])->once()->andReturn($expireCommand);
+        $client->shouldReceive('executeCommand')->with($expireCommand)->once();
+        $cache = new Predis($client, 'flysystem', 20);
+        $cache->save();
+    }
+}

+ 45 - 0
vendor/league/flysystem-cached-adapter/tests/Psr6CacheTest.php

@@ -0,0 +1,45 @@
+<?php
+
+use League\Flysystem\Cached\Storage\Psr6Cache;
+use PHPUnit\Framework\TestCase;
+
+class Psr6CacheTests extends TestCase
+{
+    public function testLoadFail()
+    {
+        $pool = Mockery::mock('Psr\Cache\CacheItemPoolInterface');
+        $item = Mockery::mock('Psr\Cache\CacheItemInterface');
+        $item->shouldReceive('isHit')->once()->andReturn(false);
+        $pool->shouldReceive('getItem')->once()->andReturn($item);
+        $cache = new Psr6Cache($pool);
+        $cache->load();
+        $this->assertFalse($cache->isComplete('', false));
+    }
+
+    public function testLoadSuccess()
+    {
+        $response = json_encode([[], ['' => true]]);
+        $pool = Mockery::mock('Psr\Cache\CacheItemPoolInterface');
+        $item = Mockery::mock('Psr\Cache\CacheItemInterface');
+        $item->shouldReceive('get')->once()->andReturn($response);
+        $item->shouldReceive('isHit')->once()->andReturn(true);
+        $pool->shouldReceive('getItem')->once()->andReturn($item);
+        $cache = new Psr6Cache($pool);
+        $cache->load();
+        $this->assertTrue($cache->isComplete('', false));
+    }
+
+    public function testSave()
+    {
+        $response = json_encode([[], []]);
+        $ttl = 4711;
+        $pool = Mockery::mock('Psr\Cache\CacheItemPoolInterface');
+        $item = Mockery::mock('Psr\Cache\CacheItemInterface');
+        $item->shouldReceive('expiresAfter')->once()->with($ttl);
+        $item->shouldReceive('set')->once()->andReturn($response);
+        $pool->shouldReceive('getItem')->once()->andReturn($item);
+        $pool->shouldReceive('save')->once()->with($item);
+        $cache = new Psr6Cache($pool, 'foo', $ttl);
+        $cache->save();
+    }
+}

+ 43 - 0
vendor/league/flysystem-cached-adapter/tests/StashTest.php

@@ -0,0 +1,43 @@
+<?php
+
+use League\Flysystem\Cached\Storage\Stash;
+use PHPUnit\Framework\TestCase;
+
+class StashTests extends TestCase
+{
+    public function testLoadFail()
+    {
+        $pool = Mockery::mock('Stash\Pool');
+        $item = Mockery::mock('Stash\Item');
+        $item->shouldReceive('get')->once()->andReturn(null);
+        $item->shouldReceive('isMiss')->once()->andReturn(true);
+        $pool->shouldReceive('getItem')->once()->andReturn($item);
+        $cache = new Stash($pool);
+        $cache->load();
+        $this->assertFalse($cache->isComplete('', false));
+    }
+
+    public function testLoadSuccess()
+    {
+        $response = json_encode([[], ['' => true]]);
+        $pool = Mockery::mock('Stash\Pool');
+        $item = Mockery::mock('Stash\Item');
+        $item->shouldReceive('get')->once()->andReturn($response);
+        $item->shouldReceive('isMiss')->once()->andReturn(false);
+        $pool->shouldReceive('getItem')->once()->andReturn($item);
+        $cache = new Stash($pool);
+        $cache->load();
+        $this->assertTrue($cache->isComplete('', false));
+    }
+
+    public function testSave()
+    {
+        $response = json_encode([[], []]);
+        $pool = Mockery::mock('Stash\Pool');
+        $item = Mockery::mock('Stash\Item');
+        $item->shouldReceive('set')->once()->andReturn($response);
+        $pool->shouldReceive('getItem')->once()->andReturn($item);
+        $cache = new Stash($pool);
+        $cache->save();
+    }
+}

+ 76 - 0
vendor/league/flysystem/CODE_OF_CONDUCT.md

@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at info+flysystem@frankdejonge.nl. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq

+ 19 - 0
vendor/league/flysystem/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2013-2019 Frank de Jonge
+
+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.

+ 16 - 0
vendor/league/flysystem/SECURITY.md

@@ -0,0 +1,16 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 1.0.x   | :white_check_mark: |
+| 2.0.x   | :x:                |
+
+## Reporting a Vulnerability
+
+When you've encountered a security vulnerability, please disclose it securely.
+
+The security process is described at: 
+[https://flysystem.thephpleague.com/docs/security/](https://flysystem.thephpleague.com/docs/security/)
+

+ 68 - 0
vendor/league/flysystem/composer.json

@@ -0,0 +1,68 @@
+{
+    "name": "league/flysystem",
+    "type": "library",
+    "description": "Filesystem abstraction: Many filesystems, one API.",
+    "keywords": [
+        "filesystem", "filesystems", "files", "storage", "dropbox", "aws",
+        "abstraction", "s3", "ftp", "sftp", "remote", "webdav",
+        "file systems", "cloud", "cloud files", "rackspace", "copy.com"
+    ],
+    "funding": [
+        {
+            "type": "other",
+            "url": "https://offset.earth/frankdejonge"
+        }
+    ],
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Frank de Jonge",
+            "email": "info@frenky.net"
+        }
+    ],
+    "require": {
+        "php": "^7.2.5 || ^8.0",
+        "ext-fileinfo": "*",
+        "league/mime-type-detection": "^1.3"
+    },
+    "require-dev": {
+        "phpspec/prophecy": "^1.11.1",
+        "phpunit/phpunit": "^8.5.8"
+    },
+    "autoload": {
+        "psr-4": {
+            "League\\Flysystem\\": "src/"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "League\\Flysystem\\Stub\\": "stub/"
+        }
+    },
+    "suggest": {
+        "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
+        "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
+        "league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
+        "league/flysystem-webdav": "Allows you to use WebDAV storage",
+        "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
+        "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
+        "spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
+        "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications",
+        "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
+        "ext-ftp": "Allows you to use FTP server storage",
+        "ext-openssl": "Allows you to use FTPS server storage",
+        "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
+        "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter"
+    },
+    "conflict": {
+        "league/flysystem-sftp": "<1.0.6"
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.1-dev"
+        }
+    },
+    "scripts": {
+        "phpstan": "php phpstan.php"
+    }
+}

+ 19 - 0
vendor/league/flysystem/deprecations.md

@@ -0,0 +1,19 @@
+# Deprecations
+
+This document lists all the planned deprecations.
+
+## Handlers will be removed in 2.0
+
+The `Handler` type and associated calls will be removed in version 2.0.
+
+### Upgrade path
+
+You should create your own implementation for handling OOP usage,
+but it's recommended to move away from using an OOP-style wrapper entirely.
+
+The reason for this is that it's too easy for implementation details (for
+your application this is Flysystem) to leak into the application. The most
+important part for Flysystem is that it improves portability and creates a
+solid boundary between your application core and the infrastructure you use.
+The OOP-style handling breaks this principle, therefore I want to stop
+promoting it. 

+ 72 - 0
vendor/league/flysystem/src/Adapter/AbstractAdapter.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace League\Flysystem\Adapter;
+
+use League\Flysystem\AdapterInterface;
+
+abstract class AbstractAdapter implements AdapterInterface
+{
+    /**
+     * @var string|null path prefix
+     */
+    protected $pathPrefix;
+
+    /**
+     * @var string
+     */
+    protected $pathSeparator = '/';
+
+    /**
+     * Set the path prefix.
+     *
+     * @param string $prefix
+     *
+     * @return void
+     */
+    public function setPathPrefix($prefix)
+    {
+        $prefix = (string) $prefix;
+
+        if ($prefix === '') {
+            $this->pathPrefix = null;
+
+            return;
+        }
+
+        $this->pathPrefix = rtrim($prefix, '\\/') . $this->pathSeparator;
+    }
+
+    /**
+     * Get the path prefix.
+     *
+     * @return string|null path prefix or null if pathPrefix is empty
+     */
+    public function getPathPrefix()
+    {
+        return $this->pathPrefix;
+    }
+
+    /**
+     * Prefix a path.
+     *
+     * @param string $path
+     *
+     * @return string prefixed path
+     */
+    public function applyPathPrefix($path)
+    {
+        return $this->getPathPrefix() . ltrim($path, '\\/');
+    }
+
+    /**
+     * Remove a path prefix.
+     *
+     * @param string $path
+     *
+     * @return string path without the prefix
+     */
+    public function removePathPrefix($path)
+    {
+        return substr($path, strlen((string) $this->getPathPrefix()));
+    }
+}

+ 705 - 0
vendor/league/flysystem/src/Adapter/AbstractFtpAdapter.php

@@ -0,0 +1,705 @@
+<?php
+
+namespace League\Flysystem\Adapter;
+
+use DateTime;
+use League\Flysystem\AdapterInterface;
+use League\Flysystem\Config;
+use League\Flysystem\NotSupportedException;
+use League\Flysystem\SafeStorage;
+use RuntimeException;
+
+abstract class AbstractFtpAdapter extends AbstractAdapter
+{
+    /**
+     * @var mixed
+     */
+    protected $connection;
+
+    /**
+     * @var string
+     */
+    protected $host;
+
+    /**
+     * @var int
+     */
+    protected $port = 21;
+
+    /**
+     * @var bool
+     */
+    protected $ssl = false;
+
+    /**
+     * @var int
+     */
+    protected $timeout = 90;
+
+    /**
+     * @var bool
+     */
+    protected $passive = true;
+
+    /**
+     * @var string
+     */
+    protected $separator = '/';
+
+    /**
+     * @var string|null
+     */
+    protected $root;
+
+    /**
+     * @var int
+     */
+    protected $permPublic = 0744;
+
+    /**
+     * @var int
+     */
+    protected $permPrivate = 0700;
+
+    /**
+     * @var array
+     */
+    protected $configurable = [];
+
+    /**
+     * @var string
+     */
+    protected $systemType;
+
+    /**
+     * @var SafeStorage
+     */
+    protected $safeStorage;
+
+    /**
+     * True to enable timestamps for FTP servers that return unix-style listings.
+     *
+     * @var bool
+     */
+    protected $enableTimestampsOnUnixListings = false;
+
+    /**
+     * Constructor.
+     *
+     * @param array $config
+     */
+    public function __construct(array $config)
+    {
+        $this->safeStorage = new SafeStorage();
+        $this->setConfig($config);
+    }
+
+    /**
+     * Set the config.
+     *
+     * @param array $config
+     *
+     * @return $this
+     */
+    public function setConfig(array $config)
+    {
+        foreach ($this->configurable as $setting) {
+            if ( ! isset($config[$setting])) {
+                continue;
+            }
+
+            $method = 'set' . ucfirst($setting);
+
+            if (method_exists($this, $method)) {
+                $this->$method($config[$setting]);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the host.
+     *
+     * @return string
+     */
+    public function getHost()
+    {
+        return $this->host;
+    }
+
+    /**
+     * Set the host.
+     *
+     * @param string $host
+     *
+     * @return $this
+     */
+    public function setHost($host)
+    {
+        $this->host = $host;
+
+        return $this;
+    }
+
+    /**
+     * Set the public permission value.
+     *
+     * @param int $permPublic
+     *
+     * @return $this
+     */
+    public function setPermPublic($permPublic)
+    {
+        $this->permPublic = $permPublic;
+
+        return $this;
+    }
+
+    /**
+     * Set the private permission value.
+     *
+     * @param int $permPrivate
+     *
+     * @return $this
+     */
+    public function setPermPrivate($permPrivate)
+    {
+        $this->permPrivate = $permPrivate;
+
+        return $this;
+    }
+
+    /**
+     * Returns the ftp port.
+     *
+     * @return int
+     */
+    public function getPort()
+    {
+        return $this->port;
+    }
+
+    /**
+     * Returns the root folder to work from.
+     *
+     * @return string
+     */
+    public function getRoot()
+    {
+        return $this->root;
+    }
+
+    /**
+     * Set the ftp port.
+     *
+     * @param int|string $port
+     *
+     * @return $this
+     */
+    public function setPort($port)
+    {
+        $this->port = (int) $port;
+
+        return $this;
+    }
+
+    /**
+     * Set the root folder to work from.
+     *
+     * @param string $root
+     *
+     * @return $this
+     */
+    public function setRoot($root)
+    {
+        $this->root = rtrim($root, '\\/') . $this->separator;
+
+        return $this;
+    }
+
+    /**
+     * Returns the ftp username.
+     *
+     * @return string username
+     */
+    public function getUsername()
+    {
+        $username = $this->safeStorage->retrieveSafely('username');
+
+        return $username !== null ? $username : 'anonymous';
+    }
+
+    /**
+     * Set ftp username.
+     *
+     * @param string $username
+     *
+     * @return $this
+     */
+    public function setUsername($username)
+    {
+        $this->safeStorage->storeSafely('username', $username);
+
+        return $this;
+    }
+
+    /**
+     * Returns the password.
+     *
+     * @return string password
+     */
+    public function getPassword()
+    {
+        return $this->safeStorage->retrieveSafely('password');
+    }
+
+    /**
+     * Set the ftp password.
+     *
+     * @param string $password
+     *
+     * @return $this
+     */
+    public function setPassword($password)
+    {
+        $this->safeStorage->storeSafely('password', $password);
+
+        return $this;
+    }
+
+    /**
+     * Returns the amount of seconds before the connection will timeout.
+     *
+     * @return int
+     */
+    public function getTimeout()
+    {
+        return $this->timeout;
+    }
+
+    /**
+     * Set the amount of seconds before the connection should timeout.
+     *
+     * @param int $timeout
+     *
+     * @return $this
+     */
+    public function setTimeout($timeout)
+    {
+        $this->timeout = (int) $timeout;
+
+        return $this;
+    }
+
+    /**
+     * Return the FTP system type.
+     *
+     * @return string
+     */
+    public function getSystemType()
+    {
+        return $this->systemType;
+    }
+
+    /**
+     * Set the FTP system type (windows or unix).
+     *
+     * @param string $systemType
+     *
+     * @return $this
+     */
+    public function setSystemType($systemType)
+    {
+        $this->systemType = strtolower($systemType);
+
+        return $this;
+    }
+
+    /**
+     * True to enable timestamps for FTP servers that return unix-style listings.
+     *
+     * @param bool $bool
+     *
+     * @return $this
+     */
+    public function setEnableTimestampsOnUnixListings($bool = false)
+    {
+        $this->enableTimestampsOnUnixListings = $bool;
+
+        return $this;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function listContents($directory = '', $recursive = false)
+    {
+        return $this->listDirectoryContents($directory, $recursive);
+    }
+
+    abstract protected function listDirectoryContents($directory, $recursive = false);
+
+    /**
+     * Normalize a directory listing.
+     *
+     * @param array  $listing
+     * @param string $prefix
+     *
+     * @return array directory listing
+     */
+    protected function normalizeListing(array $listing, $prefix = '')
+    {
+        $base = $prefix;
+        $result = [];
+        $listing = $this->removeDotDirectories($listing);
+
+        while ($item = array_shift($listing)) {
+            if (preg_match('#^.*:$#', $item)) {
+                $base = preg_replace('~^\./*|:$~', '', $item);
+                continue;
+            }
+
+            $result[] = $this->normalizeObject($item, $base);
+        }
+
+        return $this->sortListing($result);
+    }
+
+    /**
+     * Sort a directory listing.
+     *
+     * @param array $result
+     *
+     * @return array sorted listing
+     */
+    protected function sortListing(array $result)
+    {
+        $compare = function ($one, $two) {
+            return strnatcmp($one['path'], $two['path']);
+        };
+
+        usort($result, $compare);
+
+        return $result;
+    }
+
+    /**
+     * Normalize a file entry.
+     *
+     * @param string $item
+     * @param string $base
+     *
+     * @return array normalized file array
+     *
+     * @throws NotSupportedException
+     */
+    protected function normalizeObject($item, $base)
+    {
+        $systemType = $this->systemType ?: $this->detectSystemType($item);
+
+        if ($systemType === 'unix') {
+            return $this->normalizeUnixObject($item, $base);
+        } elseif ($systemType === 'windows') {
+            return $this->normalizeWindowsObject($item, $base);
+        }
+
+        throw NotSupportedException::forFtpSystemType($systemType);
+    }
+
+    /**
+     * Normalize a Unix file entry.
+     *
+     * Given $item contains:
+     *    '-rw-r--r--   1 ftp      ftp           409 Aug 19 09:01 file1.txt'
+     *
+     * This function will return:
+     * [
+     *   'type' => 'file',
+     *   'path' => 'file1.txt',
+     *   'visibility' => 'public',
+     *   'size' => 409,
+     *   'timestamp' => 1566205260
+     * ]
+     *
+     * @param string $item
+     * @param string $base
+     *
+     * @return array normalized file array
+     */
+    protected function normalizeUnixObject($item, $base)
+    {
+        $item = preg_replace('#\s+#', ' ', trim($item), 7);
+
+        if (count(explode(' ', $item, 9)) !== 9) {
+            throw new RuntimeException("Metadata can't be parsed from item '$item' , not enough parts.");
+        }
+
+        list($permissions, /* $number */, /* $owner */, /* $group */, $size, $month, $day, $timeOrYear, $name) = explode(' ', $item, 9);
+        $type = $this->detectType($permissions);
+        $path = $base === '' ? $name : $base . $this->separator . $name;
+
+        if ($type === 'dir') {
+            $result = compact('type', 'path');
+            if ($this->enableTimestampsOnUnixListings) {
+                $timestamp = $this->normalizeUnixTimestamp($month, $day, $timeOrYear);
+                $result += compact('timestamp');
+            }
+
+            return $result;
+        }
+
+        $permissions = $this->normalizePermissions($permissions);
+        $visibility = $permissions & 0044 ? AdapterInterface::VISIBILITY_PUBLIC : AdapterInterface::VISIBILITY_PRIVATE;
+        $size = (int) $size;
+
+        $result = compact('type', 'path', 'visibility', 'size');
+        if ($this->enableTimestampsOnUnixListings) {
+            $timestamp = $this->normalizeUnixTimestamp($month, $day, $timeOrYear);
+            $result += compact('timestamp');
+        }
+
+        return $result;
+    }
+
+    /**
+     * Only accurate to the minute (current year), or to the day.
+     *
+     * Inadequacies in timestamp accuracy are due to limitations of the FTP 'LIST' command
+     *
+     * Note: The 'MLSD' command is a machine-readable replacement for 'LIST'
+     * but many FTP servers do not support it :(
+     *
+     * @param string $month      e.g. 'Aug'
+     * @param string $day        e.g. '19'
+     * @param string $timeOrYear e.g. '09:01' OR '2015'
+     *
+     * @return int
+     */
+    protected function normalizeUnixTimestamp($month, $day, $timeOrYear)
+    {
+        if (is_numeric($timeOrYear)) {
+            $year = $timeOrYear;
+            $hour = '00';
+            $minute = '00';
+            $seconds = '00';
+        } else {
+            $year = date('Y');
+            list($hour, $minute) = explode(':', $timeOrYear);
+            $seconds = '00';
+        }
+        $dateTime = DateTime::createFromFormat('Y-M-j-G:i:s', "{$year}-{$month}-{$day}-{$hour}:{$minute}:{$seconds}");
+
+        return $dateTime->getTimestamp();
+    }
+
+    /**
+     * Normalize a Windows/DOS file entry.
+     *
+     * @param string $item
+     * @param string $base
+     *
+     * @return array normalized file array
+     */
+    protected function normalizeWindowsObject($item, $base)
+    {
+        $item = preg_replace('#\s+#', ' ', trim($item), 3);
+
+        if (count(explode(' ', $item, 4)) !== 4) {
+            throw new RuntimeException("Metadata can't be parsed from item '$item' , not enough parts.");
+        }
+
+        list($date, $time, $size, $name) = explode(' ', $item, 4);
+        $path = $base === '' ? $name : $base . $this->separator . $name;
+
+        // Check for the correct date/time format
+        $format = strlen($date) === 8 ? 'm-d-yH:iA' : 'Y-m-dH:i';
+        $dt = DateTime::createFromFormat($format, $date . $time);
+        $timestamp = $dt ? $dt->getTimestamp() : (int) strtotime("$date $time");
+
+        if ($size === '<DIR>') {
+            $type = 'dir';
+
+            return compact('type', 'path', 'timestamp');
+        }
+
+        $type = 'file';
+        $visibility = AdapterInterface::VISIBILITY_PUBLIC;
+        $size = (int) $size;
+
+        return compact('type', 'path', 'visibility', 'size', 'timestamp');
+    }
+
+    /**
+     * Get the system type from a listing item.
+     *
+     * @param string $item
+     *
+     * @return string the system type
+     */
+    protected function detectSystemType($item)
+    {
+        return preg_match('/^[0-9]{2,4}-[0-9]{2}-[0-9]{2}/', trim($item)) ? 'windows' : 'unix';
+    }
+
+    /**
+     * Get the file type from the permissions.
+     *
+     * @param string $permissions
+     *
+     * @return string file type
+     */
+    protected function detectType($permissions)
+    {
+        return substr($permissions, 0, 1) === 'd' ? 'dir' : 'file';
+    }
+
+    /**
+     * Normalize a permissions string.
+     *
+     * @param string $permissions
+     *
+     * @return int
+     */
+    protected function normalizePermissions($permissions)
+    {
+        if (is_numeric($permissions)) {
+            return ((int) $permissions) & 0777;
+        }
+
+        // remove the type identifier
+        $permissions = substr($permissions, 1);
+
+        // map the string rights to the numeric counterparts
+        $map = ['-' => '0', 'r' => '4', 'w' => '2', 'x' => '1'];
+        $permissions = strtr($permissions, $map);
+
+        // split up the permission groups
+        $parts = str_split($permissions, 3);
+
+        // convert the groups
+        $mapper = function ($part) {
+            return array_sum(str_split($part));
+        };
+
+        // converts to decimal number
+        return octdec(implode('', array_map($mapper, $parts)));
+    }
+
+    /**
+     * Filter out dot-directories.
+     *
+     * @param array $list
+     *
+     * @return array
+     */
+    public function removeDotDirectories(array $list)
+    {
+        $filter = function ($line) {
+            return $line !== '' && ! preg_match('#.* \.(\.)?$|^total#', $line);
+        };
+
+        return array_filter($list, $filter);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function has($path)
+    {
+        return $this->getMetadata($path);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getSize($path)
+    {
+        return $this->getMetadata($path);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getVisibility($path)
+    {
+        return $this->getMetadata($path);
+    }
+
+    /**
+     * Ensure a directory exists.
+     *
+     * @param string $dirname
+     */
+    public function ensureDirectory($dirname)
+    {
+        $dirname = (string) $dirname;
+
+        if ($dirname !== '' && ! $this->has($dirname)) {
+            $this->createDir($dirname, new Config());
+        }
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getConnection()
+    {
+        if ( ! $this->isConnected()) {
+            $this->disconnect();
+            $this->connect();
+        }
+
+        return $this->connection;
+    }
+
+    /**
+     * Get the public permission value.
+     *
+     * @return int
+     */
+    public function getPermPublic()
+    {
+        return $this->permPublic;
+    }
+
+    /**
+     * Get the private permission value.
+     *
+     * @return int
+     */
+    public function getPermPrivate()
+    {
+        return $this->permPrivate;
+    }
+
+    /**
+     * Disconnect on destruction.
+     */
+    public function __destruct()
+    {
+        $this->disconnect();
+    }
+
+    /**
+     * Establish a connection.
+     */
+    abstract public function connect();
+
+    /**
+     * Close the connection.
+     */
+    abstract public function disconnect();
+
+    /**
+     * Check if a connection is active.
+     *
+     * @return bool
+     */
+    abstract public function isConnected();
+
+    protected function escapePath($path)
+    {
+        return str_replace(['*', '[', ']'], ['\\*', '\\[', '\\]'], $path);
+    }
+}

+ 12 - 0
vendor/league/flysystem/src/Adapter/CanOverwriteFiles.php

@@ -0,0 +1,12 @@
+<?php
+
+
+namespace League\Flysystem\Adapter;
+
+/**
+ * Adapters that implement this interface let the Filesystem know that files can be overwritten using the write
+ * functions and don't need the update function to be called. This can help improve performance when asserts are disabled.
+ */
+interface CanOverwriteFiles
+{
+}

+ 584 - 0
vendor/league/flysystem/src/Adapter/Ftp.php

@@ -0,0 +1,584 @@
+<?php
+
+namespace League\Flysystem\Adapter;
+
+use League\Flysystem\Adapter\Polyfill\StreamedCopyTrait;
+use League\Flysystem\AdapterInterface;
+use League\Flysystem\Config;
+use League\Flysystem\ConnectionErrorException;
+use League\Flysystem\ConnectionRuntimeException;
+use League\Flysystem\InvalidRootException;
+use League\Flysystem\Util;
+use League\Flysystem\Util\MimeType;
+
+use function in_array;
+
+class Ftp extends AbstractFtpAdapter
+{
+    use StreamedCopyTrait;
+
+    /**
+     * @var int
+     */
+    protected $transferMode = FTP_BINARY;
+
+    /**
+     * @var null|bool
+     */
+    protected $ignorePassiveAddress = null;
+
+    /**
+     * @var bool
+     */
+    protected $recurseManually = false;
+
+    /**
+     * @var bool
+     */
+    protected $utf8 = false;
+
+    /**
+     * @var array
+     */
+    protected $configurable = [
+        'host',
+        'port',
+        'username',
+        'password',
+        'ssl',
+        'timeout',
+        'root',
+        'permPrivate',
+        'permPublic',
+        'passive',
+        'transferMode',
+        'systemType',
+        'ignorePassiveAddress',
+        'recurseManually',
+        'utf8',
+        'enableTimestampsOnUnixListings',
+    ];
+
+    /**
+     * @var bool
+     */
+    protected $isPureFtpd;
+
+    /**
+     * Set the transfer mode.
+     *
+     * @param int $mode
+     *
+     * @return $this
+     */
+    public function setTransferMode($mode)
+    {
+        $this->transferMode = $mode;
+
+        return $this;
+    }
+
+    /**
+     * Set if Ssl is enabled.
+     *
+     * @param bool $ssl
+     *
+     * @return $this
+     */
+    public function setSsl($ssl)
+    {
+        $this->ssl = (bool) $ssl;
+
+        return $this;
+    }
+
+    /**
+     * Set if passive mode should be used.
+     *
+     * @param bool $passive
+     */
+    public function setPassive($passive = true)
+    {
+        $this->passive = $passive;
+    }
+
+    /**
+     * @param bool $ignorePassiveAddress
+     */
+    public function setIgnorePassiveAddress($ignorePassiveAddress)
+    {
+        $this->ignorePassiveAddress = $ignorePassiveAddress;
+    }
+
+    /**
+     * @param bool $recurseManually
+     */
+    public function setRecurseManually($recurseManually)
+    {
+        $this->recurseManually = $recurseManually;
+    }
+
+    /**
+     * @param bool $utf8
+     */
+    public function setUtf8($utf8)
+    {
+        $this->utf8 = (bool) $utf8;
+    }
+
+    /**
+     * Connect to the FTP server.
+     */
+    public function connect()
+    {
+        $tries = 3;
+        start_connecting:
+
+        if ($this->ssl) {
+            $this->connection = @ftp_ssl_connect($this->getHost(), $this->getPort(), $this->getTimeout());
+        } else {
+            $this->connection = @ftp_connect($this->getHost(), $this->getPort(), $this->getTimeout());
+        }
+
+        if ( ! $this->connection) {
+            $tries--;
+
+            if ($tries > 0) goto start_connecting;
+
+            throw new ConnectionRuntimeException('Could not connect to host: ' . $this->getHost() . ', port:' . $this->getPort());
+        }
+
+        $this->login();
+        $this->setUtf8Mode();
+        $this->setConnectionPassiveMode();
+        $this->setConnectionRoot();
+        $this->isPureFtpd = $this->isPureFtpdServer();
+    }
+
+    /**
+     * Set the connection to UTF-8 mode.
+     */
+    protected function setUtf8Mode()
+    {
+        if ($this->utf8) {
+            $response = ftp_raw($this->connection, "OPTS UTF8 ON");
+            if (!in_array(substr($response[0], 0, 3), ['200', '202'])) {
+                throw new ConnectionRuntimeException(
+                    'Could not set UTF-8 mode for connection: ' . $this->getHost() . '::' . $this->getPort()
+                );
+            }
+        }
+    }
+
+    /**
+     * Set the connections to passive mode.
+     *
+     * @throws ConnectionRuntimeException
+     */
+    protected function setConnectionPassiveMode()
+    {
+        if (is_bool($this->ignorePassiveAddress) && defined('FTP_USEPASVADDRESS')) {
+            ftp_set_option($this->connection, FTP_USEPASVADDRESS, ! $this->ignorePassiveAddress);
+        }
+
+        if ( ! ftp_pasv($this->connection, $this->passive)) {
+            throw new ConnectionRuntimeException(
+                'Could not set passive mode for connection: ' . $this->getHost() . '::' . $this->getPort()
+            );
+        }
+    }
+
+    /**
+     * Set the connection root.
+     */
+    protected function setConnectionRoot()
+    {
+        $root = $this->getRoot();
+        $connection = $this->connection;
+
+        if ($root && ! ftp_chdir($connection, $root)) {
+            throw new InvalidRootException('Root is invalid or does not exist: ' . $this->getRoot());
+        }
+
+        // Store absolute path for further reference.
+        // This is needed when creating directories and
+        // initial root was a relative path, else the root
+        // would be relative to the chdir'd path.
+        $this->root = ftp_pwd($connection);
+    }
+
+    /**
+     * Login.
+     *
+     * @throws ConnectionRuntimeException
+     */
+    protected function login()
+    {
+        set_error_handler(function () {
+        });
+        $isLoggedIn = ftp_login(
+            $this->connection,
+            $this->getUsername(),
+            $this->getPassword()
+        );
+        restore_error_handler();
+
+        if ( ! $isLoggedIn) {
+            $this->disconnect();
+            throw new ConnectionRuntimeException(
+                'Could not login with connection: ' . $this->getHost() . '::' . $this->getPort(
+                ) . ', username: ' . $this->getUsername()
+            );
+        }
+    }
+
+    /**
+     * Disconnect from the FTP server.
+     */
+    public function disconnect()
+    {
+        if ($this->hasFtpConnection()) {
+            @ftp_close($this->connection);
+        }
+
+        $this->connection = null;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function write($path, $contents, Config $config)
+    {
+        $stream = fopen('php://temp', 'w+b');
+        fwrite($stream, $contents);
+        rewind($stream);
+        $result = $this->writeStream($path, $stream, $config);
+        fclose($stream);
+
+        if ($result === false) {
+            return false;
+        }
+
+        $result['contents'] = $contents;
+        $result['mimetype'] = $config->get('mimetype') ?: Util::guessMimeType($path, $contents);
+
+        return $result;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function writeStream($path, $resource, Config $config)
+    {
+        $this->ensureDirectory(Util::dirname($path));
+
+        if ( ! ftp_fput($this->getConnection(), $path, $resource, $this->transferMode)) {
+            return false;
+        }
+
+        if ($visibility = $config->get('visibility')) {
+            $this->setVisibility($path, $visibility);
+        }
+
+        $type = 'file';
+
+        return compact('type', 'path', 'visibility');
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function update($path, $contents, Config $config)
+    {
+        return $this->write($path, $contents, $config);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function updateStream($path, $resource, Config $config)
+    {
+        return $this->writeStream($path, $resource, $config);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function rename($path, $newpath)
+    {
+        return ftp_rename($this->getConnection(), $path, $newpath);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function delete($path)
+    {
+        return ftp_delete($this->getConnection(), $path);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function deleteDir($dirname)
+    {
+        $connection = $this->getConnection();
+        $contents = array_reverse($this->listDirectoryContents($dirname, false));
+
+        foreach ($contents as $object) {
+            if ($object['type'] === 'file') {
+                if ( ! ftp_delete($connection, $object['path'])) {
+                    return false;
+                }
+            } elseif ( ! $this->deleteDir($object['path'])) {
+                return false;
+            }
+        }
+
+        return ftp_rmdir($connection, $dirname);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function createDir($dirname, Config $config)
+    {
+        $connection = $this->getConnection();
+        $directories = explode('/', $dirname);
+
+        foreach ($directories as $directory) {
+            if (false === $this->createActualDirectory($directory, $connection)) {
+                $this->setConnectionRoot();
+
+                return false;
+            }
+
+            ftp_chdir($connection, $directory);
+        }
+
+        $this->setConnectionRoot();
+
+        return ['type' => 'dir', 'path' => $dirname];
+    }
+
+    /**
+     * Create a directory.
+     *
+     * @param string   $directory
+     * @param resource $connection
+     *
+     * @return bool
+     */
+    protected function createActualDirectory($directory, $connection)
+    {
+        // List the current directory
+        $listing = ftp_nlist($connection, '.') ?: [];
+
+        foreach ($listing as $key => $item) {
+            if (preg_match('~^\./.*~', $item)) {
+                $listing[$key] = substr($item, 2);
+            }
+        }
+
+        if (in_array($directory, $listing, true)) {
+            return true;
+        }
+
+        return (boolean) ftp_mkdir($connection, $directory);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getMetadata($path)
+    {
+        if ($path === '') {
+            return ['type' => 'dir', 'path' => ''];
+        }
+
+        if (@ftp_chdir($this->getConnection(), $path) === true) {
+            $this->setConnectionRoot();
+
+            return ['type' => 'dir', 'path' => $path];
+        }
+
+        $listing = $this->ftpRawlist('-A', $path);
+
+        if (empty($listing) || in_array('total 0', $listing, true)) {
+            return false;
+        }
+
+        if (preg_match('/.* not found/', $listing[0])) {
+            return false;
+        }
+
+        if (preg_match('/^total [0-9]*$/', $listing[0])) {
+            array_shift($listing);
+        }
+
+        return $this->normalizeObject($listing[0], '');
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getMimetype($path)
+    {
+        if ( ! $metadata = $this->getMetadata($path)) {
+            return false;
+        }
+
+        $metadata['mimetype'] = MimeType::detectByFilename($path);
+
+        return $metadata;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function getTimestamp($path)
+    {
+        $timestamp = ftp_mdtm($this->getConnection(), $path);
+
+        return ($timestamp !== -1) ? ['path' => $path, 'timestamp' => $timestamp] : false;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function read($path)
+    {
+        if ( ! $object = $this->readStream($path)) {
+            return false;
+        }
+
+        $object['contents'] = stream_get_contents($object['stream']);
+        fclose($object['stream']);
+        unset($object['stream']);
+
+        return $object;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function readStream($path)
+    {
+        $stream = fopen('php://temp', 'w+b');
+        $result = ftp_fget($this->getConnection(), $stream, $path, $this->transferMode);
+        rewind($stream);
+
+        if ( ! $result) {
+            fclose($stream);
+
+            return false;
+        }
+
+        return ['type' => 'file', 'path' => $path, 'stream' => $stream];
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function setVisibility($path, $visibility)
+    {
+        $mode = $visibility === AdapterInterface::VISIBILITY_PUBLIC ? $this->getPermPublic() : $this->getPermPrivate();
+
+        if ( ! ftp_chmod($this->getConnection(), $mode, $path)) {
+            return false;
+        }
+
+        return compact('path', 'visibility');
+    }
+
+    /**
+     * @inheritdoc
+     *
+     * @param string $directory
+     */
+    protected function listDirectoryContents($directory, $recursive = true)
+    {
+        if ($recursive && $this->recurseManually) {
+            return $this->listDirectoryContentsRecursive($directory);
+        }
+
+        $options = $recursive ? '-alnR' : '-aln';
+        $listing = $this->ftpRawlist($options, $directory);
+
+        return $listing ? $this->normalizeListing($listing, $directory) : [];
+    }
+
+    /**
+     * @inheritdoc
+     *
+     * @param string $directory
+     */
+    protected function listDirectoryContentsRecursive($directory)
+    {
+        $listing = $this->normalizeListing($this->ftpRawlist('-aln', $directory) ?: [], $directory);
+        $output = [];
+
+        foreach ($listing as $item) {
+            $output[] = $item;
+            if ($item['type'] !== 'dir') {
+                continue;
+            }
+            $output = array_merge($output, $this->listDirectoryContentsRecursive($item['path']));
+        }
+
+        return $output;
+    }
+
+    /**
+     * Check if the connection is open.
+     *
+     * @return bool
+     *
+     * @throws ConnectionErrorException
+     */
+    public function isConnected()
+    {
+        return $this->hasFtpConnection() && $this->getRawExecResponseCode('NOOP') === 200;
+    }
+
+    /**
+     * @return bool
+     */
+    protected function isPureFtpdServer()
+    {
+        $response = ftp_raw($this->connection, 'HELP');
+
+        return stripos(implode(' ', $response), 'Pure-FTPd') !== false;
+    }
+
+    /**
+     * The ftp_rawlist function with optional escaping.
+     *
+     * @param string $options
+     * @param string $path
+     *
+     * @return array
+     */
+    protected function ftpRawlist($options, $path)
+    {
+        $connection = $this->getConnection();
+
+        if ($this->isPureFtpd) {
+            $path = str_replace([' ', '[', ']'], ['\ ', '\\[', '\\]'], $path);
+        }
+
+        return ftp_rawlist($connection, $options . ' ' . $this->escapePath($path));
+    }
+
+    private function getRawExecResponseCode($command)
+    {
+        $response = @ftp_raw($this->connection, trim($command)) ?: [];
+
+        return (int) preg_replace('/\D/', '', implode(' ', (array) $response));
+    }
+
+    private function hasFtpConnection(): bool
+    {
+        return is_resource($this->connection) || $this->connection instanceof \FTP\Connection;
+    }
+}

Some files were not shown because too many files changed in this diff