Ver Fonte

add swagger php framework

CauseFX há 6 anos atrás
pai
commit
e9acaf746f
100 ficheiros alterados com 12374 adições e 2 exclusões
  1. 2 1
      api/composer.json
  2. 419 1
      api/composer.lock
  3. 14 0
      api/vendor/bin/openapi
  4. 4 0
      api/vendor/bin/openapi.bat
  5. 14 0
      api/vendor/bin/yaml-lint
  6. 4 0
      api/vendor/bin/yaml-lint.bat
  7. 3 0
      api/vendor/composer/autoload_files.php
  8. 6 0
      api/vendor/composer/autoload_psr4.php
  9. 39 0
      api/vendor/composer/autoload_static.php
  10. 432 0
      api/vendor/composer/installed.json
  11. 40 0
      api/vendor/doctrine/annotations/.doctrine-project.json
  12. 162 0
      api/vendor/doctrine/annotations/CHANGELOG.md
  13. 19 0
      api/vendor/doctrine/annotations/LICENSE
  14. 17 0
      api/vendor/doctrine/annotations/README.md
  15. 44 0
      api/vendor/doctrine/annotations/composer.json
  16. 271 0
      api/vendor/doctrine/annotations/docs/en/annotations.rst
  17. 353 0
      api/vendor/doctrine/annotations/docs/en/custom.rst
  18. 97 0
      api/vendor/doctrine/annotations/docs/en/index.rst
  19. 6 0
      api/vendor/doctrine/annotations/docs/en/sidebar.rst
  20. 79 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation.php
  21. 47 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attribute.php
  22. 37 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Attributes.php
  23. 84 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Enum.php
  24. 54 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/IgnoreAnnotation.php
  25. 33 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Required.php
  26. 107 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Annotation/Target.php
  27. 197 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php
  28. 418 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php
  29. 180 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationRegistry.php
  30. 278 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php
  31. 147 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocLexer.php
  32. 1221 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php
  33. 290 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/FileCacheReader.php
  34. 119 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/IndexedReader.php
  35. 91 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PhpParser.php
  36. 89 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/Reader.php
  37. 127 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/SimpleAnnotationReader.php
  38. 194 0
      api/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/TokenParser.php
  39. 4 0
      api/vendor/doctrine/annotations/phpbench.json.dist
  40. 14 0
      api/vendor/doctrine/annotations/phpstan.neon
  41. 19 0
      api/vendor/doctrine/lexer/LICENSE
  42. 9 0
      api/vendor/doctrine/lexer/README.md
  43. 41 0
      api/vendor/doctrine/lexer/composer.json
  44. 328 0
      api/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php
  45. 3 0
      api/vendor/symfony/deprecation-contracts/.gitignore
  46. 5 0
      api/vendor/symfony/deprecation-contracts/CHANGELOG.md
  47. 19 0
      api/vendor/symfony/deprecation-contracts/LICENSE
  48. 26 0
      api/vendor/symfony/deprecation-contracts/README.md
  49. 35 0
      api/vendor/symfony/deprecation-contracts/composer.json
  50. 27 0
      api/vendor/symfony/deprecation-contracts/function.php
  51. 79 0
      api/vendor/symfony/finder/CHANGELOG.md
  52. 91 0
      api/vendor/symfony/finder/Comparator/Comparator.php
  53. 51 0
      api/vendor/symfony/finder/Comparator/DateComparator.php
  54. 79 0
      api/vendor/symfony/finder/Comparator/NumberComparator.php
  55. 19 0
      api/vendor/symfony/finder/Exception/AccessDeniedException.php
  56. 19 0
      api/vendor/symfony/finder/Exception/DirectoryNotFoundException.php
  57. 797 0
      api/vendor/symfony/finder/Finder.php
  58. 105 0
      api/vendor/symfony/finder/Gitignore.php
  59. 111 0
      api/vendor/symfony/finder/Glob.php
  60. 61 0
      api/vendor/symfony/finder/Iterator/CustomFilterIterator.php
  61. 58 0
      api/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php
  62. 45 0
      api/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php
  63. 87 0
      api/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php
  64. 53 0
      api/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php
  65. 58 0
      api/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php
  66. 47 0
      api/vendor/symfony/finder/Iterator/FilenameFilterIterator.php
  67. 106 0
      api/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php
  68. 56 0
      api/vendor/symfony/finder/Iterator/PathFilterIterator.php
  69. 144 0
      api/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php
  70. 57 0
      api/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php
  71. 101 0
      api/vendor/symfony/finder/Iterator/SortableIterator.php
  72. 19 0
      api/vendor/symfony/finder/LICENSE
  73. 14 0
      api/vendor/symfony/finder/README.md
  74. 85 0
      api/vendor/symfony/finder/SplFileInfo.php
  75. 33 0
      api/vendor/symfony/finder/composer.json
  76. 227 0
      api/vendor/symfony/polyfill-ctype/Ctype.php
  77. 19 0
      api/vendor/symfony/polyfill-ctype/LICENSE
  78. 12 0
      api/vendor/symfony/polyfill-ctype/README.md
  79. 46 0
      api/vendor/symfony/polyfill-ctype/bootstrap.php
  80. 38 0
      api/vendor/symfony/polyfill-ctype/composer.json
  81. 224 0
      api/vendor/symfony/yaml/CHANGELOG.md
  82. 248 0
      api/vendor/symfony/yaml/Command/LintCommand.php
  83. 125 0
      api/vendor/symfony/yaml/Dumper.php
  84. 103 0
      api/vendor/symfony/yaml/Escaper.php
  85. 21 0
      api/vendor/symfony/yaml/Exception/DumpException.php
  86. 21 0
      api/vendor/symfony/yaml/Exception/ExceptionInterface.php
  87. 133 0
      api/vendor/symfony/yaml/Exception/ParseException.php
  88. 21 0
      api/vendor/symfony/yaml/Exception/RuntimeException.php
  89. 793 0
      api/vendor/symfony/yaml/Inline.php
  90. 19 0
      api/vendor/symfony/yaml/LICENSE
  91. 1261 0
      api/vendor/symfony/yaml/Parser.php
  92. 13 0
      api/vendor/symfony/yaml/README.md
  93. 45 0
      api/vendor/symfony/yaml/Resources/bin/yaml-lint
  94. 38 0
      api/vendor/symfony/yaml/Tag/TaggedValue.php
  95. 138 0
      api/vendor/symfony/yaml/Unescaper.php
  96. 102 0
      api/vendor/symfony/yaml/Yaml.php
  97. 47 0
      api/vendor/symfony/yaml/composer.json
  98. 8 0
      api/vendor/zircote/swagger-php/.gitignore
  99. 26 0
      api/vendor/zircote/swagger-php/.travis.yml
  100. 3 0
      api/vendor/zircote/swagger-php/Changelog.md

+ 2 - 1
api/composer.json

@@ -13,6 +13,7 @@
     "psr/log": "^1.1",
     "adldap2/adldap2": "^10.0",
     "slim/slim": "4.0",
-    "slim/psr7": "^1.1"
+    "slim/psr7": "^1.1",
+    "zircote/swagger-php": "^3.0"
   }
 }

+ 419 - 1
api/composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "70119fcfb61279fd6695ae48a55a2fde",
+    "content-hash": "a5faec9d74a923c354d912dbfd73cf9b",
     "packages": [
         {
             "name": "adldap2/adldap2",
@@ -194,6 +194,137 @@
             ],
             "time": "2020-03-26T03:05:01+00:00"
         },
+        {
+            "name": "doctrine/annotations",
+            "version": "1.10.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/annotations.git",
+                "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d",
+                "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/lexer": "1.*",
+                "ext-tokenizer": "*",
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "doctrine/cache": "1.*",
+                "phpunit/phpunit": "^7.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9.x-dev"
+                }
+            },
+            "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": "http://www.doctrine-project.org",
+            "keywords": [
+                "annotations",
+                "docblock",
+                "parser"
+            ],
+            "time": "2020-05-25T17:24:27+00:00"
+        },
+        {
+            "name": "doctrine/lexer",
+            "version": "1.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/lexer.git",
+                "reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
+                "reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "^6.0",
+                "phpstan/phpstan": "^0.11.8",
+                "phpunit/phpunit": "^8.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
+                }
+            },
+            "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"
+            ],
+            "time": "2020-05-25T17:44:05+00:00"
+        },
         {
             "name": "fig/http-message-util",
             "version": "1.1.4",
@@ -1658,6 +1789,167 @@
             ],
             "time": "2019-08-01T16:11:29+00:00"
         },
+        {
+            "name": "symfony/deprecation-contracts",
+            "version": "v2.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/deprecation-contracts.git",
+                "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14",
+                "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.1-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "function.php"
+                ]
+            },
+            "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": "A generic function and convention to trigger deprecation notices",
+            "homepage": "https://symfony.com",
+            "time": "2020-06-06T08:49:21+00:00"
+        },
+        {
+            "name": "symfony/finder",
+            "version": "v5.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/finder.git",
+                "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/4298870062bfc667cb78d2b379be4bf5dec5f187",
+                "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Finder\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Finder Component",
+            "homepage": "https://symfony.com",
+            "time": "2020-05-20T17:43:50+00:00"
+        },
+        {
+            "name": "symfony/polyfill-ctype",
+            "version": "v1.18.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-ctype.git",
+                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
+                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-ctype": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.18-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for ctype functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
+            ],
+            "time": "2020-07-14T12:35:20+00:00"
+        },
         {
             "name": "symfony/polyfill-mbstring",
             "version": "v1.14.0",
@@ -1956,6 +2248,69 @@
             ],
             "time": "2019-01-30T11:44:30+00:00"
         },
+        {
+            "name": "symfony/yaml",
+            "version": "v5.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "ea342353a3ef4f453809acc4ebc55382231d4d23"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/ea342353a3ef4f453809acc4ebc55382231d4d23",
+                "reference": "ea342353a3ef4f453809acc4ebc55382231d4d23",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/deprecation-contracts": "^2.1",
+                "symfony/polyfill-ctype": "~1.8"
+            },
+            "conflict": {
+                "symfony/console": "<4.4"
+            },
+            "require-dev": {
+                "symfony/console": "^4.4|^5.0"
+            },
+            "suggest": {
+                "symfony/console": "For validating YAML files using the lint command"
+            },
+            "bin": [
+                "Resources/bin/yaml-lint"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2020-05-20T17:43:50+00:00"
+        },
         {
             "name": "tightenco/collect",
             "version": "v5.7.27",
@@ -2005,6 +2360,69 @@
                 "laravel"
             ],
             "time": "2019-02-13T19:40:13+00:00"
+        },
+        {
+            "name": "zircote/swagger-php",
+            "version": "3.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/zircote/swagger-php.git",
+                "reference": "fa47d62c22c95272625624fbf8109fa46ffac43b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/zircote/swagger-php/zipball/fa47d62c22c95272625624fbf8109fa46ffac43b",
+                "reference": "fa47d62c22c95272625624fbf8109fa46ffac43b",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/annotations": "*",
+                "php": ">=7.2",
+                "symfony/finder": ">=2.2",
+                "symfony/yaml": ">=3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": ">=8",
+                "squizlabs/php_codesniffer": ">=3.3",
+                "zendframework/zend-form": "<2.8"
+            },
+            "bin": [
+                "bin/openapi"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "OpenApi\\": "src"
+                },
+                "files": [
+                    "src/functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Robert Allen",
+                    "email": "zircote@gmail.com",
+                    "homepage": "http://www.zircote.com"
+                },
+                {
+                    "name": "Bob Fanger",
+                    "email": "bfanger@gmail.com",
+                    "homepage": "http://bfanger.nl"
+                }
+            ],
+            "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations",
+            "homepage": "https://github.com/zircote/swagger-php/",
+            "keywords": [
+                "api",
+                "json",
+                "rest",
+                "service discovery"
+            ],
+            "time": "2020-05-07T09:10:49+00:00"
         }
     ],
     "packages-dev": [],

+ 14 - 0
api/vendor/bin/openapi

@@ -0,0 +1,14 @@
+#!/usr/bin/env sh
+
+dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../zircote/swagger-php/bin" && pwd)
+
+if [ -d /proc/cygdrive ]; then
+    case $(which php) in
+        $(readlink -n /proc/cygdrive)/*)
+            # We are in Cygwin using Windows php, so the path must be translated
+            dir=$(cygpath -m "$dir");
+            ;;
+    esac
+fi
+
+"${dir}/openapi" "$@"

+ 4 - 0
api/vendor/bin/openapi.bat

@@ -0,0 +1,4 @@
+@ECHO OFF
+setlocal DISABLEDELAYEDEXPANSION
+SET BIN_TARGET=%~dp0/../zircote/swagger-php/bin/openapi
+php "%BIN_TARGET%" %*

+ 14 - 0
api/vendor/bin/yaml-lint

@@ -0,0 +1,14 @@
+#!/usr/bin/env sh
+
+dir=$(cd "${0%[/\\]*}" > /dev/null; cd "../symfony/yaml/Resources/bin" && pwd)
+
+if [ -d /proc/cygdrive ]; then
+    case $(which php) in
+        $(readlink -n /proc/cygdrive)/*)
+            # We are in Cygwin using Windows php, so the path must be translated
+            dir=$(cygpath -m "$dir");
+            ;;
+    esac
+fi
+
+"${dir}/yaml-lint" "$@"

+ 4 - 0
api/vendor/bin/yaml-lint.bat

@@ -0,0 +1,4 @@
+@ECHO OFF
+setlocal DISABLEDELAYEDEXPANSION
+SET BIN_TARGET=%~dp0/../symfony/yaml/Resources/bin/yaml-lint
+php "%BIN_TARGET%" %*

+ 3 - 0
api/vendor/composer/autoload_files.php

@@ -12,6 +12,8 @@ return array(
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
     '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
     '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
+    '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
+    '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
     '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
     '253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
     '3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php',
@@ -19,4 +21,5 @@ return array(
     'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',
     'caf31cc6ec7cf2241cb6f12c226c3846' => $vendorDir . '/tightenco/collect/src/Collect/Support/alias.php',
     '0097ca414fcb37c7130ac24b05f485f8' => $vendorDir . '/dibi/dibi/src/loader.php',
+    '0ccdf99b8f62f02c52cba55802e0c2e7' => $vendorDir . '/zircote/swagger-php/src/functions.php',
 );

+ 6 - 0
api/vendor/composer/autoload_psr4.php

@@ -11,7 +11,10 @@ return array(
     'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
     'Symfony\\Polyfill\\Php56\\' => array($vendorDir . '/symfony/polyfill-php56'),
     'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
+    'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
+    'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
     'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
+    'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
     'Slim\\Tests\\' => array($vendorDir . '/slim/slim/tests'),
     'Slim\\Psr7\\' => array($vendorDir . '/slim/psr7/src'),
     'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
@@ -25,6 +28,7 @@ return array(
     'PragmaRX\\Google2FA\\' => array($vendorDir . '/pragmarx/google2fa/src'),
     'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
     'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
+    'OpenApi\\' => array($vendorDir . '/zircote/swagger-php/src'),
     'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
     'Kryptonit3\\Sonarr\\' => array($vendorDir . '/kryptonit3/sonarr/src'),
     'Kryptonit3\\SickRage\\' => array($vendorDir . '/kryptonit3/sickrage/src'),
@@ -35,6 +39,8 @@ return array(
     'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
     'Fig\\Http\\Message\\' => array($vendorDir . '/fig/http-message-util/src'),
     'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
+    'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'),
+    'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
     'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
     'Adldap\\' => array($vendorDir . '/adldap2/adldap2/src'),
 );

+ 39 - 0
api/vendor/composer/autoload_static.php

@@ -13,6 +13,8 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
         '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
         '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
+        '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
+        '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
         '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
         '253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
         '3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php',
@@ -20,6 +22,7 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
         'caf31cc6ec7cf2241cb6f12c226c3846' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/alias.php',
         '0097ca414fcb37c7130ac24b05f485f8' => __DIR__ . '/..' . '/dibi/dibi/src/loader.php',
+        '0ccdf99b8f62f02c52cba55802e0c2e7' => __DIR__ . '/..' . '/zircote/swagger-php/src/functions.php',
     );
 
     public static $prefixLengthsPsr4 = array (
@@ -33,7 +36,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             'Symfony\\Polyfill\\Php72\\' => 23,
             'Symfony\\Polyfill\\Php56\\' => 23,
             'Symfony\\Polyfill\\Mbstring\\' => 26,
+            'Symfony\\Polyfill\\Ctype\\' => 23,
+            'Symfony\\Component\\Yaml\\' => 23,
             'Symfony\\Component\\VarDumper\\' => 28,
+            'Symfony\\Component\\Finder\\' => 25,
             'Slim\\Tests\\' => 11,
             'Slim\\Psr7\\' => 10,
             'Slim\\' => 5,
@@ -51,6 +57,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             'ParagonIE\\ConstantTime\\' => 23,
             'PHPMailer\\PHPMailer\\' => 20,
         ),
+        'O' => 
+        array (
+            'OpenApi\\' => 8,
+        ),
         'L' => 
         array (
             'Lcobucci\\JWT\\' => 13,
@@ -76,6 +86,11 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             'Fig\\Http\\Message\\' => 17,
             'FastRoute\\' => 10,
         ),
+        'D' => 
+        array (
+            'Doctrine\\Common\\Lexer\\' => 22,
+            'Doctrine\\Common\\Annotations\\' => 28,
+        ),
         'C' => 
         array (
             'Composer\\Semver\\' => 16,
@@ -107,10 +122,22 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
         ),
+        'Symfony\\Polyfill\\Ctype\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
+        ),
+        'Symfony\\Component\\Yaml\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/yaml',
+        ),
         'Symfony\\Component\\VarDumper\\' => 
         array (
             0 => __DIR__ . '/..' . '/symfony/var-dumper',
         ),
+        'Symfony\\Component\\Finder\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/finder',
+        ),
         'Slim\\Tests\\' => 
         array (
             0 => __DIR__ . '/..' . '/slim/slim/tests',
@@ -165,6 +192,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
         ),
+        'OpenApi\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/zircote/swagger-php/src',
+        ),
         'Lcobucci\\JWT\\' => 
         array (
             0 => __DIR__ . '/..' . '/lcobucci/jwt/src',
@@ -205,6 +236,14 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/nikic/fast-route/src',
         ),
+        'Doctrine\\Common\\Lexer\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer',
+        ),
+        'Doctrine\\Common\\Annotations\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/doctrine/annotations/lib/Doctrine/Common/Annotations',
+        ),
         'Composer\\Semver\\' => 
         array (
             0 => __DIR__ . '/..' . '/composer/semver/src',

+ 432 - 0
api/vendor/composer/installed.json

@@ -193,6 +193,141 @@
             "sqlsrv"
         ]
     },
+    {
+        "name": "doctrine/annotations",
+        "version": "1.10.3",
+        "version_normalized": "1.10.3.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/doctrine/annotations.git",
+            "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/doctrine/annotations/zipball/5db60a4969eba0e0c197a19c077780aadbc43c5d",
+            "reference": "5db60a4969eba0e0c197a19c077780aadbc43c5d",
+            "shasum": ""
+        },
+        "require": {
+            "doctrine/lexer": "1.*",
+            "ext-tokenizer": "*",
+            "php": "^7.1 || ^8.0"
+        },
+        "require-dev": {
+            "doctrine/cache": "1.*",
+            "phpunit/phpunit": "^7.5"
+        },
+        "time": "2020-05-25T17:24:27+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.9.x-dev"
+            }
+        },
+        "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": "http://www.doctrine-project.org",
+        "keywords": [
+            "annotations",
+            "docblock",
+            "parser"
+        ]
+    },
+    {
+        "name": "doctrine/lexer",
+        "version": "1.2.1",
+        "version_normalized": "1.2.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/doctrine/lexer.git",
+            "reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
+            "reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
+            "shasum": ""
+        },
+        "require": {
+            "php": "^7.2 || ^8.0"
+        },
+        "require-dev": {
+            "doctrine/coding-standard": "^6.0",
+            "phpstan/phpstan": "^0.11.8",
+            "phpunit/phpunit": "^8.2"
+        },
+        "time": "2020-05-25T17:44:05+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.2.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
+            }
+        },
+        "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"
+        ]
+    },
     {
         "name": "fig/http-message-util",
         "version": "1.1.4",
@@ -1711,6 +1846,173 @@
             "router"
         ]
     },
+    {
+        "name": "symfony/deprecation-contracts",
+        "version": "v2.1.3",
+        "version_normalized": "2.1.3.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/deprecation-contracts.git",
+            "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14",
+            "reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.1"
+        },
+        "time": "2020-06-06T08:49:21+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.1-dev"
+            },
+            "thanks": {
+                "name": "symfony/contracts",
+                "url": "https://github.com/symfony/contracts"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "files": [
+                "function.php"
+            ]
+        },
+        "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": "A generic function and convention to trigger deprecation notices",
+        "homepage": "https://symfony.com"
+    },
+    {
+        "name": "symfony/finder",
+        "version": "v5.1.3",
+        "version_normalized": "5.1.3.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/finder.git",
+            "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/finder/zipball/4298870062bfc667cb78d2b379be4bf5dec5f187",
+            "reference": "4298870062bfc667cb78d2b379be4bf5dec5f187",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.2.5"
+        },
+        "time": "2020-05-20T17:43:50+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "5.1-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Component\\Finder\\": ""
+            },
+            "exclude-from-classmap": [
+                "/Tests/"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Fabien Potencier",
+                "email": "fabien@symfony.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Symfony Finder Component",
+        "homepage": "https://symfony.com"
+    },
+    {
+        "name": "symfony/polyfill-ctype",
+        "version": "v1.18.0",
+        "version_normalized": "1.18.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/polyfill-ctype.git",
+            "reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
+            "reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.3"
+        },
+        "suggest": {
+            "ext-ctype": "For best performance"
+        },
+        "time": "2020-07-14T12:35:20+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.18-dev"
+            },
+            "thanks": {
+                "name": "symfony/polyfill",
+                "url": "https://github.com/symfony/polyfill"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Polyfill\\Ctype\\": ""
+            },
+            "files": [
+                "bootstrap.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Gert de Pagter",
+                "email": "BackEndTea@gmail.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Symfony polyfill for ctype functions",
+        "homepage": "https://symfony.com",
+        "keywords": [
+            "compatibility",
+            "ctype",
+            "polyfill",
+            "portable"
+        ]
+    },
     {
         "name": "symfony/polyfill-mbstring",
         "version": "v1.14.0",
@@ -2019,6 +2321,71 @@
             "dump"
         ]
     },
+    {
+        "name": "symfony/yaml",
+        "version": "v5.1.3",
+        "version_normalized": "5.1.3.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/symfony/yaml.git",
+            "reference": "ea342353a3ef4f453809acc4ebc55382231d4d23"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/symfony/yaml/zipball/ea342353a3ef4f453809acc4ebc55382231d4d23",
+            "reference": "ea342353a3ef4f453809acc4ebc55382231d4d23",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.2.5",
+            "symfony/deprecation-contracts": "^2.1",
+            "symfony/polyfill-ctype": "~1.8"
+        },
+        "conflict": {
+            "symfony/console": "<4.4"
+        },
+        "require-dev": {
+            "symfony/console": "^4.4|^5.0"
+        },
+        "suggest": {
+            "symfony/console": "For validating YAML files using the lint command"
+        },
+        "time": "2020-05-20T17:43:50+00:00",
+        "bin": [
+            "Resources/bin/yaml-lint"
+        ],
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "5.1-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Symfony\\Component\\Yaml\\": ""
+            },
+            "exclude-from-classmap": [
+                "/Tests/"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Fabien Potencier",
+                "email": "fabien@symfony.com"
+            },
+            {
+                "name": "Symfony Community",
+                "homepage": "https://symfony.com/contributors"
+            }
+        ],
+        "description": "Symfony Yaml Component",
+        "homepage": "https://symfony.com"
+    },
     {
         "name": "tightenco/collect",
         "version": "v5.7.27",
@@ -2070,5 +2437,70 @@
             "collection",
             "laravel"
         ]
+    },
+    {
+        "name": "zircote/swagger-php",
+        "version": "3.0.4",
+        "version_normalized": "3.0.4.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/zircote/swagger-php.git",
+            "reference": "fa47d62c22c95272625624fbf8109fa46ffac43b"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/zircote/swagger-php/zipball/fa47d62c22c95272625624fbf8109fa46ffac43b",
+            "reference": "fa47d62c22c95272625624fbf8109fa46ffac43b",
+            "shasum": ""
+        },
+        "require": {
+            "doctrine/annotations": "*",
+            "php": ">=7.2",
+            "symfony/finder": ">=2.2",
+            "symfony/yaml": ">=3.3"
+        },
+        "require-dev": {
+            "phpunit/phpunit": ">=8",
+            "squizlabs/php_codesniffer": ">=3.3",
+            "zendframework/zend-form": "<2.8"
+        },
+        "time": "2020-05-07T09:10:49+00:00",
+        "bin": [
+            "bin/openapi"
+        ],
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "OpenApi\\": "src"
+            },
+            "files": [
+                "src/functions.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "Apache-2.0"
+        ],
+        "authors": [
+            {
+                "name": "Robert Allen",
+                "email": "zircote@gmail.com",
+                "homepage": "http://www.zircote.com"
+            },
+            {
+                "name": "Bob Fanger",
+                "email": "bfanger@gmail.com",
+                "homepage": "http://bfanger.nl"
+            }
+        ],
+        "description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations",
+        "homepage": "https://github.com/zircote/swagger-php/",
+        "keywords": [
+            "api",
+            "json",
+            "rest",
+            "service discovery"
+        ]
     }
 ]

+ 40 - 0
api/vendor/doctrine/annotations/.doctrine-project.json

@@ -0,0 +1,40 @@
+{
+    "active": true,
+    "name": "Annotations",
+    "slug": "annotations",
+    "docsSlug": "doctrine-annotations",
+    "versions": [
+        {
+            "name": "1.9",
+            "branchName": "1.9",
+            "slug": "1.9",
+            "aliases": [
+                "latest"
+            ],
+            "upcoming": true
+        },
+        {
+            "name": "1.8",
+            "branchName": "1.8",
+            "slug": "1.8",
+            "current": true,
+            "aliases": [
+                "current",
+                "stable"
+            ],
+            "maintained": true
+        },
+        {
+            "name": "1.7",
+            "branchName": "1.7",
+            "slug": "1.7",
+            "maintained": false
+        },
+        {
+            "name": "1.6",
+            "branchName": "1.6",
+            "slug": "1.6",
+            "maintained": false
+        }
+    ]
+}

+ 162 - 0
api/vendor/doctrine/annotations/CHANGELOG.md

@@ -0,0 +1,162 @@
+## Changelog
+
+### 1.6.1
+
+This release fixes an issue in which annotations such as `@foo-bar`
+and `@foo-` were incorrectly recognised as valid, and both erroneously
+parsed as `@foo`.
+
+Any annotation with `@name-*` format will now silently be ignored,
+allowing vendor-specific annotations to be prefixed with the tool
+name.
+
+Total issues resolved: **3**
+
+- [165: Update the composer branch alias](https://github.com/doctrine/annotations/pull/165) thanks to @mikeSimonson
+- [209: Change Annotation::value typehint to mixed](https://github.com/doctrine/annotations/pull/209) thanks to @malarzm
+- [257: Skip parsing annotations containing dashes, such as `@Foo-bar`, or `@Foo-`](https://github.com/doctrine/annotations/pull/257) thanks to @Ocramius
+
+### 1.6.0
+
+This release brings a new endpoint that make sure that you can't shoot yourself in the foot by calling ```registerLoader``` multiple times and a few tests improvements.
+
+Total issues resolved: **7**
+
+- [145: Memory leak in AnnotationRegistry::registerLoader() when called multiple times](https://github.com/doctrine/annotations/issues/145) thanks to @TriAnMan
+- [146: Import error on @experimental Annotation](https://github.com/doctrine/annotations/issues/146) thanks to @aturki
+- [147: Ignoring @experimental annotation used by Symfony 3.3 CacheAdapter](https://github.com/doctrine/annotations/pull/147) thanks to @aturki
+- [151: Remove duplicate code in `DCOM58Test`](https://github.com/doctrine/annotations/pull/151) thanks to @tuanphpvn
+- [161: Prevent loading class&#95;exists multiple times](https://github.com/doctrine/annotations/pull/161) thanks to @jrjohnson
+- [162: Add registerUniqueLoader to AnnotationRegistry](https://github.com/doctrine/annotations/pull/162) thanks to @jrjohnson
+- [163: Use assertDirectoryExists and assertDirectoryNotExists](https://github.com/doctrine/annotations/pull/163) thanks to @carusogabriel
+
+Thanks to everyone involved in this release.
+
+### 1.5.0
+
+This release increments the minimum supported PHP version to 7.1.0.
+
+Also, HHVM official support has been dropped.
+
+Some noticeable performance improvements to annotation autoloading
+have been applied, making failed annotation autoloading less heavy
+on the filesystem access.
+
+- [133: Add @throws annotation in AnnotationReader#__construct()](https://github.com/doctrine/annotations/issues/133) thanks to @SenseException
+- [134: Require PHP 7.1, drop HHVM support](https://github.com/doctrine/annotations/issues/134) thanks to @lcobucci
+- [135: Prevent the same loader from being registered twice](https://github.com/doctrine/annotations/issues/135)  thanks to @jrjohnson
+- [137: #135 optimise multiple class load attempts in AnnotationRegistry](https://github.com/doctrine/annotations/issues/137)  thanks to @Ocramius
+
+
+### 1.4.0
+
+This release fix an issue were some annotations could be not loaded if the namespace in the use statement started with a backslash.
+It also update the tests and drop the support for php 5.X
+
+- [115: Missing annotations with the latest composer version](https://github.com/doctrine/annotations/issues/115) thanks to @pascalporedda
+- [120: Missing annotations with the latest composer version](https://github.com/doctrine/annotations/pull/120) thanks to @gnat42
+- [121: Adding a more detailed explanation of the test](https://github.com/doctrine/annotations/pull/121) thanks to @mikeSimonson
+- [101: Test annotation parameters containing space](https://github.com/doctrine/annotations/pull/101) thanks to @mikeSimonson
+- [111: Cleanup: move to correct phpunit assertions](https://github.com/doctrine/annotations/pull/111) thanks to @Ocramius
+- [112: Removes support for PHP 5.x](https://github.com/doctrine/annotations/pull/112) thanks to @railto
+- [113: bumped phpunit version to 5.7](https://github.com/doctrine/annotations/pull/113) thanks to @gabbydgab
+- [114: Enhancement: Use SVG Travis build badge](https://github.com/doctrine/annotations/pull/114) thanks to @localheinz
+- [118: Integrating PHPStan](https://github.com/doctrine/annotations/pull/118) thanks to @ondrejmirtes
+
+### 1.3.1 - 2016-12-30
+
+This release fixes an issue with ignored annotations that were already
+autoloaded, causing the `SimpleAnnotationReader` to pick them up
+anyway. [#110](https://github.com/doctrine/annotations/pull/110)
+
+Additionally, an issue was fixed in the `CachedReader`, which was
+not correctly checking the freshness of cached annotations when
+traits were defined on a class. [#105](https://github.com/doctrine/annotations/pull/105)
+
+Total issues resolved: **2**
+
+- [105: Return single max timestamp](https://github.com/doctrine/annotations/pull/105)
+- [110: setIgnoreNotImportedAnnotations(true) didn&rsquo;t work for existing classes](https://github.com/doctrine/annotations/pull/110)
+
+### 1.3.0
+
+This release introduces a PHP version bump. `doctrine/annotations` now requires PHP
+5.6 or later to be installed.
+
+A series of additional improvements have been introduced:
+
+ * support for PHP 7 "grouped use statements"
+ * support for ignoring entire namespace names
+   via `Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredNamespace()` and
+   `Doctrine\Common\Annotations\DocParser::setIgnoredAnnotationNamespaces()`. This will
+   allow you to ignore annotations from namespaces that you cannot autoload
+ * testing all parent classes and interfaces when checking if the annotation cache
+   in the `CachedReader` is fresh
+ * simplifying the cache keys used by the `CachedReader`: keys are no longer artificially
+   namespaced, since `Doctrine\Common\Cache` already supports that
+ * corrected parsing of multibyte strings when `mbstring.func_overload` is enabled
+ * corrected parsing of annotations when `"\t"` is put before the first annotation
+   in a docblock
+ * allow skipping non-imported annotations when a custom `DocParser` is passed to
+   the `AnnotationReader` constructor
+
+Total issues resolved: **15**
+
+- [45: DocParser can now ignore whole namespaces](https://github.com/doctrine/annotations/pull/45)
+- [57: Switch to the docker-based infrastructure on Travis](https://github.com/doctrine/annotations/pull/57)
+- [59: opcache.load&#95;comments has been removed from PHP 7](https://github.com/doctrine/annotations/pull/59)
+- [62: &#91;CachedReader&#92; Test traits and parent class to see if cache is fresh](https://github.com/doctrine/annotations/pull/62)
+- [65: Remove cache salt making key unnecessarily long](https://github.com/doctrine/annotations/pull/65)
+- [66: Fix of incorrect parsing multibyte strings](https://github.com/doctrine/annotations/pull/66)
+- [68: Annotations that are indented by tab are not processed.](https://github.com/doctrine/annotations/issues/68)
+- [69: Support for Group Use Statements](https://github.com/doctrine/annotations/pull/69)
+- [70: Allow tab character before first annotation in DocBlock](https://github.com/doctrine/annotations/pull/70)
+- [74: Ignore not registered annotations fix](https://github.com/doctrine/annotations/pull/74)
+- [92: Added tests for AnnotationRegistry class.](https://github.com/doctrine/annotations/pull/92)
+- [96: Fix/#62 check trait and parent class ttl in annotations](https://github.com/doctrine/annotations/pull/96)
+- [97: Feature - #45 - allow ignoring entire namespaces](https://github.com/doctrine/annotations/pull/97)
+- [98: Enhancement/#65 remove cache salt from cached reader](https://github.com/doctrine/annotations/pull/98)
+- [99: Fix - #70 - allow tab character before first annotation in docblock](https://github.com/doctrine/annotations/pull/99)
+
+### 1.2.4
+
+Total issues resolved: **1**
+
+- [51: FileCacheReader::saveCacheFile::unlink fix](https://github.com/doctrine/annotations/pull/51)
+
+### 1.2.3
+
+Total issues resolved: [**2**](https://github.com/doctrine/annotations/milestones/v1.2.3)
+
+- [49: #46 - applying correct `chmod()` to generated cache file](https://github.com/doctrine/annotations/pull/49)
+- [50: Hotfix: match escaped quotes (revert #44)](https://github.com/doctrine/annotations/pull/50)
+
+### 1.2.2
+
+Total issues resolved: **4**
+
+- [43: Exclude files from distribution with .gitattributes](https://github.com/doctrine/annotations/pull/43)
+- [44: Update DocLexer.php](https://github.com/doctrine/annotations/pull/44)
+- [46: A plain &quot;file&#95;put&#95;contents&quot; can cause havoc](https://github.com/doctrine/annotations/pull/46)
+- [48: Deprecating the `FileCacheReader` in 1.2.2: will be removed in 2.0.0](https://github.com/doctrine/annotations/pull/48)
+
+### 1.2.1
+
+Total issues resolved: **4**
+
+- [38: fixes doctrine/common#326](https://github.com/doctrine/annotations/pull/38)
+- [39: Remove superfluous NS](https://github.com/doctrine/annotations/pull/39)
+- [41: Warn if load_comments is not enabled.](https://github.com/doctrine/annotations/pull/41)
+- [42: Clean up unused uses](https://github.com/doctrine/annotations/pull/42)
+
+### 1.2.0
+
+ * HHVM support
+ * Allowing dangling comma in annotations
+ * Excluded annotations are no longer autoloaded
+ * Importing namespaces also in traits
+ * Added support for `::class` 5.5-style constant, works also in 5.3 and 5.4
+
+### 1.1.0
+
+ * Add Exception when ZendOptimizer+ or Opcache is configured to drop comments

+ 19 - 0
api/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.

+ 17 - 0
api/vendor/doctrine/annotations/README.md

@@ -0,0 +1,17 @@
+# Doctrine Annotations
+
+[![Build Status](https://travis-ci.org/doctrine/annotations.svg?branch=master)](https://travis-ci.org/doctrine/annotations)
+[![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://poser.pugx.org/doctrine/annotations/v/stable.png)](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).
+
+## Changelog
+
+See [CHANGELOG.md](CHANGELOG.md).

+ 44 - 0
api/vendor/doctrine/annotations/composer.json

@@ -0,0 +1,44 @@
+{
+    "name": "doctrine/annotations",
+    "type": "library",
+    "description": "Docblock Annotations Parser",
+    "keywords": ["annotations", "docblock", "parser"],
+    "homepage": "http://www.doctrine-project.org",
+    "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"}
+    ],
+    "require": {
+        "php": "^7.1 || ^8.0",
+        "ext-tokenizer": "*",
+        "doctrine/lexer": "1.*"
+    },
+    "require-dev": {
+        "doctrine/cache": "1.*",
+        "phpunit/phpunit": "^7.5"
+    },
+    "config": {
+        "sort-packages": true
+    },
+    "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/SingleClassLOC1000.php"
+        ]
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.9.x-dev"
+        }
+    }
+}

+ 271 - 0
api/vendor/doctrine/annotations/docs/en/annotations.rst

@@ -0,0 +1,271 @@
+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\Validation\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 on a blacklist 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 blacklisted. 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.
+
+You can use a file caching reader, but please note it is deprecated to
+do so:
+
+.. code-block:: php
+
+    use Doctrine\Common\Annotations\FileCacheReader;
+    use Doctrine\Common\Annotations\AnnotationReader;
+
+    $reader = new FileCacheReader(
+        new AnnotationReader(),
+        "/path/to/cache",
+        $debug = true
+    );
+
+If you set the ``debug`` flag to ``true`` the cache reader will check
+for changes in the original files, which is very important during
+development. If you don't set it to ``true`` you have to delete the
+directory to clear the cache. This gives faster performance, however
+should only be used in production, because of its inconvenience during
+development.
+
+You can also use one of the ``Doctrine\Common\Cache\Cache`` cache
+implementations to cache the annotations:
+
+.. code-block:: php
+
+    use Doctrine\Common\Annotations\AnnotationReader;
+    use Doctrine\Common\Annotations\CachedReader;
+    use Doctrine\Common\Cache\ApcCache;
+
+    $reader = new CachedReader(
+        new AnnotationReader(),
+        new ApcCache(),
+        $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 blacklist 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);

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

@@ -0,0 +1,353 @@
+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;
+    }
+
+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
+-  ``ALL`` Allowed in class, property and method 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);

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

@@ -0,0 +1,97 @@
+Introduction
+============
+
+Doctrine Annotations allows to implement custom annotation
+functionality for PHP classes.
+
+.. 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
+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.
+
+:ref:`Read more about handling annotations. <annotations>`
+
+IDE Support
+-----------
+
+Some IDEs already provide support for annotations:
+
+- Eclipse via the `Symfony2 Plugin <http://symfony.dubture.com/>`_
+- PHPStorm via the `PHP Annotations Plugin <http://plugins.jetbrains.com/plugin/7320>`_ or the `Symfony2 Plugin <http://plugins.jetbrains.com/plugin/7219>`_
+
+.. _Read more about handling annotations.: annotations
+.. _Read more about custom annotations.: custom

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

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

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

@@ -0,0 +1,79 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * Annotations class.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
+ * @author Jonathan Wage <jonwage@gmail.com>
+ * @author Roman Borschel <roman@code-factory.org>
+ */
+class Annotation
+{
+    /**
+     * Value property. Common among all derived classes.
+     *
+     * @var string
+     */
+    public $value;
+
+    /**
+     * Constructor.
+     *
+     * @param array $data Key-value for properties to be defined in this class.
+     */
+    public final 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, get_class($this))
+        );
+    }
+
+    /**
+     * 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, get_class($this))
+        );
+    }
+}

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

@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check the attribute type during the parsing process.
+ *
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ *
+ * @Annotation
+ */
+final class Attribute
+{
+    /**
+     * @var string
+     */
+    public $name;
+
+    /**
+     * @var string
+     */
+    public $type;
+
+    /**
+     * @var boolean
+     */
+    public $required = false;
+}

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

@@ -0,0 +1,37 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+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.
+ *
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ *
+ * @Annotation
+ */
+final class Attributes
+{
+    /**
+     * @var array<Doctrine\Common\Annotations\Annotation\Attribute>
+     */
+    public $value;
+}

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

@@ -0,0 +1,84 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check the available values during the parsing process.
+ *
+ * @since  2.4
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ *
+ * @Annotation
+ * @Attributes({
+ *    @Attribute("value",   required = true,  type = "array"),
+ *    @Attribute("literal", required = false, type = "array")
+ * })
+ */
+final class Enum
+{
+    /**
+     * @var array
+     */
+    public $value;
+
+    /**
+     * Literal target declaration.
+     *
+     * @var array
+     */
+    public $literal;
+
+    /**
+     * Annotation constructor.
+     *
+     * @param array $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'];
+    }
+}

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

@@ -0,0 +1,54 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that can be used to signal to the parser to ignore specific
+ * annotations during the parsing process.
+ *
+ * @Annotation
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+final class IgnoreAnnotation
+{
+    /**
+     * @var array
+     */
+    public $names;
+
+    /**
+     * Constructor.
+     *
+     * @param array $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'];
+    }
+}

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

@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+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.
+ *
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ *
+ * @Annotation
+ */
+final class Required
+{
+}

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

@@ -0,0 +1,107 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations\Annotation;
+
+/**
+ * Annotation that can be used to signal to the parser
+ * to check the annotation target during the parsing process.
+ *
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ *
+ * @Annotation
+ */
+final class Target
+{
+    const TARGET_CLASS              = 1;
+    const TARGET_METHOD             = 2;
+    const TARGET_PROPERTY           = 4;
+    const TARGET_ANNOTATION         = 8;
+    const TARGET_ALL                = 15;
+
+    /**
+     * @var array
+     */
+    private static $map = [
+        'ALL'        => self::TARGET_ALL,
+        'CLASS'      => self::TARGET_CLASS,
+        'METHOD'     => self::TARGET_METHOD,
+        'PROPERTY'   => self::TARGET_PROPERTY,
+        'ANNOTATION' => self::TARGET_ANNOTATION,
+    ];
+
+    /**
+     * @var array
+     */
+    public $value;
+
+    /**
+     * Targets as bitmask.
+     *
+     * @var integer
+     */
+    public $targets;
+
+    /**
+     * Literal target declaration.
+     *
+     * @var integer
+     */
+    public $literal;
+
+    /**
+     * Annotation constructor.
+     *
+     * @param array $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);
+    }
+}

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

@@ -0,0 +1,197 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * Description of AnnotationException
+ *
+ * @since  2.0
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
+ * @author Jonathan Wage <jonwage@gmail.com>
+ * @author Roman Borschel <roman@code-factory.org>
+ */
+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.
+     *
+     * @since 2.2
+     *
+     * @param string $message
+     *
+     * @return AnnotationException
+     */
+    public static function creationError($message)
+    {
+        return new self('[Creation Error] ' . $message);
+    }
+
+    /**
+     * Creates a new AnnotationException describing a type error.
+     *
+     * @since 1.1
+     *
+     * @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.
+     *
+     * @since 2.3
+     *
+     * @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.
+     *
+     * @since 2.2
+     *
+     * @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.
+     *
+     * @since 2.2
+     *
+     * @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.
+     *
+     * @since 2.4
+     *
+     * @param string $attributeName
+     * @param string $annotationName
+     * @param string $context
+     * @param array  $available
+     * @param mixed  $given
+     *
+     * @return AnnotationException
+     */
+    public static function enumeratorError($attributeName, $annotationName, $context, $available, $given)
+    {
+        return new self(sprintf(
+            '[Enum Error] Attribute "%s" of @%s declared on %s accept 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."
+        );
+    }
+}

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

@@ -0,0 +1,418 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation;
+use Doctrine\Common\Annotations\Annotation\Target;
+use ReflectionClass;
+use ReflectionMethod;
+use ReflectionProperty;
+
+/**
+ * A reader for docblock annotations.
+ *
+ * @author  Benjamin Eberlei <kontakt@beberlei.de>
+ * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
+ * @author  Jonathan Wage <jonwage@gmail.com>
+ * @author  Roman Borschel <roman@code-factory.org>
+ * @author  Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class AnnotationReader implements Reader
+{
+    /**
+     * Global map for imports.
+     *
+     * @var array
+     */
+    private static $globalImports = [
+        'ignoreannotation' => 'Doctrine\Common\Annotations\Annotation\IgnoreAnnotation',
+    ];
+
+    /**
+     * A list with annotations that are not causing exceptions when not resolved to an annotation class.
+     *
+     * The names are case sensitive.
+     *
+     * @var array
+     */
+    private static $globalIgnoredNames = [
+        // Annotation tags
+        'Annotation' => true, 'Attribute' => true, 'Attributes' => true,
+        /* Can we enable this? 'Enum' => true, */
+        'Required' => true,
+        'Target' => true,
+        // Widely used tags (but not existent in phpdoc)
+        'fix' => true , 'fixme' => true,
+        'override' => true,
+        // PHPDocumentor 1 tags
+        'abstract'=> true, 'access'=> true,
+        'code' => true,
+        'deprec'=> true,
+        'endcode' => true, 'exception'=> true,
+        'final'=> true,
+        'ingroup' => true, 'inheritdoc'=> true, 'inheritDoc'=> true,
+        'magic' => true,
+        'name'=> true,
+        'toc' => true, 'tutorial'=> true,
+        'private' => true,
+        'static'=> true, 'staticvar'=> true, 'staticVar'=> true,
+        'throw' => true,
+        // PHPDocumentor 2 tags.
+        '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,
+        // PHPUnit tags
+        'codeCoverageIgnore' => true, 'codeCoverageIgnoreStart' => true, 'codeCoverageIgnoreEnd' => true,
+        // PHPCheckStyle
+        'SuppressWarnings' => true,
+        // PHPStorm
+        'noinspection' => true,
+        // PEAR
+        'package_version' => true,
+        // PlantUML
+        'startuml' => true, 'enduml' => true,
+        // Symfony 3.3 Cache Adapter
+        'experimental' => true,
+        // Slevomat Coding Standard
+        'phpcsSuppress' => true,
+        // PHP CodeSniffer
+        'codingStandardsIgnoreStart' => true,
+        'codingStandardsIgnoreEnd' => true,
+        // PHPStan
+        'template' => true, 'implements' => true, 'extends' => true, 'use' => true,
+    ];
+
+    /**
+     * A list with annotations that are not causing exceptions when not resolved to an annotation class.
+     *
+     * The names are case sensitive.
+     *
+     * @var array
+     */
+    private static $globalIgnoredNamespaces = [];
+
+    /**
+     * Add a new annotation to the globally ignored annotation names with regard to exception handling.
+     *
+     * @param string $name
+     */
+    static public 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
+     */
+    static public function addGlobalIgnoredNamespace($namespace)
+    {
+        self::$globalIgnoredNamespaces[$namespace] = true;
+    }
+
+    /**
+     * Annotations parser.
+     *
+     * @var \Doctrine\Common\Annotations\DocParser
+     */
+    private $parser;
+
+    /**
+     * Annotations parser used to collect parsing metadata.
+     *
+     * @var \Doctrine\Common\Annotations\DocParser
+     */
+    private $preParser;
+
+    /**
+     * PHP parser used to collect imports.
+     *
+     * @var \Doctrine\Common\Annotations\PhpParser
+     */
+    private $phpParser;
+
+    /**
+     * In-memory cache mechanism to store imported annotations per class.
+     *
+     * @var array
+     */
+    private $imports = [];
+
+    /**
+     * In-memory cache mechanism to store ignored annotations per class.
+     *
+     * @var array
+     */
+    private $ignoredAnnotationNames = [];
+
+    /**
+     * Constructor.
+     *
+     * Initializes a new AnnotationReader.
+     *
+     * @param DocParser $parser
+     *
+     * @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->getClassImports($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;
+    }
+
+    /**
+     * Returns the ignored annotations for the given class.
+     *
+     * @param \ReflectionClass $class
+     *
+     * @return array
+     */
+    private function getIgnoredAnnotationNames(ReflectionClass $class)
+    {
+        $name = $class->getName();
+        if (isset($this->ignoredAnnotationNames[$name])) {
+            return $this->ignoredAnnotationNames[$name];
+        }
+
+        $this->collectParsingMetadata($class);
+
+        return $this->ignoredAnnotationNames[$name];
+    }
+
+    /**
+     * Retrieves imports.
+     *
+     * @param \ReflectionClass $class
+     *
+     * @return array
+     */
+    private function getClassImports(ReflectionClass $class)
+    {
+        $name = $class->getName();
+        if (isset($this->imports[$name])) {
+            return $this->imports[$name];
+        }
+
+        $this->collectParsingMetadata($class);
+
+        return $this->imports[$name];
+    }
+
+    /**
+     * Retrieves imports for methods.
+     *
+     * @param \ReflectionMethod $method
+     *
+     * @return array
+     */
+    private function getMethodImports(ReflectionMethod $method)
+    {
+        $class = $method->getDeclaringClass();
+        $classImports = $this->getClassImports($class);
+
+        $traitImports = [];
+
+        foreach ($class->getTraits() as $trait) {
+            if ($trait->hasMethod($method->getName())
+                && $trait->getFileName() === $method->getFileName()
+            ) {
+                $traitImports = array_merge($traitImports, $this->phpParser->parseClass($trait));
+            }
+        }
+
+        return array_merge($classImports, $traitImports);
+    }
+
+    /**
+     * Retrieves imports for properties.
+     *
+     * @param \ReflectionProperty $property
+     *
+     * @return array
+     */
+    private function getPropertyImports(ReflectionProperty $property)
+    {
+        $class = $property->getDeclaringClass();
+        $classImports = $this->getClassImports($class);
+
+        $traitImports = [];
+
+        foreach ($class->getTraits() as $trait) {
+            if ($trait->hasProperty($property->getName())) {
+                $traitImports = array_merge($traitImports, $this->phpParser->parseClass($trait));
+            }
+        }
+
+        return array_merge($classImports, $traitImports);
+    }
+
+    /**
+     * Collects parsing metadata for a given class.
+     *
+     * @param \ReflectionClass $class
+     */
+    private function collectParsingMetadata(ReflectionClass $class)
+    {
+        $ignoredAnnotationNames = self::$globalIgnoredNames;
+        $annotations            = $this->preParser->parse($class->getDocComment(), 'class ' . $class->name);
+
+        foreach ($annotations as $annotation) {
+            if ($annotation instanceof IgnoreAnnotation) {
+                foreach ($annotation->names AS $annot) {
+                    $ignoredAnnotationNames[$annot] = true;
+                }
+            }
+        }
+
+        $name = $class->getName();
+
+        $this->imports[$name] = array_merge(
+            self::$globalImports,
+            $this->phpParser->parseClass($class),
+            ['__NAMESPACE__' => $class->getNamespaceName()]
+        );
+
+        $this->ignoredAnnotationNames[$name] = $ignoredAnnotationNames;
+    }
+}

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

@@ -0,0 +1,180 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+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[]
+     */
+    static private $autoloadNamespaces = [];
+
+    /**
+     * A map of autoloader callables.
+     *
+     * @var callable[]
+     */
+    static private $loaders = [];
+
+    /**
+     * An array of classes which cannot be found
+     *
+     * @var null[] indexed by class name
+     */
+    static private $failedToAutoload = [];
+
+    /**
+     * Whenever registerFile() was used. Disables use of standard autoloader.
+     *
+     * @var bool
+     */
+    static private $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.
+     *
+     * @param string            $namespace
+     * @param string|array|null $dirs
+     *
+     * @deprecated This method is deprecated and will be removed in doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
+     */
+    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.
+     *
+     * @param string[][]|string[]|null[] $namespaces indexed by namespace name
+     *
+     * @deprecated This method is deprecated and will be removed in doctrine/annotations 2.0. Annotations will be autoloaded in 2.0.
+     */
+    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) ) {
+            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) {
+                $file = \str_replace('\\', \DIRECTORY_SEPARATOR, $class) . '.php';
+
+                if ($dirs === null) {
+                    if ($path = stream_resolve_include_path($file)) {
+                        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;
+    }
+}

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

@@ -0,0 +1,278 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Cache\Cache;
+use ReflectionClass;
+
+/**
+ * A cache aware annotation reader.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+final class CachedReader implements Reader
+{
+    /**
+     * @var Reader
+     */
+    private $delegate;
+
+    /**
+     * @var Cache
+     */
+    private $cache;
+
+    /**
+     * @var boolean
+     */
+    private $debug;
+
+    /**
+     * @var array
+     */
+    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 = (boolean) $debug;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAnnotations(ReflectionClass $class)
+    {
+        $cacheKey = $class->getName();
+
+        if (isset($this->loadedAnnotations[$cacheKey])) {
+            return $this->loadedAnnotations[$cacheKey];
+        }
+
+        if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
+            $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];
+        }
+
+        if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
+            $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];
+        }
+
+        if (false === ($annots = $this->fetchFromCache($cacheKey, $class))) {
+            $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)
+    {
+        if (($data = $this->cache->fetch($cacheKey)) !== 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) {
+            $this->cache->save('[C]'.$cacheKey, time());
+        }
+    }
+
+    /**
+     * Checks if the cache is fresh.
+     *
+     * @param string $cacheKey
+     *
+     * @return boolean
+     */
+    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
+     *
+     * @return int
+     */
+    private function getLastModification(ReflectionClass $class)
+    {
+        $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([$this, 'getTraitLastModificationTime'], $class->getTraits()),
+            array_map([$this, 'getLastModification'], $class->getInterfaces()),
+            $parent ? [$this->getLastModification($parent)] : []
+        ));
+
+        assert($lastModification !== false);
+
+        return $this->loadedFilemtimes[$filename] = $lastModification;
+    }
+
+    /**
+     * @return int
+     */
+    private function getTraitLastModificationTime(ReflectionClass $reflectionTrait)
+    {
+        $fileName = $reflectionTrait->getFileName();
+
+        if (isset($this->loadedFilemtimes[$fileName])) {
+            return $this->loadedFilemtimes[$fileName];
+        }
+
+        $lastModificationTime = max(array_merge(
+            [$fileName ? filemtime($fileName) : 0],
+            array_map([$this, 'getTraitLastModificationTime'], $reflectionTrait->getTraits())
+        ));
+
+        assert($lastModificationTime !== false);
+
+        return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
+    }
+}

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

@@ -0,0 +1,147 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Lexer\AbstractLexer;
+
+/**
+ * Simple lexer for docblock annotations.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
+ * @author Jonathan Wage <jonwage@gmail.com>
+ * @author Roman Borschel <roman@code-factory.org>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+final class DocLexer extends AbstractLexer
+{
+    const T_NONE                = 1;
+    const T_INTEGER             = 2;
+    const T_STRING              = 3;
+    const T_FLOAT               = 4;
+
+    // All tokens that are also identifiers should be >= 100
+    const T_IDENTIFIER          = 100;
+    const T_AT                  = 101;
+    const T_CLOSE_CURLY_BRACES  = 102;
+    const T_CLOSE_PARENTHESIS   = 103;
+    const T_COMMA               = 104;
+    const T_EQUALS              = 105;
+    const T_FALSE               = 106;
+    const T_NAMESPACE_SEPARATOR = 107;
+    const T_OPEN_CURLY_BRACES   = 108;
+    const T_OPEN_PARENTHESIS    = 109;
+    const T_TRUE                = 110;
+    const T_NULL                = 111;
+    const T_COLON               = 112;
+    const T_MINUS               = 113;
+
+    /**
+     * @var array
+     */
+    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
+     */
+    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;
+    }
+}

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

@@ -0,0 +1,1221 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+use Doctrine\Common\Annotations\Annotation\Attribute;
+use ReflectionClass;
+use Doctrine\Common\Annotations\Annotation\Enum;
+use Doctrine\Common\Annotations\Annotation\Target;
+use Doctrine\Common\Annotations\Annotation\Attributes;
+
+/**
+ * A parser for docblock annotations.
+ *
+ * It is strongly discouraged to change the default annotation parsing process.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
+ * @author Jonathan Wage <jonwage@gmail.com>
+ * @author Roman Borschel <roman@code-factory.org>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ */
+final class DocParser
+{
+    /**
+     * An array of all valid tokens for a class name.
+     *
+     * @var array
+     */
+    private static $classIdentifiers = [
+        DocLexer::T_IDENTIFIER,
+        DocLexer::T_TRUE,
+        DocLexer::T_FALSE,
+        DocLexer::T_NULL
+    ];
+
+    /**
+     * The lexer.
+     *
+     * @var \Doctrine\Common\Annotations\DocLexer
+     */
+    private $lexer;
+
+    /**
+     * Current target context.
+     *
+     * @var integer
+     */
+    private $target;
+
+    /**
+     * Doc parser used to collect annotation target.
+     *
+     * @var \Doctrine\Common\Annotations\DocParser
+     */
+    private static $metadataParser;
+
+    /**
+     * Flag to control if the current annotation is nested or not.
+     *
+     * @var boolean
+     */
+    private $isNestedAnnotation = false;
+
+    /**
+     * Hashmap containing all use-statements that are to be used when parsing
+     * the given doc block.
+     *
+     * @var array
+     */
+    private $imports = [];
+
+    /**
+     * This hashmap is used internally to cache results of class_exists()
+     * look-ups.
+     *
+     * @var array
+     */
+    private $classExists = [];
+
+    /**
+     * Whether annotations that have not been imported should be ignored.
+     *
+     * @var boolean
+     */
+    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
+     * class names.
+     *
+     * @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
+     */
+    private static $annotationMetadata = [
+        'Doctrine\Common\Annotations\Annotation\Target' => [
+            'is_annotation'    => true,
+            'has_constructor'  => true,
+            '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>'
+                ]
+             ],
+        ],
+        'Doctrine\Common\Annotations\Annotation\Attribute' => [
+            'is_annotation'    => true,
+            'has_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'
+                ]
+             ],
+        ],
+        'Doctrine\Common\Annotations\Annotation\Attributes' => [
+            'is_annotation'    => true,
+            'has_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'=>'Doctrine\Common\Annotations\Annotation\Attribute',
+                    'value'     =>'array<Doctrine\Common\Annotations\Annotation\Attribute>'
+                ]
+             ],
+        ],
+        'Doctrine\Common\Annotations\Annotation\Enum' => [
+            'is_annotation'    => true,
+            'has_constructor'  => true,
+            '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,
+                ],
+             ],
+        ],
+    ];
+
+    /**
+     * Hash-map for handle types declaration.
+     *
+     * @var array
+     */
+    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 boolean $bool
+     *
+     * @return void
+     */
+    public function setIgnoreNotImportedAnnotations($bool)
+    {
+        $this->ignoreNotImportedAnnotations = (boolean) $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 $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 integer $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.
+     *
+     * @return array Array of annotations. If no annotations are found, an empty array is returned.
+     */
+    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
+     *
+     * @return int|null
+     */
+    private function findInitialTokenPosition($input)
+    {
+        $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 integer $token Type of token.
+     *
+     * @return boolean True if tokens match; false otherwise.
+     */
+    private function match($token)
+    {
+        if ( ! $this->lexer->isNextToken($token) ) {
+            $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.
+     *
+     * @param array $tokens
+     *
+     * @return boolean
+     */
+    private function matchAny(array $tokens)
+    {
+        if ( ! $this->lexer->isNextTokenAny($tokens)) {
+            $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 array|null $token    Optional token.
+     *
+     * @return void
+     *
+     * @throws AnnotationException
+     */
+    private function syntaxError($expected, $token = null)
+    {
+        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 .= '.';
+
+        throw 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 string $fqcn
+     *
+     * @return boolean
+     */
+    private function classExists($fqcn)
+    {
+        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 string $name The annotation name
+     *
+     * @return void
+     */
+    private function collectAnnotationMetadata($name)
+    {
+        if (self::$metadataParser === null) {
+            self::$metadataParser = new self();
+
+            self::$metadataParser->setIgnoreNotImportedAnnotations(true);
+            self::$metadataParser->setIgnoredAnnotationNames($this->ignoredAnnotationNames);
+            self::$metadataParser->setImports([
+                'enum'          => 'Doctrine\Common\Annotations\Annotation\Enum',
+                'target'        => 'Doctrine\Common\Annotations\Annotation\Target',
+                'attribute'     => 'Doctrine\Common\Annotations\Annotation\Attribute',
+                'attributes'    => 'Doctrine\Common\Annotations\Annotation\Attributes'
+            ]);
+
+            // 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      = new \ReflectionClass($name);
+        $docComment = $class->getDocComment();
+
+        // Sets default values for annotation metadata
+        $metadata = [
+            'default_property' => null,
+            'has_constructor'  => (null !== $constructor = $class->getConstructor()) && $constructor->getNumberOfParameters() > 0,
+            'properties'       => [],
+            'property_types'   => [],
+            'attribute_types'  => [],
+            'targets_literal'  => null,
+            'targets'          => Target::TARGET_ALL,
+            'is_annotation'    => false !== strpos($docComment, '@Annotation'),
+        ];
+
+        // 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 Attributes) {
+                    foreach ($annotation->value as $attribute) {
+                        $this->collectAttributeTypeMetadata($metadata, $attribute);
+                    }
+                }
+            }
+
+            // if not has a constructor will inject values into public properties
+            if (false === $metadata['has_constructor']) {
+                // collect all public properties
+                foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
+                    $metadata['properties'][$property->name] = $property->name;
+
+                    if (false === ($propertyComment = $property->getDocComment())) {
+                        continue;
+                    }
+
+                    $attribute = new Attribute();
+
+                    $attribute->required = (false !== strpos($propertyComment, '@Required'));
+                    $attribute->name     = $property->name;
+                    $attribute->type     = (false !== strpos($propertyComment, '@var') && preg_match('/@var\s+([^\s]+)/',$propertyComment, $matches))
+                        ? $matches[1]
+                        : 'mixed';
+
+                    $this->collectAttributeTypeMetadata($metadata, $attribute);
+
+                    // checks if the property has @Enum
+                    if (false !== strpos($propertyComment, '@Enum')) {
+                        $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']);
+            }
+        }
+
+        self::$annotationMetadata[$name] = $metadata;
+    }
+
+    /**
+     * Collects parsing metadata for a given attribute.
+     *
+     * @param array     $metadata
+     * @param Attribute $attribute
+     *
+     * @return void
+     */
+    private function collectAttributeTypeMetadata(&$metadata, Attribute $attribute)
+    {
+        // handle internal type declaration
+        $type = self::$typeMap[$attribute->type] ?? $attribute->type;
+
+        // handle the case if the property type is mixed
+        if ('mixed' === $type) {
+            return;
+        }
+
+        // Evaluate type
+        switch (true) {
+            // Checks if the property has array<type>
+            case (false !== $pos = strpos($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;
+                break;
+
+            // Checks if the property has type[]
+            case (false !== $pos = strrpos($type, '[')):
+                $arrayType  = substr($type, 0, $pos);
+                $type       = 'array';
+
+                if (isset(self::$typeMap[$arrayType])) {
+                    $arrayType = self::$typeMap[$arrayType];
+                }
+
+                $metadata['attribute_types'][$attribute->name]['array_type'] = $arrayType;
+                break;
+        }
+
+        $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]}*
+     *
+     * @return array
+     */
+    private function Annotations()
+    {
+        $annotations = [];
+
+        while (null !== $this->lexer->lookahead) {
+            if (DocLexer::T_AT !== $this->lexer->lookahead['type']) {
+                $this->lexer->moveNext();
+                continue;
+            }
+
+            // make sure the @ is preceded by non-catchable pattern
+            if (null !== $this->lexer->token && $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
+            if ((null === $peek = $this->lexer->glimpse())
+                || (DocLexer::T_NAMESPACE_SEPARATOR !== $peek['type'] && !in_array($peek['type'], self::$classIdentifiers, true))
+                || $peek['position'] !== $this->lexer->lookahead['position'] + 1) {
+                $this->lexer->moveNext();
+                continue;
+            }
+
+            $this->isNestedAnnotation = false;
+            if (false !== $annot = $this->Annotation()) {
+                $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 mixed False if it is not a valid annotation.
+     *
+     * @throws AnnotationException
+     */
+    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 = (false === $pos)? $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 = (false !== $pos)
+                    ? $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('The annotation "@%s" in %s was never imported. Did you maybe forget to add a "use" statement for this annotation?', $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('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.', $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 (0 === (self::$annotationMetadata[$name]['targets'] & $target) && $target) {
+            throw AnnotationException::semanticalError(
+                sprintf('Annotation @%s is not allowed to be declared on %s. You may only use this annotation on these code elements: %s.',
+                     $originalName, $this->context, self::$annotationMetadata[$name]['targets_literal'])
+            );
+        }
+
+        $values = $this->MethodCall();
+
+        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]);
+            }
+        }
+
+        // check if the annotation expects values via the constructor,
+        // or directly injected into public properties
+        if (self::$annotationMetadata[$name]['has_constructor'] === true) {
+            return new $name($values);
+        }
+
+        $instance = new $name();
+
+        foreach ($values as $property => $value) {
+            if (!isset(self::$annotationMetadata[$name]['properties'][$property])) {
+                if ('value' !== $property) {
+                    throw AnnotationException::creationError(sprintf('The annotation @%s declared on %s does not have a property named "%s". Available properties: %s', $originalName, $this->context, $property, implode(', ', self::$annotationMetadata[$name]['properties'])));
+                }
+
+                // handle the case if the property has no annotations
+                if ( ! $property = self::$annotationMetadata[$name]['default_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 array
+     */
+    private function MethodCall()
+    {
+        $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 array
+     */
+    private function Values()
+    {
+        $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();
+
+            if ( ! is_object($value) && ! is_array($value)) {
+                $this->syntaxError('Value', $token);
+            }
+
+            $values[] = $value;
+        }
+
+        foreach ($values as $k => $value) {
+            if (is_object($value) && $value instanceof \stdClass) {
+                $values[$value->name] = $value->value;
+            } else if ( ! isset($values['value'])){
+                $values['value'] = $value;
+            } else {
+                if ( ! is_array($values['value'])) {
+                    $values['value'] = [$values['value']];
+                }
+
+                $values['value'][] = $value;
+            }
+
+            unset($values[$k]);
+        }
+
+        return $values;
+    }
+
+    /**
+     * Constant ::= integer | string | float | boolean
+     *
+     * @return mixed
+     *
+     * @throws AnnotationException
+     */
+    private function Constant()
+    {
+        $identifier = $this->Identifier();
+
+        if ( ! defined($identifier) && false !== strpos($identifier, '::') && '\\' !== $identifier[0]) {
+            list($className, $const) = explode('::', $identifier);
+
+            $pos = strpos($className, '\\');
+            $alias = (false === $pos) ? $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 = (false !== $pos)
+                        ? $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
+     *
+     * @return string
+     */
+    private function Identifier()
+    {
+        // check if we have an annotation
+        if ( ! $this->lexer->isNextTokenAny(self::$classIdentifiers)) {
+            $this->syntaxError('namespace separator or identifier');
+        }
+
+        $this->lexer->moveNext();
+
+        $className = $this->lexer->token['value'];
+
+        while (
+            null !== $this->lexer->lookahead &&
+            $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
+     */
+    private function Value()
+    {
+        $peek = $this->lexer->glimpse();
+
+        if (DocLexer::T_EQUALS === $peek['type']) {
+            return $this->FieldAssignment();
+        }
+
+        return $this->PlainValue();
+    }
+
+    /**
+     * PlainValue ::= integer | string | float | boolean | Array | Annotation
+     *
+     * @return mixed
+     */
+    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:
+                $this->syntaxError('PlainValue');
+        }
+    }
+
+    /**
+     * FieldAssignment ::= FieldName "=" PlainValue
+     * FieldName ::= identifier
+     *
+     * @return \stdClass
+     */
+    private function FieldAssignment()
+    {
+        $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 array
+     */
+    private function Arrayx()
+    {
+        $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) {
+            list ($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
+     *
+     * @return array
+     */
+    private function ArrayEntry()
+    {
+        $peek = $this->lexer->glimpse();
+
+        if (DocLexer::T_EQUALS === $peek['type']
+                || DocLexer::T_COLON === $peek['type']) {
+
+            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
+     *
+     * @param string $name
+     *
+     * @return bool
+     */
+    private function isIgnoredAnnotation($name)
+    {
+        if ($this->ignoreNotImportedAnnotations || isset($this->ignoredAnnotationNames[$name])) {
+            return true;
+        }
+
+        foreach (array_keys($this->ignoredAnnotationNamespaces) as $ignoredAnnotationNamespace) {
+            $ignoredAnnotationNamespace = rtrim($ignoredAnnotationNamespace, '\\') . '\\';
+
+            if (0 === stripos(rtrim($name, '\\') . '\\', $ignoredAnnotationNamespace)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}

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

@@ -0,0 +1,290 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * File cache reader for annotations.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ *
+ * @deprecated the FileCacheReader is deprecated and will be removed
+ *             in version 2.0.0 of doctrine/annotations. Please use the
+ *             {@see \Doctrine\Common\Annotations\CachedReader} instead.
+ */
+class FileCacheReader implements Reader
+{
+    /**
+     * @var Reader
+     */
+    private $reader;
+
+    /**
+     * @var string
+     */
+    private $dir;
+
+    /**
+     * @var bool
+     */
+    private $debug;
+
+    /**
+     * @var array
+     */
+    private $loadedAnnotations = [];
+
+    /**
+     * @var array
+     */
+    private $classNameHashes = [];
+
+    /**
+     * @var int
+     */
+    private $umask;
+
+    /**
+     * Constructor.
+     *
+     * @param Reader  $reader
+     * @param string  $cacheDir
+     * @param boolean $debug
+     *
+     * @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;
+        }
+
+        if ($this->debug
+            && (false !== $filename = $class->getFileName())
+            && 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;
+        }
+
+        if ($this->debug
+            && (false !== $filename = $class->getFilename())
+            && 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;
+        }
+
+        if ($this->debug
+            && (false !== $filename = $class->getFilename())
+            && 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('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.', $this->dir));
+        }
+
+        $tempfile = tempnam($this->dir, uniqid('', true));
+
+        if (false === $tempfile) {
+            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 (false === $written) {
+            throw new \RuntimeException(sprintf('Unable to write cached file to: %s', $tempfile));
+        }
+
+        @chmod($tempfile, 0666 & (~$this->umask));
+
+        if (false === rename($tempfile, $path)) {
+            @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 = [];
+    }
+}

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

@@ -0,0 +1,119 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * Allows the reader to be used in-place of Doctrine's reader.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class IndexedReader implements Reader
+{
+    /**
+     * @var Reader
+     */
+    private $delegate;
+
+    /**
+     * Constructor.
+     *
+     * @param Reader $reader
+     */
+    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, $annotation)
+    {
+        return $this->delegate->getClassAnnotation($class, $annotation);
+    }
+
+    /**
+     * {@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, $annotation)
+    {
+        return $this->delegate->getMethodAnnotation($method, $annotation);
+    }
+
+    /**
+     * {@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, $annotation)
+    {
+        return $this->delegate->getPropertyAnnotation($property, $annotation);
+    }
+
+    /**
+     * Proxies all methods to the delegate.
+     *
+     * @param string $method
+     * @param array  $args
+     *
+     * @return mixed
+     */
+    public function __call($method, $args)
+    {
+        return call_user_func_array([$this->delegate, $method], $args);
+    }
+}

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

@@ -0,0 +1,91 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+use SplFileObject;
+
+/**
+ * Parses a file for namespaces/use/class declarations.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Christian Kaps <christian.kaps@mohiva.com>
+ */
+final class PhpParser
+{
+    /**
+     * Parses a class.
+     *
+     * @param \ReflectionClass $class A <code>ReflectionClass</code> object.
+     *
+     * @return array A list with use statements in the form (Alias => FQN).
+     */
+    public function parseClass(\ReflectionClass $class)
+    {
+        if (method_exists($class, 'getUseStatements')) {
+            return $class->getUseStatements();
+        }
+
+        if (false === $filename = $class->getFileName()) {
+            return [];
+        }
+
+        $content = $this->getFileContent($filename, $class->getStartLine());
+
+        if (null === $content) {
+            return [];
+        }
+
+        $namespace = preg_quote($class->getNamespaceName());
+        $content = preg_replace('/^.*?(\bnamespace\s+' . $namespace . '\s*[;{].*)$/s', '\\1', $content);
+        $tokenizer = new TokenParser('<?php ' . $content);
+
+        $statements = $tokenizer->parseUseStatements($class->getNamespaceName());
+
+        return $statements;
+    }
+
+    /**
+     * Gets the content of the file right up to the given line number.
+     *
+     * @param string  $filename   The name of the file to load.
+     * @param integer $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;
+    }
+}

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

@@ -0,0 +1,89 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * Interface for annotation readers.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+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 An array of Annotations.
+     */
+    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 string           $annotationName The name of the annotation.
+     *
+     * @return object|null The Annotation or NULL, if the requested annotation does not exist.
+     */
+    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 An array of Annotations.
+     */
+    function getMethodAnnotations(\ReflectionMethod $method);
+
+    /**
+     * Gets a method annotation.
+     *
+     * @param \ReflectionMethod $method         The ReflectionMethod to read the annotations from.
+     * @param string            $annotationName The name of the annotation.
+     *
+     * @return object|null The Annotation or NULL, if the requested annotation does not exist.
+     */
+    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 An array of Annotations.
+     */
+    function getPropertyAnnotations(\ReflectionProperty $property);
+
+    /**
+     * Gets a property annotation.
+     *
+     * @param \ReflectionProperty $property       The ReflectionProperty to read the annotations from.
+     * @param string              $annotationName The name of the annotation.
+     *
+     * @return object|null The Annotation or NULL, if the requested annotation does not exist.
+     */
+    function getPropertyAnnotation(\ReflectionProperty $property, $annotationName);
+}

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

@@ -0,0 +1,127 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * Simple Annotation Reader.
+ *
+ * This annotation reader is intended to be used in projects where you have
+ * full-control over all annotations that are available.
+ *
+ * @since  2.2
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Fabio B. Silva <fabio.bat.silva@gmail.com>
+ */
+class SimpleAnnotationReader implements Reader
+{
+    /**
+     * @var DocParser
+     */
+    private $parser;
+
+    /**
+     * Constructor.
+     *
+     * 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;
+    }
+}

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

@@ -0,0 +1,194 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Common\Annotations;
+
+/**
+ * Parses a file for namespaces/use/class declarations.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Christian Kaps <christian.kaps@mohiva.com>
+ */
+class TokenParser
+{
+    /**
+     * The token list.
+     *
+     * @var array
+     */
+    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 boolean $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped.
+     *                                     If FALSE then only whitespace and normal comments are skipped.
+     *
+     * @return array|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 A list with all found class names for a use statement.
+     */
+    public function parseUseStatement()
+    {
+
+        $groupRoot = '';
+        $class = '';
+        $alias = '';
+        $statements = [];
+        $explicitAlias = false;
+        while (($token = $this->next())) {
+            $isNameToken = $token[0] === T_STRING || $token[0] === T_NS_SEPARATOR;
+            if (!$explicitAlias && $isNameToken) {
+                $class .= $token[1];
+                $alias = $token[1];
+            } else if ($explicitAlias && $isNameToken) {
+                $alias .= $token[1];
+            } else if ($token[0] === T_AS) {
+                $explicitAlias = true;
+                $alias = '';
+            } else if ($token === ',') {
+                $statements[strtolower($alias)] = $groupRoot . $class;
+                $class = '';
+                $alias = '';
+                $explicitAlias = false;
+            } else if ($token === ';') {
+                $statements[strtolower($alias)] = $groupRoot . $class;
+                break;
+            } else if ($token === '{' ) {
+                $groupRoot = $class;
+                $class = '';
+            } else if ($token === '}' ) {
+                continue;
+            } else {
+                break;
+            }
+        }
+
+        return $statements;
+    }
+
+    /**
+     * Gets all use statements.
+     *
+     * @param string $namespaceName The namespace name of the reflected class.
+     *
+     * @return array 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)) {
+            $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();
+    }
+}

+ 4 - 0
api/vendor/doctrine/annotations/phpbench.json.dist

@@ -0,0 +1,4 @@
+{
+    "bootstrap": "tests/Doctrine/Performance/Common/bootstrap.php",
+    "path": "tests/Doctrine/Performance/Common/Annotations"
+}

+ 14 - 0
api/vendor/doctrine/annotations/phpstan.neon

@@ -0,0 +1,14 @@
+parameters:
+    autoload_files:
+        - %currentWorkingDirectory%/tests/Doctrine/Tests/Common/Annotations/DocParserTest.php
+    excludes_analyse:
+        - %currentWorkingDirectory%/tests/*/Fixtures/*
+        - %currentWorkingDirectory%/tests/Doctrine/Tests/Common/Annotations/ReservedKeywordsClasses.php
+        - %currentWorkingDirectory%/tests/Doctrine/Tests/Common/Annotations/Ticket/DCOM58Entity.php
+        - %currentWorkingDirectory%/tests/Doctrine/Tests/DoctrineTestCase.php
+    polluteScopeWithLoopInitialAssignments: true
+    ignoreErrors:
+        - '#Class Doctrine_Tests_Common_Annotations_Fixtures_ClassNoNamespaceNoComment not found#'
+        - '#Instantiated class Doctrine_Tests_Common_Annotations_Fixtures_ClassNoNamespaceNoComment not found#'
+        - '#Property Doctrine\\Tests\\Common\\Annotations\\DummyClassNonAnnotationProblem::\$foo has unknown class#'
+        - '#Call to an undefined method ReflectionClass::getUseStatements\(\)#'

+ 19 - 0
api/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
api/vendor/doctrine/lexer/README.md

@@ -0,0 +1,9 @@
+# Doctrine Lexer
+
+Build Status: [![Build Status](https://travis-ci.org/doctrine/lexer.svg?branch=master)](https://travis-ci.org/doctrine/lexer)
+
+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

+ 41 - 0
api/vendor/doctrine/lexer/composer.json

@@ -0,0 +1,41 @@
+{
+    "name": "doctrine/lexer",
+    "type": "library",
+    "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
+    "keywords": [
+        "php",
+        "parser",
+        "lexer",
+        "annotations",
+        "docblock"
+    ],
+    "homepage": "https://www.doctrine-project.org/projects/lexer.html",
+    "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"}
+    ],
+    "require": {
+        "php": "^7.2 || ^8.0"
+    },
+    "require-dev": {
+        "doctrine/coding-standard": "^6.0",
+        "phpstan/phpstan": "^0.11.8",
+        "phpunit/phpunit": "^8.2"
+    },
+    "autoload": {
+        "psr-4": { "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" }
+    },
+    "autoload-dev": {
+        "psr-4": { "Doctrine\\Tests\\": "tests/Doctrine" }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.2.x-dev"
+        }
+    },
+    "config": {
+        "sort-packages": true
+    }
+}

+ 328 - 0
api/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php

@@ -0,0 +1,328 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Doctrine\Common\Lexer;
+
+use ReflectionClass;
+use const PREG_SPLIT_DELIM_CAPTURE;
+use const PREG_SPLIT_NO_EMPTY;
+use const PREG_SPLIT_OFFSET_CAPTURE;
+use function implode;
+use function in_array;
+use function preg_split;
+use function sprintf;
+use function substr;
+
+/**
+ * Base class for writing simple lexers, i.e. for creating small DSLs.
+ */
+abstract class AbstractLexer
+{
+    /**
+     * Lexer original input string.
+     *
+     * @var string
+     */
+    private $input;
+
+    /**
+     * Array of scanned tokens.
+     *
+     * Each token is an associative array containing three items:
+     *  - 'value'    : the string value of the token in the input string
+     *  - 'type'     : the type of the token (identifier, numeric, string, input
+     *                 parameter, none)
+     *  - 'position' : the position of the token in the input string
+     *
+     * @var array
+     */
+    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 array|null
+     */
+    public $lookahead;
+
+    /**
+     * The last matched/seen token.
+     *
+     * @var array|null
+     */
+    public $token;
+
+    /**
+     * Composed regex for input parsing.
+     *
+     * @var string
+     */
+    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 int|string $token
+     *
+     * @return bool
+     */
+    public function isNextToken($token)
+    {
+        return $this->lookahead !== null && $this->lookahead['type'] === $token;
+    }
+
+    /**
+     * Checks whether any of the given tokens matches the current lookahead.
+     *
+     * @param array $tokens
+     *
+     * @return bool
+     */
+    public function isNextTokenAny(array $tokens)
+    {
+        return $this->lookahead !== null && in_array($this->lookahead['type'], $tokens, true);
+    }
+
+    /**
+     * Moves to the next token in the input string.
+     *
+     * @return bool
+     */
+    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 string $type The token type to skip until.
+     *
+     * @return void
+     */
+    public function skipUntil($type)
+    {
+        while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
+            $this->moveNext();
+        }
+    }
+
+    /**
+     * Checks if given value is identical to the given token.
+     *
+     * @param mixed      $value
+     * @param int|string $token
+     *
+     * @return bool
+     */
+    public function isA($value, $token)
+    {
+        return $this->getType($value) === $token;
+    }
+
+    /**
+     * Moves the lookahead token forward.
+     *
+     * @return array|null The next token or NULL if there are no more tokens ahead.
+     */
+    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 array|null The next token or NULL if there are no more tokens ahead.
+     */
+    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
+            $type = $this->getType($match[0]);
+
+            $this->tokens[] = [
+                'value' => $match[0],
+                'type'  => $type,
+                'position' => $match[1],
+            ];
+        }
+    }
+
+    /**
+     * Gets the literal for a given token.
+     *
+     * @param int|string $token
+     *
+     * @return int|string
+     */
+    public function getLiteral($token)
+    {
+        $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 array
+     */
+    abstract protected function getCatchablePatterns();
+
+    /**
+     * Lexical non-catchable patterns.
+     *
+     * @return array
+     */
+    abstract protected function getNonCatchablePatterns();
+
+    /**
+     * Retrieve token type. Also processes the token value if necessary.
+     *
+     * @param string $value
+     *
+     * @return int|string|null
+     */
+    abstract protected function getType(&$value);
+}

+ 3 - 0
api/vendor/symfony/deprecation-contracts/.gitignore

@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml

+ 5 - 0
api/vendor/symfony/deprecation-contracts/CHANGELOG.md

@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/master/CHANGELOG.md

+ 19 - 0
api/vendor/symfony/deprecation-contracts/LICENSE

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

+ 26 - 0
api/vendor/symfony/deprecation-contracts/README.md

@@ -0,0 +1,26 @@
+Symfony Deprecation Contracts
+=============================
+
+A generic function and convention to trigger deprecation notices.
+
+This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices.
+
+By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,
+the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.
+
+The function requires at least 3 arguments:
+ - the name of the Composer package that is triggering the deprecation
+ - the version of the package that introduced the deprecation
+ - the message of the deprecation
+ - more arguments can be provided: they will be inserted in the message using `printf()` formatting
+
+Example:
+```php
+trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin');
+```
+
+This will generate the following message:
+`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.`
+
+While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty
+`function trigger_deprecation() {}` in your application.

+ 35 - 0
api/vendor/symfony/deprecation-contracts/composer.json

@@ -0,0 +1,35 @@
+{
+    "name": "symfony/deprecation-contracts",
+    "type": "library",
+    "description": "A generic function and convention to trigger deprecation notices",
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "p@tchwork.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.1"
+    },
+    "autoload": {
+        "files": [
+            "function.php"
+        ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.1-dev"
+        },
+        "thanks": {
+            "name": "symfony/contracts",
+            "url": "https://github.com/symfony/contracts"
+        }
+    }
+}

+ 27 - 0
api/vendor/symfony/deprecation-contracts/function.php

@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (!function_exists('trigger_deprecation')) {
+    /**
+     * Triggers a silenced deprecation notice.
+     *
+     * @param string $package The name of the Composer package that is triggering the deprecation
+     * @param string $version The version of the package that introduced the deprecation
+     * @param string $message The message of the deprecation
+     * @param mixed  ...$args Values to insert in the message using printf() formatting
+     *
+     * @author Nicolas Grekas <p@tchwork.com>
+     */
+    function trigger_deprecation(string $package, string $version, string $message, ...$args): void
+    {
+        @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), E_USER_DEPRECATED);
+    }
+}

+ 79 - 0
api/vendor/symfony/finder/CHANGELOG.md

@@ -0,0 +1,79 @@
+CHANGELOG
+=========
+
+5.0.0
+-----
+
+ * added `$useNaturalSort` argument to `Finder::sortByName()`
+
+4.3.0
+-----
+
+ * added Finder::ignoreVCSIgnored() to ignore files based on rules listed in .gitignore
+
+4.2.0
+-----
+
+ * added $useNaturalSort option to Finder::sortByName() method
+ * the `Finder::sortByName()` method will have a new `$useNaturalSort`
+   argument in version 5.0, not defining it is deprecated
+ * added `Finder::reverseSorting()` to reverse the sorting
+
+4.0.0
+-----
+
+ * removed `ExceptionInterface`
+ * removed `Symfony\Component\Finder\Iterator\FilterIterator`
+
+3.4.0
+-----
+
+ * deprecated `Symfony\Component\Finder\Iterator\FilterIterator`
+ * added Finder::hasResults() method to check if any results were found
+
+3.3.0
+-----
+
+ * added double-star matching to Glob::toRegex()
+
+3.0.0
+-----
+
+ * removed deprecated classes
+
+2.8.0
+-----
+
+ * deprecated adapters and related classes
+
+2.5.0
+-----
+ * added support for GLOB_BRACE in the paths passed to Finder::in()
+
+2.3.0
+-----
+
+ * added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs())
+ * unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception
+
+2.2.0
+-----
+
+ * added Finder::path() and Finder::notPath() methods
+ * added finder adapters to improve performance on specific platforms
+ * added support for wildcard characters (glob patterns) in the paths passed
+   to Finder::in()
+
+2.1.0
+-----
+
+ * added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and
+   Finder::sortByModifiedTime()
+ * added Countable to Finder
+ * added support for an array of directories as an argument to
+   Finder::exclude()
+ * added searching based on the file content via Finder::contains() and
+   Finder::notContains()
+ * added support for the != operator in the Comparator
+ * [BC BREAK] filter expressions (used for file name and content) are no more
+   considered as regexps but glob patterns when they are enclosed in '*' or '?'

+ 91 - 0
api/vendor/symfony/finder/Comparator/Comparator.php

@@ -0,0 +1,91 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Comparator;
+
+/**
+ * Comparator.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Comparator
+{
+    private $target;
+    private $operator = '==';
+
+    /**
+     * Gets the target value.
+     *
+     * @return string The target value
+     */
+    public function getTarget()
+    {
+        return $this->target;
+    }
+
+    public function setTarget(string $target)
+    {
+        $this->target = $target;
+    }
+
+    /**
+     * Gets the comparison operator.
+     *
+     * @return string The operator
+     */
+    public function getOperator()
+    {
+        return $this->operator;
+    }
+
+    /**
+     * Sets the comparison operator.
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function setOperator(string $operator)
+    {
+        if ('' === $operator) {
+            $operator = '==';
+        }
+
+        if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) {
+            throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
+        }
+
+        $this->operator = $operator;
+    }
+
+    /**
+     * Tests against the target.
+     *
+     * @param mixed $test A test value
+     *
+     * @return bool
+     */
+    public function test($test)
+    {
+        switch ($this->operator) {
+            case '>':
+                return $test > $this->target;
+            case '>=':
+                return $test >= $this->target;
+            case '<':
+                return $test < $this->target;
+            case '<=':
+                return $test <= $this->target;
+            case '!=':
+                return $test != $this->target;
+        }
+
+        return $test == $this->target;
+    }
+}

+ 51 - 0
api/vendor/symfony/finder/Comparator/DateComparator.php

@@ -0,0 +1,51 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Comparator;
+
+/**
+ * DateCompare compiles date comparisons.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class DateComparator extends Comparator
+{
+    /**
+     * @param string $test A comparison string
+     *
+     * @throws \InvalidArgumentException If the test is not understood
+     */
+    public function __construct(string $test)
+    {
+        if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
+            throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
+        }
+
+        try {
+            $date = new \DateTime($matches[2]);
+            $target = $date->format('U');
+        } catch (\Exception $e) {
+            throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
+        }
+
+        $operator = isset($matches[1]) ? $matches[1] : '==';
+        if ('since' === $operator || 'after' === $operator) {
+            $operator = '>';
+        }
+
+        if ('until' === $operator || 'before' === $operator) {
+            $operator = '<';
+        }
+
+        $this->setOperator($operator);
+        $this->setTarget($target);
+    }
+}

+ 79 - 0
api/vendor/symfony/finder/Comparator/NumberComparator.php

@@ -0,0 +1,79 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Comparator;
+
+/**
+ * NumberComparator compiles a simple comparison to an anonymous
+ * subroutine, which you can call with a value to be tested again.
+ *
+ * Now this would be very pointless, if NumberCompare didn't understand
+ * magnitudes.
+ *
+ * The target value may use magnitudes of kilobytes (k, ki),
+ * megabytes (m, mi), or gigabytes (g, gi).  Those suffixed
+ * with an i use the appropriate 2**n version in accordance with the
+ * IEC standard: http://physics.nist.gov/cuu/Units/binary.html
+ *
+ * Based on the Perl Number::Compare module.
+ *
+ * @author    Fabien Potencier <fabien@symfony.com> PHP port
+ * @author    Richard Clamp <richardc@unixbeard.net> Perl version
+ * @copyright 2004-2005 Fabien Potencier <fabien@symfony.com>
+ * @copyright 2002 Richard Clamp <richardc@unixbeard.net>
+ *
+ * @see http://physics.nist.gov/cuu/Units/binary.html
+ */
+class NumberComparator extends Comparator
+{
+    /**
+     * @param string|int $test A comparison string or an integer
+     *
+     * @throws \InvalidArgumentException If the test is not understood
+     */
+    public function __construct(?string $test)
+    {
+        if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
+            throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
+        }
+
+        $target = $matches[2];
+        if (!is_numeric($target)) {
+            throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
+        }
+        if (isset($matches[3])) {
+            // magnitude
+            switch (strtolower($matches[3])) {
+                case 'k':
+                    $target *= 1000;
+                    break;
+                case 'ki':
+                    $target *= 1024;
+                    break;
+                case 'm':
+                    $target *= 1000000;
+                    break;
+                case 'mi':
+                    $target *= 1024 * 1024;
+                    break;
+                case 'g':
+                    $target *= 1000000000;
+                    break;
+                case 'gi':
+                    $target *= 1024 * 1024 * 1024;
+                    break;
+            }
+        }
+
+        $this->setTarget($target);
+        $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
+    }
+}

+ 19 - 0
api/vendor/symfony/finder/Exception/AccessDeniedException.php

@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Exception;
+
+/**
+ * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
+ */
+class AccessDeniedException extends \UnexpectedValueException
+{
+}

+ 19 - 0
api/vendor/symfony/finder/Exception/DirectoryNotFoundException.php

@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Exception;
+
+/**
+ * @author Andreas Erhard <andreas.erhard@i-med.ac.at>
+ */
+class DirectoryNotFoundException extends \InvalidArgumentException
+{
+}

+ 797 - 0
api/vendor/symfony/finder/Finder.php

@@ -0,0 +1,797 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder;
+
+use Symfony\Component\Finder\Comparator\DateComparator;
+use Symfony\Component\Finder\Comparator\NumberComparator;
+use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
+use Symfony\Component\Finder\Iterator\CustomFilterIterator;
+use Symfony\Component\Finder\Iterator\DateRangeFilterIterator;
+use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator;
+use Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator;
+use Symfony\Component\Finder\Iterator\FilecontentFilterIterator;
+use Symfony\Component\Finder\Iterator\FilenameFilterIterator;
+use Symfony\Component\Finder\Iterator\SizeRangeFilterIterator;
+use Symfony\Component\Finder\Iterator\SortableIterator;
+
+/**
+ * Finder allows to build rules to find files and directories.
+ *
+ * It is a thin wrapper around several specialized iterator classes.
+ *
+ * All rules may be invoked several times.
+ *
+ * All methods return the current Finder object to allow chaining:
+ *
+ *     $finder = Finder::create()->files()->name('*.php')->in(__DIR__);
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Finder implements \IteratorAggregate, \Countable
+{
+    const IGNORE_VCS_FILES = 1;
+    const IGNORE_DOT_FILES = 2;
+    const IGNORE_VCS_IGNORED_FILES = 4;
+
+    private $mode = 0;
+    private $names = [];
+    private $notNames = [];
+    private $exclude = [];
+    private $filters = [];
+    private $depths = [];
+    private $sizes = [];
+    private $followLinks = false;
+    private $reverseSorting = false;
+    private $sort = false;
+    private $ignore = 0;
+    private $dirs = [];
+    private $dates = [];
+    private $iterators = [];
+    private $contains = [];
+    private $notContains = [];
+    private $paths = [];
+    private $notPaths = [];
+    private $ignoreUnreadableDirs = false;
+
+    private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg'];
+
+    public function __construct()
+    {
+        $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
+    }
+
+    /**
+     * Creates a new Finder.
+     *
+     * @return static
+     */
+    public static function create()
+    {
+        return new static();
+    }
+
+    /**
+     * Restricts the matching to directories only.
+     *
+     * @return $this
+     */
+    public function directories()
+    {
+        $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
+
+        return $this;
+    }
+
+    /**
+     * Restricts the matching to files only.
+     *
+     * @return $this
+     */
+    public function files()
+    {
+        $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
+
+        return $this;
+    }
+
+    /**
+     * Adds tests for the directory depth.
+     *
+     * Usage:
+     *
+     *     $finder->depth('> 1') // the Finder will start matching at level 1.
+     *     $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point.
+     *     $finder->depth(['>= 1', '< 3'])
+     *
+     * @param string|int|string[]|int[] $levels The depth level expression or an array of depth levels
+     *
+     * @return $this
+     *
+     * @see DepthRangeFilterIterator
+     * @see NumberComparator
+     */
+    public function depth($levels)
+    {
+        foreach ((array) $levels as $level) {
+            $this->depths[] = new Comparator\NumberComparator($level);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Adds tests for file dates (last modified).
+     *
+     * The date must be something that strtotime() is able to parse:
+     *
+     *     $finder->date('since yesterday');
+     *     $finder->date('until 2 days ago');
+     *     $finder->date('> now - 2 hours');
+     *     $finder->date('>= 2005-10-15');
+     *     $finder->date(['>= 2005-10-15', '<= 2006-05-27']);
+     *
+     * @param string|string[] $dates A date range string or an array of date ranges
+     *
+     * @return $this
+     *
+     * @see strtotime
+     * @see DateRangeFilterIterator
+     * @see DateComparator
+     */
+    public function date($dates)
+    {
+        foreach ((array) $dates as $date) {
+            $this->dates[] = new Comparator\DateComparator($date);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Adds rules that files must match.
+     *
+     * You can use patterns (delimited with / sign), globs or simple strings.
+     *
+     *     $finder->name('*.php')
+     *     $finder->name('/\.php$/') // same as above
+     *     $finder->name('test.php')
+     *     $finder->name(['test.py', 'test.php'])
+     *
+     * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns
+     *
+     * @return $this
+     *
+     * @see FilenameFilterIterator
+     */
+    public function name($patterns)
+    {
+        $this->names = array_merge($this->names, (array) $patterns);
+
+        return $this;
+    }
+
+    /**
+     * Adds rules that files must not match.
+     *
+     * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns
+     *
+     * @return $this
+     *
+     * @see FilenameFilterIterator
+     */
+    public function notName($patterns)
+    {
+        $this->notNames = array_merge($this->notNames, (array) $patterns);
+
+        return $this;
+    }
+
+    /**
+     * Adds tests that file contents must match.
+     *
+     * Strings or PCRE patterns can be used:
+     *
+     *     $finder->contains('Lorem ipsum')
+     *     $finder->contains('/Lorem ipsum/i')
+     *     $finder->contains(['dolor', '/ipsum/i'])
+     *
+     * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns
+     *
+     * @return $this
+     *
+     * @see FilecontentFilterIterator
+     */
+    public function contains($patterns)
+    {
+        $this->contains = array_merge($this->contains, (array) $patterns);
+
+        return $this;
+    }
+
+    /**
+     * Adds tests that file contents must not match.
+     *
+     * Strings or PCRE patterns can be used:
+     *
+     *     $finder->notContains('Lorem ipsum')
+     *     $finder->notContains('/Lorem ipsum/i')
+     *     $finder->notContains(['lorem', '/dolor/i'])
+     *
+     * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns
+     *
+     * @return $this
+     *
+     * @see FilecontentFilterIterator
+     */
+    public function notContains($patterns)
+    {
+        $this->notContains = array_merge($this->notContains, (array) $patterns);
+
+        return $this;
+    }
+
+    /**
+     * Adds rules that filenames must match.
+     *
+     * You can use patterns (delimited with / sign) or simple strings.
+     *
+     *     $finder->path('some/special/dir')
+     *     $finder->path('/some\/special\/dir/') // same as above
+     *     $finder->path(['some dir', 'another/dir'])
+     *
+     * Use only / as dirname separator.
+     *
+     * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns
+     *
+     * @return $this
+     *
+     * @see FilenameFilterIterator
+     */
+    public function path($patterns)
+    {
+        $this->paths = array_merge($this->paths, (array) $patterns);
+
+        return $this;
+    }
+
+    /**
+     * Adds rules that filenames must not match.
+     *
+     * You can use patterns (delimited with / sign) or simple strings.
+     *
+     *     $finder->notPath('some/special/dir')
+     *     $finder->notPath('/some\/special\/dir/') // same as above
+     *     $finder->notPath(['some/file.txt', 'another/file.log'])
+     *
+     * Use only / as dirname separator.
+     *
+     * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns
+     *
+     * @return $this
+     *
+     * @see FilenameFilterIterator
+     */
+    public function notPath($patterns)
+    {
+        $this->notPaths = array_merge($this->notPaths, (array) $patterns);
+
+        return $this;
+    }
+
+    /**
+     * Adds tests for file sizes.
+     *
+     *     $finder->size('> 10K');
+     *     $finder->size('<= 1Ki');
+     *     $finder->size(4);
+     *     $finder->size(['> 10K', '< 20K'])
+     *
+     * @param string|int|string[]|int[] $sizes A size range string or an integer or an array of size ranges
+     *
+     * @return $this
+     *
+     * @see SizeRangeFilterIterator
+     * @see NumberComparator
+     */
+    public function size($sizes)
+    {
+        foreach ((array) $sizes as $size) {
+            $this->sizes[] = new Comparator\NumberComparator($size);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Excludes directories.
+     *
+     * Directories passed as argument must be relative to the ones defined with the `in()` method. For example:
+     *
+     *     $finder->in(__DIR__)->exclude('ruby');
+     *
+     * @param string|array $dirs A directory path or an array of directories
+     *
+     * @return $this
+     *
+     * @see ExcludeDirectoryFilterIterator
+     */
+    public function exclude($dirs)
+    {
+        $this->exclude = array_merge($this->exclude, (array) $dirs);
+
+        return $this;
+    }
+
+    /**
+     * Excludes "hidden" directories and files (starting with a dot).
+     *
+     * This option is enabled by default.
+     *
+     * @return $this
+     *
+     * @see ExcludeDirectoryFilterIterator
+     */
+    public function ignoreDotFiles(bool $ignoreDotFiles)
+    {
+        if ($ignoreDotFiles) {
+            $this->ignore |= static::IGNORE_DOT_FILES;
+        } else {
+            $this->ignore &= ~static::IGNORE_DOT_FILES;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Forces the finder to ignore version control directories.
+     *
+     * This option is enabled by default.
+     *
+     * @return $this
+     *
+     * @see ExcludeDirectoryFilterIterator
+     */
+    public function ignoreVCS(bool $ignoreVCS)
+    {
+        if ($ignoreVCS) {
+            $this->ignore |= static::IGNORE_VCS_FILES;
+        } else {
+            $this->ignore &= ~static::IGNORE_VCS_FILES;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Forces Finder to obey .gitignore and ignore files based on rules listed there.
+     *
+     * This option is disabled by default.
+     *
+     * @return $this
+     */
+    public function ignoreVCSIgnored(bool $ignoreVCSIgnored)
+    {
+        if ($ignoreVCSIgnored) {
+            $this->ignore |= static::IGNORE_VCS_IGNORED_FILES;
+        } else {
+            $this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Adds VCS patterns.
+     *
+     * @see ignoreVCS()
+     *
+     * @param string|string[] $pattern VCS patterns to ignore
+     */
+    public static function addVCSPattern($pattern)
+    {
+        foreach ((array) $pattern as $p) {
+            self::$vcsPatterns[] = $p;
+        }
+
+        self::$vcsPatterns = array_unique(self::$vcsPatterns);
+    }
+
+    /**
+     * Sorts files and directories by an anonymous function.
+     *
+     * The anonymous function receives two \SplFileInfo instances to compare.
+     *
+     * This can be slow as all the matching files and directories must be retrieved for comparison.
+     *
+     * @return $this
+     *
+     * @see SortableIterator
+     */
+    public function sort(\Closure $closure)
+    {
+        $this->sort = $closure;
+
+        return $this;
+    }
+
+    /**
+     * Sorts files and directories by name.
+     *
+     * This can be slow as all the matching files and directories must be retrieved for comparison.
+     *
+     * @return $this
+     *
+     * @see SortableIterator
+     */
+    public function sortByName(bool $useNaturalSort = false)
+    {
+        $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME;
+
+        return $this;
+    }
+
+    /**
+     * Sorts files and directories by type (directories before files), then by name.
+     *
+     * This can be slow as all the matching files and directories must be retrieved for comparison.
+     *
+     * @return $this
+     *
+     * @see SortableIterator
+     */
+    public function sortByType()
+    {
+        $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
+
+        return $this;
+    }
+
+    /**
+     * Sorts files and directories by the last accessed time.
+     *
+     * This is the time that the file was last accessed, read or written to.
+     *
+     * This can be slow as all the matching files and directories must be retrieved for comparison.
+     *
+     * @return $this
+     *
+     * @see SortableIterator
+     */
+    public function sortByAccessedTime()
+    {
+        $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
+
+        return $this;
+    }
+
+    /**
+     * Reverses the sorting.
+     *
+     * @return $this
+     */
+    public function reverseSorting()
+    {
+        $this->reverseSorting = true;
+
+        return $this;
+    }
+
+    /**
+     * Sorts files and directories by the last inode changed time.
+     *
+     * This is the time that the inode information was last modified (permissions, owner, group or other metadata).
+     *
+     * On Windows, since inode is not available, changed time is actually the file creation time.
+     *
+     * This can be slow as all the matching files and directories must be retrieved for comparison.
+     *
+     * @return $this
+     *
+     * @see SortableIterator
+     */
+    public function sortByChangedTime()
+    {
+        $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
+
+        return $this;
+    }
+
+    /**
+     * Sorts files and directories by the last modified time.
+     *
+     * This is the last time the actual contents of the file were last modified.
+     *
+     * This can be slow as all the matching files and directories must be retrieved for comparison.
+     *
+     * @return $this
+     *
+     * @see SortableIterator
+     */
+    public function sortByModifiedTime()
+    {
+        $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
+
+        return $this;
+    }
+
+    /**
+     * Filters the iterator with an anonymous function.
+     *
+     * The anonymous function receives a \SplFileInfo and must return false
+     * to remove files.
+     *
+     * @return $this
+     *
+     * @see CustomFilterIterator
+     */
+    public function filter(\Closure $closure)
+    {
+        $this->filters[] = $closure;
+
+        return $this;
+    }
+
+    /**
+     * Forces the following of symlinks.
+     *
+     * @return $this
+     */
+    public function followLinks()
+    {
+        $this->followLinks = true;
+
+        return $this;
+    }
+
+    /**
+     * Tells finder to ignore unreadable directories.
+     *
+     * By default, scanning unreadable directories content throws an AccessDeniedException.
+     *
+     * @return $this
+     */
+    public function ignoreUnreadableDirs(bool $ignore = true)
+    {
+        $this->ignoreUnreadableDirs = $ignore;
+
+        return $this;
+    }
+
+    /**
+     * Searches files and directories which match defined rules.
+     *
+     * @param string|string[] $dirs A directory path or an array of directories
+     *
+     * @return $this
+     *
+     * @throws DirectoryNotFoundException if one of the directories does not exist
+     */
+    public function in($dirs)
+    {
+        $resolvedDirs = [];
+
+        foreach ((array) $dirs as $dir) {
+            if (is_dir($dir)) {
+                $resolvedDirs[] = $this->normalizeDir($dir);
+            } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR | GLOB_NOSORT)) {
+                sort($glob);
+                $resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob));
+            } else {
+                throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir));
+            }
+        }
+
+        $this->dirs = array_merge($this->dirs, $resolvedDirs);
+
+        return $this;
+    }
+
+    /**
+     * Returns an Iterator for the current Finder configuration.
+     *
+     * This method implements the IteratorAggregate interface.
+     *
+     * @return \Iterator|SplFileInfo[] An iterator
+     *
+     * @throws \LogicException if the in() method has not been called
+     */
+    public function getIterator()
+    {
+        if (0 === \count($this->dirs) && 0 === \count($this->iterators)) {
+            throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
+        }
+
+        if (1 === \count($this->dirs) && 0 === \count($this->iterators)) {
+            return $this->searchInDirectory($this->dirs[0]);
+        }
+
+        $iterator = new \AppendIterator();
+        foreach ($this->dirs as $dir) {
+            $iterator->append($this->searchInDirectory($dir));
+        }
+
+        foreach ($this->iterators as $it) {
+            $iterator->append($it);
+        }
+
+        return $iterator;
+    }
+
+    /**
+     * Appends an existing set of files/directories to the finder.
+     *
+     * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array.
+     *
+     * @return $this
+     *
+     * @throws \InvalidArgumentException when the given argument is not iterable
+     */
+    public function append(iterable $iterator)
+    {
+        if ($iterator instanceof \IteratorAggregate) {
+            $this->iterators[] = $iterator->getIterator();
+        } elseif ($iterator instanceof \Iterator) {
+            $this->iterators[] = $iterator;
+        } elseif ($iterator instanceof \Traversable || \is_array($iterator)) {
+            $it = new \ArrayIterator();
+            foreach ($iterator as $file) {
+                $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
+            }
+            $this->iterators[] = $it;
+        } else {
+            throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
+        }
+
+        return $this;
+    }
+
+    /**
+     * Check if the any results were found.
+     *
+     * @return bool
+     */
+    public function hasResults()
+    {
+        foreach ($this->getIterator() as $_) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Counts all the results collected by the iterators.
+     *
+     * @return int
+     */
+    public function count()
+    {
+        return iterator_count($this->getIterator());
+    }
+
+    private function searchInDirectory(string $dir): \Iterator
+    {
+        $exclude = $this->exclude;
+        $notPaths = $this->notPaths;
+
+        if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
+            $exclude = array_merge($exclude, self::$vcsPatterns);
+        }
+
+        if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
+            $notPaths[] = '#(^|/)\..+(/|$)#';
+        }
+
+        if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) {
+            $gitignoreFilePath = sprintf('%s/.gitignore', $dir);
+            if (!is_readable($gitignoreFilePath)) {
+                throw new \RuntimeException(sprintf('The "ignoreVCSIgnored" option cannot be used by the Finder as the "%s" file is not readable.', $gitignoreFilePath));
+            }
+            $notPaths = array_merge($notPaths, [Gitignore::toRegex(file_get_contents($gitignoreFilePath))]);
+        }
+
+        $minDepth = 0;
+        $maxDepth = PHP_INT_MAX;
+
+        foreach ($this->depths as $comparator) {
+            switch ($comparator->getOperator()) {
+                case '>':
+                    $minDepth = $comparator->getTarget() + 1;
+                    break;
+                case '>=':
+                    $minDepth = $comparator->getTarget();
+                    break;
+                case '<':
+                    $maxDepth = $comparator->getTarget() - 1;
+                    break;
+                case '<=':
+                    $maxDepth = $comparator->getTarget();
+                    break;
+                default:
+                    $minDepth = $maxDepth = $comparator->getTarget();
+            }
+        }
+
+        $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
+
+        if ($this->followLinks) {
+            $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
+        }
+
+        $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
+
+        if ($exclude) {
+            $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude);
+        }
+
+        $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
+
+        if ($minDepth > 0 || $maxDepth < PHP_INT_MAX) {
+            $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth);
+        }
+
+        if ($this->mode) {
+            $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
+        }
+
+        if ($this->names || $this->notNames) {
+            $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
+        }
+
+        if ($this->contains || $this->notContains) {
+            $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
+        }
+
+        if ($this->sizes) {
+            $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
+        }
+
+        if ($this->dates) {
+            $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
+        }
+
+        if ($this->filters) {
+            $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
+        }
+
+        if ($this->paths || $notPaths) {
+            $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths);
+        }
+
+        if ($this->sort || $this->reverseSorting) {
+            $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting);
+            $iterator = $iteratorAggregate->getIterator();
+        }
+
+        return $iterator;
+    }
+
+    /**
+     * Normalizes given directory names by removing trailing slashes.
+     *
+     * Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper
+     */
+    private function normalizeDir(string $dir): string
+    {
+        if ('/' === $dir) {
+            return $dir;
+        }
+
+        $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR);
+
+        if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) {
+            $dir .= '/';
+        }
+
+        return $dir;
+    }
+}

+ 105 - 0
api/vendor/symfony/finder/Gitignore.php

@@ -0,0 +1,105 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder;
+
+/**
+ * Gitignore matches against text.
+ *
+ * @author Ahmed Abdou <mail@ahmd.io>
+ */
+class Gitignore
+{
+    /**
+     * Returns a regexp which is the equivalent of the gitignore pattern.
+     *
+     * @return string The regexp
+     */
+    public static function toRegex(string $gitignoreFileContent): string
+    {
+        $gitignoreFileContent = preg_replace('/^[^\\\r\n]*#.*/m', '', $gitignoreFileContent);
+        $gitignoreLines = preg_split('/\r\n|\r|\n/', $gitignoreFileContent);
+        $gitignoreLines = array_map('trim', $gitignoreLines);
+        $gitignoreLines = array_filter($gitignoreLines);
+
+        $ignoreLinesPositive = array_filter($gitignoreLines, function (string $line) {
+            return !preg_match('/^!/', $line);
+        });
+
+        $ignoreLinesNegative = array_filter($gitignoreLines, function (string $line) {
+            return preg_match('/^!/', $line);
+        });
+
+        $ignoreLinesNegative = array_map(function (string $line) {
+            return preg_replace('/^!(.*)/', '${1}', $line);
+        }, $ignoreLinesNegative);
+        $ignoreLinesNegative = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesNegative);
+
+        $ignoreLinesPositive = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesPositive);
+        if (empty($ignoreLinesPositive)) {
+            return '/^$/';
+        }
+
+        if (empty($ignoreLinesNegative)) {
+            return sprintf('/%s/', implode('|', $ignoreLinesPositive));
+        }
+
+        return sprintf('/(?=^(?:(?!(%s)).)*$)(%s)/', implode('|', $ignoreLinesNegative), implode('|', $ignoreLinesPositive));
+    }
+
+    private static function getRegexFromGitignore(string $gitignorePattern): string
+    {
+        $regex = '(';
+        if (0 === strpos($gitignorePattern, '/')) {
+            $gitignorePattern = substr($gitignorePattern, 1);
+            $regex .= '^';
+        } else {
+            $regex .= '(^|\/)';
+        }
+
+        if ('/' === $gitignorePattern[\strlen($gitignorePattern) - 1]) {
+            $gitignorePattern = substr($gitignorePattern, 0, -1);
+        }
+
+        $iMax = \strlen($gitignorePattern);
+        for ($i = 0; $i < $iMax; ++$i) {
+            $doubleChars = substr($gitignorePattern, $i, 2);
+            if ('**' === $doubleChars) {
+                $regex .= '.+';
+                ++$i;
+                continue;
+            }
+
+            $c = $gitignorePattern[$i];
+            switch ($c) {
+                case '*':
+                    $regex .= '[^\/]+';
+                    break;
+                case '/':
+                case '.':
+                case ':':
+                case '(':
+                case ')':
+                case '{':
+                case '}':
+                    $regex .= '\\'.$c;
+                    break;
+                default:
+                    $regex .= $c;
+            }
+        }
+
+        $regex .= '($|\/)';
+        $regex .= ')';
+
+        return $regex;
+    }
+}

+ 111 - 0
api/vendor/symfony/finder/Glob.php

@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder;
+
+/**
+ * Glob matches globbing patterns against text.
+ *
+ *     if match_glob("foo.*", "foo.bar") echo "matched\n";
+ *
+ *     // prints foo.bar and foo.baz
+ *     $regex = glob_to_regex("foo.*");
+ *     for (['foo.bar', 'foo.baz', 'foo', 'bar'] as $t)
+ *     {
+ *         if (/$regex/) echo "matched: $car\n";
+ *     }
+ *
+ * Glob implements glob(3) style matching that can be used to match
+ * against text, rather than fetching names from a filesystem.
+ *
+ * Based on the Perl Text::Glob module.
+ *
+ * @author Fabien Potencier <fabien@symfony.com> PHP port
+ * @author     Richard Clamp <richardc@unixbeard.net> Perl version
+ * @copyright  2004-2005 Fabien Potencier <fabien@symfony.com>
+ * @copyright  2002 Richard Clamp <richardc@unixbeard.net>
+ */
+class Glob
+{
+    /**
+     * Returns a regexp which is the equivalent of the glob pattern.
+     *
+     * @return string
+     */
+    public static function toRegex(string $glob, bool $strictLeadingDot = true, bool $strictWildcardSlash = true, string $delimiter = '#')
+    {
+        $firstByte = true;
+        $escaping = false;
+        $inCurlies = 0;
+        $regex = '';
+        $sizeGlob = \strlen($glob);
+        for ($i = 0; $i < $sizeGlob; ++$i) {
+            $car = $glob[$i];
+            if ($firstByte && $strictLeadingDot && '.' !== $car) {
+                $regex .= '(?=[^\.])';
+            }
+
+            $firstByte = '/' === $car;
+
+            if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1].$glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) {
+                $car = '[^/]++/';
+                if (!isset($glob[$i + 3])) {
+                    $car .= '?';
+                }
+
+                if ($strictLeadingDot) {
+                    $car = '(?=[^\.])'.$car;
+                }
+
+                $car = '/(?:'.$car.')*';
+                $i += 2 + isset($glob[$i + 3]);
+
+                if ('/' === $delimiter) {
+                    $car = str_replace('/', '\\/', $car);
+                }
+            }
+
+            if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
+                $regex .= "\\$car";
+            } elseif ('*' === $car) {
+                $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
+            } elseif ('?' === $car) {
+                $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
+            } elseif ('{' === $car) {
+                $regex .= $escaping ? '\\{' : '(';
+                if (!$escaping) {
+                    ++$inCurlies;
+                }
+            } elseif ('}' === $car && $inCurlies) {
+                $regex .= $escaping ? '}' : ')';
+                if (!$escaping) {
+                    --$inCurlies;
+                }
+            } elseif (',' === $car && $inCurlies) {
+                $regex .= $escaping ? ',' : '|';
+            } elseif ('\\' === $car) {
+                if ($escaping) {
+                    $regex .= '\\\\';
+                    $escaping = false;
+                } else {
+                    $escaping = true;
+                }
+
+                continue;
+            } else {
+                $regex .= $car;
+            }
+            $escaping = false;
+        }
+
+        return $delimiter.'^'.$regex.'$'.$delimiter;
+    }
+}

+ 61 - 0
api/vendor/symfony/finder/Iterator/CustomFilterIterator.php

@@ -0,0 +1,61 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * CustomFilterIterator filters files by applying anonymous functions.
+ *
+ * The anonymous function receives a \SplFileInfo and must return false
+ * to remove files.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class CustomFilterIterator extends \FilterIterator
+{
+    private $filters = [];
+
+    /**
+     * @param \Iterator  $iterator The Iterator to filter
+     * @param callable[] $filters  An array of PHP callbacks
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function __construct(\Iterator $iterator, array $filters)
+    {
+        foreach ($filters as $filter) {
+            if (!\is_callable($filter)) {
+                throw new \InvalidArgumentException('Invalid PHP callback.');
+            }
+        }
+        $this->filters = $filters;
+
+        parent::__construct($iterator);
+    }
+
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        $fileinfo = $this->current();
+
+        foreach ($this->filters as $filter) {
+            if (false === $filter($fileinfo)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 58 - 0
api/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php

@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Comparator\DateComparator;
+
+/**
+ * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates).
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class DateRangeFilterIterator extends \FilterIterator
+{
+    private $comparators = [];
+
+    /**
+     * @param \Iterator        $iterator    The Iterator to filter
+     * @param DateComparator[] $comparators An array of DateComparator instances
+     */
+    public function __construct(\Iterator $iterator, array $comparators)
+    {
+        $this->comparators = $comparators;
+
+        parent::__construct($iterator);
+    }
+
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        $fileinfo = $this->current();
+
+        if (!file_exists($fileinfo->getPathname())) {
+            return false;
+        }
+
+        $filedate = $fileinfo->getMTime();
+        foreach ($this->comparators as $compare) {
+            if (!$compare->test($filedate)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 45 - 0
api/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php

@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * DepthRangeFilterIterator limits the directory depth.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class DepthRangeFilterIterator extends \FilterIterator
+{
+    private $minDepth = 0;
+
+    /**
+     * @param \RecursiveIteratorIterator $iterator The Iterator to filter
+     * @param int                        $minDepth The min depth
+     * @param int                        $maxDepth The max depth
+     */
+    public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = PHP_INT_MAX)
+    {
+        $this->minDepth = $minDepth;
+        $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
+
+        parent::__construct($iterator);
+    }
+
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        return $this->getInnerIterator()->getDepth() >= $this->minDepth;
+    }
+}

+ 87 - 0
api/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php

@@ -0,0 +1,87 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * ExcludeDirectoryFilterIterator filters out directories.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator
+{
+    private $iterator;
+    private $isRecursive;
+    private $excludedDirs = [];
+    private $excludedPattern;
+
+    /**
+     * @param \Iterator $iterator    The Iterator to filter
+     * @param string[]  $directories An array of directories to exclude
+     */
+    public function __construct(\Iterator $iterator, array $directories)
+    {
+        $this->iterator = $iterator;
+        $this->isRecursive = $iterator instanceof \RecursiveIterator;
+        $patterns = [];
+        foreach ($directories as $directory) {
+            $directory = rtrim($directory, '/');
+            if (!$this->isRecursive || false !== strpos($directory, '/')) {
+                $patterns[] = preg_quote($directory, '#');
+            } else {
+                $this->excludedDirs[$directory] = true;
+            }
+        }
+        if ($patterns) {
+            $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#';
+        }
+
+        parent::__construct($iterator);
+    }
+
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool True if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) {
+            return false;
+        }
+
+        if ($this->excludedPattern) {
+            $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
+            $path = str_replace('\\', '/', $path);
+
+            return !preg_match($this->excludedPattern, $path);
+        }
+
+        return true;
+    }
+
+    /**
+     * @return bool
+     */
+    public function hasChildren()
+    {
+        return $this->isRecursive && $this->iterator->hasChildren();
+    }
+
+    public function getChildren()
+    {
+        $children = new self($this->iterator->getChildren(), []);
+        $children->excludedDirs = $this->excludedDirs;
+        $children->excludedPattern = $this->excludedPattern;
+
+        return $children;
+    }
+}

+ 53 - 0
api/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php

@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * FileTypeFilterIterator only keeps files, directories, or both.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class FileTypeFilterIterator extends \FilterIterator
+{
+    const ONLY_FILES = 1;
+    const ONLY_DIRECTORIES = 2;
+
+    private $mode;
+
+    /**
+     * @param \Iterator $iterator The Iterator to filter
+     * @param int       $mode     The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES)
+     */
+    public function __construct(\Iterator $iterator, int $mode)
+    {
+        $this->mode = $mode;
+
+        parent::__construct($iterator);
+    }
+
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        $fileinfo = $this->current();
+        if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
+            return false;
+        } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
+            return false;
+        }
+
+        return true;
+    }
+}

+ 58 - 0
api/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php

@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings).
+ *
+ * @author Fabien Potencier  <fabien@symfony.com>
+ * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
+ */
+class FilecontentFilterIterator extends MultiplePcreFilterIterator
+{
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        if (!$this->matchRegexps && !$this->noMatchRegexps) {
+            return true;
+        }
+
+        $fileinfo = $this->current();
+
+        if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
+            return false;
+        }
+
+        $content = $fileinfo->getContents();
+        if (!$content) {
+            return false;
+        }
+
+        return $this->isAccepted($content);
+    }
+
+    /**
+     * Converts string to regexp if necessary.
+     *
+     * @param string $str Pattern: string or regexp
+     *
+     * @return string regexp corresponding to a given string or regexp
+     */
+    protected function toRegex(string $str)
+    {
+        return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
+    }
+}

+ 47 - 0
api/vendor/symfony/finder/Iterator/FilenameFilterIterator.php

@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Glob;
+
+/**
+ * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string).
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class FilenameFilterIterator extends MultiplePcreFilterIterator
+{
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        return $this->isAccepted($this->current()->getFilename());
+    }
+
+    /**
+     * Converts glob to regexp.
+     *
+     * PCRE patterns are left unchanged.
+     * Glob strings are transformed with Glob::toRegex().
+     *
+     * @param string $str Pattern: glob or regexp
+     *
+     * @return string regexp corresponding to a given glob or regexp
+     */
+    protected function toRegex(string $str)
+    {
+        return $this->isRegex($str) ? $str : Glob::toRegex($str);
+    }
+}

+ 106 - 0
api/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php

@@ -0,0 +1,106 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings).
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+abstract class MultiplePcreFilterIterator extends \FilterIterator
+{
+    protected $matchRegexps = [];
+    protected $noMatchRegexps = [];
+
+    /**
+     * @param \Iterator $iterator        The Iterator to filter
+     * @param string[]  $matchPatterns   An array of patterns that need to match
+     * @param string[]  $noMatchPatterns An array of patterns that need to not match
+     */
+    public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
+    {
+        foreach ($matchPatterns as $pattern) {
+            $this->matchRegexps[] = $this->toRegex($pattern);
+        }
+
+        foreach ($noMatchPatterns as $pattern) {
+            $this->noMatchRegexps[] = $this->toRegex($pattern);
+        }
+
+        parent::__construct($iterator);
+    }
+
+    /**
+     * Checks whether the string is accepted by the regex filters.
+     *
+     * If there is no regexps defined in the class, this method will accept the string.
+     * Such case can be handled by child classes before calling the method if they want to
+     * apply a different behavior.
+     *
+     * @return bool
+     */
+    protected function isAccepted(string $string)
+    {
+        // should at least not match one rule to exclude
+        foreach ($this->noMatchRegexps as $regex) {
+            if (preg_match($regex, $string)) {
+                return false;
+            }
+        }
+
+        // should at least match one rule
+        if ($this->matchRegexps) {
+            foreach ($this->matchRegexps as $regex) {
+                if (preg_match($regex, $string)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        // If there is no match rules, the file is accepted
+        return true;
+    }
+
+    /**
+     * Checks whether the string is a regex.
+     *
+     * @return bool
+     */
+    protected function isRegex(string $str)
+    {
+        if (preg_match('/^(.{3,}?)[imsxuADU]*$/', $str, $m)) {
+            $start = substr($m[1], 0, 1);
+            $end = substr($m[1], -1);
+
+            if ($start === $end) {
+                return !preg_match('/[*?[:alnum:] \\\\]/', $start);
+            }
+
+            foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) {
+                if ($start === $delimiters[0] && $end === $delimiters[1]) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Converts string into regexp.
+     *
+     * @return string
+     */
+    abstract protected function toRegex(string $str);
+}

+ 56 - 0
api/vendor/symfony/finder/Iterator/PathFilterIterator.php

@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * PathFilterIterator filters files by path patterns (e.g. some/special/dir).
+ *
+ * @author Fabien Potencier  <fabien@symfony.com>
+ * @author Włodzimierz Gajda <gajdaw@gajdaw.pl>
+ */
+class PathFilterIterator extends MultiplePcreFilterIterator
+{
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        $filename = $this->current()->getRelativePathname();
+
+        if ('\\' === \DIRECTORY_SEPARATOR) {
+            $filename = str_replace('\\', '/', $filename);
+        }
+
+        return $this->isAccepted($filename);
+    }
+
+    /**
+     * Converts strings to regexp.
+     *
+     * PCRE patterns are left unchanged.
+     *
+     * Default conversion:
+     *     'lorem/ipsum/dolor' ==>  'lorem\/ipsum\/dolor/'
+     *
+     * Use only / as directory separator (on Windows also).
+     *
+     * @param string $str Pattern: regexp or dirname
+     *
+     * @return string regexp corresponding to a given string or regexp
+     */
+    protected function toRegex(string $str)
+    {
+        return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
+    }
+}

+ 144 - 0
api/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php

@@ -0,0 +1,144 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Exception\AccessDeniedException;
+use Symfony\Component\Finder\SplFileInfo;
+
+/**
+ * Extends the \RecursiveDirectoryIterator to support relative paths.
+ *
+ * @author Victor Berchet <victor@suumit.com>
+ */
+class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
+{
+    /**
+     * @var bool
+     */
+    private $ignoreUnreadableDirs;
+
+    /**
+     * @var bool
+     */
+    private $rewindable;
+
+    // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations
+    private $rootPath;
+    private $subPath;
+    private $directorySeparator = '/';
+
+    /**
+     * @throws \RuntimeException
+     */
+    public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = false)
+    {
+        if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
+            throw new \RuntimeException('This iterator only support returning current as fileinfo.');
+        }
+
+        parent::__construct($path, $flags);
+        $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
+        $this->rootPath = $path;
+        if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) {
+            $this->directorySeparator = \DIRECTORY_SEPARATOR;
+        }
+    }
+
+    /**
+     * Return an instance of SplFileInfo with support for relative paths.
+     *
+     * @return SplFileInfo File information
+     */
+    public function current()
+    {
+        // the logic here avoids redoing the same work in all iterations
+
+        if (null === $subPathname = $this->subPath) {
+            $subPathname = $this->subPath = (string) $this->getSubPath();
+        }
+        if ('' !== $subPathname) {
+            $subPathname .= $this->directorySeparator;
+        }
+        $subPathname .= $this->getFilename();
+
+        if ('/' !== $basePath = $this->rootPath) {
+            $basePath .= $this->directorySeparator;
+        }
+
+        return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
+    }
+
+    /**
+     * @return \RecursiveIterator
+     *
+     * @throws AccessDeniedException
+     */
+    public function getChildren()
+    {
+        try {
+            $children = parent::getChildren();
+
+            if ($children instanceof self) {
+                // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore
+                $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
+
+                // performance optimization to avoid redoing the same work in all children
+                $children->rewindable = &$this->rewindable;
+                $children->rootPath = $this->rootPath;
+            }
+
+            return $children;
+        } catch (\UnexpectedValueException $e) {
+            if ($this->ignoreUnreadableDirs) {
+                // If directory is unreadable and finder is set to ignore it, a fake empty content is returned.
+                return new \RecursiveArrayIterator([]);
+            } else {
+                throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
+            }
+        }
+    }
+
+    /**
+     * Do nothing for non rewindable stream.
+     */
+    public function rewind()
+    {
+        if (false === $this->isRewindable()) {
+            return;
+        }
+
+        parent::rewind();
+    }
+
+    /**
+     * Checks if the stream is rewindable.
+     *
+     * @return bool true when the stream is rewindable, false otherwise
+     */
+    public function isRewindable()
+    {
+        if (null !== $this->rewindable) {
+            return $this->rewindable;
+        }
+
+        if (false !== $stream = @opendir($this->getPath())) {
+            $infos = stream_get_meta_data($stream);
+            closedir($stream);
+
+            if ($infos['seekable']) {
+                return $this->rewindable = true;
+            }
+        }
+
+        return $this->rewindable = false;
+    }
+}

+ 57 - 0
api/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php

@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+use Symfony\Component\Finder\Comparator\NumberComparator;
+
+/**
+ * SizeRangeFilterIterator filters out files that are not in the given size range.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class SizeRangeFilterIterator extends \FilterIterator
+{
+    private $comparators = [];
+
+    /**
+     * @param \Iterator          $iterator    The Iterator to filter
+     * @param NumberComparator[] $comparators An array of NumberComparator instances
+     */
+    public function __construct(\Iterator $iterator, array $comparators)
+    {
+        $this->comparators = $comparators;
+
+        parent::__construct($iterator);
+    }
+
+    /**
+     * Filters the iterator values.
+     *
+     * @return bool true if the value should be kept, false otherwise
+     */
+    public function accept()
+    {
+        $fileinfo = $this->current();
+        if (!$fileinfo->isFile()) {
+            return true;
+        }
+
+        $filesize = $fileinfo->getSize();
+        foreach ($this->comparators as $compare) {
+            if (!$compare->test($filesize)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 101 - 0
api/vendor/symfony/finder/Iterator/SortableIterator.php

@@ -0,0 +1,101 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder\Iterator;
+
+/**
+ * SortableIterator applies a sort on a given Iterator.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class SortableIterator implements \IteratorAggregate
+{
+    const SORT_BY_NONE = 0;
+    const SORT_BY_NAME = 1;
+    const SORT_BY_TYPE = 2;
+    const SORT_BY_ACCESSED_TIME = 3;
+    const SORT_BY_CHANGED_TIME = 4;
+    const SORT_BY_MODIFIED_TIME = 5;
+    const SORT_BY_NAME_NATURAL = 6;
+
+    private $iterator;
+    private $sort;
+
+    /**
+     * @param \Traversable $iterator The Iterator to filter
+     * @param int|callable $sort     The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = false)
+    {
+        $this->iterator = $iterator;
+        $order = $reverseOrder ? -1 : 1;
+
+        if (self::SORT_BY_NAME === $sort) {
+            $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
+                return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
+            };
+        } elseif (self::SORT_BY_NAME_NATURAL === $sort) {
+            $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
+                return $order * strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
+            };
+        } elseif (self::SORT_BY_TYPE === $sort) {
+            $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
+                if ($a->isDir() && $b->isFile()) {
+                    return -$order;
+                } elseif ($a->isFile() && $b->isDir()) {
+                    return $order;
+                }
+
+                return $order * strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname());
+            };
+        } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
+            $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
+                return $order * ($a->getATime() - $b->getATime());
+            };
+        } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
+            $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
+                return $order * ($a->getCTime() - $b->getCTime());
+            };
+        } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
+            $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use ($order) {
+                return $order * ($a->getMTime() - $b->getMTime());
+            };
+        } elseif (self::SORT_BY_NONE === $sort) {
+            $this->sort = $order;
+        } elseif (\is_callable($sort)) {
+            $this->sort = $reverseOrder ? static function (\SplFileInfo $a, \SplFileInfo $b) use ($sort) { return -$sort($a, $b); } : $sort;
+        } else {
+            throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
+        }
+    }
+
+    /**
+     * @return \Traversable
+     */
+    public function getIterator()
+    {
+        if (1 === $this->sort) {
+            return $this->iterator;
+        }
+
+        $array = iterator_to_array($this->iterator, true);
+
+        if (-1 === $this->sort) {
+            $array = array_reverse($array);
+        } else {
+            uasort($array, $this->sort);
+        }
+
+        return new \ArrayIterator($array);
+    }
+}

+ 19 - 0
api/vendor/symfony/finder/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2004-2020 Fabien Potencier
+
+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.

+ 14 - 0
api/vendor/symfony/finder/README.md

@@ -0,0 +1,14 @@
+Finder Component
+================
+
+The Finder component finds files and directories via an intuitive fluent
+interface.
+
+Resources
+---------
+
+  * [Documentation](https://symfony.com/doc/current/components/finder.html)
+  * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+  * [Report issues](https://github.com/symfony/symfony/issues) and
+    [send Pull Requests](https://github.com/symfony/symfony/pulls)
+    in the [main Symfony repository](https://github.com/symfony/symfony)

+ 85 - 0
api/vendor/symfony/finder/SplFileInfo.php

@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Finder;
+
+/**
+ * Extends \SplFileInfo to support relative paths.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class SplFileInfo extends \SplFileInfo
+{
+    private $relativePath;
+    private $relativePathname;
+
+    /**
+     * @param string $file             The file name
+     * @param string $relativePath     The relative path
+     * @param string $relativePathname The relative path name
+     */
+    public function __construct(string $file, string $relativePath, string $relativePathname)
+    {
+        parent::__construct($file);
+        $this->relativePath = $relativePath;
+        $this->relativePathname = $relativePathname;
+    }
+
+    /**
+     * Returns the relative path.
+     *
+     * This path does not contain the file name.
+     *
+     * @return string the relative path
+     */
+    public function getRelativePath()
+    {
+        return $this->relativePath;
+    }
+
+    /**
+     * Returns the relative path name.
+     *
+     * This path contains the file name.
+     *
+     * @return string the relative path name
+     */
+    public function getRelativePathname()
+    {
+        return $this->relativePathname;
+    }
+
+    public function getFilenameWithoutExtension(): string
+    {
+        $filename = $this->getFilename();
+
+        return pathinfo($filename, PATHINFO_FILENAME);
+    }
+
+    /**
+     * Returns the contents of the file.
+     *
+     * @return string the contents of the file
+     *
+     * @throws \RuntimeException
+     */
+    public function getContents()
+    {
+        set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
+        $content = file_get_contents($this->getPathname());
+        restore_error_handler();
+        if (false === $content) {
+            throw new \RuntimeException($error);
+        }
+
+        return $content;
+    }
+}

+ 33 - 0
api/vendor/symfony/finder/composer.json

@@ -0,0 +1,33 @@
+{
+    "name": "symfony/finder",
+    "type": "library",
+    "description": "Symfony Finder Component",
+    "keywords": [],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.2.5"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Component\\Finder\\": "" },
+        "exclude-from-classmap": [
+            "/Tests/"
+        ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "5.1-dev"
+        }
+    }
+}

+ 227 - 0
api/vendor/symfony/polyfill-ctype/Ctype.php

@@ -0,0 +1,227 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Ctype;
+
+/**
+ * Ctype implementation through regex.
+ *
+ * @internal
+ *
+ * @author Gert de Pagter <BackEndTea@gmail.com>
+ */
+final class Ctype
+{
+    /**
+     * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.
+     *
+     * @see https://php.net/ctype-alnum
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_alnum($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text is a letter, FALSE otherwise.
+     *
+     * @see https://php.net/ctype-alpha
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_alpha($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.
+     *
+     * @see https://php.net/ctype-cntrl
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_cntrl($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.
+     *
+     * @see https://php.net/ctype-digit
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_digit($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.
+     *
+     * @see https://php.net/ctype-graph
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_graph($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text is a lowercase letter.
+     *
+     * @see https://php.net/ctype-lower
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_lower($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.
+     *
+     * @see https://php.net/ctype-print
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_print($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.
+     *
+     * @see https://php.net/ctype-punct
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_punct($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.
+     *
+     * @see https://php.net/ctype-space
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_space($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text is an uppercase letter.
+     *
+     * @see https://php.net/ctype-upper
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_upper($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
+    }
+
+    /**
+     * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
+     *
+     * @see https://php.net/ctype-xdigit
+     *
+     * @param string|int $text
+     *
+     * @return bool
+     */
+    public static function ctype_xdigit($text)
+    {
+        $text = self::convert_int_to_char_for_ctype($text);
+
+        return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
+    }
+
+    /**
+     * Converts integers to their char versions according to normal ctype behaviour, if needed.
+     *
+     * If an integer between -128 and 255 inclusive is provided,
+     * it is interpreted as the ASCII value of a single character
+     * (negative values have 256 added in order to allow characters in the Extended ASCII range).
+     * Any other integer is interpreted as a string containing the decimal digits of the integer.
+     *
+     * @param string|int $int
+     *
+     * @return mixed
+     */
+    private static function convert_int_to_char_for_ctype($int)
+    {
+        if (!\is_int($int)) {
+            return $int;
+        }
+
+        if ($int < -128 || $int > 255) {
+            return (string) $int;
+        }
+
+        if ($int < 0) {
+            $int += 256;
+        }
+
+        return \chr($int);
+    }
+}

+ 19 - 0
api/vendor/symfony/polyfill-ctype/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2018-2019 Fabien Potencier
+
+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.

+ 12 - 0
api/vendor/symfony/polyfill-ctype/README.md

@@ -0,0 +1,12 @@
+Symfony Polyfill / Ctype
+========================
+
+This component provides `ctype_*` functions to users who run php versions without the ctype extension.
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).

+ 46 - 0
api/vendor/symfony/polyfill-ctype/bootstrap.php

@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Ctype as p;
+
+if (!function_exists('ctype_alnum')) {
+    function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
+}
+if (!function_exists('ctype_alpha')) {
+    function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
+}
+if (!function_exists('ctype_cntrl')) {
+    function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
+}
+if (!function_exists('ctype_digit')) {
+    function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
+}
+if (!function_exists('ctype_graph')) {
+    function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
+}
+if (!function_exists('ctype_lower')) {
+    function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
+}
+if (!function_exists('ctype_print')) {
+    function ctype_print($text) { return p\Ctype::ctype_print($text); }
+}
+if (!function_exists('ctype_punct')) {
+    function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
+}
+if (!function_exists('ctype_space')) {
+    function ctype_space($text) { return p\Ctype::ctype_space($text); }
+}
+if (!function_exists('ctype_upper')) {
+    function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
+}
+if (!function_exists('ctype_xdigit')) {
+    function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
+}

+ 38 - 0
api/vendor/symfony/polyfill-ctype/composer.json

@@ -0,0 +1,38 @@
+{
+    "name": "symfony/polyfill-ctype",
+    "type": "library",
+    "description": "Symfony polyfill for ctype functions",
+    "keywords": ["polyfill", "compatibility", "portable", "ctype"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Gert de Pagter",
+            "email": "BackEndTea@gmail.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.3"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" },
+        "files": [ "bootstrap.php" ]
+    },
+    "suggest": {
+        "ext-ctype": "For best performance"
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.18-dev"
+        },
+        "thanks": {
+            "name": "symfony/polyfill",
+            "url": "https://github.com/symfony/polyfill"
+        }
+    }
+}

+ 224 - 0
api/vendor/symfony/yaml/CHANGELOG.md

@@ -0,0 +1,224 @@
+CHANGELOG
+=========
+
+5.1.0
+-----
+
+ * Added support for parsing numbers prefixed with `0o` as octal numbers.
+ * Deprecated support for parsing numbers starting with `0` as octal numbers. They will be parsed as strings as of Symfony 6.0. Prefix numbers with `0o`
+   so that they are parsed as octal numbers.
+
+   Before:
+
+   ```yaml
+   Yaml::parse('072');
+   ```
+
+   After:
+
+   ```yaml
+   Yaml::parse('0o72');
+   ```
+
+ * Added `yaml-lint` binary.
+ * Deprecated using the `!php/object` and `!php/const` tags without a value.
+
+5.0.0
+-----
+
+ * Removed support for mappings inside multi-line strings.
+ * removed support for implicit STDIN usage in the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit.
+
+4.4.0
+-----
+
+ * Added support for parsing the inline notation spanning multiple lines.
+ * Added support to dump `null` as `~` by using the `Yaml::DUMP_NULL_AS_TILDE` flag.
+ * deprecated accepting STDIN implicitly when using the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit.
+
+4.3.0
+-----
+
+ * Using a mapping inside a multi-line string is deprecated and will throw a `ParseException` in 5.0.
+
+4.2.0
+-----
+
+ * added support for multiple files or directories in `LintCommand`
+
+4.0.0
+-----
+
+ * The behavior of the non-specific tag `!` is changed and now forces
+   non-evaluating your values.
+ * complex mappings will throw a `ParseException`
+ * support for the comma as a group separator for floats has been dropped, use
+   the underscore instead
+ * support for the `!!php/object` tag has been dropped, use the `!php/object`
+   tag instead
+ * duplicate mapping keys throw a `ParseException`
+ * non-string mapping keys throw a `ParseException`, use the `Yaml::PARSE_KEYS_AS_STRINGS`
+   flag to cast them to strings
+ * `%` at the beginning of an unquoted string throw a `ParseException`
+ * mappings with a colon (`:`) that is not followed by a whitespace throw a
+   `ParseException`
+ * the `Dumper::setIndentation()` method has been removed
+ * being able to pass boolean options to the `Yaml::parse()`, `Yaml::dump()`,
+   `Parser::parse()`, and `Dumper::dump()` methods to configure the behavior of
+   the parser and dumper is no longer supported, pass bitmask flags instead
+ * the constructor arguments of the `Parser` class have been removed
+ * the `Inline` class is internal and no longer part of the BC promise
+ * removed support for the `!str` tag, use the `!!str` tag instead
+ * added support for tagged scalars.
+
+   ```yml
+   Yaml::parse('!foo bar', Yaml::PARSE_CUSTOM_TAGS);
+   // returns TaggedValue('foo', 'bar');
+   ```
+
+3.4.0
+-----
+
+ * added support for parsing YAML files using the `Yaml::parseFile()` or `Parser::parseFile()` method
+
+ * the `Dumper`, `Parser`, and `Yaml` classes are marked as final
+
+ * Deprecated the `!php/object:` tag which will be replaced by the
+   `!php/object` tag (without the colon) in 4.0.
+
+ * Deprecated the `!php/const:` tag which will be replaced by the
+   `!php/const` tag (without the colon) in 4.0.
+
+ * Support for the `!str` tag is deprecated, use the `!!str` tag instead.
+
+ * Deprecated using the non-specific tag `!` as its behavior will change in 4.0.
+   It will force non-evaluating your values in 4.0. Use plain integers or `!!float` instead.
+
+3.3.0
+-----
+
+ * Starting an unquoted string with a question mark followed by a space is
+   deprecated and will throw a `ParseException` in Symfony 4.0.
+
+ * Deprecated support for implicitly parsing non-string mapping keys as strings.
+   Mapping keys that are no strings will lead to a `ParseException` in Symfony
+   4.0. Use quotes to opt-in for keys to be parsed as strings.
+
+   Before:
+
+   ```php
+   $yaml = <<<YAML
+   null: null key
+   true: boolean true
+   2.0: float key
+   YAML;
+
+   Yaml::parse($yaml);
+   ```
+
+   After:
+
+   ```php
+
+   $yaml = <<<YAML
+   "null": null key
+   "true": boolean true
+   "2.0": float key
+   YAML;
+
+   Yaml::parse($yaml);
+   ```
+
+ * Omitted mapping values will be parsed as `null`.
+
+ * Omitting the key of a mapping is deprecated and will throw a `ParseException` in Symfony 4.0.
+
+ * Added support for dumping empty PHP arrays as YAML sequences:
+
+   ```php
+   Yaml::dump([], 0, 0, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
+   ```
+
+3.2.0
+-----
+
+ * Mappings with a colon (`:`) that is not followed by a whitespace are deprecated
+   when the mapping key is not quoted and will lead to a `ParseException` in
+   Symfony 4.0 (e.g. `foo:bar` must be `foo: bar`).
+
+ * Added support for parsing PHP constants:
+
+   ```php
+   Yaml::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_CONSTANT);
+   ```
+
+ * Support for silently ignoring duplicate mapping keys in YAML has been
+   deprecated and will lead to a `ParseException` in Symfony 4.0.
+
+3.1.0
+-----
+
+ * Added support to dump `stdClass` and `ArrayAccess` objects as YAML mappings
+   through the `Yaml::DUMP_OBJECT_AS_MAP` flag.
+
+ * Strings that are not UTF-8 encoded will be dumped as base64 encoded binary
+   data.
+
+ * Added support for dumping multi line strings as literal blocks.
+
+ * Added support for parsing base64 encoded binary data when they are tagged
+   with the `!!binary` tag.
+
+ * Added support for parsing timestamps as `\DateTime` objects:
+
+   ```php
+   Yaml::parse('2001-12-15 21:59:43.10 -5', Yaml::PARSE_DATETIME);
+   ```
+
+ * `\DateTime` and `\DateTimeImmutable` objects are dumped as YAML timestamps.
+
+ * Deprecated usage of `%` at the beginning of an unquoted string.
+
+ * Added support for customizing the YAML parser behavior through an optional bit field:
+
+   ```php
+   Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE | Yaml::PARSE_OBJECT | Yaml::PARSE_OBJECT_FOR_MAP);
+   ```
+
+ * Added support for customizing the dumped YAML string through an optional bit field:
+
+   ```php
+   Yaml::dump(['foo' => new A(), 'bar' => 1], 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE | Yaml::DUMP_OBJECT);
+   ```
+
+3.0.0
+-----
+
+ * Yaml::parse() now throws an exception when a blackslash is not escaped
+   in double-quoted strings
+
+2.8.0
+-----
+
+ * Deprecated usage of a colon in an unquoted mapping value
+ * Deprecated usage of @, \`, | and > at the beginning of an unquoted string
+ * When surrounding strings with double-quotes, you must now escape `\` characters. Not
+   escaping those characters (when surrounded by double-quotes) is deprecated.
+
+   Before:
+
+   ```yml
+   class: "Foo\Var"
+   ```
+
+   After:
+
+   ```yml
+   class: "Foo\\Var"
+   ```
+
+2.1.0
+-----
+
+ * Yaml::parse() does not evaluate loaded files as PHP files by default
+   anymore (call Yaml::enablePhpParsing() to get back the old behavior)

+ 248 - 0
api/vendor/symfony/yaml/Command/LintCommand.php

@@ -0,0 +1,248 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Exception\InvalidArgumentException;
+use Symfony\Component\Console\Exception\RuntimeException;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Parser;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * Validates YAML files syntax and outputs encountered errors.
+ *
+ * @author Grégoire Pineau <lyrixx@lyrixx.info>
+ * @author Robin Chalas <robin.chalas@gmail.com>
+ */
+class LintCommand extends Command
+{
+    protected static $defaultName = 'lint:yaml';
+
+    private $parser;
+    private $format;
+    private $displayCorrectFiles;
+    private $directoryIteratorProvider;
+    private $isReadableProvider;
+
+    public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null)
+    {
+        parent::__construct($name);
+
+        $this->directoryIteratorProvider = $directoryIteratorProvider;
+        $this->isReadableProvider = $isReadableProvider;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this
+            ->setDescription('Lints a file and outputs encountered errors')
+            ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
+            ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
+            ->addOption('parse-tags', null, InputOption::VALUE_NONE, 'Parse custom tags')
+            ->setHelp(<<<EOF
+The <info>%command.name%</info> command lints a YAML file and outputs to STDOUT
+the first encountered syntax error.
+
+You can validates YAML contents passed from STDIN:
+
+  <info>cat filename | php %command.full_name% -</info>
+
+You can also validate the syntax of a file:
+
+  <info>php %command.full_name% filename</info>
+
+Or of a whole directory:
+
+  <info>php %command.full_name% dirname</info>
+  <info>php %command.full_name% dirname --format=json</info>
+
+EOF
+            )
+        ;
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $io = new SymfonyStyle($input, $output);
+        $filenames = (array) $input->getArgument('filename');
+        $this->format = $input->getOption('format');
+        $this->displayCorrectFiles = $output->isVerbose();
+        $flags = $input->getOption('parse-tags') ? Yaml::PARSE_CUSTOM_TAGS : 0;
+
+        if (['-'] === $filenames) {
+            return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
+        }
+
+        if (!$filenames) {
+            throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
+        }
+
+        $filesInfo = [];
+        foreach ($filenames as $filename) {
+            if (!$this->isReadable($filename)) {
+                throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
+            }
+
+            foreach ($this->getFiles($filename) as $file) {
+                $filesInfo[] = $this->validate(file_get_contents($file), $flags, $file);
+            }
+        }
+
+        return $this->display($io, $filesInfo);
+    }
+
+    private function validate(string $content, int $flags, string $file = null)
+    {
+        $prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) {
+            if (E_USER_DEPRECATED === $level) {
+                throw new ParseException($message, $this->getParser()->getRealCurrentLineNb() + 1);
+            }
+
+            return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false;
+        });
+
+        try {
+            $this->getParser()->parse($content, Yaml::PARSE_CONSTANT | $flags);
+        } catch (ParseException $e) {
+            return ['file' => $file, 'line' => $e->getParsedLine(), 'valid' => false, 'message' => $e->getMessage()];
+        } finally {
+            restore_error_handler();
+        }
+
+        return ['file' => $file, 'valid' => true];
+    }
+
+    private function display(SymfonyStyle $io, array $files): int
+    {
+        switch ($this->format) {
+            case 'txt':
+                return $this->displayTxt($io, $files);
+            case 'json':
+                return $this->displayJson($io, $files);
+            default:
+                throw new InvalidArgumentException(sprintf('The format "%s" is not supported.', $this->format));
+        }
+    }
+
+    private function displayTxt(SymfonyStyle $io, array $filesInfo): int
+    {
+        $countFiles = \count($filesInfo);
+        $erroredFiles = 0;
+        $suggestTagOption = false;
+
+        foreach ($filesInfo as $info) {
+            if ($info['valid'] && $this->displayCorrectFiles) {
+                $io->comment('<info>OK</info>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
+            } elseif (!$info['valid']) {
+                ++$erroredFiles;
+                $io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
+                $io->text(sprintf('<error> >> %s</error>', $info['message']));
+
+                if (false !== strpos($info['message'], 'PARSE_CUSTOM_TAGS')) {
+                    $suggestTagOption = true;
+                }
+            }
+        }
+
+        if (0 === $erroredFiles) {
+            $io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles));
+        } else {
+            $io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.%s', $countFiles - $erroredFiles, $erroredFiles, $suggestTagOption ? ' Use the --parse-tags option if you want parse custom tags.' : ''));
+        }
+
+        return min($erroredFiles, 1);
+    }
+
+    private function displayJson(SymfonyStyle $io, array $filesInfo): int
+    {
+        $errors = 0;
+
+        array_walk($filesInfo, function (&$v) use (&$errors) {
+            $v['file'] = (string) $v['file'];
+            if (!$v['valid']) {
+                ++$errors;
+            }
+
+            if (isset($v['message']) && false !== strpos($v['message'], 'PARSE_CUSTOM_TAGS')) {
+                $v['message'] .= ' Use the --parse-tags option if you want parse custom tags.';
+            }
+        });
+
+        $io->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
+
+        return min($errors, 1);
+    }
+
+    private function getFiles(string $fileOrDirectory): iterable
+    {
+        if (is_file($fileOrDirectory)) {
+            yield new \SplFileInfo($fileOrDirectory);
+
+            return;
+        }
+
+        foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
+            if (!\in_array($file->getExtension(), ['yml', 'yaml'])) {
+                continue;
+            }
+
+            yield $file;
+        }
+    }
+
+    private function getParser(): Parser
+    {
+        if (!$this->parser) {
+            $this->parser = new Parser();
+        }
+
+        return $this->parser;
+    }
+
+    private function getDirectoryIterator(string $directory): iterable
+    {
+        $default = function ($directory) {
+            return new \RecursiveIteratorIterator(
+                new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS),
+                \RecursiveIteratorIterator::LEAVES_ONLY
+            );
+        };
+
+        if (null !== $this->directoryIteratorProvider) {
+            return ($this->directoryIteratorProvider)($directory, $default);
+        }
+
+        return $default($directory);
+    }
+
+    private function isReadable(string $fileOrDirectory): bool
+    {
+        $default = function ($fileOrDirectory) {
+            return is_readable($fileOrDirectory);
+        };
+
+        if (null !== $this->isReadableProvider) {
+            return ($this->isReadableProvider)($fileOrDirectory, $default);
+        }
+
+        return $default($fileOrDirectory);
+    }
+}

+ 125 - 0
api/vendor/symfony/yaml/Dumper.php

@@ -0,0 +1,125 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml;
+
+use Symfony\Component\Yaml\Tag\TaggedValue;
+
+/**
+ * Dumper dumps PHP variables to YAML strings.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @final
+ */
+class Dumper
+{
+    /**
+     * The amount of spaces to use for indentation of nested nodes.
+     *
+     * @var int
+     */
+    protected $indentation;
+
+    public function __construct(int $indentation = 4)
+    {
+        if ($indentation < 1) {
+            throw new \InvalidArgumentException('The indentation must be greater than zero.');
+        }
+
+        $this->indentation = $indentation;
+    }
+
+    /**
+     * Dumps a PHP value to YAML.
+     *
+     * @param mixed $input  The PHP value
+     * @param int   $inline The level where you switch to inline YAML
+     * @param int   $indent The level of indentation (used internally)
+     * @param int   $flags  A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
+     *
+     * @return string The YAML representation of the PHP value
+     */
+    public function dump($input, int $inline = 0, int $indent = 0, int $flags = 0): string
+    {
+        $output = '';
+        $prefix = $indent ? str_repeat(' ', $indent) : '';
+        $dumpObjectAsInlineMap = true;
+
+        if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($input instanceof \ArrayObject || $input instanceof \stdClass)) {
+            $dumpObjectAsInlineMap = empty((array) $input);
+        }
+
+        if ($inline <= 0 || (!\is_array($input) && !$input instanceof TaggedValue && $dumpObjectAsInlineMap) || empty($input)) {
+            $output .= $prefix.Inline::dump($input, $flags);
+        } else {
+            $dumpAsMap = Inline::isHash($input);
+
+            foreach ($input as $key => $value) {
+                if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value) && false !== strpos($value, "\n") && false === strpos($value, "\r")) {
+                    // If the first line starts with a space character, the spec requires a blockIndicationIndicator
+                    // http://www.yaml.org/spec/1.2/spec.html#id2793979
+                    $blockIndentationIndicator = (' ' === substr($value, 0, 1)) ? (string) $this->indentation : '';
+                    $output .= sprintf("%s%s%s |%s\n", $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator);
+
+                    foreach (explode("\n", $value) as $row) {
+                        $output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row);
+                    }
+
+                    continue;
+                }
+
+                if ($value instanceof TaggedValue) {
+                    $output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag());
+
+                    if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && false !== strpos($value->getValue(), "\n") && false === strpos($value->getValue(), "\r\n")) {
+                        // If the first line starts with a space character, the spec requires a blockIndicationIndicator
+                        // http://www.yaml.org/spec/1.2/spec.html#id2793979
+                        $blockIndentationIndicator = (' ' === substr($value->getValue(), 0, 1)) ? (string) $this->indentation : '';
+                        $output .= sprintf(" |%s\n", $blockIndentationIndicator);
+
+                        foreach (explode("\n", $value->getValue()) as $row) {
+                            $output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row);
+                        }
+
+                        continue;
+                    }
+
+                    if ($inline - 1 <= 0 || null === $value->getValue() || is_scalar($value->getValue())) {
+                        $output .= ' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n";
+                    } else {
+                        $output .= "\n";
+                        $output .= $this->dump($value->getValue(), $inline - 1, $dumpAsMap ? $indent + $this->indentation : $indent + 2, $flags);
+                    }
+
+                    continue;
+                }
+
+                $dumpObjectAsInlineMap = true;
+
+                if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \ArrayObject || $value instanceof \stdClass)) {
+                    $dumpObjectAsInlineMap = empty((array) $value);
+                }
+
+                $willBeInlined = $inline - 1 <= 0 || !\is_array($value) && $dumpObjectAsInlineMap || empty($value);
+
+                $output .= sprintf('%s%s%s%s',
+                    $prefix,
+                    $dumpAsMap ? Inline::dump($key, $flags).':' : '-',
+                    $willBeInlined ? ' ' : "\n",
+                    $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $flags)
+                ).($willBeInlined ? "\n" : '');
+            }
+        }
+
+        return $output;
+    }
+}

+ 103 - 0
api/vendor/symfony/yaml/Escaper.php

@@ -0,0 +1,103 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml;
+
+/**
+ * Escaper encapsulates escaping rules for single and double-quoted
+ * YAML strings.
+ *
+ * @author Matthew Lewinski <matthew@lewinski.org>
+ *
+ * @internal
+ */
+class Escaper
+{
+    // Characters that would cause a dumped string to require double quoting.
+    const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\x7f|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";
+
+    // Mapping arrays for escaping a double quoted string. The backslash is
+    // first to ensure proper escaping because str_replace operates iteratively
+    // on the input arrays. This ordering of the characters avoids the use of strtr,
+    // which performs more slowly.
+    private static $escapees = ['\\', '\\\\', '\\"', '"',
+                                     "\x00",  "\x01",  "\x02",  "\x03",  "\x04",  "\x05",  "\x06",  "\x07",
+                                     "\x08",  "\x09",  "\x0a",  "\x0b",  "\x0c",  "\x0d",  "\x0e",  "\x0f",
+                                     "\x10",  "\x11",  "\x12",  "\x13",  "\x14",  "\x15",  "\x16",  "\x17",
+                                     "\x18",  "\x19",  "\x1a",  "\x1b",  "\x1c",  "\x1d",  "\x1e",  "\x1f",
+                                     "\x7f",
+                                     "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9",
+                               ];
+    private static $escaped = ['\\\\', '\\"', '\\\\', '\\"',
+                                     '\\0',   '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\a',
+                                     '\\b',   '\\t',   '\\n',   '\\v',   '\\f',   '\\r',   '\\x0e', '\\x0f',
+                                     '\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17',
+                                     '\\x18', '\\x19', '\\x1a', '\\e',   '\\x1c', '\\x1d', '\\x1e', '\\x1f',
+                                     '\\x7f',
+                                     '\\N', '\\_', '\\L', '\\P',
+                              ];
+
+    /**
+     * Determines if a PHP value would require double quoting in YAML.
+     *
+     * @param string $value A PHP value
+     *
+     * @return bool True if the value would require double quotes
+     */
+    public static function requiresDoubleQuoting(string $value): bool
+    {
+        return 0 < preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
+    }
+
+    /**
+     * Escapes and surrounds a PHP value with double quotes.
+     *
+     * @param string $value A PHP value
+     *
+     * @return string The quoted, escaped string
+     */
+    public static function escapeWithDoubleQuotes(string $value): string
+    {
+        return sprintf('"%s"', str_replace(self::$escapees, self::$escaped, $value));
+    }
+
+    /**
+     * Determines if a PHP value would require single quoting in YAML.
+     *
+     * @param string $value A PHP value
+     *
+     * @return bool True if the value would require single quotes
+     */
+    public static function requiresSingleQuoting(string $value): bool
+    {
+        // Determines if a PHP value is entirely composed of a value that would
+        // require single quoting in YAML.
+        if (\in_array(strtolower($value), ['null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'])) {
+            return true;
+        }
+
+        // Determines if the PHP value contains any single characters that would
+        // cause it to require single quoting in YAML.
+        return 0 < preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value);
+    }
+
+    /**
+     * Escapes and surrounds a PHP value with single quotes.
+     *
+     * @param string $value A PHP value
+     *
+     * @return string The quoted, escaped string
+     */
+    public static function escapeWithSingleQuotes(string $value): string
+    {
+        return sprintf("'%s'", str_replace('\'', '\'\'', $value));
+    }
+}

+ 21 - 0
api/vendor/symfony/yaml/Exception/DumpException.php

@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml\Exception;
+
+/**
+ * Exception class thrown when an error occurs during dumping.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class DumpException extends RuntimeException
+{
+}

+ 21 - 0
api/vendor/symfony/yaml/Exception/ExceptionInterface.php

@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml\Exception;
+
+/**
+ * Exception interface for all exceptions thrown by the component.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+interface ExceptionInterface extends \Throwable
+{
+}

+ 133 - 0
api/vendor/symfony/yaml/Exception/ParseException.php

@@ -0,0 +1,133 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml\Exception;
+
+/**
+ * Exception class thrown when an error occurs during parsing.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ParseException extends RuntimeException
+{
+    private $parsedFile;
+    private $parsedLine;
+    private $snippet;
+    private $rawMessage;
+
+    /**
+     * @param string          $message    The error message
+     * @param int             $parsedLine The line where the error occurred
+     * @param string|null     $snippet    The snippet of code near the problem
+     * @param string|null     $parsedFile The file name where the error occurred
+     * @param \Exception|null $previous   The previous exception
+     */
+    public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null)
+    {
+        $this->parsedFile = $parsedFile;
+        $this->parsedLine = $parsedLine;
+        $this->snippet = $snippet;
+        $this->rawMessage = $message;
+
+        $this->updateRepr();
+
+        parent::__construct($this->message, 0, $previous);
+    }
+
+    /**
+     * Gets the snippet of code near the error.
+     *
+     * @return string The snippet of code
+     */
+    public function getSnippet()
+    {
+        return $this->snippet;
+    }
+
+    /**
+     * Sets the snippet of code near the error.
+     */
+    public function setSnippet(string $snippet)
+    {
+        $this->snippet = $snippet;
+
+        $this->updateRepr();
+    }
+
+    /**
+     * Gets the filename where the error occurred.
+     *
+     * This method returns null if a string is parsed.
+     *
+     * @return string The filename
+     */
+    public function getParsedFile()
+    {
+        return $this->parsedFile;
+    }
+
+    /**
+     * Sets the filename where the error occurred.
+     */
+    public function setParsedFile(string $parsedFile)
+    {
+        $this->parsedFile = $parsedFile;
+
+        $this->updateRepr();
+    }
+
+    /**
+     * Gets the line where the error occurred.
+     *
+     * @return int The file line
+     */
+    public function getParsedLine()
+    {
+        return $this->parsedLine;
+    }
+
+    /**
+     * Sets the line where the error occurred.
+     */
+    public function setParsedLine(int $parsedLine)
+    {
+        $this->parsedLine = $parsedLine;
+
+        $this->updateRepr();
+    }
+
+    private function updateRepr()
+    {
+        $this->message = $this->rawMessage;
+
+        $dot = false;
+        if ('.' === substr($this->message, -1)) {
+            $this->message = substr($this->message, 0, -1);
+            $dot = true;
+        }
+
+        if (null !== $this->parsedFile) {
+            $this->message .= sprintf(' in %s', json_encode($this->parsedFile, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
+        }
+
+        if ($this->parsedLine >= 0) {
+            $this->message .= sprintf(' at line %d', $this->parsedLine);
+        }
+
+        if ($this->snippet) {
+            $this->message .= sprintf(' (near "%s")', $this->snippet);
+        }
+
+        if ($dot) {
+            $this->message .= '.';
+        }
+    }
+}

+ 21 - 0
api/vendor/symfony/yaml/Exception/RuntimeException.php

@@ -0,0 +1,21 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml\Exception;
+
+/**
+ * Exception class thrown when an error occurs during parsing.
+ *
+ * @author Romain Neutron <imprec@gmail.com>
+ */
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}

+ 793 - 0
api/vendor/symfony/yaml/Inline.php

@@ -0,0 +1,793 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml;
+
+use Symfony\Component\Yaml\Exception\DumpException;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Tag\TaggedValue;
+
+/**
+ * Inline implements a YAML parser/dumper for the YAML inline syntax.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @internal
+ */
+class Inline
+{
+    const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
+
+    public static $parsedLineNumber = -1;
+    public static $parsedFilename;
+
+    private static $exceptionOnInvalidType = false;
+    private static $objectSupport = false;
+    private static $objectForMap = false;
+    private static $constantSupport = false;
+
+    public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null)
+    {
+        self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
+        self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
+        self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
+        self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
+        self::$parsedFilename = $parsedFilename;
+
+        if (null !== $parsedLineNumber) {
+            self::$parsedLineNumber = $parsedLineNumber;
+        }
+    }
+
+    /**
+     * Converts a YAML string to a PHP value.
+     *
+     * @param string $value      A YAML string
+     * @param int    $flags      A bit field of PARSE_* constants to customize the YAML parser behavior
+     * @param array  $references Mapping of variable names to values
+     *
+     * @return mixed A PHP value
+     *
+     * @throws ParseException
+     */
+    public static function parse(string $value = null, int $flags = 0, array $references = [])
+    {
+        self::initialize($flags);
+
+        $value = trim($value);
+
+        if ('' === $value) {
+            return '';
+        }
+
+        if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
+            $mbEncoding = mb_internal_encoding();
+            mb_internal_encoding('ASCII');
+        }
+
+        try {
+            $i = 0;
+            $tag = self::parseTag($value, $i, $flags);
+            switch ($value[$i]) {
+                case '[':
+                    $result = self::parseSequence($value, $flags, $i, $references);
+                    ++$i;
+                    break;
+                case '{':
+                    $result = self::parseMapping($value, $flags, $i, $references);
+                    ++$i;
+                    break;
+                default:
+                    $result = self::parseScalar($value, $flags, null, $i, null === $tag, $references);
+            }
+
+            // some comments are allowed at the end
+            if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) {
+                throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
+            }
+
+            if (null !== $tag && '' !== $tag) {
+                return new TaggedValue($tag, $result);
+            }
+
+            return $result;
+        } finally {
+            if (isset($mbEncoding)) {
+                mb_internal_encoding($mbEncoding);
+            }
+        }
+    }
+
+    /**
+     * Dumps a given PHP variable to a YAML string.
+     *
+     * @param mixed $value The PHP variable to convert
+     * @param int   $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
+     *
+     * @return string The YAML string representing the PHP value
+     *
+     * @throws DumpException When trying to dump PHP resource
+     */
+    public static function dump($value, int $flags = 0): string
+    {
+        switch (true) {
+            case \is_resource($value):
+                if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
+                    throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
+                }
+
+                return self::dumpNull($flags);
+            case $value instanceof \DateTimeInterface:
+                return $value->format('c');
+            case \is_object($value):
+                if ($value instanceof TaggedValue) {
+                    return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags);
+                }
+
+                if (Yaml::DUMP_OBJECT & $flags) {
+                    return '!php/object '.self::dump(serialize($value));
+                }
+
+                if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
+                    $output = [];
+
+                    foreach ($value as $key => $val) {
+                        $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
+                    }
+
+                    return sprintf('{ %s }', implode(', ', $output));
+                }
+
+                if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
+                    throw new DumpException('Object support when dumping a YAML file has been disabled.');
+                }
+
+                return self::dumpNull($flags);
+            case \is_array($value):
+                return self::dumpArray($value, $flags);
+            case null === $value:
+                return self::dumpNull($flags);
+            case true === $value:
+                return 'true';
+            case false === $value:
+                return 'false';
+            case ctype_digit($value):
+                return \is_string($value) ? "'$value'" : (int) $value;
+            case is_numeric($value):
+                $locale = setlocale(LC_NUMERIC, 0);
+                if (false !== $locale) {
+                    setlocale(LC_NUMERIC, 'C');
+                }
+                if (\is_float($value)) {
+                    $repr = (string) $value;
+                    if (is_infinite($value)) {
+                        $repr = str_ireplace('INF', '.Inf', $repr);
+                    } elseif (floor($value) == $value && $repr == $value) {
+                        // Preserve float data type since storing a whole number will result in integer value.
+                        $repr = '!!float '.$repr;
+                    }
+                } else {
+                    $repr = \is_string($value) ? "'$value'" : (string) $value;
+                }
+                if (false !== $locale) {
+                    setlocale(LC_NUMERIC, $locale);
+                }
+
+                return $repr;
+            case '' == $value:
+                return "''";
+            case self::isBinaryString($value):
+                return '!!binary '.base64_encode($value);
+            case Escaper::requiresDoubleQuoting($value):
+                return Escaper::escapeWithDoubleQuotes($value);
+            case Escaper::requiresSingleQuoting($value):
+            case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value):
+            case Parser::preg_match(self::getHexRegex(), $value):
+            case Parser::preg_match(self::getTimestampRegex(), $value):
+                return Escaper::escapeWithSingleQuotes($value);
+            default:
+                return $value;
+        }
+    }
+
+    /**
+     * Check if given array is hash or just normal indexed array.
+     *
+     * @param array|\ArrayObject|\stdClass $value The PHP array or array-like object to check
+     *
+     * @return bool true if value is hash array, false otherwise
+     */
+    public static function isHash($value): bool
+    {
+        if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
+            return true;
+        }
+
+        $expectedKey = 0;
+
+        foreach ($value as $key => $val) {
+            if ($key !== $expectedKey++) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Dumps a PHP array to a YAML string.
+     *
+     * @param array $value The PHP array to dump
+     * @param int   $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
+     *
+     * @return string The YAML string representing the PHP array
+     */
+    private static function dumpArray(array $value, int $flags): string
+    {
+        // array
+        if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
+            $output = [];
+            foreach ($value as $val) {
+                $output[] = self::dump($val, $flags);
+            }
+
+            return sprintf('[%s]', implode(', ', $output));
+        }
+
+        // hash
+        $output = [];
+        foreach ($value as $key => $val) {
+            $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
+        }
+
+        return sprintf('{ %s }', implode(', ', $output));
+    }
+
+    private static function dumpNull(int $flags): string
+    {
+        if (Yaml::DUMP_NULL_AS_TILDE & $flags) {
+            return '~';
+        }
+
+        return 'null';
+    }
+
+    /**
+     * Parses a YAML scalar.
+     *
+     * @return mixed
+     *
+     * @throws ParseException When malformed inline YAML string is parsed
+     */
+    public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array $references = [])
+    {
+        if (\in_array($scalar[$i], ['"', "'"], true)) {
+            // quoted scalar
+            $output = self::parseQuotedScalar($scalar, $i);
+
+            if (null !== $delimiters) {
+                $tmp = ltrim(substr($scalar, $i), " \n");
+                if ('' === $tmp) {
+                    throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+                }
+                if (!\in_array($tmp[0], $delimiters)) {
+                    throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+                }
+            }
+        } else {
+            // "normal" string
+            if (!$delimiters) {
+                $output = substr($scalar, $i);
+                $i += \strlen($output);
+
+                // remove comments
+                if (Parser::preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) {
+                    $output = substr($output, 0, $match[0][1]);
+                }
+            } elseif (Parser::preg_match('/^(.*?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
+                $output = $match[1];
+                $i += \strlen($output);
+                $output = trim($output);
+            } else {
+                throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename);
+            }
+
+            // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
+            if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0] || '%' === $output[0])) {
+                throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]), self::$parsedLineNumber + 1, $output, self::$parsedFilename);
+            }
+
+            if ($evaluate) {
+                $output = self::evaluateScalar($output, $flags, $references);
+            }
+        }
+
+        return $output;
+    }
+
+    /**
+     * Parses a YAML quoted scalar.
+     *
+     * @throws ParseException When malformed inline YAML string is parsed
+     */
+    private static function parseQuotedScalar(string $scalar, int &$i): string
+    {
+        if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
+            throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+        }
+
+        $output = substr($match[0], 1, -1);
+
+        $unescaper = new Unescaper();
+        if ('"' == $scalar[$i]) {
+            $output = $unescaper->unescapeDoubleQuotedString($output);
+        } else {
+            $output = $unescaper->unescapeSingleQuotedString($output);
+        }
+
+        $i += \strlen($match[0]);
+
+        return $output;
+    }
+
+    /**
+     * Parses a YAML sequence.
+     *
+     * @throws ParseException When malformed inline YAML string is parsed
+     */
+    private static function parseSequence(string $sequence, int $flags, int &$i = 0, array $references = []): array
+    {
+        $output = [];
+        $len = \strlen($sequence);
+        ++$i;
+
+        // [foo, bar, ...]
+        while ($i < $len) {
+            if (']' === $sequence[$i]) {
+                return $output;
+            }
+            if (',' === $sequence[$i] || ' ' === $sequence[$i]) {
+                ++$i;
+
+                continue;
+            }
+
+            $tag = self::parseTag($sequence, $i, $flags);
+            switch ($sequence[$i]) {
+                case '[':
+                    // nested sequence
+                    $value = self::parseSequence($sequence, $flags, $i, $references);
+                    break;
+                case '{':
+                    // nested mapping
+                    $value = self::parseMapping($sequence, $flags, $i, $references);
+                    break;
+                default:
+                    $isQuoted = \in_array($sequence[$i], ['"', "'"], true);
+                    $value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references);
+
+                    // the value can be an array if a reference has been resolved to an array var
+                    if (\is_string($value) && !$isQuoted && false !== strpos($value, ': ')) {
+                        // embedded mapping?
+                        try {
+                            $pos = 0;
+                            $value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
+                        } catch (\InvalidArgumentException $e) {
+                            // no, it's not
+                        }
+                    }
+
+                    --$i;
+            }
+
+            if (null !== $tag && '' !== $tag) {
+                $value = new TaggedValue($tag, $value);
+            }
+
+            $output[] = $value;
+
+            ++$i;
+        }
+
+        throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $sequence), self::$parsedLineNumber + 1, null, self::$parsedFilename);
+    }
+
+    /**
+     * Parses a YAML mapping.
+     *
+     * @return array|\stdClass
+     *
+     * @throws ParseException When malformed inline YAML string is parsed
+     */
+    private static function parseMapping(string $mapping, int $flags, int &$i = 0, array $references = [])
+    {
+        $output = [];
+        $len = \strlen($mapping);
+        ++$i;
+        $allowOverwrite = false;
+
+        // {foo: bar, bar:foo, ...}
+        while ($i < $len) {
+            switch ($mapping[$i]) {
+                case ' ':
+                case ',':
+                case "\n":
+                    ++$i;
+                    continue 2;
+                case '}':
+                    if (self::$objectForMap) {
+                        return (object) $output;
+                    }
+
+                    return $output;
+            }
+
+            // key
+            $offsetBeforeKeyParsing = $i;
+            $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
+            $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, []);
+
+            if ($offsetBeforeKeyParsing === $i) {
+                throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
+            }
+
+            if ('!php/const' === $key) {
+                $key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false, []);
+                $key = self::evaluateScalar($key, $flags);
+            }
+
+            if (false === $i = strpos($mapping, ':', $i)) {
+                break;
+            }
+
+            if (!$isKeyQuoted) {
+                $evaluatedKey = self::evaluateScalar($key, $flags, $references);
+
+                if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
+                    throw new ParseException('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead.', self::$parsedLineNumber + 1, $mapping);
+                }
+            }
+
+            if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}', "\n"], true))) {
+                throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
+            }
+
+            if ('<<' === $key) {
+                $allowOverwrite = true;
+            }
+
+            while ($i < $len) {
+                if (':' === $mapping[$i] || ' ' === $mapping[$i] || "\n" === $mapping[$i]) {
+                    ++$i;
+
+                    continue;
+                }
+
+                $tag = self::parseTag($mapping, $i, $flags);
+                switch ($mapping[$i]) {
+                    case '[':
+                        // nested sequence
+                        $value = self::parseSequence($mapping, $flags, $i, $references);
+                        // Spec: Keys MUST be unique; first one wins.
+                        // Parser cannot abort this mapping earlier, since lines
+                        // are processed sequentially.
+                        // But overwriting is allowed when a merge node is used in current block.
+                        if ('<<' === $key) {
+                            foreach ($value as $parsedValue) {
+                                $output += $parsedValue;
+                            }
+                        } elseif ($allowOverwrite || !isset($output[$key])) {
+                            if (null !== $tag) {
+                                $output[$key] = new TaggedValue($tag, $value);
+                            } else {
+                                $output[$key] = $value;
+                            }
+                        } elseif (isset($output[$key])) {
+                            throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
+                        }
+                        break;
+                    case '{':
+                        // nested mapping
+                        $value = self::parseMapping($mapping, $flags, $i, $references);
+                        // Spec: Keys MUST be unique; first one wins.
+                        // Parser cannot abort this mapping earlier, since lines
+                        // are processed sequentially.
+                        // But overwriting is allowed when a merge node is used in current block.
+                        if ('<<' === $key) {
+                            $output += $value;
+                        } elseif ($allowOverwrite || !isset($output[$key])) {
+                            if (null !== $tag) {
+                                $output[$key] = new TaggedValue($tag, $value);
+                            } else {
+                                $output[$key] = $value;
+                            }
+                        } elseif (isset($output[$key])) {
+                            throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
+                        }
+                        break;
+                    default:
+                        $value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references);
+                        // Spec: Keys MUST be unique; first one wins.
+                        // Parser cannot abort this mapping earlier, since lines
+                        // are processed sequentially.
+                        // But overwriting is allowed when a merge node is used in current block.
+                        if ('<<' === $key) {
+                            $output += $value;
+                        } elseif ($allowOverwrite || !isset($output[$key])) {
+                            if (null !== $tag) {
+                                $output[$key] = new TaggedValue($tag, $value);
+                            } else {
+                                $output[$key] = $value;
+                            }
+                        } elseif (isset($output[$key])) {
+                            throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
+                        }
+                        --$i;
+                }
+                ++$i;
+
+                continue 2;
+            }
+        }
+
+        throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename);
+    }
+
+    /**
+     * Evaluates scalars and replaces magic values.
+     *
+     * @return mixed The evaluated YAML string
+     *
+     * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
+     */
+    private static function evaluateScalar(string $scalar, int $flags, array $references = [])
+    {
+        $scalar = trim($scalar);
+
+        if ('*' === ($scalar[0] ?? '')) {
+            if (false !== $pos = strpos($scalar, '#')) {
+                $value = substr($scalar, 1, $pos - 2);
+            } else {
+                $value = substr($scalar, 1);
+            }
+
+            // an unquoted *
+            if (false === $value || '' === $value) {
+                throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
+            }
+
+            if (!\array_key_exists($value, $references)) {
+                throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
+            }
+
+            return $references[$value];
+        }
+
+        $scalarLower = strtolower($scalar);
+
+        switch (true) {
+            case 'null' === $scalarLower:
+            case '' === $scalar:
+            case '~' === $scalar:
+                return null;
+            case 'true' === $scalarLower:
+                return true;
+            case 'false' === $scalarLower:
+                return false;
+            case '!' === $scalar[0]:
+                switch (true) {
+                    case 0 === strncmp($scalar, '!!str ', 6):
+                        return (string) substr($scalar, 6);
+                    case 0 === strncmp($scalar, '! ', 2):
+                        return substr($scalar, 2);
+                    case 0 === strncmp($scalar, '!php/object', 11):
+                        if (self::$objectSupport) {
+                            if (!isset($scalar[12])) {
+                                trigger_deprecation('symfony/yaml', '5.1', 'Using the !php/object tag without a value is deprecated.');
+
+                                return false;
+                            }
+
+                            return unserialize(self::parseScalar(substr($scalar, 12)));
+                        }
+
+                        if (self::$exceptionOnInvalidType) {
+                            throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+                        }
+
+                        return null;
+                    case 0 === strncmp($scalar, '!php/const', 10):
+                        if (self::$constantSupport) {
+                            if (!isset($scalar[11])) {
+                                trigger_deprecation('symfony/yaml', '5.1', 'Using the !php/const tag without a value is deprecated.');
+
+                                return '';
+                            }
+
+                            $i = 0;
+                            if (\defined($const = self::parseScalar(substr($scalar, 11), 0, null, $i, false))) {
+                                return \constant($const);
+                            }
+
+                            throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+                        }
+                        if (self::$exceptionOnInvalidType) {
+                            throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+                        }
+
+                        return null;
+                    case 0 === strncmp($scalar, '!!float ', 8):
+                        return (float) substr($scalar, 8);
+                    case 0 === strncmp($scalar, '!!binary ', 9):
+                        return self::evaluateBinaryScalar(substr($scalar, 9));
+                    default:
+                        throw new ParseException(sprintf('The string "%s" could not be parsed as it uses an unsupported built-in tag.', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename);
+                }
+            case preg_match('/^(?:\+|-)?0o(?P<value>[0-7_]++)$/', $scalar, $matches):
+                $value = str_replace('_', '', $matches['value']);
+
+                if ('-' === $scalar[0]) {
+                    return -octdec($value);
+                } else {
+                    return octdec($value);
+                }
+
+            // Optimize for returning strings.
+            // no break
+            case \in_array($scalar[0], ['+', '-', '.'], true) || is_numeric($scalar[0]):
+                if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
+                    $scalar = str_replace('_', '', (string) $scalar);
+                }
+
+                switch (true) {
+                    case ctype_digit($scalar):
+                        if ('0' === $scalar[0] && '0' !== $scalar) {
+                            trigger_deprecation('symfony/yaml', '5.1', 'Support for parsing numbers prefixed with 0 as octal numbers. They will be parsed as strings as of 6.0.');
+
+                            return octdec(preg_replace('/[^0-7]/', '', $scalar));
+                        }
+
+                        $cast = (int) $scalar;
+
+                        return ($scalar === (string) $cast) ? $cast : $scalar;
+                    case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
+                        if ('0' === $scalar[1] && '-0' !== $scalar) {
+                            trigger_deprecation('symfony/yaml', '5.1', 'Support for parsing numbers prefixed with 0 as octal numbers. They will be parsed as strings as of 6.0.');
+
+                            return -octdec(preg_replace('/[^0-7]/', '', substr($scalar, 1)));
+                        }
+
+                        $cast = (int) $scalar;
+
+                        return ($scalar === (string) $cast) ? $cast : $scalar;
+                    case is_numeric($scalar):
+                    case Parser::preg_match(self::getHexRegex(), $scalar):
+                        $scalar = str_replace('_', '', $scalar);
+
+                        return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
+                    case '.inf' === $scalarLower:
+                    case '.nan' === $scalarLower:
+                        return -log(0);
+                    case '-.inf' === $scalarLower:
+                        return log(0);
+                    case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
+                        return (float) str_replace('_', '', $scalar);
+                    case Parser::preg_match(self::getTimestampRegex(), $scalar):
+                        if (Yaml::PARSE_DATETIME & $flags) {
+                            // When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
+                            return new \DateTime($scalar, new \DateTimeZone('UTC'));
+                        }
+
+                        $timeZone = date_default_timezone_get();
+                        date_default_timezone_set('UTC');
+                        $time = strtotime($scalar);
+                        date_default_timezone_set($timeZone);
+
+                        return $time;
+                }
+        }
+
+        return (string) $scalar;
+    }
+
+    private static function parseTag(string $value, int &$i, int $flags): ?string
+    {
+        if ('!' !== $value[$i]) {
+            return null;
+        }
+
+        $tagLength = strcspn($value, " \t\n[]{},", $i + 1);
+        $tag = substr($value, $i + 1, $tagLength);
+
+        $nextOffset = $i + $tagLength + 1;
+        $nextOffset += strspn($value, ' ', $nextOffset);
+
+        if ('' === $tag && (!isset($value[$nextOffset]) || \in_array($value[$nextOffset], [']', '}', ','], true))) {
+            throw new ParseException(sprintf('Using the unquoted scalar value "!" is not supported. You must quote it.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
+        }
+
+        // Is followed by a scalar and is a built-in tag
+        if ('' !== $tag && (!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && ('!' === $tag[0] || 'str' === $tag || 'php/const' === $tag || 'php/object' === $tag)) {
+            // Manage in {@link self::evaluateScalar()}
+            return null;
+        }
+
+        $i = $nextOffset;
+
+        // Built-in tags
+        if ('' !== $tag && '!' === $tag[0]) {
+            throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
+        }
+
+        if ('' !== $tag && !isset($value[$i])) {
+            throw new ParseException(sprintf('Missing value for tag "%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
+        }
+
+        if ('' === $tag || Yaml::PARSE_CUSTOM_TAGS & $flags) {
+            return $tag;
+        }
+
+        throw new ParseException(sprintf('Tags support is not enabled. Enable the "Yaml::PARSE_CUSTOM_TAGS" flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
+    }
+
+    public static function evaluateBinaryScalar(string $scalar): string
+    {
+        $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
+
+        if (0 !== (\strlen($parsedBinaryData) % 4)) {
+            throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', \strlen($parsedBinaryData)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+        }
+
+        if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
+            throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+        }
+
+        return base64_decode($parsedBinaryData, true);
+    }
+
+    private static function isBinaryString(string $value): bool
+    {
+        return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
+    }
+
+    /**
+     * Gets a regex that matches a YAML date.
+     *
+     * @return string The regular expression
+     *
+     * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
+     */
+    private static function getTimestampRegex(): string
+    {
+        return <<<EOF
+        ~^
+        (?P<year>[0-9][0-9][0-9][0-9])
+        -(?P<month>[0-9][0-9]?)
+        -(?P<day>[0-9][0-9]?)
+        (?:(?:[Tt]|[ \t]+)
+        (?P<hour>[0-9][0-9]?)
+        :(?P<minute>[0-9][0-9])
+        :(?P<second>[0-9][0-9])
+        (?:\.(?P<fraction>[0-9]*))?
+        (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
+        (?::(?P<tz_minute>[0-9][0-9]))?))?)?
+        $~x
+EOF;
+    }
+
+    /**
+     * Gets a regex that matches a YAML number in hexadecimal notation.
+     */
+    private static function getHexRegex(): string
+    {
+        return '~^0x[0-9a-f_]++$~i';
+    }
+}

+ 19 - 0
api/vendor/symfony/yaml/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2004-2020 Fabien Potencier
+
+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.

+ 1261 - 0
api/vendor/symfony/yaml/Parser.php

@@ -0,0 +1,1261 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml;
+
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Tag\TaggedValue;
+
+/**
+ * Parser parses YAML strings to convert them to PHP arrays.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @final
+ */
+class Parser
+{
+    const TAG_PATTERN = '(?P<tag>![\w!.\/:-]+)';
+    const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
+
+    private $filename;
+    private $offset = 0;
+    private $numberOfParsedLines = 0;
+    private $totalNumberOfLines;
+    private $lines = [];
+    private $currentLineNb = -1;
+    private $currentLine = '';
+    private $refs = [];
+    private $skippedLineNumbers = [];
+    private $locallySkippedLineNumbers = [];
+    private $refsBeingParsed = [];
+
+    /**
+     * Parses a YAML file into a PHP value.
+     *
+     * @param string $filename The path to the YAML file to be parsed
+     * @param int    $flags    A bit field of PARSE_* constants to customize the YAML parser behavior
+     *
+     * @return mixed The YAML converted to a PHP value
+     *
+     * @throws ParseException If the file could not be read or the YAML is not valid
+     */
+    public function parseFile(string $filename, int $flags = 0)
+    {
+        if (!is_file($filename)) {
+            throw new ParseException(sprintf('File "%s" does not exist.', $filename));
+        }
+
+        if (!is_readable($filename)) {
+            throw new ParseException(sprintf('File "%s" cannot be read.', $filename));
+        }
+
+        $this->filename = $filename;
+
+        try {
+            return $this->parse(file_get_contents($filename), $flags);
+        } finally {
+            $this->filename = null;
+        }
+    }
+
+    /**
+     * Parses a YAML string to a PHP value.
+     *
+     * @param string $value A YAML string
+     * @param int    $flags A bit field of PARSE_* constants to customize the YAML parser behavior
+     *
+     * @return mixed A PHP value
+     *
+     * @throws ParseException If the YAML is not valid
+     */
+    public function parse(string $value, int $flags = 0)
+    {
+        if (false === preg_match('//u', $value)) {
+            throw new ParseException('The YAML value does not appear to be valid UTF-8.', -1, null, $this->filename);
+        }
+
+        $this->refs = [];
+
+        $mbEncoding = null;
+
+        if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
+            $mbEncoding = mb_internal_encoding();
+            mb_internal_encoding('UTF-8');
+        }
+
+        try {
+            $data = $this->doParse($value, $flags);
+        } finally {
+            if (null !== $mbEncoding) {
+                mb_internal_encoding($mbEncoding);
+            }
+            $this->lines = [];
+            $this->currentLine = '';
+            $this->numberOfParsedLines = 0;
+            $this->refs = [];
+            $this->skippedLineNumbers = [];
+            $this->locallySkippedLineNumbers = [];
+        }
+
+        return $data;
+    }
+
+    private function doParse(string $value, int $flags)
+    {
+        $this->currentLineNb = -1;
+        $this->currentLine = '';
+        $value = $this->cleanup($value);
+        $this->lines = explode("\n", $value);
+        $this->numberOfParsedLines = \count($this->lines);
+        $this->locallySkippedLineNumbers = [];
+
+        if (null === $this->totalNumberOfLines) {
+            $this->totalNumberOfLines = $this->numberOfParsedLines;
+        }
+
+        if (!$this->moveToNextLine()) {
+            return null;
+        }
+
+        $data = [];
+        $context = null;
+        $allowOverwrite = false;
+
+        while ($this->isCurrentLineEmpty()) {
+            if (!$this->moveToNextLine()) {
+                return null;
+            }
+        }
+
+        // Resolves the tag and returns if end of the document
+        if (null !== ($tag = $this->getLineTag($this->currentLine, $flags, false)) && !$this->moveToNextLine()) {
+            return new TaggedValue($tag, '');
+        }
+
+        do {
+            if ($this->isCurrentLineEmpty()) {
+                continue;
+            }
+
+            // tab?
+            if ("\t" === $this->currentLine[0]) {
+                throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+            }
+
+            Inline::initialize($flags, $this->getRealCurrentLineNb(), $this->filename);
+
+            $isRef = $mergeNode = false;
+            if ('-' === $this->currentLine[0] && self::preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+))?$#u', rtrim($this->currentLine), $values)) {
+                if ($context && 'mapping' == $context) {
+                    throw new ParseException('You cannot define a sequence item when in a mapping.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                }
+                $context = 'sequence';
+
+                if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
+                    $isRef = $matches['ref'];
+                    $this->refsBeingParsed[] = $isRef;
+                    $values['value'] = $matches['value'];
+                }
+
+                if (isset($values['value'][1]) && '?' === $values['value'][0] && ' ' === $values['value'][1]) {
+                    throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
+                }
+
+                // array
+                if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
+                    $data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true) ?? '', $flags);
+                } elseif (null !== $subTag = $this->getLineTag(ltrim($values['value'], ' '), $flags)) {
+                    $data[] = new TaggedValue(
+                        $subTag,
+                        $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags)
+                    );
+                } else {
+                    if (isset($values['leadspaces'])
+                        && self::preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->trimTag($values['value']), $matches)
+                    ) {
+                        // this is a compact notation element, add to next block and parse
+                        $block = $values['value'];
+                        if ($this->isNextLineIndented()) {
+                            $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + \strlen($values['leadspaces']) + 1);
+                        }
+
+                        $data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $flags);
+                    } else {
+                        $data[] = $this->parseValue($values['value'], $flags, $context);
+                    }
+                }
+                if ($isRef) {
+                    $this->refs[$isRef] = end($data);
+                    array_pop($this->refsBeingParsed);
+                }
+            } elseif (
+                self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
+                && (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"]))
+            ) {
+                if ($context && 'sequence' == $context) {
+                    throw new ParseException('You cannot define a mapping item when in a sequence.', $this->currentLineNb + 1, $this->currentLine, $this->filename);
+                }
+                $context = 'mapping';
+
+                try {
+                    $key = Inline::parseScalar($values['key']);
+                } catch (ParseException $e) {
+                    $e->setParsedLine($this->getRealCurrentLineNb() + 1);
+                    $e->setSnippet($this->currentLine);
+
+                    throw $e;
+                }
+
+                if (!\is_string($key) && !\is_int($key)) {
+                    throw new ParseException(sprintf('%s keys are not supported. Quote your evaluable mapping keys instead.', is_numeric($key) ? 'Numeric' : 'Non-string'), $this->getRealCurrentLineNb() + 1, $this->currentLine);
+                }
+
+                // Convert float keys to strings, to avoid being converted to integers by PHP
+                if (\is_float($key)) {
+                    $key = (string) $key;
+                }
+
+                if ('<<' === $key && (!isset($values['value']) || '&' !== $values['value'][0] || !self::preg_match('#^&(?P<ref>[^ ]+)#u', $values['value'], $refMatches))) {
+                    $mergeNode = true;
+                    $allowOverwrite = true;
+                    if (isset($values['value'][0]) && '*' === $values['value'][0]) {
+                        $refName = substr(rtrim($values['value']), 1);
+                        if (!\array_key_exists($refName, $this->refs)) {
+                            if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) {
+                                throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $refName, $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename);
+                            }
+
+                            throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                        }
+
+                        $refValue = $this->refs[$refName];
+
+                        if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $refValue instanceof \stdClass) {
+                            $refValue = (array) $refValue;
+                        }
+
+                        if (!\is_array($refValue)) {
+                            throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                        }
+
+                        $data += $refValue; // array union
+                    } else {
+                        if (isset($values['value']) && '' !== $values['value']) {
+                            $value = $values['value'];
+                        } else {
+                            $value = $this->getNextEmbedBlock();
+                        }
+                        $parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $flags);
+
+                        if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsed instanceof \stdClass) {
+                            $parsed = (array) $parsed;
+                        }
+
+                        if (!\is_array($parsed)) {
+                            throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                        }
+
+                        if (isset($parsed[0])) {
+                            // If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes
+                            // and each of these nodes is merged in turn according to its order in the sequence. Keys in mapping nodes earlier
+                            // in the sequence override keys specified in later mapping nodes.
+                            foreach ($parsed as $parsedItem) {
+                                if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsedItem instanceof \stdClass) {
+                                    $parsedItem = (array) $parsedItem;
+                                }
+
+                                if (!\is_array($parsedItem)) {
+                                    throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem, $this->filename);
+                                }
+
+                                $data += $parsedItem; // array union
+                            }
+                        } else {
+                            // If the value associated with the key is a single mapping node, each of its key/value pairs is inserted into the
+                            // current mapping, unless the key already exists in it.
+                            $data += $parsed; // array union
+                        }
+                    }
+                } elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) {
+                    $isRef = $matches['ref'];
+                    $this->refsBeingParsed[] = $isRef;
+                    $values['value'] = $matches['value'];
+                }
+
+                $subTag = null;
+                if ($mergeNode) {
+                    // Merge keys
+                } elseif (!isset($values['value']) || '' === $values['value'] || '#' === ($values['value'][0] ?? '') || (null !== $subTag = $this->getLineTag($values['value'], $flags)) || '<<' === $key) {
+                    // hash
+                    // if next line is less indented or equal, then it means that the current value is null
+                    if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) {
+                        // Spec: Keys MUST be unique; first one wins.
+                        // But overwriting is allowed when a merge node is used in current block.
+                        if ($allowOverwrite || !isset($data[$key])) {
+                            if (null !== $subTag) {
+                                $data[$key] = new TaggedValue($subTag, '');
+                            } else {
+                                $data[$key] = null;
+                            }
+                        } else {
+                            throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine);
+                        }
+                    } else {
+                        // remember the parsed line number here in case we need it to provide some contexts in error messages below
+                        $realCurrentLineNbKey = $this->getRealCurrentLineNb();
+                        $value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $flags);
+                        if ('<<' === $key) {
+                            $this->refs[$refMatches['ref']] = $value;
+
+                            if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $value instanceof \stdClass) {
+                                $value = (array) $value;
+                            }
+
+                            $data += $value;
+                        } elseif ($allowOverwrite || !isset($data[$key])) {
+                            // Spec: Keys MUST be unique; first one wins.
+                            // But overwriting is allowed when a merge node is used in current block.
+                            if (null !== $subTag) {
+                                $data[$key] = new TaggedValue($subTag, $value);
+                            } else {
+                                $data[$key] = $value;
+                            }
+                        } else {
+                            throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $realCurrentLineNbKey + 1, $this->currentLine);
+                        }
+                    }
+                } else {
+                    $value = $this->parseValue(rtrim($values['value']), $flags, $context);
+                    // Spec: Keys MUST be unique; first one wins.
+                    // But overwriting is allowed when a merge node is used in current block.
+                    if ($allowOverwrite || !isset($data[$key])) {
+                        $data[$key] = $value;
+                    } else {
+                        throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine);
+                    }
+                }
+                if ($isRef) {
+                    $this->refs[$isRef] = $data[$key];
+                    array_pop($this->refsBeingParsed);
+                }
+            } elseif ('"' === $this->currentLine[0] || "'" === $this->currentLine[0]) {
+                if (null !== $context) {
+                    throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                }
+
+                try {
+                    return Inline::parse($this->parseQuotedString($this->currentLine), $flags, $this->refs);
+                } catch (ParseException $e) {
+                    $e->setParsedLine($this->getRealCurrentLineNb() + 1);
+                    $e->setSnippet($this->currentLine);
+
+                    throw $e;
+                }
+            } elseif ('{' === $this->currentLine[0]) {
+                if (null !== $context) {
+                    throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                }
+
+                try {
+                    $parsedMapping = Inline::parse($this->lexInlineMapping($this->currentLine), $flags, $this->refs);
+
+                    while ($this->moveToNextLine()) {
+                        if (!$this->isCurrentLineEmpty()) {
+                            throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                        }
+                    }
+
+                    return $parsedMapping;
+                } catch (ParseException $e) {
+                    $e->setParsedLine($this->getRealCurrentLineNb() + 1);
+                    $e->setSnippet($this->currentLine);
+
+                    throw $e;
+                }
+            } elseif ('[' === $this->currentLine[0]) {
+                if (null !== $context) {
+                    throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                }
+
+                try {
+                    $parsedSequence = Inline::parse($this->lexInlineSequence($this->currentLine), $flags, $this->refs);
+
+                    while ($this->moveToNextLine()) {
+                        if (!$this->isCurrentLineEmpty()) {
+                            throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                        }
+                    }
+
+                    return $parsedSequence;
+                } catch (ParseException $e) {
+                    $e->setParsedLine($this->getRealCurrentLineNb() + 1);
+                    $e->setSnippet($this->currentLine);
+
+                    throw $e;
+                }
+            } else {
+                // multiple documents are not supported
+                if ('---' === $this->currentLine) {
+                    throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine, $this->filename);
+                }
+
+                if ($deprecatedUsage = (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1])) {
+                    throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
+                }
+
+                // 1-liner optionally followed by newline(s)
+                if (\is_string($value) && $this->lines[0] === trim($value)) {
+                    try {
+                        $value = Inline::parse($this->lines[0], $flags, $this->refs);
+                    } catch (ParseException $e) {
+                        $e->setParsedLine($this->getRealCurrentLineNb() + 1);
+                        $e->setSnippet($this->currentLine);
+
+                        throw $e;
+                    }
+
+                    return $value;
+                }
+
+                // try to parse the value as a multi-line string as a last resort
+                if (0 === $this->currentLineNb) {
+                    $previousLineWasNewline = false;
+                    $previousLineWasTerminatedWithBackslash = false;
+                    $value = '';
+
+                    foreach ($this->lines as $line) {
+                        $trimmedLine = trim($line);
+                        if ('#' === ($trimmedLine[0] ?? '')) {
+                            continue;
+                        }
+                        // If the indentation is not consistent at offset 0, it is to be considered as a ParseError
+                        if (0 === $this->offset && !$deprecatedUsage && isset($line[0]) && ' ' === $line[0]) {
+                            throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                        }
+
+                        if (false !== strpos($line, ': ')) {
+                            throw new ParseException('Mapping values are not allowed in multi-line blocks.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+                        }
+
+                        if ('' === $trimmedLine) {
+                            $value .= "\n";
+                        } elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
+                            $value .= ' ';
+                        }
+
+                        if ('' !== $trimmedLine && '\\' === $line[-1]) {
+                            $value .= ltrim(substr($line, 0, -1));
+                        } elseif ('' !== $trimmedLine) {
+                            $value .= $trimmedLine;
+                        }
+
+                        if ('' === $trimmedLine) {
+                            $previousLineWasNewline = true;
+                            $previousLineWasTerminatedWithBackslash = false;
+                        } elseif ('\\' === $line[-1]) {
+                            $previousLineWasNewline = false;
+                            $previousLineWasTerminatedWithBackslash = true;
+                        } else {
+                            $previousLineWasNewline = false;
+                            $previousLineWasTerminatedWithBackslash = false;
+                        }
+                    }
+
+                    try {
+                        return Inline::parse(trim($value));
+                    } catch (ParseException $e) {
+                        // fall-through to the ParseException thrown below
+                    }
+                }
+
+                throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+            }
+        } while ($this->moveToNextLine());
+
+        if (null !== $tag) {
+            $data = new TaggedValue($tag, $data);
+        }
+
+        if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && 'mapping' === $context && !\is_object($data)) {
+            $object = new \stdClass();
+
+            foreach ($data as $key => $value) {
+                $object->$key = $value;
+            }
+
+            $data = $object;
+        }
+
+        return empty($data) ? null : $data;
+    }
+
+    private function parseBlock(int $offset, string $yaml, int $flags)
+    {
+        $skippedLineNumbers = $this->skippedLineNumbers;
+
+        foreach ($this->locallySkippedLineNumbers as $lineNumber) {
+            if ($lineNumber < $offset) {
+                continue;
+            }
+
+            $skippedLineNumbers[] = $lineNumber;
+        }
+
+        $parser = new self();
+        $parser->offset = $offset;
+        $parser->totalNumberOfLines = $this->totalNumberOfLines;
+        $parser->skippedLineNumbers = $skippedLineNumbers;
+        $parser->refs = &$this->refs;
+        $parser->refsBeingParsed = $this->refsBeingParsed;
+
+        return $parser->doParse($yaml, $flags);
+    }
+
+    /**
+     * Returns the current line number (takes the offset into account).
+     *
+     * @internal
+     *
+     * @return int The current line number
+     */
+    public function getRealCurrentLineNb(): int
+    {
+        $realCurrentLineNumber = $this->currentLineNb + $this->offset;
+
+        foreach ($this->skippedLineNumbers as $skippedLineNumber) {
+            if ($skippedLineNumber > $realCurrentLineNumber) {
+                break;
+            }
+
+            ++$realCurrentLineNumber;
+        }
+
+        return $realCurrentLineNumber;
+    }
+
+    /**
+     * Returns the current line indentation.
+     *
+     * @return int The current line indentation
+     */
+    private function getCurrentLineIndentation(): int
+    {
+        if (' ' !== ($this->currentLine[0] ?? '')) {
+            return 0;
+        }
+
+        return \strlen($this->currentLine) - \strlen(ltrim($this->currentLine, ' '));
+    }
+
+    /**
+     * Returns the next embed block of YAML.
+     *
+     * @param int|null $indentation The indent level at which the block is to be read, or null for default
+     * @param bool     $inSequence  True if the enclosing data structure is a sequence
+     *
+     * @return string A YAML string
+     *
+     * @throws ParseException When indentation problem are detected
+     */
+    private function getNextEmbedBlock(int $indentation = null, bool $inSequence = false): string
+    {
+        $oldLineIndentation = $this->getCurrentLineIndentation();
+
+        if (!$this->moveToNextLine()) {
+            return '';
+        }
+
+        if (null === $indentation) {
+            $newIndent = null;
+            $movements = 0;
+
+            do {
+                $EOF = false;
+
+                // empty and comment-like lines do not influence the indentation depth
+                if ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) {
+                    $EOF = !$this->moveToNextLine();
+
+                    if (!$EOF) {
+                        ++$movements;
+                    }
+                } else {
+                    $newIndent = $this->getCurrentLineIndentation();
+                }
+            } while (!$EOF && null === $newIndent);
+
+            for ($i = 0; $i < $movements; ++$i) {
+                $this->moveToPreviousLine();
+            }
+
+            $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem();
+
+            if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) {
+                throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+            }
+        } else {
+            $newIndent = $indentation;
+        }
+
+        $data = [];
+        if ($this->getCurrentLineIndentation() >= $newIndent) {
+            $data[] = substr($this->currentLine, $newIndent);
+        } elseif ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) {
+            $data[] = $this->currentLine;
+        } else {
+            $this->moveToPreviousLine();
+
+            return '';
+        }
+
+        if ($inSequence && $oldLineIndentation === $newIndent && isset($data[0][0]) && '-' === $data[0][0]) {
+            // the previous line contained a dash but no item content, this line is a sequence item with the same indentation
+            // and therefore no nested list or mapping
+            $this->moveToPreviousLine();
+
+            return '';
+        }
+
+        $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
+        $isItComment = $this->isCurrentLineComment();
+
+        while ($this->moveToNextLine()) {
+            if ($isItComment && !$isItUnindentedCollection) {
+                $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem();
+                $isItComment = $this->isCurrentLineComment();
+            }
+
+            $indent = $this->getCurrentLineIndentation();
+
+            if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
+                $this->moveToPreviousLine();
+                break;
+            }
+
+            if ($this->isCurrentLineBlank()) {
+                $data[] = substr($this->currentLine, $newIndent);
+                continue;
+            }
+
+            if ($indent >= $newIndent) {
+                $data[] = substr($this->currentLine, $newIndent);
+            } elseif ($this->isCurrentLineComment()) {
+                $data[] = $this->currentLine;
+            } elseif (0 == $indent) {
+                $this->moveToPreviousLine();
+
+                break;
+            } else {
+                throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
+            }
+        }
+
+        return implode("\n", $data);
+    }
+
+    /**
+     * Moves the parser to the next line.
+     */
+    private function moveToNextLine(): bool
+    {
+        if ($this->currentLineNb >= $this->numberOfParsedLines - 1) {
+            return false;
+        }
+
+        $this->currentLine = $this->lines[++$this->currentLineNb];
+
+        return true;
+    }
+
+    /**
+     * Moves the parser to the previous line.
+     */
+    private function moveToPreviousLine(): bool
+    {
+        if ($this->currentLineNb < 1) {
+            return false;
+        }
+
+        $this->currentLine = $this->lines[--$this->currentLineNb];
+
+        return true;
+    }
+
+    /**
+     * Parses a YAML value.
+     *
+     * @param string $value   A YAML value
+     * @param int    $flags   A bit field of PARSE_* constants to customize the YAML parser behavior
+     * @param string $context The parser context (either sequence or mapping)
+     *
+     * @return mixed A PHP value
+     *
+     * @throws ParseException When reference does not exist
+     */
+    private function parseValue(string $value, int $flags, string $context)
+    {
+        if ('*' === ($value[0] ?? '')) {
+            if (false !== $pos = strpos($value, '#')) {
+                $value = substr($value, 1, $pos - 2);
+            } else {
+                $value = substr($value, 1);
+            }
+
+            if (!\array_key_exists($value, $this->refs)) {
+                if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) {
+                    throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $value, $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
+                }
+
+                throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
+            }
+
+            return $this->refs[$value];
+        }
+
+        if (\in_array($value[0], ['!', '|', '>'], true) && self::preg_match('/^(?:'.self::TAG_PATTERN.' +)?'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
+            $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
+
+            $data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs((int) $modifiers));
+
+            if ('' !== $matches['tag'] && '!' !== $matches['tag']) {
+                if ('!!binary' === $matches['tag']) {
+                    return Inline::evaluateBinaryScalar($data);
+                }
+
+                return new TaggedValue(substr($matches['tag'], 1), $data);
+            }
+
+            return $data;
+        }
+
+        try {
+            if ('' !== $value && '{' === $value[0]) {
+                return Inline::parse($this->lexInlineMapping($value), $flags, $this->refs);
+            } elseif ('' !== $value && '[' === $value[0]) {
+                return Inline::parse($this->lexInlineSequence($value), $flags, $this->refs);
+            }
+
+            $quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
+
+            // do not take following lines into account when the current line is a quoted single line value
+            if (null !== $quotation && self::preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) {
+                return Inline::parse($value, $flags, $this->refs);
+            }
+
+            $lines = [];
+
+            while ($this->moveToNextLine()) {
+                // unquoted strings end before the first unindented line
+                if (null === $quotation && 0 === $this->getCurrentLineIndentation()) {
+                    $this->moveToPreviousLine();
+
+                    break;
+                }
+
+                $lines[] = trim($this->currentLine);
+
+                // quoted string values end with a line that is terminated with the quotation character
+                $escapedLine = str_replace(['\\\\', '\\"'], '', $this->currentLine);
+                if ('' !== $escapedLine && $escapedLine[-1] === $quotation) {
+                    break;
+                }
+            }
+
+            for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
+                if ('' === $lines[$i]) {
+                    $value .= "\n";
+                    $previousLineBlank = true;
+                } elseif ($previousLineBlank) {
+                    $value .= $lines[$i];
+                    $previousLineBlank = false;
+                } else {
+                    $value .= ' '.$lines[$i];
+                    $previousLineBlank = false;
+                }
+            }
+
+            Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
+
+            $parsedValue = Inline::parse($value, $flags, $this->refs);
+
+            if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
+                throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
+            }
+
+            return $parsedValue;
+        } catch (ParseException $e) {
+            $e->setParsedLine($this->getRealCurrentLineNb() + 1);
+            $e->setSnippet($this->currentLine);
+
+            throw $e;
+        }
+    }
+
+    /**
+     * Parses a block scalar.
+     *
+     * @param string $style       The style indicator that was used to begin this block scalar (| or >)
+     * @param string $chomping    The chomping indicator that was used to begin this block scalar (+ or -)
+     * @param int    $indentation The indentation indicator that was used to begin this block scalar
+     */
+    private function parseBlockScalar(string $style, string $chomping = '', int $indentation = 0): string
+    {
+        $notEOF = $this->moveToNextLine();
+        if (!$notEOF) {
+            return '';
+        }
+
+        $isCurrentLineBlank = $this->isCurrentLineBlank();
+        $blockLines = [];
+
+        // leading blank lines are consumed before determining indentation
+        while ($notEOF && $isCurrentLineBlank) {
+            // newline only if not EOF
+            if ($notEOF = $this->moveToNextLine()) {
+                $blockLines[] = '';
+                $isCurrentLineBlank = $this->isCurrentLineBlank();
+            }
+        }
+
+        // determine indentation if not specified
+        if (0 === $indentation) {
+            $currentLineLength = \strlen($this->currentLine);
+
+            for ($i = 0; $i < $currentLineLength && ' ' === $this->currentLine[$i]; ++$i) {
+                ++$indentation;
+            }
+        }
+
+        if ($indentation > 0) {
+            $pattern = sprintf('/^ {%d}(.*)$/', $indentation);
+
+            while (
+                $notEOF && (
+                    $isCurrentLineBlank ||
+                    self::preg_match($pattern, $this->currentLine, $matches)
+                )
+            ) {
+                if ($isCurrentLineBlank && \strlen($this->currentLine) > $indentation) {
+                    $blockLines[] = substr($this->currentLine, $indentation);
+                } elseif ($isCurrentLineBlank) {
+                    $blockLines[] = '';
+                } else {
+                    $blockLines[] = $matches[1];
+                }
+
+                // newline only if not EOF
+                if ($notEOF = $this->moveToNextLine()) {
+                    $isCurrentLineBlank = $this->isCurrentLineBlank();
+                }
+            }
+        } elseif ($notEOF) {
+            $blockLines[] = '';
+        }
+
+        if ($notEOF) {
+            $blockLines[] = '';
+            $this->moveToPreviousLine();
+        } elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) {
+            $blockLines[] = '';
+        }
+
+        // folded style
+        if ('>' === $style) {
+            $text = '';
+            $previousLineIndented = false;
+            $previousLineBlank = false;
+
+            for ($i = 0, $blockLinesCount = \count($blockLines); $i < $blockLinesCount; ++$i) {
+                if ('' === $blockLines[$i]) {
+                    $text .= "\n";
+                    $previousLineIndented = false;
+                    $previousLineBlank = true;
+                } elseif (' ' === $blockLines[$i][0]) {
+                    $text .= "\n".$blockLines[$i];
+                    $previousLineIndented = true;
+                    $previousLineBlank = false;
+                } elseif ($previousLineIndented) {
+                    $text .= "\n".$blockLines[$i];
+                    $previousLineIndented = false;
+                    $previousLineBlank = false;
+                } elseif ($previousLineBlank || 0 === $i) {
+                    $text .= $blockLines[$i];
+                    $previousLineIndented = false;
+                    $previousLineBlank = false;
+                } else {
+                    $text .= ' '.$blockLines[$i];
+                    $previousLineIndented = false;
+                    $previousLineBlank = false;
+                }
+            }
+        } else {
+            $text = implode("\n", $blockLines);
+        }
+
+        // deal with trailing newlines
+        if ('' === $chomping) {
+            $text = preg_replace('/\n+$/', "\n", $text);
+        } elseif ('-' === $chomping) {
+            $text = preg_replace('/\n+$/', '', $text);
+        }
+
+        return $text;
+    }
+
+    /**
+     * Returns true if the next line is indented.
+     *
+     * @return bool Returns true if the next line is indented, false otherwise
+     */
+    private function isNextLineIndented(): bool
+    {
+        $currentIndentation = $this->getCurrentLineIndentation();
+        $movements = 0;
+
+        do {
+            $EOF = !$this->moveToNextLine();
+
+            if (!$EOF) {
+                ++$movements;
+            }
+        } while (!$EOF && ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()));
+
+        if ($EOF) {
+            return false;
+        }
+
+        $ret = $this->getCurrentLineIndentation() > $currentIndentation;
+
+        for ($i = 0; $i < $movements; ++$i) {
+            $this->moveToPreviousLine();
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Returns true if the current line is blank or if it is a comment line.
+     *
+     * @return bool Returns true if the current line is empty or if it is a comment line, false otherwise
+     */
+    private function isCurrentLineEmpty(): bool
+    {
+        return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
+    }
+
+    /**
+     * Returns true if the current line is blank.
+     *
+     * @return bool Returns true if the current line is blank, false otherwise
+     */
+    private function isCurrentLineBlank(): bool
+    {
+        return '' === $this->currentLine || '' === trim($this->currentLine, ' ');
+    }
+
+    /**
+     * Returns true if the current line is a comment line.
+     *
+     * @return bool Returns true if the current line is a comment line, false otherwise
+     */
+    private function isCurrentLineComment(): bool
+    {
+        //checking explicitly the first char of the trim is faster than loops or strpos
+        $ltrimmedLine = '' !== $this->currentLine && ' ' === $this->currentLine[0] ? ltrim($this->currentLine, ' ') : $this->currentLine;
+
+        return '' !== $ltrimmedLine && '#' === $ltrimmedLine[0];
+    }
+
+    private function isCurrentLineLastLineInDocument(): bool
+    {
+        return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1);
+    }
+
+    /**
+     * Cleanups a YAML string to be parsed.
+     *
+     * @param string $value The input YAML string
+     *
+     * @return string A cleaned up YAML string
+     */
+    private function cleanup(string $value): string
+    {
+        $value = str_replace(["\r\n", "\r"], "\n", $value);
+
+        // strip YAML header
+        $count = 0;
+        $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u', '', $value, -1, $count);
+        $this->offset += $count;
+
+        // remove leading comments
+        $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
+        if (1 === $count) {
+            // items have been removed, update the offset
+            $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
+            $value = $trimmedValue;
+        }
+
+        // remove start of the document marker (---)
+        $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
+        if (1 === $count) {
+            // items have been removed, update the offset
+            $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
+            $value = $trimmedValue;
+
+            // remove end of the document marker (...)
+            $value = preg_replace('#\.\.\.\s*$#', '', $value);
+        }
+
+        return $value;
+    }
+
+    /**
+     * Returns true if the next line starts unindented collection.
+     *
+     * @return bool Returns true if the next line starts unindented collection, false otherwise
+     */
+    private function isNextLineUnIndentedCollection(): bool
+    {
+        $currentIndentation = $this->getCurrentLineIndentation();
+        $movements = 0;
+
+        do {
+            $EOF = !$this->moveToNextLine();
+
+            if (!$EOF) {
+                ++$movements;
+            }
+        } while (!$EOF && ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()));
+
+        if ($EOF) {
+            return false;
+        }
+
+        $ret = $this->getCurrentLineIndentation() === $currentIndentation && $this->isStringUnIndentedCollectionItem();
+
+        for ($i = 0; $i < $movements; ++$i) {
+            $this->moveToPreviousLine();
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Returns true if the string is un-indented collection item.
+     *
+     * @return bool Returns true if the string is un-indented collection item, false otherwise
+     */
+    private function isStringUnIndentedCollectionItem(): bool
+    {
+        return 0 === strncmp($this->currentLine, '- ', 2) || '-' === rtrim($this->currentLine);
+    }
+
+    /**
+     * A local wrapper for "preg_match" which will throw a ParseException if there
+     * is an internal error in the PCRE engine.
+     *
+     * This avoids us needing to check for "false" every time PCRE is used
+     * in the YAML engine
+     *
+     * @throws ParseException on a PCRE internal error
+     *
+     * @see preg_last_error()
+     *
+     * @internal
+     */
+    public static function preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int
+    {
+        if (false === $ret = preg_match($pattern, $subject, $matches, $flags, $offset)) {
+            switch (preg_last_error()) {
+                case PREG_INTERNAL_ERROR:
+                    $error = 'Internal PCRE error.';
+                    break;
+                case PREG_BACKTRACK_LIMIT_ERROR:
+                    $error = 'pcre.backtrack_limit reached.';
+                    break;
+                case PREG_RECURSION_LIMIT_ERROR:
+                    $error = 'pcre.recursion_limit reached.';
+                    break;
+                case PREG_BAD_UTF8_ERROR:
+                    $error = 'Malformed UTF-8 data.';
+                    break;
+                case PREG_BAD_UTF8_OFFSET_ERROR:
+                    $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point.';
+                    break;
+                default:
+                    $error = 'Error.';
+            }
+
+            throw new ParseException($error);
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Trim the tag on top of the value.
+     *
+     * Prevent values such as "!foo {quz: bar}" to be considered as
+     * a mapping block.
+     */
+    private function trimTag(string $value): string
+    {
+        if ('!' === $value[0]) {
+            return ltrim(substr($value, 1, strcspn($value, " \r\n", 1)), ' ');
+        }
+
+        return $value;
+    }
+
+    private function getLineTag(string $value, int $flags, bool $nextLineCheck = true): ?string
+    {
+        if ('' === $value || '!' !== $value[0] || 1 !== self::preg_match('/^'.self::TAG_PATTERN.' *( +#.*)?$/', $value, $matches)) {
+            return null;
+        }
+
+        if ($nextLineCheck && !$this->isNextLineIndented()) {
+            return null;
+        }
+
+        $tag = substr($matches['tag'], 1);
+
+        // Built-in tags
+        if ($tag && '!' === $tag[0]) {
+            throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
+        }
+
+        if (Yaml::PARSE_CUSTOM_TAGS & $flags) {
+            return $tag;
+        }
+
+        throw new ParseException(sprintf('Tags support is not enabled. You must use the flag "Yaml::PARSE_CUSTOM_TAGS" to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
+    }
+
+    private function parseQuotedString(string $yaml): ?string
+    {
+        if ('' === $yaml || ('"' !== $yaml[0] && "'" !== $yaml[0])) {
+            throw new \InvalidArgumentException(sprintf('"%s" is not a quoted string.', $yaml));
+        }
+
+        $lines = [$yaml];
+
+        while ($this->moveToNextLine()) {
+            $lines[] = $this->currentLine;
+
+            if (!$this->isCurrentLineEmpty() && $yaml[0] === $this->currentLine[-1]) {
+                break;
+            }
+        }
+
+        $value = '';
+
+        for ($i = 0, $linesCount = \count($lines), $previousLineWasNewline = false, $previousLineWasTerminatedWithBackslash = false; $i < $linesCount; ++$i) {
+            $trimmedLine = trim($lines[$i]);
+            if ('' === $trimmedLine) {
+                $value .= "\n";
+            } elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
+                $value .= ' ';
+            }
+
+            if ('' !== $trimmedLine && '\\' === $lines[$i][-1]) {
+                $value .= ltrim(substr($lines[$i], 0, -1));
+            } elseif ('' !== $trimmedLine) {
+                $value .= $trimmedLine;
+            }
+
+            if ('' === $trimmedLine) {
+                $previousLineWasNewline = true;
+                $previousLineWasTerminatedWithBackslash = false;
+            } elseif ('\\' === $lines[$i][-1]) {
+                $previousLineWasNewline = false;
+                $previousLineWasTerminatedWithBackslash = true;
+            } else {
+                $previousLineWasNewline = false;
+                $previousLineWasTerminatedWithBackslash = false;
+            }
+        }
+
+        return $value;
+
+        for ($i = 1; isset($yaml[$i]) && $quotation !== $yaml[$i]; ++$i) {
+        }
+
+        // quoted single line string
+        if (isset($yaml[$i]) && $quotation === $yaml[$i]) {
+            return $yaml;
+        }
+
+        $lines = [$yaml];
+
+        while ($this->moveToNextLine()) {
+            for ($i = 1; isset($this->currentLine[$i]) && $quotation !== $this->currentLine[$i]; ++$i) {
+            }
+
+            $lines[] = trim($this->currentLine);
+
+            if (isset($this->currentLine[$i]) && $quotation === $this->currentLine[$i]) {
+                break;
+            }
+        }
+    }
+
+    private function lexInlineMapping(string $yaml): string
+    {
+        if ('' === $yaml || '{' !== $yaml[0]) {
+            throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
+        }
+
+        for ($i = 1; isset($yaml[$i]) && '}' !== $yaml[$i]; ++$i) {
+        }
+
+        if (isset($yaml[$i]) && '}' === $yaml[$i]) {
+            return $yaml;
+        }
+
+        $lines = [$yaml];
+
+        while ($this->moveToNextLine()) {
+            $lines[] = $this->currentLine;
+        }
+
+        return implode("\n", $lines);
+    }
+
+    private function lexInlineSequence(string $yaml): string
+    {
+        if ('' === $yaml || '[' !== $yaml[0]) {
+            throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
+        }
+
+        for ($i = 1; isset($yaml[$i]) && ']' !== $yaml[$i]; ++$i) {
+        }
+
+        if (isset($yaml[$i]) && ']' === $yaml[$i]) {
+            return $yaml;
+        }
+
+        $value = $yaml;
+
+        while ($this->moveToNextLine()) {
+            for ($i = 1; isset($this->currentLine[$i]) && ']' !== $this->currentLine[$i]; ++$i) {
+            }
+
+            $value .= trim($this->currentLine);
+
+            if (isset($this->currentLine[$i]) && ']' === $this->currentLine[$i]) {
+                break;
+            }
+        }
+
+        return $value;
+    }
+}

+ 13 - 0
api/vendor/symfony/yaml/README.md

@@ -0,0 +1,13 @@
+Yaml Component
+==============
+
+The Yaml component loads and dumps YAML files.
+
+Resources
+---------
+
+  * [Documentation](https://symfony.com/doc/current/components/yaml.html)
+  * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+  * [Report issues](https://github.com/symfony/symfony/issues) and
+    [send Pull Requests](https://github.com/symfony/symfony/pulls)
+    in the [main Symfony repository](https://github.com/symfony/symfony)

+ 45 - 0
api/vendor/symfony/yaml/Resources/bin/yaml-lint

@@ -0,0 +1,45 @@
+#!/usr/bin/env php
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Runs the Yaml lint command.
+ *
+ * @author Jan Schädlich <jan.schaedlich@sensiolabs.de>
+ */
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Yaml\Command\LintCommand;
+
+function includeIfExists(string $file): bool
+{
+    return file_exists($file) && include $file;
+}
+
+if (
+    !includeIfExists(__DIR__ . '/../../../../autoload.php') &&
+    !includeIfExists(__DIR__ . '/../../vendor/autoload.php') &&
+    !includeIfExists(__DIR__ . '/../../../../../../vendor/autoload.php')
+) {
+    fwrite(STDERR, 'Install dependencies using Composer.'.PHP_EOL);
+    exit(1);
+}
+
+if (!class_exists(Application::class)) {
+    fwrite(STDERR, 'You need the "symfony/console" component in order to run the Yaml linter.'.PHP_EOL);
+    exit(1);
+}
+
+(new Application())->add($command = new LintCommand())
+    ->getApplication()
+    ->setDefaultCommand($command->getName(), true)
+    ->run()
+;

+ 38 - 0
api/vendor/symfony/yaml/Tag/TaggedValue.php

@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml\Tag;
+
+/**
+ * @author Nicolas Grekas <p@tchwork.com>
+ * @author Guilhem N. <egetick@gmail.com>
+ */
+final class TaggedValue
+{
+    private $tag;
+    private $value;
+
+    public function __construct(string $tag, $value)
+    {
+        $this->tag = $tag;
+        $this->value = $value;
+    }
+
+    public function getTag(): string
+    {
+        return $this->tag;
+    }
+
+    public function getValue()
+    {
+        return $this->value;
+    }
+}

+ 138 - 0
api/vendor/symfony/yaml/Unescaper.php

@@ -0,0 +1,138 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml;
+
+use Symfony\Component\Yaml\Exception\ParseException;
+
+/**
+ * Unescaper encapsulates unescaping rules for single and double-quoted
+ * YAML strings.
+ *
+ * @author Matthew Lewinski <matthew@lewinski.org>
+ *
+ * @internal
+ */
+class Unescaper
+{
+    /**
+     * Regex fragment that matches an escaped character in a double quoted string.
+     */
+    const REGEX_ESCAPED_CHARACTER = '\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)';
+
+    /**
+     * Unescapes a single quoted string.
+     *
+     * @param string $value A single quoted string
+     *
+     * @return string The unescaped string
+     */
+    public function unescapeSingleQuotedString(string $value): string
+    {
+        return str_replace('\'\'', '\'', $value);
+    }
+
+    /**
+     * Unescapes a double quoted string.
+     *
+     * @param string $value A double quoted string
+     *
+     * @return string The unescaped string
+     */
+    public function unescapeDoubleQuotedString(string $value): string
+    {
+        $callback = function ($match) {
+            return $this->unescapeCharacter($match[0]);
+        };
+
+        // evaluate the string
+        return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value);
+    }
+
+    /**
+     * Unescapes a character that was found in a double-quoted string.
+     *
+     * @param string $value An escaped character
+     *
+     * @return string The unescaped character
+     */
+    private function unescapeCharacter(string $value): string
+    {
+        switch ($value[1]) {
+            case '0':
+                return "\x0";
+            case 'a':
+                return "\x7";
+            case 'b':
+                return "\x8";
+            case 't':
+                return "\t";
+            case "\t":
+                return "\t";
+            case 'n':
+                return "\n";
+            case 'v':
+                return "\xB";
+            case 'f':
+                return "\xC";
+            case 'r':
+                return "\r";
+            case 'e':
+                return "\x1B";
+            case ' ':
+                return ' ';
+            case '"':
+                return '"';
+            case '/':
+                return '/';
+            case '\\':
+                return '\\';
+            case 'N':
+                // U+0085 NEXT LINE
+                return "\xC2\x85";
+            case '_':
+                // U+00A0 NO-BREAK SPACE
+                return "\xC2\xA0";
+            case 'L':
+                // U+2028 LINE SEPARATOR
+                return "\xE2\x80\xA8";
+            case 'P':
+                // U+2029 PARAGRAPH SEPARATOR
+                return "\xE2\x80\xA9";
+            case 'x':
+                return self::utf8chr(hexdec(substr($value, 2, 2)));
+            case 'u':
+                return self::utf8chr(hexdec(substr($value, 2, 4)));
+            case 'U':
+                return self::utf8chr(hexdec(substr($value, 2, 8)));
+            default:
+                throw new ParseException(sprintf('Found unknown escape character "%s".', $value));
+        }
+    }
+
+    /**
+     * Get the UTF-8 character for the given code point.
+     */
+    private static function utf8chr(int $c): string
+    {
+        if (0x80 > $c %= 0x200000) {
+            return \chr($c);
+        }
+        if (0x800 > $c) {
+            return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F);
+        }
+        if (0x10000 > $c) {
+            return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
+        }
+
+        return \chr(0xF0 | $c >> 18).\chr(0x80 | $c >> 12 & 0x3F).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F);
+    }
+}

+ 102 - 0
api/vendor/symfony/yaml/Yaml.php

@@ -0,0 +1,102 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Yaml;
+
+use Symfony\Component\Yaml\Exception\ParseException;
+
+/**
+ * Yaml offers convenience methods to load and dump YAML.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @final
+ */
+class Yaml
+{
+    const DUMP_OBJECT = 1;
+    const PARSE_EXCEPTION_ON_INVALID_TYPE = 2;
+    const PARSE_OBJECT = 4;
+    const PARSE_OBJECT_FOR_MAP = 8;
+    const DUMP_EXCEPTION_ON_INVALID_TYPE = 16;
+    const PARSE_DATETIME = 32;
+    const DUMP_OBJECT_AS_MAP = 64;
+    const DUMP_MULTI_LINE_LITERAL_BLOCK = 128;
+    const PARSE_CONSTANT = 256;
+    const PARSE_CUSTOM_TAGS = 512;
+    const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;
+    const DUMP_NULL_AS_TILDE = 2048;
+
+    /**
+     * Parses a YAML file into a PHP value.
+     *
+     * Usage:
+     *
+     *     $array = Yaml::parseFile('config.yml');
+     *     print_r($array);
+     *
+     * @param string $filename The path to the YAML file to be parsed
+     * @param int    $flags    A bit field of PARSE_* constants to customize the YAML parser behavior
+     *
+     * @return mixed The YAML converted to a PHP value
+     *
+     * @throws ParseException If the file could not be read or the YAML is not valid
+     */
+    public static function parseFile(string $filename, int $flags = 0)
+    {
+        $yaml = new Parser();
+
+        return $yaml->parseFile($filename, $flags);
+    }
+
+    /**
+     * Parses YAML into a PHP value.
+     *
+     *  Usage:
+     *  <code>
+     *   $array = Yaml::parse(file_get_contents('config.yml'));
+     *   print_r($array);
+     *  </code>
+     *
+     * @param string $input A string containing YAML
+     * @param int    $flags A bit field of PARSE_* constants to customize the YAML parser behavior
+     *
+     * @return mixed The YAML converted to a PHP value
+     *
+     * @throws ParseException If the YAML is not valid
+     */
+    public static function parse(string $input, int $flags = 0)
+    {
+        $yaml = new Parser();
+
+        return $yaml->parse($input, $flags);
+    }
+
+    /**
+     * Dumps a PHP value to a YAML string.
+     *
+     * The dump method, when supplied with an array, will do its best
+     * to convert the array into friendly YAML.
+     *
+     * @param mixed $input  The PHP value
+     * @param int   $inline The level where you switch to inline YAML
+     * @param int   $indent The amount of spaces to use for indentation of nested nodes
+     * @param int   $flags  A bit field of DUMP_* constants to customize the dumped YAML string
+     *
+     * @return string A YAML string representing the original PHP value
+     */
+    public static function dump($input, int $inline = 2, int $indent = 4, int $flags = 0): string
+    {
+        $yaml = new Dumper($indent);
+
+        return $yaml->dump($input, $inline, 0, $flags);
+    }
+}

+ 47 - 0
api/vendor/symfony/yaml/composer.json

@@ -0,0 +1,47 @@
+{
+    "name": "symfony/yaml",
+    "type": "library",
+    "description": "Symfony Yaml Component",
+    "keywords": [],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Fabien Potencier",
+            "email": "fabien@symfony.com"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.2.5",
+        "symfony/deprecation-contracts": "^2.1",
+        "symfony/polyfill-ctype": "~1.8"
+    },
+    "require-dev": {
+        "symfony/console": "^4.4|^5.0"
+    },
+    "conflict": {
+        "symfony/console": "<4.4"
+    },
+    "suggest": {
+        "symfony/console": "For validating YAML files using the lint command"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Component\\Yaml\\": "" },
+        "exclude-from-classmap": [
+            "/Tests/"
+        ]
+    },
+    "bin": [
+        "Resources/bin/yaml-lint"
+    ],
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-master": "5.1-dev"
+        }
+    }
+}

+ 8 - 0
api/vendor/zircote/swagger-php/.gitignore

@@ -0,0 +1,8 @@
+/vendor
+/composer.lock
+/bin/*
+!/bin/openapi
+/openapi.json
+/openapi.yaml
+/docs/.vuepress/dist
+.phpunit.result.cache

+ 26 - 0
api/vendor/zircote/swagger-php/.travis.yml

@@ -0,0 +1,26 @@
+language: php
+
+php:
+  - 7.2
+  - 7.3
+  - 7.4
+
+sudo: false
+
+env:
+  global:
+    - PHPUNIT=1
+
+matrix:
+  include:
+    - php: 7.4
+      env: PHPCS=1 PHPUNIT=0
+
+before_script:
+  - composer self-update
+  - composer install --prefer-dist --no-interaction
+
+script:
+  - sh -c "if [ '$PHPUNIT' = '1' ]; then ./bin/phpunit; fi"
+
+  - sh -c "if [ '$PHPCS' = '1' ]; then ./bin/phpcs -p --extensions=php --standard=PSR2 --error-severity=1 --warning-severity=0 ./src ./tests; fi"

+ 3 - 0
api/vendor/zircote/swagger-php/Changelog.md

@@ -0,0 +1,3 @@
+# Changelog
+
+The changelog is moved to the [releases page](https://github.com/zircote/swagger-php/releases)

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff