CauseFX 5 лет назад
Родитель
Сommit
20ad235725
100 измененных файлов с 5762 добавлено и 6 удалено
  1. 2 1
      api/composer.json
  2. 294 1
      api/composer.lock
  3. 2 1
      api/vendor/composer/autoload_files.php
  4. 5 1
      api/vendor/composer/autoload_psr4.php
  5. 28 2
      api/vendor/composer/autoload_static.php
  6. 303 0
      api/vendor/composer/installed.json
  7. 5 0
      api/vendor/nikic/fast-route/.gitignore
  8. 1 0
      api/vendor/nikic/fast-route/.hhconfig
  9. 20 0
      api/vendor/nikic/fast-route/.travis.yml
  10. 126 0
      api/vendor/nikic/fast-route/FastRoute.hhi
  11. 31 0
      api/vendor/nikic/fast-route/LICENSE
  12. 313 0
      api/vendor/nikic/fast-route/README.md
  13. 24 0
      api/vendor/nikic/fast-route/composer.json
  14. 24 0
      api/vendor/nikic/fast-route/phpunit.xml
  15. 28 0
      api/vendor/nikic/fast-route/psalm.xml
  16. 7 0
      api/vendor/nikic/fast-route/src/BadRouteException.php
  17. 26 0
      api/vendor/nikic/fast-route/src/DataGenerator.php
  18. 31 0
      api/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php
  19. 30 0
      api/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php
  20. 27 0
      api/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php
  21. 27 0
      api/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php
  22. 186 0
      api/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php
  23. 26 0
      api/vendor/nikic/fast-route/src/Dispatcher.php
  24. 31 0
      api/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php
  25. 31 0
      api/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php
  26. 33 0
      api/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php
  27. 31 0
      api/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php
  28. 88 0
      api/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php
  29. 47 0
      api/vendor/nikic/fast-route/src/Route.php
  30. 152 0
      api/vendor/nikic/fast-route/src/RouteCollector.php
  31. 37 0
      api/vendor/nikic/fast-route/src/RouteParser.php
  32. 87 0
      api/vendor/nikic/fast-route/src/RouteParser/Std.php
  33. 12 0
      api/vendor/nikic/fast-route/src/bootstrap.php
  34. 74 0
      api/vendor/nikic/fast-route/src/functions.php
  35. 16 0
      api/vendor/nikic/fast-route/test/Dispatcher/CharCountBasedTest.php
  36. 581 0
      api/vendor/nikic/fast-route/test/Dispatcher/DispatcherTest.php
  37. 16 0
      api/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php
  38. 16 0
      api/vendor/nikic/fast-route/test/Dispatcher/GroupPosBasedTest.php
  39. 24 0
      api/vendor/nikic/fast-route/test/Dispatcher/MarkBasedTest.php
  40. 44 0
      api/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php
  41. 29 0
      api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php
  42. 11 0
      api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php
  43. 11 0
      api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php
  44. 108 0
      api/vendor/nikic/fast-route/test/RouteCollectorTest.php
  45. 154 0
      api/vendor/nikic/fast-route/test/RouteParser/StdTest.php
  46. 11 0
      api/vendor/nikic/fast-route/test/bootstrap.php
  47. 2 0
      api/vendor/psr/http-factory/.gitignore
  48. 7 0
      api/vendor/psr/http-factory/.pullapprove.yml
  49. 21 0
      api/vendor/psr/http-factory/LICENSE
  50. 10 0
      api/vendor/psr/http-factory/README.md
  51. 35 0
      api/vendor/psr/http-factory/composer.json
  52. 18 0
      api/vendor/psr/http-factory/src/RequestFactoryInterface.php
  53. 18 0
      api/vendor/psr/http-factory/src/ResponseFactoryInterface.php
  54. 24 0
      api/vendor/psr/http-factory/src/ServerRequestFactoryInterface.php
  55. 45 0
      api/vendor/psr/http-factory/src/StreamFactoryInterface.php
  56. 34 0
      api/vendor/psr/http-factory/src/UploadedFileFactoryInterface.php
  57. 17 0
      api/vendor/psr/http-factory/src/UriFactoryInterface.php
  58. 21 0
      api/vendor/psr/http-server-handler/LICENSE
  59. 6 0
      api/vendor/psr/http-server-handler/README.md
  60. 36 0
      api/vendor/psr/http-server-handler/composer.json
  61. 22 0
      api/vendor/psr/http-server-handler/src/RequestHandlerInterface.php
  62. 21 0
      api/vendor/psr/http-server-middleware/LICENSE
  63. 6 0
      api/vendor/psr/http-server-middleware/README.md
  64. 36 0
      api/vendor/psr/http-server-middleware/composer.json
  65. 25 0
      api/vendor/psr/http-server-middleware/src/MiddlewareInterface.php
  66. 66 0
      api/vendor/slim/slim/CHANGELOG.md
  67. 19 0
      api/vendor/slim/slim/LICENSE.md
  68. 17 0
      api/vendor/slim/slim/MAINTAINERS.md
  69. 191 0
      api/vendor/slim/slim/Slim/App.php
  70. 100 0
      api/vendor/slim/slim/Slim/CallableResolver.php
  71. 46 0
      api/vendor/slim/slim/Slim/DeferredCallable.php
  72. 22 0
      api/vendor/slim/slim/Slim/Error/AbstractErrorRenderer.php
  73. 106 0
      api/vendor/slim/slim/Slim/Error/Renderers/HtmlErrorRenderer.php
  74. 53 0
      api/vendor/slim/slim/Slim/Error/Renderers/JsonErrorRenderer.php
  75. 73 0
      api/vendor/slim/slim/Slim/Error/Renderers/PlainTextErrorRenderer.php
  76. 57 0
      api/vendor/slim/slim/Slim/Error/Renderers/XmlErrorRenderer.php
  77. 18 0
      api/vendor/slim/slim/Slim/Exception/HttpBadRequestException.php
  78. 92 0
      api/vendor/slim/slim/Slim/Exception/HttpException.php
  79. 18 0
      api/vendor/slim/slim/Slim/Exception/HttpForbiddenException.php
  80. 18 0
      api/vendor/slim/slim/Slim/Exception/HttpInternalServerErrorException.php
  81. 41 0
      api/vendor/slim/slim/Slim/Exception/HttpMethodNotAllowedException.php
  82. 18 0
      api/vendor/slim/slim/Slim/Exception/HttpNotFoundException.php
  83. 18 0
      api/vendor/slim/slim/Slim/Exception/HttpNotImplementedException.php
  84. 30 0
      api/vendor/slim/slim/Slim/Exception/HttpSpecializedException.php
  85. 18 0
      api/vendor/slim/slim/Slim/Exception/HttpUnauthorizedException.php
  86. 209 0
      api/vendor/slim/slim/Slim/Factory/AppFactory.php
  87. 18 0
      api/vendor/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php
  88. 35 0
      api/vendor/slim/slim/Slim/Factory/Psr17/NyholmPsr17Factory.php
  89. 103 0
      api/vendor/slim/slim/Slim/Factory/Psr17/Psr17Factory.php
  90. 49 0
      api/vendor/slim/slim/Slim/Factory/Psr17/Psr17FactoryProvider.php
  91. 47 0
      api/vendor/slim/slim/Slim/Factory/Psr17/ServerRequestCreator.php
  92. 30 0
      api/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpPsr17Factory.php
  93. 57 0
      api/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpServerRequestCreator.php
  94. 18 0
      api/vendor/slim/slim/Slim/Factory/Psr17/SlimPsr17Factory.php
  95. 18 0
      api/vendor/slim/slim/Slim/Factory/Psr17/ZendDiactorosPsr17Factory.php
  96. 111 0
      api/vendor/slim/slim/Slim/Factory/ServerRequestCreatorFactory.php
  97. 309 0
      api/vendor/slim/slim/Slim/Handlers/ErrorHandler.php
  98. 39 0
      api/vendor/slim/slim/Slim/Handlers/Strategies/RequestHandler.php
  99. 44 0
      api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php
  100. 40 0
      api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseArgs.php

+ 2 - 1
api/composer.json

@@ -11,6 +11,7 @@
     "pusher/pusher-php-server": "^4.0",
     "pragmarx/google2fa": "^3.0",
     "psr/log": "^1.1",
-    "adldap2/adldap2": "^10.0"
+    "adldap2/adldap2": "^10.0",
+    "slim/slim": "4.0"
   }
 }

+ 294 - 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": "b895341ab62fbe32e131b91bf9ca2e04",
+    "content-hash": "a5603400dc1d65d4e7fcf53b9f191ee1",
     "packages": [
         {
             "name": "adldap2/adldap2",
@@ -590,6 +590,52 @@
             ],
             "time": "2019-05-24T18:30:49+00:00"
         },
+        {
+            "name": "nikic/fast-route",
+            "version": "v1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nikic/FastRoute.git",
+                "reference": "181d480e08d9476e61381e04a71b34dc0432e812"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812",
+                "reference": "181d480e08d9476e61381e04a71b34dc0432e812",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35|~5.7"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "FastRoute\\": "src/"
+                },
+                "files": [
+                    "src/functions.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Nikita Popov",
+                    "email": "nikic@php.net"
+                }
+            ],
+            "description": "Fast request router for PHP",
+            "keywords": [
+                "router",
+                "routing"
+            ],
+            "time": "2018-02-13T20:26:39+00:00"
+        },
         {
             "name": "paragonie/constant_time_encoding",
             "version": "v2.2.2",
@@ -951,6 +997,58 @@
             ],
             "time": "2017-02-14T16:28:37+00:00"
         },
+        {
+            "name": "psr/http-factory",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-factory.git",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.0",
+                "psr/http-message": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for PSR-7 HTTP message factories",
+            "keywords": [
+                "factory",
+                "http",
+                "message",
+                "psr",
+                "psr-17",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "time": "2019-04-30T12:38:16+00:00"
+        },
         {
             "name": "psr/http-message",
             "version": "1.0.1",
@@ -1001,6 +1099,112 @@
             ],
             "time": "2016-08-06T14:39:51+00:00"
         },
+        {
+            "name": "psr/http-server-handler",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-server-handler.git",
+                "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
+                "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0",
+                "psr/http-message": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Server\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP server-side request handler",
+            "keywords": [
+                "handler",
+                "http",
+                "http-interop",
+                "psr",
+                "psr-15",
+                "psr-7",
+                "request",
+                "response",
+                "server"
+            ],
+            "time": "2018-10-30T16:46:14+00:00"
+        },
+        {
+            "name": "psr/http-server-middleware",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-server-middleware.git",
+                "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5",
+                "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0",
+                "psr/http-message": "^1.0",
+                "psr/http-server-handler": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Server\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP server-side middleware",
+            "keywords": [
+                "http",
+                "http-interop",
+                "middleware",
+                "psr",
+                "psr-15",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "time": "2018-10-30T17:12:04+00:00"
+        },
         {
             "name": "psr/log",
             "version": "1.1.0",
@@ -1239,6 +1443,95 @@
             ],
             "time": "2016-10-13T00:11:37+00:00"
         },
+        {
+            "name": "slim/slim",
+            "version": "4.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/slimphp/Slim.git",
+                "reference": "2b0ed80b2ab4acfb5e7648797b8202e4d9aea06d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/slimphp/Slim/zipball/2b0ed80b2ab4acfb5e7648797b8202e4d9aea06d",
+                "reference": "2b0ed80b2ab4acfb5e7648797b8202e4d9aea06d",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "nikic/fast-route": "^1.3",
+                "php": "^7.1",
+                "psr/container": "^1.0",
+                "psr/http-factory": "^1.0",
+                "psr/http-message": "^1.0",
+                "psr/http-server-handler": "^1.0",
+                "psr/http-server-middleware": "^1.0"
+            },
+            "require-dev": {
+                "ext-simplexml": "*",
+                "guzzlehttp/psr7": "^1.5",
+                "http-interop/http-factory-guzzle": "^1.0",
+                "nyholm/psr7": "^1.1",
+                "nyholm/psr7-server": "^0.3.0",
+                "phpspec/prophecy": "^1.8",
+                "phpstan/phpstan": "^0.11.5",
+                "phpunit/phpunit": "^7.5",
+                "slim/http": "^0.7",
+                "slim/psr7": "^0.3",
+                "squizlabs/php_codesniffer": "^3.4.2",
+                "zendframework/zend-diactoros": "^2.1"
+            },
+            "suggest": {
+                "slim/psr7": "Slim PSR-7 implementation. See http://www.slimframework.com/docs/v4/start/installation.html for more information."
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Slim\\": "Slim",
+                    "Slim\\Tests\\": "tests"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Josh Lockhart",
+                    "email": "hello@joshlockhart.com",
+                    "homepage": "https://joshlockhart.com"
+                },
+                {
+                    "name": "Andrew Smith",
+                    "email": "a.smith@silentworks.co.uk",
+                    "homepage": "http://silentworks.co.uk"
+                },
+                {
+                    "name": "Rob Allen",
+                    "email": "rob@akrabat.com",
+                    "homepage": "http://akrabat.com"
+                },
+                {
+                    "name": "Pierre Berube",
+                    "email": "pierre@lgse.com",
+                    "homepage": "http://www.lgse.com"
+                },
+                {
+                    "name": "Gabriel Manricks",
+                    "email": "gmanricks@me.com",
+                    "homepage": "http://gabrielmanricks.com"
+                }
+            ],
+            "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
+            "homepage": "https://slimframework.com",
+            "keywords": [
+                "api",
+                "framework",
+                "micro",
+                "router"
+            ],
+            "time": "2019-08-01T16:11:29+00:00"
+        },
         {
             "name": "symfony/polyfill-mbstring",
             "version": "v1.14.0",

+ 2 - 1
api/vendor/composer/autoload_files.php

@@ -7,12 +7,13 @@ $baseDir = dirname($vendorDir);
 
 return array(
     '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
-    'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
     'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
+    'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
     '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
     '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/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',
     'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
     'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',

+ 5 - 1
api/vendor/composer/autoload_psr4.php

@@ -12,10 +12,13 @@ return array(
     'Symfony\\Polyfill\\Php56\\' => array($vendorDir . '/symfony/polyfill-php56'),
     'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
     'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
+    'Slim\\Tests\\' => array($vendorDir . '/slim/slim/tests'),
+    'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
     'Pusher\\' => array($vendorDir . '/pusher/pusher-php-server/src'),
     'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
-    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
+    'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'),
+    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
     'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
     'PragmaRX\\Google2FA\\Tests\\' => array($vendorDir . '/pragmarx/google2fa/tests'),
     'PragmaRX\\Google2FA\\' => array($vendorDir . '/pragmarx/google2fa/src'),
@@ -29,6 +32,7 @@ return array(
     'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
     'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
     'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
+    'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
     'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
     'Adldap\\' => array($vendorDir . '/adldap2/adldap2/src'),
 );

+ 28 - 2
api/vendor/composer/autoload_static.php

@@ -8,12 +8,13 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
 {
     public static $files = array (
         '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
-        'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
         'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
+        'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
         '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
         '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/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',
         'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
         'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
@@ -33,12 +34,15 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             'Symfony\\Polyfill\\Php56\\' => 23,
             'Symfony\\Polyfill\\Mbstring\\' => 26,
             'Symfony\\Component\\VarDumper\\' => 28,
+            'Slim\\Tests\\' => 11,
+            'Slim\\' => 5,
         ),
         'P' => 
         array (
             'Pusher\\' => 7,
             'Psr\\SimpleCache\\' => 16,
             'Psr\\Log\\' => 8,
+            'Psr\\Http\\Server\\' => 16,
             'Psr\\Http\\Message\\' => 17,
             'Psr\\Container\\' => 14,
             'PragmaRX\\Google2FA\\Tests\\' => 25,
@@ -66,6 +70,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             'GuzzleHttp\\Promise\\' => 19,
             'GuzzleHttp\\' => 11,
         ),
+        'F' => 
+        array (
+            'FastRoute\\' => 10,
+        ),
         'C' => 
         array (
             'Composer\\Semver\\' => 16,
@@ -101,6 +109,14 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/symfony/var-dumper',
         ),
+        'Slim\\Tests\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/slim/slim/tests',
+        ),
+        'Slim\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/slim/slim/Slim',
+        ),
         'Pusher\\' => 
         array (
             0 => __DIR__ . '/..' . '/pusher/pusher-php-server/src',
@@ -113,9 +129,15 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
         ),
+        'Psr\\Http\\Server\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/http-server-handler/src',
+            1 => __DIR__ . '/..' . '/psr/http-server-middleware/src',
+        ),
         'Psr\\Http\\Message\\' => 
         array (
-            0 => __DIR__ . '/..' . '/psr/http-message/src',
+            0 => __DIR__ . '/..' . '/psr/http-factory/src',
+            1 => __DIR__ . '/..' . '/psr/http-message/src',
         ),
         'Psr\\Container\\' => 
         array (
@@ -169,6 +191,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src',
         ),
+        'FastRoute\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/nikic/fast-route/src',
+        ),
         'Composer\\Semver\\' => 
         array (
             0 => __DIR__ . '/..' . '/composer/semver/src',

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

@@ -605,6 +605,54 @@
             "jwt"
         ]
     },
+    {
+        "name": "nikic/fast-route",
+        "version": "v1.3.0",
+        "version_normalized": "1.3.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/nikic/FastRoute.git",
+            "reference": "181d480e08d9476e61381e04a71b34dc0432e812"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812",
+            "reference": "181d480e08d9476e61381e04a71b34dc0432e812",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.4.0"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "^4.8.35|~5.7"
+        },
+        "time": "2018-02-13T20:26:39+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "FastRoute\\": "src/"
+            },
+            "files": [
+                "src/functions.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD-3-Clause"
+        ],
+        "authors": [
+            {
+                "name": "Nikita Popov",
+                "email": "nikic@php.net"
+            }
+        ],
+        "description": "Fast request router for PHP",
+        "keywords": [
+            "router",
+            "routing"
+        ]
+    },
     {
         "name": "paragonie/constant_time_encoding",
         "version": "v2.2.2",
@@ -978,6 +1026,60 @@
             "psr"
         ]
     },
+    {
+        "name": "psr/http-factory",
+        "version": "1.0.1",
+        "version_normalized": "1.0.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/php-fig/http-factory.git",
+            "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+            "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.0.0",
+            "psr/http-message": "^1.0"
+        },
+        "time": "2019-04-30T12:38:16+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.0.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Psr\\Http\\Message\\": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "PHP-FIG",
+                "homepage": "http://www.php-fig.org/"
+            }
+        ],
+        "description": "Common interfaces for PSR-7 HTTP message factories",
+        "keywords": [
+            "factory",
+            "http",
+            "message",
+            "psr",
+            "psr-17",
+            "psr-7",
+            "request",
+            "response"
+        ]
+    },
     {
         "name": "psr/http-message",
         "version": "1.0.1",
@@ -1030,6 +1132,116 @@
             "response"
         ]
     },
+    {
+        "name": "psr/http-server-handler",
+        "version": "1.0.1",
+        "version_normalized": "1.0.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/php-fig/http-server-handler.git",
+            "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
+            "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.0",
+            "psr/http-message": "^1.0"
+        },
+        "time": "2018-10-30T16:46:14+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.0.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Psr\\Http\\Server\\": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "PHP-FIG",
+                "homepage": "http://www.php-fig.org/"
+            }
+        ],
+        "description": "Common interface for HTTP server-side request handler",
+        "keywords": [
+            "handler",
+            "http",
+            "http-interop",
+            "psr",
+            "psr-15",
+            "psr-7",
+            "request",
+            "response",
+            "server"
+        ]
+    },
+    {
+        "name": "psr/http-server-middleware",
+        "version": "1.0.1",
+        "version_normalized": "1.0.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/php-fig/http-server-middleware.git",
+            "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5",
+            "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=7.0",
+            "psr/http-message": "^1.0",
+            "psr/http-server-handler": "^1.0"
+        },
+        "time": "2018-10-30T17:12:04+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.0.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Psr\\Http\\Server\\": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "PHP-FIG",
+                "homepage": "http://www.php-fig.org/"
+            }
+        ],
+        "description": "Common interface for HTTP server-side middleware",
+        "keywords": [
+            "http",
+            "http-interop",
+            "middleware",
+            "psr",
+            "psr-15",
+            "psr-7",
+            "request",
+            "response"
+        ]
+    },
     {
         "name": "psr/log",
         "version": "1.1.0",
@@ -1278,6 +1490,97 @@
             "sockets"
         ]
     },
+    {
+        "name": "slim/slim",
+        "version": "4.0.0",
+        "version_normalized": "4.0.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/slimphp/Slim.git",
+            "reference": "2b0ed80b2ab4acfb5e7648797b8202e4d9aea06d"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/slimphp/Slim/zipball/2b0ed80b2ab4acfb5e7648797b8202e4d9aea06d",
+            "reference": "2b0ed80b2ab4acfb5e7648797b8202e4d9aea06d",
+            "shasum": ""
+        },
+        "require": {
+            "ext-json": "*",
+            "nikic/fast-route": "^1.3",
+            "php": "^7.1",
+            "psr/container": "^1.0",
+            "psr/http-factory": "^1.0",
+            "psr/http-message": "^1.0",
+            "psr/http-server-handler": "^1.0",
+            "psr/http-server-middleware": "^1.0"
+        },
+        "require-dev": {
+            "ext-simplexml": "*",
+            "guzzlehttp/psr7": "^1.5",
+            "http-interop/http-factory-guzzle": "^1.0",
+            "nyholm/psr7": "^1.1",
+            "nyholm/psr7-server": "^0.3.0",
+            "phpspec/prophecy": "^1.8",
+            "phpstan/phpstan": "^0.11.5",
+            "phpunit/phpunit": "^7.5",
+            "slim/http": "^0.7",
+            "slim/psr7": "^0.3",
+            "squizlabs/php_codesniffer": "^3.4.2",
+            "zendframework/zend-diactoros": "^2.1"
+        },
+        "suggest": {
+            "slim/psr7": "Slim PSR-7 implementation. See http://www.slimframework.com/docs/v4/start/installation.html for more information."
+        },
+        "time": "2019-08-01T16:11:29+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Slim\\": "Slim",
+                "Slim\\Tests\\": "tests"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Josh Lockhart",
+                "email": "hello@joshlockhart.com",
+                "homepage": "https://joshlockhart.com"
+            },
+            {
+                "name": "Andrew Smith",
+                "email": "a.smith@silentworks.co.uk",
+                "homepage": "http://silentworks.co.uk"
+            },
+            {
+                "name": "Rob Allen",
+                "email": "rob@akrabat.com",
+                "homepage": "http://akrabat.com"
+            },
+            {
+                "name": "Pierre Berube",
+                "email": "pierre@lgse.com",
+                "homepage": "http://www.lgse.com"
+            },
+            {
+                "name": "Gabriel Manricks",
+                "email": "gmanricks@me.com",
+                "homepage": "http://gabrielmanricks.com"
+            }
+        ],
+        "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
+        "homepage": "https://slimframework.com",
+        "keywords": [
+            "api",
+            "framework",
+            "micro",
+            "router"
+        ]
+    },
     {
         "name": "symfony/polyfill-mbstring",
         "version": "v1.14.0",

+ 5 - 0
api/vendor/nikic/fast-route/.gitignore

@@ -0,0 +1,5 @@
+/vendor/
+.idea/
+
+# ignore lock file since we have no extra dependencies
+composer.lock

+ 1 - 0
api/vendor/nikic/fast-route/.hhconfig

@@ -0,0 +1 @@
+assume_php=false

+ 20 - 0
api/vendor/nikic/fast-route/.travis.yml

@@ -0,0 +1,20 @@
+sudo: false
+language: php
+
+php:
+  - 5.4
+  - 5.5
+  - 5.6
+  - 7.0
+  - 7.1
+  - 7.2
+  - hhvm
+
+script:
+  - ./vendor/bin/phpunit
+
+before_install:
+  - travis_retry composer self-update
+
+install:
+  - composer install

+ 126 - 0
api/vendor/nikic/fast-route/FastRoute.hhi

@@ -0,0 +1,126 @@
+<?hh // decl
+
+namespace FastRoute {
+    class BadRouteException extends \LogicException {
+    }
+
+    interface RouteParser {
+        public function parse(string $route): array<array>;
+    }
+
+    class RouteCollector {
+        public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator);
+        public function addRoute(mixed $httpMethod, string $route, mixed $handler): void;
+        public function getData(): array;
+    }
+
+    class Route {
+        public function __construct(string $httpMethod, mixed $handler, string $regex, array $variables);
+        public function matches(string $str): bool;
+    }
+
+    interface DataGenerator {
+        public function addRoute(string $httpMethod, array $routeData, mixed $handler);
+        public function getData(): array;
+    }
+
+    interface Dispatcher {
+        const int NOT_FOUND = 0;
+        const int FOUND = 1;
+        const int METHOD_NOT_ALLOWED = 2;
+        public function dispatch(string $httpMethod, string $uri): array;
+    }
+
+    function simpleDispatcher(
+        (function(RouteCollector): void) $routeDefinitionCallback,
+        shape(
+          ?'routeParser' => classname<RouteParser>,
+          ?'dataGenerator' => classname<DataGenerator>,
+          ?'dispatcher' => classname<Dispatcher>,
+          ?'routeCollector' => classname<RouteCollector>,
+        ) $options = shape()): Dispatcher;
+
+    function cachedDispatcher(
+        (function(RouteCollector): void) $routeDefinitionCallback,
+        shape(
+          ?'routeParser' => classname<RouteParser>,
+          ?'dataGenerator' => classname<DataGenerator>,
+          ?'dispatcher' => classname<Dispatcher>,
+          ?'routeCollector' => classname<RouteCollector>,
+          ?'cacheDisabled' => bool,
+          ?'cacheFile' => string,
+        ) $options = shape()): Dispatcher;
+}
+
+namespace FastRoute\DataGenerator {
+    abstract class RegexBasedAbstract implements \FastRoute\DataGenerator {
+        protected abstract function getApproxChunkSize();
+        protected abstract function processChunk($regexToRoutesMap);
+
+        public function addRoute(string $httpMethod, array $routeData, mixed $handler): void;
+        public function getData(): array;
+    }
+
+    class CharCountBased extends RegexBasedAbstract {
+        protected function getApproxChunkSize(): int;
+        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
+    }
+
+    class GroupCountBased extends RegexBasedAbstract {
+        protected function getApproxChunkSize(): int;
+        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
+    }
+
+    class GroupPosBased extends RegexBasedAbstract {
+        protected function getApproxChunkSize(): int;
+        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
+    }
+
+    class MarkBased extends RegexBasedAbstract {
+        protected function getApproxChunkSize(): int;
+        protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
+    }
+}
+
+namespace FastRoute\Dispatcher {
+    abstract class RegexBasedAbstract implements \FastRoute\Dispatcher {
+        protected abstract function dispatchVariableRoute(array<array> $routeData, string $uri): array;
+
+        public function dispatch(string $httpMethod, string $uri): array;
+    }
+
+    class GroupPosBased extends RegexBasedAbstract {
+        public function __construct(array $data);
+        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
+    }
+
+    class GroupCountBased extends RegexBasedAbstract {
+        public function __construct(array $data);
+        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
+    }
+
+    class CharCountBased extends RegexBasedAbstract {
+        public function __construct(array $data);
+        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
+    }
+
+    class MarkBased extends RegexBasedAbstract {
+        public function __construct(array $data);
+        protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
+    }
+}
+
+namespace FastRoute\RouteParser {
+    class Std implements \FastRoute\RouteParser {
+        const string VARIABLE_REGEX = <<<'REGEX'
+\{
+    \s* ([a-zA-Z][a-zA-Z0-9_]*) \s*
+    (?:
+        : \s* ([^{}]*(?:\{(?-1)\}[^{}]*)*)
+    )?
+\}
+REGEX;
+        const string DEFAULT_DISPATCH_REGEX = '[^/]+';
+        public function parse(string $route): array<array>;
+    }
+}

+ 31 - 0
api/vendor/nikic/fast-route/LICENSE

@@ -0,0 +1,31 @@
+Copyright (c) 2013 by Nikita Popov.
+
+Some rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * The names of the contributors may not be used to endorse or
+      promote products derived from this software without specific
+      prior written permission.
+
+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.

+ 313 - 0
api/vendor/nikic/fast-route/README.md

@@ -0,0 +1,313 @@
+FastRoute - Fast request router for PHP
+=======================================
+
+This library provides a fast implementation of a regular expression based router. [Blog post explaining how the
+implementation works and why it is fast.][blog_post]
+
+Install
+-------
+
+To install with composer:
+
+```sh
+composer require nikic/fast-route
+```
+
+Requires PHP 5.4 or newer.
+
+Usage
+-----
+
+Here's a basic usage example:
+
+```php
+<?php
+
+require '/path/to/vendor/autoload.php';
+
+$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
+    $r->addRoute('GET', '/users', 'get_all_users_handler');
+    // {id} must be a number (\d+)
+    $r->addRoute('GET', '/user/{id:\d+}', 'get_user_handler');
+    // The /{title} suffix is optional
+    $r->addRoute('GET', '/articles/{id:\d+}[/{title}]', 'get_article_handler');
+});
+
+// Fetch method and URI from somewhere
+$httpMethod = $_SERVER['REQUEST_METHOD'];
+$uri = $_SERVER['REQUEST_URI'];
+
+// Strip query string (?foo=bar) and decode URI
+if (false !== $pos = strpos($uri, '?')) {
+    $uri = substr($uri, 0, $pos);
+}
+$uri = rawurldecode($uri);
+
+$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
+switch ($routeInfo[0]) {
+    case FastRoute\Dispatcher::NOT_FOUND:
+        // ... 404 Not Found
+        break;
+    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
+        $allowedMethods = $routeInfo[1];
+        // ... 405 Method Not Allowed
+        break;
+    case FastRoute\Dispatcher::FOUND:
+        $handler = $routeInfo[1];
+        $vars = $routeInfo[2];
+        // ... call $handler with $vars
+        break;
+}
+```
+
+### Defining routes
+
+The routes are defined by calling the `FastRoute\simpleDispatcher()` function, which accepts
+a callable taking a `FastRoute\RouteCollector` instance. The routes are added by calling
+`addRoute()` on the collector instance:
+
+```php
+$r->addRoute($method, $routePattern, $handler);
+```
+
+The `$method` is an uppercase HTTP method string for which a certain route should match. It
+is possible to specify multiple valid methods using an array:
+
+```php
+// These two calls
+$r->addRoute('GET', '/test', 'handler');
+$r->addRoute('POST', '/test', 'handler');
+// Are equivalent to this one call
+$r->addRoute(['GET', 'POST'], '/test', 'handler');
+```
+
+By default the `$routePattern` uses a syntax where `{foo}` specifies a placeholder with name `foo`
+and matching the regex `[^/]+`. To adjust the pattern the placeholder matches, you can specify
+a custom pattern by writing `{bar:[0-9]+}`. Some examples:
+
+```php
+// Matches /user/42, but not /user/xyz
+$r->addRoute('GET', '/user/{id:\d+}', 'handler');
+
+// Matches /user/foobar, but not /user/foo/bar
+$r->addRoute('GET', '/user/{name}', 'handler');
+
+// Matches /user/foo/bar as well
+$r->addRoute('GET', '/user/{name:.+}', 'handler');
+```
+
+Custom patterns for route placeholders cannot use capturing groups. For example `{lang:(en|de)}`
+is not a valid placeholder, because `()` is a capturing group. Instead you can use either
+`{lang:en|de}` or `{lang:(?:en|de)}`.
+
+Furthermore parts of the route enclosed in `[...]` are considered optional, so that `/foo[bar]`
+will match both `/foo` and `/foobar`. Optional parts are only supported in a trailing position,
+not in the middle of a route.
+
+```php
+// This route
+$r->addRoute('GET', '/user/{id:\d+}[/{name}]', 'handler');
+// Is equivalent to these two routes
+$r->addRoute('GET', '/user/{id:\d+}', 'handler');
+$r->addRoute('GET', '/user/{id:\d+}/{name}', 'handler');
+
+// Multiple nested optional parts are possible as well
+$r->addRoute('GET', '/user[/{id:\d+}[/{name}]]', 'handler');
+
+// This route is NOT valid, because optional parts can only occur at the end
+$r->addRoute('GET', '/user[/{id:\d+}]/{name}', 'handler');
+```
+
+The `$handler` parameter does not necessarily have to be a callback, it could also be a controller
+class name or any other kind of data you wish to associate with the route. FastRoute only tells you
+which handler corresponds to your URI, how you interpret it is up to you.
+
+#### Shorcut methods for common request methods
+
+For the `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `HEAD` request methods shortcut methods are available. For example:
+
+```php
+$r->get('/get-route', 'get_handler');
+$r->post('/post-route', 'post_handler');
+```
+
+Is equivalent to:
+
+```php
+$r->addRoute('GET', '/get-route', 'get_handler');
+$r->addRoute('POST', '/post-route', 'post_handler');
+```
+
+#### Route Groups
+
+Additionally, you can specify routes inside of a group. All routes defined inside a group will have a common prefix.
+
+For example, defining your routes as:
+
+```php
+$r->addGroup('/admin', function (RouteCollector $r) {
+    $r->addRoute('GET', '/do-something', 'handler');
+    $r->addRoute('GET', '/do-another-thing', 'handler');
+    $r->addRoute('GET', '/do-something-else', 'handler');
+});
+```
+
+Will have the same result as:
+
+ ```php
+$r->addRoute('GET', '/admin/do-something', 'handler');
+$r->addRoute('GET', '/admin/do-another-thing', 'handler');
+$r->addRoute('GET', '/admin/do-something-else', 'handler');
+ ```
+
+Nested groups are also supported, in which case the prefixes of all the nested groups are combined.
+
+### Caching
+
+The reason `simpleDispatcher` accepts a callback for defining the routes is to allow seamless
+caching. By using `cachedDispatcher` instead of `simpleDispatcher` you can cache the generated
+routing data and construct the dispatcher from the cached information:
+
+```php
+<?php
+
+$dispatcher = FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $r) {
+    $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
+    $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
+    $r->addRoute('GET', '/user/{name}', 'handler2');
+}, [
+    'cacheFile' => __DIR__ . '/route.cache', /* required */
+    'cacheDisabled' => IS_DEBUG_ENABLED,     /* optional, enabled by default */
+]);
+```
+
+The second parameter to the function is an options array, which can be used to specify the cache
+file location, among other things.
+
+### Dispatching a URI
+
+A URI is dispatched by calling the `dispatch()` method of the created dispatcher. This method
+accepts the HTTP method and a URI. Getting those two bits of information (and normalizing them
+appropriately) is your job - this library is not bound to the PHP web SAPIs.
+
+The `dispatch()` method returns an array whose first element contains a status code. It is one
+of `Dispatcher::NOT_FOUND`, `Dispatcher::METHOD_NOT_ALLOWED` and `Dispatcher::FOUND`. For the
+method not allowed status the second array element contains a list of HTTP methods allowed for
+the supplied URI. For example:
+
+    [FastRoute\Dispatcher::METHOD_NOT_ALLOWED, ['GET', 'POST']]
+
+> **NOTE:** The HTTP specification requires that a `405 Method Not Allowed` response include the
+`Allow:` header to detail available methods for the requested resource. Applications using FastRoute
+should use the second array element to add this header when relaying a 405 response.
+
+For the found status the second array element is the handler that was associated with the route
+and the third array element is a dictionary of placeholder names to their values. For example:
+
+    /* Routing against GET /user/nikic/42 */
+
+    [FastRoute\Dispatcher::FOUND, 'handler0', ['name' => 'nikic', 'id' => '42']]
+
+### Overriding the route parser and dispatcher
+
+The routing process makes use of three components: A route parser, a data generator and a
+dispatcher. The three components adhere to the following interfaces:
+
+```php
+<?php
+
+namespace FastRoute;
+
+interface RouteParser {
+    public function parse($route);
+}
+
+interface DataGenerator {
+    public function addRoute($httpMethod, $routeData, $handler);
+    public function getData();
+}
+
+interface Dispatcher {
+    const NOT_FOUND = 0, FOUND = 1, METHOD_NOT_ALLOWED = 2;
+
+    public function dispatch($httpMethod, $uri);
+}
+```
+
+The route parser takes a route pattern string and converts it into an array of route infos, where
+each route info is again an array of it's parts. The structure is best understood using an example:
+
+    /* The route /user/{id:\d+}[/{name}] converts to the following array: */
+    [
+        [
+            '/user/',
+            ['id', '\d+'],
+        ],
+        [
+            '/user/',
+            ['id', '\d+'],
+            '/',
+            ['name', '[^/]+'],
+        ],
+    ]
+
+This array can then be passed to the `addRoute()` method of a data generator. After all routes have
+been added the `getData()` of the generator is invoked, which returns all the routing data required
+by the dispatcher. The format of this data is not further specified - it is tightly coupled to
+the corresponding dispatcher.
+
+The dispatcher accepts the routing data via a constructor and provides a `dispatch()` method, which
+you're already familiar with.
+
+The route parser can be overwritten individually (to make use of some different pattern syntax),
+however the data generator and dispatcher should always be changed as a pair, as the output from
+the former is tightly coupled to the input of the latter. The reason the generator and the
+dispatcher are separate is that only the latter is needed when using caching (as the output of
+the former is what is being cached.)
+
+When using the `simpleDispatcher` / `cachedDispatcher` functions from above the override happens
+through the options array:
+
+```php
+<?php
+
+$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
+    /* ... */
+}, [
+    'routeParser' => 'FastRoute\\RouteParser\\Std',
+    'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
+    'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
+]);
+```
+
+The above options array corresponds to the defaults. By replacing `GroupCountBased` by
+`GroupPosBased` you could switch to a different dispatching strategy.
+
+### A Note on HEAD Requests
+
+The HTTP spec requires servers to [support both GET and HEAD methods][2616-511]:
+
+> The methods GET and HEAD MUST be supported by all general-purpose servers
+
+To avoid forcing users to manually register HEAD routes for each resource we fallback to matching an
+available GET route for a given resource. The PHP web SAPI transparently removes the entity body
+from HEAD responses so this behavior has no effect on the vast majority of users.
+
+However, implementers using FastRoute outside the web SAPI environment (e.g. a custom server) MUST
+NOT send entity bodies generated in response to HEAD requests. If you are a non-SAPI user this is
+*your responsibility*; FastRoute has no purview to prevent you from breaking HTTP in such cases.
+
+Finally, note that applications MAY always specify their own HEAD method route for a given
+resource to bypass this behavior entirely.
+
+### Credits
+
+This library is based on a router that [Levi Morrison][levi] implemented for the Aerys server.
+
+A large number of tests, as well as HTTP compliance considerations, were provided by [Daniel Lowrey][rdlowrey].
+
+
+[2616-511]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 "RFC 2616 Section 5.1.1"
+[blog_post]: http://nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html
+[levi]: https://github.com/morrisonlevi
+[rdlowrey]: https://github.com/rdlowrey

+ 24 - 0
api/vendor/nikic/fast-route/composer.json

@@ -0,0 +1,24 @@
+{
+  "name": "nikic/fast-route",
+  "description": "Fast request router for PHP",
+  "keywords": ["routing", "router"],
+  "license": "BSD-3-Clause",
+  "authors": [
+    {
+      "name": "Nikita Popov",
+      "email": "nikic@php.net"
+    }
+  ],
+  "autoload": {
+    "psr-4": {
+      "FastRoute\\": "src/"
+    },
+    "files": ["src/functions.php"]
+  },
+  "require": {
+    "php": ">=5.4.0"
+  },
+  "require-dev": {
+    "phpunit/phpunit": "^4.8.35|~5.7"
+  }
+}

+ 24 - 0
api/vendor/nikic/fast-route/phpunit.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         syntaxCheck="false"
+         bootstrap="test/bootstrap.php"
+        >
+    <testsuites>
+        <testsuite name="FastRoute Tests">
+            <directory>./test/</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory>./src/</directory>
+        </whitelist>
+    </filter>
+</phpunit>

+ 28 - 0
api/vendor/nikic/fast-route/psalm.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<psalm
+    name="Example Psalm config with recommended defaults"
+    stopOnFirstError="false"
+    useDocblockTypes="true"
+    totallyTyped="false"
+    requireVoidReturnType="false"
+>
+    <projectFiles>
+        <directory name="src" />
+    </projectFiles>
+
+    <issueHandlers>
+        <LessSpecificReturnType errorLevel="info" />
+
+        <!-- level 3 issues - slightly lazy code writing, but provably low false-negatives -->
+        <DeprecatedMethod errorLevel="info" />
+
+        <MissingClosureReturnType errorLevel="info" />
+        <MissingReturnType errorLevel="info" />
+        <MissingPropertyType errorLevel="info" />
+        <InvalidDocblock errorLevel="info" />
+        <MisplacedRequiredParam errorLevel="info" />
+
+        <PropertyNotSetInConstructor errorLevel="info" />
+        <MissingConstructor errorLevel="info" />
+    </issueHandlers>
+</psalm>

+ 7 - 0
api/vendor/nikic/fast-route/src/BadRouteException.php

@@ -0,0 +1,7 @@
+<?php
+
+namespace FastRoute;
+
+class BadRouteException extends \LogicException
+{
+}

+ 26 - 0
api/vendor/nikic/fast-route/src/DataGenerator.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace FastRoute;
+
+interface DataGenerator
+{
+    /**
+     * Adds a route to the data generator. The route data uses the
+     * same format that is returned by RouterParser::parser().
+     *
+     * The handler doesn't necessarily need to be a callable, it
+     * can be arbitrary data that will be returned when the route
+     * matches.
+     *
+     * @param string $httpMethod
+     * @param array $routeData
+     * @param mixed $handler
+     */
+    public function addRoute($httpMethod, $routeData, $handler);
+
+    /**
+     * Returns dispatcher data in some unspecified format, which
+     * depends on the used method of dispatch.
+     */
+    public function getData();
+}

+ 31 - 0
api/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace FastRoute\DataGenerator;
+
+class CharCountBased extends RegexBasedAbstract
+{
+    protected function getApproxChunkSize()
+    {
+        return 30;
+    }
+
+    protected function processChunk($regexToRoutesMap)
+    {
+        $routeMap = [];
+        $regexes = [];
+
+        $suffixLen = 0;
+        $suffix = '';
+        $count = count($regexToRoutesMap);
+        foreach ($regexToRoutesMap as $regex => $route) {
+            $suffixLen++;
+            $suffix .= "\t";
+
+            $regexes[] = '(?:' . $regex . '/(\t{' . $suffixLen . '})\t{' . ($count - $suffixLen) . '})';
+            $routeMap[$suffix] = [$route->handler, $route->variables];
+        }
+
+        $regex = '~^(?|' . implode('|', $regexes) . ')$~';
+        return ['regex' => $regex, 'suffix' => '/' . $suffix, 'routeMap' => $routeMap];
+    }
+}

+ 30 - 0
api/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace FastRoute\DataGenerator;
+
+class GroupCountBased extends RegexBasedAbstract
+{
+    protected function getApproxChunkSize()
+    {
+        return 10;
+    }
+
+    protected function processChunk($regexToRoutesMap)
+    {
+        $routeMap = [];
+        $regexes = [];
+        $numGroups = 0;
+        foreach ($regexToRoutesMap as $regex => $route) {
+            $numVariables = count($route->variables);
+            $numGroups = max($numGroups, $numVariables);
+
+            $regexes[] = $regex . str_repeat('()', $numGroups - $numVariables);
+            $routeMap[$numGroups + 1] = [$route->handler, $route->variables];
+
+            ++$numGroups;
+        }
+
+        $regex = '~^(?|' . implode('|', $regexes) . ')$~';
+        return ['regex' => $regex, 'routeMap' => $routeMap];
+    }
+}

+ 27 - 0
api/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace FastRoute\DataGenerator;
+
+class GroupPosBased extends RegexBasedAbstract
+{
+    protected function getApproxChunkSize()
+    {
+        return 10;
+    }
+
+    protected function processChunk($regexToRoutesMap)
+    {
+        $routeMap = [];
+        $regexes = [];
+        $offset = 1;
+        foreach ($regexToRoutesMap as $regex => $route) {
+            $regexes[] = $regex;
+            $routeMap[$offset] = [$route->handler, $route->variables];
+
+            $offset += count($route->variables);
+        }
+
+        $regex = '~^(?:' . implode('|', $regexes) . ')$~';
+        return ['regex' => $regex, 'routeMap' => $routeMap];
+    }
+}

+ 27 - 0
api/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace FastRoute\DataGenerator;
+
+class MarkBased extends RegexBasedAbstract
+{
+    protected function getApproxChunkSize()
+    {
+        return 30;
+    }
+
+    protected function processChunk($regexToRoutesMap)
+    {
+        $routeMap = [];
+        $regexes = [];
+        $markName = 'a';
+        foreach ($regexToRoutesMap as $regex => $route) {
+            $regexes[] = $regex . '(*MARK:' . $markName . ')';
+            $routeMap[$markName] = [$route->handler, $route->variables];
+
+            ++$markName;
+        }
+
+        $regex = '~^(?|' . implode('|', $regexes) . ')$~';
+        return ['regex' => $regex, 'routeMap' => $routeMap];
+    }
+}

+ 186 - 0
api/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php

@@ -0,0 +1,186 @@
+<?php
+
+namespace FastRoute\DataGenerator;
+
+use FastRoute\BadRouteException;
+use FastRoute\DataGenerator;
+use FastRoute\Route;
+
+abstract class RegexBasedAbstract implements DataGenerator
+{
+    /** @var mixed[][] */
+    protected $staticRoutes = [];
+
+    /** @var Route[][] */
+    protected $methodToRegexToRoutesMap = [];
+
+    /**
+     * @return int
+     */
+    abstract protected function getApproxChunkSize();
+
+    /**
+     * @return mixed[]
+     */
+    abstract protected function processChunk($regexToRoutesMap);
+
+    public function addRoute($httpMethod, $routeData, $handler)
+    {
+        if ($this->isStaticRoute($routeData)) {
+            $this->addStaticRoute($httpMethod, $routeData, $handler);
+        } else {
+            $this->addVariableRoute($httpMethod, $routeData, $handler);
+        }
+    }
+
+    /**
+     * @return mixed[]
+     */
+    public function getData()
+    {
+        if (empty($this->methodToRegexToRoutesMap)) {
+            return [$this->staticRoutes, []];
+        }
+
+        return [$this->staticRoutes, $this->generateVariableRouteData()];
+    }
+
+    /**
+     * @return mixed[]
+     */
+    private function generateVariableRouteData()
+    {
+        $data = [];
+        foreach ($this->methodToRegexToRoutesMap as $method => $regexToRoutesMap) {
+            $chunkSize = $this->computeChunkSize(count($regexToRoutesMap));
+            $chunks = array_chunk($regexToRoutesMap, $chunkSize, true);
+            $data[$method] = array_map([$this, 'processChunk'], $chunks);
+        }
+        return $data;
+    }
+
+    /**
+     * @param int
+     * @return int
+     */
+    private function computeChunkSize($count)
+    {
+        $numParts = max(1, round($count / $this->getApproxChunkSize()));
+        return (int) ceil($count / $numParts);
+    }
+
+    /**
+     * @param mixed[]
+     * @return bool
+     */
+    private function isStaticRoute($routeData)
+    {
+        return count($routeData) === 1 && is_string($routeData[0]);
+    }
+
+    private function addStaticRoute($httpMethod, $routeData, $handler)
+    {
+        $routeStr = $routeData[0];
+
+        if (isset($this->staticRoutes[$httpMethod][$routeStr])) {
+            throw new BadRouteException(sprintf(
+                'Cannot register two routes matching "%s" for method "%s"',
+                $routeStr, $httpMethod
+            ));
+        }
+
+        if (isset($this->methodToRegexToRoutesMap[$httpMethod])) {
+            foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) {
+                if ($route->matches($routeStr)) {
+                    throw new BadRouteException(sprintf(
+                        'Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"',
+                        $routeStr, $route->regex, $httpMethod
+                    ));
+                }
+            }
+        }
+
+        $this->staticRoutes[$httpMethod][$routeStr] = $handler;
+    }
+
+    private function addVariableRoute($httpMethod, $routeData, $handler)
+    {
+        list($regex, $variables) = $this->buildRegexForRoute($routeData);
+
+        if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) {
+            throw new BadRouteException(sprintf(
+                'Cannot register two routes matching "%s" for method "%s"',
+                $regex, $httpMethod
+            ));
+        }
+
+        $this->methodToRegexToRoutesMap[$httpMethod][$regex] = new Route(
+            $httpMethod, $handler, $regex, $variables
+        );
+    }
+
+    /**
+     * @param mixed[]
+     * @return mixed[]
+     */
+    private function buildRegexForRoute($routeData)
+    {
+        $regex = '';
+        $variables = [];
+        foreach ($routeData as $part) {
+            if (is_string($part)) {
+                $regex .= preg_quote($part, '~');
+                continue;
+            }
+
+            list($varName, $regexPart) = $part;
+
+            if (isset($variables[$varName])) {
+                throw new BadRouteException(sprintf(
+                    'Cannot use the same placeholder "%s" twice', $varName
+                ));
+            }
+
+            if ($this->regexHasCapturingGroups($regexPart)) {
+                throw new BadRouteException(sprintf(
+                    'Regex "%s" for parameter "%s" contains a capturing group',
+                    $regexPart, $varName
+                ));
+            }
+
+            $variables[$varName] = $varName;
+            $regex .= '(' . $regexPart . ')';
+        }
+
+        return [$regex, $variables];
+    }
+
+    /**
+     * @param string
+     * @return bool
+     */
+    private function regexHasCapturingGroups($regex)
+    {
+        if (false === strpos($regex, '(')) {
+            // Needs to have at least a ( to contain a capturing group
+            return false;
+        }
+
+        // Semi-accurate detection for capturing groups
+        return (bool) preg_match(
+            '~
+                (?:
+                    \(\?\(
+                  | \[ [^\]\\\\]* (?: \\\\ . [^\]\\\\]* )* \]
+                  | \\\\ .
+                ) (*SKIP)(*FAIL) |
+                \(
+                (?!
+                    \? (?! <(?![!=]) | P< | \' )
+                  | \*
+                )
+            ~x',
+            $regex
+        );
+    }
+}

+ 26 - 0
api/vendor/nikic/fast-route/src/Dispatcher.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace FastRoute;
+
+interface Dispatcher
+{
+    const NOT_FOUND = 0;
+    const FOUND = 1;
+    const METHOD_NOT_ALLOWED = 2;
+
+    /**
+     * Dispatches against the provided HTTP method verb and URI.
+     *
+     * Returns array with one of the following formats:
+     *
+     *     [self::NOT_FOUND]
+     *     [self::METHOD_NOT_ALLOWED, ['GET', 'OTHER_ALLOWED_METHODS']]
+     *     [self::FOUND, $handler, ['varName' => 'value', ...]]
+     *
+     * @param string $httpMethod
+     * @param string $uri
+     *
+     * @return array
+     */
+    public function dispatch($httpMethod, $uri);
+}

+ 31 - 0
api/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class CharCountBased extends RegexBasedAbstract
+{
+    public function __construct($data)
+    {
+        list($this->staticRouteMap, $this->variableRouteData) = $data;
+    }
+
+    protected function dispatchVariableRoute($routeData, $uri)
+    {
+        foreach ($routeData as $data) {
+            if (!preg_match($data['regex'], $uri . $data['suffix'], $matches)) {
+                continue;
+            }
+
+            list($handler, $varNames) = $data['routeMap'][end($matches)];
+
+            $vars = [];
+            $i = 0;
+            foreach ($varNames as $varName) {
+                $vars[$varName] = $matches[++$i];
+            }
+            return [self::FOUND, $handler, $vars];
+        }
+
+        return [self::NOT_FOUND];
+    }
+}

+ 31 - 0
api/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class GroupCountBased extends RegexBasedAbstract
+{
+    public function __construct($data)
+    {
+        list($this->staticRouteMap, $this->variableRouteData) = $data;
+    }
+
+    protected function dispatchVariableRoute($routeData, $uri)
+    {
+        foreach ($routeData as $data) {
+            if (!preg_match($data['regex'], $uri, $matches)) {
+                continue;
+            }
+
+            list($handler, $varNames) = $data['routeMap'][count($matches)];
+
+            $vars = [];
+            $i = 0;
+            foreach ($varNames as $varName) {
+                $vars[$varName] = $matches[++$i];
+            }
+            return [self::FOUND, $handler, $vars];
+        }
+
+        return [self::NOT_FOUND];
+    }
+}

+ 33 - 0
api/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class GroupPosBased extends RegexBasedAbstract
+{
+    public function __construct($data)
+    {
+        list($this->staticRouteMap, $this->variableRouteData) = $data;
+    }
+
+    protected function dispatchVariableRoute($routeData, $uri)
+    {
+        foreach ($routeData as $data) {
+            if (!preg_match($data['regex'], $uri, $matches)) {
+                continue;
+            }
+
+            // find first non-empty match
+            for ($i = 1; '' === $matches[$i]; ++$i);
+
+            list($handler, $varNames) = $data['routeMap'][$i];
+
+            $vars = [];
+            foreach ($varNames as $varName) {
+                $vars[$varName] = $matches[$i++];
+            }
+            return [self::FOUND, $handler, $vars];
+        }
+
+        return [self::NOT_FOUND];
+    }
+}

+ 31 - 0
api/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class MarkBased extends RegexBasedAbstract
+{
+    public function __construct($data)
+    {
+        list($this->staticRouteMap, $this->variableRouteData) = $data;
+    }
+
+    protected function dispatchVariableRoute($routeData, $uri)
+    {
+        foreach ($routeData as $data) {
+            if (!preg_match($data['regex'], $uri, $matches)) {
+                continue;
+            }
+
+            list($handler, $varNames) = $data['routeMap'][$matches['MARK']];
+
+            $vars = [];
+            $i = 0;
+            foreach ($varNames as $varName) {
+                $vars[$varName] = $matches[++$i];
+            }
+            return [self::FOUND, $handler, $vars];
+        }
+
+        return [self::NOT_FOUND];
+    }
+}

+ 88 - 0
api/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php

@@ -0,0 +1,88 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+use FastRoute\Dispatcher;
+
+abstract class RegexBasedAbstract implements Dispatcher
+{
+    /** @var mixed[][] */
+    protected $staticRouteMap = [];
+
+    /** @var mixed[] */
+    protected $variableRouteData = [];
+
+    /**
+     * @return mixed[]
+     */
+    abstract protected function dispatchVariableRoute($routeData, $uri);
+
+    public function dispatch($httpMethod, $uri)
+    {
+        if (isset($this->staticRouteMap[$httpMethod][$uri])) {
+            $handler = $this->staticRouteMap[$httpMethod][$uri];
+            return [self::FOUND, $handler, []];
+        }
+
+        $varRouteData = $this->variableRouteData;
+        if (isset($varRouteData[$httpMethod])) {
+            $result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri);
+            if ($result[0] === self::FOUND) {
+                return $result;
+            }
+        }
+
+        // For HEAD requests, attempt fallback to GET
+        if ($httpMethod === 'HEAD') {
+            if (isset($this->staticRouteMap['GET'][$uri])) {
+                $handler = $this->staticRouteMap['GET'][$uri];
+                return [self::FOUND, $handler, []];
+            }
+            if (isset($varRouteData['GET'])) {
+                $result = $this->dispatchVariableRoute($varRouteData['GET'], $uri);
+                if ($result[0] === self::FOUND) {
+                    return $result;
+                }
+            }
+        }
+
+        // If nothing else matches, try fallback routes
+        if (isset($this->staticRouteMap['*'][$uri])) {
+            $handler = $this->staticRouteMap['*'][$uri];
+            return [self::FOUND, $handler, []];
+        }
+        if (isset($varRouteData['*'])) {
+            $result = $this->dispatchVariableRoute($varRouteData['*'], $uri);
+            if ($result[0] === self::FOUND) {
+                return $result;
+            }
+        }
+
+        // Find allowed methods for this URI by matching against all other HTTP methods as well
+        $allowedMethods = [];
+
+        foreach ($this->staticRouteMap as $method => $uriMap) {
+            if ($method !== $httpMethod && isset($uriMap[$uri])) {
+                $allowedMethods[] = $method;
+            }
+        }
+
+        foreach ($varRouteData as $method => $routeData) {
+            if ($method === $httpMethod) {
+                continue;
+            }
+
+            $result = $this->dispatchVariableRoute($routeData, $uri);
+            if ($result[0] === self::FOUND) {
+                $allowedMethods[] = $method;
+            }
+        }
+
+        // If there are no allowed methods the route simply does not exist
+        if ($allowedMethods) {
+            return [self::METHOD_NOT_ALLOWED, $allowedMethods];
+        }
+
+        return [self::NOT_FOUND];
+    }
+}

+ 47 - 0
api/vendor/nikic/fast-route/src/Route.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace FastRoute;
+
+class Route
+{
+    /** @var string */
+    public $httpMethod;
+
+    /** @var string */
+    public $regex;
+
+    /** @var array */
+    public $variables;
+
+    /** @var mixed */
+    public $handler;
+
+    /**
+     * Constructs a route (value object).
+     *
+     * @param string $httpMethod
+     * @param mixed  $handler
+     * @param string $regex
+     * @param array  $variables
+     */
+    public function __construct($httpMethod, $handler, $regex, $variables)
+    {
+        $this->httpMethod = $httpMethod;
+        $this->handler = $handler;
+        $this->regex = $regex;
+        $this->variables = $variables;
+    }
+
+    /**
+     * Tests whether this route matches the given string.
+     *
+     * @param string $str
+     *
+     * @return bool
+     */
+    public function matches($str)
+    {
+        $regex = '~^' . $this->regex . '$~';
+        return (bool) preg_match($regex, $str);
+    }
+}

+ 152 - 0
api/vendor/nikic/fast-route/src/RouteCollector.php

@@ -0,0 +1,152 @@
+<?php
+
+namespace FastRoute;
+
+class RouteCollector
+{
+    /** @var RouteParser */
+    protected $routeParser;
+
+    /** @var DataGenerator */
+    protected $dataGenerator;
+
+    /** @var string */
+    protected $currentGroupPrefix;
+
+    /**
+     * Constructs a route collector.
+     *
+     * @param RouteParser   $routeParser
+     * @param DataGenerator $dataGenerator
+     */
+    public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator)
+    {
+        $this->routeParser = $routeParser;
+        $this->dataGenerator = $dataGenerator;
+        $this->currentGroupPrefix = '';
+    }
+
+    /**
+     * Adds a route to the collection.
+     *
+     * The syntax used in the $route string depends on the used route parser.
+     *
+     * @param string|string[] $httpMethod
+     * @param string $route
+     * @param mixed  $handler
+     */
+    public function addRoute($httpMethod, $route, $handler)
+    {
+        $route = $this->currentGroupPrefix . $route;
+        $routeDatas = $this->routeParser->parse($route);
+        foreach ((array) $httpMethod as $method) {
+            foreach ($routeDatas as $routeData) {
+                $this->dataGenerator->addRoute($method, $routeData, $handler);
+            }
+        }
+    }
+
+    /**
+     * Create a route group with a common prefix.
+     *
+     * All routes created in the passed callback will have the given group prefix prepended.
+     *
+     * @param string $prefix
+     * @param callable $callback
+     */
+    public function addGroup($prefix, callable $callback)
+    {
+        $previousGroupPrefix = $this->currentGroupPrefix;
+        $this->currentGroupPrefix = $previousGroupPrefix . $prefix;
+        $callback($this);
+        $this->currentGroupPrefix = $previousGroupPrefix;
+    }
+
+    /**
+     * Adds a GET route to the collection
+     * 
+     * This is simply an alias of $this->addRoute('GET', $route, $handler)
+     *
+     * @param string $route
+     * @param mixed  $handler
+     */
+    public function get($route, $handler)
+    {
+        $this->addRoute('GET', $route, $handler);
+    }
+
+    /**
+     * Adds a POST route to the collection
+     * 
+     * This is simply an alias of $this->addRoute('POST', $route, $handler)
+     *
+     * @param string $route
+     * @param mixed  $handler
+     */
+    public function post($route, $handler)
+    {
+        $this->addRoute('POST', $route, $handler);
+    }
+
+    /**
+     * Adds a PUT route to the collection
+     * 
+     * This is simply an alias of $this->addRoute('PUT', $route, $handler)
+     *
+     * @param string $route
+     * @param mixed  $handler
+     */
+    public function put($route, $handler)
+    {
+        $this->addRoute('PUT', $route, $handler);
+    }
+
+    /**
+     * Adds a DELETE route to the collection
+     * 
+     * This is simply an alias of $this->addRoute('DELETE', $route, $handler)
+     *
+     * @param string $route
+     * @param mixed  $handler
+     */
+    public function delete($route, $handler)
+    {
+        $this->addRoute('DELETE', $route, $handler);
+    }
+
+    /**
+     * Adds a PATCH route to the collection
+     * 
+     * This is simply an alias of $this->addRoute('PATCH', $route, $handler)
+     *
+     * @param string $route
+     * @param mixed  $handler
+     */
+    public function patch($route, $handler)
+    {
+        $this->addRoute('PATCH', $route, $handler);
+    }
+
+    /**
+     * Adds a HEAD route to the collection
+     *
+     * This is simply an alias of $this->addRoute('HEAD', $route, $handler)
+     *
+     * @param string $route
+     * @param mixed  $handler
+     */
+    public function head($route, $handler)
+    {
+        $this->addRoute('HEAD', $route, $handler);
+    }
+
+    /**
+     * Returns the collected route data, as provided by the data generator.
+     *
+     * @return array
+     */
+    public function getData()
+    {
+        return $this->dataGenerator->getData();
+    }
+}

+ 37 - 0
api/vendor/nikic/fast-route/src/RouteParser.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace FastRoute;
+
+interface RouteParser
+{
+    /**
+     * Parses a route string into multiple route data arrays.
+     *
+     * The expected output is defined using an example:
+     *
+     * For the route string "/fixedRoutePart/{varName}[/moreFixed/{varName2:\d+}]", if {varName} is interpreted as
+     * a placeholder and [...] is interpreted as an optional route part, the expected result is:
+     *
+     * [
+     *     // first route: without optional part
+     *     [
+     *         "/fixedRoutePart/",
+     *         ["varName", "[^/]+"],
+     *     ],
+     *     // second route: with optional part
+     *     [
+     *         "/fixedRoutePart/",
+     *         ["varName", "[^/]+"],
+     *         "/moreFixed/",
+     *         ["varName2", [0-9]+"],
+     *     ],
+     * ]
+     *
+     * Here one route string was converted into two route data arrays.
+     *
+     * @param string $route Route string to parse
+     *
+     * @return mixed[][] Array of route data arrays
+     */
+    public function parse($route);
+}

+ 87 - 0
api/vendor/nikic/fast-route/src/RouteParser/Std.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace FastRoute\RouteParser;
+
+use FastRoute\BadRouteException;
+use FastRoute\RouteParser;
+
+/**
+ * Parses route strings of the following form:
+ *
+ * "/user/{name}[/{id:[0-9]+}]"
+ */
+class Std implements RouteParser
+{
+    const VARIABLE_REGEX = <<<'REGEX'
+\{
+    \s* ([a-zA-Z_][a-zA-Z0-9_-]*) \s*
+    (?:
+        : \s* ([^{}]*(?:\{(?-1)\}[^{}]*)*)
+    )?
+\}
+REGEX;
+    const DEFAULT_DISPATCH_REGEX = '[^/]+';
+
+    public function parse($route)
+    {
+        $routeWithoutClosingOptionals = rtrim($route, ']');
+        $numOptionals = strlen($route) - strlen($routeWithoutClosingOptionals);
+
+        // Split on [ while skipping placeholders
+        $segments = preg_split('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \[~x', $routeWithoutClosingOptionals);
+        if ($numOptionals !== count($segments) - 1) {
+            // If there are any ] in the middle of the route, throw a more specific error message
+            if (preg_match('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \]~x', $routeWithoutClosingOptionals)) {
+                throw new BadRouteException('Optional segments can only occur at the end of a route');
+            }
+            throw new BadRouteException("Number of opening '[' and closing ']' does not match");
+        }
+
+        $currentRoute = '';
+        $routeDatas = [];
+        foreach ($segments as $n => $segment) {
+            if ($segment === '' && $n !== 0) {
+                throw new BadRouteException('Empty optional part');
+            }
+
+            $currentRoute .= $segment;
+            $routeDatas[] = $this->parsePlaceholders($currentRoute);
+        }
+        return $routeDatas;
+    }
+
+    /**
+     * Parses a route string that does not contain optional segments.
+     *
+     * @param string
+     * @return mixed[]
+     */
+    private function parsePlaceholders($route)
+    {
+        if (!preg_match_all(
+            '~' . self::VARIABLE_REGEX . '~x', $route, $matches,
+            PREG_OFFSET_CAPTURE | PREG_SET_ORDER
+        )) {
+            return [$route];
+        }
+
+        $offset = 0;
+        $routeData = [];
+        foreach ($matches as $set) {
+            if ($set[0][1] > $offset) {
+                $routeData[] = substr($route, $offset, $set[0][1] - $offset);
+            }
+            $routeData[] = [
+                $set[1][0],
+                isset($set[2]) ? trim($set[2][0]) : self::DEFAULT_DISPATCH_REGEX
+            ];
+            $offset = $set[0][1] + strlen($set[0][0]);
+        }
+
+        if ($offset !== strlen($route)) {
+            $routeData[] = substr($route, $offset);
+        }
+
+        return $routeData;
+    }
+}

+ 12 - 0
api/vendor/nikic/fast-route/src/bootstrap.php

@@ -0,0 +1,12 @@
+<?php
+
+namespace FastRoute;
+
+require __DIR__ . '/functions.php';
+
+spl_autoload_register(function ($class) {
+    if (strpos($class, 'FastRoute\\') === 0) {
+        $name = substr($class, strlen('FastRoute'));
+        require __DIR__ . strtr($name, '\\', DIRECTORY_SEPARATOR) . '.php';
+    }
+});

+ 74 - 0
api/vendor/nikic/fast-route/src/functions.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace FastRoute;
+
+if (!function_exists('FastRoute\simpleDispatcher')) {
+    /**
+     * @param callable $routeDefinitionCallback
+     * @param array $options
+     *
+     * @return Dispatcher
+     */
+    function simpleDispatcher(callable $routeDefinitionCallback, array $options = [])
+    {
+        $options += [
+            'routeParser' => 'FastRoute\\RouteParser\\Std',
+            'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
+            'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
+            'routeCollector' => 'FastRoute\\RouteCollector',
+        ];
+
+        /** @var RouteCollector $routeCollector */
+        $routeCollector = new $options['routeCollector'](
+            new $options['routeParser'], new $options['dataGenerator']
+        );
+        $routeDefinitionCallback($routeCollector);
+
+        return new $options['dispatcher']($routeCollector->getData());
+    }
+
+    /**
+     * @param callable $routeDefinitionCallback
+     * @param array $options
+     *
+     * @return Dispatcher
+     */
+    function cachedDispatcher(callable $routeDefinitionCallback, array $options = [])
+    {
+        $options += [
+            'routeParser' => 'FastRoute\\RouteParser\\Std',
+            'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
+            'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
+            'routeCollector' => 'FastRoute\\RouteCollector',
+            'cacheDisabled' => false,
+        ];
+
+        if (!isset($options['cacheFile'])) {
+            throw new \LogicException('Must specify "cacheFile" option');
+        }
+
+        if (!$options['cacheDisabled'] && file_exists($options['cacheFile'])) {
+            $dispatchData = require $options['cacheFile'];
+            if (!is_array($dispatchData)) {
+                throw new \RuntimeException('Invalid cache file "' . $options['cacheFile'] . '"');
+            }
+            return new $options['dispatcher']($dispatchData);
+        }
+
+        $routeCollector = new $options['routeCollector'](
+            new $options['routeParser'], new $options['dataGenerator']
+        );
+        $routeDefinitionCallback($routeCollector);
+
+        /** @var RouteCollector $routeCollector */
+        $dispatchData = $routeCollector->getData();
+        if (!$options['cacheDisabled']) {
+            file_put_contents(
+                $options['cacheFile'],
+                '<?php return ' . var_export($dispatchData, true) . ';'
+            );
+        }
+
+        return new $options['dispatcher']($dispatchData);
+    }
+}

+ 16 - 0
api/vendor/nikic/fast-route/test/Dispatcher/CharCountBasedTest.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class CharCountBasedTest extends DispatcherTest
+{
+    protected function getDispatcherClass()
+    {
+        return 'FastRoute\\Dispatcher\\CharCountBased';
+    }
+
+    protected function getDataGeneratorClass()
+    {
+        return 'FastRoute\\DataGenerator\\CharCountBased';
+    }
+}

+ 581 - 0
api/vendor/nikic/fast-route/test/Dispatcher/DispatcherTest.php

@@ -0,0 +1,581 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+use FastRoute\RouteCollector;
+use PHPUnit\Framework\TestCase;
+
+abstract class DispatcherTest extends TestCase
+{
+    /**
+     * Delegate dispatcher selection to child test classes
+     */
+    abstract protected function getDispatcherClass();
+
+    /**
+     * Delegate dataGenerator selection to child test classes
+     */
+    abstract protected function getDataGeneratorClass();
+
+    /**
+     * Set appropriate options for the specific Dispatcher class we're testing
+     */
+    private function generateDispatcherOptions()
+    {
+        return [
+            'dataGenerator' => $this->getDataGeneratorClass(),
+            'dispatcher' => $this->getDispatcherClass()
+        ];
+    }
+
+    /**
+     * @dataProvider provideFoundDispatchCases
+     */
+    public function testFoundDispatches($method, $uri, $callback, $handler, $argDict)
+    {
+        $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions());
+        $info = $dispatcher->dispatch($method, $uri);
+        $this->assertSame($dispatcher::FOUND, $info[0]);
+        $this->assertSame($handler, $info[1]);
+        $this->assertSame($argDict, $info[2]);
+    }
+
+    /**
+     * @dataProvider provideNotFoundDispatchCases
+     */
+    public function testNotFoundDispatches($method, $uri, $callback)
+    {
+        $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions());
+        $routeInfo = $dispatcher->dispatch($method, $uri);
+        $this->assertArrayNotHasKey(1, $routeInfo,
+            'NOT_FOUND result must only contain a single element in the returned info array'
+        );
+        $this->assertSame($dispatcher::NOT_FOUND, $routeInfo[0]);
+    }
+
+    /**
+     * @dataProvider provideMethodNotAllowedDispatchCases
+     */
+    public function testMethodNotAllowedDispatches($method, $uri, $callback, $availableMethods)
+    {
+        $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions());
+        $routeInfo = $dispatcher->dispatch($method, $uri);
+        $this->assertArrayHasKey(1, $routeInfo,
+            'METHOD_NOT_ALLOWED result must return an array of allowed methods at index 1'
+        );
+
+        list($routedStatus, $methodArray) = $dispatcher->dispatch($method, $uri);
+        $this->assertSame($dispatcher::METHOD_NOT_ALLOWED, $routedStatus);
+        $this->assertSame($availableMethods, $methodArray);
+    }
+
+    /**
+     * @expectedException \FastRoute\BadRouteException
+     * @expectedExceptionMessage Cannot use the same placeholder "test" twice
+     */
+    public function testDuplicateVariableNameError()
+    {
+        \FastRoute\simpleDispatcher(function (RouteCollector $r) {
+            $r->addRoute('GET', '/foo/{test}/{test:\d+}', 'handler0');
+        }, $this->generateDispatcherOptions());
+    }
+
+    /**
+     * @expectedException \FastRoute\BadRouteException
+     * @expectedExceptionMessage Cannot register two routes matching "/user/([^/]+)" for method "GET"
+     */
+    public function testDuplicateVariableRoute()
+    {
+        \FastRoute\simpleDispatcher(function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{id}', 'handler0'); // oops, forgot \d+ restriction ;)
+            $r->addRoute('GET', '/user/{name}', 'handler1');
+        }, $this->generateDispatcherOptions());
+    }
+
+    /**
+     * @expectedException \FastRoute\BadRouteException
+     * @expectedExceptionMessage Cannot register two routes matching "/user" for method "GET"
+     */
+    public function testDuplicateStaticRoute()
+    {
+        \FastRoute\simpleDispatcher(function (RouteCollector $r) {
+            $r->addRoute('GET', '/user', 'handler0');
+            $r->addRoute('GET', '/user', 'handler1');
+        }, $this->generateDispatcherOptions());
+    }
+
+    /**
+     * @expectedException \FastRoute\BadRouteException
+     * @expectedExceptionMessage Static route "/user/nikic" is shadowed by previously defined variable route "/user/([^/]+)" for method "GET"
+     */
+    public function testShadowedStaticRoute()
+    {
+        \FastRoute\simpleDispatcher(function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}', 'handler0');
+            $r->addRoute('GET', '/user/nikic', 'handler1');
+        }, $this->generateDispatcherOptions());
+    }
+
+    /**
+     * @expectedException \FastRoute\BadRouteException
+     * @expectedExceptionMessage Regex "(en|de)" for parameter "lang" contains a capturing group
+     */
+    public function testCapturing()
+    {
+        \FastRoute\simpleDispatcher(function (RouteCollector $r) {
+            $r->addRoute('GET', '/{lang:(en|de)}', 'handler0');
+        }, $this->generateDispatcherOptions());
+    }
+
+    public function provideFoundDispatchCases()
+    {
+        $cases = [];
+
+        // 0 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/resource/123/456', 'handler0');
+        };
+
+        $method = 'GET';
+        $uri = '/resource/123/456';
+        $handler = 'handler0';
+        $argDict = [];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 1 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/handler0', 'handler0');
+            $r->addRoute('GET', '/handler1', 'handler1');
+            $r->addRoute('GET', '/handler2', 'handler2');
+        };
+
+        $method = 'GET';
+        $uri = '/handler2';
+        $handler = 'handler2';
+        $argDict = [];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 2 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
+            $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
+            $r->addRoute('GET', '/user/{name}', 'handler2');
+        };
+
+        $method = 'GET';
+        $uri = '/user/rdlowrey';
+        $handler = 'handler2';
+        $argDict = ['name' => 'rdlowrey'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 3 -------------------------------------------------------------------------------------->
+
+        // reuse $callback from #2
+
+        $method = 'GET';
+        $uri = '/user/12345';
+        $handler = 'handler1';
+        $argDict = ['id' => '12345'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 4 -------------------------------------------------------------------------------------->
+
+        // reuse $callback from #3
+
+        $method = 'GET';
+        $uri = '/user/NaN';
+        $handler = 'handler2';
+        $argDict = ['name' => 'NaN'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 5 -------------------------------------------------------------------------------------->
+
+        // reuse $callback from #4
+
+        $method = 'GET';
+        $uri = '/user/rdlowrey/12345';
+        $handler = 'handler0';
+        $argDict = ['name' => 'rdlowrey', 'id' => '12345'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 6 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler0');
+            $r->addRoute('GET', '/user/12345/extension', 'handler1');
+            $r->addRoute('GET', '/user/{id:[0-9]+}.{extension}', 'handler2');
+        };
+
+        $method = 'GET';
+        $uri = '/user/12345.svg';
+        $handler = 'handler2';
+        $argDict = ['id' => '12345', 'extension' => 'svg'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 7 ----- Test GET method fallback on HEAD route miss ------------------------------------>
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}', 'handler0');
+            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler1');
+            $r->addRoute('GET', '/static0', 'handler2');
+            $r->addRoute('GET', '/static1', 'handler3');
+            $r->addRoute('HEAD', '/static1', 'handler4');
+        };
+
+        $method = 'HEAD';
+        $uri = '/user/rdlowrey';
+        $handler = 'handler0';
+        $argDict = ['name' => 'rdlowrey'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 8 ----- Test GET method fallback on HEAD route miss ------------------------------------>
+
+        // reuse $callback from #7
+
+        $method = 'HEAD';
+        $uri = '/user/rdlowrey/1234';
+        $handler = 'handler1';
+        $argDict = ['name' => 'rdlowrey', 'id' => '1234'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 9 ----- Test GET method fallback on HEAD route miss ------------------------------------>
+
+        // reuse $callback from #8
+
+        $method = 'HEAD';
+        $uri = '/static0';
+        $handler = 'handler2';
+        $argDict = [];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 10 ---- Test existing HEAD route used if available (no fallback) ----------------------->
+
+        // reuse $callback from #9
+
+        $method = 'HEAD';
+        $uri = '/static1';
+        $handler = 'handler4';
+        $argDict = [];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 11 ---- More specified routes are not shadowed by less specific of another method ------>
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}', 'handler0');
+            $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1');
+        };
+
+        $method = 'POST';
+        $uri = '/user/rdlowrey';
+        $handler = 'handler1';
+        $argDict = ['name' => 'rdlowrey'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 12 ---- Handler of more specific routes is used, if it occurs first -------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}', 'handler0');
+            $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1');
+            $r->addRoute('POST', '/user/{name}', 'handler2');
+        };
+
+        $method = 'POST';
+        $uri = '/user/rdlowrey';
+        $handler = 'handler1';
+        $argDict = ['name' => 'rdlowrey'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 13 ---- Route with constant suffix ----------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}', 'handler0');
+            $r->addRoute('GET', '/user/{name}/edit', 'handler1');
+        };
+
+        $method = 'GET';
+        $uri = '/user/rdlowrey/edit';
+        $handler = 'handler1';
+        $argDict = ['name' => 'rdlowrey'];
+
+        $cases[] = [$method, $uri, $callback, $handler, $argDict];
+
+        // 14 ---- Handle multiple methods with the same handler ---------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost');
+            $r->addRoute(['DELETE'], '/user', 'handlerDelete');
+            $r->addRoute([], '/user', 'handlerNone');
+        };
+
+        $argDict = [];
+        $cases[] = ['GET', '/user', $callback, 'handlerGetPost', $argDict];
+        $cases[] = ['POST', '/user', $callback, 'handlerGetPost', $argDict];
+        $cases[] = ['DELETE', '/user', $callback, 'handlerDelete', $argDict];
+
+        // 17 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('POST', '/user.json', 'handler0');
+            $r->addRoute('GET', '/{entity}.json', 'handler1');
+        };
+
+        $cases[] = ['GET', '/user.json', $callback, 'handler1', ['entity' => 'user']];
+
+        // 18 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '', 'handler0');
+        };
+
+        $cases[] = ['GET', '', $callback, 'handler0', []];
+
+        // 19 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('HEAD', '/a/{foo}', 'handler0');
+            $r->addRoute('GET', '/b/{foo}', 'handler1');
+        };
+
+        $cases[] = ['HEAD', '/b/bar', $callback, 'handler1', ['foo' => 'bar']];
+
+        // 20 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('HEAD', '/a', 'handler0');
+            $r->addRoute('GET', '/b', 'handler1');
+        };
+
+        $cases[] = ['HEAD', '/b', $callback, 'handler1', []];
+
+        // 21 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/foo', 'handler0');
+            $r->addRoute('HEAD', '/{bar}', 'handler1');
+        };
+
+        $cases[] = ['HEAD', '/foo', $callback, 'handler1', ['bar' => 'foo']];
+
+        // 22 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('*', '/user', 'handler0');
+            $r->addRoute('*', '/{user}', 'handler1');
+            $r->addRoute('GET', '/user', 'handler2');
+        };
+
+        $cases[] = ['GET', '/user', $callback, 'handler2', []];
+
+        // 23 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('*', '/user', 'handler0');
+            $r->addRoute('GET', '/user', 'handler1');
+        };
+
+        $cases[] = ['POST', '/user', $callback, 'handler0', []];
+
+        // 24 ----
+
+        $cases[] = ['HEAD', '/user', $callback, 'handler1', []];
+
+        // 25 ----
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/{bar}', 'handler0');
+            $r->addRoute('*', '/foo', 'handler1');
+        };
+
+        $cases[] = ['GET', '/foo', $callback, 'handler0', ['bar' => 'foo']];
+
+        // 26 ----
+
+        $callback = function(RouteCollector $r) {
+            $r->addRoute('GET', '/user', 'handler0');
+            $r->addRoute('*', '/{foo:.*}', 'handler1');
+        };
+
+        $cases[] = ['POST', '/bar', $callback, 'handler1', ['foo' => 'bar']];
+
+        // x -------------------------------------------------------------------------------------->
+
+        return $cases;
+    }
+
+    public function provideNotFoundDispatchCases()
+    {
+        $cases = [];
+
+        // 0 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/resource/123/456', 'handler0');
+        };
+
+        $method = 'GET';
+        $uri = '/not-found';
+
+        $cases[] = [$method, $uri, $callback];
+
+        // 1 -------------------------------------------------------------------------------------->
+
+        // reuse callback from #0
+        $method = 'POST';
+        $uri = '/not-found';
+
+        $cases[] = [$method, $uri, $callback];
+
+        // 2 -------------------------------------------------------------------------------------->
+
+        // reuse callback from #1
+        $method = 'PUT';
+        $uri = '/not-found';
+
+        $cases[] = [$method, $uri, $callback];
+
+        // 3 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/handler0', 'handler0');
+            $r->addRoute('GET', '/handler1', 'handler1');
+            $r->addRoute('GET', '/handler2', 'handler2');
+        };
+
+        $method = 'GET';
+        $uri = '/not-found';
+
+        $cases[] = [$method, $uri, $callback];
+
+        // 4 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
+            $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
+            $r->addRoute('GET', '/user/{name}', 'handler2');
+        };
+
+        $method = 'GET';
+        $uri = '/not-found';
+
+        $cases[] = [$method, $uri, $callback];
+
+        // 5 -------------------------------------------------------------------------------------->
+
+        // reuse callback from #4
+        $method = 'GET';
+        $uri = '/user/rdlowrey/12345/not-found';
+
+        $cases[] = [$method, $uri, $callback];
+
+        // 6 -------------------------------------------------------------------------------------->
+
+        // reuse callback from #5
+        $method = 'HEAD';
+
+        $cases[] = [$method, $uri, $callback];
+
+        // x -------------------------------------------------------------------------------------->
+
+        return $cases;
+    }
+
+    public function provideMethodNotAllowedDispatchCases()
+    {
+        $cases = [];
+
+        // 0 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/resource/123/456', 'handler0');
+        };
+
+        $method = 'POST';
+        $uri = '/resource/123/456';
+        $allowedMethods = ['GET'];
+
+        $cases[] = [$method, $uri, $callback, $allowedMethods];
+
+        // 1 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/resource/123/456', 'handler0');
+            $r->addRoute('POST', '/resource/123/456', 'handler1');
+            $r->addRoute('PUT', '/resource/123/456', 'handler2');
+            $r->addRoute('*', '/', 'handler3');
+        };
+
+        $method = 'DELETE';
+        $uri = '/resource/123/456';
+        $allowedMethods = ['GET', 'POST', 'PUT'];
+
+        $cases[] = [$method, $uri, $callback, $allowedMethods];
+
+        // 2 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
+            $r->addRoute('POST', '/user/{name}/{id:[0-9]+}', 'handler1');
+            $r->addRoute('PUT', '/user/{name}/{id:[0-9]+}', 'handler2');
+            $r->addRoute('PATCH', '/user/{name}/{id:[0-9]+}', 'handler3');
+        };
+
+        $method = 'DELETE';
+        $uri = '/user/rdlowrey/42';
+        $allowedMethods = ['GET', 'POST', 'PUT', 'PATCH'];
+
+        $cases[] = [$method, $uri, $callback, $allowedMethods];
+
+        // 3 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('POST', '/user/{name}', 'handler1');
+            $r->addRoute('PUT', '/user/{name:[a-z]+}', 'handler2');
+            $r->addRoute('PATCH', '/user/{name:[a-z]+}', 'handler3');
+        };
+
+        $method = 'GET';
+        $uri = '/user/rdlowrey';
+        $allowedMethods = ['POST', 'PUT', 'PATCH'];
+
+        $cases[] = [$method, $uri, $callback, $allowedMethods];
+
+        // 4 -------------------------------------------------------------------------------------->
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost');
+            $r->addRoute(['DELETE'], '/user', 'handlerDelete');
+            $r->addRoute([], '/user', 'handlerNone');
+        };
+
+        $cases[] = ['PUT', '/user', $callback, ['GET', 'POST', 'DELETE']];
+
+        // 5
+
+        $callback = function (RouteCollector $r) {
+            $r->addRoute('POST', '/user.json', 'handler0');
+            $r->addRoute('GET', '/{entity}.json', 'handler1');
+        };
+
+        $cases[] = ['PUT', '/user.json', $callback, ['POST', 'GET']];
+
+        // x -------------------------------------------------------------------------------------->
+
+        return $cases;
+    }
+}

+ 16 - 0
api/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class GroupCountBasedTest extends DispatcherTest
+{
+    protected function getDispatcherClass()
+    {
+        return 'FastRoute\\Dispatcher\\GroupCountBased';
+    }
+
+    protected function getDataGeneratorClass()
+    {
+        return 'FastRoute\\DataGenerator\\GroupCountBased';
+    }
+}

+ 16 - 0
api/vendor/nikic/fast-route/test/Dispatcher/GroupPosBasedTest.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class GroupPosBasedTest extends DispatcherTest
+{
+    protected function getDispatcherClass()
+    {
+        return 'FastRoute\\Dispatcher\\GroupPosBased';
+    }
+
+    protected function getDataGeneratorClass()
+    {
+        return 'FastRoute\\DataGenerator\\GroupPosBased';
+    }
+}

+ 24 - 0
api/vendor/nikic/fast-route/test/Dispatcher/MarkBasedTest.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace FastRoute\Dispatcher;
+
+class MarkBasedTest extends DispatcherTest
+{
+    public function setUp()
+    {
+        preg_match('/(*MARK:A)a/', 'a', $matches);
+        if (!isset($matches['MARK'])) {
+            $this->markTestSkipped('PHP 5.6 required for MARK support');
+        }
+    }
+
+    protected function getDispatcherClass()
+    {
+        return 'FastRoute\\Dispatcher\\MarkBased';
+    }
+
+    protected function getDataGeneratorClass()
+    {
+        return 'FastRoute\\DataGenerator\\MarkBased';
+    }
+}

+ 44 - 0
api/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace FastRoute;
+
+use PHPUnit\Framework\TestCase;
+
+class HackTypecheckerTest extends TestCase
+{
+    const SERVER_ALREADY_RUNNING_CODE = 77;
+
+    public function testTypechecks($recurse = true)
+    {
+        if (!defined('HHVM_VERSION')) {
+            $this->markTestSkipped('HHVM only');
+        }
+        if (!version_compare(HHVM_VERSION, '3.9.0', '>=')) {
+          $this->markTestSkipped('classname<T> requires HHVM 3.9+');
+        }
+
+        // The typechecker recurses the whole tree, so it makes sure
+        // that everything in fixtures/ is valid when this runs.
+
+        $output = [];
+        $exit_code = null;
+        exec(
+            'hh_server --check ' . escapeshellarg(__DIR__ . '/../../') . ' 2>&1',
+            $output,
+            $exit_code
+        );
+        if ($exit_code === self::SERVER_ALREADY_RUNNING_CODE) {
+            $this->assertTrue(
+              $recurse,
+              'Typechecker still running after running hh_client stop'
+            );
+            // Server already running - 3.10 => 3.11 regression:
+            // https://github.com/facebook/hhvm/issues/6646
+            exec('hh_client stop 2>/dev/null');
+            $this->testTypechecks(/* recurse = */ false);
+            return;
+
+        }
+        $this->assertSame(0, $exit_code, implode("\n", $output));
+    }
+}

+ 29 - 0
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php

@@ -0,0 +1,29 @@
+<?hh
+
+namespace FastRoute\TestFixtures;
+
+function all_options_simple(): \FastRoute\Dispatcher {
+    return \FastRoute\simpleDispatcher(
+      $collector ==> {},
+      shape(
+        'routeParser' => \FastRoute\RouteParser\Std::class,
+        'dataGenerator' => \FastRoute\DataGenerator\GroupCountBased::class,
+        'dispatcher' => \FastRoute\Dispatcher\GroupCountBased::class,
+        'routeCollector' => \FastRoute\RouteCollector::class,
+      ),
+    );
+}
+
+function all_options_cached(): \FastRoute\Dispatcher {
+    return \FastRoute\cachedDispatcher(
+      $collector ==> {},
+      shape(
+        'routeParser' => \FastRoute\RouteParser\Std::class,
+        'dataGenerator' => \FastRoute\DataGenerator\GroupCountBased::class,
+        'dispatcher' => \FastRoute\Dispatcher\GroupCountBased::class,
+        'routeCollector' => \FastRoute\RouteCollector::class,
+        'cacheFile' => '/dev/null',
+        'cacheDisabled' => false,
+      ),
+    );
+}

+ 11 - 0
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php

@@ -0,0 +1,11 @@
+<?hh
+
+namespace FastRoute\TestFixtures;
+
+function empty_options_simple(): \FastRoute\Dispatcher {
+    return \FastRoute\simpleDispatcher($collector ==> {}, shape());
+}
+
+function empty_options_cached(): \FastRoute\Dispatcher {
+    return \FastRoute\cachedDispatcher($collector ==> {}, shape());
+}

+ 11 - 0
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php

@@ -0,0 +1,11 @@
+<?hh
+
+namespace FastRoute\TestFixtures;
+
+function no_options_simple(): \FastRoute\Dispatcher {
+    return \FastRoute\simpleDispatcher($collector ==> {});
+}
+
+function no_options_cached(): \FastRoute\Dispatcher {
+    return \FastRoute\cachedDispatcher($collector ==> {});
+}

+ 108 - 0
api/vendor/nikic/fast-route/test/RouteCollectorTest.php

@@ -0,0 +1,108 @@
+<?php
+
+namespace FastRoute;
+
+use PHPUnit\Framework\TestCase;
+
+class RouteCollectorTest extends TestCase
+{
+    public function testShortcuts()
+    {
+        $r = new DummyRouteCollector();
+
+        $r->delete('/delete', 'delete');
+        $r->get('/get', 'get');
+        $r->head('/head', 'head');
+        $r->patch('/patch', 'patch');
+        $r->post('/post', 'post');
+        $r->put('/put', 'put');
+
+        $expected = [
+            ['DELETE', '/delete', 'delete'],
+            ['GET', '/get', 'get'],
+            ['HEAD', '/head', 'head'],
+            ['PATCH', '/patch', 'patch'],
+            ['POST', '/post', 'post'],
+            ['PUT', '/put', 'put'],
+        ];
+
+        $this->assertSame($expected, $r->routes);
+    }
+
+    public function testGroups()
+    {
+        $r = new DummyRouteCollector();
+
+        $r->delete('/delete', 'delete');
+        $r->get('/get', 'get');
+        $r->head('/head', 'head');
+        $r->patch('/patch', 'patch');
+        $r->post('/post', 'post');
+        $r->put('/put', 'put');
+
+        $r->addGroup('/group-one', function (DummyRouteCollector $r) {
+            $r->delete('/delete', 'delete');
+            $r->get('/get', 'get');
+            $r->head('/head', 'head');
+            $r->patch('/patch', 'patch');
+            $r->post('/post', 'post');
+            $r->put('/put', 'put');
+
+            $r->addGroup('/group-two', function (DummyRouteCollector $r) {
+                $r->delete('/delete', 'delete');
+                $r->get('/get', 'get');
+                $r->head('/head', 'head');
+                $r->patch('/patch', 'patch');
+                $r->post('/post', 'post');
+                $r->put('/put', 'put');
+            });
+        });
+
+        $r->addGroup('/admin', function (DummyRouteCollector $r) {
+            $r->get('-some-info', 'admin-some-info');
+        });
+        $r->addGroup('/admin-', function (DummyRouteCollector $r) {
+            $r->get('more-info', 'admin-more-info');
+        });
+
+        $expected = [
+            ['DELETE', '/delete', 'delete'],
+            ['GET', '/get', 'get'],
+            ['HEAD', '/head', 'head'],
+            ['PATCH', '/patch', 'patch'],
+            ['POST', '/post', 'post'],
+            ['PUT', '/put', 'put'],
+            ['DELETE', '/group-one/delete', 'delete'],
+            ['GET', '/group-one/get', 'get'],
+            ['HEAD', '/group-one/head', 'head'],
+            ['PATCH', '/group-one/patch', 'patch'],
+            ['POST', '/group-one/post', 'post'],
+            ['PUT', '/group-one/put', 'put'],
+            ['DELETE', '/group-one/group-two/delete', 'delete'],
+            ['GET', '/group-one/group-two/get', 'get'],
+            ['HEAD', '/group-one/group-two/head', 'head'],
+            ['PATCH', '/group-one/group-two/patch', 'patch'],
+            ['POST', '/group-one/group-two/post', 'post'],
+            ['PUT', '/group-one/group-two/put', 'put'],
+            ['GET', '/admin-some-info', 'admin-some-info'],
+            ['GET', '/admin-more-info', 'admin-more-info'],
+        ];
+
+        $this->assertSame($expected, $r->routes);
+    }
+}
+
+class DummyRouteCollector extends RouteCollector
+{
+    public $routes = [];
+
+    public function __construct()
+    {
+    }
+
+    public function addRoute($method, $route, $handler)
+    {
+        $route = $this->currentGroupPrefix . $route;
+        $this->routes[] = [$method, $route, $handler];
+    }
+}

+ 154 - 0
api/vendor/nikic/fast-route/test/RouteParser/StdTest.php

@@ -0,0 +1,154 @@
+<?php
+
+namespace FastRoute\RouteParser;
+
+use PHPUnit\Framework\TestCase;
+
+class StdTest extends TestCase
+{
+    /** @dataProvider provideTestParse */
+    public function testParse($routeString, $expectedRouteDatas)
+    {
+        $parser = new Std();
+        $routeDatas = $parser->parse($routeString);
+        $this->assertSame($expectedRouteDatas, $routeDatas);
+    }
+
+    /** @dataProvider provideTestParseError */
+    public function testParseError($routeString, $expectedExceptionMessage)
+    {
+        $parser = new Std();
+        $this->setExpectedException('FastRoute\\BadRouteException', $expectedExceptionMessage);
+        $parser->parse($routeString);
+    }
+
+    public function provideTestParse()
+    {
+        return [
+            [
+                '/test',
+                [
+                    ['/test'],
+                ]
+            ],
+            [
+                '/test/{param}',
+                [
+                    ['/test/', ['param', '[^/]+']],
+                ]
+            ],
+            [
+                '/te{ param }st',
+                [
+                    ['/te', ['param', '[^/]+'], 'st']
+                ]
+            ],
+            [
+                '/test/{param1}/test2/{param2}',
+                [
+                    ['/test/', ['param1', '[^/]+'], '/test2/', ['param2', '[^/]+']]
+                ]
+            ],
+            [
+                '/test/{param:\d+}',
+                [
+                    ['/test/', ['param', '\d+']]
+                ]
+            ],
+            [
+                '/test/{ param : \d{1,9} }',
+                [
+                    ['/test/', ['param', '\d{1,9}']]
+                ]
+            ],
+            [
+                '/test[opt]',
+                [
+                    ['/test'],
+                    ['/testopt'],
+                ]
+            ],
+            [
+                '/test[/{param}]',
+                [
+                    ['/test'],
+                    ['/test/', ['param', '[^/]+']],
+                ]
+            ],
+            [
+                '/{param}[opt]',
+                [
+                    ['/', ['param', '[^/]+']],
+                    ['/', ['param', '[^/]+'], 'opt']
+                ]
+            ],
+            [
+                '/test[/{name}[/{id:[0-9]+}]]',
+                [
+                    ['/test'],
+                    ['/test/', ['name', '[^/]+']],
+                    ['/test/', ['name', '[^/]+'], '/', ['id', '[0-9]+']],
+                ]
+            ],
+            [
+                '',
+                [
+                    [''],
+                ]
+            ],
+            [
+                '[test]',
+                [
+                    [''],
+                    ['test'],
+                ]
+            ],
+            [
+                '/{foo-bar}',
+                [
+                    ['/', ['foo-bar', '[^/]+']]
+                ]
+            ],
+            [
+                '/{_foo:.*}',
+                [
+                    ['/', ['_foo', '.*']]
+                ]
+            ],
+        ];
+    }
+
+    public function provideTestParseError()
+    {
+        return [
+            [
+                '/test[opt',
+                "Number of opening '[' and closing ']' does not match"
+            ],
+            [
+                '/test[opt[opt2]',
+                "Number of opening '[' and closing ']' does not match"
+            ],
+            [
+                '/testopt]',
+                "Number of opening '[' and closing ']' does not match"
+            ],
+            [
+                '/test[]',
+                'Empty optional part'
+            ],
+            [
+                '/test[[opt]]',
+                'Empty optional part'
+            ],
+            [
+                '[[test]]',
+                'Empty optional part'
+            ],
+            [
+                '/test[/opt]/required',
+                'Optional segments can only occur at the end of a route'
+            ],
+        ];
+    }
+}

+ 11 - 0
api/vendor/nikic/fast-route/test/bootstrap.php

@@ -0,0 +1,11 @@
+<?php
+
+require_once __DIR__ . '/../src/functions.php';
+
+spl_autoload_register(function ($class) {
+    if (strpos($class, 'FastRoute\\') === 0) {
+        $dir = strcasecmp(substr($class, -4), 'Test') ? 'src/' : 'test/';
+        $name = substr($class, strlen('FastRoute'));
+        require __DIR__ . '/../' . $dir . strtr($name, '\\', DIRECTORY_SEPARATOR) . '.php';
+    }
+});

+ 2 - 0
api/vendor/psr/http-factory/.gitignore

@@ -0,0 +1,2 @@
+composer.lock
+vendor/

+ 7 - 0
api/vendor/psr/http-factory/.pullapprove.yml

@@ -0,0 +1,7 @@
+extends: default
+reviewers:
+    -
+        name: contributors
+        required: 1
+        teams:
+            - http-factory-contributors

+ 21 - 0
api/vendor/psr/http-factory/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 PHP-FIG
+
+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.

+ 10 - 0
api/vendor/psr/http-factory/README.md

@@ -0,0 +1,10 @@
+HTTP Factories
+==============
+
+This repository holds all interfaces related to [PSR-17 (HTTP Message Factories)][psr-17]. 
+Please refer to the specification for a description.
+
+You can find implementations of the specification by looking for packages providing the 
+[psr/http-factory-implementation](https://packagist.org/providers/psr/http-factory-implementation) virtual package.
+
+[psr-17]: https://www.php-fig.org/psr/psr-17/

+ 35 - 0
api/vendor/psr/http-factory/composer.json

@@ -0,0 +1,35 @@
+{
+    "name": "psr/http-factory",
+    "description": "Common interfaces for PSR-7 HTTP message factories",
+    "keywords": [
+        "psr",
+        "psr-7",
+        "psr-17",
+        "http",
+        "factory",
+        "message",
+        "request",
+        "response"
+    ],
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "PHP-FIG",
+            "homepage": "http://www.php-fig.org/"
+        }
+    ],
+    "require": {
+        "php": ">=7.0.0",
+        "psr/http-message": "^1.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Psr\\Http\\Message\\": "src/"
+        }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.0.x-dev"
+        }
+    }
+}

+ 18 - 0
api/vendor/psr/http-factory/src/RequestFactoryInterface.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Psr\Http\Message;
+
+interface RequestFactoryInterface
+{
+    /**
+     * Create a new request.
+     *
+     * @param string $method The HTTP method associated with the request.
+     * @param UriInterface|string $uri The URI associated with the request. If
+     *     the value is a string, the factory MUST create a UriInterface
+     *     instance based on it.
+     *
+     * @return RequestInterface
+     */
+    public function createRequest(string $method, $uri): RequestInterface;
+}

+ 18 - 0
api/vendor/psr/http-factory/src/ResponseFactoryInterface.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Psr\Http\Message;
+
+interface ResponseFactoryInterface
+{
+    /**
+     * Create a new response.
+     *
+     * @param int $code HTTP status code; defaults to 200
+     * @param string $reasonPhrase Reason phrase to associate with status code
+     *     in generated response; if none is provided implementations MAY use
+     *     the defaults as suggested in the HTTP specification.
+     *
+     * @return ResponseInterface
+     */
+    public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface;
+}

+ 24 - 0
api/vendor/psr/http-factory/src/ServerRequestFactoryInterface.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Psr\Http\Message;
+
+interface ServerRequestFactoryInterface
+{
+    /**
+     * Create a new server request.
+     *
+     * Note that server-params are taken precisely as given - no parsing/processing
+     * of the given values is performed, and, in particular, no attempt is made to
+     * determine the HTTP method or URI, which must be provided explicitly.
+     *
+     * @param string $method The HTTP method associated with the request.
+     * @param UriInterface|string $uri The URI associated with the request. If
+     *     the value is a string, the factory MUST create a UriInterface
+     *     instance based on it.
+     * @param array $serverParams Array of SAPI parameters with which to seed
+     *     the generated request instance.
+     *
+     * @return ServerRequestInterface
+     */
+    public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface;
+}

+ 45 - 0
api/vendor/psr/http-factory/src/StreamFactoryInterface.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace Psr\Http\Message;
+
+interface StreamFactoryInterface
+{
+    /**
+     * Create a new stream from a string.
+     *
+     * The stream SHOULD be created with a temporary resource.
+     *
+     * @param string $content String content with which to populate the stream.
+     *
+     * @return StreamInterface
+     */
+    public function createStream(string $content = ''): StreamInterface;
+
+    /**
+     * Create a stream from an existing file.
+     *
+     * The file MUST be opened using the given mode, which may be any mode
+     * supported by the `fopen` function.
+     *
+     * The `$filename` MAY be any string supported by `fopen()`.
+     *
+     * @param string $filename Filename or stream URI to use as basis of stream.
+     * @param string $mode Mode with which to open the underlying filename/stream.
+     *
+     * @return StreamInterface
+     * @throws \RuntimeException If the file cannot be opened.
+     * @throws \InvalidArgumentException If the mode is invalid.
+     */
+    public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface;
+
+    /**
+     * Create a new stream from an existing resource.
+     *
+     * The stream MUST be readable and may be writable.
+     *
+     * @param resource $resource PHP resource to use as basis of stream.
+     *
+     * @return StreamInterface
+     */
+    public function createStreamFromResource($resource): StreamInterface;
+}

+ 34 - 0
api/vendor/psr/http-factory/src/UploadedFileFactoryInterface.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace Psr\Http\Message;
+
+interface UploadedFileFactoryInterface
+{
+    /**
+     * Create a new uploaded file.
+     *
+     * If a size is not provided it will be determined by checking the size of
+     * the file.
+     *
+     * @see http://php.net/manual/features.file-upload.post-method.php
+     * @see http://php.net/manual/features.file-upload.errors.php
+     *
+     * @param StreamInterface $stream Underlying stream representing the
+     *     uploaded file content.
+     * @param int $size in bytes
+     * @param int $error PHP file upload error
+     * @param string $clientFilename Filename as provided by the client, if any.
+     * @param string $clientMediaType Media type as provided by the client, if any.
+     *
+     * @return UploadedFileInterface
+     *
+     * @throws \InvalidArgumentException If the file resource is not readable.
+     */
+    public function createUploadedFile(
+        StreamInterface $stream,
+        int $size = null,
+        int $error = \UPLOAD_ERR_OK,
+        string $clientFilename = null,
+        string $clientMediaType = null
+    ): UploadedFileInterface;
+}

+ 17 - 0
api/vendor/psr/http-factory/src/UriFactoryInterface.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace Psr\Http\Message;
+
+interface UriFactoryInterface
+{
+    /**
+     * Create a new URI.
+     *
+     * @param string $uri
+     *
+     * @return UriInterface
+     *
+     * @throws \InvalidArgumentException If the given URI cannot be parsed.
+     */
+    public function createUri(string $uri = ''): UriInterface;
+}

+ 21 - 0
api/vendor/psr/http-server-handler/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 PHP Framework Interoperability Group
+
+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.

+ 6 - 0
api/vendor/psr/http-server-handler/README.md

@@ -0,0 +1,6 @@
+HTTP Server Handler
+===================
+
+Provides the `RequestHandlerInterface` of [PSR-15][psr-15].
+
+[psr-15]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-15-request-handlers.md

+ 36 - 0
api/vendor/psr/http-server-handler/composer.json

@@ -0,0 +1,36 @@
+{
+    "name": "psr/http-server-handler",
+    "description": "Common interface for HTTP server-side request handler",
+    "keywords": [
+        "psr",
+        "psr-7",
+        "psr-15",
+        "http-interop",
+        "http",
+        "server",
+        "handler",
+        "request",
+        "response"
+    ],
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "PHP-FIG",
+            "homepage": "http://www.php-fig.org/"
+        }
+    ],
+    "require": {
+        "php": ">=7.0",
+        "psr/http-message": "^1.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Psr\\Http\\Server\\": "src/"
+        }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.0.x-dev"
+        }
+    }
+}

+ 22 - 0
api/vendor/psr/http-server-handler/src/RequestHandlerInterface.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace Psr\Http\Server;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Handles a server request and produces a response.
+ *
+ * An HTTP request handler process an HTTP request in order to produce an
+ * HTTP response.
+ */
+interface RequestHandlerInterface
+{
+    /**
+     * Handles a request and produces a response.
+     *
+     * May call other collaborating code to generate the response.
+     */
+    public function handle(ServerRequestInterface $request): ResponseInterface;
+}

+ 21 - 0
api/vendor/psr/http-server-middleware/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 PHP Framework Interoperability Group
+
+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.

+ 6 - 0
api/vendor/psr/http-server-middleware/README.md

@@ -0,0 +1,6 @@
+HTTP Server Middleware
+======================
+
+Provides the `MiddlewareInterface` of [PSR-15][psr-15].
+
+[psr-15]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-15-request-handlers.md

+ 36 - 0
api/vendor/psr/http-server-middleware/composer.json

@@ -0,0 +1,36 @@
+{
+    "name": "psr/http-server-middleware",
+    "description": "Common interface for HTTP server-side middleware",
+    "keywords": [
+        "psr",
+        "psr-7",
+        "psr-15",
+        "http-interop",
+        "http",
+        "middleware",
+        "request",
+        "response"
+    ],
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "PHP-FIG",
+            "homepage": "http://www.php-fig.org/"
+        }
+    ],
+    "require": {
+        "php": ">=7.0",
+        "psr/http-message": "^1.0",
+        "psr/http-server-handler": "^1.0"
+    },
+    "autoload": {
+        "psr-4": {
+            "Psr\\Http\\Server\\": "src/"
+        }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "1.0.x-dev"
+        }
+    }
+}

+ 25 - 0
api/vendor/psr/http-server-middleware/src/MiddlewareInterface.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace Psr\Http\Server;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Participant in processing a server request and response.
+ *
+ * An HTTP middleware component participates in processing an HTTP message:
+ * by acting on the request, generating the response, or forwarding the
+ * request to a subsequent middleware and possibly acting on its response.
+ */
+interface MiddlewareInterface
+{
+    /**
+     * Process an incoming server request.
+     *
+     * Processes an incoming server request in order to produce a response.
+     * If unable to produce the response itself, it may delegate to the provided
+     * request handler to do so.
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;
+}

+ 66 - 0
api/vendor/slim/slim/CHANGELOG.md

@@ -0,0 +1,66 @@
+# Changelog
+
+## 4.0.0 - 2019-08-01
+
+### Added
+- [#2765](https://github.com/slimphp/Slim/pull/2765) Simplify queueing of internal middleware `ErrorMiddleware` and `RoutingMiddleware`
+- [#2759](https://github.com/slimphp/Slim/pull/2759) Add `RouteContext` to enable access to the current route, route parser, and routing results
+- [#2751](https://github.com/slimphp/Slim/pull/2751) Add ability to set default error renderer content type on the `ErrorHandler` component
+- [#2737](https://github.com/slimphp/Slim/pull/2737) BC Change via `ErrorRendererInterface` changed to use invokable pattern to leverage `CallableResolver`
+- [#2734](https://github.com/slimphp/Slim/pull/2734) Add support for content-type base error renderers and setting default error renderer
+- [#2716](https://github.com/slimphp/Slim/pull/2716) Add automatic Slim-Http Request/Response decoration when library is in scope
+- [#2654](https://github.com/slimphp/Slim/pull/2654) `RouteParser::pathFor()` and `RouteParser::relativePathFor()` are deprecated. Use `RouteParser::urlFor()` and `RouteParser::relativeUrlFor()`
+- [#2642](https://github.com/slimphp/Slim/pull/2642) Add `AppFactory` to enable PSR-7 implementation and ServerRequest creator auto-detection
+- [#2641](https://github.com/slimphp/Slim/pull/2641) Add `RouteCollectorProxyInterface` which extracts all the route mapping functionality from app into its own interface
+- [#2640](https://github.com/slimphp/Slim/pull/2640) Add `RouteParserInterface` and decouple FastRoute route parser entirely from core. The methods `relativePathFor()`, `urlFor()` and `fullUrlFor()` are now located on this interface
+- [#2639](https://github.com/slimphp/Slim/pull/2639) Add `DispatcherInterface` and decouple FastRoute dispatcher entirely from core. This enables us to swap out our router implementation for any other router
+- [#2638](https://github.com/slimphp/Slim/pull/2638) Add `RouteCollector::fullUrlFor()` to give the ability to generate fully qualified URLs
+- [#2634](https://github.com/slimphp/Slim/pull/2634) Added ability to set invocation strategy on a per-route basis
+- [#2555](https://github.com/slimphp/Slim/pull/2555) Added PSR-15 Middleware Support
+- [#2529](https://github.com/slimphp/Slim/pull/2529) Slim no longer ships with a PSR-7 implementation. You need to provide a PSR-7 ServerRequest and a PSR-17 ResponseFactory to run Slim
+- [#2507](https://github.com/slimphp/Slim/pull/2507) Method names are now case-sensitive in Router::map(), and so, by extension, in App::map() 
+- [#2497](https://github.com/slimphp/Slim/pull/2497) PSR-15 RequestHandlers can now be used as route callables
+- [#2496](https://github.com/slimphp/Slim/pull/2496) A Slim App can now be used as PSR-15 Request Handler
+- [#2405](https://github.com/slimphp/Slim/pull/2405) RoutingMiddleware now adds the `routingResults` request attribute to hold the results of routing
+- [#2404](https://github.com/slimphp/Slim/pull/2404) Slim 4 requires PHP 7.1 or higher
+- [#2425](https://github.com/slimphp/Slim/pull/2425) Added $app->redirect()
+- [#2398](https://github.com/slimphp/Slim/pull/2398) Added Middleware\ErrorMiddleware
+- [#2329](https://github.com/slimphp/Slim/pull/2329) Added Middleware\MethodOverrideMiddleware
+- [#2288](https://github.com/slimphp/Slim/pull/2288) Separate routing from dispatching
+- [#2254](https://github.com/slimphp/Slim/pull/2254) Added Middleware\ContentLengthMiddleware
+- [#2166](https://github.com/slimphp/Slim/pull/2166) Added Middleware\OutputBufferingMiddleware
+
+### Deprecated
+
+- [#2641](https://github.com/slimphp/Slim/pull/2641) Deprecate `RouteCollector::pushGroup()`,`RouteCollector::popGroup()` which gets replaced by `RouteCollector::group()`
+- [#2638](https://github.com/slimphp/Slim/pull/2638) Deprecate `RouteCollector::pathFor()` which gets replaced by `RouteCollector::urlFor()` preserving the orignal functionality
+- [#2555](https://github.com/slimphp/Slim/pull/2555) Double-Pass Middleware Support has been deprecated
+
+### Removed
+
+- [#2612](https://github.com/slimphp/Slim/pull/2612) Remove Routable, refactored RouteGroup and Route interface
+- [#2589](https://github.com/slimphp/Slim/pull/2589) Remove App::$settings altogether
+- [#2587](https://github.com/slimphp/Slim/pull/2587) Remove Pimple as a dev-dependency
+- [#2398](https://github.com/slimphp/Slim/pull/2398) Slim no longer has error handling built into App. Add ErrorMiddleware() as the outermost middleware
+- [#2375](https://github.com/slimphp/Slim/pull/2375) Slim no longer sets the `default_mimetype` to an empty string, so you need to set it yourself in php.ini or your app using `ini_set('default_mimetype', '');`
+- [#2288](https://github.com/slimphp/Slim/pull/2288) `determineRouteBeforeAppMiddleware` setting is removed. Add RoutingMiddleware() where you need it now
+- [#2254](https://github.com/slimphp/Slim/pull/2254) `addContentLengthHeader` setting is removed
+- [#2221](https://github.com/slimphp/Slim/pull/2221) `Slim\Http` has been removed and Slim now depends on the separate Slim-Http component
+- [#2166](https://github.com/slimphp/Slim/pull/2166) `outputBuffering` setting is removed
+- [#2078](https://github.com/slimphp/Slim/pull/2078) Remove App::subRequest()
+- [#2098](https://github.com/slimphp/Slim/pull/2098) Remove CallableResolverTrait
+- [#2102](https://github.com/slimphp/Slim/pull/2102) Remove container from router
+- [#2124](https://github.com/slimphp/Slim/pull/2124) Remove Slim\Exception\SlimException
+- [#2174](https://github.com/slimphp/Slim/pull/2174) Switch from Container-Interop to PSR-11
+- [#2290](https://github.com/slimphp/Slim/pull/2290) Removed container. Set your own using `App::setContainer()`
+- [#2560](https://github.com/slimphp/Slim/pull/2560) Remove binding of $this to group()
+
+### Changed
+
+- [#2104](https://github.com/slimphp/Slim/pull/2104) Settings are the top level array elements in `App::__construct()`
+
+### Fixed
+- [#2588](https://github.com/slimphp/Slim/pull/2588) Fix file/directory permission handling of `Router::setCacheFile()`
+- [#2067](https://github.com/slimphp/Slim/pull/2067) Unit tests now pass on Windows systems
+- [#2405](https://github.com/slimphp/Slim/pull/2405) We rawurldecode() the path before passing to FastRoute, so UTF-8 characters in paths should now work
+

+ 19 - 0
api/vendor/slim/slim/LICENSE.md

@@ -0,0 +1,19 @@
+Copyright (c) 2011-2017 Josh Lockhart
+
+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/slim/slim/MAINTAINERS.md

@@ -0,0 +1,17 @@
+# Maintainers
+
+There aren't many rules for maintainers of Slim to remember; what we have is listed here.
+
+## We don't merge our own PRs
+
+Our code is better if more than one set of eyes looks at it. Therefore we do not merge our own pull requests unless there is an exceptional circumstance. This helps to spot errors in the patch and also enables us to share information about the project around the maintainer team.
+
+## PRs tagged `WIP` are not ready to be merged
+
+Sometimes it's helpful to collaborate on a patch before it's ready to be merged. We use the text `WIP` (for _Work in Progress_) in the title to mark these PRs. 
+
+If a PR has `WIP` in its title, then it is not to be merged. The person who raised the PR will remove the `WIP` text when they are ready for a full review and merge.
+
+## Assign a merged PR to a milestone
+
+By ensuring that all merged PRs are assigned to a milestone, we can easily find which PRs were in which release.

+ 191 - 0
api/vendor/slim/slim/Slim/App.php

@@ -0,0 +1,191 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim;
+
+use Psr\Container\ContainerInterface;
+use Psr\Http\Message\ResponseFactoryInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use Slim\Factory\ServerRequestCreatorFactory;
+use Slim\Interfaces\CallableResolverInterface;
+use Slim\Interfaces\RouteCollectorInterface;
+use Slim\Interfaces\RouteResolverInterface;
+use Slim\Middleware\ErrorMiddleware;
+use Slim\Middleware\RoutingMiddleware;
+use Slim\Routing\RouteCollectorProxy;
+use Slim\Routing\RouteResolver;
+use Slim\Routing\RouteRunner;
+
+class App extends RouteCollectorProxy implements RequestHandlerInterface
+{
+    /**
+     * Current version
+     *
+     * @var string
+     */
+    public const VERSION = '4.0.0';
+
+    /**
+     * @var MiddlewareDispatcher
+     */
+    protected $middlewareDispatcher;
+
+    /**
+     * @var RouteResolverInterface
+     */
+    protected $routeResolver;
+
+    /**
+     * @param ResponseFactoryInterface       $responseFactory
+     * @param ContainerInterface|null        $container
+     * @param CallableResolverInterface|null $callableResolver
+     * @param RouteCollectorInterface|null   $routeCollector
+     * @param RouteResolverInterface|null    $routeResolver
+     */
+    public function __construct(
+        ResponseFactoryInterface $responseFactory,
+        ?ContainerInterface $container = null,
+        ?CallableResolverInterface $callableResolver = null,
+        ?RouteCollectorInterface $routeCollector = null,
+        ?RouteResolverInterface $routeResolver = null
+    ) {
+        parent::__construct(
+            $responseFactory,
+            $callableResolver ?? new CallableResolver($container),
+            $container,
+            $routeCollector
+        );
+
+        $this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
+        $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser());
+
+        $this->middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $container);
+    }
+
+    /**
+     * @return RouteResolverInterface
+     */
+    public function getRouteResolver(): RouteResolverInterface
+    {
+        return $this->routeResolver;
+    }
+
+    /**
+     * @param MiddlewareInterface|string|callable $middleware
+     * @return self
+     */
+    public function add($middleware): self
+    {
+        $this->middlewareDispatcher->add($middleware);
+        return $this;
+    }
+
+    /**
+     * @param MiddlewareInterface $middleware
+     * @return self
+     */
+    public function addMiddleware(MiddlewareInterface $middleware): self
+    {
+        $this->middlewareDispatcher->addMiddleware($middleware);
+        return $this;
+    }
+
+    /**
+     * Add the slim built-in routing middleware to the app middleware stack
+     *
+     * @return RoutingMiddleware
+     */
+    public function addRoutingMiddleware(): RoutingMiddleware
+    {
+        $routingMiddleware = new RoutingMiddleware(
+            $this->getRouteResolver(),
+            $this->getRouteCollector()->getRouteParser()
+        );
+        $this->add($routingMiddleware);
+        return $routingMiddleware;
+    }
+
+    /**
+     * Add the slim built-in error middleware to the app middleware stack
+     *
+     * @param bool $displayErrorDetails
+     * @param bool $logErrors
+     * @param bool $logErrorDetails
+     *
+     * @return ErrorMiddleware
+     */
+    public function addErrorMiddleware(
+        bool $displayErrorDetails,
+        bool $logErrors,
+        bool $logErrorDetails
+    ): ErrorMiddleware {
+        $errorMiddleware = new ErrorMiddleware(
+            $this->getCallableResolver(),
+            $this->getResponseFactory(),
+            $displayErrorDetails,
+            $logErrors,
+            $logErrorDetails
+        );
+        $this->add($errorMiddleware);
+        return $errorMiddleware;
+    }
+
+    /**
+     * Run application
+     *
+     * This method traverses the application middleware stack and then sends the
+     * resultant Response object to the HTTP client.
+     *
+     * @param ServerRequestInterface|null $request
+     * @return void
+     */
+    public function run(?ServerRequestInterface $request = null): void
+    {
+        if (!$request) {
+            $serverRequestCreator = ServerRequestCreatorFactory::create();
+            $request = $serverRequestCreator->createServerRequestFromGlobals();
+        }
+
+        $response = $this->handle($request);
+        $responseEmitter = new ResponseEmitter();
+        $responseEmitter->emit($response);
+    }
+
+    /**
+     * Handle a request
+     *
+     * This method traverses the application middleware stack and then returns the
+     * resultant Response object.
+     *
+     * @param ServerRequestInterface $request
+     * @return ResponseInterface
+     */
+    public function handle(ServerRequestInterface $request): ResponseInterface
+    {
+        $response = $this->middlewareDispatcher->handle($request);
+
+        /**
+         * This is to be in compliance with RFC 2616, Section 9.
+         * If the incoming request method is HEAD, we need to ensure that the response body
+         * is empty as the request may fall back on a GET route handler due to FastRoute's
+         * routing logic which could potentially append content to the response body
+         * https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
+         */
+        $method = strtoupper($request->getMethod());
+        if ($method === 'HEAD') {
+            $emptyBody = $this->responseFactory->createResponse()->getBody();
+            return $response->withBody($emptyBody);
+        }
+
+        return $response;
+    }
+}

+ 100 - 0
api/vendor/slim/slim/Slim/CallableResolver.php

@@ -0,0 +1,100 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim;
+
+use Closure;
+use Psr\Container\ContainerInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use RuntimeException;
+use Slim\Interfaces\CallableResolverInterface;
+
+/**
+ * This class resolves a string of the format 'class:method' into a closure
+ * that can be dispatched.
+ */
+final class CallableResolver implements CallableResolverInterface
+{
+    /**
+     * @var ContainerInterface|null
+     */
+    private $container;
+
+    /**
+     * @param ContainerInterface|null $container
+     */
+    public function __construct(?ContainerInterface $container = null)
+    {
+        $this->container = $container;
+    }
+
+    /**
+     * Resolve toResolve into a callable that the router can dispatch.
+     *
+     * If toResolve is of the format 'class:method', then try to extract 'class'
+     * from the container otherwise instantiate it and then dispatch 'method'.
+     *
+     * @param mixed $toResolve
+     * @return callable
+     *
+     * @throws RuntimeException if the callable does not exist
+     * @throws RuntimeException if the callable is not resolvable
+     */
+    public function resolve($toResolve): callable
+    {
+        $resolved = $toResolve;
+
+        if (!is_callable($toResolve) && is_string($toResolve)) {
+            $class = $toResolve;
+            $instance = null;
+            $method = null;
+
+            // check for slim callable as "class:method"
+            $callablePattern = '!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!';
+            if (preg_match($callablePattern, $toResolve, $matches)) {
+                $class = $matches[1];
+                $method = $matches[2];
+            }
+
+            if ($this->container instanceof ContainerInterface && $this->container->has($class)) {
+                $instance = $this->container->get($class);
+            } else {
+                if (!class_exists($class)) {
+                    throw new RuntimeException(sprintf('Callable %s does not exist', $class));
+                }
+                $instance = new $class($this->container);
+            }
+
+            // For a class that implements RequestHandlerInterface, we will call handle()
+            // if no method has been specified explicitly
+            if ($instance instanceof RequestHandlerInterface && $method === null) {
+                $method = 'handle';
+            }
+
+            $resolved = [$instance, $method ?? '__invoke'];
+        }
+
+        if ($resolved instanceof RequestHandlerInterface) {
+            $resolved = [$resolved, 'handle'];
+        }
+
+        if (!is_callable($resolved)) {
+            throw new RuntimeException(sprintf(
+                '%s is not resolvable',
+                is_array($toResolve) || is_object($toResolve) ? json_encode($toResolve) : $toResolve
+            ));
+        }
+
+        if ($this->container instanceof ContainerInterface && $resolved instanceof Closure) {
+            $resolved = $resolved->bindTo($this->container);
+        }
+
+        return $resolved;
+    }
+}

+ 46 - 0
api/vendor/slim/slim/Slim/DeferredCallable.php

@@ -0,0 +1,46 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim;
+
+use Slim\Interfaces\CallableResolverInterface;
+
+class DeferredCallable
+{
+    /**
+     * @var callable|string
+     */
+    protected $callable;
+
+    /**
+     * @var CallableResolverInterface|null
+     */
+    protected $callableResolver;
+
+    /**
+     * @param callable|string                $callable
+     * @param CallableResolverInterface|null $resolver
+     */
+    public function __construct($callable, ?CallableResolverInterface $resolver = null)
+    {
+        $this->callable = $callable;
+        $this->callableResolver = $resolver;
+    }
+
+    public function __invoke(...$args)
+    {
+        /** @var callable $callable */
+        $callable = $this->callable;
+        if ($this->callableResolver) {
+            $callable = $this->callableResolver->resolve($callable);
+        }
+
+        return $callable(...$args);
+    }
+}

+ 22 - 0
api/vendor/slim/slim/Slim/Error/AbstractErrorRenderer.php

@@ -0,0 +1,22 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Error;
+
+use Slim\Interfaces\ErrorRendererInterface;
+
+/**
+ * Abstract Slim application error renderer
+ *
+ * It outputs the error message and diagnostic information in one of the following formats:
+ * JSON, XML, Plain Text or HTML
+ */
+abstract class AbstractErrorRenderer implements ErrorRendererInterface
+{
+}

+ 106 - 0
api/vendor/slim/slim/Slim/Error/Renderers/HtmlErrorRenderer.php

@@ -0,0 +1,106 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Error\Renderers;
+
+use Slim\Error\AbstractErrorRenderer;
+use Throwable;
+
+/**
+ * Default Slim application HTML Error Renderer
+ */
+class HtmlErrorRenderer extends AbstractErrorRenderer
+{
+    /**
+     * @param Throwable $exception
+     * @param bool      $displayErrorDetails
+     * @return string
+     */
+    public function __invoke(Throwable $exception, bool $displayErrorDetails): string
+    {
+        $title = 'Slim Application Error';
+
+        if ($displayErrorDetails) {
+            $html = '<p>The application could not run because of the following error:</p>';
+            $html .= '<h2>Details</h2>';
+            $html .= $this->renderExceptionFragment($exception);
+        } else {
+            $html = '<p>A website error has occurred. Sorry for the temporary inconvenience.</p>';
+        }
+
+        return $this->renderHtmlBody($title, $html);
+    }
+
+    /**
+     * @param Throwable $exception
+     * @return string
+     */
+    private function renderExceptionFragment(Throwable $exception): string
+    {
+        $html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
+
+        $code = $exception->getCode();
+        if ($code !== null) {
+            $html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
+        }
+
+        $message = $exception->getMessage();
+        if ($message !== null) {
+            $html .= sprintf('<div><strong>Message:</strong> %s</div>', htmlentities($message));
+        }
+
+        $file = $exception->getFile();
+        if ($file !== null) {
+            $html .= sprintf('<div><strong>File:</strong> %s</div>', $file);
+        }
+
+        $line = $exception->getLine();
+        if ($line !== null) {
+            $html .= sprintf('<div><strong>Line:</strong> %s</div>', $line);
+        }
+
+        $trace = $exception->getTraceAsString();
+        if ($trace !== null) {
+            $html .= '<h2>Trace</h2>';
+            $html .= sprintf('<pre>%s</pre>', htmlentities($trace));
+        }
+
+        return $html;
+    }
+
+    /**
+     * @param string $title
+     * @param string $html
+     * @return string
+     */
+    public function renderHtmlBody(string $title = '', string $html = ''): string
+    {
+        return sprintf(
+            '<html>' .
+            '   <head>' .
+            "       <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>" .
+            '       <title>%s</title>' .
+            '       <style>' .
+            '           body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana,sans-serif}' .
+            '           h1{margin:0;font-size:48px;font-weight:normal;line-height:48px}' .
+            '           strong{display:inline-block;width:65px}' .
+            '       </style>' .
+            '   </head>' .
+            '   <body>' .
+            '       <h1>%s</h1>' .
+            '       <div>%s</div>' .
+            '       <a href="#" onClick="window.history.go(-1)">Go Back</a>' .
+            '   </body>' .
+            '</html>',
+            $title,
+            $title,
+            $html
+        );
+    }
+}

+ 53 - 0
api/vendor/slim/slim/Slim/Error/Renderers/JsonErrorRenderer.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Error\Renderers;
+
+use Slim\Error\AbstractErrorRenderer;
+use Throwable;
+
+/**
+ * Default Slim application JSON Error Renderer
+ */
+class JsonErrorRenderer extends AbstractErrorRenderer
+{
+    /**
+     * @param Throwable $exception
+     * @param bool      $displayErrorDetails
+     * @return string
+     */
+    public function __invoke(Throwable $exception, bool $displayErrorDetails): string
+    {
+        $error = ['message' => $exception->getMessage()];
+
+        if ($displayErrorDetails) {
+            $error['exception'] = [];
+            do {
+                $error['exception'][] = $this->formatExceptionFragment($exception);
+            } while ($exception = $exception->getPrevious());
+        }
+
+        return (string) json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+    }
+
+    /**
+     * @param Throwable $exception
+     * @return array
+     */
+    private function formatExceptionFragment(Throwable $exception): array
+    {
+        return [
+            'type' => get_class($exception),
+            'code' => $exception->getCode(),
+            'message' => $exception->getMessage(),
+            'file' => $exception->getFile(),
+            'line' => $exception->getLine(),
+        ];
+    }
+}

+ 73 - 0
api/vendor/slim/slim/Slim/Error/Renderers/PlainTextErrorRenderer.php

@@ -0,0 +1,73 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Error\Renderers;
+
+use Slim\Error\AbstractErrorRenderer;
+use Throwable;
+
+/**
+ * Default Slim application Plain Text Error Renderer
+ */
+class PlainTextErrorRenderer extends AbstractErrorRenderer
+{
+    /**
+     * @param Throwable $exception
+     * @param bool      $displayErrorDetails
+     * @return string
+     */
+    public function __invoke(Throwable $exception, bool $displayErrorDetails): string
+    {
+        $text = "Slim Application Error:\n";
+        $text .= $this->formatExceptionFragment($exception);
+
+        while ($displayErrorDetails && $exception = $exception->getPrevious()) {
+            $text .= "\nPrevious Error:\n";
+            $text .= $this->formatExceptionFragment($exception);
+        }
+
+        return $text;
+    }
+
+    /**
+     * @param Throwable $exception
+     * @return string
+     */
+    private function formatExceptionFragment(Throwable $exception): string
+    {
+        $text = sprintf("Type: %s\n", get_class($exception));
+
+        $code = $exception->getCode();
+        if ($code !== null) {
+            $text .= sprintf("Code: %s\n", $code);
+        }
+
+        $message = $exception->getMessage();
+        if ($message !== null) {
+            $text .= sprintf("Message: %s\n", htmlentities($message));
+        }
+
+        $file = $exception->getFile();
+        if ($file !== null) {
+            $text .= sprintf("File: %s\n", $file);
+        }
+
+        $line = $exception->getLine();
+        if ($line !== null) {
+            $text .= sprintf("Line: %s\n", $line);
+        }
+
+        $trace = $exception->getTraceAsString();
+        if ($trace !== null) {
+            $text .= sprintf('Trace: %s', $trace);
+        }
+
+        return $text;
+    }
+}

+ 57 - 0
api/vendor/slim/slim/Slim/Error/Renderers/XmlErrorRenderer.php

@@ -0,0 +1,57 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Error\Renderers;
+
+use Slim\Error\AbstractErrorRenderer;
+use Throwable;
+
+/**
+ * Default Slim application XML Error Renderer
+ */
+class XmlErrorRenderer extends AbstractErrorRenderer
+{
+    /**
+     * @param Throwable $exception
+     * @param bool      $displayErrorDetails
+     * @return string
+     */
+    public function __invoke(Throwable $exception, bool $displayErrorDetails): string
+    {
+        $xml = '<' . '?xml version="1.0" encoding="UTF-8" standalone="yes"?' . ">\n";
+        $xml .= "<error>\n  <message>" . $this->createCdataSection($exception->getMessage()) . "</message>\n";
+
+        if ($displayErrorDetails) {
+            do {
+                $xml .= "  <exception>\n";
+                $xml .= '    <type>' . get_class($exception) . "</type>\n";
+                $xml .= '    <code>' . $exception->getCode() . "</code>\n";
+                $xml .= '    <message>' . $this->createCdataSection($exception->getMessage()) . "</message>\n";
+                $xml .= '    <file>' . $exception->getFile() . "</file>\n";
+                $xml .= '    <line>' . $exception->getLine() . "</line>\n";
+                $xml .= "  </exception>\n";
+            } while ($exception = $exception->getPrevious());
+        }
+
+        $xml .= '</error>';
+
+        return $xml;
+    }
+
+    /**
+     * Returns a CDATA section with the given content.
+     *
+     * @param  string $content
+     * @return string
+     */
+    private function createCdataSection(string $content): string
+    {
+        return sprintf('<![CDATA[%s]]>', str_replace(']]>', ']]]]><![CDATA[>', $content));
+    }
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Exception/HttpBadRequestException.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpBadRequestException extends HttpSpecializedException
+{
+    protected $code = 400;
+    protected $message = 'Bad request.';
+    protected $title = '400 Bad Request';
+    protected $description = 'The server cannot or will not process the request due to an apparent client error.';
+}

+ 92 - 0
api/vendor/slim/slim/Slim/Exception/HttpException.php

@@ -0,0 +1,92 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+use Exception;
+use Psr\Http\Message\ServerRequestInterface;
+use Throwable;
+
+class HttpException extends Exception
+{
+    /**
+     * @var ServerRequestInterface
+     */
+    protected $request;
+
+    /**
+     * @var string
+     */
+    protected $title = '';
+
+    /**
+     * @var string
+     */
+    protected $description = '';
+
+    /**
+     * @param ServerRequestInterface $request
+     * @param string                 $message
+     * @param int                    $code
+     * @param Throwable|null         $previous
+     */
+    public function __construct(
+        ServerRequestInterface $request,
+        string $message = '',
+        int $code = 0,
+        ?Throwable $previous = null
+    ) {
+        parent::__construct($message, $code, $previous);
+        $this->request = $request;
+    }
+
+    /**
+     * @return ServerRequestInterface
+     */
+    public function getRequest(): ServerRequestInterface
+    {
+        return $this->request;
+    }
+
+    /**
+     * @return string
+     */
+    public function getTitle(): string
+    {
+        return $this->title;
+    }
+
+    /**
+     * @param string $title
+     * @return self
+     */
+    public function setTitle(string $title): self
+    {
+        $this->title = $title;
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getDescription(): string
+    {
+        return $this->description;
+    }
+
+    /**
+     * @param string $description
+     * @return self
+     */
+    public function setDescription(string $description): self
+    {
+        $this->description = $description;
+        return $this;
+    }
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Exception/HttpForbiddenException.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpForbiddenException extends HttpSpecializedException
+{
+    protected $code = 403;
+    protected $message = 'Forbidden.';
+    protected $title = '403 Forbidden';
+    protected $description = 'You are not permitted to perform the requested operation.';
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Exception/HttpInternalServerErrorException.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpInternalServerErrorException extends HttpSpecializedException
+{
+    protected $code = 500;
+    protected $message = 'Internal server error.';
+    protected $title = '500 Internal Server Error';
+    protected $description = 'Unexpected condition encountered preventing server from fulfilling request.';
+}

+ 41 - 0
api/vendor/slim/slim/Slim/Exception/HttpMethodNotAllowedException.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpMethodNotAllowedException extends HttpSpecializedException
+{
+    /**
+     * @var array
+     */
+    protected $allowedMethods = [];
+
+    protected $code = 405;
+    protected $message = 'Method not allowed.';
+    protected $title = '405 Method Not Allowed';
+    protected $description = 'The request method is not supported for the requested resource.';
+
+    /**
+     * @return array
+     */
+    public function getAllowedMethods(): array
+    {
+        return $this->allowedMethods;
+    }
+
+    /**
+     * @param array $methods
+     * @return self
+     */
+    public function setAllowedMethods(array $methods): HttpMethodNotAllowedException
+    {
+        $this->allowedMethods = $methods;
+        return $this;
+    }
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Exception/HttpNotFoundException.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpNotFoundException extends HttpSpecializedException
+{
+    protected $code = 404;
+    protected $message = 'Not found.';
+    protected $title = '404 Not Found';
+    protected $description = 'The requested resource could not be found. Please verify the URI and try again.';
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Exception/HttpNotImplementedException.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpNotImplementedException extends HttpSpecializedException
+{
+    protected $code = 501;
+    protected $message = 'Not implemented.';
+    protected $title = '501 Not Implemented';
+    protected $description = 'The server does not support the functionality required to fulfill the request.';
+}

+ 30 - 0
api/vendor/slim/slim/Slim/Exception/HttpSpecializedException.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+use Psr\Http\Message\ServerRequestInterface;
+use Throwable;
+
+abstract class HttpSpecializedException extends HttpException
+{
+    /**
+     * @param ServerRequestInterface $request
+     * @param string|null            $message
+     * @param Throwable|null         $previous
+     */
+    public function __construct(ServerRequestInterface $request, ?string $message = null, ?Throwable $previous = null)
+    {
+        if ($message !== null) {
+            $this->message = $message;
+        }
+
+        parent::__construct($request, $this->message, $this->code, $previous);
+    }
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Exception/HttpUnauthorizedException.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Exception;
+
+class HttpUnauthorizedException extends HttpSpecializedException
+{
+    protected $code = 401;
+    protected $message = 'Unauthorized.';
+    protected $title = '401 Unauthorized';
+    protected $description = 'The request requires valid user authentication.';
+}

+ 209 - 0
api/vendor/slim/slim/Slim/Factory/AppFactory.php

@@ -0,0 +1,209 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory;
+
+use Psr\Container\ContainerInterface;
+use Psr\Http\Message\ResponseFactoryInterface;
+use Psr\Http\Message\StreamFactoryInterface;
+use RuntimeException;
+use Slim\App;
+use Slim\Factory\Psr17\Psr17Factory;
+use Slim\Factory\Psr17\Psr17FactoryProvider;
+use Slim\Factory\Psr17\SlimHttpPsr17Factory;
+use Slim\Interfaces\CallableResolverInterface;
+use Slim\Interfaces\Psr17FactoryProviderInterface;
+use Slim\Interfaces\RouteCollectorInterface;
+use Slim\Interfaces\RouteResolverInterface;
+
+class AppFactory
+{
+    /**
+     * @var Psr17FactoryProviderInterface|null
+     */
+    protected static $psr17FactoryProvider;
+
+    /**
+     * @var ResponseFactoryInterface|null
+     */
+    protected static $responseFactory;
+
+    /**
+     * @var StreamFactoryInterface|null
+     */
+    protected static $streamFactory;
+
+    /**
+     * @var ContainerInterface|null
+     */
+    protected static $container;
+
+    /**
+     * @var CallableResolverInterface|null
+     */
+    protected static $callableResolver;
+
+    /**
+     * @var RouteCollectorInterface|null
+     */
+    protected static $routeCollector;
+
+    /**
+     * @var RouteResolverInterface|null
+     */
+    protected static $routeResolver;
+
+    /**
+     * @var bool
+     */
+    protected static $slimHttpDecoratorsAutomaticDetectionEnabled = true;
+
+    /**
+     * @param ResponseFactoryInterface|null  $responseFactory
+     * @param ContainerInterface|null        $container
+     * @param CallableResolverInterface|null $callableResolver
+     * @param RouteCollectorInterface|null   $routeCollector
+     * @param RouteResolverInterface|null    $routeResolver
+     * @return App
+     */
+    public static function create(
+        ?ResponseFactoryInterface $responseFactory = null,
+        ?ContainerInterface $container = null,
+        ?CallableResolverInterface $callableResolver = null,
+        ?RouteCollectorInterface $routeCollector = null,
+        ?RouteResolverInterface $routeResolver = null
+    ): App {
+        static::$responseFactory = $responseFactory ?? static::$responseFactory;
+        return new App(
+            self::determineResponseFactory(),
+            $container ?? static::$container,
+            $callableResolver ?? static::$callableResolver,
+            $routeCollector ?? static::$routeCollector,
+            $routeResolver ?? static::$routeResolver
+        );
+    }
+
+    /**
+     * @return ResponseFactoryInterface
+     * @throws RuntimeException
+     */
+    public static function determineResponseFactory(): ResponseFactoryInterface
+    {
+        if (static::$responseFactory) {
+            if (static::$streamFactory) {
+                return static::attemptResponseFactoryDecoration(static::$responseFactory, static::$streamFactory);
+            }
+            return static::$responseFactory;
+        }
+
+        $psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
+
+        /** @var Psr17Factory $psr17factory */
+        foreach ($psr17FactoryProvider->getFactories() as $psr17factory) {
+            if ($psr17factory::isResponseFactoryAvailable()) {
+                $responseFactory = $psr17factory::getResponseFactory();
+
+                if ($psr17factory::isStreamFactoryAvailable() || static::$streamFactory) {
+                    $streamFactory = static::$streamFactory ?? $psr17factory::getStreamFactory();
+                    return static::attemptResponseFactoryDecoration($responseFactory, $streamFactory);
+                }
+
+                return $responseFactory;
+            }
+        }
+
+        throw new RuntimeException(
+            "Could not detect any PSR-17 ResponseFactory implementations. " .
+            "Please install a supported implementation in order to use `AppFactory::create()`. " .
+            "See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
+        );
+    }
+
+    /**
+     * @param ResponseFactoryInterface $responseFactory
+     * @param StreamFactoryInterface   $streamFactory
+     * @return ResponseFactoryInterface
+     */
+    protected static function attemptResponseFactoryDecoration(
+        ResponseFactoryInterface $responseFactory,
+        StreamFactoryInterface $streamFactory
+    ): ResponseFactoryInterface {
+        if (static::$slimHttpDecoratorsAutomaticDetectionEnabled
+            && SlimHttpPsr17Factory::isResponseFactoryAvailable()
+        ) {
+            return SlimHttpPsr17Factory::createDecoratedResponseFactory($responseFactory, $streamFactory);
+        }
+
+        return $responseFactory;
+    }
+
+    /**
+     * @param Psr17FactoryProviderInterface $psr17FactoryProvider
+     */
+    public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
+    {
+        static::$psr17FactoryProvider = $psr17FactoryProvider;
+    }
+
+    /**
+     * @param ResponseFactoryInterface $responseFactory
+     */
+    public static function setResponseFactory(ResponseFactoryInterface $responseFactory): void
+    {
+        static::$responseFactory = $responseFactory;
+    }
+
+    /**
+     * @param StreamFactoryInterface $streamFactory
+     */
+    public static function setStreamFactory(StreamFactoryInterface $streamFactory): void
+    {
+        static::$streamFactory = $streamFactory;
+    }
+
+    /**
+     * @param ContainerInterface $container
+     */
+    public static function setContainer(ContainerInterface $container): void
+    {
+        static::$container = $container;
+    }
+
+    /**
+     * @param CallableResolverInterface $callableResolver
+     */
+    public static function setCallableResolver(CallableResolverInterface $callableResolver): void
+    {
+        static::$callableResolver = $callableResolver;
+    }
+
+    /**
+     * @param RouteCollectorInterface $routeCollector
+     */
+    public static function setRouteCollector(RouteCollectorInterface $routeCollector): void
+    {
+        static::$routeCollector = $routeCollector;
+    }
+
+    /**
+     * @param RouteResolverInterface $routeResolver
+     */
+    public static function setRouteResolver(RouteResolverInterface $routeResolver): void
+    {
+        static::$routeResolver = $routeResolver;
+    }
+
+    /**
+     * @param bool $enabled
+     */
+    public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
+    {
+        static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
+    }
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+class GuzzlePsr17Factory extends Psr17Factory
+{
+    protected static $responseFactoryClass = 'Http\Factory\Guzzle\ResponseFactory';
+    protected static $streamFactoryClass = 'Http\Factory\Guzzle\StreamFactory';
+    protected static $serverRequestCreatorClass = 'GuzzleHttp\Psr7\ServerRequest';
+    protected static $serverRequestCreatorMethod = 'fromGlobals';
+}

+ 35 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/NyholmPsr17Factory.php

@@ -0,0 +1,35 @@
+<?php
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+use Slim\Interfaces\ServerRequestCreatorInterface;
+
+class NyholmPsr17Factory extends Psr17Factory
+{
+    protected static $responseFactoryClass = 'Nyholm\Psr7\Factory\Psr17Factory';
+    protected static $streamFactoryClass = 'Nyholm\Psr7\Factory\Psr17Factory';
+    protected static $serverRequestCreatorClass = 'Nyholm\Psr7Server\ServerRequestCreator';
+    protected static $serverRequestCreatorMethod = 'fromGlobals';
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function getServerRequestCreator(): ServerRequestCreatorInterface
+    {
+        /*
+         * Nyholm Psr17Factory implements all factories in one unified
+         * factory which implements all of the PSR-17 factory interfaces
+         */
+        $psr17Factory = new static::$responseFactoryClass;
+
+        $serverRequestCreator = new static::$serverRequestCreatorClass(
+            $psr17Factory,
+            $psr17Factory,
+            $psr17Factory,
+            $psr17Factory
+        );
+
+        return new ServerRequestCreator($serverRequestCreator, static::$serverRequestCreatorMethod);
+    }
+}

+ 103 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/Psr17Factory.php

@@ -0,0 +1,103 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+use Psr\Http\Message\ResponseFactoryInterface;
+use Psr\Http\Message\StreamFactoryInterface;
+use RuntimeException;
+use Slim\Interfaces\Psr17FactoryInterface;
+use Slim\Interfaces\ServerRequestCreatorInterface;
+
+abstract class Psr17Factory implements Psr17FactoryInterface
+{
+    /**
+     * @var string
+     */
+    protected static $responseFactoryClass;
+
+    /**
+     * @var string
+     */
+    protected static $streamFactoryClass;
+
+    /**
+     * @var string
+     */
+    protected static $serverRequestCreatorClass;
+
+    /**
+     * @var string
+     */
+    protected static $serverRequestCreatorMethod;
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function getResponseFactory(): ResponseFactoryInterface
+    {
+        if (!static::isResponseFactoryAvailable()) {
+            throw new RuntimeException(get_called_class() . ' could not instantiate a response factory.');
+        }
+
+        return new static::$responseFactoryClass;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function getStreamFactory(): StreamFactoryInterface
+    {
+        if (!static::isStreamFactoryAvailable()) {
+            throw new RuntimeException(get_called_class() . ' could not instantiate a stream factory.');
+        }
+
+        return new static::$streamFactoryClass;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function getServerRequestCreator(): ServerRequestCreatorInterface
+    {
+        if (!static::isServerRequestCreatorAvailable()) {
+            throw new RuntimeException(get_called_class() . ' could not instantiate a server request creator.');
+        }
+
+        return new ServerRequestCreator(static::$serverRequestCreatorClass, static::$serverRequestCreatorMethod);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function isResponseFactoryAvailable(): bool
+    {
+        return static::$responseFactoryClass && class_exists(static::$responseFactoryClass);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function isStreamFactoryAvailable(): bool
+    {
+        return static::$streamFactoryClass && class_exists(static::$streamFactoryClass);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function isServerRequestCreatorAvailable(): bool
+    {
+        return (
+            static::$serverRequestCreatorClass
+            && static::$serverRequestCreatorMethod
+            && class_exists(static::$serverRequestCreatorClass)
+        );
+    }
+}

+ 49 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/Psr17FactoryProvider.php

@@ -0,0 +1,49 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+use Slim\Interfaces\Psr17FactoryProviderInterface;
+
+class Psr17FactoryProvider implements Psr17FactoryProviderInterface
+{
+    /**
+     * @var string[]
+     */
+    protected static $factories = [
+        SlimPsr17Factory::class,
+        NyholmPsr17Factory::class,
+        ZendDiactorosPsr17Factory::class,
+        GuzzlePsr17Factory::class,
+    ];
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function getFactories(): array
+    {
+        return static::$factories;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function setFactories(array $factories): void
+    {
+        static::$factories = $factories;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function addFactory(string $factory): void
+    {
+        array_unshift(static::$factories, $factory);
+    }
+}

+ 47 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/ServerRequestCreator.php

@@ -0,0 +1,47 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+use Closure;
+use Psr\Http\Message\ServerRequestInterface;
+use Slim\Interfaces\ServerRequestCreatorInterface;
+
+class ServerRequestCreator implements ServerRequestCreatorInterface
+{
+    /**
+     * @var object|string
+     */
+    protected $serverRequestCreator;
+
+    /**
+     * @var string
+     */
+    protected $serverRequestCreatorMethod;
+
+    /**
+     * @param object|string $serverRequestCreator
+     * @param string        $serverRequestCreatorMethod
+     */
+    public function __construct($serverRequestCreator, string $serverRequestCreatorMethod)
+    {
+        $this->serverRequestCreator = $serverRequestCreator;
+        $this->serverRequestCreatorMethod = $serverRequestCreatorMethod;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function createServerRequestFromGlobals(): ServerRequestInterface
+    {
+        /** @var callable $callable */
+        $callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod];
+        return (Closure::fromCallable($callable))();
+    }
+}

+ 30 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpPsr17Factory.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+use Psr\Http\Message\ResponseFactoryInterface;
+use Psr\Http\Message\StreamFactoryInterface;
+
+class SlimHttpPsr17Factory extends Psr17Factory
+{
+    protected static $responseFactoryClass = 'Slim\Http\Factory\DecoratedResponseFactory';
+
+    /**
+     * @param ResponseFactoryInterface $responseFactory
+     * @param StreamFactoryInterface   $streamFactory
+     * @return ResponseFactoryInterface
+     */
+    public static function createDecoratedResponseFactory(
+        ResponseFactoryInterface $responseFactory,
+        StreamFactoryInterface $streamFactory
+    ): ResponseFactoryInterface {
+        return new static::$responseFactoryClass($responseFactory, $streamFactory);
+    }
+}

+ 57 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpServerRequestCreator.php

@@ -0,0 +1,57 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+use Psr\Http\Message\ServerRequestInterface;
+use RuntimeException;
+use Slim\Interfaces\ServerRequestCreatorInterface;
+
+class SlimHttpServerRequestCreator implements ServerRequestCreatorInterface
+{
+    /**
+     * @var ServerRequestCreatorInterface
+     */
+    protected $serverRequestCreator;
+
+    /**
+     * @var string
+     */
+    protected static $serverRequestDecoratorClass = 'Slim\Http\ServerRequest';
+
+    /**
+     * @param ServerRequestCreatorInterface $serverRequestCreator
+     */
+    public function __construct(ServerRequestCreatorInterface $serverRequestCreator)
+    {
+        $this->serverRequestCreator = $serverRequestCreator;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function createServerRequestFromGlobals(): ServerRequestInterface
+    {
+        if (!static::isServerRequestDecoratorAvailable()) {
+            throw new RuntimeException('The Slim-Http ServerRequest decorator is not available.');
+        }
+
+        $request = $this->serverRequestCreator->createServerRequestFromGlobals();
+
+        return new static::$serverRequestDecoratorClass($request);
+    }
+
+    /**
+     * @return bool
+     */
+    public static function isServerRequestDecoratorAvailable(): bool
+    {
+        return class_exists(static::$serverRequestDecoratorClass);
+    }
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/SlimPsr17Factory.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+class SlimPsr17Factory extends Psr17Factory
+{
+    protected static $responseFactoryClass = 'Slim\Psr7\Factory\ResponseFactory';
+    protected static $streamFactoryClass = 'Slim\Psr7\Factory\StreamFactory';
+    protected static $serverRequestCreatorClass = 'Slim\Psr7\Factory\ServerRequestFactory';
+    protected static $serverRequestCreatorMethod = 'createFromGlobals';
+}

+ 18 - 0
api/vendor/slim/slim/Slim/Factory/Psr17/ZendDiactorosPsr17Factory.php

@@ -0,0 +1,18 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory\Psr17;
+
+class ZendDiactorosPsr17Factory extends Psr17Factory
+{
+    protected static $responseFactoryClass = 'Zend\Diactoros\ResponseFactory';
+    protected static $streamFactoryClass = 'Zend\Diactoros\StreamFactory';
+    protected static $serverRequestCreatorClass = 'Zend\Diactoros\ServerRequestFactory';
+    protected static $serverRequestCreatorMethod = 'fromGlobals';
+}

+ 111 - 0
api/vendor/slim/slim/Slim/Factory/ServerRequestCreatorFactory.php

@@ -0,0 +1,111 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Factory;
+
+use RuntimeException;
+use Slim\Factory\Psr17\Psr17Factory;
+use Slim\Factory\Psr17\Psr17FactoryProvider;
+use Slim\Factory\Psr17\SlimHttpServerRequestCreator;
+use Slim\Interfaces\Psr17FactoryProviderInterface;
+use Slim\Interfaces\ServerRequestCreatorInterface;
+
+class ServerRequestCreatorFactory
+{
+    /**
+     * @var Psr17FactoryProviderInterface|null
+     */
+    protected static $psr17FactoryProvider;
+
+    /**
+     * @var ServerRequestCreatorInterface|null
+     */
+    protected static $serverRequestCreator;
+
+    /**
+     * @var bool
+     */
+    protected static $slimHttpDecoratorsAutomaticDetectionEnabled = true;
+
+    /**
+     * @return ServerRequestCreatorInterface
+     */
+    public static function create(): ServerRequestCreatorInterface
+    {
+        return static::determineServerRequestCreator();
+    }
+
+    /**
+     * @return ServerRequestCreatorInterface
+     * @throws RuntimeException
+     */
+    public static function determineServerRequestCreator(): ServerRequestCreatorInterface
+    {
+        if (static::$serverRequestCreator) {
+            return static::attemptServerRequestCreatorDecoration(static::$serverRequestCreator);
+        }
+
+        $psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
+
+        /** @var Psr17Factory $psr17Factory */
+        foreach ($psr17FactoryProvider->getFactories() as $psr17Factory) {
+            if ($psr17Factory::isServerRequestCreatorAvailable()) {
+                $serverRequestCreator = $psr17Factory::getServerRequestCreator();
+                return static::attemptServerRequestCreatorDecoration($serverRequestCreator);
+            }
+        }
+
+        throw new RuntimeException(
+            "Could not detect any ServerRequest creator implementations. " .
+            "Please install a supported implementation in order to use `App::run()` " .
+            "without having to pass in a `ServerRequest` object. " .
+            "See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
+        );
+    }
+
+    /**
+     * @param ServerRequestCreatorInterface $serverRequestCreator
+     * @return ServerRequestCreatorInterface
+     */
+    protected static function attemptServerRequestCreatorDecoration(
+        ServerRequestCreatorInterface $serverRequestCreator
+    ): ServerRequestCreatorInterface {
+        if (static::$slimHttpDecoratorsAutomaticDetectionEnabled
+            && SlimHttpServerRequestCreator::isServerRequestDecoratorAvailable()
+        ) {
+            return new SlimHttpServerRequestCreator($serverRequestCreator);
+        }
+
+        return $serverRequestCreator;
+    }
+
+    /**
+     * @param Psr17FactoryProviderInterface $psr17FactoryProvider
+     */
+    public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
+    {
+        static::$psr17FactoryProvider = $psr17FactoryProvider;
+    }
+
+    /**
+     * @param ServerRequestCreatorInterface $serverRequestCreator
+     */
+    public static function setServerRequestCreator(ServerRequestCreatorInterface $serverRequestCreator): void
+    {
+        self::$serverRequestCreator = $serverRequestCreator;
+    }
+
+    /**
+     * @param bool $enabled
+     */
+    public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
+    {
+        static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
+    }
+}

+ 309 - 0
api/vendor/slim/slim/Slim/Handlers/ErrorHandler.php

@@ -0,0 +1,309 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Handlers;
+
+use Psr\Http\Message\ResponseFactoryInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use RuntimeException;
+use Slim\Error\Renderers\HtmlErrorRenderer;
+use Slim\Error\Renderers\JsonErrorRenderer;
+use Slim\Error\Renderers\PlainTextErrorRenderer;
+use Slim\Error\Renderers\XmlErrorRenderer;
+use Slim\Exception\HttpException;
+use Slim\Exception\HttpMethodNotAllowedException;
+use Slim\Interfaces\CallableResolverInterface;
+use Slim\Interfaces\ErrorHandlerInterface;
+use Slim\Interfaces\ErrorRendererInterface;
+use Throwable;
+
+/**
+ * Default Slim application error handler
+ *
+ * It outputs the error message and diagnostic information in one of the following formats:
+ * JSON, XML, Plain Text or HTML based on the Accept header.
+ */
+class ErrorHandler implements ErrorHandlerInterface
+{
+    /**
+     * @var string
+     */
+    protected $defaultErrorRendererContentType = 'text/html';
+
+    /**
+     * @var ErrorRendererInterface|string|callable
+     */
+    protected $defaultErrorRenderer = HtmlErrorRenderer::class;
+
+    /**
+     * @var array
+     */
+    protected $errorRenderers = [
+        'application/json' => JsonErrorRenderer::class,
+        'application/xml' => XmlErrorRenderer::class,
+        'text/xml' => XmlErrorRenderer::class,
+        'text/html' => HtmlErrorRenderer::class,
+        'text/plain' => PlainTextErrorRenderer::class,
+    ];
+
+    /**
+     * @var bool
+     */
+    protected $displayErrorDetails;
+
+    /**
+     * @var bool
+     */
+    protected $logErrors;
+
+    /**
+     * @var bool
+     */
+    protected $logErrorDetails;
+
+    /**
+     * @var string|null
+     */
+    protected $contentType;
+
+    /**
+     * @var string
+     */
+    protected $method;
+
+    /**
+     * @var ServerRequestInterface
+     */
+    protected $request;
+
+    /**
+     * @var Throwable
+     */
+    protected $exception;
+
+    /**
+     * @var int
+     */
+    protected $statusCode;
+
+    /**
+     * @var CallableResolverInterface
+     */
+    protected $callableResolver;
+
+    /**
+     * @var ResponseFactoryInterface
+     */
+    protected $responseFactory;
+
+    /**
+     * @param CallableResolverInterface $callableResolver
+     * @param ResponseFactoryInterface  $responseFactory
+     */
+    public function __construct(CallableResolverInterface $callableResolver, ResponseFactoryInterface $responseFactory)
+    {
+        $this->callableResolver = $callableResolver;
+        $this->responseFactory = $responseFactory;
+    }
+
+    /**
+     * Invoke error handler
+     *
+     * @param ServerRequestInterface $request             The most recent Request object
+     * @param Throwable              $exception           The caught Exception object
+     * @param bool                   $displayErrorDetails Whether or not to display the error details
+     * @param bool                   $logErrors           Whether or not to log errors
+     * @param bool                   $logErrorDetails     Whether or not to log error details
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(
+        ServerRequestInterface $request,
+        Throwable $exception,
+        bool $displayErrorDetails,
+        bool $logErrors,
+        bool $logErrorDetails
+    ): ResponseInterface {
+        $this->displayErrorDetails = $displayErrorDetails;
+        $this->logErrors = $logErrors;
+        $this->logErrorDetails = $logErrorDetails;
+        $this->request = $request;
+        $this->exception = $exception;
+        $this->method = $request->getMethod();
+        $this->statusCode = $this->determineStatusCode();
+        if (is_null($this->contentType)) {
+            $this->contentType = $this->determineContentType($request);
+        }
+
+        if ($logErrors) {
+            $this->writeToErrorLog();
+        }
+
+        return $this->respond();
+    }
+
+    /**
+     * Force the content type for all error handler responses.
+     *
+     * @param string|null $contentType The content type
+     */
+    public function forceContentType(?string $contentType): void
+    {
+        $this->contentType = $contentType;
+    }
+
+    /**
+     * @return int
+     */
+    protected function determineStatusCode(): int
+    {
+        if ($this->method === 'OPTIONS') {
+            return 200;
+        }
+
+        if ($this->exception instanceof HttpException) {
+            return $this->exception->getCode();
+        }
+
+        return 500;
+    }
+
+    /**
+     * Determine which content type we know about is wanted using Accept header
+     *
+     * Note: This method is a bare-bones implementation designed specifically for
+     * Slim's error handling requirements. Consider a fully-feature solution such
+     * as willdurand/negotiation for any other situation.
+     *
+     * @param ServerRequestInterface $request
+     * @return string
+     */
+    protected function determineContentType(ServerRequestInterface $request): ?string
+    {
+        $acceptHeader = $request->getHeaderLine('Accept');
+        $selectedContentTypes = array_intersect(
+            explode(',', $acceptHeader),
+            array_keys($this->errorRenderers)
+        );
+        $count = count($selectedContentTypes);
+
+        if ($count) {
+            $current = current($selectedContentTypes);
+
+            /**
+             * Ensure other supported content types take precedence over text/plain
+             * when multiple content types are provided via Accept header.
+             */
+            if ($current === 'text/plain' && $count > 1) {
+                return next($selectedContentTypes);
+            }
+
+            return $current;
+        }
+
+        if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) {
+            $mediaType = 'application/' . $matches[1];
+            if (array_key_exists($mediaType, $this->errorRenderers)) {
+                return $mediaType;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Determine which renderer to use based on content type
+     *
+     * @return callable
+     *
+     * @throws RuntimeException
+     */
+    protected function determineRenderer(): callable
+    {
+        if (!is_null($this->contentType) && array_key_exists($this->contentType, $this->errorRenderers)) {
+            $renderer = $this->errorRenderers[$this->contentType];
+        } else {
+            $renderer = $this->defaultErrorRenderer;
+        }
+
+        return $this->callableResolver->resolve($renderer);
+    }
+
+    /**
+     * Register an error renderer for a specific content-type
+     *
+     * @param string  $contentType  The content-type this renderer should be registered to
+     * @param ErrorRendererInterface|string|callable $errorRenderer The error renderer
+     */
+    public function registerErrorRenderer(string $contentType, $errorRenderer): void
+    {
+        $this->errorRenderers[$contentType] = $errorRenderer;
+    }
+
+    /**
+     * Set the default error renderer
+     *
+     * @param string                                 $contentType   The content type of the default error renderer
+     * @param ErrorRendererInterface|string|callable $errorRenderer The default error renderer
+     */
+    public function setDefaultErrorRenderer(string $contentType, $errorRenderer): void
+    {
+        $this->defaultErrorRendererContentType = $contentType;
+        $this->defaultErrorRenderer = $errorRenderer;
+    }
+
+    /**
+     * Write to the error log if $logErrors has been set to true
+     *
+     * @return void
+     */
+    protected function writeToErrorLog(): void
+    {
+        $renderer = new PlainTextErrorRenderer();
+        $error = $renderer->__invoke($this->exception, $this->logErrorDetails);
+        $error .= "\nView in rendered output by enabling the \"displayErrorDetails\" setting.\n";
+        $this->logError($error);
+    }
+
+    /**
+     * Wraps the error_log function so that this can be easily tested
+     *
+     * @param string $error
+     * @return void
+     */
+    protected function logError(string $error): void
+    {
+        error_log($error);
+    }
+
+    /**
+     * @return ResponseInterface
+     */
+    protected function respond(): ResponseInterface
+    {
+        $response = $this->responseFactory->createResponse($this->statusCode);
+        if (!is_null($this->contentType) && array_key_exists($this->contentType, $this->errorRenderers)) {
+            $response = $response->withHeader('Content-type', $this->contentType);
+        } else {
+            $response = $response->withHeader('Content-type', $this->defaultErrorRendererContentType);
+        }
+
+        if ($this->exception instanceof HttpMethodNotAllowedException) {
+            $allowedMethods = implode(', ', $this->exception->getAllowedMethods());
+            $response = $response->withHeader('Allow', $allowedMethods);
+        }
+
+        $renderer = $this->determineRenderer();
+        $body = call_user_func($renderer, $this->exception, $this->displayErrorDetails);
+        $response->getBody()->write($body);
+
+        return $response;
+    }
+}

+ 39 - 0
api/vendor/slim/slim/Slim/Handlers/Strategies/RequestHandler.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Handlers\Strategies;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Slim\Interfaces\InvocationStrategyInterface;
+
+/**
+ * Default route callback strategy with route parameters as an array of arguments.
+ */
+class RequestHandler implements InvocationStrategyInterface
+{
+    /**
+     * Invoke a route callable that implements RequestHandlerInterface
+     *
+     * @param callable               $callable
+     * @param ServerRequestInterface $request
+     * @param ResponseInterface      $response
+     * @param array                  $routeArguments
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(
+        callable $callable,
+        ServerRequestInterface $request,
+        ResponseInterface $response,
+        array $routeArguments
+    ): ResponseInterface {
+        return $callable($request);
+    }
+}

+ 44 - 0
api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php

@@ -0,0 +1,44 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Handlers\Strategies;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Slim\Interfaces\InvocationStrategyInterface;
+
+/**
+ * Default route callback strategy with route parameters as an array of arguments.
+ */
+class RequestResponse implements InvocationStrategyInterface
+{
+    /**
+     * Invoke a route callable with request, response, and all route parameters
+     * as an array of arguments.
+     *
+     * @param callable               $callable
+     * @param ServerRequestInterface $request
+     * @param ResponseInterface      $response
+     * @param array                  $routeArguments
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(
+        callable $callable,
+        ServerRequestInterface $request,
+        ResponseInterface $response,
+        array $routeArguments
+    ): ResponseInterface {
+        foreach ($routeArguments as $k => $v) {
+            $request = $request->withAttribute($k, $v);
+        }
+
+        return $callable($request, $response, $routeArguments);
+    }
+}

+ 40 - 0
api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseArgs.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * Slim Framework (https://slimframework.com)
+ *
+ * @license https://github.com/slimphp/Slim/blob/4.x/LICENSE.md (MIT License)
+ */
+
+declare(strict_types=1);
+
+namespace Slim\Handlers\Strategies;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Slim\Interfaces\InvocationStrategyInterface;
+
+/**
+ * Route callback strategy with route parameters as individual arguments.
+ */
+class RequestResponseArgs implements InvocationStrategyInterface
+{
+    /**
+     * Invoke a route callable with request, response and all route parameters
+     * as individual arguments.
+     *
+     * @param callable               $callable
+     * @param ServerRequestInterface $request
+     * @param ResponseInterface      $response
+     * @param array                  $routeArguments
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(
+        callable $callable,
+        ServerRequestInterface $request,
+        ResponseInterface $response,
+        array $routeArguments
+    ): ResponseInterface {
+        return $callable($request, $response, ...array_values($routeArguments));
+    }
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов