Просмотр исходного кода

updated uuid framework for uuid (#1835)

CauseFX 3 лет назад
Родитель
Сommit
671ed62abc
100 измененных файлов с 11378 добавлено и 950 удалено
  1. 2 1
      api/composer.json
  2. 261 50
      api/composer.lock
  3. 5 0
      api/vendor/autoload.php
  4. 415 0
      api/vendor/brick/math/CHANGELOG.md
  5. 20 0
      api/vendor/brick/math/LICENSE
  6. 17 0
      api/vendor/brick/math/SECURITY.md
  7. 35 0
      api/vendor/brick/math/composer.json
  8. 895 0
      api/vendor/brick/math/src/BigDecimal.php
  9. 1184 0
      api/vendor/brick/math/src/BigInteger.php
  10. 572 0
      api/vendor/brick/math/src/BigNumber.php
  11. 523 0
      api/vendor/brick/math/src/BigRational.php
  12. 41 0
      api/vendor/brick/math/src/Exception/DivisionByZeroException.php
  13. 27 0
      api/vendor/brick/math/src/Exception/IntegerOverflowException.php
  14. 14 0
      api/vendor/brick/math/src/Exception/MathException.php
  15. 12 0
      api/vendor/brick/math/src/Exception/NegativeNumberException.php
  16. 35 0
      api/vendor/brick/math/src/Exception/NumberFormatException.php
  17. 21 0
      api/vendor/brick/math/src/Exception/RoundingNecessaryException.php
  18. 756 0
      api/vendor/brick/math/src/Internal/Calculator.php
  19. 116 0
      api/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
  20. 156 0
      api/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php
  21. 634 0
      api/vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
  22. 107 0
      api/vendor/brick/math/src/RoundingMode.php
  23. 1 0
      api/vendor/composer/autoload_classmap.php
  24. 2 1
      api/vendor/composer/autoload_files.php
  25. 3 0
      api/vendor/composer/autoload_psr4.php
  26. 1 1
      api/vendor/composer/autoload_real.php
  27. 18 1
      api/vendor/composer/autoload_static.php
  28. 269 49
      api/vendor/composer/installed.json
  29. 33 6
      api/vendor/composer/installed.php
  30. 19 0
      api/vendor/ramsey/collection/LICENSE
  31. 82 0
      api/vendor/ramsey/collection/README.md
  32. 113 0
      api/vendor/ramsey/collection/SECURITY.md
  33. 102 0
      api/vendor/ramsey/collection/composer.json
  34. 209 0
      api/vendor/ramsey/collection/src/AbstractArray.php
  35. 318 0
      api/vendor/ramsey/collection/src/AbstractCollection.php
  36. 50 0
      api/vendor/ramsey/collection/src/AbstractSet.php
  37. 51 0
      api/vendor/ramsey/collection/src/ArrayInterface.php
  38. 106 0
      api/vendor/ramsey/collection/src/Collection.php
  39. 205 0
      api/vendor/ramsey/collection/src/CollectionInterface.php
  40. 187 0
      api/vendor/ramsey/collection/src/DoubleEndedQueue.php
  41. 316 0
      api/vendor/ramsey/collection/src/DoubleEndedQueueInterface.php
  42. 22 0
      api/vendor/ramsey/collection/src/Exception/CollectionMismatchException.php
  43. 22 0
      api/vendor/ramsey/collection/src/Exception/InvalidArgumentException.php
  44. 22 0
      api/vendor/ramsey/collection/src/Exception/InvalidSortOrderException.php
  45. 22 0
      api/vendor/ramsey/collection/src/Exception/NoSuchElementException.php
  46. 22 0
      api/vendor/ramsey/collection/src/Exception/OutOfBoundsException.php
  47. 22 0
      api/vendor/ramsey/collection/src/Exception/UnsupportedOperationException.php
  48. 22 0
      api/vendor/ramsey/collection/src/Exception/ValueExtractionException.php
  49. 24 0
      api/vendor/ramsey/collection/src/GenericArray.php
  50. 162 0
      api/vendor/ramsey/collection/src/Map/AbstractMap.php
  51. 69 0
      api/vendor/ramsey/collection/src/Map/AbstractTypedMap.php
  52. 25 0
      api/vendor/ramsey/collection/src/Map/AssociativeArrayMap.php
  53. 149 0
      api/vendor/ramsey/collection/src/Map/MapInterface.php
  54. 120 0
      api/vendor/ramsey/collection/src/Map/NamedParameterMap.php
  55. 137 0
      api/vendor/ramsey/collection/src/Map/TypedMap.php
  56. 35 0
      api/vendor/ramsey/collection/src/Map/TypedMapInterface.php
  57. 169 0
      api/vendor/ramsey/collection/src/Queue.php
  58. 203 0
      api/vendor/ramsey/collection/src/QueueInterface.php
  59. 69 0
      api/vendor/ramsey/collection/src/Set.php
  60. 73 0
      api/vendor/ramsey/collection/src/Tool/TypeTrait.php
  61. 58 0
      api/vendor/ramsey/collection/src/Tool/ValueExtractorTrait.php
  62. 94 0
      api/vendor/ramsey/collection/src/Tool/ValueToStringTrait.php
  63. 0 2
      api/vendor/ramsey/uuid/LICENSE
  64. 47 151
      api/vendor/ramsey/uuid/README.md
  65. 62 49
      api/vendor/ramsey/uuid/composer.json
  66. 38 16
      api/vendor/ramsey/uuid/src/BinaryUtils.php
  67. 80 0
      api/vendor/ramsey/uuid/src/Builder/BuilderCollection.php
  68. 8 36
      api/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php
  69. 41 18
      api/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php
  70. 74 0
      api/vendor/ramsey/uuid/src/Builder/FallbackBuilder.php
  71. 14 9
      api/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php
  72. 34 23
      api/vendor/ramsey/uuid/src/Codec/CodecInterface.php
  73. 20 68
      api/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php
  74. 76 31
      api/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php
  75. 63 95
      api/vendor/ramsey/uuid/src/Codec/StringCodec.php
  76. 66 61
      api/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php
  77. 34 5
      api/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php
  78. 27 24
      api/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php
  79. 8 41
      api/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php
  80. 63 0
      api/vendor/ramsey/uuid/src/Converter/Number/GenericNumberConverter.php
  81. 28 19
      api/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php
  82. 25 33
      api/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php
  83. 8 25
      api/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php
  84. 124 0
      api/vendor/ramsey/uuid/src/Converter/Time/GenericTimeConverter.php
  85. 152 16
      api/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php
  86. 36 15
      api/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php
  87. 6 97
      api/vendor/ramsey/uuid/src/DegradedUuid.php
  88. 147 0
      api/vendor/ramsey/uuid/src/DeprecatedUuidInterface.php
  89. 370 0
      api/vendor/ramsey/uuid/src/DeprecatedUuidMethodsTrait.php
  90. 24 0
      api/vendor/ramsey/uuid/src/Exception/BuilderNotFoundException.php
  91. 24 0
      api/vendor/ramsey/uuid/src/Exception/DateTimeException.php
  92. 25 0
      api/vendor/ramsey/uuid/src/Exception/DceSecurityException.php
  93. 24 0
      api/vendor/ramsey/uuid/src/Exception/InvalidArgumentException.php
  94. 24 0
      api/vendor/ramsey/uuid/src/Exception/InvalidBytesException.php
  95. 8 7
      api/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php
  96. 25 0
      api/vendor/ramsey/uuid/src/Exception/NameException.php
  97. 24 0
      api/vendor/ramsey/uuid/src/Exception/NodeException.php
  98. 27 0
      api/vendor/ramsey/uuid/src/Exception/RandomSourceException.php
  99. 24 0
      api/vendor/ramsey/uuid/src/Exception/TimeSourceException.php
  100. 24 0
      api/vendor/ramsey/uuid/src/Exception/UnableToBuildUuidException.php

+ 2 - 1
api/composer.json

@@ -21,6 +21,7 @@
     "bcremer/line-reader": "^1.1",
     "peppeocchi/php-cron-scheduler": "^4.0",
     "simshaun/recurr": "^5.0",
-    "stripe/stripe-php": "^7.116"
+    "stripe/stripe-php": "^7.116",
+    "ramsey/uuid": "^4.2"
   }
 }

+ 261 - 50
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": "b9b8c0d029836d5199c013198edf67e3",
+    "content-hash": "ca4f53441305ffa3e09c532006fa9c19",
     "packages": [
         {
             "name": "adldap2/adldap2",
@@ -170,6 +170,66 @@
             },
             "time": "2017-02-26T18:30:14+00:00"
         },
+        {
+            "name": "brick/math",
+            "version": "0.9.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/brick/math.git",
+                "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae",
+                "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "php-coveralls/php-coveralls": "^2.2",
+                "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
+                "vimeo/psalm": "4.9.2"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Brick\\Math\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Arbitrary-precision arithmetic library",
+            "keywords": [
+                "Arbitrary-precision",
+                "BigInteger",
+                "BigRational",
+                "arithmetic",
+                "bigdecimal",
+                "bignum",
+                "brick",
+                "math"
+            ],
+            "support": {
+                "issues": "https://github.com/brick/math/issues",
+                "source": "https://github.com/brick/math/tree/0.9.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/BenMorel",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/brick/math",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-08-15T20:50:18+00:00"
+        },
         {
             "name": "composer/semver",
             "version": "1.7.2",
@@ -1386,7 +1446,7 @@
             "require": {
                 "monolog/monolog": "^1.24",
                 "php": "~7.1",
-                "ramsey/uuid": "^3.8"
+                "ramsey/uuid": "^4.2"
             },
             "require-dev": {
                 "friendsofphp/php-cs-fixer": "^2.14",
@@ -2617,88 +2677,162 @@
             },
             "time": "2019-03-08T08:55:37+00:00"
         },
+        {
+            "name": "ramsey/collection",
+            "version": "1.2.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ramsey/collection.git",
+                "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a",
+                "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.3 || ^8",
+                "symfony/polyfill-php81": "^1.23"
+            },
+            "require-dev": {
+                "captainhook/captainhook": "^5.3",
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "ergebnis/composer-normalize": "^2.6",
+                "fakerphp/faker": "^1.5",
+                "hamcrest/hamcrest-php": "^2",
+                "jangregor/phpstan-prophecy": "^0.8",
+                "mockery/mockery": "^1.3",
+                "phpspec/prophecy-phpunit": "^2.0",
+                "phpstan/extension-installer": "^1",
+                "phpstan/phpstan": "^0.12.32",
+                "phpstan/phpstan-mockery": "^0.12.5",
+                "phpstan/phpstan-phpunit": "^0.12.11",
+                "phpunit/phpunit": "^8.5 || ^9",
+                "psy/psysh": "^0.10.4",
+                "slevomat/coding-standard": "^6.3",
+                "squizlabs/php_codesniffer": "^3.5",
+                "vimeo/psalm": "^4.4"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Ramsey\\Collection\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ben Ramsey",
+                    "email": "ben@benramsey.com",
+                    "homepage": "https://benramsey.com"
+                }
+            ],
+            "description": "A PHP library for representing and manipulating collections.",
+            "keywords": [
+                "array",
+                "collection",
+                "hash",
+                "map",
+                "queue",
+                "set"
+            ],
+            "support": {
+                "issues": "https://github.com/ramsey/collection/issues",
+                "source": "https://github.com/ramsey/collection/tree/1.2.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/ramsey",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-10-10T03:01:02+00:00"
+        },
         {
             "name": "ramsey/uuid",
-            "version": "3.9.6",
+            "version": "4.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/uuid.git",
-                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3"
+                "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ramsey/uuid/zipball/ffa80ab953edd85d5b6c004f96181a538aad35a3",
-                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
+                "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
                 "shasum": ""
             },
             "require": {
+                "brick/math": "^0.8 || ^0.9",
                 "ext-json": "*",
-                "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
-                "php": "^5.4 | ^7.0 | ^8.0",
-                "symfony/polyfill-ctype": "^1.8"
+                "php": "^7.2 || ^8.0",
+                "ramsey/collection": "^1.0",
+                "symfony/polyfill-ctype": "^1.8",
+                "symfony/polyfill-php80": "^1.14"
             },
             "replace": {
                 "rhumsaa/uuid": "self.version"
             },
             "require-dev": {
-                "codeception/aspect-mock": "^1 | ^2",
-                "doctrine/annotations": "^1.2",
-                "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
-                "mockery/mockery": "^0.9.11 | ^1",
+                "captainhook/captainhook": "^5.10",
+                "captainhook/plugin-composer": "^5.3",
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "doctrine/annotations": "^1.8",
+                "ergebnis/composer-normalize": "^2.15",
+                "mockery/mockery": "^1.3",
                 "moontoast/math": "^1.1",
-                "nikic/php-parser": "<=4.5.0",
                 "paragonie/random-lib": "^2",
-                "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
-                "php-parallel-lint/php-parallel-lint": "^1.3",
-                "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+                "php-mock/php-mock": "^2.2",
+                "php-mock/php-mock-mockery": "^1.3",
+                "php-parallel-lint/php-parallel-lint": "^1.1",
+                "phpbench/phpbench": "^1.0",
+                "phpstan/extension-installer": "^1.0",
+                "phpstan/phpstan": "^0.12",
+                "phpstan/phpstan-mockery": "^0.12",
+                "phpstan/phpstan-phpunit": "^0.12",
+                "phpunit/phpunit": "^8.5 || ^9",
+                "slevomat/coding-standard": "^7.0",
                 "squizlabs/php_codesniffer": "^3.5",
-                "yoast/phpunit-polyfills": "^1.0"
+                "vimeo/psalm": "^4.9"
             },
             "suggest": {
-                "ext-ctype": "Provides support for PHP Ctype functions",
-                "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
-                "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
-                "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
-                "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+                "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
+                "ext-ctype": "Enables faster processing of character classification using ctype functions.",
+                "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
+                "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
                 "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
-                "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
                 "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.x-dev"
+                    "dev-main": "4.x-dev"
+                },
+                "captainhook": {
+                    "force-install": true
                 }
             },
             "autoload": {
-                "psr-4": {
-                    "Ramsey\\Uuid\\": "src/"
-                },
                 "files": [
                     "src/functions.php"
-                ]
+                ],
+                "psr-4": {
+                    "Ramsey\\Uuid\\": "src/"
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                 "MIT"
             ],
-            "authors": [
-                {
-                    "name": "Ben Ramsey",
-                    "email": "ben@benramsey.com",
-                    "homepage": "https://benramsey.com"
-                },
-                {
-                    "name": "Marijn Huizendveld",
-                    "email": "marijn.huizendveld@gmail.com"
-                },
-                {
-                    "name": "Thibaud Fabre",
-                    "email": "thibaud@aztech.io"
-                }
-            ],
-            "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
-            "homepage": "https://github.com/ramsey/uuid",
+            "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
             "keywords": [
                 "guid",
                 "identifier",
@@ -2706,9 +2840,7 @@
             ],
             "support": {
                 "issues": "https://github.com/ramsey/uuid/issues",
-                "rss": "https://github.com/ramsey/uuid/releases.atom",
-                "source": "https://github.com/ramsey/uuid",
-                "wiki": "https://github.com/ramsey/uuid/wiki"
+                "source": "https://github.com/ramsey/uuid/tree/4.2.3"
             },
             "funding": [
                 {
@@ -2720,7 +2852,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-09-25T23:07:42+00:00"
+            "time": "2021-09-25T23:10:38+00:00"
         },
         {
             "name": "rmccue/requests",
@@ -3569,6 +3701,85 @@
             ],
             "time": "2021-01-07T16:49:33+00:00"
         },
+        {
+            "name": "symfony/polyfill-php81",
+            "version": "v1.25.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php81.git",
+                "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
+                "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.23-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php81\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-09-13T13:58:11+00:00"
+        },
         {
             "name": "symfony/polyfill-util",
             "version": "v1.9.0",

+ 5 - 0
api/vendor/autoload.php

@@ -2,6 +2,11 @@
 
 // autoload.php @generated by Composer
 
+if (PHP_VERSION_ID < 50600) {
+    echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    exit(1);
+}
+
 require_once __DIR__ . '/composer/autoload_real.php';
 
 return ComposerAutoloaderInitcbdc783d76f8e7563dcce7d8af053ecb::getLoader();

+ 415 - 0
api/vendor/brick/math/CHANGELOG.md

@@ -0,0 +1,415 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15
+
+🚀 **Compatibility with PHP 8.1**
+
+- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (thanks @TRowbotham)
+
+## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20
+
+🐛 **Bug fix**
+
+- Incorrect results could be returned when using the BCMath calculator, with a default scale set with `bcscale()`, on PHP >= 7.2 (#55).
+
+## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19
+
+✨ New features
+
+- `BigInteger::not()` returns the bitwise `NOT` value
+
+🐛 **Bug fixes**
+
+- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers
+- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available
+
+## [0.9.0](https://github.com/brick/math/releases/tag/0.9.0) - 2020-08-18
+
+👌 **Improvements**
+
+- `BigNumber::of()` now accepts `.123` and `123.` formats, both of which return a `BigDecimal`
+
+💥 **Breaking changes**
+
+- Deprecated method `BigInteger::powerMod()` has been removed - use `modPow()` instead
+- Deprecated method `BigInteger::parse()` has been removed - use `fromBase()` instead
+
+## [0.8.17](https://github.com/brick/math/releases/tag/0.8.17) - 2020-08-19
+
+🐛 **Bug fix**
+
+- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers
+- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available
+
+## [0.8.16](https://github.com/brick/math/releases/tag/0.8.16) - 2020-08-18
+
+🚑 **Critical fix**
+
+- This version reintroduces the deprecated `BigInteger::parse()` method, that has been removed by mistake in version `0.8.9` and should have lasted for the whole `0.8` release cycle.
+
+✨ **New features**
+
+- `BigInteger::modInverse()` calculates a modular multiplicative inverse
+- `BigInteger::fromBytes()` creates a `BigInteger` from a byte string
+- `BigInteger::toBytes()` converts a `BigInteger` to a byte string
+- `BigInteger::randomBits()` creates a pseudo-random `BigInteger` of a given bit length
+- `BigInteger::randomRange()` creates a pseudo-random `BigInteger` between two bounds
+
+💩 **Deprecations**
+
+- `BigInteger::powerMod()` is now deprecated in favour of `modPow()`
+
+## [0.8.15](https://github.com/brick/math/releases/tag/0.8.15) - 2020-04-15
+
+🐛 **Fixes**
+
+- added missing `ext-json` requirement, due to `BigNumber` implementing `JsonSerializable`
+
+⚡️ **Optimizations**
+
+- additional optimization in `BigInteger::remainder()`
+
+## [0.8.14](https://github.com/brick/math/releases/tag/0.8.14) - 2020-02-18
+
+✨ **New features**
+
+- `BigInteger::getLowestSetBit()` returns the index of the rightmost one bit
+
+## [0.8.13](https://github.com/brick/math/releases/tag/0.8.13) - 2020-02-16
+
+✨ **New features**
+
+- `BigInteger::isEven()` tests whether the number is even
+- `BigInteger::isOdd()` tests whether the number is odd
+- `BigInteger::testBit()` tests if a bit is set
+- `BigInteger::getBitLength()` returns the number of bits in the minimal representation of the number
+
+## [0.8.12](https://github.com/brick/math/releases/tag/0.8.12) - 2020-02-03
+
+🛠️ **Maintenance release**
+
+Classes are now annotated for better static analysis with [psalm](https://psalm.dev/).
+
+This is a maintenance release: no bug fixes, no new features, no breaking changes.
+
+## [0.8.11](https://github.com/brick/math/releases/tag/0.8.11) - 2020-01-23
+
+✨ **New feature**
+
+`BigInteger::powerMod()` performs a power-with-modulo operation. Useful for crypto.
+
+## [0.8.10](https://github.com/brick/math/releases/tag/0.8.10) - 2020-01-21
+
+✨ **New feature**
+
+`BigInteger::mod()` returns the **modulo** of two numbers. The *modulo* differs from the *remainder* when the signs of the operands are different.
+
+## [0.8.9](https://github.com/brick/math/releases/tag/0.8.9) - 2020-01-08
+
+⚡️ **Performance improvements**
+
+A few additional optimizations in `BigInteger` and `BigDecimal` when one of the operands can be returned as is. Thanks to @tomtomsen in #24.
+
+## [0.8.8](https://github.com/brick/math/releases/tag/0.8.8) - 2019-04-25
+
+🐛 **Bug fixes**
+
+- `BigInteger::toBase()` could return an empty string for zero values (BCMath & Native calculators only, GMP calculator unaffected)
+
+✨ **New features**
+
+- `BigInteger::toArbitraryBase()` converts a number to an arbitrary base, using a custom alphabet
+- `BigInteger::fromArbitraryBase()` converts a string in an arbitrary base, using a custom alphabet, back to a number
+
+These methods can be used as the foundation to convert strings between different bases/alphabets, using BigInteger as an intermediate representation.
+
+💩 **Deprecations**
+
+- `BigInteger::parse()` is now deprecated in favour of `fromBase()`
+
+`BigInteger::fromBase()` works the same way as `parse()`, with 2 minor differences:
+
+- the `$base` parameter is required, it does not default to `10`
+- it throws a `NumberFormatException` instead of an `InvalidArgumentException` when the number is malformed
+
+## [0.8.7](https://github.com/brick/math/releases/tag/0.8.7) - 2019-04-20
+
+**Improvements**
+
+- Safer conversion from `float` when using custom locales
+- **Much faster** `NativeCalculator` implementation 🚀
+
+You can expect **at least a 3x performance improvement** for common arithmetic operations when using the library on systems without GMP or BCMath; it gets exponentially faster on multiplications with a high number of digits. This is due to calculations now being performed on whole blocks of digits (the block size depending on the platform, 32-bit or 64-bit) instead of digit-by-digit as before.
+
+## [0.8.6](https://github.com/brick/math/releases/tag/0.8.6) - 2019-04-11
+
+**New method**
+
+`BigNumber::sum()` returns the sum of one or more numbers.
+
+## [0.8.5](https://github.com/brick/math/releases/tag/0.8.5) - 2019-02-12
+
+**Bug fix**: `of()` factory methods could fail when passing a `float` in environments using a `LC_NUMERIC` locale with a decimal separator other than `'.'` (#20).
+
+Thanks @manowark 👍
+
+## [0.8.4](https://github.com/brick/math/releases/tag/0.8.4) - 2018-12-07
+
+**New method**
+
+`BigDecimal::sqrt()` calculates the square root of a decimal number, to a given scale.
+
+## [0.8.3](https://github.com/brick/math/releases/tag/0.8.3) - 2018-12-06
+
+**New method**
+
+`BigInteger::sqrt()` calculates the square root of a number (thanks @peter279k).
+
+**New exception**
+
+`NegativeNumberException` is thrown when calling `sqrt()` on a negative number.
+
+## [0.8.2](https://github.com/brick/math/releases/tag/0.8.2) - 2018-11-08
+
+**Performance update**
+
+- Further improvement of `toInt()` performance
+- `NativeCalculator` can now perform some multiplications more efficiently
+
+## [0.8.1](https://github.com/brick/math/releases/tag/0.8.1) - 2018-11-07
+
+Performance optimization of `toInt()` methods.
+
+## [0.8.0](https://github.com/brick/math/releases/tag/0.8.0) - 2018-10-13
+
+**Breaking changes**
+
+The following deprecated methods have been removed. Use the new method name instead:
+
+| Method removed | Replacement method |
+| --- | --- |
+| `BigDecimal::getIntegral()` | `BigDecimal::getIntegralPart()` |
+| `BigDecimal::getFraction()` | `BigDecimal::getFractionalPart()` |
+
+---
+
+**New features**
+
+`BigInteger` has been augmented with 5 new methods for bitwise operations:
+
+| New method | Description |
+| --- | --- |
+| `and()` | performs a bitwise `AND` operation on two numbers |
+| `or()` | performs a bitwise `OR` operation on two numbers |
+| `xor()` | performs a bitwise `XOR` operation on two numbers |
+| `shiftedLeft()` | returns the number shifted left by a number of bits |
+| `shiftedRight()` | returns the number shifted right by a number of bits |
+
+Thanks to @DASPRiD 👍
+
+## [0.7.3](https://github.com/brick/math/releases/tag/0.7.3) - 2018-08-20
+
+**New method:** `BigDecimal::hasNonZeroFractionalPart()`
+
+**Renamed/deprecated methods:**
+
+- `BigDecimal::getIntegral()` has been renamed to `getIntegralPart()` and is now deprecated
+- `BigDecimal::getFraction()` has been renamed to `getFractionalPart()` and is now deprecated
+
+## [0.7.2](https://github.com/brick/math/releases/tag/0.7.2) - 2018-07-21
+
+**Performance update**
+
+`BigInteger::parse()` and `toBase()` now use GMP's built-in base conversion features when available.
+
+## [0.7.1](https://github.com/brick/math/releases/tag/0.7.1) - 2018-03-01
+
+This is a maintenance release, no code has been changed.
+
+- When installed with `--no-dev`, the autoloader does not autoload tests anymore
+- Tests and other files unnecessary for production are excluded from the dist package
+
+This will help make installations more compact.
+
+## [0.7.0](https://github.com/brick/math/releases/tag/0.7.0) - 2017-10-02
+
+Methods renamed:
+
+- `BigNumber:sign()` has been renamed to `getSign()`
+- `BigDecimal::unscaledValue()` has been renamed to `getUnscaledValue()`
+- `BigDecimal::scale()` has been renamed to `getScale()`
+- `BigDecimal::integral()` has been renamed to `getIntegral()`
+- `BigDecimal::fraction()` has been renamed to `getFraction()`
+- `BigRational::numerator()` has been renamed to `getNumerator()`
+- `BigRational::denominator()` has been renamed to `getDenominator()`
+
+Classes renamed:
+
+- `ArithmeticException` has been renamed to `MathException`
+
+## [0.6.2](https://github.com/brick/math/releases/tag/0.6.2) - 2017-10-02
+
+The base class for all exceptions is now `MathException`.
+`ArithmeticException` has been deprecated, and will be removed in 0.7.0.
+
+## [0.6.1](https://github.com/brick/math/releases/tag/0.6.1) - 2017-10-02
+
+A number of methods have been renamed:
+
+- `BigNumber:sign()` is deprecated; use `getSign()` instead
+- `BigDecimal::unscaledValue()` is deprecated; use `getUnscaledValue()` instead
+- `BigDecimal::scale()` is deprecated; use `getScale()` instead
+- `BigDecimal::integral()` is deprecated; use `getIntegral()` instead
+- `BigDecimal::fraction()` is deprecated; use `getFraction()` instead
+- `BigRational::numerator()` is deprecated; use `getNumerator()` instead
+- `BigRational::denominator()` is deprecated; use `getDenominator()` instead
+
+The old methods will be removed in version 0.7.0.
+
+## [0.6.0](https://github.com/brick/math/releases/tag/0.6.0) - 2017-08-25
+
+- Minimum PHP version is now [7.1](https://gophp71.org/); for PHP 5.6 and PHP 7.0 support, use version `0.5`
+- Deprecated method `BigDecimal::withScale()` has been removed; use `toScale()` instead
+- Method `BigNumber::toInteger()` has been renamed to `toInt()`
+
+## [0.5.4](https://github.com/brick/math/releases/tag/0.5.4) - 2016-10-17
+
+`BigNumber` classes now implement [JsonSerializable](http://php.net/manual/en/class.jsonserializable.php).
+The JSON output is always a string.
+
+## [0.5.3](https://github.com/brick/math/releases/tag/0.5.3) - 2016-03-31
+
+This is a bugfix release. Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.
+
+## [0.5.2](https://github.com/brick/math/releases/tag/0.5.2) - 2015-08-06
+
+The `$scale` parameter of `BigDecimal::dividedBy()` is now optional again.
+
+## [0.5.1](https://github.com/brick/math/releases/tag/0.5.1) - 2015-07-05
+
+**New method: `BigNumber::toScale()`**
+
+This allows to convert any `BigNumber` to a `BigDecimal` with a given scale, using rounding if necessary.
+
+## [0.5.0](https://github.com/brick/math/releases/tag/0.5.0) - 2015-07-04
+
+**New features**
+- Common `BigNumber` interface for all classes, with the following methods:
+  - `sign()` and derived methods (`isZero()`, `isPositive()`, ...)
+  - `compareTo()` and derived methods (`isEqualTo()`, `isGreaterThan()`, ...) that work across different `BigNumber` types
+  - `toBigInteger()`, `toBigDecimal()`, `toBigRational`() conversion methods
+  - `toInteger()` and `toFloat()` conversion methods to native types
+- Unified `of()` behaviour: every class now accepts any type of number, provided that it can be safely converted to the current type
+- New method: `BigDecimal::exactlyDividedBy()`; this method automatically computes the scale of the result, provided that the division yields a finite number of digits
+- New methods: `BigRational::quotient()` and `remainder()`
+- Fine-grained exceptions: `DivisionByZeroException`, `RoundingNecessaryException`, `NumberFormatException`
+- Factory methods `zero()`, `one()` and `ten()` available in all classes
+- Rounding mode reintroduced in `BigInteger::dividedBy()`
+
+This release also comes with many performance improvements.
+
+---
+
+**Breaking changes**
+- `BigInteger`:
+  - `getSign()` is renamed to `sign()`
+  - `toString()` is renamed to `toBase()`
+  - `BigInteger::dividedBy()` now throws an exception by default if the remainder is not zero; use `quotient()` to get the previous behaviour
+- `BigDecimal`:
+  - `getSign()` is renamed to `sign()`
+  - `getUnscaledValue()` is renamed to `unscaledValue()`
+  - `getScale()` is renamed to `scale()`
+  - `getIntegral()` is renamed to `integral()`
+  - `getFraction()` is renamed to `fraction()`
+  - `divideAndRemainder()` is renamed to `quotientAndRemainder()`
+  - `dividedBy()` now takes a **mandatory** `$scale` parameter **before** the rounding mode
+  - `toBigInteger()` does not accept a `$roundingMode` parameter any more
+  - `toBigRational()` does not simplify the fraction any more; explicitly add `->simplified()` to get the previous behaviour
+- `BigRational`:
+  - `getSign()` is renamed to `sign()`
+  - `getNumerator()` is renamed to  `numerator()`
+  - `getDenominator()` is renamed to  `denominator()`
+  - `of()` is renamed to `nd()`, while `parse()` is renamed to `of()`
+- Miscellaneous:
+  - `ArithmeticException` is moved to an `Exception\` sub-namespace
+  - `of()` factory methods now throw `NumberFormatException` instead of `InvalidArgumentException`
+
+## [0.4.3](https://github.com/brick/math/releases/tag/0.4.3) - 2016-03-31
+
+Backport of two bug fixes from the 0.5 branch:
+- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected
+- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.
+
+## [0.4.2](https://github.com/brick/math/releases/tag/0.4.2) - 2015-06-16
+
+New method: `BigDecimal::stripTrailingZeros()`
+
+## [0.4.1](https://github.com/brick/math/releases/tag/0.4.1) - 2015-06-12
+
+Introducing a `BigRational` class, to perform calculations on fractions of any size.
+
+## [0.4.0](https://github.com/brick/math/releases/tag/0.4.0) - 2015-06-12
+
+Rounding modes have been removed from `BigInteger`, and are now a concept specific to `BigDecimal`.
+
+`BigInteger::dividedBy()` now always returns the quotient of the division.
+
+## [0.3.5](https://github.com/brick/math/releases/tag/0.3.5) - 2016-03-31
+
+Backport of two bug fixes from the 0.5 branch:
+
+- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected
+- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.
+
+## [0.3.4](https://github.com/brick/math/releases/tag/0.3.4) - 2015-06-11
+
+New methods:
+- `BigInteger::remainder()` returns the remainder of a division only
+- `BigInteger::gcd()` returns the greatest common divisor of two numbers
+
+## [0.3.3](https://github.com/brick/math/releases/tag/0.3.3) - 2015-06-07
+
+Fix `toString()` not handling negative numbers.
+
+## [0.3.2](https://github.com/brick/math/releases/tag/0.3.2) - 2015-06-07
+
+`BigInteger` and `BigDecimal` now have a `getSign()` method that returns:
+- `-1` if the number is negative
+- `0` if the number is zero
+- `1` if the number is positive
+
+## [0.3.1](https://github.com/brick/math/releases/tag/0.3.1) - 2015-06-05
+
+Minor performance improvements
+
+## [0.3.0](https://github.com/brick/math/releases/tag/0.3.0) - 2015-06-04
+
+The `$roundingMode` and `$scale` parameters have been swapped in `BigDecimal::dividedBy()`.
+
+## [0.2.2](https://github.com/brick/math/releases/tag/0.2.2) - 2015-06-04
+
+Stronger immutability guarantee for `BigInteger` and `BigDecimal`.
+
+So far, it would have been possible to break immutability of these classes by calling the `unserialize()` internal function. This release fixes that.
+
+## [0.2.1](https://github.com/brick/math/releases/tag/0.2.1) - 2015-06-02
+
+Added `BigDecimal::divideAndRemainder()`
+
+## [0.2.0](https://github.com/brick/math/releases/tag/0.2.0) - 2015-05-22
+
+- `min()` and `max()` do not accept an `array` any more, but a variable number of parameters
+- **minimum PHP version is now 5.6**
+- continuous integration with PHP 7
+
+## [0.1.1](https://github.com/brick/math/releases/tag/0.1.1) - 2014-09-01
+
+- Added `BigInteger::power()`
+- Added HHVM support
+
+## [0.1.0](https://github.com/brick/math/releases/tag/0.1.0) - 2014-08-31
+
+First beta release.
+

+ 20 - 0
api/vendor/brick/math/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-present Benjamin Morel
+
+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/brick/math/SECURITY.md

@@ -0,0 +1,17 @@
+# Security Policy
+
+## Supported Versions
+
+Only the last two release streams are supported.
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 0.9.x   | :white_check_mark: |
+| 0.8.x   | :white_check_mark: |
+| < 0.8   | :x:                |
+
+## Reporting a Vulnerability
+
+To report a security vulnerability, please use the
+[Tidelift security contact](https://tidelift.com/security).
+Tidelift will coordinate the fix and disclosure.

+ 35 - 0
api/vendor/brick/math/composer.json

@@ -0,0 +1,35 @@
+{
+    "name": "brick/math",
+    "description": "Arbitrary-precision arithmetic library",
+    "type": "library",
+    "keywords": [
+        "Brick",
+        "Math",
+        "Arbitrary-precision",
+        "Arithmetic",
+        "BigInteger",
+        "BigDecimal",
+        "BigRational",
+        "Bignum"
+    ],
+    "license": "MIT",
+    "require": {
+        "php": "^7.1 || ^8.0",
+        "ext-json": "*"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
+        "php-coveralls/php-coveralls": "^2.2",
+        "vimeo/psalm": "4.9.2"
+    },
+    "autoload": {
+        "psr-4": {
+            "Brick\\Math\\": "src/"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Brick\\Math\\Tests\\": "tests/"
+        }
+    }
+}

+ 895 - 0
api/vendor/brick/math/src/BigDecimal.php

@@ -0,0 +1,895 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math;
+
+use Brick\Math\Exception\DivisionByZeroException;
+use Brick\Math\Exception\MathException;
+use Brick\Math\Exception\NegativeNumberException;
+use Brick\Math\Internal\Calculator;
+
+/**
+ * Immutable, arbitrary-precision signed decimal numbers.
+ *
+ * @psalm-immutable
+ */
+final class BigDecimal extends BigNumber
+{
+    /**
+     * The unscaled value of this decimal number.
+     *
+     * This is a string of digits with an optional leading minus sign.
+     * No leading zero must be present.
+     * No leading minus sign must be present if the value is 0.
+     *
+     * @var string
+     */
+    private $value;
+
+    /**
+     * The scale (number of digits after the decimal point) of this decimal number.
+     *
+     * This must be zero or more.
+     *
+     * @var int
+     */
+    private $scale;
+
+    /**
+     * Protected constructor. Use a factory method to obtain an instance.
+     *
+     * @param string $value The unscaled value, validated.
+     * @param int    $scale The scale, validated.
+     */
+    protected function __construct(string $value, int $scale = 0)
+    {
+        $this->value = $value;
+        $this->scale = $scale;
+    }
+
+    /**
+     * Creates a BigDecimal of the given value.
+     *
+     * @param BigNumber|int|float|string $value
+     *
+     * @return BigDecimal
+     *
+     * @throws MathException If the value cannot be converted to a BigDecimal.
+     *
+     * @psalm-pure
+     */
+    public static function of($value) : BigNumber
+    {
+        return parent::of($value)->toBigDecimal();
+    }
+
+    /**
+     * Creates a BigDecimal from an unscaled value and a scale.
+     *
+     * Example: `(12345, 3)` will result in the BigDecimal `12.345`.
+     *
+     * @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger.
+     * @param int                        $scale The scale of the number, positive or zero.
+     *
+     * @return BigDecimal
+     *
+     * @throws \InvalidArgumentException If the scale is negative.
+     *
+     * @psalm-pure
+     */
+    public static function ofUnscaledValue($value, int $scale = 0) : BigDecimal
+    {
+        if ($scale < 0) {
+            throw new \InvalidArgumentException('The scale cannot be negative.');
+        }
+
+        return new BigDecimal((string) BigInteger::of($value), $scale);
+    }
+
+    /**
+     * Returns a BigDecimal representing zero, with a scale of zero.
+     *
+     * @return BigDecimal
+     *
+     * @psalm-pure
+     */
+    public static function zero() : BigDecimal
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigDecimal|null $zero
+         */
+        static $zero;
+
+        if ($zero === null) {
+            $zero = new BigDecimal('0');
+        }
+
+        return $zero;
+    }
+
+    /**
+     * Returns a BigDecimal representing one, with a scale of zero.
+     *
+     * @return BigDecimal
+     *
+     * @psalm-pure
+     */
+    public static function one() : BigDecimal
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigDecimal|null $one
+         */
+        static $one;
+
+        if ($one === null) {
+            $one = new BigDecimal('1');
+        }
+
+        return $one;
+    }
+
+    /**
+     * Returns a BigDecimal representing ten, with a scale of zero.
+     *
+     * @return BigDecimal
+     *
+     * @psalm-pure
+     */
+    public static function ten() : BigDecimal
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigDecimal|null $ten
+         */
+        static $ten;
+
+        if ($ten === null) {
+            $ten = new BigDecimal('10');
+        }
+
+        return $ten;
+    }
+
+    /**
+     * Returns the sum of this number and the given one.
+     *
+     * The result has a scale of `max($this->scale, $that->scale)`.
+     *
+     * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal.
+     *
+     * @return BigDecimal The result.
+     *
+     * @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
+     */
+    public function plus($that) : BigDecimal
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->value === '0' && $that->scale <= $this->scale) {
+            return $this;
+        }
+
+        if ($this->value === '0' && $this->scale <= $that->scale) {
+            return $that;
+        }
+
+        [$a, $b] = $this->scaleValues($this, $that);
+
+        $value = Calculator::get()->add($a, $b);
+        $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+        return new BigDecimal($value, $scale);
+    }
+
+    /**
+     * Returns the difference of this number and the given one.
+     *
+     * The result has a scale of `max($this->scale, $that->scale)`.
+     *
+     * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal.
+     *
+     * @return BigDecimal The result.
+     *
+     * @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
+     */
+    public function minus($that) : BigDecimal
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->value === '0' && $that->scale <= $this->scale) {
+            return $this;
+        }
+
+        [$a, $b] = $this->scaleValues($this, $that);
+
+        $value = Calculator::get()->sub($a, $b);
+        $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+        return new BigDecimal($value, $scale);
+    }
+
+    /**
+     * Returns the product of this number and the given one.
+     *
+     * The result has a scale of `$this->scale + $that->scale`.
+     *
+     * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal.
+     *
+     * @return BigDecimal The result.
+     *
+     * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal.
+     */
+    public function multipliedBy($that) : BigDecimal
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->value === '1' && $that->scale === 0) {
+            return $this;
+        }
+
+        if ($this->value === '1' && $this->scale === 0) {
+            return $that;
+        }
+
+        $value = Calculator::get()->mul($this->value, $that->value);
+        $scale = $this->scale + $that->scale;
+
+        return new BigDecimal($value, $scale);
+    }
+
+    /**
+     * Returns the result of the division of this number by the given one, at the given scale.
+     *
+     * @param BigNumber|int|float|string $that         The divisor.
+     * @param int|null                   $scale        The desired scale, or null to use the scale of this number.
+     * @param int                        $roundingMode An optional rounding mode.
+     *
+     * @return BigDecimal
+     *
+     * @throws \InvalidArgumentException If the scale or rounding mode is invalid.
+     * @throws MathException             If the number is invalid, is zero, or rounding was necessary.
+     */
+    public function dividedBy($that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->isZero()) {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        if ($scale === null) {
+            $scale = $this->scale;
+        } elseif ($scale < 0) {
+            throw new \InvalidArgumentException('Scale cannot be negative.');
+        }
+
+        if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) {
+            return $this;
+        }
+
+        $p = $this->valueWithMinScale($that->scale + $scale);
+        $q = $that->valueWithMinScale($this->scale - $scale);
+
+        $result = Calculator::get()->divRound($p, $q, $roundingMode);
+
+        return new BigDecimal($result, $scale);
+    }
+
+    /**
+     * Returns the exact result of the division of this number by the given one.
+     *
+     * The scale of the result is automatically calculated to fit all the fraction digits.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
+     *
+     * @return BigDecimal The result.
+     *
+     * @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero,
+     *                       or the result yields an infinite number of digits.
+     */
+    public function exactlyDividedBy($that) : BigDecimal
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->value === '0') {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        [, $b] = $this->scaleValues($this, $that);
+
+        $d = \rtrim($b, '0');
+        $scale = \strlen($b) - \strlen($d);
+
+        $calculator = Calculator::get();
+
+        foreach ([5, 2] as $prime) {
+            for (;;) {
+                $lastDigit = (int) $d[-1];
+
+                if ($lastDigit % $prime !== 0) {
+                    break;
+                }
+
+                $d = $calculator->divQ($d, (string) $prime);
+                $scale++;
+            }
+        }
+
+        return $this->dividedBy($that, $scale)->stripTrailingZeros();
+    }
+
+    /**
+     * Returns this number exponentiated to the given value.
+     *
+     * The result has a scale of `$this->scale * $exponent`.
+     *
+     * @param int $exponent The exponent.
+     *
+     * @return BigDecimal The result.
+     *
+     * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
+     */
+    public function power(int $exponent) : BigDecimal
+    {
+        if ($exponent === 0) {
+            return BigDecimal::one();
+        }
+
+        if ($exponent === 1) {
+            return $this;
+        }
+
+        if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
+            throw new \InvalidArgumentException(\sprintf(
+                'The exponent %d is not in the range 0 to %d.',
+                $exponent,
+                Calculator::MAX_POWER
+            ));
+        }
+
+        return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent);
+    }
+
+    /**
+     * Returns the quotient of the division of this number by this given one.
+     *
+     * The quotient has a scale of `0`.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
+     *
+     * @return BigDecimal The quotient.
+     *
+     * @throws MathException If the divisor is not a valid decimal number, or is zero.
+     */
+    public function quotient($that) : BigDecimal
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->isZero()) {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        $p = $this->valueWithMinScale($that->scale);
+        $q = $that->valueWithMinScale($this->scale);
+
+        $quotient = Calculator::get()->divQ($p, $q);
+
+        return new BigDecimal($quotient, 0);
+    }
+
+    /**
+     * Returns the remainder of the division of this number by this given one.
+     *
+     * The remainder has a scale of `max($this->scale, $that->scale)`.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
+     *
+     * @return BigDecimal The remainder.
+     *
+     * @throws MathException If the divisor is not a valid decimal number, or is zero.
+     */
+    public function remainder($that) : BigDecimal
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->isZero()) {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        $p = $this->valueWithMinScale($that->scale);
+        $q = $that->valueWithMinScale($this->scale);
+
+        $remainder = Calculator::get()->divR($p, $q);
+
+        $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+        return new BigDecimal($remainder, $scale);
+    }
+
+    /**
+     * Returns the quotient and remainder of the division of this number by the given one.
+     *
+     * The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
+     *
+     * @return BigDecimal[] An array containing the quotient and the remainder.
+     *
+     * @throws MathException If the divisor is not a valid decimal number, or is zero.
+     */
+    public function quotientAndRemainder($that) : array
+    {
+        $that = BigDecimal::of($that);
+
+        if ($that->isZero()) {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        $p = $this->valueWithMinScale($that->scale);
+        $q = $that->valueWithMinScale($this->scale);
+
+        [$quotient, $remainder] = Calculator::get()->divQR($p, $q);
+
+        $scale = $this->scale > $that->scale ? $this->scale : $that->scale;
+
+        $quotient = new BigDecimal($quotient, 0);
+        $remainder = new BigDecimal($remainder, $scale);
+
+        return [$quotient, $remainder];
+    }
+
+    /**
+     * Returns the square root of this number, rounded down to the given number of decimals.
+     *
+     * @param int $scale
+     *
+     * @return BigDecimal
+     *
+     * @throws \InvalidArgumentException If the scale is negative.
+     * @throws NegativeNumberException If this number is negative.
+     */
+    public function sqrt(int $scale) : BigDecimal
+    {
+        if ($scale < 0) {
+            throw new \InvalidArgumentException('Scale cannot be negative.');
+        }
+
+        if ($this->value === '0') {
+            return new BigDecimal('0', $scale);
+        }
+
+        if ($this->value[0] === '-') {
+            throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
+        }
+
+        $value = $this->value;
+        $addDigits = 2 * $scale - $this->scale;
+
+        if ($addDigits > 0) {
+            // add zeros
+            $value .= \str_repeat('0', $addDigits);
+        } elseif ($addDigits < 0) {
+            // trim digits
+            if (-$addDigits >= \strlen($this->value)) {
+                // requesting a scale too low, will always yield a zero result
+                return new BigDecimal('0', $scale);
+            }
+
+            $value = \substr($value, 0, $addDigits);
+        }
+
+        $value = Calculator::get()->sqrt($value);
+
+        return new BigDecimal($value, $scale);
+    }
+
+    /**
+     * Returns a copy of this BigDecimal with the decimal point moved $n places to the left.
+     *
+     * @param int $n
+     *
+     * @return BigDecimal
+     */
+    public function withPointMovedLeft(int $n) : BigDecimal
+    {
+        if ($n === 0) {
+            return $this;
+        }
+
+        if ($n < 0) {
+            return $this->withPointMovedRight(-$n);
+        }
+
+        return new BigDecimal($this->value, $this->scale + $n);
+    }
+
+    /**
+     * Returns a copy of this BigDecimal with the decimal point moved $n places to the right.
+     *
+     * @param int $n
+     *
+     * @return BigDecimal
+     */
+    public function withPointMovedRight(int $n) : BigDecimal
+    {
+        if ($n === 0) {
+            return $this;
+        }
+
+        if ($n < 0) {
+            return $this->withPointMovedLeft(-$n);
+        }
+
+        $value = $this->value;
+        $scale = $this->scale - $n;
+
+        if ($scale < 0) {
+            if ($value !== '0') {
+                $value .= \str_repeat('0', -$scale);
+            }
+            $scale = 0;
+        }
+
+        return new BigDecimal($value, $scale);
+    }
+
+    /**
+     * Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part.
+     *
+     * @return BigDecimal
+     */
+    public function stripTrailingZeros() : BigDecimal
+    {
+        if ($this->scale === 0) {
+            return $this;
+        }
+
+        $trimmedValue = \rtrim($this->value, '0');
+
+        if ($trimmedValue === '') {
+            return BigDecimal::zero();
+        }
+
+        $trimmableZeros = \strlen($this->value) - \strlen($trimmedValue);
+
+        if ($trimmableZeros === 0) {
+            return $this;
+        }
+
+        if ($trimmableZeros > $this->scale) {
+            $trimmableZeros = $this->scale;
+        }
+
+        $value = \substr($this->value, 0, -$trimmableZeros);
+        $scale = $this->scale - $trimmableZeros;
+
+        return new BigDecimal($value, $scale);
+    }
+
+    /**
+     * Returns the absolute value of this number.
+     *
+     * @return BigDecimal
+     */
+    public function abs() : BigDecimal
+    {
+        return $this->isNegative() ? $this->negated() : $this;
+    }
+
+    /**
+     * Returns the negated value of this number.
+     *
+     * @return BigDecimal
+     */
+    public function negated() : BigDecimal
+    {
+        return new BigDecimal(Calculator::get()->neg($this->value), $this->scale);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function compareTo($that) : int
+    {
+        $that = BigNumber::of($that);
+
+        if ($that instanceof BigInteger) {
+            $that = $that->toBigDecimal();
+        }
+
+        if ($that instanceof BigDecimal) {
+            [$a, $b] = $this->scaleValues($this, $that);
+
+            return Calculator::get()->cmp($a, $b);
+        }
+
+        return - $that->compareTo($this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSign() : int
+    {
+        return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
+    }
+
+    /**
+     * @return BigInteger
+     */
+    public function getUnscaledValue() : BigInteger
+    {
+        return BigInteger::create($this->value);
+    }
+
+    /**
+     * @return int
+     */
+    public function getScale() : int
+    {
+        return $this->scale;
+    }
+
+    /**
+     * Returns a string representing the integral part of this decimal number.
+     *
+     * Example: `-123.456` => `-123`.
+     *
+     * @return string
+     */
+    public function getIntegralPart() : string
+    {
+        if ($this->scale === 0) {
+            return $this->value;
+        }
+
+        $value = $this->getUnscaledValueWithLeadingZeros();
+
+        return \substr($value, 0, -$this->scale);
+    }
+
+    /**
+     * Returns a string representing the fractional part of this decimal number.
+     *
+     * If the scale is zero, an empty string is returned.
+     *
+     * Examples: `-123.456` => '456', `123` => ''.
+     *
+     * @return string
+     */
+    public function getFractionalPart() : string
+    {
+        if ($this->scale === 0) {
+            return '';
+        }
+
+        $value = $this->getUnscaledValueWithLeadingZeros();
+
+        return \substr($value, -$this->scale);
+    }
+
+    /**
+     * Returns whether this decimal number has a non-zero fractional part.
+     *
+     * @return bool
+     */
+    public function hasNonZeroFractionalPart() : bool
+    {
+        return $this->getFractionalPart() !== \str_repeat('0', $this->scale);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigInteger() : BigInteger
+    {
+        $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0);
+
+        return BigInteger::create($zeroScaleDecimal->value);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigDecimal() : BigDecimal
+    {
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigRational() : BigRational
+    {
+        $numerator = BigInteger::create($this->value);
+        $denominator = BigInteger::create('1' . \str_repeat('0', $this->scale));
+
+        return BigRational::create($numerator, $denominator, false);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
+    {
+        if ($scale === $this->scale) {
+            return $this;
+        }
+
+        return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toInt() : int
+    {
+        return $this->toBigInteger()->toInt();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toFloat() : float
+    {
+        return (float) (string) $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString() : string
+    {
+        if ($this->scale === 0) {
+            return $this->value;
+        }
+
+        $value = $this->getUnscaledValueWithLeadingZeros();
+
+        return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale);
+    }
+
+    /**
+     * This method is required for serializing the object and SHOULD NOT be accessed directly.
+     *
+     * @internal
+     *
+     * @return array{value: string, scale: int}
+     */
+    public function __serialize(): array
+    {
+        return ['value' => $this->value, 'scale' => $this->scale];
+    }
+
+    /**
+     * This method is only here to allow unserializing the object and cannot be accessed directly.
+     *
+     * @internal
+     * @psalm-suppress RedundantPropertyInitializationCheck
+     *
+     * @param array{value: string, scale: int} $data
+     *
+     * @return void
+     *
+     * @throws \LogicException
+     */
+    public function __unserialize(array $data): void
+    {
+        if (isset($this->value)) {
+            throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
+        }
+
+        $this->value = $data['value'];
+        $this->scale = $data['scale'];
+    }
+
+    /**
+     * This method is required by interface Serializable and SHOULD NOT be accessed directly.
+     *
+     * @internal
+     *
+     * @return string
+     */
+    public function serialize() : string
+    {
+        return $this->value . ':' . $this->scale;
+    }
+
+    /**
+     * This method is only here to implement interface Serializable and cannot be accessed directly.
+     *
+     * @internal
+     * @psalm-suppress RedundantPropertyInitializationCheck
+     *
+     * @param string $value
+     *
+     * @return void
+     *
+     * @throws \LogicException
+     */
+    public function unserialize($value) : void
+    {
+        if (isset($this->value)) {
+            throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
+        }
+
+        [$value, $scale] = \explode(':', $value);
+
+        $this->value = $value;
+        $this->scale = (int) $scale;
+    }
+
+    /**
+     * Puts the internal values of the given decimal numbers on the same scale.
+     *
+     * @param BigDecimal $x The first decimal number.
+     * @param BigDecimal $y The second decimal number.
+     *
+     * @return array{string, string} The scaled integer values of $x and $y.
+     */
+    private function scaleValues(BigDecimal $x, BigDecimal $y) : array
+    {
+        $a = $x->value;
+        $b = $y->value;
+
+        if ($b !== '0' && $x->scale > $y->scale) {
+            $b .= \str_repeat('0', $x->scale - $y->scale);
+        } elseif ($a !== '0' && $x->scale < $y->scale) {
+            $a .= \str_repeat('0', $y->scale - $x->scale);
+        }
+
+        return [$a, $b];
+    }
+
+    /**
+     * @param int $scale
+     *
+     * @return string
+     */
+    private function valueWithMinScale(int $scale) : string
+    {
+        $value = $this->value;
+
+        if ($this->value !== '0' && $scale > $this->scale) {
+            $value .= \str_repeat('0', $scale - $this->scale);
+        }
+
+        return $value;
+    }
+
+    /**
+     * Adds leading zeros if necessary to the unscaled value to represent the full decimal number.
+     *
+     * @return string
+     */
+    private function getUnscaledValueWithLeadingZeros() : string
+    {
+        $value = $this->value;
+        $targetLength = $this->scale + 1;
+        $negative = ($value[0] === '-');
+        $length = \strlen($value);
+
+        if ($negative) {
+            $length--;
+        }
+
+        if ($length >= $targetLength) {
+            return $this->value;
+        }
+
+        if ($negative) {
+            $value = \substr($value, 1);
+        }
+
+        $value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT);
+
+        if ($negative) {
+            $value = '-' . $value;
+        }
+
+        return $value;
+    }
+}

+ 1184 - 0
api/vendor/brick/math/src/BigInteger.php

@@ -0,0 +1,1184 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math;
+
+use Brick\Math\Exception\DivisionByZeroException;
+use Brick\Math\Exception\IntegerOverflowException;
+use Brick\Math\Exception\MathException;
+use Brick\Math\Exception\NegativeNumberException;
+use Brick\Math\Exception\NumberFormatException;
+use Brick\Math\Internal\Calculator;
+
+/**
+ * An arbitrary-size integer.
+ *
+ * All methods accepting a number as a parameter accept either a BigInteger instance,
+ * an integer, or a string representing an arbitrary size integer.
+ *
+ * @psalm-immutable
+ */
+final class BigInteger extends BigNumber
+{
+    /**
+     * The value, as a string of digits with optional leading minus sign.
+     *
+     * No leading zeros must be present.
+     * No leading minus sign must be present if the number is zero.
+     *
+     * @var string
+     */
+    private $value;
+
+    /**
+     * Protected constructor. Use a factory method to obtain an instance.
+     *
+     * @param string $value A string of digits, with optional leading minus sign.
+     */
+    protected function __construct(string $value)
+    {
+        $this->value = $value;
+    }
+
+    /**
+     * Creates a BigInteger of the given value.
+     *
+     * @param BigNumber|int|float|string $value
+     *
+     * @return BigInteger
+     *
+     * @throws MathException If the value cannot be converted to a BigInteger.
+     *
+     * @psalm-pure
+     */
+    public static function of($value) : BigNumber
+    {
+        return parent::of($value)->toBigInteger();
+    }
+
+    /**
+     * Creates a number from a string in a given base.
+     *
+     * The string can optionally be prefixed with the `+` or `-` sign.
+     *
+     * Bases greater than 36 are not supported by this method, as there is no clear consensus on which of the lowercase
+     * or uppercase characters should come first. Instead, this method accepts any base up to 36, and does not
+     * differentiate lowercase and uppercase characters, which are considered equal.
+     *
+     * For bases greater than 36, and/or custom alphabets, use the fromArbitraryBase() method.
+     *
+     * @param string $number The number to convert, in the given base.
+     * @param int    $base   The base of the number, between 2 and 36.
+     *
+     * @return BigInteger
+     *
+     * @throws NumberFormatException     If the number is empty, or contains invalid chars for the given base.
+     * @throws \InvalidArgumentException If the base is out of range.
+     *
+     * @psalm-pure
+     */
+    public static function fromBase(string $number, int $base) : BigInteger
+    {
+        if ($number === '') {
+            throw new NumberFormatException('The number cannot be empty.');
+        }
+
+        if ($base < 2 || $base > 36) {
+            throw new \InvalidArgumentException(\sprintf('Base %d is not in range 2 to 36.', $base));
+        }
+
+        if ($number[0] === '-') {
+            $sign = '-';
+            $number = \substr($number, 1);
+        } elseif ($number[0] === '+') {
+            $sign = '';
+            $number = \substr($number, 1);
+        } else {
+            $sign = '';
+        }
+
+        if ($number === '') {
+            throw new NumberFormatException('The number cannot be empty.');
+        }
+
+        $number = \ltrim($number, '0');
+
+        if ($number === '') {
+            // The result will be the same in any base, avoid further calculation.
+            return BigInteger::zero();
+        }
+
+        if ($number === '1') {
+            // The result will be the same in any base, avoid further calculation.
+            return new BigInteger($sign . '1');
+        }
+
+        $pattern = '/[^' . \substr(Calculator::ALPHABET, 0, $base) . ']/';
+
+        if (\preg_match($pattern, \strtolower($number), $matches) === 1) {
+            throw new NumberFormatException(\sprintf('"%s" is not a valid character in base %d.', $matches[0], $base));
+        }
+
+        if ($base === 10) {
+            // The number is usable as is, avoid further calculation.
+            return new BigInteger($sign . $number);
+        }
+
+        $result = Calculator::get()->fromBase($number, $base);
+
+        return new BigInteger($sign . $result);
+    }
+
+    /**
+     * Parses a string containing an integer in an arbitrary base, using a custom alphabet.
+     *
+     * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers.
+     *
+     * @param string $number   The number to parse.
+     * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
+     *
+     * @return BigInteger
+     *
+     * @throws NumberFormatException     If the given number is empty or contains invalid chars for the given alphabet.
+     * @throws \InvalidArgumentException If the alphabet does not contain at least 2 chars.
+     *
+     * @psalm-pure
+     */
+    public static function fromArbitraryBase(string $number, string $alphabet) : BigInteger
+    {
+        if ($number === '') {
+            throw new NumberFormatException('The number cannot be empty.');
+        }
+
+        $base = \strlen($alphabet);
+
+        if ($base < 2) {
+            throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
+        }
+
+        $pattern = '/[^' . \preg_quote($alphabet, '/') . ']/';
+
+        if (\preg_match($pattern, $number, $matches) === 1) {
+            throw NumberFormatException::charNotInAlphabet($matches[0]);
+        }
+
+        $number = Calculator::get()->fromArbitraryBase($number, $alphabet, $base);
+
+        return new BigInteger($number);
+    }
+
+    /**
+     * Translates a string of bytes containing the binary representation of a BigInteger into a BigInteger.
+     *
+     * The input string is assumed to be in big-endian byte-order: the most significant byte is in the zeroth element.
+     *
+     * If `$signed` is true, the input is assumed to be in two's-complement representation, and the leading bit is
+     * interpreted as a sign bit. If `$signed` is false, the input is interpreted as an unsigned number, and the
+     * resulting BigInteger will always be positive or zero.
+     *
+     * This method can be used to retrieve a number exported by `toBytes()`, as long as the `$signed` flags match.
+     *
+     * @param string $value  The byte string.
+     * @param bool   $signed Whether to interpret as a signed number in two's-complement representation with a leading
+     *                       sign bit.
+     *
+     * @return BigInteger
+     *
+     * @throws NumberFormatException If the string is empty.
+     */
+    public static function fromBytes(string $value, bool $signed = true) : BigInteger
+    {
+        if ($value === '') {
+            throw new NumberFormatException('The byte string must not be empty.');
+        }
+
+        $twosComplement = false;
+
+        if ($signed) {
+            $x = \ord($value[0]);
+
+            if (($twosComplement = ($x >= 0x80))) {
+                $value = ~$value;
+            }
+        }
+
+        $number = self::fromBase(\bin2hex($value), 16);
+
+        if ($twosComplement) {
+            return $number->plus(1)->negated();
+        }
+
+        return $number;
+    }
+
+    /**
+     * Generates a pseudo-random number in the range 0 to 2^numBits - 1.
+     *
+     * Using the default random bytes generator, this method is suitable for cryptographic use.
+     *
+     * @psalm-param callable(int): string $randomBytesGenerator
+     *
+     * @param int           $numBits              The number of bits.
+     * @param callable|null $randomBytesGenerator A function that accepts a number of bytes as an integer, and returns a
+     *                                            string of random bytes of the given length. Defaults to the
+     *                                            `random_bytes()` function.
+     *
+     * @return BigInteger
+     *
+     * @throws \InvalidArgumentException If $numBits is negative.
+     */
+    public static function randomBits(int $numBits, ?callable $randomBytesGenerator = null) : BigInteger
+    {
+        if ($numBits < 0) {
+            throw new \InvalidArgumentException('The number of bits cannot be negative.');
+        }
+
+        if ($numBits === 0) {
+            return BigInteger::zero();
+        }
+
+        if ($randomBytesGenerator === null) {
+            $randomBytesGenerator = 'random_bytes';
+        }
+
+        $byteLength = \intdiv($numBits - 1, 8) + 1;
+
+        $extraBits = ($byteLength * 8 - $numBits);
+        $bitmask   = \chr(0xFF >> $extraBits);
+
+        $randomBytes    = $randomBytesGenerator($byteLength);
+        $randomBytes[0] = $randomBytes[0] & $bitmask;
+
+        return self::fromBytes($randomBytes, false);
+    }
+
+    /**
+     * Generates a pseudo-random number between `$min` and `$max`.
+     *
+     * Using the default random bytes generator, this method is suitable for cryptographic use.
+     *
+     * @psalm-param (callable(int): string)|null $randomBytesGenerator
+     *
+     * @param BigNumber|int|float|string $min                  The lower bound. Must be convertible to a BigInteger.
+     * @param BigNumber|int|float|string $max                  The upper bound. Must be convertible to a BigInteger.
+     * @param callable|null              $randomBytesGenerator A function that accepts a number of bytes as an integer,
+     *                                                         and returns a string of random bytes of the given length.
+     *                                                         Defaults to the `random_bytes()` function.
+     *
+     * @return BigInteger
+     *
+     * @throws MathException If one of the parameters cannot be converted to a BigInteger,
+     *                       or `$min` is greater than `$max`.
+     */
+    public static function randomRange($min, $max, ?callable $randomBytesGenerator = null) : BigInteger
+    {
+        $min = BigInteger::of($min);
+        $max = BigInteger::of($max);
+
+        if ($min->isGreaterThan($max)) {
+            throw new MathException('$min cannot be greater than $max.');
+        }
+
+        if ($min->isEqualTo($max)) {
+            return $min;
+        }
+
+        $diff      = $max->minus($min);
+        $bitLength = $diff->getBitLength();
+
+        // try until the number is in range (50% to 100% chance of success)
+        do {
+            $randomNumber = self::randomBits($bitLength, $randomBytesGenerator);
+        } while ($randomNumber->isGreaterThan($diff));
+
+        return $randomNumber->plus($min);
+    }
+
+    /**
+     * Returns a BigInteger representing zero.
+     *
+     * @return BigInteger
+     *
+     * @psalm-pure
+     */
+    public static function zero() : BigInteger
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigInteger|null $zero
+         */
+        static $zero;
+
+        if ($zero === null) {
+            $zero = new BigInteger('0');
+        }
+
+        return $zero;
+    }
+
+    /**
+     * Returns a BigInteger representing one.
+     *
+     * @return BigInteger
+     *
+     * @psalm-pure
+     */
+    public static function one() : BigInteger
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigInteger|null $one
+         */
+        static $one;
+
+        if ($one === null) {
+            $one = new BigInteger('1');
+        }
+
+        return $one;
+    }
+
+    /**
+     * Returns a BigInteger representing ten.
+     *
+     * @return BigInteger
+     *
+     * @psalm-pure
+     */
+    public static function ten() : BigInteger
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigInteger|null $ten
+         */
+        static $ten;
+
+        if ($ten === null) {
+            $ten = new BigInteger('10');
+        }
+
+        return $ten;
+    }
+
+    /**
+     * Returns the sum of this number and the given one.
+     *
+     * @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigInteger.
+     *
+     * @return BigInteger The result.
+     *
+     * @throws MathException If the number is not valid, or is not convertible to a BigInteger.
+     */
+    public function plus($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '0') {
+            return $this;
+        }
+
+        if ($this->value === '0') {
+            return $that;
+        }
+
+        $value = Calculator::get()->add($this->value, $that->value);
+
+        return new BigInteger($value);
+    }
+
+    /**
+     * Returns the difference of this number and the given one.
+     *
+     * @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigInteger.
+     *
+     * @return BigInteger The result.
+     *
+     * @throws MathException If the number is not valid, or is not convertible to a BigInteger.
+     */
+    public function minus($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '0') {
+            return $this;
+        }
+
+        $value = Calculator::get()->sub($this->value, $that->value);
+
+        return new BigInteger($value);
+    }
+
+    /**
+     * Returns the product of this number and the given one.
+     *
+     * @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigInteger.
+     *
+     * @return BigInteger The result.
+     *
+     * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger.
+     */
+    public function multipliedBy($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '1') {
+            return $this;
+        }
+
+        if ($this->value === '1') {
+            return $that;
+        }
+
+        $value = Calculator::get()->mul($this->value, $that->value);
+
+        return new BigInteger($value);
+    }
+
+    /**
+     * Returns the result of the division of this number by the given one.
+     *
+     * @param BigNumber|int|float|string $that         The divisor. Must be convertible to a BigInteger.
+     * @param int                        $roundingMode An optional rounding mode.
+     *
+     * @return BigInteger The result.
+     *
+     * @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero,
+     *                       or RoundingMode::UNNECESSARY is used and the remainder is not zero.
+     */
+    public function dividedBy($that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '1') {
+            return $this;
+        }
+
+        if ($that->value === '0') {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        $result = Calculator::get()->divRound($this->value, $that->value, $roundingMode);
+
+        return new BigInteger($result);
+    }
+
+    /**
+     * Returns this number exponentiated to the given value.
+     *
+     * @param int $exponent The exponent.
+     *
+     * @return BigInteger The result.
+     *
+     * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
+     */
+    public function power(int $exponent) : BigInteger
+    {
+        if ($exponent === 0) {
+            return BigInteger::one();
+        }
+
+        if ($exponent === 1) {
+            return $this;
+        }
+
+        if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
+            throw new \InvalidArgumentException(\sprintf(
+                'The exponent %d is not in the range 0 to %d.',
+                $exponent,
+                Calculator::MAX_POWER
+            ));
+        }
+
+        return new BigInteger(Calculator::get()->pow($this->value, $exponent));
+    }
+
+    /**
+     * Returns the quotient of the division of this number by the given one.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
+     *
+     * @return BigInteger
+     *
+     * @throws DivisionByZeroException If the divisor is zero.
+     */
+    public function quotient($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '1') {
+            return $this;
+        }
+
+        if ($that->value === '0') {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        $quotient = Calculator::get()->divQ($this->value, $that->value);
+
+        return new BigInteger($quotient);
+    }
+
+    /**
+     * Returns the remainder of the division of this number by the given one.
+     *
+     * The remainder, when non-zero, has the same sign as the dividend.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
+     *
+     * @return BigInteger
+     *
+     * @throws DivisionByZeroException If the divisor is zero.
+     */
+    public function remainder($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '1') {
+            return BigInteger::zero();
+        }
+
+        if ($that->value === '0') {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        $remainder = Calculator::get()->divR($this->value, $that->value);
+
+        return new BigInteger($remainder);
+    }
+
+    /**
+     * Returns the quotient and remainder of the division of this number by the given one.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
+     *
+     * @return BigInteger[] An array containing the quotient and the remainder.
+     *
+     * @throws DivisionByZeroException If the divisor is zero.
+     */
+    public function quotientAndRemainder($that) : array
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '0') {
+            throw DivisionByZeroException::divisionByZero();
+        }
+
+        [$quotient, $remainder] = Calculator::get()->divQR($this->value, $that->value);
+
+        return [
+            new BigInteger($quotient),
+            new BigInteger($remainder)
+        ];
+    }
+
+    /**
+     * Returns the modulo of this number and the given one.
+     *
+     * The modulo operation yields the same result as the remainder operation when both operands are of the same sign,
+     * and may differ when signs are different.
+     *
+     * The result of the modulo operation, when non-zero, has the same sign as the divisor.
+     *
+     * @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
+     *
+     * @return BigInteger
+     *
+     * @throws DivisionByZeroException If the divisor is zero.
+     */
+    public function mod($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '0') {
+            throw DivisionByZeroException::modulusMustNotBeZero();
+        }
+
+        $value = Calculator::get()->mod($this->value, $that->value);
+
+        return new BigInteger($value);
+    }
+
+    /**
+     * Returns the modular multiplicative inverse of this BigInteger modulo $m.
+     *
+     * @param BigInteger $m
+     *
+     * @return BigInteger
+     *
+     * @throws DivisionByZeroException If $m is zero.
+     * @throws NegativeNumberException If $m is negative.
+     * @throws MathException           If this BigInteger has no multiplicative inverse mod m (that is, this BigInteger
+     *                                 is not relatively prime to m).
+     */
+    public function modInverse(BigInteger $m) : BigInteger
+    {
+        if ($m->value === '0') {
+            throw DivisionByZeroException::modulusMustNotBeZero();
+        }
+
+        if ($m->isNegative()) {
+            throw new NegativeNumberException('Modulus must not be negative.');
+        }
+
+        if ($m->value === '1') {
+            return BigInteger::zero();
+        }
+
+        $value = Calculator::get()->modInverse($this->value, $m->value);
+
+        if ($value === null) {
+            throw new MathException('Unable to compute the modInverse for the given modulus.');
+        }
+
+        return new BigInteger($value);
+    }
+
+    /**
+     * Returns this number raised into power with modulo.
+     *
+     * This operation only works on positive numbers.
+     *
+     * @param BigNumber|int|float|string $exp The exponent. Must be positive or zero.
+     * @param BigNumber|int|float|string $mod The modulus. Must be strictly positive.
+     *
+     * @return BigInteger
+     *
+     * @throws NegativeNumberException If any of the operands is negative.
+     * @throws DivisionByZeroException If the modulus is zero.
+     */
+    public function modPow($exp, $mod) : BigInteger
+    {
+        $exp = BigInteger::of($exp);
+        $mod = BigInteger::of($mod);
+
+        if ($this->isNegative() || $exp->isNegative() || $mod->isNegative()) {
+            throw new NegativeNumberException('The operands cannot be negative.');
+        }
+
+        if ($mod->isZero()) {
+            throw DivisionByZeroException::modulusMustNotBeZero();
+        }
+
+        $result = Calculator::get()->modPow($this->value, $exp->value, $mod->value);
+
+        return new BigInteger($result);
+    }
+
+    /**
+     * Returns the greatest common divisor of this number and the given one.
+     *
+     * The GCD is always positive, unless both operands are zero, in which case it is zero.
+     *
+     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
+     *
+     * @return BigInteger
+     */
+    public function gcd($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        if ($that->value === '0' && $this->value[0] !== '-') {
+            return $this;
+        }
+
+        if ($this->value === '0' && $that->value[0] !== '-') {
+            return $that;
+        }
+
+        $value = Calculator::get()->gcd($this->value, $that->value);
+
+        return new BigInteger($value);
+    }
+
+    /**
+     * Returns the integer square root number of this number, rounded down.
+     *
+     * The result is the largest x such that x² ≤ n.
+     *
+     * @return BigInteger
+     *
+     * @throws NegativeNumberException If this number is negative.
+     */
+    public function sqrt() : BigInteger
+    {
+        if ($this->value[0] === '-') {
+            throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
+        }
+
+        $value = Calculator::get()->sqrt($this->value);
+
+        return new BigInteger($value);
+    }
+
+    /**
+     * Returns the absolute value of this number.
+     *
+     * @return BigInteger
+     */
+    public function abs() : BigInteger
+    {
+        return $this->isNegative() ? $this->negated() : $this;
+    }
+
+    /**
+     * Returns the inverse of this number.
+     *
+     * @return BigInteger
+     */
+    public function negated() : BigInteger
+    {
+        return new BigInteger(Calculator::get()->neg($this->value));
+    }
+
+    /**
+     * Returns the integer bitwise-and combined with another integer.
+     *
+     * This method returns a negative BigInteger if and only if both operands are negative.
+     *
+     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
+     *
+     * @return BigInteger
+     */
+    public function and($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        return new BigInteger(Calculator::get()->and($this->value, $that->value));
+    }
+
+    /**
+     * Returns the integer bitwise-or combined with another integer.
+     *
+     * This method returns a negative BigInteger if and only if either of the operands is negative.
+     *
+     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
+     *
+     * @return BigInteger
+     */
+    public function or($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        return new BigInteger(Calculator::get()->or($this->value, $that->value));
+    }
+
+    /**
+     * Returns the integer bitwise-xor combined with another integer.
+     *
+     * This method returns a negative BigInteger if and only if exactly one of the operands is negative.
+     *
+     * @param BigNumber|int|float|string $that The operand. Must be convertible to an integer number.
+     *
+     * @return BigInteger
+     */
+    public function xor($that) : BigInteger
+    {
+        $that = BigInteger::of($that);
+
+        return new BigInteger(Calculator::get()->xor($this->value, $that->value));
+    }
+
+    /**
+     * Returns the bitwise-not of this BigInteger.
+     *
+     * @return BigInteger
+     */
+    public function not() : BigInteger
+    {
+        return $this->negated()->minus(1);
+    }
+
+    /**
+     * Returns the integer left shifted by a given number of bits.
+     *
+     * @param int $distance The distance to shift.
+     *
+     * @return BigInteger
+     */
+    public function shiftedLeft(int $distance) : BigInteger
+    {
+        if ($distance === 0) {
+            return $this;
+        }
+
+        if ($distance < 0) {
+            return $this->shiftedRight(- $distance);
+        }
+
+        return $this->multipliedBy(BigInteger::of(2)->power($distance));
+    }
+
+    /**
+     * Returns the integer right shifted by a given number of bits.
+     *
+     * @param int $distance The distance to shift.
+     *
+     * @return BigInteger
+     */
+    public function shiftedRight(int $distance) : BigInteger
+    {
+        if ($distance === 0) {
+            return $this;
+        }
+
+        if ($distance < 0) {
+            return $this->shiftedLeft(- $distance);
+        }
+
+        $operand = BigInteger::of(2)->power($distance);
+
+        if ($this->isPositiveOrZero()) {
+            return $this->quotient($operand);
+        }
+
+        return $this->dividedBy($operand, RoundingMode::UP);
+    }
+
+    /**
+     * Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit.
+     *
+     * For positive BigIntegers, this is equivalent to the number of bits in the ordinary binary representation.
+     * Computes (ceil(log2(this < 0 ? -this : this+1))).
+     *
+     * @return int
+     */
+    public function getBitLength() : int
+    {
+        if ($this->value === '0') {
+            return 0;
+        }
+
+        if ($this->isNegative()) {
+            return $this->abs()->minus(1)->getBitLength();
+        }
+
+        return \strlen($this->toBase(2));
+    }
+
+    /**
+     * Returns the index of the rightmost (lowest-order) one bit in this BigInteger.
+     *
+     * Returns -1 if this BigInteger contains no one bits.
+     *
+     * @return int
+     */
+    public function getLowestSetBit() : int
+    {
+        $n = $this;
+        $bitLength = $this->getBitLength();
+
+        for ($i = 0; $i <= $bitLength; $i++) {
+            if ($n->isOdd()) {
+                return $i;
+            }
+
+            $n = $n->shiftedRight(1);
+        }
+
+        return -1;
+    }
+
+    /**
+     * Returns whether this number is even.
+     *
+     * @return bool
+     */
+    public function isEven() : bool
+    {
+        return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], true);
+    }
+
+    /**
+     * Returns whether this number is odd.
+     *
+     * @return bool
+     */
+    public function isOdd() : bool
+    {
+        return \in_array($this->value[-1], ['1', '3', '5', '7', '9'], true);
+    }
+
+    /**
+     * Returns true if and only if the designated bit is set.
+     *
+     * Computes ((this & (1<<n)) != 0).
+     *
+     * @param int $n The bit to test, 0-based.
+     *
+     * @return bool
+     *
+     * @throws \InvalidArgumentException If the bit to test is negative.
+     */
+    public function testBit(int $n) : bool
+    {
+        if ($n < 0) {
+            throw new \InvalidArgumentException('The bit to test cannot be negative.');
+        }
+
+        return $this->shiftedRight($n)->isOdd();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function compareTo($that) : int
+    {
+        $that = BigNumber::of($that);
+
+        if ($that instanceof BigInteger) {
+            return Calculator::get()->cmp($this->value, $that->value);
+        }
+
+        return - $that->compareTo($this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSign() : int
+    {
+        return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigInteger() : BigInteger
+    {
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigDecimal() : BigDecimal
+    {
+        return BigDecimal::create($this->value);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigRational() : BigRational
+    {
+        return BigRational::create($this, BigInteger::one(), false);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
+    {
+        return $this->toBigDecimal()->toScale($scale, $roundingMode);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toInt() : int
+    {
+        $intValue = (int) $this->value;
+
+        if ($this->value !== (string) $intValue) {
+            throw IntegerOverflowException::toIntOverflow($this);
+        }
+
+        return $intValue;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toFloat() : float
+    {
+        return (float) $this->value;
+    }
+
+    /**
+     * Returns a string representation of this number in the given base.
+     *
+     * The output will always be lowercase for bases greater than 10.
+     *
+     * @param int $base
+     *
+     * @return string
+     *
+     * @throws \InvalidArgumentException If the base is out of range.
+     */
+    public function toBase(int $base) : string
+    {
+        if ($base === 10) {
+            return $this->value;
+        }
+
+        if ($base < 2 || $base > 36) {
+            throw new \InvalidArgumentException(\sprintf('Base %d is out of range [2, 36]', $base));
+        }
+
+        return Calculator::get()->toBase($this->value, $base);
+    }
+
+    /**
+     * Returns a string representation of this number in an arbitrary base with a custom alphabet.
+     *
+     * Because this method accepts an alphabet with any character, including dash, it does not handle negative numbers;
+     * a NegativeNumberException will be thrown when attempting to call this method on a negative number.
+     *
+     * @param string $alphabet The alphabet, for example '01' for base 2, or '01234567' for base 8.
+     *
+     * @return string
+     *
+     * @throws NegativeNumberException   If this number is negative.
+     * @throws \InvalidArgumentException If the given alphabet does not contain at least 2 chars.
+     */
+    public function toArbitraryBase(string $alphabet) : string
+    {
+        $base = \strlen($alphabet);
+
+        if ($base < 2) {
+            throw new \InvalidArgumentException('The alphabet must contain at least 2 chars.');
+        }
+
+        if ($this->value[0] === '-') {
+            throw new NegativeNumberException(__FUNCTION__ . '() does not support negative numbers.');
+        }
+
+        return Calculator::get()->toArbitraryBase($this->value, $alphabet, $base);
+    }
+
+    /**
+     * Returns a string of bytes containing the binary representation of this BigInteger.
+     *
+     * The string is in big-endian byte-order: the most significant byte is in the zeroth element.
+     *
+     * If `$signed` is true, the output will be in two's-complement representation, and a sign bit will be prepended to
+     * the output. If `$signed` is false, no sign bit will be prepended, and this method will throw an exception if the
+     * number is negative.
+     *
+     * The string will contain the minimum number of bytes required to represent this BigInteger, including a sign bit
+     * if `$signed` is true.
+     *
+     * This representation is compatible with the `fromBytes()` factory method, as long as the `$signed` flags match.
+     *
+     * @param bool $signed Whether to output a signed number in two's-complement representation with a leading sign bit.
+     *
+     * @return string
+     *
+     * @throws NegativeNumberException If $signed is false, and the number is negative.
+     */
+    public function toBytes(bool $signed = true) : string
+    {
+        if (! $signed && $this->isNegative()) {
+            throw new NegativeNumberException('Cannot convert a negative number to a byte string when $signed is false.');
+        }
+
+        $hex = $this->abs()->toBase(16);
+
+        if (\strlen($hex) % 2 !== 0) {
+            $hex = '0' . $hex;
+        }
+
+        $baseHexLength = \strlen($hex);
+
+        if ($signed) {
+            if ($this->isNegative()) {
+                $bin = \hex2bin($hex);
+                assert($bin !== false);
+
+                $hex = \bin2hex(~$bin);
+                $hex = self::fromBase($hex, 16)->plus(1)->toBase(16);
+
+                $hexLength = \strlen($hex);
+
+                if ($hexLength < $baseHexLength) {
+                    $hex = \str_repeat('0', $baseHexLength - $hexLength) . $hex;
+                }
+
+                if ($hex[0] < '8') {
+                    $hex = 'FF' . $hex;
+                }
+            } else {
+                if ($hex[0] >= '8') {
+                    $hex = '00' . $hex;
+                }
+            }
+        }
+
+        return \hex2bin($hex);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString() : string
+    {
+        return $this->value;
+    }
+
+    /**
+     * This method is required for serializing the object and SHOULD NOT be accessed directly.
+     *
+     * @internal
+     *
+     * @return array{value: string}
+     */
+    public function __serialize(): array
+    {
+        return ['value' => $this->value];
+    }
+
+    /**
+     * This method is only here to allow unserializing the object and cannot be accessed directly.
+     *
+     * @internal
+     * @psalm-suppress RedundantPropertyInitializationCheck
+     *
+     * @param array{value: string} $data
+     *
+     * @return void
+     *
+     * @throws \LogicException
+     */
+    public function __unserialize(array $data): void
+    {
+        if (isset($this->value)) {
+            throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
+        }
+
+        $this->value = $data['value'];
+    }
+
+    /**
+     * This method is required by interface Serializable and SHOULD NOT be accessed directly.
+     *
+     * @internal
+     *
+     * @return string
+     */
+    public function serialize() : string
+    {
+        return $this->value;
+    }
+
+    /**
+     * This method is only here to implement interface Serializable and cannot be accessed directly.
+     *
+     * @internal
+     * @psalm-suppress RedundantPropertyInitializationCheck
+     *
+     * @param string $value
+     *
+     * @return void
+     *
+     * @throws \LogicException
+     */
+    public function unserialize($value) : void
+    {
+        if (isset($this->value)) {
+            throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
+        }
+
+        $this->value = $value;
+    }
+}

+ 572 - 0
api/vendor/brick/math/src/BigNumber.php

@@ -0,0 +1,572 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math;
+
+use Brick\Math\Exception\DivisionByZeroException;
+use Brick\Math\Exception\MathException;
+use Brick\Math\Exception\NumberFormatException;
+use Brick\Math\Exception\RoundingNecessaryException;
+
+/**
+ * Common interface for arbitrary-precision rational numbers.
+ *
+ * @psalm-immutable
+ */
+abstract class BigNumber implements \Serializable, \JsonSerializable
+{
+    /**
+     * The regular expression used to parse integer, decimal and rational numbers.
+     */
+    private const PARSE_REGEXP =
+        '/^' .
+            '(?<sign>[\-\+])?' .
+            '(?:' .
+                '(?:' .
+                    '(?<integral>[0-9]+)?' .
+                    '(?<point>\.)?' .
+                    '(?<fractional>[0-9]+)?' .
+                    '(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
+                ')|(?:' .
+                    '(?<numerator>[0-9]+)' .
+                    '\/?' .
+                    '(?<denominator>[0-9]+)' .
+                ')' .
+            ')' .
+        '$/';
+
+    /**
+     * Creates a BigNumber of the given value.
+     *
+     * The concrete return type is dependent on the given value, with the following rules:
+     *
+     * - BigNumber instances are returned as is
+     * - integer numbers are returned as BigInteger
+     * - floating point numbers are converted to a string then parsed as such
+     * - strings containing a `/` character are returned as BigRational
+     * - strings containing a `.` character or using an exponential notation are returned as BigDecimal
+     * - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger
+     *
+     * @param BigNumber|int|float|string $value
+     *
+     * @return BigNumber
+     *
+     * @throws NumberFormatException   If the format of the number is not valid.
+     * @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
+     *
+     * @psalm-pure
+     */
+    public static function of($value) : BigNumber
+    {
+        if ($value instanceof BigNumber) {
+            return $value;
+        }
+
+        if (\is_int($value)) {
+            return new BigInteger((string) $value);
+        }
+
+        /** @psalm-suppress RedundantCastGivenDocblockType We cannot trust the untyped $value here! */
+        $value = \is_float($value) ? self::floatToString($value) : (string) $value;
+
+        $throw = static function() use ($value) : void {
+            throw new NumberFormatException(\sprintf(
+                'The given value "%s" does not represent a valid number.',
+                $value
+            ));
+        };
+
+        if (\preg_match(self::PARSE_REGEXP, $value, $matches) !== 1) {
+            $throw();
+        }
+
+        $getMatch = static function(string $value) use ($matches) : ?string {
+            return isset($matches[$value]) && $matches[$value] !== '' ? $matches[$value] : null;
+        };
+
+        $sign        = $getMatch('sign');
+        $numerator   = $getMatch('numerator');
+        $denominator = $getMatch('denominator');
+
+        if ($numerator !== null) {
+            assert($denominator !== null);
+
+            if ($sign !== null) {
+                $numerator = $sign . $numerator;
+            }
+
+            $numerator   = self::cleanUp($numerator);
+            $denominator = self::cleanUp($denominator);
+
+            if ($denominator === '0') {
+                throw DivisionByZeroException::denominatorMustNotBeZero();
+            }
+
+            return new BigRational(
+                new BigInteger($numerator),
+                new BigInteger($denominator),
+                false
+            );
+        }
+
+        $point      = $getMatch('point');
+        $integral   = $getMatch('integral');
+        $fractional = $getMatch('fractional');
+        $exponent   = $getMatch('exponent');
+
+        if ($integral === null && $fractional === null) {
+            $throw();
+        }
+
+        if ($integral === null) {
+            $integral = '0';
+        }
+
+        if ($point !== null || $exponent !== null) {
+            $fractional = ($fractional ?? '');
+            $exponent = ($exponent !== null) ? (int) $exponent : 0;
+
+            if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) {
+                throw new NumberFormatException('Exponent too large.');
+            }
+
+            $unscaledValue = self::cleanUp(($sign ?? ''). $integral . $fractional);
+
+            $scale = \strlen($fractional) - $exponent;
+
+            if ($scale < 0) {
+                if ($unscaledValue !== '0') {
+                    $unscaledValue .= \str_repeat('0', - $scale);
+                }
+                $scale = 0;
+            }
+
+            return new BigDecimal($unscaledValue, $scale);
+        }
+
+        $integral = self::cleanUp(($sign ?? '') . $integral);
+
+        return new BigInteger($integral);
+    }
+
+    /**
+     * Safely converts float to string, avoiding locale-dependent issues.
+     *
+     * @see https://github.com/brick/math/pull/20
+     *
+     * @param float $float
+     *
+     * @return string
+     *
+     * @psalm-pure
+     * @psalm-suppress ImpureFunctionCall
+     */
+    private static function floatToString(float $float) : string
+    {
+        $currentLocale = \setlocale(LC_NUMERIC, '0');
+        \setlocale(LC_NUMERIC, 'C');
+
+        $result = (string) $float;
+
+        \setlocale(LC_NUMERIC, $currentLocale);
+
+        return $result;
+    }
+
+    /**
+     * Proxy method to access protected constructors from sibling classes.
+     *
+     * @internal
+     *
+     * @param mixed ...$args The arguments to the constructor.
+     *
+     * @return static
+     *
+     * @psalm-pure
+     * @psalm-suppress TooManyArguments
+     * @psalm-suppress UnsafeInstantiation
+     */
+    protected static function create(... $args) : BigNumber
+    {
+        return new static(... $args);
+    }
+
+    /**
+     * Returns the minimum of the given values.
+     *
+     * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
+     *                                              to an instance of the class this method is called on.
+     *
+     * @return static The minimum value.
+     *
+     * @throws \InvalidArgumentException If no values are given.
+     * @throws MathException             If an argument is not valid.
+     *
+     * @psalm-suppress LessSpecificReturnStatement
+     * @psalm-suppress MoreSpecificReturnType
+     * @psalm-pure
+     */
+    public static function min(...$values) : BigNumber
+    {
+        $min = null;
+
+        foreach ($values as $value) {
+            $value = static::of($value);
+
+            if ($min === null || $value->isLessThan($min)) {
+                $min = $value;
+            }
+        }
+
+        if ($min === null) {
+            throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
+        }
+
+        return $min;
+    }
+
+    /**
+     * Returns the maximum of the given values.
+     *
+     * @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
+     *                                              to an instance of the class this method is called on.
+     *
+     * @return static The maximum value.
+     *
+     * @throws \InvalidArgumentException If no values are given.
+     * @throws MathException             If an argument is not valid.
+     *
+     * @psalm-suppress LessSpecificReturnStatement
+     * @psalm-suppress MoreSpecificReturnType
+     * @psalm-pure
+     */
+    public static function max(...$values) : BigNumber
+    {
+        $max = null;
+
+        foreach ($values as $value) {
+            $value = static::of($value);
+
+            if ($max === null || $value->isGreaterThan($max)) {
+                $max = $value;
+            }
+        }
+
+        if ($max === null) {
+            throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
+        }
+
+        return $max;
+    }
+
+    /**
+     * Returns the sum of the given values.
+     *
+     * @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible
+     *                                              to an instance of the class this method is called on.
+     *
+     * @return static The sum.
+     *
+     * @throws \InvalidArgumentException If no values are given.
+     * @throws MathException             If an argument is not valid.
+     *
+     * @psalm-suppress LessSpecificReturnStatement
+     * @psalm-suppress MoreSpecificReturnType
+     * @psalm-pure
+     */
+    public static function sum(...$values) : BigNumber
+    {
+        /** @var BigNumber|null $sum */
+        $sum = null;
+
+        foreach ($values as $value) {
+            $value = static::of($value);
+
+            $sum = $sum === null ? $value : self::add($sum, $value);
+        }
+
+        if ($sum === null) {
+            throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
+        }
+
+        return $sum;
+    }
+
+    /**
+     * Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException.
+     *
+     * @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to
+     *       concrete classes the responsibility to perform the addition themselves or delegate it to the given number,
+     *       depending on their ability to perform the operation. This will also require a version bump because we're
+     *       potentially breaking custom BigNumber implementations (if any...)
+     *
+     * @param BigNumber $a
+     * @param BigNumber $b
+     *
+     * @return BigNumber
+     *
+     * @psalm-pure
+     */
+    private static function add(BigNumber $a, BigNumber $b) : BigNumber
+    {
+        if ($a instanceof BigRational) {
+            return $a->plus($b);
+        }
+
+        if ($b instanceof BigRational) {
+            return $b->plus($a);
+        }
+
+        if ($a instanceof BigDecimal) {
+            return $a->plus($b);
+        }
+
+        if ($b instanceof BigDecimal) {
+            return $b->plus($a);
+        }
+
+        /** @var BigInteger $a */
+
+        return $a->plus($b);
+    }
+
+    /**
+     * Removes optional leading zeros and + sign from the given number.
+     *
+     * @param string $number The number, validated as a non-empty string of digits with optional leading sign.
+     *
+     * @return string
+     *
+     * @psalm-pure
+     */
+    private static function cleanUp(string $number) : string
+    {
+        $firstChar = $number[0];
+
+        if ($firstChar === '+' || $firstChar === '-') {
+            $number = \substr($number, 1);
+        }
+
+        $number = \ltrim($number, '0');
+
+        if ($number === '') {
+            return '0';
+        }
+
+        if ($firstChar === '-') {
+            return '-' . $number;
+        }
+
+        return $number;
+    }
+
+    /**
+     * Checks if this number is equal to the given one.
+     *
+     * @param BigNumber|int|float|string $that
+     *
+     * @return bool
+     */
+    public function isEqualTo($that) : bool
+    {
+        return $this->compareTo($that) === 0;
+    }
+
+    /**
+     * Checks if this number is strictly lower than the given one.
+     *
+     * @param BigNumber|int|float|string $that
+     *
+     * @return bool
+     */
+    public function isLessThan($that) : bool
+    {
+        return $this->compareTo($that) < 0;
+    }
+
+    /**
+     * Checks if this number is lower than or equal to the given one.
+     *
+     * @param BigNumber|int|float|string $that
+     *
+     * @return bool
+     */
+    public function isLessThanOrEqualTo($that) : bool
+    {
+        return $this->compareTo($that) <= 0;
+    }
+
+    /**
+     * Checks if this number is strictly greater than the given one.
+     *
+     * @param BigNumber|int|float|string $that
+     *
+     * @return bool
+     */
+    public function isGreaterThan($that) : bool
+    {
+        return $this->compareTo($that) > 0;
+    }
+
+    /**
+     * Checks if this number is greater than or equal to the given one.
+     *
+     * @param BigNumber|int|float|string $that
+     *
+     * @return bool
+     */
+    public function isGreaterThanOrEqualTo($that) : bool
+    {
+        return $this->compareTo($that) >= 0;
+    }
+
+    /**
+     * Checks if this number equals zero.
+     *
+     * @return bool
+     */
+    public function isZero() : bool
+    {
+        return $this->getSign() === 0;
+    }
+
+    /**
+     * Checks if this number is strictly negative.
+     *
+     * @return bool
+     */
+    public function isNegative() : bool
+    {
+        return $this->getSign() < 0;
+    }
+
+    /**
+     * Checks if this number is negative or zero.
+     *
+     * @return bool
+     */
+    public function isNegativeOrZero() : bool
+    {
+        return $this->getSign() <= 0;
+    }
+
+    /**
+     * Checks if this number is strictly positive.
+     *
+     * @return bool
+     */
+    public function isPositive() : bool
+    {
+        return $this->getSign() > 0;
+    }
+
+    /**
+     * Checks if this number is positive or zero.
+     *
+     * @return bool
+     */
+    public function isPositiveOrZero() : bool
+    {
+        return $this->getSign() >= 0;
+    }
+
+    /**
+     * Returns the sign of this number.
+     *
+     * @return int -1 if the number is negative, 0 if zero, 1 if positive.
+     */
+    abstract public function getSign() : int;
+
+    /**
+     * Compares this number to the given one.
+     *
+     * @param BigNumber|int|float|string $that
+     *
+     * @return int [-1,0,1] If `$this` is lower than, equal to, or greater than `$that`.
+     *
+     * @throws MathException If the number is not valid.
+     */
+    abstract public function compareTo($that) : int;
+
+    /**
+     * Converts this number to a BigInteger.
+     *
+     * @return BigInteger The converted number.
+     *
+     * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding.
+     */
+    abstract public function toBigInteger() : BigInteger;
+
+    /**
+     * Converts this number to a BigDecimal.
+     *
+     * @return BigDecimal The converted number.
+     *
+     * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding.
+     */
+    abstract public function toBigDecimal() : BigDecimal;
+
+    /**
+     * Converts this number to a BigRational.
+     *
+     * @return BigRational The converted number.
+     */
+    abstract public function toBigRational() : BigRational;
+
+    /**
+     * Converts this number to a BigDecimal with the given scale, using rounding if necessary.
+     *
+     * @param int $scale        The scale of the resulting `BigDecimal`.
+     * @param int $roundingMode A `RoundingMode` constant.
+     *
+     * @return BigDecimal
+     *
+     * @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.
+     *                                    This only applies when RoundingMode::UNNECESSARY is used.
+     */
+    abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
+
+    /**
+     * Returns the exact value of this number as a native integer.
+     *
+     * If this number cannot be converted to a native integer without losing precision, an exception is thrown.
+     * Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit.
+     *
+     * @return int The converted value.
+     *
+     * @throws MathException If this number cannot be exactly converted to a native integer.
+     */
+    abstract public function toInt() : int;
+
+    /**
+     * Returns an approximation of this number as a floating-point value.
+     *
+     * Note that this method can discard information as the precision of a floating-point value
+     * is inherently limited.
+     *
+     * If the number is greater than the largest representable floating point number, positive infinity is returned.
+     * If the number is less than the smallest representable floating point number, negative infinity is returned.
+     *
+     * @return float The converted value.
+     */
+    abstract public function toFloat() : float;
+
+    /**
+     * Returns a string representation of this number.
+     *
+     * The output of this method can be parsed by the `of()` factory method;
+     * this will yield an object equal to this one, without any information loss.
+     *
+     * @return string
+     */
+    abstract public function __toString() : string;
+
+    /**
+     * {@inheritdoc}
+     */
+    public function jsonSerialize() : string
+    {
+        return $this->__toString();
+    }
+}

+ 523 - 0
api/vendor/brick/math/src/BigRational.php

@@ -0,0 +1,523 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math;
+
+use Brick\Math\Exception\DivisionByZeroException;
+use Brick\Math\Exception\MathException;
+use Brick\Math\Exception\NumberFormatException;
+use Brick\Math\Exception\RoundingNecessaryException;
+
+/**
+ * An arbitrarily large rational number.
+ *
+ * This class is immutable.
+ *
+ * @psalm-immutable
+ */
+final class BigRational extends BigNumber
+{
+    /**
+     * The numerator.
+     *
+     * @var BigInteger
+     */
+    private $numerator;
+
+    /**
+     * The denominator. Always strictly positive.
+     *
+     * @var BigInteger
+     */
+    private $denominator;
+
+    /**
+     * Protected constructor. Use a factory method to obtain an instance.
+     *
+     * @param BigInteger $numerator        The numerator.
+     * @param BigInteger $denominator      The denominator.
+     * @param bool       $checkDenominator Whether to check the denominator for negative and zero.
+     *
+     * @throws DivisionByZeroException If the denominator is zero.
+     */
+    protected function __construct(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator)
+    {
+        if ($checkDenominator) {
+            if ($denominator->isZero()) {
+                throw DivisionByZeroException::denominatorMustNotBeZero();
+            }
+
+            if ($denominator->isNegative()) {
+                $numerator   = $numerator->negated();
+                $denominator = $denominator->negated();
+            }
+        }
+
+        $this->numerator   = $numerator;
+        $this->denominator = $denominator;
+    }
+
+    /**
+     * Creates a BigRational of the given value.
+     *
+     * @param BigNumber|int|float|string $value
+     *
+     * @return BigRational
+     *
+     * @throws MathException If the value cannot be converted to a BigRational.
+     *
+     * @psalm-pure
+     */
+    public static function of($value) : BigNumber
+    {
+        return parent::of($value)->toBigRational();
+    }
+
+    /**
+     * Creates a BigRational out of a numerator and a denominator.
+     *
+     * If the denominator is negative, the signs of both the numerator and the denominator
+     * will be inverted to ensure that the denominator is always positive.
+     *
+     * @param BigNumber|int|float|string $numerator   The numerator. Must be convertible to a BigInteger.
+     * @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger.
+     *
+     * @return BigRational
+     *
+     * @throws NumberFormatException      If an argument does not represent a valid number.
+     * @throws RoundingNecessaryException If an argument represents a non-integer number.
+     * @throws DivisionByZeroException    If the denominator is zero.
+     *
+     * @psalm-pure
+     */
+    public static function nd($numerator, $denominator) : BigRational
+    {
+        $numerator   = BigInteger::of($numerator);
+        $denominator = BigInteger::of($denominator);
+
+        return new BigRational($numerator, $denominator, true);
+    }
+
+    /**
+     * Returns a BigRational representing zero.
+     *
+     * @return BigRational
+     *
+     * @psalm-pure
+     */
+    public static function zero() : BigRational
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigRational|null $zero
+         */
+        static $zero;
+
+        if ($zero === null) {
+            $zero = new BigRational(BigInteger::zero(), BigInteger::one(), false);
+        }
+
+        return $zero;
+    }
+
+    /**
+     * Returns a BigRational representing one.
+     *
+     * @return BigRational
+     *
+     * @psalm-pure
+     */
+    public static function one() : BigRational
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigRational|null $one
+         */
+        static $one;
+
+        if ($one === null) {
+            $one = new BigRational(BigInteger::one(), BigInteger::one(), false);
+        }
+
+        return $one;
+    }
+
+    /**
+     * Returns a BigRational representing ten.
+     *
+     * @return BigRational
+     *
+     * @psalm-pure
+     */
+    public static function ten() : BigRational
+    {
+        /**
+         * @psalm-suppress ImpureStaticVariable
+         * @var BigRational|null $ten
+         */
+        static $ten;
+
+        if ($ten === null) {
+            $ten = new BigRational(BigInteger::ten(), BigInteger::one(), false);
+        }
+
+        return $ten;
+    }
+
+    /**
+     * @return BigInteger
+     */
+    public function getNumerator() : BigInteger
+    {
+        return $this->numerator;
+    }
+
+    /**
+     * @return BigInteger
+     */
+    public function getDenominator() : BigInteger
+    {
+        return $this->denominator;
+    }
+
+    /**
+     * Returns the quotient of the division of the numerator by the denominator.
+     *
+     * @return BigInteger
+     */
+    public function quotient() : BigInteger
+    {
+        return $this->numerator->quotient($this->denominator);
+    }
+
+    /**
+     * Returns the remainder of the division of the numerator by the denominator.
+     *
+     * @return BigInteger
+     */
+    public function remainder() : BigInteger
+    {
+        return $this->numerator->remainder($this->denominator);
+    }
+
+    /**
+     * Returns the quotient and remainder of the division of the numerator by the denominator.
+     *
+     * @return BigInteger[]
+     */
+    public function quotientAndRemainder() : array
+    {
+        return $this->numerator->quotientAndRemainder($this->denominator);
+    }
+
+    /**
+     * Returns the sum of this number and the given one.
+     *
+     * @param BigNumber|int|float|string $that The number to add.
+     *
+     * @return BigRational The result.
+     *
+     * @throws MathException If the number is not valid.
+     */
+    public function plus($that) : BigRational
+    {
+        $that = BigRational::of($that);
+
+        $numerator   = $this->numerator->multipliedBy($that->denominator);
+        $numerator   = $numerator->plus($that->numerator->multipliedBy($this->denominator));
+        $denominator = $this->denominator->multipliedBy($that->denominator);
+
+        return new BigRational($numerator, $denominator, false);
+    }
+
+    /**
+     * Returns the difference of this number and the given one.
+     *
+     * @param BigNumber|int|float|string $that The number to subtract.
+     *
+     * @return BigRational The result.
+     *
+     * @throws MathException If the number is not valid.
+     */
+    public function minus($that) : BigRational
+    {
+        $that = BigRational::of($that);
+
+        $numerator   = $this->numerator->multipliedBy($that->denominator);
+        $numerator   = $numerator->minus($that->numerator->multipliedBy($this->denominator));
+        $denominator = $this->denominator->multipliedBy($that->denominator);
+
+        return new BigRational($numerator, $denominator, false);
+    }
+
+    /**
+     * Returns the product of this number and the given one.
+     *
+     * @param BigNumber|int|float|string $that The multiplier.
+     *
+     * @return BigRational The result.
+     *
+     * @throws MathException If the multiplier is not a valid number.
+     */
+    public function multipliedBy($that) : BigRational
+    {
+        $that = BigRational::of($that);
+
+        $numerator   = $this->numerator->multipliedBy($that->numerator);
+        $denominator = $this->denominator->multipliedBy($that->denominator);
+
+        return new BigRational($numerator, $denominator, false);
+    }
+
+    /**
+     * Returns the result of the division of this number by the given one.
+     *
+     * @param BigNumber|int|float|string $that The divisor.
+     *
+     * @return BigRational The result.
+     *
+     * @throws MathException If the divisor is not a valid number, or is zero.
+     */
+    public function dividedBy($that) : BigRational
+    {
+        $that = BigRational::of($that);
+
+        $numerator   = $this->numerator->multipliedBy($that->denominator);
+        $denominator = $this->denominator->multipliedBy($that->numerator);
+
+        return new BigRational($numerator, $denominator, true);
+    }
+
+    /**
+     * Returns this number exponentiated to the given value.
+     *
+     * @param int $exponent The exponent.
+     *
+     * @return BigRational The result.
+     *
+     * @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
+     */
+    public function power(int $exponent) : BigRational
+    {
+        if ($exponent === 0) {
+            $one = BigInteger::one();
+
+            return new BigRational($one, $one, false);
+        }
+
+        if ($exponent === 1) {
+            return $this;
+        }
+
+        return new BigRational(
+            $this->numerator->power($exponent),
+            $this->denominator->power($exponent),
+            false
+        );
+    }
+
+    /**
+     * Returns the reciprocal of this BigRational.
+     *
+     * The reciprocal has the numerator and denominator swapped.
+     *
+     * @return BigRational
+     *
+     * @throws DivisionByZeroException If the numerator is zero.
+     */
+    public function reciprocal() : BigRational
+    {
+        return new BigRational($this->denominator, $this->numerator, true);
+    }
+
+    /**
+     * Returns the absolute value of this BigRational.
+     *
+     * @return BigRational
+     */
+    public function abs() : BigRational
+    {
+        return new BigRational($this->numerator->abs(), $this->denominator, false);
+    }
+
+    /**
+     * Returns the negated value of this BigRational.
+     *
+     * @return BigRational
+     */
+    public function negated() : BigRational
+    {
+        return new BigRational($this->numerator->negated(), $this->denominator, false);
+    }
+
+    /**
+     * Returns the simplified value of this BigRational.
+     *
+     * @return BigRational
+     */
+    public function simplified() : BigRational
+    {
+        $gcd = $this->numerator->gcd($this->denominator);
+
+        $numerator = $this->numerator->quotient($gcd);
+        $denominator = $this->denominator->quotient($gcd);
+
+        return new BigRational($numerator, $denominator, false);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function compareTo($that) : int
+    {
+        return $this->minus($that)->getSign();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSign() : int
+    {
+        return $this->numerator->getSign();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigInteger() : BigInteger
+    {
+        $simplified = $this->simplified();
+
+        if (! $simplified->denominator->isEqualTo(1)) {
+            throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.');
+        }
+
+        return $simplified->numerator;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigDecimal() : BigDecimal
+    {
+        return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBigRational() : BigRational
+    {
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
+    {
+        return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toInt() : int
+    {
+        return $this->toBigInteger()->toInt();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toFloat() : float
+    {
+        return $this->numerator->toFloat() / $this->denominator->toFloat();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function __toString() : string
+    {
+        $numerator   = (string) $this->numerator;
+        $denominator = (string) $this->denominator;
+
+        if ($denominator === '1') {
+            return $numerator;
+        }
+
+        return $this->numerator . '/' . $this->denominator;
+    }
+
+    /**
+     * This method is required for serializing the object and SHOULD NOT be accessed directly.
+     *
+     * @internal
+     *
+     * @return array{numerator: BigInteger, denominator: BigInteger}
+     */
+    public function __serialize(): array
+    {
+        return ['numerator' => $this->numerator, 'denominator' => $this->denominator];
+    }
+
+    /**
+     * This method is only here to allow unserializing the object and cannot be accessed directly.
+     *
+     * @internal
+     * @psalm-suppress RedundantPropertyInitializationCheck
+     *
+     * @param array{numerator: BigInteger, denominator: BigInteger} $data
+     *
+     * @return void
+     *
+     * @throws \LogicException
+     */
+    public function __unserialize(array $data): void
+    {
+        if (isset($this->numerator)) {
+            throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
+        }
+
+        $this->numerator = $data['numerator'];
+        $this->denominator = $data['denominator'];
+    }
+
+    /**
+     * This method is required by interface Serializable and SHOULD NOT be accessed directly.
+     *
+     * @internal
+     *
+     * @return string
+     */
+    public function serialize() : string
+    {
+        return $this->numerator . '/' . $this->denominator;
+    }
+
+    /**
+     * This method is only here to implement interface Serializable and cannot be accessed directly.
+     *
+     * @internal
+     * @psalm-suppress RedundantPropertyInitializationCheck
+     *
+     * @param string $value
+     *
+     * @return void
+     *
+     * @throws \LogicException
+     */
+    public function unserialize($value) : void
+    {
+        if (isset($this->numerator)) {
+            throw new \LogicException('unserialize() is an internal function, it must not be called directly.');
+        }
+
+        [$numerator, $denominator] = \explode('/', $value);
+
+        $this->numerator   = BigInteger::of($numerator);
+        $this->denominator = BigInteger::of($denominator);
+    }
+}

+ 41 - 0
api/vendor/brick/math/src/Exception/DivisionByZeroException.php

@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Exception;
+
+/**
+ * Exception thrown when a division by zero occurs.
+ */
+class DivisionByZeroException extends MathException
+{
+    /**
+     * @return DivisionByZeroException
+     *
+     * @psalm-pure
+     */
+    public static function divisionByZero() : DivisionByZeroException
+    {
+        return new self('Division by zero.');
+    }
+
+    /**
+     * @return DivisionByZeroException
+     *
+     * @psalm-pure
+     */
+    public static function modulusMustNotBeZero() : DivisionByZeroException
+    {
+        return new self('The modulus must not be zero.');
+    }
+
+    /**
+     * @return DivisionByZeroException
+     *
+     * @psalm-pure
+     */
+    public static function denominatorMustNotBeZero() : DivisionByZeroException
+    {
+        return new self('The denominator of a rational number cannot be zero.');
+    }
+}

+ 27 - 0
api/vendor/brick/math/src/Exception/IntegerOverflowException.php

@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Exception;
+
+use Brick\Math\BigInteger;
+
+/**
+ * Exception thrown when an integer overflow occurs.
+ */
+class IntegerOverflowException extends MathException
+{
+    /**
+     * @param BigInteger $value
+     *
+     * @return IntegerOverflowException
+     *
+     * @psalm-pure
+     */
+    public static function toIntOverflow(BigInteger $value) : IntegerOverflowException
+    {
+        $message = '%s is out of range %d to %d and cannot be represented as an integer.';
+
+        return new self(\sprintf($message, (string) $value, PHP_INT_MIN, PHP_INT_MAX));
+    }
+}

+ 14 - 0
api/vendor/brick/math/src/Exception/MathException.php

@@ -0,0 +1,14 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Exception;
+
+/**
+ * Base class for all math exceptions.
+ *
+ * This class is abstract to ensure that only fine-grained exceptions are thrown throughout the code.
+ */
+class MathException extends \RuntimeException
+{
+}

+ 12 - 0
api/vendor/brick/math/src/Exception/NegativeNumberException.php

@@ -0,0 +1,12 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Exception;
+
+/**
+ * Exception thrown when attempting to perform an unsupported operation, such as a square root, on a negative number.
+ */
+class NegativeNumberException extends MathException
+{
+}

+ 35 - 0
api/vendor/brick/math/src/Exception/NumberFormatException.php

@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Exception;
+
+/**
+ * Exception thrown when attempting to create a number from a string with an invalid format.
+ */
+class NumberFormatException extends MathException
+{
+    /**
+     * @param string $char The failing character.
+     *
+     * @return NumberFormatException
+     *
+     * @psalm-pure
+     */
+    public static function charNotInAlphabet(string $char) : self
+    {
+        $ord = \ord($char);
+
+        if ($ord < 32 || $ord > 126) {
+            $char = \strtoupper(\dechex($ord));
+
+            if ($ord < 10) {
+                $char = '0' . $char;
+            }
+        } else {
+            $char = '"' . $char . '"';
+        }
+
+        return new self(sprintf('Char %s is not a valid character in the given alphabet.', $char));
+    }
+}

+ 21 - 0
api/vendor/brick/math/src/Exception/RoundingNecessaryException.php

@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Exception;
+
+/**
+ * Exception thrown when a number cannot be represented at the requested scale without rounding.
+ */
+class RoundingNecessaryException extends MathException
+{
+    /**
+     * @return RoundingNecessaryException
+     *
+     * @psalm-pure
+     */
+    public static function roundingNecessary() : RoundingNecessaryException
+    {
+        return new self('Rounding is necessary to represent the result of the operation at this scale.');
+    }
+}

+ 756 - 0
api/vendor/brick/math/src/Internal/Calculator.php

@@ -0,0 +1,756 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Internal;
+
+use Brick\Math\Exception\RoundingNecessaryException;
+use Brick\Math\RoundingMode;
+
+/**
+ * Performs basic operations on arbitrary size integers.
+ *
+ * Unless otherwise specified, all parameters must be validated as non-empty strings of digits,
+ * without leading zero, and with an optional leading minus sign if the number is not zero.
+ *
+ * Any other parameter format will lead to undefined behaviour.
+ * All methods must return strings respecting this format, unless specified otherwise.
+ *
+ * @internal
+ *
+ * @psalm-immutable
+ */
+abstract class Calculator
+{
+    /**
+     * The maximum exponent value allowed for the pow() method.
+     */
+    public const MAX_POWER = 1000000;
+
+    /**
+     * The alphabet for converting from and to base 2 to 36, lowercase.
+     */
+    public const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz';
+
+    /**
+     * The Calculator instance in use.
+     *
+     * @var Calculator|null
+     */
+    private static $instance;
+
+    /**
+     * Sets the Calculator instance to use.
+     *
+     * An instance is typically set only in unit tests: the autodetect is usually the best option.
+     *
+     * @param Calculator|null $calculator The calculator instance, or NULL to revert to autodetect.
+     *
+     * @return void
+     */
+    final public static function set(?Calculator $calculator) : void
+    {
+        self::$instance = $calculator;
+    }
+
+    /**
+     * Returns the Calculator instance to use.
+     *
+     * If none has been explicitly set, the fastest available implementation will be returned.
+     *
+     * @return Calculator
+     *
+     * @psalm-pure
+     * @psalm-suppress ImpureStaticProperty
+     */
+    final public static function get() : Calculator
+    {
+        if (self::$instance === null) {
+            /** @psalm-suppress ImpureMethodCall */
+            self::$instance = self::detect();
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * Returns the fastest available Calculator implementation.
+     *
+     * @codeCoverageIgnore
+     *
+     * @return Calculator
+     */
+    private static function detect() : Calculator
+    {
+        if (\extension_loaded('gmp')) {
+            return new Calculator\GmpCalculator();
+        }
+
+        if (\extension_loaded('bcmath')) {
+            return new Calculator\BcMathCalculator();
+        }
+
+        return new Calculator\NativeCalculator();
+    }
+
+    /**
+     * Extracts the sign & digits of the operands.
+     *
+     * @param string $a The first operand.
+     * @param string $b The second operand.
+     *
+     * @return array{bool, bool, string, string} Whether $a and $b are negative, followed by their digits.
+     */
+    final protected function init(string $a, string $b) : array
+    {
+        return [
+            $aNeg = ($a[0] === '-'),
+            $bNeg = ($b[0] === '-'),
+
+            $aNeg ? \substr($a, 1) : $a,
+            $bNeg ? \substr($b, 1) : $b,
+        ];
+    }
+
+    /**
+     * Returns the absolute value of a number.
+     *
+     * @param string $n The number.
+     *
+     * @return string The absolute value.
+     */
+    final public function abs(string $n) : string
+    {
+        return ($n[0] === '-') ? \substr($n, 1) : $n;
+    }
+
+    /**
+     * Negates a number.
+     *
+     * @param string $n The number.
+     *
+     * @return string The negated value.
+     */
+    final public function neg(string $n) : string
+    {
+        if ($n === '0') {
+            return '0';
+        }
+
+        if ($n[0] === '-') {
+            return \substr($n, 1);
+        }
+
+        return '-' . $n;
+    }
+
+    /**
+     * Compares two numbers.
+     *
+     * @param string $a The first number.
+     * @param string $b The second number.
+     *
+     * @return int [-1, 0, 1] If the first number is less than, equal to, or greater than the second number.
+     */
+    final public function cmp(string $a, string $b) : int
+    {
+        [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+        if ($aNeg && ! $bNeg) {
+            return -1;
+        }
+
+        if ($bNeg && ! $aNeg) {
+            return 1;
+        }
+
+        $aLen = \strlen($aDig);
+        $bLen = \strlen($bDig);
+
+        if ($aLen < $bLen) {
+            $result = -1;
+        } elseif ($aLen > $bLen) {
+            $result = 1;
+        } else {
+            $result = $aDig <=> $bDig;
+        }
+
+        return $aNeg ? -$result : $result;
+    }
+
+    /**
+     * Adds two numbers.
+     *
+     * @param string $a The augend.
+     * @param string $b The addend.
+     *
+     * @return string The sum.
+     */
+    abstract public function add(string $a, string $b) : string;
+
+    /**
+     * Subtracts two numbers.
+     *
+     * @param string $a The minuend.
+     * @param string $b The subtrahend.
+     *
+     * @return string The difference.
+     */
+    abstract public function sub(string $a, string $b) : string;
+
+    /**
+     * Multiplies two numbers.
+     *
+     * @param string $a The multiplicand.
+     * @param string $b The multiplier.
+     *
+     * @return string The product.
+     */
+    abstract public function mul(string $a, string $b) : string;
+
+    /**
+     * Returns the quotient of the division of two numbers.
+     *
+     * @param string $a The dividend.
+     * @param string $b The divisor, must not be zero.
+     *
+     * @return string The quotient.
+     */
+    abstract public function divQ(string $a, string $b) : string;
+
+    /**
+     * Returns the remainder of the division of two numbers.
+     *
+     * @param string $a The dividend.
+     * @param string $b The divisor, must not be zero.
+     *
+     * @return string The remainder.
+     */
+    abstract public function divR(string $a, string $b) : string;
+
+    /**
+     * Returns the quotient and remainder of the division of two numbers.
+     *
+     * @param string $a The dividend.
+     * @param string $b The divisor, must not be zero.
+     *
+     * @return string[] An array containing the quotient and remainder.
+     */
+    abstract public function divQR(string $a, string $b) : array;
+
+    /**
+     * Exponentiates a number.
+     *
+     * @param string $a The base number.
+     * @param int    $e The exponent, validated as an integer between 0 and MAX_POWER.
+     *
+     * @return string The power.
+     */
+    abstract public function pow(string $a, int $e) : string;
+
+    /**
+     * @param string $a
+     * @param string $b The modulus; must not be zero.
+     *
+     * @return string
+     */
+    public function mod(string $a, string $b) : string
+    {
+        return $this->divR($this->add($this->divR($a, $b), $b), $b);
+    }
+
+    /**
+     * Returns the modular multiplicative inverse of $x modulo $m.
+     *
+     * If $x has no multiplicative inverse mod m, this method must return null.
+     *
+     * This method can be overridden by the concrete implementation if the underlying library has built-in support.
+     *
+     * @param string $x
+     * @param string $m The modulus; must not be negative or zero.
+     *
+     * @return string|null
+     */
+    public function modInverse(string $x, string $m) : ?string
+    {
+        if ($m === '1') {
+            return '0';
+        }
+
+        $modVal = $x;
+
+        if ($x[0] === '-' || ($this->cmp($this->abs($x), $m) >= 0)) {
+            $modVal = $this->mod($x, $m);
+        }
+
+        $x = '0';
+        $y = '0';
+        $g = $this->gcdExtended($modVal, $m, $x, $y);
+
+        if ($g !== '1') {
+            return null;
+        }
+
+        return $this->mod($this->add($this->mod($x, $m), $m), $m);
+    }
+
+    /**
+     * Raises a number into power with modulo.
+     *
+     * @param string $base The base number; must be positive or zero.
+     * @param string $exp  The exponent; must be positive or zero.
+     * @param string $mod  The modulus; must be strictly positive.
+     *
+     * @return string The power.
+     */
+    abstract public function modPow(string $base, string $exp, string $mod) : string;
+
+    /**
+     * Returns the greatest common divisor of the two numbers.
+     *
+     * This method can be overridden by the concrete implementation if the underlying library
+     * has built-in support for GCD calculations.
+     *
+     * @param string $a The first number.
+     * @param string $b The second number.
+     *
+     * @return string The GCD, always positive, or zero if both arguments are zero.
+     */
+    public function gcd(string $a, string $b) : string
+    {
+        if ($a === '0') {
+            return $this->abs($b);
+        }
+
+        if ($b === '0') {
+            return $this->abs($a);
+        }
+
+        return $this->gcd($b, $this->divR($a, $b));
+    }
+
+    private function gcdExtended(string $a, string $b, string &$x, string &$y) : string
+    {
+        if ($a === '0') {
+            $x = '0';
+            $y = '1';
+
+            return $b;
+        }
+
+        $x1 = '0';
+        $y1 = '0';
+
+        $gcd = $this->gcdExtended($this->mod($b, $a), $a, $x1, $y1);
+
+        $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1));
+        $y = $x1;
+
+        return $gcd;
+    }
+
+    /**
+     * Returns the square root of the given number, rounded down.
+     *
+     * The result is the largest x such that x² ≤ n.
+     * The input MUST NOT be negative.
+     *
+     * @param string $n The number.
+     *
+     * @return string The square root.
+     */
+    abstract public function sqrt(string $n) : string;
+
+    /**
+     * Converts a number from an arbitrary base.
+     *
+     * This method can be overridden by the concrete implementation if the underlying library
+     * has built-in support for base conversion.
+     *
+     * @param string $number The number, positive or zero, non-empty, case-insensitively validated for the given base.
+     * @param int    $base   The base of the number, validated from 2 to 36.
+     *
+     * @return string The converted number, following the Calculator conventions.
+     */
+    public function fromBase(string $number, int $base) : string
+    {
+        return $this->fromArbitraryBase(\strtolower($number), self::ALPHABET, $base);
+    }
+
+    /**
+     * Converts a number to an arbitrary base.
+     *
+     * This method can be overridden by the concrete implementation if the underlying library
+     * has built-in support for base conversion.
+     *
+     * @param string $number The number to convert, following the Calculator conventions.
+     * @param int    $base   The base to convert to, validated from 2 to 36.
+     *
+     * @return string The converted number, lowercase.
+     */
+    public function toBase(string $number, int $base) : string
+    {
+        $negative = ($number[0] === '-');
+
+        if ($negative) {
+            $number = \substr($number, 1);
+        }
+
+        $number = $this->toArbitraryBase($number, self::ALPHABET, $base);
+
+        if ($negative) {
+            return '-' . $number;
+        }
+
+        return $number;
+    }
+
+    /**
+     * Converts a non-negative number in an arbitrary base using a custom alphabet, to base 10.
+     *
+     * @param string $number   The number to convert, validated as a non-empty string,
+     *                         containing only chars in the given alphabet/base.
+     * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum.
+     * @param int    $base     The base of the number, validated from 2 to alphabet length.
+     *
+     * @return string The number in base 10, following the Calculator conventions.
+     */
+    final public function fromArbitraryBase(string $number, string $alphabet, int $base) : string
+    {
+        // remove leading "zeros"
+        $number = \ltrim($number, $alphabet[0]);
+
+        if ($number === '') {
+            return '0';
+        }
+
+        // optimize for "one"
+        if ($number === $alphabet[1]) {
+            return '1';
+        }
+
+        $result = '0';
+        $power = '1';
+
+        $base = (string) $base;
+
+        for ($i = \strlen($number) - 1; $i >= 0; $i--) {
+            $index = \strpos($alphabet, $number[$i]);
+
+            if ($index !== 0) {
+                $result = $this->add($result, ($index === 1)
+                    ? $power
+                    : $this->mul($power, (string) $index)
+                );
+            }
+
+            if ($i !== 0) {
+                $power = $this->mul($power, $base);
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Converts a non-negative number to an arbitrary base using a custom alphabet.
+     *
+     * @param string $number   The number to convert, positive or zero, following the Calculator conventions.
+     * @param string $alphabet The alphabet that contains every digit, validated as 2 chars minimum.
+     * @param int    $base     The base to convert to, validated from 2 to alphabet length.
+     *
+     * @return string The converted number in the given alphabet.
+     */
+    final public function toArbitraryBase(string $number, string $alphabet, int $base) : string
+    {
+        if ($number === '0') {
+            return $alphabet[0];
+        }
+
+        $base = (string) $base;
+        $result = '';
+
+        while ($number !== '0') {
+            [$number, $remainder] = $this->divQR($number, $base);
+            $remainder = (int) $remainder;
+
+            $result .= $alphabet[$remainder];
+        }
+
+        return \strrev($result);
+    }
+
+    /**
+     * Performs a rounded division.
+     *
+     * Rounding is performed when the remainder of the division is not zero.
+     *
+     * @param string $a            The dividend.
+     * @param string $b            The divisor, must not be zero.
+     * @param int    $roundingMode The rounding mode.
+     *
+     * @return string
+     *
+     * @throws \InvalidArgumentException  If the rounding mode is invalid.
+     * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
+     */
+    final public function divRound(string $a, string $b, int $roundingMode) : string
+    {
+        [$quotient, $remainder] = $this->divQR($a, $b);
+
+        $hasDiscardedFraction = ($remainder !== '0');
+        $isPositiveOrZero = ($a[0] === '-') === ($b[0] === '-');
+
+        $discardedFractionSign = function() use ($remainder, $b) : int {
+            $r = $this->abs($this->mul($remainder, '2'));
+            $b = $this->abs($b);
+
+            return $this->cmp($r, $b);
+        };
+
+        $increment = false;
+
+        switch ($roundingMode) {
+            case RoundingMode::UNNECESSARY:
+                if ($hasDiscardedFraction) {
+                    throw RoundingNecessaryException::roundingNecessary();
+                }
+                break;
+
+            case RoundingMode::UP:
+                $increment = $hasDiscardedFraction;
+                break;
+
+            case RoundingMode::DOWN:
+                break;
+
+            case RoundingMode::CEILING:
+                $increment = $hasDiscardedFraction && $isPositiveOrZero;
+                break;
+
+            case RoundingMode::FLOOR:
+                $increment = $hasDiscardedFraction && ! $isPositiveOrZero;
+                break;
+
+            case RoundingMode::HALF_UP:
+                $increment = $discardedFractionSign() >= 0;
+                break;
+
+            case RoundingMode::HALF_DOWN:
+                $increment = $discardedFractionSign() > 0;
+                break;
+
+            case RoundingMode::HALF_CEILING:
+                $increment = $isPositiveOrZero ? $discardedFractionSign() >= 0 : $discardedFractionSign() > 0;
+                break;
+
+            case RoundingMode::HALF_FLOOR:
+                $increment = $isPositiveOrZero ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0;
+                break;
+
+            case RoundingMode::HALF_EVEN:
+                $lastDigit = (int) $quotient[-1];
+                $lastDigitIsEven = ($lastDigit % 2 === 0);
+                $increment = $lastDigitIsEven ? $discardedFractionSign() > 0 : $discardedFractionSign() >= 0;
+                break;
+
+            default:
+                throw new \InvalidArgumentException('Invalid rounding mode.');
+        }
+
+        if ($increment) {
+            return $this->add($quotient, $isPositiveOrZero ? '1' : '-1');
+        }
+
+        return $quotient;
+    }
+
+    /**
+     * Calculates bitwise AND of two numbers.
+     *
+     * This method can be overridden by the concrete implementation if the underlying library
+     * has built-in support for bitwise operations.
+     *
+     * @param string $a
+     * @param string $b
+     *
+     * @return string
+     */
+    public function and(string $a, string $b) : string
+    {
+        return $this->bitwise('and', $a, $b);
+    }
+
+    /**
+     * Calculates bitwise OR of two numbers.
+     *
+     * This method can be overridden by the concrete implementation if the underlying library
+     * has built-in support for bitwise operations.
+     *
+     * @param string $a
+     * @param string $b
+     *
+     * @return string
+     */
+    public function or(string $a, string $b) : string
+    {
+        return $this->bitwise('or', $a, $b);
+    }
+
+    /**
+     * Calculates bitwise XOR of two numbers.
+     *
+     * This method can be overridden by the concrete implementation if the underlying library
+     * has built-in support for bitwise operations.
+     *
+     * @param string $a
+     * @param string $b
+     *
+     * @return string
+     */
+    public function xor(string $a, string $b) : string
+    {
+        return $this->bitwise('xor', $a, $b);
+    }
+
+    /**
+     * Performs a bitwise operation on a decimal number.
+     *
+     * @param string $operator The operator to use, must be "and", "or" or "xor".
+     * @param string $a        The left operand.
+     * @param string $b        The right operand.
+     *
+     * @return string
+     */
+    private function bitwise(string $operator, string $a, string $b) : string
+    {
+        [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+        $aBin = $this->toBinary($aDig);
+        $bBin = $this->toBinary($bDig);
+
+        $aLen = \strlen($aBin);
+        $bLen = \strlen($bBin);
+
+        if ($aLen > $bLen) {
+            $bBin = \str_repeat("\x00", $aLen - $bLen) . $bBin;
+        } elseif ($bLen > $aLen) {
+            $aBin = \str_repeat("\x00", $bLen - $aLen) . $aBin;
+        }
+
+        if ($aNeg) {
+            $aBin = $this->twosComplement($aBin);
+        }
+        if ($bNeg) {
+            $bBin = $this->twosComplement($bBin);
+        }
+
+        switch ($operator) {
+            case 'and':
+                $value = $aBin & $bBin;
+                $negative = ($aNeg and $bNeg);
+                break;
+
+            case 'or':
+                $value = $aBin | $bBin;
+                $negative = ($aNeg or $bNeg);
+                break;
+
+            case 'xor':
+                $value = $aBin ^ $bBin;
+                $negative = ($aNeg xor $bNeg);
+                break;
+
+            // @codeCoverageIgnoreStart
+            default:
+                throw new \InvalidArgumentException('Invalid bitwise operator.');
+            // @codeCoverageIgnoreEnd
+        }
+
+        if ($negative) {
+            $value = $this->twosComplement($value);
+        }
+
+        $result = $this->toDecimal($value);
+
+        return $negative ? $this->neg($result) : $result;
+    }
+
+    /**
+     * @param string $number A positive, binary number.
+     *
+     * @return string
+     */
+    private function twosComplement(string $number) : string
+    {
+        $xor = \str_repeat("\xff", \strlen($number));
+
+        $number ^= $xor;
+
+        for ($i = \strlen($number) - 1; $i >= 0; $i--) {
+            $byte = \ord($number[$i]);
+
+            if (++$byte !== 256) {
+                $number[$i] = \chr($byte);
+                break;
+            }
+
+            $number[$i] = "\x00";
+
+            if ($i === 0) {
+                $number = "\x01" . $number;
+            }
+        }
+
+        return $number;
+    }
+
+    /**
+     * Converts a decimal number to a binary string.
+     *
+     * @param string $number The number to convert, positive or zero, only digits.
+     *
+     * @return string
+     */
+    private function toBinary(string $number) : string
+    {
+        $result = '';
+
+        while ($number !== '0') {
+            [$number, $remainder] = $this->divQR($number, '256');
+            $result .= \chr((int) $remainder);
+        }
+
+        return \strrev($result);
+    }
+
+    /**
+     * Returns the positive decimal representation of a binary number.
+     *
+     * @param string $bytes The bytes representing the number.
+     *
+     * @return string
+     */
+    private function toDecimal(string $bytes) : string
+    {
+        $result = '0';
+        $power = '1';
+
+        for ($i = \strlen($bytes) - 1; $i >= 0; $i--) {
+            $index = \ord($bytes[$i]);
+
+            if ($index !== 0) {
+                $result = $this->add($result, ($index === 1)
+                    ? $power
+                    : $this->mul($power, (string) $index)
+                );
+            }
+
+            if ($i !== 0) {
+                $power = $this->mul($power, '256');
+            }
+        }
+
+        return $result;
+    }
+}

+ 116 - 0
api/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php

@@ -0,0 +1,116 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Internal\Calculator;
+
+use Brick\Math\Internal\Calculator;
+
+/**
+ * Calculator implementation built around the bcmath library.
+ *
+ * @internal
+ *
+ * @psalm-immutable
+ */
+class BcMathCalculator extends Calculator
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function add(string $a, string $b) : string
+    {
+        return \bcadd($a, $b, 0);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function sub(string $a, string $b) : string
+    {
+        return \bcsub($a, $b, 0);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function mul(string $a, string $b) : string
+    {
+        return \bcmul($a, $b, 0);
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @psalm-suppress InvalidNullableReturnType
+     * @psalm-suppress NullableReturnStatement
+     */
+    public function divQ(string $a, string $b) : string
+    {
+        return \bcdiv($a, $b, 0);
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @psalm-suppress InvalidNullableReturnType
+     * @psalm-suppress NullableReturnStatement
+     */
+    public function divR(string $a, string $b) : string
+    {
+        if (version_compare(PHP_VERSION, '7.2') >= 0) {
+            return \bcmod($a, $b, 0);
+        }
+
+        return \bcmod($a, $b);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function divQR(string $a, string $b) : array
+    {
+        $q = \bcdiv($a, $b, 0);
+
+        if (version_compare(PHP_VERSION, '7.2') >= 0) {
+            $r = \bcmod($a, $b, 0);
+        } else {
+            $r = \bcmod($a, $b);
+        }
+
+        assert($q !== null);
+        assert($r !== null);
+
+        return [$q, $r];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function pow(string $a, int $e) : string
+    {
+        return \bcpow($a, (string) $e, 0);
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @psalm-suppress InvalidNullableReturnType
+     * @psalm-suppress NullableReturnStatement
+     */
+    public function modPow(string $base, string $exp, string $mod) : string
+    {
+        return \bcpowmod($base, $exp, $mod, 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @psalm-suppress NullableReturnStatement
+     * @psalm-suppress InvalidNullableReturnType
+     */
+    public function sqrt(string $n) : string
+    {
+        return \bcsqrt($n, 0);
+    }
+}

+ 156 - 0
api/vendor/brick/math/src/Internal/Calculator/GmpCalculator.php

@@ -0,0 +1,156 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Internal\Calculator;
+
+use Brick\Math\Internal\Calculator;
+
+/**
+ * Calculator implementation built around the GMP library.
+ *
+ * @internal
+ *
+ * @psalm-immutable
+ */
+class GmpCalculator extends Calculator
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function add(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_add($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function sub(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_sub($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function mul(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_mul($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function divQ(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_div_q($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function divR(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_div_r($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function divQR(string $a, string $b) : array
+    {
+        [$q, $r] = \gmp_div_qr($a, $b);
+
+        return [
+            \gmp_strval($q),
+            \gmp_strval($r)
+        ];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function pow(string $a, int $e) : string
+    {
+        return \gmp_strval(\gmp_pow($a, $e));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function modInverse(string $x, string $m) : ?string
+    {
+        $result = \gmp_invert($x, $m);
+
+        if ($result === false) {
+            return null;
+        }
+
+        return \gmp_strval($result);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function modPow(string $base, string $exp, string $mod) : string
+    {
+        return \gmp_strval(\gmp_powm($base, $exp, $mod));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function gcd(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_gcd($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function fromBase(string $number, int $base) : string
+    {
+        return \gmp_strval(\gmp_init($number, $base));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function toBase(string $number, int $base) : string
+    {
+        return \gmp_strval($number, $base);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function and(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_and($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function or(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_or($a, $b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function xor(string $a, string $b) : string
+    {
+        return \gmp_strval(\gmp_xor($a, $b));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function sqrt(string $n) : string
+    {
+        return \gmp_strval(\gmp_sqrt($n));
+    }
+}

+ 634 - 0
api/vendor/brick/math/src/Internal/Calculator/NativeCalculator.php

@@ -0,0 +1,634 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math\Internal\Calculator;
+
+use Brick\Math\Internal\Calculator;
+
+/**
+ * Calculator implementation using only native PHP code.
+ *
+ * @internal
+ *
+ * @psalm-immutable
+ */
+class NativeCalculator extends Calculator
+{
+    /**
+     * The max number of digits the platform can natively add, subtract, multiply or divide without overflow.
+     * For multiplication, this represents the max sum of the lengths of both operands.
+     *
+     * For addition, it is assumed that an extra digit can hold a carry (1) without overflowing.
+     * Example: 32-bit: max number 1,999,999,999 (9 digits + carry)
+     *          64-bit: max number 1,999,999,999,999,999,999 (18 digits + carry)
+     *
+     * @var int
+     */
+    private $maxDigits;
+
+    /**
+     * Class constructor.
+     *
+     * @codeCoverageIgnore
+     */
+    public function __construct()
+    {
+        switch (PHP_INT_SIZE) {
+            case 4:
+                $this->maxDigits = 9;
+                break;
+
+            case 8:
+                $this->maxDigits = 18;
+                break;
+
+            default:
+                throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.');
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function add(string $a, string $b) : string
+    {
+        /**
+         * @psalm-var numeric-string $a
+         * @psalm-var numeric-string $b
+         */
+        $result = $a + $b;
+
+        if (is_int($result)) {
+            return (string) $result;
+        }
+
+        if ($a === '0') {
+            return $b;
+        }
+
+        if ($b === '0') {
+            return $a;
+        }
+
+        [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+        $result = $aNeg === $bNeg ? $this->doAdd($aDig, $bDig) : $this->doSub($aDig, $bDig);
+
+        if ($aNeg) {
+            $result = $this->neg($result);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function sub(string $a, string $b) : string
+    {
+        return $this->add($a, $this->neg($b));
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function mul(string $a, string $b) : string
+    {
+        /**
+         * @psalm-var numeric-string $a
+         * @psalm-var numeric-string $b
+         */
+        $result = $a * $b;
+
+        if (is_int($result)) {
+            return (string) $result;
+        }
+
+        if ($a === '0' || $b === '0') {
+            return '0';
+        }
+
+        if ($a === '1') {
+            return $b;
+        }
+
+        if ($b === '1') {
+            return $a;
+        }
+
+        if ($a === '-1') {
+            return $this->neg($b);
+        }
+
+        if ($b === '-1') {
+            return $this->neg($a);
+        }
+
+        [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+        $result = $this->doMul($aDig, $bDig);
+
+        if ($aNeg !== $bNeg) {
+            $result = $this->neg($result);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function divQ(string $a, string $b) : string
+    {
+        return $this->divQR($a, $b)[0];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function divR(string $a, string $b): string
+    {
+        return $this->divQR($a, $b)[1];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function divQR(string $a, string $b) : array
+    {
+        if ($a === '0') {
+            return ['0', '0'];
+        }
+
+        if ($a === $b) {
+            return ['1', '0'];
+        }
+
+        if ($b === '1') {
+            return [$a, '0'];
+        }
+
+        if ($b === '-1') {
+            return [$this->neg($a), '0'];
+        }
+
+        /** @psalm-var numeric-string $a */
+        $na = $a * 1; // cast to number
+
+        if (is_int($na)) {
+            /** @psalm-var numeric-string $b */
+            $nb = $b * 1;
+
+            if (is_int($nb)) {
+                // the only division that may overflow is PHP_INT_MIN / -1,
+                // which cannot happen here as we've already handled a divisor of -1 above.
+                $r = $na % $nb;
+                $q = ($na - $r) / $nb;
+
+                assert(is_int($q));
+
+                return [
+                    (string) $q,
+                    (string) $r
+                ];
+            }
+        }
+
+        [$aNeg, $bNeg, $aDig, $bDig] = $this->init($a, $b);
+
+        [$q, $r] = $this->doDiv($aDig, $bDig);
+
+        if ($aNeg !== $bNeg) {
+            $q = $this->neg($q);
+        }
+
+        if ($aNeg) {
+            $r = $this->neg($r);
+        }
+
+        return [$q, $r];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function pow(string $a, int $e) : string
+    {
+        if ($e === 0) {
+            return '1';
+        }
+
+        if ($e === 1) {
+            return $a;
+        }
+
+        $odd = $e % 2;
+        $e -= $odd;
+
+        $aa = $this->mul($a, $a);
+
+        /** @psalm-suppress PossiblyInvalidArgument We're sure that $e / 2 is an int now */
+        $result = $this->pow($aa, $e / 2);
+
+        if ($odd === 1) {
+            $result = $this->mul($result, $a);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Algorithm from: https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/
+     *
+     * {@inheritdoc}
+     */
+    public function modPow(string $base, string $exp, string $mod) : string
+    {
+        // special case: the algorithm below fails with 0 power 0 mod 1 (returns 1 instead of 0)
+        if ($base === '0' && $exp === '0' && $mod === '1') {
+            return '0';
+        }
+
+        // special case: the algorithm below fails with power 0 mod 1 (returns 1 instead of 0)
+        if ($exp === '0' && $mod === '1') {
+            return '0';
+        }
+
+        $x = $base;
+
+        $res = '1';
+
+        // numbers are positive, so we can use remainder instead of modulo
+        $x = $this->divR($x, $mod);
+
+        while ($exp !== '0') {
+            if (in_array($exp[-1], ['1', '3', '5', '7', '9'])) { // odd
+                $res = $this->divR($this->mul($res, $x), $mod);
+            }
+
+            $exp = $this->divQ($exp, '2');
+            $x = $this->divR($this->mul($x, $x), $mod);
+        }
+
+        return $res;
+    }
+
+    /**
+     * Adapted from https://cp-algorithms.com/num_methods/roots_newton.html
+     *
+     * {@inheritDoc}
+     */
+    public function sqrt(string $n) : string
+    {
+        if ($n === '0') {
+            return '0';
+        }
+
+        // initial approximation
+        $x = \str_repeat('9', \intdiv(\strlen($n), 2) ?: 1);
+
+        $decreased = false;
+
+        for (;;) {
+            $nx = $this->divQ($this->add($x, $this->divQ($n, $x)), '2');
+
+            if ($x === $nx || $this->cmp($nx, $x) > 0 && $decreased) {
+                break;
+            }
+
+            $decreased = $this->cmp($nx, $x) < 0;
+            $x = $nx;
+        }
+
+        return $x;
+    }
+
+    /**
+     * Performs the addition of two non-signed large integers.
+     *
+     * @param string $a The first operand.
+     * @param string $b The second operand.
+     *
+     * @return string
+     */
+    private function doAdd(string $a, string $b) : string
+    {
+        [$a, $b, $length] = $this->pad($a, $b);
+
+        $carry = 0;
+        $result = '';
+
+        for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) {
+            $blockLength = $this->maxDigits;
+
+            if ($i < 0) {
+                $blockLength += $i;
+                /** @psalm-suppress LoopInvalidation */
+                $i = 0;
+            }
+
+            /** @psalm-var numeric-string $blockA */
+            $blockA = \substr($a, $i, $blockLength);
+
+            /** @psalm-var numeric-string $blockB */
+            $blockB = \substr($b, $i, $blockLength);
+
+            $sum = (string) ($blockA + $blockB + $carry);
+            $sumLength = \strlen($sum);
+
+            if ($sumLength > $blockLength) {
+                $sum = \substr($sum, 1);
+                $carry = 1;
+            } else {
+                if ($sumLength < $blockLength) {
+                    $sum = \str_repeat('0', $blockLength - $sumLength) . $sum;
+                }
+                $carry = 0;
+            }
+
+            $result = $sum . $result;
+
+            if ($i === 0) {
+                break;
+            }
+        }
+
+        if ($carry === 1) {
+            $result = '1' . $result;
+        }
+
+        return $result;
+    }
+
+    /**
+     * Performs the subtraction of two non-signed large integers.
+     *
+     * @param string $a The first operand.
+     * @param string $b The second operand.
+     *
+     * @return string
+     */
+    private function doSub(string $a, string $b) : string
+    {
+        if ($a === $b) {
+            return '0';
+        }
+
+        // Ensure that we always subtract to a positive result: biggest minus smallest.
+        $cmp = $this->doCmp($a, $b);
+
+        $invert = ($cmp === -1);
+
+        if ($invert) {
+            $c = $a;
+            $a = $b;
+            $b = $c;
+        }
+
+        [$a, $b, $length] = $this->pad($a, $b);
+
+        $carry = 0;
+        $result = '';
+
+        $complement = 10 ** $this->maxDigits;
+
+        for ($i = $length - $this->maxDigits;; $i -= $this->maxDigits) {
+            $blockLength = $this->maxDigits;
+
+            if ($i < 0) {
+                $blockLength += $i;
+                /** @psalm-suppress LoopInvalidation */
+                $i = 0;
+            }
+
+            /** @psalm-var numeric-string $blockA */
+            $blockA = \substr($a, $i, $blockLength);
+
+            /** @psalm-var numeric-string $blockB */
+            $blockB = \substr($b, $i, $blockLength);
+
+            $sum = $blockA - $blockB - $carry;
+
+            if ($sum < 0) {
+                $sum += $complement;
+                $carry = 1;
+            } else {
+                $carry = 0;
+            }
+
+            $sum = (string) $sum;
+            $sumLength = \strlen($sum);
+
+            if ($sumLength < $blockLength) {
+                $sum = \str_repeat('0', $blockLength - $sumLength) . $sum;
+            }
+
+            $result = $sum . $result;
+
+            if ($i === 0) {
+                break;
+            }
+        }
+
+        // Carry cannot be 1 when the loop ends, as a > b
+        assert($carry === 0);
+
+        $result = \ltrim($result, '0');
+
+        if ($invert) {
+            $result = $this->neg($result);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Performs the multiplication of two non-signed large integers.
+     *
+     * @param string $a The first operand.
+     * @param string $b The second operand.
+     *
+     * @return string
+     */
+    private function doMul(string $a, string $b) : string
+    {
+        $x = \strlen($a);
+        $y = \strlen($b);
+
+        $maxDigits = \intdiv($this->maxDigits, 2);
+        $complement = 10 ** $maxDigits;
+
+        $result = '0';
+
+        for ($i = $x - $maxDigits;; $i -= $maxDigits) {
+            $blockALength = $maxDigits;
+
+            if ($i < 0) {
+                $blockALength += $i;
+                /** @psalm-suppress LoopInvalidation */
+                $i = 0;
+            }
+
+            $blockA = (int) \substr($a, $i, $blockALength);
+
+            $line = '';
+            $carry = 0;
+
+            for ($j = $y - $maxDigits;; $j -= $maxDigits) {
+                $blockBLength = $maxDigits;
+
+                if ($j < 0) {
+                    $blockBLength += $j;
+                    /** @psalm-suppress LoopInvalidation */
+                    $j = 0;
+                }
+
+                $blockB = (int) \substr($b, $j, $blockBLength);
+
+                $mul = $blockA * $blockB + $carry;
+                $value = $mul % $complement;
+                $carry = ($mul - $value) / $complement;
+
+                $value = (string) $value;
+                $value = \str_pad($value, $maxDigits, '0', STR_PAD_LEFT);
+
+                $line = $value . $line;
+
+                if ($j === 0) {
+                    break;
+                }
+            }
+
+            if ($carry !== 0) {
+                $line = $carry . $line;
+            }
+
+            $line = \ltrim($line, '0');
+
+            if ($line !== '') {
+                $line .= \str_repeat('0', $x - $blockALength - $i);
+                $result = $this->add($result, $line);
+            }
+
+            if ($i === 0) {
+                break;
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Performs the division of two non-signed large integers.
+     *
+     * @param string $a The first operand.
+     * @param string $b The second operand.
+     *
+     * @return string[] The quotient and remainder.
+     */
+    private function doDiv(string $a, string $b) : array
+    {
+        $cmp = $this->doCmp($a, $b);
+
+        if ($cmp === -1) {
+            return ['0', $a];
+        }
+
+        $x = \strlen($a);
+        $y = \strlen($b);
+
+        // we now know that a >= b && x >= y
+
+        $q = '0'; // quotient
+        $r = $a; // remainder
+        $z = $y; // focus length, always $y or $y+1
+
+        for (;;) {
+            $focus = \substr($a, 0, $z);
+
+            $cmp = $this->doCmp($focus, $b);
+
+            if ($cmp === -1) {
+                if ($z === $x) { // remainder < dividend
+                    break;
+                }
+
+                $z++;
+            }
+
+            $zeros = \str_repeat('0', $x - $z);
+
+            $q = $this->add($q, '1' . $zeros);
+            $a = $this->sub($a, $b . $zeros);
+
+            $r = $a;
+
+            if ($r === '0') { // remainder == 0
+                break;
+            }
+
+            $x = \strlen($a);
+
+            if ($x < $y) { // remainder < dividend
+                break;
+            }
+
+            $z = $y;
+        }
+
+        return [$q, $r];
+    }
+
+    /**
+     * Compares two non-signed large numbers.
+     *
+     * @param string $a The first operand.
+     * @param string $b The second operand.
+     *
+     * @return int [-1, 0, 1]
+     */
+    private function doCmp(string $a, string $b) : int
+    {
+        $x = \strlen($a);
+        $y = \strlen($b);
+
+        $cmp = $x <=> $y;
+
+        if ($cmp !== 0) {
+            return $cmp;
+        }
+
+        return \strcmp($a, $b) <=> 0; // enforce [-1, 0, 1]
+    }
+
+    /**
+     * Pads the left of one of the given numbers with zeros if necessary to make both numbers the same length.
+     *
+     * The numbers must only consist of digits, without leading minus sign.
+     *
+     * @param string $a The first operand.
+     * @param string $b The second operand.
+     *
+     * @return array{string, string, int}
+     */
+    private function pad(string $a, string $b) : array
+    {
+        $x = \strlen($a);
+        $y = \strlen($b);
+
+        if ($x > $y) {
+            $b = \str_repeat('0', $x - $y) . $b;
+
+            return [$a, $b, $x];
+        }
+
+        if ($x < $y) {
+            $a = \str_repeat('0', $y - $x) . $a;
+
+            return [$a, $b, $y];
+        }
+
+        return [$a, $b, $x];
+    }
+}

+ 107 - 0
api/vendor/brick/math/src/RoundingMode.php

@@ -0,0 +1,107 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Brick\Math;
+
+/**
+ * Specifies a rounding behavior for numerical operations capable of discarding precision.
+ *
+ * Each rounding mode indicates how the least significant returned digit of a rounded result
+ * is to be calculated. If fewer digits are returned than the digits needed to represent the
+ * exact numerical result, the discarded digits will be referred to as the discarded fraction
+ * regardless the digits' contribution to the value of the number. In other words, considered
+ * as a numerical value, the discarded fraction could have an absolute value greater than one.
+ */
+final class RoundingMode
+{
+    /**
+     * Private constructor. This class is not instantiable.
+     *
+     * @codeCoverageIgnore
+     */
+    private function __construct()
+    {
+    }
+
+    /**
+     * Asserts that the requested operation has an exact result, hence no rounding is necessary.
+     *
+     * If this rounding mode is specified on an operation that yields a result that
+     * cannot be represented at the requested scale, a RoundingNecessaryException is thrown.
+     */
+    public const UNNECESSARY = 0;
+
+    /**
+     * Rounds away from zero.
+     *
+     * Always increments the digit prior to a nonzero discarded fraction.
+     * Note that this rounding mode never decreases the magnitude of the calculated value.
+     */
+    public const UP = 1;
+
+    /**
+     * Rounds towards zero.
+     *
+     * Never increments the digit prior to a discarded fraction (i.e., truncates).
+     * Note that this rounding mode never increases the magnitude of the calculated value.
+     */
+    public const DOWN = 2;
+
+    /**
+     * Rounds towards positive infinity.
+     *
+     * If the result is positive, behaves as for UP; if negative, behaves as for DOWN.
+     * Note that this rounding mode never decreases the calculated value.
+     */
+    public const CEILING = 3;
+
+    /**
+     * Rounds towards negative infinity.
+     *
+     * If the result is positive, behave as for DOWN; if negative, behave as for UP.
+     * Note that this rounding mode never increases the calculated value.
+     */
+    public const FLOOR = 4;
+
+    /**
+     * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
+     *
+     * Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN.
+     * Note that this is the rounding mode commonly taught at school.
+     */
+    public const HALF_UP = 5;
+
+    /**
+     * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
+     *
+     * Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN.
+     */
+    public const HALF_DOWN = 6;
+
+    /**
+     * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity.
+     *
+     * If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN.
+     */
+    public const HALF_CEILING = 7;
+
+    /**
+     * Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity.
+     *
+     * If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP.
+     */
+    public const HALF_FLOOR = 8;
+
+    /**
+     * Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor.
+     *
+     * Behaves as for HALF_UP if the digit to the left of the discarded fraction is odd;
+     * behaves as for HALF_DOWN if it's even.
+     *
+     * Note that this is the rounding mode that statistically minimizes
+     * cumulative error when applied repeatedly over a sequence of calculations.
+     * It is sometimes known as "Banker's rounding", and is chiefly used in the USA.
+     */
+    public const HALF_EVEN = 9;
+}

+ 1 - 0
api/vendor/composer/autoload_classmap.php

@@ -75,6 +75,7 @@ return array(
     'Dibi\\Translator' => $vendorDir . '/dibi/dibi/src/Dibi/Translator.php',
     'Dibi\\Type' => $vendorDir . '/dibi/dibi/src/Dibi/Type.php',
     'Dibi\\UniqueConstraintViolationException' => $vendorDir . '/dibi/dibi/src/Dibi/exceptions.php',
+    'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
     'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
     'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
     'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',

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

@@ -13,13 +13,14 @@ return array(
     '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
     '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
     '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
+    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
+    '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
     '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.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',
     'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php',
     'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php',
-    'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
     'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',
     'caf31cc6ec7cf2241cb6f12c226c3846' => $vendorDir . '/tightenco/collect/src/Collect/Support/alias.php',
     '0ccdf99b8f62f02c52cba55802e0c2e7' => $vendorDir . '/zircote/swagger-php/src/functions.php',

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

@@ -9,6 +9,7 @@ return array(
     'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'),
     'Tightenco\\Collect\\' => array($vendorDir . '/tightenco/collect/src/Collect'),
     'Symfony\\Polyfill\\Util\\' => array($vendorDir . '/symfony/polyfill-util'),
+    'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'),
     'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
     'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
     'Symfony\\Polyfill\\Php56\\' => array($vendorDir . '/symfony/polyfill-php56'),
@@ -22,6 +23,7 @@ return array(
     'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
     'Recurr\\' => array($vendorDir . '/simshaun/recurr/src/Recurr'),
     'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'),
+    'Ramsey\\Collection\\' => array($vendorDir . '/ramsey/collection/src'),
     'Pusher\\' => array($vendorDir . '/pusher/pusher-php-server/src'),
     'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
@@ -58,6 +60,7 @@ return array(
     'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
     'Cron\\' => array($vendorDir . '/dragonmantank/cron-expression/src/Cron'),
     'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
+    'Brick\\Math\\' => array($vendorDir . '/brick/math/src'),
     'Bogstag\\OAuth2\\Client\\' => array($vendorDir . '/bogstag/oauth2-trakt/src'),
     'Bcremer\\LineReader\\' => array($vendorDir . '/bcremer/line-reader/src'),
     'Adldap\\' => array($vendorDir . '/adldap2/adldap2/src'),

+ 1 - 1
api/vendor/composer/autoload_real.php

@@ -29,7 +29,7 @@ class ComposerAutoloaderInitcbdc783d76f8e7563dcce7d8af053ecb
         spl_autoload_unregister(array('ComposerAutoloaderInitcbdc783d76f8e7563dcce7d8af053ecb', 'loadClassLoader'));
 
         require __DIR__ . '/autoload_static.php';
-        \Composer\Autoload\ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb::getInitializer($loader)();
+        call_user_func(\Composer\Autoload\ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb::getInitializer($loader));
 
         $loader->register(true);
 

+ 18 - 1
api/vendor/composer/autoload_static.php

@@ -14,13 +14,14 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
         '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
         '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
+        'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
+        '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
         '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.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',
         'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php',
         'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php',
-        'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
         'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
         'caf31cc6ec7cf2241cb6f12c226c3846' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/alias.php',
         '0ccdf99b8f62f02c52cba55802e0c2e7' => __DIR__ . '/..' . '/zircote/swagger-php/src/functions.php',
@@ -38,6 +39,7 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'S' => 
         array (
             'Symfony\\Polyfill\\Util\\' => 22,
+            'Symfony\\Polyfill\\Php81\\' => 23,
             'Symfony\\Polyfill\\Php80\\' => 23,
             'Symfony\\Polyfill\\Php72\\' => 23,
             'Symfony\\Polyfill\\Php56\\' => 23,
@@ -54,6 +56,7 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             'Recurr\\' => 7,
             'Ramsey\\Uuid\\' => 12,
+            'Ramsey\\Collection\\' => 18,
         ),
         'P' => 
         array (
@@ -129,6 +132,7 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         ),
         'B' => 
         array (
+            'Brick\\Math\\' => 11,
             'Bogstag\\OAuth2\\Client\\' => 22,
             'Bcremer\\LineReader\\' => 19,
         ),
@@ -151,6 +155,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/symfony/polyfill-util',
         ),
+        'Symfony\\Polyfill\\Php81\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-php81',
+        ),
         'Symfony\\Polyfill\\Php80\\' => 
         array (
             0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
@@ -203,6 +211,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/ramsey/uuid/src',
         ),
+        'Ramsey\\Collection\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/ramsey/collection/src',
+        ),
         'Pusher\\' => 
         array (
             0 => __DIR__ . '/..' . '/pusher/pusher-php-server/src',
@@ -349,6 +361,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/composer/semver/src',
         ),
+        'Brick\\Math\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/brick/math/src',
+        ),
         'Bogstag\\OAuth2\\Client\\' => 
         array (
             0 => __DIR__ . '/..' . '/bogstag/oauth2-trakt/src',
@@ -450,6 +466,7 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         'Dibi\\Translator' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Translator.php',
         'Dibi\\Type' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Type.php',
         'Dibi\\UniqueConstraintViolationException' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/exceptions.php',
+        'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
         'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
         'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
         'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',

+ 269 - 49
api/vendor/composer/installed.json

@@ -173,6 +173,69 @@
             },
             "install-path": "../bogstag/oauth2-trakt"
         },
+        {
+            "name": "brick/math",
+            "version": "0.9.3",
+            "version_normalized": "0.9.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/brick/math.git",
+                "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae",
+                "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "php-coveralls/php-coveralls": "^2.2",
+                "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
+                "vimeo/psalm": "4.9.2"
+            },
+            "time": "2021-08-15T20:50:18+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Brick\\Math\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Arbitrary-precision arithmetic library",
+            "keywords": [
+                "Arbitrary-precision",
+                "BigInteger",
+                "BigRational",
+                "arithmetic",
+                "bigdecimal",
+                "bignum",
+                "brick",
+                "math"
+            ],
+            "support": {
+                "issues": "https://github.com/brick/math/issues",
+                "source": "https://github.com/brick/math/tree/0.9.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/BenMorel",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/brick/math",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../brick/math"
+        },
         {
             "name": "composer/semver",
             "version": "1.7.2",
@@ -2721,91 +2784,168 @@
             "description": "A polyfill for getallheaders.",
             "install-path": "../ralouphie/getallheaders"
         },
+        {
+            "name": "ramsey/collection",
+            "version": "1.2.2",
+            "version_normalized": "1.2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ramsey/collection.git",
+                "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a",
+                "reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.3 || ^8",
+                "symfony/polyfill-php81": "^1.23"
+            },
+            "require-dev": {
+                "captainhook/captainhook": "^5.3",
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "ergebnis/composer-normalize": "^2.6",
+                "fakerphp/faker": "^1.5",
+                "hamcrest/hamcrest-php": "^2",
+                "jangregor/phpstan-prophecy": "^0.8",
+                "mockery/mockery": "^1.3",
+                "phpspec/prophecy-phpunit": "^2.0",
+                "phpstan/extension-installer": "^1",
+                "phpstan/phpstan": "^0.12.32",
+                "phpstan/phpstan-mockery": "^0.12.5",
+                "phpstan/phpstan-phpunit": "^0.12.11",
+                "phpunit/phpunit": "^8.5 || ^9",
+                "psy/psysh": "^0.10.4",
+                "slevomat/coding-standard": "^6.3",
+                "squizlabs/php_codesniffer": "^3.5",
+                "vimeo/psalm": "^4.4"
+            },
+            "time": "2021-10-10T03:01:02+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Ramsey\\Collection\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ben Ramsey",
+                    "email": "ben@benramsey.com",
+                    "homepage": "https://benramsey.com"
+                }
+            ],
+            "description": "A PHP library for representing and manipulating collections.",
+            "keywords": [
+                "array",
+                "collection",
+                "hash",
+                "map",
+                "queue",
+                "set"
+            ],
+            "support": {
+                "issues": "https://github.com/ramsey/collection/issues",
+                "source": "https://github.com/ramsey/collection/tree/1.2.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/ramsey",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../ramsey/collection"
+        },
         {
             "name": "ramsey/uuid",
-            "version": "3.9.6",
-            "version_normalized": "3.9.6.0",
+            "version": "4.2.3",
+            "version_normalized": "4.2.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/uuid.git",
-                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3"
+                "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ramsey/uuid/zipball/ffa80ab953edd85d5b6c004f96181a538aad35a3",
-                "reference": "ffa80ab953edd85d5b6c004f96181a538aad35a3",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
+                "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
                 "shasum": ""
             },
             "require": {
+                "brick/math": "^0.8 || ^0.9",
                 "ext-json": "*",
-                "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
-                "php": "^5.4 | ^7.0 | ^8.0",
-                "symfony/polyfill-ctype": "^1.8"
+                "php": "^7.2 || ^8.0",
+                "ramsey/collection": "^1.0",
+                "symfony/polyfill-ctype": "^1.8",
+                "symfony/polyfill-php80": "^1.14"
             },
             "replace": {
                 "rhumsaa/uuid": "self.version"
             },
             "require-dev": {
-                "codeception/aspect-mock": "^1 | ^2",
-                "doctrine/annotations": "^1.2",
-                "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
-                "mockery/mockery": "^0.9.11 | ^1",
+                "captainhook/captainhook": "^5.10",
+                "captainhook/plugin-composer": "^5.3",
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "doctrine/annotations": "^1.8",
+                "ergebnis/composer-normalize": "^2.15",
+                "mockery/mockery": "^1.3",
                 "moontoast/math": "^1.1",
-                "nikic/php-parser": "<=4.5.0",
                 "paragonie/random-lib": "^2",
-                "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
-                "php-parallel-lint/php-parallel-lint": "^1.3",
-                "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+                "php-mock/php-mock": "^2.2",
+                "php-mock/php-mock-mockery": "^1.3",
+                "php-parallel-lint/php-parallel-lint": "^1.1",
+                "phpbench/phpbench": "^1.0",
+                "phpstan/extension-installer": "^1.0",
+                "phpstan/phpstan": "^0.12",
+                "phpstan/phpstan-mockery": "^0.12",
+                "phpstan/phpstan-phpunit": "^0.12",
+                "phpunit/phpunit": "^8.5 || ^9",
+                "slevomat/coding-standard": "^7.0",
                 "squizlabs/php_codesniffer": "^3.5",
-                "yoast/phpunit-polyfills": "^1.0"
+                "vimeo/psalm": "^4.9"
             },
             "suggest": {
-                "ext-ctype": "Provides support for PHP Ctype functions",
-                "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
-                "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
-                "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
-                "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+                "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
+                "ext-ctype": "Enables faster processing of character classification using ctype functions.",
+                "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
+                "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
                 "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
-                "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
                 "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
             },
-            "time": "2021-09-25T23:07:42+00:00",
+            "time": "2021-09-25T23:10:38+00:00",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.x-dev"
+                    "dev-main": "4.x-dev"
+                },
+                "captainhook": {
+                    "force-install": true
                 }
             },
             "installation-source": "dist",
             "autoload": {
-                "psr-4": {
-                    "Ramsey\\Uuid\\": "src/"
-                },
                 "files": [
                     "src/functions.php"
-                ]
+                ],
+                "psr-4": {
+                    "Ramsey\\Uuid\\": "src/"
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                 "MIT"
             ],
-            "authors": [
-                {
-                    "name": "Ben Ramsey",
-                    "email": "ben@benramsey.com",
-                    "homepage": "https://benramsey.com"
-                },
-                {
-                    "name": "Marijn Huizendveld",
-                    "email": "marijn.huizendveld@gmail.com"
-                },
-                {
-                    "name": "Thibaud Fabre",
-                    "email": "thibaud@aztech.io"
-                }
-            ],
-            "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
-            "homepage": "https://github.com/ramsey/uuid",
+            "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
             "keywords": [
                 "guid",
                 "identifier",
@@ -2813,9 +2953,7 @@
             ],
             "support": {
                 "issues": "https://github.com/ramsey/uuid/issues",
-                "rss": "https://github.com/ramsey/uuid/releases.atom",
-                "source": "https://github.com/ramsey/uuid",
-                "wiki": "https://github.com/ramsey/uuid/wiki"
+                "source": "https://github.com/ramsey/uuid/tree/4.2.3"
             },
             "funding": [
                 {
@@ -3712,6 +3850,88 @@
             ],
             "install-path": "../symfony/polyfill-php80"
         },
+        {
+            "name": "symfony/polyfill-php81",
+            "version": "v1.25.0",
+            "version_normalized": "1.25.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php81.git",
+                "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
+                "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "time": "2021-09-13T13:58:11+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.23-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php81\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/polyfill-php81"
+        },
         {
             "name": "symfony/polyfill-util",
             "version": "v1.9.0",

+ 33 - 6
api/vendor/composer/installed.php

@@ -5,7 +5,7 @@
         'type' => 'library',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
-        'reference' => 'e20df3c36c967d374fdacb21f84497b19e5f042e',
+        'reference' => '1ae02fda50382bb86ea50b76579b5e773c4a1ff1',
         'name' => '__root__',
         'dev' => true,
     ),
@@ -16,7 +16,7 @@
             'type' => 'library',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
-            'reference' => 'e20df3c36c967d374fdacb21f84497b19e5f042e',
+            'reference' => '1ae02fda50382bb86ea50b76579b5e773c4a1ff1',
             'dev_requirement' => false,
         ),
         'adldap2/adldap2' => array(
@@ -46,6 +46,15 @@
             'reference' => 'fbb9253d9e317e84dc2b3f1253afc1dcbb4414a2',
             'dev_requirement' => false,
         ),
+        'brick/math' => array(
+            'pretty_version' => '0.9.3',
+            'version' => '0.9.3.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../brick/math',
+            'aliases' => array(),
+            'reference' => 'ca57d18f028f84f777b2168cd1911b0dee2343ae',
+            'dev_requirement' => false,
+        ),
         'composer/semver' => array(
             'pretty_version' => '1.7.2',
             'version' => '1.7.2.0',
@@ -451,19 +460,28 @@
             'reference' => '120b605dfeb996808c31b6477290a714d356e822',
             'dev_requirement' => false,
         ),
+        'ramsey/collection' => array(
+            'pretty_version' => '1.2.2',
+            'version' => '1.2.2.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../ramsey/collection',
+            'aliases' => array(),
+            'reference' => 'cccc74ee5e328031b15640b51056ee8d3bb66c0a',
+            'dev_requirement' => false,
+        ),
         'ramsey/uuid' => array(
-            'pretty_version' => '3.9.6',
-            'version' => '3.9.6.0',
+            'pretty_version' => '4.2.3',
+            'version' => '4.2.3.0',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ramsey/uuid',
             'aliases' => array(),
-            'reference' => 'ffa80ab953edd85d5b6c004f96181a538aad35a3',
+            'reference' => 'fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df',
             'dev_requirement' => false,
         ),
         'rhumsaa/uuid' => array(
             'dev_requirement' => false,
             'replaced' => array(
-                0 => '3.9.6',
+                0 => '4.2.3',
             ),
         ),
         'rmccue/requests' => array(
@@ -574,6 +592,15 @@
             'reference' => 'dc3063ba22c2a1fd2f45ed856374d79114998f91',
             'dev_requirement' => false,
         ),
+        'symfony/polyfill-php81' => array(
+            'pretty_version' => 'v1.25.0',
+            'version' => '1.25.0.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/polyfill-php81',
+            'aliases' => array(),
+            'reference' => '5de4ba2d41b15f9bd0e19b2ab9674135813ec98f',
+            'dev_requirement' => false,
+        ),
         'symfony/polyfill-util' => array(
             'pretty_version' => 'v1.9.0',
             'version' => '1.9.0.0',

+ 19 - 0
api/vendor/ramsey/collection/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2015-2021 Ben Ramsey <ben@benramsey.com>
+
+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.

+ 82 - 0
api/vendor/ramsey/collection/README.md

@@ -0,0 +1,82 @@
+<h1 align="center">ramsey/collection</h1>
+
+<p align="center">
+    <strong>A PHP library for representing and manipulating collections.</strong>
+</p>
+
+<p align="center">
+    <a href="https://github.com/ramsey/collection"><img src="http://img.shields.io/badge/source-ramsey/collection-blue.svg?style=flat-square" alt="Source Code"></a>
+    <a href="https://packagist.org/packages/ramsey/collection"><img src="https://img.shields.io/packagist/v/ramsey/collection.svg?style=flat-square&label=release" alt="Download Package"></a>
+    <a href="https://php.net"><img src="https://img.shields.io/packagist/php-v/ramsey/collection.svg?style=flat-square&colorB=%238892BF" alt="PHP Programming Language"></a>
+    <a href="https://github.com/ramsey/collection/blob/master/LICENSE"><img src="https://img.shields.io/packagist/l/ramsey/collection.svg?style=flat-square&colorB=darkcyan" alt="Read License"></a>
+    <a href="https://github.com/ramsey/collection/actions?query=workflow%3ACI"><img src="https://img.shields.io/github/workflow/status/ramsey/collection/CI?label=CI&logo=github&style=flat-square" alt="Build Status"></a>
+    <a href="https://codecov.io/gh/ramsey/collection"><img src="https://img.shields.io/codecov/c/gh/ramsey/collection?label=codecov&logo=codecov&style=flat-square" alt="Codecov Code Coverage"></a>
+    <a href="https://shepherd.dev/github/ramsey/collection"><img src="https://img.shields.io/endpoint?style=flat-square&url=https%3A%2F%2Fshepherd.dev%2Fgithub%2Framsey%2Fcollection%2Fcoverage" alt="Psalm Type Coverage"></a>
+</p>
+
+## About
+
+ramsey/collection is a PHP library for representing and manipulating collections.
+
+Much inspiration for this library came from the [Java Collections Framework][java].
+
+This project adheres to a [code of conduct](CODE_OF_CONDUCT.md).
+By participating in this project and its community, you are expected to
+uphold this code.
+
+## Installation
+
+Install this package as a dependency using [Composer](https://getcomposer.org).
+
+``` bash
+composer require ramsey/collection
+```
+
+## Usage
+
+Examples of how to use this framework can be found in the
+[Wiki pages](https://github.com/ramsey/collection/wiki/Examples).
+
+## Contributing
+
+Contributions are welcome! Before contributing to this project, familiarize
+yourself with [CONTRIBUTING.md](CONTRIBUTING.md).
+
+To develop this project, you will need [PHP](https://www.php.net) 7.3 or greater
+and [Composer](https://getcomposer.org).
+
+After cloning this repository locally, execute the following commands:
+
+``` bash
+cd /path/to/repository
+composer install
+```
+
+Now, you are ready to develop!
+
+## Coordinated Disclosure
+
+Keeping user information safe and secure is a top priority, and we welcome the
+contribution of external security researchers. If you believe you've found a
+security issue in software that is maintained in this repository, please read
+[SECURITY.md][] for instructions on submitting a vulnerability report.
+
+## ramsey/collection for Enterprise
+
+Available as part of the Tidelift Subscription.
+
+The maintainers of ramsey/collection and thousands of other packages are working
+with Tidelift to deliver commercial support and maintenance for the open source
+packages you use to build your applications. Save time, reduce risk, and improve
+code health, while paying the maintainers of the exact packages you use.
+[Learn more.](https://tidelift.com/subscription/pkg/packagist-ramsey-collection?utm_source=undefined&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
+
+## Copyright and License
+
+The ramsey/collection library is copyright © [Ben Ramsey](https://benramsey.com)
+and licensed for use under the terms of the
+MIT License (MIT). Please see [LICENSE](LICENSE) for more information.
+
+
+[java]: http://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html
+[security.md]: https://github.com/ramsey/collection/blob/master/SECURITY.md

+ 113 - 0
api/vendor/ramsey/collection/SECURITY.md

@@ -0,0 +1,113 @@
+<!--
+    This policy was created using the HackerOne Policy Builder:
+    https://hackerone.com/policy-builder/
+ -->
+
+# Vulnerability Disclosure Policy
+
+Keeping user information safe and secure is a top priority, and we welcome the
+contribution of external security researchers.
+
+## Scope
+
+If you believe you've found a security issue in software that is maintained in
+this repository, we encourage you to notify us.
+
+| Version | In scope | Source code |
+| :-----: | :------: | :---------- |
+| latest  | ✅        | https://github.com/ramsey/collection |
+
+## How to Submit a Report
+
+To submit a vulnerability report, please contact us at <security@ramsey.dev>.
+Your submission will be reviewed and validated by a member of our team.
+
+## Safe Harbor
+
+We support safe harbor for security researchers who:
+
+* Make a good faith effort to avoid privacy violations, destruction of data, and
+  interruption or degradation of our services.
+* Only interact with accounts you own or with explicit permission of the account
+  holder. If you do encounter Personally Identifiable Information (PII) contact
+  us immediately, do not proceed with access, and immediately purge any local
+  information.
+* Provide us with a reasonable amount of time to resolve vulnerabilities prior
+  to any disclosure to the public or a third-party.
+
+We will consider activities conducted consistent with this policy to constitute
+"authorized" conduct and will not pursue civil action or initiate a complaint to
+law enforcement. We will help to the extent we can if legal action is initiated
+by a third party against you.
+
+Please submit a report to us before engaging in conduct that may be inconsistent
+with or unaddressed by this policy.
+
+## Preferences
+
+* Please provide detailed reports with reproducible steps and a clearly defined
+  impact.
+* Include the version number of the vulnerable package in your report
+* Social engineering (e.g. phishing, vishing, smishing) is prohibited.
+
+## Encryption Key for security@ramsey.dev
+
+For increased privacy when reporting sensitive issues, you may encrypt your
+messages using the following key:
+
+```
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBF+Z9gEBEACbT/pIx8RR0K18t8Z2rDnmEV44YdT7HNsMdq+D6SAlx8UUb6AU
+jGIbV9dgBgGNtOLU1pxloaJwL9bWIRbj+X/Qb2WNIP//Vz1Y40ox1dSpfCUrizXx
+kb4p58Xml0PsB8dg3b4RDUgKwGC37ne5xmDnigyJPbiB2XJ6Xc46oPCjh86XROTK
+wEBB2lY67ClBlSlvC2V9KmbTboRQkLdQDhOaUosMb99zRb0EWqDLaFkZVjY5HI7i
+0pTveE6dI12NfHhTwKjZ5pUiAZQGlKA6J1dMjY2unxHZkQj5MlMfrLSyJHZxccdJ
+xD94T6OTcTHt/XmMpI2AObpewZDdChDQmcYDZXGfAhFoJmbvXsmLMGXKgzKoZ/ls
+RmLsQhh7+/r8E+Pn5r+A6Hh4uAc14ApyEP0ckKeIXw1C6pepHM4E8TEXVr/IA6K/
+z6jlHORixIFX7iNOnfHh+qwOgZw40D6JnBfEzjFi+T2Cy+JzN2uy7I8UnecTMGo3
+5t6astPy6xcH6kZYzFTV7XERR6LIIVyLAiMFd8kF5MbJ8N5ElRFsFHPW+82N2HDX
+c60iSaTB85k6R6xd8JIKDiaKE4sSuw2wHFCKq33d/GamYezp1wO+bVUQg88efljC
+2JNFyD+vl30josqhw1HcmbE1TP3DlYeIL5jQOlxCMsgai6JtTfHFM/5MYwARAQAB
+tBNzZWN1cml0eUByYW1zZXkuZGV2iQJUBBMBCAA+FiEE4drPD+/ofZ570fAYq0bv
+vXQCywIFAl+Z9gECGwMFCQeGH4AFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ
+q0bvvXQCywIkEA//Qcwv8MtTCy01LHZd9c7VslwhNdXQDYymcTyjcYw8x7O22m4B
+3hXE6vqAplFhVxxkqXB2ef0tQuzxhPHNJgkCE4Wq4i+V6qGpaSVHQT2W6DN/NIhL
+vS8OdScc6zddmIbIkSrzVVAtjwehFNEIrX3DnbbbK+Iku7vsKT5EclOluIsjlYoX
+goW8IeReyDBqOe2H3hoCGw6EA0D/NYV2bJnfy53rXVIyarsXXeOLp7eNEH6Td7aW
+PVSrMZJe1t+knrEGnEdrXWzlg4lCJJCtemGv+pKBUomnyISXSdqyoRCCzvQjqyig
+2kRebUX8BXPW33p4OXPj9sIboUOjZwormWwqqbFMO+J4TiVCUoEoheI7emPFRcNN
+QtPJrjbY1++OznBc0GRpfeUkGoU1cbRl1bnepnFIZMTDLkrVW6I1Y4q8ZVwX3BkE
+N81ctFrRpHBlU36EdHvjPQmGtuiL77Qq3fWmMv7yTvK1wHJAXfEb0ZJWHZCbck3w
+l0CVq0Z+UUAOM8Rp1N0N8m92xtapav0qCFU9qzf2J5qX6GRmWv+d29wPgFHzDWBm
+nnrYYIA4wJLx00U6SMcVBSnNe91B+RfGY5XQhbWPjQQecOGCSDsxaFAq2MeOVJyZ
+bIjLYfG9GxoLKr5R7oLRJvZI4nKKBc1Kci/crZbdiSdQhSQGlDz88F1OHeCIdQQQ
+EQgAHRYhBOhdAxHd+lus86YQ57Atl5icjAcbBQJfmfdIAAoJELAtl5icjAcbFVcA
+/1LqB3ZjsnXDAvvAXZVjSPqofSlpMLeRQP6IM/A9Odq0AQCZrtZc1knOMGEcjppK
+Rk+sy/R0Mshy8TDuaZIRgh2Ux7kCDQRfmfYBARAAmchKzzVz7IaEq7PnZDb3szQs
+T/+E9F3m39yOpV4fEB1YzObonFakXNT7Gw2tZEx0eitUMqQ/13jjfu3UdzlKl2bR
+qA8LrSQRhB+PTC9A1XvwxCUYhhjGiLzJ9CZL6hBQB43qHOmE9XJPme90geLsF+gK
+u39Waj1SNWzwGg+Gy1Gl5f2AJoDTxznreCuFGj+Vfaczt/hlfgqpOdb9jsmdoE7t
+3DSWppA9dRHWwQSgE6J28rR4QySBcqyXS6IMykqaJn7Z26yNIaITLnHCZOSY8zhP
+ha7GFsN549EOCgECbrnPt9dmI2+hQE0RO0e7SOBNsIf5sz/i7urhwuj0CbOqhjc2
+X1AEVNFCVcb6HPi/AWefdFCRu0gaWQxn5g+9nkq5slEgvzCCiKYzaBIcr8qR6Hb4
+FaOPVPxO8vndRouq57Ws8XpAwbPttioFuCqF4u9K+tK/8e2/R8QgRYJsE3Cz/Fu8
++pZFpMnqbDEbK3DL3ss+1ed1sky+mDV8qXXeI33XW5hMFnk1JWshUjHNlQmE6ftC
+U0xSTMVUtwJhzH2zDp8lEdu7qi3EsNULOl68ozDr6soWAvCbHPeTdTOnFySGCleG
+/3TonsoZJs/sSPPJnxFQ1DtgQL6EbhIwa0ZwU4eKYVHZ9tjxuMX3teFzRvOrJjgs
++ywGlsIURtEckT5Y6nMAEQEAAYkCPAQYAQgAJhYhBOHazw/v6H2ee9HwGKtG7710
+AssCBQJfmfYBAhsMBQkHhh+AAAoJEKtG7710AssC8NcP/iDAcy1aZFvkA0EbZ85p
+i7/+ywtE/1wF4U4/9OuLcoskqGGnl1pJNPooMOSBCfreoTB8HimT0Fln0CoaOm4Q
+pScNq39JXmf4VxauqUJVARByP6zUfgYarqoaZNeuFF0S4AZJ2HhGzaQPjDz1uKVM
+PE6tQSgQkFzdZ9AtRA4vElTH6yRAgmepUsOihk0b0gUtVnwtRYZ8e0Qt3ie97a73
+DxLgAgedFRUbLRYiT0vNaYbainBsLWKpN/T8odwIg/smP0Khjp/ckV60cZTdBiPR
+szBTPJESMUTu0VPntc4gWwGsmhZJg/Tt/qP08XYo3VxNYBegyuWwNR66zDWvwvGH
+muMv5UchuDxp6Rt3JkIO4voMT1JSjWy9p8krkPEE4V6PxAagLjdZSkt92wVLiK5x
+y5gNrtPhU45YdRAKHr36OvJBJQ42CDaZ6nzrzghcIp9CZ7ANHrI+QLRM/csz+AGA
+szSp6S4mc1lnxxfbOhPPpebZPn0nIAXoZnnoVKdrxBVedPQHT59ZFvKTQ9Fs7gd3
+sYNuc7tJGFGC2CxBH4ANDpOQkc5q9JJ1HSGrXU3juxIiRgfA26Q22S9c71dXjElw
+Ri584QH+bL6kkYmm8xpKF6TVwhwu5xx/jBPrbWqFrtbvLNrnfPoapTihBfdIhkT6
+nmgawbBHA02D5xEqB5SU3WJu
+=eJNx
+-----END PGP PUBLIC KEY BLOCK-----
+```

+ 102 - 0
api/vendor/ramsey/collection/composer.json

@@ -0,0 +1,102 @@
+{
+    "name": "ramsey/collection",
+    "type": "library",
+    "description": "A PHP library for representing and manipulating collections.",
+    "keywords": [
+        "array",
+        "collection",
+        "hash",
+        "map",
+        "queue",
+        "set"
+    ],
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Ben Ramsey",
+            "email": "ben@benramsey.com",
+            "homepage": "https://benramsey.com"
+        }
+    ],
+    "require": {
+        "php": "^7.3 || ^8",
+        "symfony/polyfill-php81": "^1.23"
+    },
+    "require-dev": {
+        "captainhook/captainhook": "^5.3",
+        "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+        "ergebnis/composer-normalize": "^2.6",
+        "fakerphp/faker": "^1.5",
+        "hamcrest/hamcrest-php": "^2",
+        "jangregor/phpstan-prophecy": "^0.8",
+        "mockery/mockery": "^1.3",
+        "phpspec/prophecy-phpunit": "^2.0",
+        "phpstan/extension-installer": "^1",
+        "phpstan/phpstan": "^0.12.32",
+        "phpstan/phpstan-mockery": "^0.12.5",
+        "phpstan/phpstan-phpunit": "^0.12.11",
+        "phpunit/phpunit": "^8.5 || ^9",
+        "psy/psysh": "^0.10.4",
+        "slevomat/coding-standard": "^6.3",
+        "squizlabs/php_codesniffer": "^3.5",
+        "vimeo/psalm": "^4.4"
+    },
+    "config": {
+        "sort-packages": true
+    },
+    "autoload": {
+        "psr-4": {
+            "Ramsey\\Collection\\": "src/"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Ramsey\\Console\\": "resources/console/",
+            "Ramsey\\Collection\\Test\\": "tests/",
+            "Ramsey\\Test\\Generics\\": "tests/generics/"
+        },
+        "files": [
+            "vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest.php"
+        ]
+    },
+    "scripts": {
+        "post-autoload-dump": "captainhook install --ansi -f -s",
+        "dev:analyze": [
+            "@dev:analyze:phpstan",
+            "@dev:analyze:psalm"
+        ],
+        "dev:analyze:phpstan": "phpstan --memory-limit=1G analyse",
+        "dev:analyze:psalm": "psalm --diff --config=psalm.xml",
+        "dev:build:clean": "git clean -fX build/.",
+        "dev:build:clear-cache": "git clean -fX build/cache/.",
+        "dev:lint": "phpcs --cache=build/cache/phpcs.cache",
+        "dev:lint:fix": "./bin/lint-fix.sh",
+        "dev:repl": [
+            "echo ; echo 'Type ./bin/repl to start the REPL.'"
+        ],
+        "dev:test": "phpunit",
+        "dev:test:all": [
+            "@dev:lint",
+            "@dev:analyze",
+            "@dev:test"
+        ],
+        "dev:test:coverage:ci": "phpunit --coverage-clover build/logs/clover.xml",
+        "dev:test:coverage:html": "phpunit --coverage-html build/coverage",
+        "test": "@dev:test:all"
+    },
+    "scripts-descriptions": {
+        "dev:analyze": "Performs static analysis on the code base.",
+        "dev:analyze:phpstan": "Runs the PHPStan static analyzer.",
+        "dev:analyze:psalm": "Runs the Psalm static analyzer.",
+        "dev:build:clean": "Removes everything not under version control from the build directory.",
+        "dev:build:clear-cache": "Removes everything not under version control from build/cache/.",
+        "dev:lint": "Checks all source code for coding standards issues.",
+        "dev:lint:fix": "Checks source code for coding standards issues and fixes them, if possible.",
+        "dev:repl": "Note: Use ./bin/repl to run the REPL.",
+        "dev:test": "Runs the full unit test suite.",
+        "dev:test:all": "Runs linting, static analysis, and unit tests.",
+        "dev:test:coverage:ci": "Runs the unit test suite and generates a Clover coverage report.",
+        "dev:test:coverage:html": "Runs the unit tests suite and generates an HTML coverage report.",
+        "test": "Shortcut to run the full test suite."
+    }
+}

+ 209 - 0
api/vendor/ramsey/collection/src/AbstractArray.php

@@ -0,0 +1,209 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+use ArrayIterator;
+use Traversable;
+
+use function serialize;
+use function unserialize;
+
+/**
+ * This class provides a basic implementation of `ArrayInterface`, to minimize
+ * the effort required to implement this interface.
+ *
+ * @template T
+ * @implements ArrayInterface<T>
+ */
+abstract class AbstractArray implements ArrayInterface
+{
+    /**
+     * The items of this array.
+     *
+     * @var array<array-key, T>
+     */
+    protected $data = [];
+
+    /**
+     * Constructs a new array object.
+     *
+     * @param array<array-key, T> $data The initial items to add to this array.
+     */
+    public function __construct(array $data = [])
+    {
+        // Invoke offsetSet() for each value added; in this way, sub-classes
+        // may provide additional logic about values added to the array object.
+        foreach ($data as $key => $value) {
+            $this[$key] = $value;
+        }
+    }
+
+    /**
+     * Returns an iterator for this array.
+     *
+     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php IteratorAggregate::getIterator()
+     *
+     * @return Traversable<array-key, T>
+     */
+    public function getIterator(): Traversable
+    {
+        return new ArrayIterator($this->data);
+    }
+
+    /**
+     * Returns `true` if the given offset exists in this array.
+     *
+     * @link http://php.net/manual/en/arrayaccess.offsetexists.php ArrayAccess::offsetExists()
+     *
+     * @param array-key $offset The offset to check.
+     */
+    public function offsetExists($offset): bool
+    {
+        return isset($this->data[$offset]);
+    }
+
+    /**
+     * Returns the value at the specified offset.
+     *
+     * @link http://php.net/manual/en/arrayaccess.offsetget.php ArrayAccess::offsetGet()
+     *
+     * @param array-key $offset The offset for which a value should be returned.
+     *
+     * @return T|null the value stored at the offset, or null if the offset
+     *     does not exist.
+     *
+     * @psalm-suppress InvalidAttribute
+     */
+    #[\ReturnTypeWillChange] // phpcs:ignore
+    public function offsetGet($offset)
+    {
+        return $this->data[$offset] ?? null;
+    }
+
+    /**
+     * Sets the given value to the given offset in the array.
+     *
+     * @link http://php.net/manual/en/arrayaccess.offsetset.php ArrayAccess::offsetSet()
+     *
+     * @param array-key|null $offset The offset to set. If `null`, the value may be
+     *     set at a numerically-indexed offset.
+     * @param T $value The value to set at the given offset.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function offsetSet($offset, $value): void
+    {
+        if ($offset === null) {
+            $this->data[] = $value;
+        } else {
+            $this->data[$offset] = $value;
+        }
+    }
+
+    /**
+     * Removes the given offset and its value from the array.
+     *
+     * @link http://php.net/manual/en/arrayaccess.offsetunset.php ArrayAccess::offsetUnset()
+     *
+     * @param array-key $offset The offset to remove from the array.
+     */
+    public function offsetUnset($offset): void
+    {
+        unset($this->data[$offset]);
+    }
+
+    /**
+     * Returns a serialized string representation of this array object.
+     *
+     * @deprecated The Serializable interface will go away in PHP 9.
+     *
+     * @link http://php.net/manual/en/serializable.serialize.php Serializable::serialize()
+     *
+     * @return string a PHP serialized string.
+     */
+    public function serialize(): string
+    {
+        return serialize($this->data);
+    }
+
+    /**
+     * Returns data suitable for PHP serialization.
+     *
+     * @link https://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.serialize
+     * @link https://www.php.net/serialize
+     *
+     * @return array<array-key, T>
+     */
+    public function __serialize(): array
+    {
+        return $this->data;
+    }
+
+    /**
+     * Converts a serialized string representation into an instance object.
+     *
+     * @deprecated The Serializable interface will go away in PHP 9.
+     *
+     * @link http://php.net/manual/en/serializable.unserialize.php Serializable::unserialize()
+     *
+     * @param string $serialized A PHP serialized string to unserialize.
+     *
+     * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+     */
+    public function unserialize($serialized): void
+    {
+        /** @var array<array-key, T> $data */
+        $data = unserialize($serialized, ['allowed_classes' => false]);
+
+        $this->data = $data;
+    }
+
+    /**
+     * Adds unserialized data to the object.
+     *
+     * @param array<array-key, T> $data
+     */
+    public function __unserialize(array $data): void
+    {
+        $this->data = $data;
+    }
+
+    /**
+     * Returns the number of items in this array.
+     *
+     * @link http://php.net/manual/en/countable.count.php Countable::count()
+     */
+    public function count(): int
+    {
+        return count($this->data);
+    }
+
+    public function clear(): void
+    {
+        $this->data = [];
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function toArray(): array
+    {
+        return $this->data;
+    }
+
+    public function isEmpty(): bool
+    {
+        return count($this->data) === 0;
+    }
+}

+ 318 - 0
api/vendor/ramsey/collection/src/AbstractCollection.php

@@ -0,0 +1,318 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+use Closure;
+use Ramsey\Collection\Exception\CollectionMismatchException;
+use Ramsey\Collection\Exception\InvalidArgumentException;
+use Ramsey\Collection\Exception\InvalidSortOrderException;
+use Ramsey\Collection\Exception\OutOfBoundsException;
+use Ramsey\Collection\Tool\TypeTrait;
+use Ramsey\Collection\Tool\ValueExtractorTrait;
+use Ramsey\Collection\Tool\ValueToStringTrait;
+
+use function array_filter;
+use function array_map;
+use function array_merge;
+use function array_search;
+use function array_udiff;
+use function array_uintersect;
+use function current;
+use function end;
+use function in_array;
+use function is_int;
+use function reset;
+use function sprintf;
+use function unserialize;
+use function usort;
+
+/**
+ * This class provides a basic implementation of `CollectionInterface`, to
+ * minimize the effort required to implement this interface
+ *
+ * @template T
+ * @extends AbstractArray<T>
+ * @implements CollectionInterface<T>
+ */
+abstract class AbstractCollection extends AbstractArray implements CollectionInterface
+{
+    use TypeTrait;
+    use ValueToStringTrait;
+    use ValueExtractorTrait;
+
+    /**
+     * @inheritDoc
+     */
+    public function add($element): bool
+    {
+        $this[] = $element;
+
+        return true;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function contains($element, bool $strict = true): bool
+    {
+        return in_array($element, $this->data, $strict);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offsetSet($offset, $value): void
+    {
+        if ($this->checkType($this->getType(), $value) === false) {
+            throw new InvalidArgumentException(
+                'Value must be of type ' . $this->getType() . '; value is '
+                . $this->toolValueToString($value)
+            );
+        }
+
+        if ($offset === null) {
+            $this->data[] = $value;
+        } else {
+            $this->data[$offset] = $value;
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function remove($element): bool
+    {
+        if (($position = array_search($element, $this->data, true)) !== false) {
+            unset($this->data[$position]);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function column(string $propertyOrMethod): array
+    {
+        $temp = [];
+
+        foreach ($this->data as $item) {
+            /** @var mixed $value */
+            $value = $this->extractValue($item, $propertyOrMethod);
+
+            /** @psalm-suppress MixedAssignment */
+            $temp[] = $value;
+        }
+
+        return $temp;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function first()
+    {
+        if ($this->isEmpty()) {
+            throw new OutOfBoundsException('Can\'t determine first item. Collection is empty');
+        }
+
+        reset($this->data);
+
+        /** @var T $first */
+        $first = current($this->data);
+
+        return $first;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function last()
+    {
+        if ($this->isEmpty()) {
+            throw new OutOfBoundsException('Can\'t determine last item. Collection is empty');
+        }
+
+        /** @var T $item */
+        $item = end($this->data);
+        reset($this->data);
+
+        return $item;
+    }
+
+    public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): CollectionInterface
+    {
+        if (!in_array($order, [self::SORT_ASC, self::SORT_DESC], true)) {
+            throw new InvalidSortOrderException('Invalid sort order given: ' . $order);
+        }
+
+        $collection = clone $this;
+
+        usort(
+            $collection->data,
+            /**
+             * @param T $a
+             * @param T $b
+             */
+            function ($a, $b) use ($propertyOrMethod, $order): int {
+                /** @var mixed $aValue */
+                $aValue = $this->extractValue($a, $propertyOrMethod);
+
+                /** @var mixed $bValue */
+                $bValue = $this->extractValue($b, $propertyOrMethod);
+
+                return ($aValue <=> $bValue) * ($order === self::SORT_DESC ? -1 : 1);
+            }
+        );
+
+        return $collection;
+    }
+
+    public function filter(callable $callback): CollectionInterface
+    {
+        $collection = clone $this;
+        $collection->data = array_merge([], array_filter($collection->data, $callback));
+
+        return $collection;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function where(string $propertyOrMethod, $value): CollectionInterface
+    {
+        return $this->filter(function ($item) use ($propertyOrMethod, $value) {
+            /** @var mixed $accessorValue */
+            $accessorValue = $this->extractValue($item, $propertyOrMethod);
+
+            return $accessorValue === $value;
+        });
+    }
+
+    public function map(callable $callback): CollectionInterface
+    {
+        return new Collection('mixed', array_map($callback, $this->data));
+    }
+
+    public function diff(CollectionInterface $other): CollectionInterface
+    {
+        $this->compareCollectionTypes($other);
+
+        $diffAtoB = array_udiff($this->data, $other->toArray(), $this->getComparator());
+        $diffBtoA = array_udiff($other->toArray(), $this->data, $this->getComparator());
+
+        /** @var array<array-key, T> $diff */
+        $diff = array_merge($diffAtoB, $diffBtoA);
+
+        $collection = clone $this;
+        $collection->data = $diff;
+
+        return $collection;
+    }
+
+    public function intersect(CollectionInterface $other): CollectionInterface
+    {
+        $this->compareCollectionTypes($other);
+
+        /** @var array<array-key, T> $intersect */
+        $intersect = array_uintersect($this->data, $other->toArray(), $this->getComparator());
+
+        $collection = clone $this;
+        $collection->data = $intersect;
+
+        return $collection;
+    }
+
+    public function merge(CollectionInterface ...$collections): CollectionInterface
+    {
+        $mergedCollection = clone $this;
+
+        foreach ($collections as $index => $collection) {
+            if (!$collection instanceof static) {
+                throw new CollectionMismatchException(
+                    sprintf('Collection with index %d must be of type %s', $index, static::class)
+                );
+            }
+
+            // When using generics (Collection.php, Set.php, etc),
+            // we also need to make sure that the internal types match each other
+            if ($collection->getType() !== $this->getType()) {
+                throw new CollectionMismatchException(
+                    sprintf('Collection items in collection with index %d must be of type %s', $index, $this->getType())
+                );
+            }
+
+            foreach ($collection as $key => $value) {
+                if (is_int($key)) {
+                    $mergedCollection[] = $value;
+                } else {
+                    $mergedCollection[$key] = $value;
+                }
+            }
+        }
+
+        return $mergedCollection;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function unserialize($serialized): void
+    {
+        /** @var array<array-key, T> $data */
+        $data = unserialize($serialized, ['allowed_classes' => [$this->getType()]]);
+
+        $this->data = $data;
+    }
+
+    /**
+     * @param CollectionInterface<T> $other
+     */
+    private function compareCollectionTypes(CollectionInterface $other): void
+    {
+        if (!$other instanceof static) {
+            throw new CollectionMismatchException('Collection must be of type ' . static::class);
+        }
+
+        // When using generics (Collection.php, Set.php, etc),
+        // we also need to make sure that the internal types match each other
+        if ($other->getType() !== $this->getType()) {
+            throw new CollectionMismatchException('Collection items must be of type ' . $this->getType());
+        }
+    }
+
+    private function getComparator(): Closure
+    {
+        return /**
+             * @param T $a
+             * @param T $b
+             */
+            function ($a, $b): int {
+                // If the two values are object, we convert them to unique scalars.
+                // If the collection contains mixed values (unlikely) where some are objects
+                // and some are not, we leave them as they are.
+                // The comparator should still work and the result of $a < $b should
+                // be consistent but unpredictable since not documented.
+                if (is_object($a) && is_object($b)) {
+                    $a = spl_object_id($a);
+                    $b = spl_object_id($b);
+                }
+
+                return $a === $b ? 0 : ($a < $b ? 1 : -1);
+            };
+    }
+}

+ 50 - 0
api/vendor/ramsey/collection/src/AbstractSet.php

@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+/**
+ * This class contains the basic implementation of a collection that does not
+ * allow duplicated values (a set), to minimize the effort required to implement
+ * this specific type of collection.
+ *
+ * @template T
+ * @extends AbstractCollection<T>
+ */
+abstract class AbstractSet extends AbstractCollection
+{
+    /**
+     * @inheritDoc
+     */
+    public function add($element): bool
+    {
+        if ($this->contains($element)) {
+            return false;
+        }
+
+        return parent::add($element);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offsetSet($offset, $value): void
+    {
+        if ($this->contains($value)) {
+            return;
+        }
+
+        parent::offsetSet($offset, $value);
+    }
+}

+ 51 - 0
api/vendor/ramsey/collection/src/ArrayInterface.php

@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+use ArrayAccess;
+use Countable;
+use IteratorAggregate;
+use Serializable;
+
+/**
+ * `ArrayInterface` provides traversable array functionality to data types.
+ *
+ * @template T
+ * @extends ArrayAccess<array-key, T>
+ * @extends IteratorAggregate<array-key, T>
+ */
+interface ArrayInterface extends
+    ArrayAccess,
+    Countable,
+    IteratorAggregate,
+    Serializable
+{
+    /**
+     * Removes all items from this array.
+     */
+    public function clear(): void;
+
+    /**
+     * Returns a native PHP array representation of this array object.
+     *
+     * @return array<array-key, T>
+     */
+    public function toArray(): array;
+
+    /**
+     * Returns `true` if this array is empty.
+     */
+    public function isEmpty(): bool;
+}

+ 106 - 0
api/vendor/ramsey/collection/src/Collection.php

@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+/**
+ * A collection represents a group of objects.
+ *
+ * Each object in the collection is of a specific, defined type.
+ *
+ * This is a direct implementation of `CollectionInterface`, provided for
+ * the sake of convenience.
+ *
+ * Example usage:
+ *
+ * ``` php
+ * $collection = new \Ramsey\Collection\Collection('My\\Foo');
+ * $collection->add(new \My\Foo());
+ * $collection->add(new \My\Foo());
+ *
+ * foreach ($collection as $foo) {
+ *     // Do something with $foo
+ * }
+ * ```
+ *
+ * It is preferable to subclass `AbstractCollection` to create your own typed
+ * collections. For example:
+ *
+ * ``` php
+ * namespace My\Foo;
+ *
+ * class FooCollection extends \Ramsey\Collection\AbstractCollection
+ * {
+ *     public function getType()
+ *     {
+ *         return 'My\\Foo';
+ *     }
+ * }
+ * ```
+ *
+ * And then use it similarly to the earlier example:
+ *
+ * ``` php
+ * $fooCollection = new \My\Foo\FooCollection();
+ * $fooCollection->add(new \My\Foo());
+ * $fooCollection->add(new \My\Foo());
+ *
+ * foreach ($fooCollection as $foo) {
+ *     // Do something with $foo
+ * }
+ * ```
+ *
+ * The benefit with this approach is that you may do type-checking on the
+ * collection object:
+ *
+ * ``` php
+ * if ($collection instanceof \My\Foo\FooCollection) {
+ *     // the collection is a collection of My\Foo objects
+ * }
+ * ```
+ *
+ * @template T
+ * @extends AbstractCollection<T>
+ */
+class Collection extends AbstractCollection
+{
+    /**
+     * The type of elements stored in this collection.
+     *
+     * A collection's type is immutable once it is set. For this reason, this
+     * property is set private.
+     *
+     * @var string
+     */
+    private $collectionType;
+
+    /**
+     * Constructs a collection object of the specified type, optionally with the
+     * specified data.
+     *
+     * @param string $collectionType The type (FQCN) associated with this
+     *     collection.
+     * @param array<array-key, T> $data The initial items to store in the collection.
+     */
+    public function __construct(string $collectionType, array $data = [])
+    {
+        $this->collectionType = $collectionType;
+        parent::__construct($data);
+    }
+
+    public function getType(): string
+    {
+        return $this->collectionType;
+    }
+}

+ 205 - 0
api/vendor/ramsey/collection/src/CollectionInterface.php

@@ -0,0 +1,205 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+/**
+ * A collection represents a group of objects, known as its elements.
+ *
+ * Some collections allow duplicate elements and others do not. Some are ordered
+ * and others unordered.
+ *
+ * @template T
+ * @extends ArrayInterface<T>
+ */
+interface CollectionInterface extends ArrayInterface
+{
+    /**
+     * Ascending sort type.
+     */
+    public const SORT_ASC = 'asc';
+
+    /**
+     * Descending sort type.
+     */
+    public const SORT_DESC = 'desc';
+
+    /**
+     * Ensures that this collection contains the specified element (optional
+     * operation).
+     *
+     * Returns `true` if this collection changed as a result of the call.
+     * (Returns `false` if this collection does not permit duplicates and
+     * already contains the specified element.)
+     *
+     * Collections that support this operation may place limitations on what
+     * elements may be added to this collection. In particular, some
+     * collections will refuse to add `null` elements, and others will impose
+     * restrictions on the type of elements that may be added. Collection
+     * classes should clearly specify in their documentation any restrictions
+     * on what elements may be added.
+     *
+     * If a collection refuses to add a particular element for any reason other
+     * than that it already contains the element, it must throw an exception
+     * (rather than returning `false`). This preserves the invariant that a
+     * collection always contains the specified element after this call returns.
+     *
+     * @param T $element The element to add to the collection.
+     *
+     * @return bool `true` if this collection changed as a result of the call.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function add($element): bool;
+
+    /**
+     * Returns `true` if this collection contains the specified element.
+     *
+     * @param T $element The element to check whether the collection contains.
+     * @param bool $strict Whether to perform a strict type check on the value.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function contains($element, bool $strict = true): bool;
+
+    /**
+     * Returns the type associated with this collection.
+     */
+    public function getType(): string;
+
+    /**
+     * Removes a single instance of the specified element from this collection,
+     * if it is present.
+     *
+     * @param T $element The element to remove from the collection.
+     *
+     * @return bool `true` if an element was removed as a result of this call.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function remove($element): bool;
+
+    /**
+     * Returns the values from the given property or method.
+     *
+     * @param string $propertyOrMethod The property or method name to filter by.
+     *
+     * @return list<mixed>
+     */
+    public function column(string $propertyOrMethod): array;
+
+    /**
+     * Returns the first item of the collection.
+     *
+     * @return T
+     */
+    public function first();
+
+    /**
+     * Returns the last item of the collection.
+     *
+     * @return T
+     */
+    public function last();
+
+    /**
+     * Sort the collection by a property or method with the given sort order.
+     *
+     * This will always leave the original collection untouched and will return
+     * a new one.
+     *
+     * @param string $propertyOrMethod The property or method to sort by.
+     * @param string $order The sort order for the resulting collection (one of
+     *     this interface's `SORT_*` constants).
+     *
+     * @return CollectionInterface<T>
+     */
+    public function sort(string $propertyOrMethod, string $order = self::SORT_ASC): self;
+
+    /**
+     * Filter out items of the collection which don't match the criteria of
+     * given callback.
+     *
+     * This will always leave the original collection untouched and will return
+     * a new one.
+     *
+     * See the {@link http://php.net/manual/en/function.array-filter.php PHP array_filter() documentation}
+     * for examples of how the `$callback` parameter works.
+     *
+     * @param callable(T):bool $callback A callable to use for filtering elements.
+     *
+     * @return CollectionInterface<T>
+     */
+    public function filter(callable $callback): self;
+
+    /**
+     * Create a new collection where items match the criteria of given callback.
+     *
+     * This will always leave the original collection untouched and will return
+     * a new one.
+     *
+     * @param string $propertyOrMethod The property or method to evaluate.
+     * @param mixed $value The value to match.
+     *
+     * @return CollectionInterface<T>
+     */
+    public function where(string $propertyOrMethod, $value): self;
+
+    /**
+     * Apply a given callback method on each item of the collection.
+     *
+     * This will always leave the original collection untouched. The new
+     * collection is created by mapping the callback to each item of the
+     * original collection.
+     *
+     * See the {@link http://php.net/manual/en/function.array-map.php PHP array_map() documentation}
+     * for examples of how the `$callback` parameter works.
+     *
+     * @param callable(T):TCallbackReturn $callback A callable to apply to each
+     *     item of the collection.
+     *
+     * @return CollectionInterface<TCallbackReturn>
+     *
+     * @template TCallbackReturn
+     */
+    public function map(callable $callback): self;
+
+    /**
+     * Create a new collection with divergent items between current and given
+     * collection.
+     *
+     * @param CollectionInterface<T> $other The collection to check for divergent
+     *     items.
+     *
+     * @return CollectionInterface<T>
+     */
+    public function diff(CollectionInterface $other): self;
+
+    /**
+     * Create a new collection with intersecting item between current and given
+     * collection.
+     *
+     * @param CollectionInterface<T> $other The collection to check for
+     *     intersecting items.
+     *
+     * @return CollectionInterface<T>
+     */
+    public function intersect(CollectionInterface $other): self;
+
+    /**
+     * Merge current items and items of given collections into a new one.
+     *
+     * @param CollectionInterface<T> ...$collections The collections to merge.
+     *
+     * @return CollectionInterface<T>
+     */
+    public function merge(CollectionInterface ...$collections): self;
+}

+ 187 - 0
api/vendor/ramsey/collection/src/DoubleEndedQueue.php

@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+use Ramsey\Collection\Exception\InvalidArgumentException;
+use Ramsey\Collection\Exception\NoSuchElementException;
+
+/**
+ * This class provides a basic implementation of `DoubleEndedQueueInterface`, to
+ * minimize the effort required to implement this interface.
+ *
+ * @template T
+ * @extends Queue<T>
+ * @implements DoubleEndedQueueInterface<T>
+ */
+class DoubleEndedQueue extends Queue implements DoubleEndedQueueInterface
+{
+    /**
+     * Index of the last element in the queue.
+     *
+     * @var int
+     */
+    private $tail = -1;
+
+    /**
+     * @inheritDoc
+     */
+    public function offsetSet($offset, $value): void
+    {
+        if ($this->checkType($this->getType(), $value) === false) {
+            throw new InvalidArgumentException(
+                'Value must be of type ' . $this->getType() . '; value is '
+                . $this->toolValueToString($value)
+            );
+        }
+
+        $this->tail++;
+
+        $this->data[$this->tail] = $value;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function addFirst($element): bool
+    {
+        if ($this->checkType($this->getType(), $element) === false) {
+            throw new InvalidArgumentException(
+                'Value must be of type ' . $this->getType() . '; value is '
+                . $this->toolValueToString($element)
+            );
+        }
+
+        $this->index--;
+
+        $this->data[$this->index] = $element;
+
+        return true;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function addLast($element): bool
+    {
+        return $this->add($element);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offerFirst($element): bool
+    {
+        try {
+            return $this->addFirst($element);
+        } catch (InvalidArgumentException $e) {
+            return false;
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offerLast($element): bool
+    {
+        return $this->offer($element);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function removeFirst()
+    {
+        return $this->remove();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function removeLast()
+    {
+        $tail = $this->pollLast();
+
+        if ($tail === null) {
+            throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
+        }
+
+        return $tail;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function pollFirst()
+    {
+        return $this->poll();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function pollLast()
+    {
+        if ($this->count() === 0) {
+            return null;
+        }
+
+        $tail = $this[$this->tail];
+
+        unset($this[$this->tail]);
+        $this->tail--;
+
+        return $tail;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function firstElement()
+    {
+        return $this->element();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function lastElement()
+    {
+        if ($this->count() === 0) {
+            throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
+        }
+
+        return $this->data[$this->tail];
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function peekFirst()
+    {
+        return $this->peek();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function peekLast()
+    {
+        if ($this->count() === 0) {
+            return null;
+        }
+
+        return $this->data[$this->tail];
+    }
+}

+ 316 - 0
api/vendor/ramsey/collection/src/DoubleEndedQueueInterface.php

@@ -0,0 +1,316 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+use Ramsey\Collection\Exception\NoSuchElementException;
+
+/**
+ * A linear collection that supports element insertion and removal at both ends.
+ *
+ * Most `DoubleEndedQueueInterface` implementations place no fixed limits on the
+ * number of elements they may contain, but this interface supports
+ * capacity-restricted double-ended queues as well as those with no fixed size
+ * limit.
+ *
+ * This interface defines methods to access the elements at both ends of the
+ * double-ended queue. Methods are provided to insert, remove, and examine the
+ * element. Each of these methods exists in two forms: one throws an exception
+ * if the operation fails, the other returns a special value (either `null` or
+ * `false`, depending on the operation). The latter form of the insert operation
+ * is designed specifically for use with capacity-restricted implementations; in
+ * most implementations, insert operations cannot fail.
+ *
+ * The twelve methods described above are summarized in the following table:
+ *
+ * <table>
+ * <caption>Summary of DoubleEndedQueueInterface methods</caption>
+ * <thead>
+ * <tr>
+ * <th></th>
+ * <th colspan=2>First Element (Head)</th>
+ * <th colspan=2>Last Element (Tail)</th>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td><em>Throws exception</em></td>
+ * <td><em>Special value</em></td>
+ * <td><em>Throws exception</em></td>
+ * <td><em>Special value</em></td>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <th>Insert</th>
+ * <td><code>addFirst()</code></td>
+ * <td><code>offerFirst()</code></td>
+ * <td><code>addLast()</code></td>
+ * <td><code>offerLast()</code></td>
+ * </tr>
+ * <tr>
+ * <th>Remove</th>
+ * <td><code>removeFirst()</code></td>
+ * <td><code>pollFirst()</code></td>
+ * <td><code>removeLast()</code></td>
+ * <td><code>pollLast()</code></td>
+ * </tr>
+ * <tr>
+ * <th>Examine</th>
+ * <td><code>firstElement()</code></td>
+ * <td><code>peekFirst()</code></td>
+ * <td><code>lastElement()</code></td>
+ * <td><code>peekLast()</code></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * This interface extends the `QueueInterface`. When a double-ended queue is
+ * used as a queue, FIFO (first-in-first-out) behavior results. Elements are
+ * added at the end of the double-ended queue and removed from the beginning.
+ * The methods inherited from the `QueueInterface` are precisely equivalent to
+ * `DoubleEndedQueueInterface` methods as indicated in the following table:
+ *
+ * <table>
+ * <caption>Comparison of QueueInterface and DoubleEndedQueueInterface methods</caption>
+ * <thead>
+ * <tr>
+ * <th>QueueInterface Method</th>
+ * <th>DoubleEndedQueueInterface Method</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td><code>add()</code></td>
+ * <td><code>addLast()</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>offer()</code></td>
+ * <td><code>offerLast()</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>remove()</code></td>
+ * <td><code>removeFirst()</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>poll()</code></td>
+ * <td><code>pollFirst()</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>element()</code></td>
+ * <td><code>firstElement()</code></td>
+ * </tr>
+ * <tr>
+ * <td><code>peek()</code></td>
+ * <td><code>peekFirst()</code></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * Double-ended queues can also be used as LIFO (last-in-first-out) stacks. When
+ * a double-ended queue is used as a stack, elements are pushed and popped from
+ * the beginning of the double-ended queue. Stack concepts are precisely
+ * equivalent to `DoubleEndedQueueInterface` methods as indicated in the table
+ * below:
+ *
+ * <table>
+ * <caption>Comparison of stack concepts and DoubleEndedQueueInterface methods</caption>
+ * <thead>
+ * <tr>
+ * <th>Stack concept</th>
+ * <th>DoubleEndedQueueInterface Method</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td><em>push</em></td>
+ * <td><code>addFirst()</code></td>
+ * </tr>
+ * <tr>
+ * <td><em>pop</em></td>
+ * <td><code>removeFirst()</code></td>
+ * </tr>
+ * <tr>
+ * <td><em>peek</em></td>
+ * <td><code>peekFirst()</code></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * Note that the `peek()` method works equally well when a double-ended queue is
+ * used as a queue or a stack; in either case, elements are drawn from the
+ * beginning of the double-ended queue.
+ *
+ * While `DoubleEndedQueueInterface` implementations are not strictly required
+ * to prohibit the insertion of `null` elements, they are strongly encouraged to
+ * do so. Users of any `DoubleEndedQueueInterface` implementations that do allow
+ * `null` elements are strongly encouraged *not* to take advantage of the
+ * ability to insert nulls. This is so because `null` is used as a special
+ * return value by various methods to indicated that the double-ended queue is
+ * empty.
+ *
+ * @template T
+ * @extends QueueInterface<T>
+ */
+interface DoubleEndedQueueInterface extends QueueInterface
+{
+    /**
+     * Inserts the specified element at the front of this queue if it is
+     * possible to do so immediately without violating capacity restrictions.
+     *
+     * When using a capacity-restricted double-ended queue, it is generally
+     * preferable to use the `offerFirst()` method.
+     *
+     * @param T $element The element to add to the front of this queue.
+     *
+     * @return bool `true` if this queue changed as a result of the call.
+     *
+     * @throws \RuntimeException if a queue refuses to add a particular element
+     *     for any reason other than that it already contains the element.
+     *     Implementations should use a more-specific exception that extends
+     *     `\RuntimeException`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function addFirst($element): bool;
+
+    /**
+     * Inserts the specified element at the end of this queue if it is possible
+     * to do so immediately without violating capacity restrictions.
+     *
+     * When using a capacity-restricted double-ended queue, it is generally
+     * preferable to use the `offerLast()` method.
+     *
+     * This method is equivalent to `add()`.
+     *
+     * @param T $element The element to add to the end of this queue.
+     *
+     * @return bool `true` if this queue changed as a result of the call.
+     *
+     * @throws \RuntimeException if a queue refuses to add a particular element
+     *     for any reason other than that it already contains the element.
+     *     Implementations should use a more-specific exception that extends
+     *     `\RuntimeException`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function addLast($element): bool;
+
+    /**
+     * Inserts the specified element at the front of this queue if it is
+     * possible to do so immediately without violating capacity restrictions.
+     *
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to `addFirst()`, which can fail to insert an element only by
+     * throwing an exception.
+     *
+     * @param T $element The element to add to the front of this queue.
+     *
+     * @return bool `true` if the element was added to this queue, else `false`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function offerFirst($element): bool;
+
+    /**
+     * Inserts the specified element at the end of this queue if it is possible
+     * to do so immediately without violating capacity restrictions.
+     *
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to `addLast()` which can fail to insert an element only by
+     * throwing an exception.
+     *
+     * @param T $element The element to add to the end of this queue.
+     *
+     * @return bool `true` if the element was added to this queue, else `false`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function offerLast($element): bool;
+
+    /**
+     * Retrieves and removes the head of this queue.
+     *
+     * This method differs from `pollFirst()` only in that it throws an
+     * exception if this queue is empty.
+     *
+     * @return T the first element in this queue.
+     *
+     * @throws NoSuchElementException if this queue is empty.
+     */
+    public function removeFirst();
+
+    /**
+     * Retrieves and removes the tail of this queue.
+     *
+     * This method differs from `pollLast()` only in that it throws an exception
+     * if this queue is empty.
+     *
+     * @return T the last element in this queue.
+     *
+     * @throws NoSuchElementException if this queue is empty.
+     */
+    public function removeLast();
+
+    /**
+     * Retrieves and removes the head of this queue, or returns `null` if this
+     * queue is empty.
+     *
+     * @return T|null the head of this queue, or `null` if this queue is empty.
+     */
+    public function pollFirst();
+
+    /**
+     * Retrieves and removes the tail of this queue, or returns `null` if this
+     * queue is empty.
+     *
+     * @return T|null the tail of this queue, or `null` if this queue is empty.
+     */
+    public function pollLast();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.
+     *
+     * This method differs from `peekFirst()` only in that it throws an
+     * exception if this queue is empty.
+     *
+     * @return T the head of this queue.
+     *
+     * @throws NoSuchElementException if this queue is empty.
+     */
+    public function firstElement();
+
+    /**
+     * Retrieves, but does not remove, the tail of this queue.
+     *
+     * This method differs from `peekLast()` only in that it throws an exception
+     * if this queue is empty.
+     *
+     * @return T the tail of this queue.
+     *
+     * @throws NoSuchElementException if this queue is empty.
+     */
+    public function lastElement();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue, or returns `null`
+     * if this queue is empty.
+     *
+     * @return T|null the head of this queue, or `null` if this queue is empty.
+     */
+    public function peekFirst();
+
+    /**
+     * Retrieves, but does not remove, the tail of this queue, or returns `null`
+     * if this queue is empty.
+     *
+     * @return T|null the tail of this queue, or `null` if this queue is empty.
+     */
+    public function peekLast();
+}

+ 22 - 0
api/vendor/ramsey/collection/src/Exception/CollectionMismatchException.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Exception;
+
+/**
+ * Thrown when attempting to operate on collections of differing types.
+ */
+class CollectionMismatchException extends \RuntimeException
+{
+}

+ 22 - 0
api/vendor/ramsey/collection/src/Exception/InvalidArgumentException.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Exception;
+
+/**
+ * Thrown to indicate an argument is not of the expected type.
+ */
+class InvalidArgumentException extends \InvalidArgumentException
+{
+}

+ 22 - 0
api/vendor/ramsey/collection/src/Exception/InvalidSortOrderException.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Exception;
+
+/**
+ * Thrown when attempting to use a sort order that is not recognized.
+ */
+class InvalidSortOrderException extends \RuntimeException
+{
+}

+ 22 - 0
api/vendor/ramsey/collection/src/Exception/NoSuchElementException.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Exception;
+
+/**
+ * Thrown when attempting to access an element that does not exist.
+ */
+class NoSuchElementException extends \RuntimeException
+{
+}

+ 22 - 0
api/vendor/ramsey/collection/src/Exception/OutOfBoundsException.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Exception;
+
+/**
+ * Thrown when attempting to access an element out of the range of the collection.
+ */
+class OutOfBoundsException extends \OutOfBoundsException
+{
+}

+ 22 - 0
api/vendor/ramsey/collection/src/Exception/UnsupportedOperationException.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Exception;
+
+/**
+ * Thrown to indicate that the requested operation is not supported.
+ */
+class UnsupportedOperationException extends \RuntimeException
+{
+}

+ 22 - 0
api/vendor/ramsey/collection/src/Exception/ValueExtractionException.php

@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Exception;
+
+/**
+ * Thrown when attempting to extract a value for a method or property that does not exist.
+ */
+class ValueExtractionException extends \RuntimeException
+{
+}

+ 24 - 0
api/vendor/ramsey/collection/src/GenericArray.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+/**
+ * `GenericArray` represents a standard array object.
+ *
+ * @extends AbstractArray<mixed>
+ */
+class GenericArray extends AbstractArray
+{
+}

+ 162 - 0
api/vendor/ramsey/collection/src/Map/AbstractMap.php

@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Map;
+
+use Ramsey\Collection\AbstractArray;
+use Ramsey\Collection\Exception\InvalidArgumentException;
+
+use function array_key_exists;
+use function array_keys;
+use function in_array;
+
+/**
+ * This class provides a basic implementation of `MapInterface`, to minimize the
+ * effort required to implement this interface.
+ *
+ * @template T
+ * @extends AbstractArray<T>
+ * @implements MapInterface<T>
+ */
+abstract class AbstractMap extends AbstractArray implements MapInterface
+{
+    /**
+     * @inheritDoc
+     */
+    public function offsetSet($offset, $value): void
+    {
+        if ($offset === null) {
+            throw new InvalidArgumentException(
+                'Map elements are key/value pairs; a key must be provided for '
+                . 'value ' . var_export($value, true)
+            );
+        }
+
+        $this->data[$offset] = $value;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function containsKey($key): bool
+    {
+        return array_key_exists($key, $this->data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function containsValue($value): bool
+    {
+        return in_array($value, $this->data, true);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function keys(): array
+    {
+        return array_keys($this->data);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function get($key, $defaultValue = null)
+    {
+        if (!$this->containsKey($key)) {
+            return $defaultValue;
+        }
+
+        return $this[$key];
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function put($key, $value)
+    {
+        $previousValue = $this->get($key);
+        $this[$key] = $value;
+
+        return $previousValue;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function putIfAbsent($key, $value)
+    {
+        $currentValue = $this->get($key);
+
+        if ($currentValue === null) {
+            $this[$key] = $value;
+        }
+
+        return $currentValue;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function remove($key)
+    {
+        $previousValue = $this->get($key);
+        unset($this[$key]);
+
+        return $previousValue;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function removeIf($key, $value): bool
+    {
+        if ($this->get($key) === $value) {
+            unset($this[$key]);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function replace($key, $value)
+    {
+        $currentValue = $this->get($key);
+
+        if ($this->containsKey($key)) {
+            $this[$key] = $value;
+        }
+
+        return $currentValue;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function replaceIf($key, $oldValue, $newValue): bool
+    {
+        if ($this->get($key) === $oldValue) {
+            $this[$key] = $newValue;
+
+            return true;
+        }
+
+        return false;
+    }
+}

+ 69 - 0
api/vendor/ramsey/collection/src/Map/AbstractTypedMap.php

@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Map;
+
+use Ramsey\Collection\Exception\InvalidArgumentException;
+use Ramsey\Collection\Tool\TypeTrait;
+use Ramsey\Collection\Tool\ValueToStringTrait;
+
+/**
+ * This class provides a basic implementation of `TypedMapInterface`, to
+ * minimize the effort required to implement this interface.
+ *
+ * @template K
+ * @template T
+ * @extends AbstractMap<T>
+ * @implements TypedMapInterface<T>
+ */
+abstract class AbstractTypedMap extends AbstractMap implements TypedMapInterface
+{
+    use TypeTrait;
+    use ValueToStringTrait;
+
+    /**
+     * @param K|null $offset
+     * @param T $value
+     *
+     * @inheritDoc
+     *
+     * @psalm-suppress MoreSpecificImplementedParamType
+     */
+    public function offsetSet($offset, $value): void
+    {
+        if ($offset === null) {
+            throw new InvalidArgumentException(
+                'Map elements are key/value pairs; a key must be provided for '
+                . 'value ' . var_export($value, true)
+            );
+        }
+
+        if ($this->checkType($this->getKeyType(), $offset) === false) {
+            throw new InvalidArgumentException(
+                'Key must be of type ' . $this->getKeyType() . '; key is '
+                . $this->toolValueToString($offset)
+            );
+        }
+
+        if ($this->checkType($this->getValueType(), $value) === false) {
+            throw new InvalidArgumentException(
+                'Value must be of type ' . $this->getValueType() . '; value is '
+                . $this->toolValueToString($value)
+            );
+        }
+
+        /** @psalm-suppress MixedArgumentTypeCoercion */
+        parent::offsetSet($offset, $value);
+    }
+}

+ 25 - 0
api/vendor/ramsey/collection/src/Map/AssociativeArrayMap.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Map;
+
+/**
+ * `AssociativeArrayMap` represents a standard associative array object.
+ *
+ * @template T
+ * @extends AbstractMap<T>
+ */
+class AssociativeArrayMap extends AbstractMap
+{
+}

+ 149 - 0
api/vendor/ramsey/collection/src/Map/MapInterface.php

@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Map;
+
+use Ramsey\Collection\ArrayInterface;
+
+/**
+ * An object that maps keys to values.
+ *
+ * A map cannot contain duplicate keys; each key can map to at most one value.
+ *
+ * @template T
+ * @extends ArrayInterface<T>
+ */
+interface MapInterface extends ArrayInterface
+{
+    /**
+     * Returns `true` if this map contains a mapping for the specified key.
+     *
+     * @param array-key $key The key to check in the map.
+     */
+    public function containsKey($key): bool;
+
+    /**
+     * Returns `true` if this map maps one or more keys to the specified value.
+     *
+     * This performs a strict type check on the value.
+     *
+     * @param T $value The value to check in the map.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function containsValue($value): bool;
+
+    /**
+     * Return an array of the keys contained in this map.
+     *
+     * @return list<array-key>
+     */
+    public function keys(): array;
+
+    /**
+     * Returns the value to which the specified key is mapped, `null` if this
+     * map contains no mapping for the key, or (optionally) `$defaultValue` if
+     * this map contains no mapping for the key.
+     *
+     * @param array-key $key The key to return from the map.
+     * @param T|null $defaultValue The default value to use if `$key` is not found.
+     *
+     * @return T|null the value or `null` if the key could not be found.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function get($key, $defaultValue = null);
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     *
+     * If the map previously contained a mapping for the key, the old value is
+     * replaced by the specified value.
+     *
+     * @param array-key $key The key to put or replace in the map.
+     * @param T $value The value to store at `$key`.
+     *
+     * @return T|null the previous value associated with key, or `null` if
+     *     there was no mapping for `$key`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function put($key, $value);
+
+    /**
+     * Associates the specified value with the specified key in this map only if
+     * it is not already set.
+     *
+     * If there is already a value associated with `$key`, this returns that
+     * value without replacing it.
+     *
+     * @param array-key $key The key to put in the map.
+     * @param T $value The value to store at `$key`.
+     *
+     * @return T|null the previous value associated with key, or `null` if
+     *     there was no mapping for `$key`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function putIfAbsent($key, $value);
+
+    /**
+     * Removes the mapping for a key from this map if it is present.
+     *
+     * @param array-key $key The key to remove from the map.
+     *
+     * @return T|null the previous value associated with key, or `null` if
+     *     there was no mapping for `$key`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function remove($key);
+
+    /**
+     * Removes the entry for the specified key only if it is currently mapped to
+     * the specified value.
+     *
+     * This performs a strict type check on the value.
+     *
+     * @param array-key $key The key to remove from the map.
+     * @param T $value The value to match.
+     *
+     * @return bool true if the value was removed.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function removeIf($key, $value): bool;
+
+    /**
+     * Replaces the entry for the specified key only if it is currently mapped
+     * to some value.
+     *
+     * @param array-key $key The key to replace.
+     * @param T $value The value to set at `$key`.
+     *
+     * @return T|null the previous value associated with key, or `null` if
+     *     there was no mapping for `$key`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function replace($key, $value);
+
+    /**
+     * Replaces the entry for the specified key only if currently mapped to the
+     * specified value.
+     *
+     * This performs a strict type check on the value.
+     *
+     * @param array-key $key The key to remove from the map.
+     * @param T $oldValue The value to match.
+     * @param T $newValue The value to use as a replacement.
+     *
+     * @return bool true if the value was replaced.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function replaceIf($key, $oldValue, $newValue): bool;
+}

+ 120 - 0
api/vendor/ramsey/collection/src/Map/NamedParameterMap.php

@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Map;
+
+use Ramsey\Collection\Exception\InvalidArgumentException;
+use Ramsey\Collection\Tool\TypeTrait;
+use Ramsey\Collection\Tool\ValueToStringTrait;
+
+use function array_combine;
+use function array_key_exists;
+use function is_int;
+
+/**
+ * `NamedParameterMap` represents a mapping of values to a set of named keys
+ * that may optionally be typed
+ *
+ * @extends AbstractMap<mixed>
+ */
+class NamedParameterMap extends AbstractMap
+{
+    use TypeTrait;
+    use ValueToStringTrait;
+
+    /**
+     * Named parameters defined for this map.
+     *
+     * @var array<string, string>
+     */
+    protected $namedParameters;
+
+    /**
+     * Constructs a new `NamedParameterMap`.
+     *
+     * @param array<array-key, string> $namedParameters The named parameters defined for this map.
+     * @param array<array-key, mixed> $data An initial set of data to set on this map.
+     */
+    public function __construct(array $namedParameters, array $data = [])
+    {
+        $this->namedParameters = $this->filterNamedParameters($namedParameters);
+        parent::__construct($data);
+    }
+
+    /**
+     * Returns named parameters set for this `NamedParameterMap`.
+     *
+     * @return array<string, string>
+     */
+    public function getNamedParameters(): array
+    {
+        return $this->namedParameters;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offsetSet($offset, $value): void
+    {
+        if ($offset === null) {
+            throw new InvalidArgumentException(
+                'Map elements are key/value pairs; a key must be provided for '
+                . 'value ' . var_export($value, true)
+            );
+        }
+
+        if (!array_key_exists($offset, $this->namedParameters)) {
+            throw new InvalidArgumentException(
+                'Attempting to set value for unconfigured parameter \''
+                . $offset . '\''
+            );
+        }
+
+        if ($this->checkType($this->namedParameters[$offset], $value) === false) {
+            throw new InvalidArgumentException(
+                'Value for \'' . $offset . '\' must be of type '
+                . $this->namedParameters[$offset] . '; value is '
+                . $this->toolValueToString($value)
+            );
+        }
+
+        $this->data[$offset] = $value;
+    }
+
+    /**
+     * Given an array of named parameters, constructs a proper mapping of
+     * named parameters to types.
+     *
+     * @param array<array-key, string> $namedParameters The named parameters to filter.
+     *
+     * @return array<string, string>
+     */
+    protected function filterNamedParameters(array $namedParameters): array
+    {
+        $names = [];
+        $types = [];
+
+        foreach ($namedParameters as $key => $value) {
+            if (is_int($key)) {
+                $names[] = $value;
+                $types[] = 'mixed';
+            } else {
+                $names[] = $key;
+                $types[] = $value;
+            }
+        }
+
+        return array_combine($names, $types) ?: [];
+    }
+}

+ 137 - 0
api/vendor/ramsey/collection/src/Map/TypedMap.php

@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Map;
+
+use Ramsey\Collection\Tool\TypeTrait;
+
+/**
+ * A `TypedMap` represents a map of elements where key and value are typed.
+ *
+ * Each element is identified by a key with defined type and a value of defined
+ * type. The keys of the map must be unique. The values on the map can be=
+ * repeated but each with its own different key.
+ *
+ * The most common case is to use a string type key, but it's not limited to
+ * this type of keys.
+ *
+ * This is a direct implementation of `TypedMapInterface`, provided for the sake
+ * of convenience.
+ *
+ * Example usage:
+ *
+ * ```php
+ * $map = new TypedMap('string', Foo::class);
+ * $map['x'] = new Foo();
+ * foreach ($map as $key => $value) {
+ *     // do something with $key, it will be a Foo::class
+ * }
+ *
+ * // this will throw an exception since key must be string
+ * $map[10] = new Foo();
+ *
+ * // this will throw an exception since value must be a Foo
+ * $map['bar'] = 'bar';
+ *
+ * // initialize map with contents
+ * $map = new TypedMap('string', Foo::class, [
+ *     new Foo(), new Foo(), new Foo()
+ * ]);
+ * ```
+ *
+ * It is preferable to subclass `AbstractTypedMap` to create your own typed map
+ * implementation:
+ *
+ * ```php
+ * class FooTypedMap extends AbstractTypedMap
+ * {
+ *     public function getKeyType()
+ *     {
+ *         return 'int';
+ *     }
+ *
+ *     public function getValueType()
+ *     {
+ *          return Foo::class;
+ *     }
+ * }
+ * ```
+ *
+ * … but you also may use the `TypedMap` class:
+ *
+ * ```php
+ * class FooTypedMap extends TypedMap
+ * {
+ *     public function __constructor(array $data = [])
+ *     {
+ *         parent::__construct('int', Foo::class, $data);
+ *     }
+ * }
+ * ```
+ *
+ * @template K
+ * @template T
+ * @extends AbstractTypedMap<K, T>
+ */
+class TypedMap extends AbstractTypedMap
+{
+    use TypeTrait;
+
+    /**
+     * The data type of keys stored in this collection.
+     *
+     * A map key's type is immutable once it is set. For this reason, this
+     * property is set private.
+     *
+     * @var string data type of the map key.
+     */
+    private $keyType;
+
+    /**
+     * The data type of values stored in this collection.
+     *
+     * A map value's type is immutable once it is set. For this reason, this
+     * property is set private.
+     *
+     * @var string data type of the map value.
+     */
+    private $valueType;
+
+    /**
+     * Constructs a map object of the specified key and value types,
+     * optionally with the specified data.
+     *
+     * @param string $keyType The data type of the map's keys.
+     * @param string $valueType The data type of the map's values.
+     * @param array<K, T> $data The initial data to set for this map.
+     */
+    public function __construct(string $keyType, string $valueType, array $data = [])
+    {
+        $this->keyType = $keyType;
+        $this->valueType = $valueType;
+
+        /** @psalm-suppress MixedArgumentTypeCoercion */
+        parent::__construct($data);
+    }
+
+    public function getKeyType(): string
+    {
+        return $this->keyType;
+    }
+
+    public function getValueType(): string
+    {
+        return $this->valueType;
+    }
+}

+ 35 - 0
api/vendor/ramsey/collection/src/Map/TypedMapInterface.php

@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Map;
+
+/**
+ * A `TypedMapInterface` represents a map of elements where key and value are
+ * typed.
+ *
+ * @template T
+ * @extends MapInterface<T>
+ */
+interface TypedMapInterface extends MapInterface
+{
+    /**
+     * Return the type used on the key.
+     */
+    public function getKeyType(): string;
+
+    /**
+     * Return the type forced on the values.
+     */
+    public function getValueType(): string;
+}

+ 169 - 0
api/vendor/ramsey/collection/src/Queue.php

@@ -0,0 +1,169 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+use Ramsey\Collection\Exception\InvalidArgumentException;
+use Ramsey\Collection\Exception\NoSuchElementException;
+use Ramsey\Collection\Tool\TypeTrait;
+use Ramsey\Collection\Tool\ValueToStringTrait;
+
+/**
+ * This class provides a basic implementation of `QueueInterface`, to minimize
+ * the effort required to implement this interface.
+ *
+ * @template T
+ * @extends AbstractArray<T>
+ * @implements QueueInterface<T>
+ */
+class Queue extends AbstractArray implements QueueInterface
+{
+    use TypeTrait;
+    use ValueToStringTrait;
+
+    /**
+     * The type of elements stored in this queue.
+     *
+     * A queue's type is immutable once it is set. For this reason, this
+     * property is set private.
+     *
+     * @var string
+     */
+    private $queueType;
+
+    /**
+     * The index of the head of the queue.
+     *
+     * @var int
+     */
+    protected $index = 0;
+
+    /**
+     * Constructs a queue object of the specified type, optionally with the
+     * specified data.
+     *
+     * @param string $queueType The type (FQCN) associated with this queue.
+     * @param array<array-key, T> $data The initial items to store in the collection.
+     */
+    public function __construct(string $queueType, array $data = [])
+    {
+        $this->queueType = $queueType;
+        parent::__construct($data);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Since arbitrary offsets may not be manipulated in a queue, this method
+     * serves only to fulfill the `ArrayAccess` interface requirements. It is
+     * invoked by other operations when adding values to the queue.
+     */
+    public function offsetSet($offset, $value): void
+    {
+        if ($this->checkType($this->getType(), $value) === false) {
+            throw new InvalidArgumentException(
+                'Value must be of type ' . $this->getType() . '; value is '
+                . $this->toolValueToString($value)
+            );
+        }
+
+        $this->data[] = $value;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function add($element): bool
+    {
+        $this[] = $element;
+
+        return true;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function element()
+    {
+        $element = $this->peek();
+
+        if ($element === null) {
+            throw new NoSuchElementException(
+                'Can\'t return element from Queue. Queue is empty.'
+            );
+        }
+
+        return $element;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function offer($element): bool
+    {
+        try {
+            return $this->add($element);
+        } catch (InvalidArgumentException $e) {
+            return false;
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function peek()
+    {
+        if ($this->count() === 0) {
+            return null;
+        }
+
+        return $this[$this->index];
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function poll()
+    {
+        if ($this->count() === 0) {
+            return null;
+        }
+
+        $head = $this[$this->index];
+
+        unset($this[$this->index]);
+        $this->index++;
+
+        return $head;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function remove()
+    {
+        $head = $this->poll();
+
+        if ($head === null) {
+            throw new NoSuchElementException('Can\'t return element from Queue. Queue is empty.');
+        }
+
+        return $head;
+    }
+
+    public function getType(): string
+    {
+        return $this->queueType;
+    }
+}

+ 203 - 0
api/vendor/ramsey/collection/src/QueueInterface.php

@@ -0,0 +1,203 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+use Ramsey\Collection\Exception\NoSuchElementException;
+
+/**
+ * A queue is a collection in which the entities in the collection are kept in
+ * order.
+ *
+ * The principal operations on the queue are the addition of entities to the end
+ * (tail), also known as *enqueue*, and removal of entities from the front
+ * (head), also known as *dequeue*. This makes the queue a first-in-first-out
+ * (FIFO) data structure.
+ *
+ * Besides basic array operations, queues provide additional insertion,
+ * extraction, and inspection operations. Each of these methods exists in two
+ * forms: one throws an exception if the operation fails, the other returns a
+ * special value (either `null` or `false`, depending on the operation). The
+ * latter form of the insert operation is designed specifically for use with
+ * capacity-restricted `QueueInterface` implementations; in most
+ * implementations, insert operations cannot fail.
+ *
+ * <table>
+ * <caption>Summary of QueueInterface methods</caption>
+ * <thead>
+ * <tr>
+ * <td></td>
+ * <td><em>Throws exception</em></td>
+ * <td><em>Returns special value</em></td>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <th>Insert</th>
+ * <td><code>add()</code></td>
+ * <td><code>offer()</code></td>
+ * </tr>
+ * <tr>
+ * <th>Remove</th>
+ * <td><code>remove()</code></td>
+ * <td><code>poll()</code></td>
+ * </tr>
+ * <tr>
+ * <th>Examine</th>
+ * <td><code>element()</code></td>
+ * <td><code>peek()</code></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * Queues typically, but do not necessarily, order elements in a FIFO
+ * (first-in-first-out) manner. Among the exceptions are priority queues, which
+ * order elements according to a supplied comparator, or the elements' natural
+ * ordering, and LIFO queues (or stacks) which order the elements LIFO
+ * (last-in-first-out). Whatever the ordering used, the head of the queue is
+ * that element which would be removed by a call to remove() or poll(). In a
+ * FIFO queue, all new elements are inserted at the tail of the queue. Other
+ * kinds of queues may use different placement rules. Every `QueueInterface`
+ * implementation must specify its ordering properties.
+ *
+ * The `offer()` method inserts an element if possible, otherwise returning
+ * `false`. This differs from the `add()` method, which can fail to add an
+ * element only by throwing an unchecked exception. The `offer()` method is
+ * designed for use when failure is a normal, rather than exceptional
+ * occurrence, for example, in fixed-capacity (or "bounded") queues.
+ *
+ * The `remove()` and `poll()` methods remove and return the head of the queue.
+ * Exactly which element is removed from the queue is a function of the queue's
+ * ordering policy, which differs from implementation to implementation. The
+ * `remove()` and `poll()` methods differ only in their behavior when the queue
+ * is empty: the `remove()` method throws an exception, while the `poll()`
+ * method returns `null`.
+ *
+ * The `element()` and `peek()` methods return, but do not remove, the head of
+ * the queue.
+ *
+ * `QueueInterface` implementations generally do not allow insertion of `null`
+ * elements, although some implementations do not prohibit insertion of `null`.
+ * Even in the implementations that permit it, `null` should not be inserted
+ * into a queue, as `null` is also used as a special return value by the
+ * `poll()` method to indicate that the queue contains no elements.
+ *
+ * @template T
+ * @extends ArrayInterface<T>
+ */
+interface QueueInterface extends ArrayInterface
+{
+    /**
+     * Ensures that this queue contains the specified element (optional
+     * operation).
+     *
+     * Returns `true` if this queue changed as a result of the call. (Returns
+     * `false` if this queue does not permit duplicates and already contains the
+     * specified element.)
+     *
+     * Queues that support this operation may place limitations on what elements
+     * may be added to this queue. In particular, some queues will refuse to add
+     * `null` elements, and others will impose restrictions on the type of
+     * elements that may be added. Queue classes should clearly specify in their
+     * documentation any restrictions on what elements may be added.
+     *
+     * If a queue refuses to add a particular element for any reason other than
+     * that it already contains the element, it must throw an exception (rather
+     * than returning `false`). This preserves the invariant that a queue always
+     * contains the specified element after this call returns.
+     *
+     * @see self::offer()
+     *
+     * @param T $element The element to add to this queue.
+     *
+     * @return bool `true` if this queue changed as a result of the call.
+     *
+     * @throws \RuntimeException if a queue refuses to add a particular element
+     *     for any reason other than that it already contains the element.
+     *     Implementations should use a more-specific exception that extends
+     *     `\RuntimeException`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function add($element): bool;
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.
+     *
+     * This method differs from `peek()` only in that it throws an exception if
+     * this queue is empty.
+     *
+     * @see self::peek()
+     *
+     * @return T the head of this queue.
+     *
+     * @throws NoSuchElementException if this queue is empty.
+     */
+    public function element();
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do so
+     * immediately without violating capacity restrictions.
+     *
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to `add()`, which can fail to insert an element only by
+     * throwing an exception.
+     *
+     * @see self::add()
+     *
+     * @param T $element The element to add to this queue.
+     *
+     * @return bool `true` if the element was added to this queue, else `false`.
+     */
+    // phpcs:ignore SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+    public function offer($element): bool;
+
+    /**
+     * Retrieves, but does not remove, the head of this queue, or returns `null`
+     * if this queue is empty.
+     *
+     * @see self::element()
+     *
+     * @return T|null the head of this queue, or `null` if this queue is empty.
+     */
+    public function peek();
+
+    /**
+     * Retrieves and removes the head of this queue, or returns `null`
+     * if this queue is empty.
+     *
+     * @see self::remove()
+     *
+     * @return T|null the head of this queue, or `null` if this queue is empty.
+     */
+    public function poll();
+
+    /**
+     * Retrieves and removes the head of this queue.
+     *
+     * This method differs from `poll()` only in that it throws an exception if
+     * this queue is empty.
+     *
+     * @see self::poll()
+     *
+     * @return T the head of this queue.
+     *
+     * @throws NoSuchElementException if this queue is empty.
+     */
+    public function remove();
+
+    /**
+     * Returns the type associated with this queue.
+     */
+    public function getType(): string;
+}

+ 69 - 0
api/vendor/ramsey/collection/src/Set.php

@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection;
+
+/**
+ * A set is a collection that contains no duplicate elements.
+ *
+ * Great care must be exercised if mutable objects are used as set elements.
+ * The behavior of a set is not specified if the value of an object is changed
+ * in a manner that affects equals comparisons while the object is an element in
+ * the set.
+ *
+ * Example usage:
+ *
+ * ``` php
+ * $foo = new \My\Foo();
+ * $set = new Set(\My\Foo::class);
+ *
+ * $set->add($foo); // returns TRUE, the element don't exists
+ * $set->add($foo); // returns FALSE, the element already exists
+ *
+ * $bar = new \My\Foo();
+ * $set->add($bar); // returns TRUE, $bar !== $foo
+ * ```
+ *
+ * @template T
+ * @extends AbstractSet<T>
+ */
+class Set extends AbstractSet
+{
+    /**
+     * The type of elements stored in this set
+     *
+     * A set's type is immutable. For this reason, this property is private.
+     *
+     * @var string
+     */
+    private $setType;
+
+    /**
+     * Constructs a set object of the specified type, optionally with the
+     * specified data.
+     *
+     * @param string $setType The type (FQCN) associated with this set.
+     * @param array<array-key, T> $data The initial items to store in the set.
+     */
+    public function __construct(string $setType, array $data = [])
+    {
+        $this->setType = $setType;
+        parent::__construct($data);
+    }
+
+    public function getType(): string
+    {
+        return $this->setType;
+    }
+}

+ 73 - 0
api/vendor/ramsey/collection/src/Tool/TypeTrait.php

@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Tool;
+
+use function is_array;
+use function is_bool;
+use function is_callable;
+use function is_float;
+use function is_int;
+use function is_numeric;
+use function is_object;
+use function is_resource;
+use function is_scalar;
+use function is_string;
+
+/**
+ * Provides functionality to check values for specific types.
+ */
+trait TypeTrait
+{
+    /**
+     * Returns `true` if value is of the specified type.
+     *
+     * @param string $type The type to check the value against.
+     * @param mixed $value The value to check.
+     */
+    protected function checkType(string $type, $value): bool
+    {
+        switch ($type) {
+            case 'array':
+                return is_array($value);
+            case 'bool':
+            case 'boolean':
+                return is_bool($value);
+            case 'callable':
+                return is_callable($value);
+            case 'float':
+            case 'double':
+                return is_float($value);
+            case 'int':
+            case 'integer':
+                return is_int($value);
+            case 'null':
+                return $value === null;
+            case 'numeric':
+                return is_numeric($value);
+            case 'object':
+                return is_object($value);
+            case 'resource':
+                return is_resource($value);
+            case 'scalar':
+                return is_scalar($value);
+            case 'string':
+                return is_string($value);
+            case 'mixed':
+                return true;
+            default:
+                return $value instanceof $type;
+        }
+    }
+}

+ 58 - 0
api/vendor/ramsey/collection/src/Tool/ValueExtractorTrait.php

@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Tool;
+
+use Ramsey\Collection\Exception\ValueExtractionException;
+
+use function get_class;
+use function method_exists;
+use function property_exists;
+use function sprintf;
+
+/**
+ * Provides functionality to extract the value of a property or method from an object.
+ */
+trait ValueExtractorTrait
+{
+    /**
+     * Extracts the value of the given property or method from the object.
+     *
+     * @param mixed $object The object to extract the value from.
+     * @param string $propertyOrMethod The property or method for which the
+     *     value should be extracted.
+     *
+     * @return mixed the value extracted from the specified property or method.
+     *
+     * @throws ValueExtractionException if the method or property is not defined.
+     */
+    protected function extractValue($object, string $propertyOrMethod)
+    {
+        if (!is_object($object)) {
+            throw new ValueExtractionException('Unable to extract a value from a non-object');
+        }
+
+        if (property_exists($object, $propertyOrMethod)) {
+            return $object->$propertyOrMethod;
+        }
+
+        if (method_exists($object, $propertyOrMethod)) {
+            return $object->{$propertyOrMethod}();
+        }
+
+        throw new ValueExtractionException(
+            sprintf('Method or property "%s" not defined in %s', $propertyOrMethod, get_class($object))
+        );
+    }
+}

+ 94 - 0
api/vendor/ramsey/collection/src/Tool/ValueToStringTrait.php

@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * This file is part of the ramsey/collection library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Collection\Tool;
+
+use DateTimeInterface;
+
+use function get_class;
+use function get_resource_type;
+use function is_array;
+use function is_bool;
+use function is_callable;
+use function is_resource;
+use function is_scalar;
+
+/**
+ * Provides functionality to express a value as string
+ */
+trait ValueToStringTrait
+{
+    /**
+     * Returns a string representation of the value.
+     *
+     * - null value: `'NULL'`
+     * - boolean: `'TRUE'`, `'FALSE'`
+     * - array: `'Array'`
+     * - scalar: converted-value
+     * - resource: `'(type resource #number)'`
+     * - object with `__toString()`: result of `__toString()`
+     * - object DateTime: ISO 8601 date
+     * - object: `'(className Object)'`
+     * - anonymous function: same as object
+     *
+     * @param mixed $value the value to return as a string.
+     */
+    protected function toolValueToString($value): string
+    {
+        // null
+        if ($value === null) {
+            return 'NULL';
+        }
+
+        // boolean constants
+        if (is_bool($value)) {
+            return $value ? 'TRUE' : 'FALSE';
+        }
+
+        // array
+        if (is_array($value)) {
+            return 'Array';
+        }
+
+        // scalar types (integer, float, string)
+        if (is_scalar($value)) {
+            return (string) $value;
+        }
+
+        // resource
+        if (is_resource($value)) {
+            return '(' . get_resource_type($value) . ' resource #' . (int) $value . ')';
+        }
+
+        // If we don't know what it is, use var_export().
+        if (!is_object($value)) {
+            return '(' . var_export($value, true) . ')';
+        }
+
+        // From here, $value should be an object.
+
+        // __toString() is implemented
+        if (is_callable([$value, '__toString'])) {
+            return (string) $value->__toString();
+        }
+
+        // object of type \DateTime
+        if ($value instanceof DateTimeInterface) {
+            return $value->format('c');
+        }
+
+        // unknown type
+        return '(' . get_class($value) . ' Object)';
+    }
+}

+ 0 - 2
api/vendor/ramsey/uuid/LICENSE

@@ -1,5 +1,3 @@
-MIT License
-
 Copyright (c) 2012-2021 Ben Ramsey <ben@benramsey.com>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy

+ 47 - 151
api/vendor/ramsey/uuid/README.md

@@ -1,44 +1,29 @@
-# ramsey/uuid
-
-*IMPORTANT: This is the 3.x series. Please upgrade to the 4.x series.*
-
-*NOTICE: Formerly known as `rhumsaa/uuid`, The package and namespace names have
-changed to `ramsey/uuid` and `Ramsey\Uuid`, respectively.*
-
-[![Source Code][badge-source]][source]
-[![Series][badge-series]][series]
-[![Upgrade][badge-upgrade]][upgrade]
-[![PHP Version][badge-php]][php]
-[![Software License][badge-license]][license]
-[![Build Status][badge-build]][build]
-[![Coverage Status][badge-coverage]][coverage]
-
-ramsey/uuid is a PHP 5.4+ library for generating and working with
-[RFC 4122][rfc4122] version 1, 3, 4, and 5 universally unique identifiers
-(UUID).
-
-This project adheres to a [Contributor Code of Conduct][conduct]. By
-participating in this project and its community, you are expected to uphold this
-code.
-
-From [Wikipedia](http://en.wikipedia.org/wiki/Universally_unique_identifier):
-
-> The intent of UUIDs is to enable distributed systems to uniquely identify
-> information without significant central coordination. In this context the word
-> unique should be taken to mean "practically unique" rather than "guaranteed
-> unique". Since the identifiers have a finite size, it is possible for two
-> differing items to share the same identifier. The identifier size and
-> generation process need to be selected so as to make this sufficiently
-> improbable in practice. Anyone can create a UUID and use it to identify
-> something with reasonable confidence that the same identifier will never be
-> unintentionally created by anyone to identify something else. Information
-> labeled with UUIDs can therefore be later combined into a single database
-> without needing to resolve identifier (ID) conflicts.
+<h1 align="center">ramsey/uuid</h1>
+
+<p align="center">
+    <strong>A PHP library for generating and working with UUIDs.</strong>
+</p>
+
+<p align="center">
+    <a href="https://github.com/ramsey/uuid"><img src="http://img.shields.io/badge/source-ramsey/uuid-blue.svg?style=flat-square" alt="Source Code"></a>
+    <a href="https://packagist.org/packages/ramsey/uuid"><img src="https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=release" alt="Download Package"></a>
+    <a href="https://php.net"><img src="https://img.shields.io/packagist/php-v/ramsey/uuid.svg?style=flat-square&colorB=%238892BF" alt="PHP Programming Language"></a>
+    <a href="https://github.com/ramsey/uuid/blob/main/LICENSE"><img src="https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square&colorB=darkcyan" alt="Read License"></a>
+    <a href="https://github.com/ramsey/uuid/actions/workflows/continuous-integration.yml"><img src="https://img.shields.io/github/workflow/status/ramsey/uuid/build/main?logo=github&style=flat-square" alt="Build Status"></a>
+    <a href="https://codecov.io/gh/ramsey/uuid"><img src="https://img.shields.io/codecov/c/gh/ramsey/uuid?label=codecov&logo=codecov&style=flat-square" alt="Codecov Code Coverage"></a>
+    <a href="https://shepherd.dev/github/ramsey/uuid"><img src="https://img.shields.io/endpoint?style=flat-square&url=https%3A%2F%2Fshepherd.dev%2Fgithub%2Framsey%2Fuuid%2Fcoverage" alt="Psalm Type Coverage"></a>
+</p>
+
+ramsey/uuid is a PHP library for generating and working with universally unique
+identifiers (UUIDs).
+
+This project adheres to a [code of conduct](CODE_OF_CONDUCT.md).
+By participating in this project and its community, you are expected to
+uphold this code.
 
 Much inspiration for this library came from the [Java][javauuid] and
 [Python][pyuuid] UUID libraries.
 
-
 ## Installation
 
 The preferred method of installation is via [Composer][]. Run the following
@@ -49,110 +34,38 @@ command to install the package and add it as a requirement to your project's
 composer require ramsey/uuid
 ```
 
+## Upgrading to Version 4
 
-## Upgrading from 2.x to 3.x
-
-While we have made significant internal changes to the library, we have made
-every effort to ensure a seamless upgrade path from the 2.x series of this
-library to 3.x.
-
-One major breaking change is the transition from the `Rhumsaa` root namespace to
-`Ramsey`. In most cases, all you will need is to change the namespace to
-`Ramsey` in your code, and everything will "just work."
-
-Here are full details on the breaking changes to the public API of this library:
-
-1. All namespace references of `Rhumsaa` have changed to `Ramsey`. Simply change
-   the namespace to `Ramsey` in your code and everything should work.
-2. The console application has moved to
-   [ramsey/uuid-console](https://packagist.org/packages/ramsey/uuid-console).
-   If using the console functionality, use Composer to require
-   `ramsey/uuid-console`.
-3. The Doctrine field type mapping has moved to
-   [ramsey/uuid-doctrine](https://packagist.org/packages/ramsey/uuid-doctrine).
-   If using the Doctrine functionality, use Composer to require
-   `ramsey/uuid-doctrine`.
-
-
-## What to do if you see a "rhumsaa/uuid is abandoned" message
-
-When installing your project's dependencies using Composer, you might see the
-following message:
-
-```
-Package rhumsaa/uuid is abandoned, you should avoid using it. Use
-ramsey/uuid instead.
-```
-
-Don't panic. Simply execute the following commands with Composer:
-
-``` bash
-composer remove rhumsaa/uuid
-composer require ramsey/uuid=^2.9
-```
-
-After doing so, you will have the latest ramsey/uuid package in the 2.x series,
-and there will be no need to modify any code; the namespace in the 2.x series is
-still `Rhumsaa`.
-
-
-## Requirements
-
-Some methods in this library have requirements due to integer size restrictions
-on 32-bit and 64-bit builds of PHP. A 64-bit build of PHP and the
-[Moontoast\Math][] library are recommended. However, this library is designed to
-work on 32-bit builds of PHP without Moontoast\Math, with some degraded
-functionality. Please check the API documentation for more information.
-
-If a particular requirement is not present, then an
-`UnsatisfiedDependencyException` is thrown, allowing one to catch a bad call in
-an environment where the call is not supported and gracefully degrade.
-
-
-## Examples
-
-See the [cookbook on the wiki][wiki-cookbook] for more examples and approaches
-to specific use-cases.
+See the documentation for a thorough upgrade guide:
 
-```php
-<?php
-require 'vendor/autoload.php';
+* [Upgrading ramsey/uuid Version 3 to 4](https://uuid.ramsey.dev/en/latest/upgrading/3-to-4.html)
 
-use Ramsey\Uuid\Uuid;
-use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+## Documentation
 
-try {
+Please see <https://uuid.ramsey.dev> for documentation, tips, examples, and
+frequently asked questions.
 
-    // Generate a version 1 (time-based) UUID object
-    $uuid1 = Uuid::uuid1();
-    echo $uuid1->toString() . "\n"; // i.e. e4eaaaf2-d142-11e1-b3e4-080027620cdd
-
-    // Generate a version 3 (name-based and hashed with MD5) UUID object
-    $uuid3 = Uuid::uuid3(Uuid::NAMESPACE_DNS, 'php.net');
-    echo $uuid3->toString() . "\n"; // i.e. 11a38b9a-b3da-360f-9353-a5a725514269
-
-    // Generate a version 4 (random) UUID object
-    $uuid4 = Uuid::uuid4();
-    echo $uuid4->toString() . "\n"; // i.e. 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a
-
-    // Generate a version 5 (name-based and hashed with SHA1) UUID object
-    $uuid5 = Uuid::uuid5(Uuid::NAMESPACE_DNS, 'php.net');
-    echo $uuid5->toString() . "\n"; // i.e. c4a760a8-dbcf-5254-a0d9-6a4474bd1b62
-
-} catch (UnsatisfiedDependencyException $e) {
+## Contributing
 
-    // Some dependency was not met. Either the method cannot be called on a
-    // 32-bit system, or it can, but it relies on Moontoast\Math to be present.
-    echo 'Caught exception: ' . $e->getMessage() . "\n";
+Contributions are welcome! To contribute, please familiarize yourself with
+[CONTRIBUTING.md](CONTRIBUTING.md).
 
-}
-```
+## Coordinated Disclosure
 
+Keeping user information safe and secure is a top priority, and we welcome the
+contribution of external security researchers. If you believe you've found a
+security issue in software that is maintained in this repository, please read
+[SECURITY.md][] for instructions on submitting a vulnerability report.
 
-## Contributing
+## ramsey/uuid for Enterprise
 
-Contributions are welcome! Please read [CONTRIBUTING.md][] for details.
+Available as part of the Tidelift Subscription.
 
+The maintainers of ramsey/uuid and thousands of other packages are working with
+Tidelift to deliver commercial support and maintenance for the open source
+packages you use to build your applications. Save time, reduce risk, and improve
+code health, while paying the maintainers of the exact packages you use.
+[Learn more.](https://tidelift.com/subscription/pkg/packagist-ramsey-uuid?utm_source=undefined&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
 
 ## Copyright and License
 
@@ -160,28 +73,11 @@ The ramsey/uuid library is copyright © [Ben Ramsey](https://benramsey.com/) and
 licensed for use under the MIT License (MIT). Please see [LICENSE][] for more
 information.
 
-
 [rfc4122]: http://tools.ietf.org/html/rfc4122
-[conduct]: https://github.com/ramsey/uuid/blob/master/.github/CODE_OF_CONDUCT.md
+[conduct]: https://github.com/ramsey/uuid/blob/main/CODE_OF_CONDUCT.md
 [javauuid]: http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html
 [pyuuid]: http://docs.python.org/3/library/uuid.html
 [composer]: http://getcomposer.org/
-[moontoast\math]: https://packagist.org/packages/moontoast/math
-[wiki-cookbook]: https://github.com/ramsey/uuid/wiki/Ramsey%5CUuid-Cookbook
-[contributing.md]: https://github.com/ramsey/uuid/blob/master/.github/CONTRIBUTING.md
-
-[badge-source]: https://img.shields.io/badge/source-ramsey/uuid-blue.svg?style=flat-square
-[badge-series]: https://img.shields.io/badge/series-3.x-darkcyan.svg?style=flat-square
-[badge-upgrade]: https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=upgrade&colorB=darkred
-[badge-license]: https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square&colorB=darkcyan
-[badge-php]: https://img.shields.io/packagist/php-v/ramsey/uuid/3.x-dev.svg?style=flat-square&colorB=%238892BF
-[badge-build]: https://img.shields.io/github/workflow/status/ramsey/uuid/build/3.x.svg?logo=github&style=flat-square
-[badge-coverage]: https://img.shields.io/codecov/c/gh/ramsey/uuid/3.x.svg?style=flat-square&logo=codecov
-
-[source]: https://github.com/ramsey/uuid/tree/3.x
-[series]: https://packagist.org/packages/ramsey/uuid
-[upgrade]: https://packagist.org/packages/ramsey/uuid
-[license]: https://github.com/ramsey/uuid/blob/master/LICENSE
-[php]: https://php.net
-[build]: https://github.com/ramsey/uuid/actions/workflows/continuous-integration.yml?query=branch%3A3.x
-[coverage]: https://app.codecov.io/gh/ramsey/uuid/branch/3.x
+[contributing.md]: https://github.com/ramsey/uuid/blob/main/CONTRIBUTING.md
+[security.md]: https://github.com/ramsey/uuid/blob/main/SECURITY.md
+[license]: https://github.com/ramsey/uuid/blob/main/LICENSE

+ 62 - 49
api/vendor/ramsey/uuid/composer.json

@@ -1,66 +1,65 @@
 {
     "name": "ramsey/uuid",
     "type": "library",
-    "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
-    "keywords": ["uuid", "identifier", "guid"],
-    "homepage": "https://github.com/ramsey/uuid",
-    "license": "MIT",
-    "authors": [
-        {
-            "name": "Ben Ramsey",
-            "email": "ben@benramsey.com",
-            "homepage": "https://benramsey.com"
-        },
-        {
-            "name": "Marijn Huizendveld",
-            "email": "marijn.huizendveld@gmail.com"
-        },
-        {
-            "name": "Thibaud Fabre",
-            "email": "thibaud@aztech.io"
-        }
+    "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
+    "keywords": [
+        "uuid",
+        "identifier",
+        "guid"
     ],
+    "license": "MIT",
     "require": {
-        "php": "^5.4 | ^7.0 | ^8.0",
+        "php": "^7.2 || ^8.0",
         "ext-json": "*",
-        "paragonie/random_compat": "^1 | ^2 | ^9.99.99",
-        "symfony/polyfill-ctype": "^1.8"
+        "brick/math": "^0.8 || ^0.9",
+        "ramsey/collection": "^1.0",
+        "symfony/polyfill-ctype": "^1.8",
+        "symfony/polyfill-php80": "^1.14"
+    },
+    "replace": {
+        "rhumsaa/uuid": "self.version"
     },
     "require-dev": {
-        "codeception/aspect-mock": "^1 | ^2",
-        "doctrine/annotations": "^1.2",
-        "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
-        "mockery/mockery": "^0.9.11 | ^1",
+        "captainhook/captainhook": "^5.10",
+        "captainhook/plugin-composer": "^5.3",
+        "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+        "doctrine/annotations": "^1.8",
+        "ergebnis/composer-normalize": "^2.15",
+        "mockery/mockery": "^1.3",
         "moontoast/math": "^1.1",
-        "nikic/php-parser": "<=4.5.0",
         "paragonie/random-lib": "^2",
-        "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
-        "php-parallel-lint/php-parallel-lint": "^1.3",
-        "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
+        "php-mock/php-mock": "^2.2",
+        "php-mock/php-mock-mockery": "^1.3",
+        "php-parallel-lint/php-parallel-lint": "^1.1",
+        "phpbench/phpbench": "^1.0",
+        "phpstan/extension-installer": "^1.0",
+        "phpstan/phpstan": "^0.12",
+        "phpstan/phpstan-mockery": "^0.12",
+        "phpstan/phpstan-phpunit": "^0.12",
+        "phpunit/phpunit": "^8.5 || ^9",
+        "slevomat/coding-standard": "^7.0",
         "squizlabs/php_codesniffer": "^3.5",
-        "yoast/phpunit-polyfills": "^1.0"
+        "vimeo/psalm": "^4.9"
     },
     "suggest": {
-        "ext-ctype": "Provides support for PHP Ctype functions",
-        "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
-        "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
-        "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
-        "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
-        "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
-        "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type.",
-        "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter"
+        "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
+        "ext-ctype": "Enables faster processing of character classification using ctype functions.",
+        "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
+        "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
+        "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+        "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
     },
     "config": {
         "sort-packages": true
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "3.x-dev"
+            "dev-main": "4.x-dev"
+        },
+        "captainhook": {
+            "force-install": true
         }
     },
-    "replace": {
-        "rhumsaa/uuid": "self.version"
-    },
     "autoload": {
         "psr-4": {
             "Ramsey\\Uuid\\": "src/"
@@ -71,24 +70,38 @@
     },
     "autoload-dev": {
         "psr-4": {
+            "Ramsey\\Uuid\\Benchmark\\": "tests/benchmark/",
+            "Ramsey\\Uuid\\StaticAnalysis\\": "tests/static-analysis/",
             "Ramsey\\Uuid\\Test\\": "tests/"
         }
     },
+    "minimum-stability": "dev",
+    "prefer-stable": true,
     "scripts": {
+        "analyze": [
+            "@phpstan",
+            "@psalm"
+        ],
+        "build:clean": "git clean -fX build/",
         "lint": "parallel-lint src tests",
-        "phpcs": "phpcs src tests --standard=psr2 -sp --colors",
+        "lint:paths": "parallel-lint",
+        "phpbench": "phpbench run",
+        "phpcbf": "phpcbf -vpw --cache=build/cache/phpcs.cache",
+        "phpcs": "phpcs --cache=build/cache/phpcs.cache",
+        "phpstan": [
+            "phpstan analyse --no-progress",
+            "phpstan analyse -c phpstan-tests.neon --no-progress"
+        ],
         "phpunit": "phpunit --verbose --colors=always",
         "phpunit-coverage": "phpunit --verbose --colors=always --coverage-html build/coverage",
+        "psalm": "psalm --show-info=false --config=psalm.xml",
         "test": [
             "@lint",
+            "@phpbench",
             "@phpcs",
+            "@phpstan",
+            "@psalm",
             "@phpunit"
         ]
-    },
-    "support": {
-        "issues": "https://github.com/ramsey/uuid/issues",
-        "rss": "https://github.com/ramsey/uuid/releases.atom",
-        "source": "https://github.com/ramsey/uuid",
-        "wiki": "https://github.com/ramsey/uuid/wiki"
     }
 }

+ 38 - 16
api/vendor/ramsey/uuid/src/BinaryUtils.php

@@ -1,5 +1,17 @@
 <?php
 
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
 namespace Ramsey\Uuid;
 
 /**
@@ -8,32 +20,42 @@ namespace Ramsey\Uuid;
 class BinaryUtils
 {
     /**
-     * Applies the RFC 4122 variant field to the `clock_seq_hi_and_reserved` field
+     * Applies the RFC 4122 variant field to the 16-bit clock sequence
+     *
+     * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
      *
-     * @param $clockSeqHi
-     * @return int The high field of the clock sequence multiplexed with the variant
-     * @link http://tools.ietf.org/html/rfc4122#section-4.1.1
+     * @param int $clockSeq The 16-bit clock sequence value before the RFC 4122
+     *     variant is applied
+     *
+     * @return int The 16-bit clock sequence multiplexed with the UUID variant
+     *
+     * @psalm-pure
      */
-    public static function applyVariant($clockSeqHi)
+    public static function applyVariant(int $clockSeq): int
     {
-        // Set the variant to RFC 4122
-        $clockSeqHi = $clockSeqHi & 0x3f;
-        $clockSeqHi |= 0x80;
+        $clockSeq = $clockSeq & 0x3fff;
+        $clockSeq |= 0x8000;
 
-        return $clockSeqHi;
+        return $clockSeq;
     }
 
     /**
-     * Applies the RFC 4122 version number to the `time_hi_and_version` field
+     * Applies the RFC 4122 version number to the 16-bit `time_hi_and_version` field
+     *
+     * @link http://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
+     *
+     * @param int $timeHi The value of the 16-bit `time_hi_and_version` field
+     *     before the RFC 4122 version is applied
+     * @param int $version The RFC 4122 version to apply to the `time_hi` field
+     *
+     * @return int The 16-bit time_hi field of the timestamp multiplexed with
+     *     the UUID version number
      *
-     * @param string $timeHi
-     * @param integer $version
-     * @return int The high field of the timestamp multiplexed with the version number
-     * @link http://tools.ietf.org/html/rfc4122#section-4.1.3
+     * @psalm-pure
      */
-    public static function applyVersion($timeHi, $version)
+    public static function applyVersion(int $timeHi, int $version): int
     {
-        $timeHi = hexdec($timeHi) & 0x0fff;
+        $timeHi = $timeHi & 0x0fff;
         $timeHi |= $version << 12;
 
         return $timeHi;

+ 80 - 0
api/vendor/ramsey/uuid/src/Builder/BuilderCollection.php

@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Builder;
+
+use Ramsey\Collection\AbstractCollection;
+use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
+use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
+use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
+use Ramsey\Uuid\Guid\GuidBuilder;
+use Ramsey\Uuid\Math\BrickMathCalculator;
+use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
+use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
+use Traversable;
+
+/**
+ * A collection of UuidBuilderInterface objects
+ *
+ * @extends AbstractCollection<UuidBuilderInterface>
+ */
+class BuilderCollection extends AbstractCollection
+{
+    public function getType(): string
+    {
+        return UuidBuilderInterface::class;
+    }
+
+    /**
+     * @psalm-mutation-free
+     * @psalm-suppress ImpureMethodCall
+     * @psalm-suppress InvalidTemplateParam
+     */
+    public function getIterator(): Traversable
+    {
+        return parent::getIterator();
+    }
+
+    /**
+     * Re-constructs the object from its serialized form
+     *
+     * @param string $serialized The serialized PHP string to unserialize into
+     *     a UuidInterface instance
+     *
+     * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+     * @psalm-suppress RedundantConditionGivenDocblockType
+     */
+    public function unserialize($serialized): void
+    {
+        /** @var array<array-key, UuidBuilderInterface> $data */
+        $data = unserialize($serialized, [
+            'allowed_classes' => [
+                BrickMathCalculator::class,
+                GenericNumberConverter::class,
+                GenericTimeConverter::class,
+                GuidBuilder::class,
+                NonstandardUuidBuilder::class,
+                PhpTimeConverter::class,
+                Rfc4122UuidBuilder::class,
+            ],
+        ]);
+
+        $this->data = array_filter(
+            $data,
+            function ($unserialized): bool {
+                return $unserialized instanceof UuidBuilderInterface;
+            }
+        );
+    }
+}

+ 8 - 36
api/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,48 +8,19 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Builder;
 
-use Ramsey\Uuid\Codec\CodecInterface;
-use Ramsey\Uuid\Converter\NumberConverterInterface;
-use Ramsey\Uuid\Uuid;
+use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
 
 /**
- * DefaultUuidBuilder is the default UUID builder for ramsey/uuid; it builds
- * instances of Uuid objects
+ * @deprecated Transition to {@see Rfc4122UuidBuilder}.
+ *
+ * @psalm-immutable
  */
-class DefaultUuidBuilder implements UuidBuilderInterface
+class DefaultUuidBuilder extends Rfc4122UuidBuilder
 {
-    /**
-     * @var NumberConverterInterface
-     */
-    private $converter;
-
-    /**
-     * Constructs the DefaultUuidBuilder
-     *
-     * @param NumberConverterInterface $converter The number converter to use when constructing the Uuid
-     */
-    public function __construct(NumberConverterInterface $converter)
-    {
-        $this->converter = $converter;
-    }
-
-    /**
-     * Builds a Uuid
-     *
-     * @param CodecInterface $codec The codec to use for building this Uuid
-     * @param array $fields An array of fields from which to construct the Uuid;
-     *     see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
-     * @return Uuid
-     */
-    public function build(CodecInterface $codec, array $fields)
-    {
-        return new Uuid($fields, $this->converter, $codec);
-    }
 }

+ 41 - 18
api/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,47 +8,69 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Builder;
 
 use Ramsey\Uuid\Codec\CodecInterface;
 use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Converter\Time\DegradedTimeConverter;
+use Ramsey\Uuid\Converter\TimeConverterInterface;
 use Ramsey\Uuid\DegradedUuid;
+use Ramsey\Uuid\Rfc4122\Fields as Rfc4122Fields;
+use Ramsey\Uuid\UuidInterface;
 
 /**
- * DegradedUuidBuilder builds instances of DegradedUuid
+ * @deprecated DegradedUuid instances are no longer necessary to support 32-bit
+ *     systems. Transition to {@see DefaultUuidBuilder}.
+ *
+ * @psalm-immutable
  */
 class DegradedUuidBuilder implements UuidBuilderInterface
 {
     /**
      * @var NumberConverterInterface
      */
-    private $converter;
+    private $numberConverter;
 
     /**
-     * Constructs the DegradedUuidBuilder
-     *
-     * @param NumberConverterInterface $converter The number converter to use when constructing the DegradedUuid
+     * @var TimeConverterInterface
      */
-    public function __construct(NumberConverterInterface $converter)
-    {
-        $this->converter = $converter;
+    private $timeConverter;
+
+    /**
+     * @param NumberConverterInterface $numberConverter The number converter to
+     *     use when constructing the DegradedUuid
+     * @param TimeConverterInterface|null $timeConverter The time converter to use
+     *     for converting timestamps extracted from a UUID to Unix timestamps
+     */
+    public function __construct(
+        NumberConverterInterface $numberConverter,
+        ?TimeConverterInterface $timeConverter = null
+    ) {
+        $this->numberConverter = $numberConverter;
+        $this->timeConverter = $timeConverter ?: new DegradedTimeConverter();
     }
 
     /**
-     * Builds a DegradedUuid
+     * Builds and returns a DegradedUuid
+     *
+     * @param CodecInterface $codec The codec to use for building this DegradedUuid instance
+     * @param string $bytes The byte string from which to construct a UUID
+     *
+     * @return DegradedUuid The DegradedUuidBuild returns an instance of Ramsey\Uuid\DegradedUuid
      *
-     * @param CodecInterface $codec The codec to use for building this DegradedUuid
-     * @param array $fields An array of fields from which to construct the DegradedUuid;
-     *     see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
-     * @return DegradedUuid
+     * @psalm-pure
      */
-    public function build(CodecInterface $codec, array $fields)
+    public function build(CodecInterface $codec, string $bytes): UuidInterface
     {
-        return new DegradedUuid($fields, $this->converter, $codec);
+        return new DegradedUuid(
+            new Rfc4122Fields($bytes),
+            $this->numberConverter,
+            $codec,
+            $this->timeConverter
+        );
     }
 }

+ 74 - 0
api/vendor/ramsey/uuid/src/Builder/FallbackBuilder.php

@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Builder;
+
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Exception\BuilderNotFoundException;
+use Ramsey\Uuid\Exception\UnableToBuildUuidException;
+use Ramsey\Uuid\UuidInterface;
+
+/**
+ * FallbackBuilder builds a UUID by stepping through a list of UUID builders
+ * until a UUID can be constructed without exceptions
+ *
+ * @psalm-immutable
+ */
+class FallbackBuilder implements UuidBuilderInterface
+{
+    /**
+     * @var BuilderCollection
+     */
+    private $builders;
+
+    /**
+     * @param BuilderCollection $builders An array of UUID builders
+     */
+    public function __construct(BuilderCollection $builders)
+    {
+        $this->builders = $builders;
+    }
+
+    /**
+     * Builds and returns a UuidInterface instance using the first builder that
+     * succeeds
+     *
+     * @param CodecInterface $codec The codec to use for building this instance
+     * @param string $bytes The byte string from which to construct a UUID
+     *
+     * @return UuidInterface an instance of a UUID object
+     *
+     * @psalm-pure
+     */
+    public function build(CodecInterface $codec, string $bytes): UuidInterface
+    {
+        $lastBuilderException = null;
+
+        foreach ($this->builders as $builder) {
+            try {
+                return $builder->build($codec, $bytes);
+            } catch (UnableToBuildUuidException $exception) {
+                $lastBuilderException = $exception;
+
+                continue;
+            }
+        }
+
+        throw new BuilderNotFoundException(
+            'Could not find a suitable builder for the provided codec and fields',
+            0,
+            $lastBuilderException
+        );
+    }
+}

+ 14 - 9
api/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,28 +8,32 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Builder;
 
 use Ramsey\Uuid\Codec\CodecInterface;
 use Ramsey\Uuid\UuidInterface;
 
 /**
- * UuidBuilderInterface builds instances UuidInterface
+ * A UUID builder builds instances of UuidInterface
+ *
+ * @psalm-immutable
  */
 interface UuidBuilderInterface
 {
     /**
-     * Builds an instance of a UuidInterface
+     * Builds and returns a UuidInterface
      *
      * @param CodecInterface $codec The codec to use for building this UuidInterface instance
-     * @param array $fields An array of fields from which to construct a UuidInterface instance;
-     *     see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
-     * @return UuidInterface
+     * @param string $bytes The byte string from which to construct a UUID
+     *
+     * @return UuidInterface Implementations may choose to return more specific
+     *     instances of UUIDs that implement UuidInterface
+     *
+     * @psalm-pure
      */
-    public function build(CodecInterface $codec, array $fields);
+    public function build(CodecInterface $codec, string $bytes): UuidInterface;
 }

+ 34 - 23
api/vendor/ramsey/uuid/src/Codec/CodecInterface.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,54 +8,64 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Codec;
 
-use InvalidArgumentException;
-use Ramsey\Uuid\Exception\InvalidUuidStringException;
 use Ramsey\Uuid\UuidInterface;
 
 /**
- * CodecInterface represents a UUID coder-decoder
+ * A codec encodes and decodes a UUID according to defined rules
+ *
+ * @psalm-immutable
  */
 interface CodecInterface
 {
     /**
-     * Encodes a UuidInterface as a string representation of a UUID
+     * Returns a hexadecimal string representation of a UuidInterface
+     *
+     * @param UuidInterface $uuid The UUID for which to create a hexadecimal
+     *     string representation
      *
-     * @param UuidInterface $uuid
      * @return string Hexadecimal string representation of a UUID
+     *
+     * @psalm-return non-empty-string
      */
-    public function encode(UuidInterface $uuid);
+    public function encode(UuidInterface $uuid): string;
 
     /**
-     * Encodes a UuidInterface as a binary representation of a UUID
+     * Returns a binary string representation of a UuidInterface
+     *
+     * @param UuidInterface $uuid The UUID for which to create a binary string
+     *     representation
      *
-     * @param UuidInterface $uuid
      * @return string Binary string representation of a UUID
+     *
+     * @psalm-return non-empty-string
      */
-    public function encodeBinary(UuidInterface $uuid);
+    public function encodeBinary(UuidInterface $uuid): string;
 
     /**
-     * Decodes a string representation of a UUID into a UuidInterface object instance
+     * Returns a UuidInterface derived from a hexadecimal string representation
      *
-     * @param string $encodedUuid
-     * @return UuidInterface
-     * @throws InvalidUuidStringException
+     * @param string $encodedUuid The hexadecimal string representation to
+     *     convert into a UuidInterface instance
+     *
+     * @return UuidInterface An instance of a UUID decoded from a hexadecimal
+     *     string representation
      */
-    public function decode($encodedUuid);
+    public function decode(string $encodedUuid): UuidInterface;
 
     /**
-     * Decodes a binary representation of a UUID into a UuidInterface object instance
+     * Returns a UuidInterface derived from a binary string representation
+     *
+     * @param string $bytes The binary string representation to convert into a
+     *     UuidInterface instance
      *
-     * @param string $bytes
-     * @return UuidInterface
-     * @throws InvalidUuidStringException
-     * @throws InvalidArgumentException if string has not 16 characters
+     * @return UuidInterface An instance of a UUID decoded from a binary string
+     *     representation
      */
-    public function decodeBytes($bytes);
+    public function decodeBytes(string $bytes): UuidInterface;
 }

+ 20 - 68
api/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,97 +8,48 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Codec;
 
-use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\Guid\Guid;
 use Ramsey\Uuid\UuidInterface;
 
+use function bin2hex;
+use function substr;
+
 /**
  * GuidStringCodec encodes and decodes globally unique identifiers (GUID)
  *
- * @link https://en.wikipedia.org/wiki/Globally_unique_identifier
+ * @see Guid
+ *
+ * @psalm-immutable
  */
 class GuidStringCodec extends StringCodec
 {
-    /**
-     * Encodes a UuidInterface as a string representation of a GUID
-     *
-     * @param UuidInterface $uuid
-     * @return string Hexadecimal string representation of a GUID
-     */
-    public function encode(UuidInterface $uuid)
-    {
-        $components = array_values($uuid->getFieldsHex());
-
-        // Swap byte-order on the first three fields
-        $this->swapFields($components);
-
-        return vsprintf(
-            '%08s-%04s-%04s-%02s%02s-%012s',
-            $components
-        );
-    }
-
-    /**
-     * Encodes a UuidInterface as a binary representation of a GUID
-     *
-     * @param UuidInterface $uuid
-     * @return string Binary string representation of a GUID
-     */
-    public function encodeBinary(UuidInterface $uuid)
+    public function decode(string $encodedUuid): UuidInterface
     {
-        $components = array_values($uuid->getFieldsHex());
+        $bytes = $this->getBytes($encodedUuid);
 
-        return hex2bin(implode('', $components));
+        return $this->getBuilder()->build($this, $this->swapBytes($bytes));
     }
 
-    /**
-     * Decodes a string representation of a GUID into a UuidInterface object instance
-     *
-     * @param string $encodedUuid
-     * @return UuidInterface
-     * @throws InvalidUuidStringException
-     */
-    public function decode($encodedUuid)
-    {
-        $components = $this->extractComponents($encodedUuid);
-
-        $this->swapFields($components);
-
-        return $this->getBuilder()->build($this, $this->getFields($components));
-    }
-
-    /**
-     * Decodes a binary representation of a GUID into a UuidInterface object instance
-     *
-     * @param string $bytes
-     * @return UuidInterface
-     * @throws InvalidUuidStringException
-     */
-    public function decodeBytes($bytes)
+    public function decodeBytes(string $bytes): UuidInterface
     {
         // Specifically call parent::decode to preserve correct byte order
         return parent::decode(bin2hex($bytes));
     }
 
     /**
-     * Swaps fields to support GUID byte order
-     *
-     * @param array $components An array of UUID components (the UUID exploded on its dashes)
-     * @return void
+     * Swaps bytes according to the GUID rules
      */
-    protected function swapFields(array &$components)
+    private function swapBytes(string $bytes): string
     {
-        $hex = unpack('H*', pack('L', hexdec($components[0])));
-        $components[0] = $hex[1];
-        $hex = unpack('H*', pack('S', hexdec($components[1])));
-        $components[1] = $hex[1];
-        $hex = unpack('H*', pack('S', hexdec($components[2])));
-        $components[2] = $hex[1];
+        return $bytes[3] . $bytes[2] . $bytes[1] . $bytes[0]
+            . $bytes[5] . $bytes[4]
+            . $bytes[7] . $bytes[6]
+            . substr($bytes, 8);
     }
 }

+ 76 - 31
api/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,62 +8,106 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
+
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Codec;
 
-use InvalidArgumentException;
+use Ramsey\Uuid\Exception\InvalidArgumentException;
+use Ramsey\Uuid\Exception\UnsupportedOperationException;
+use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
+use Ramsey\Uuid\Uuid;
 use Ramsey\Uuid\UuidInterface;
 
+use function strlen;
+use function substr;
+
 /**
- * OrderedTimeCodec optimizes the bytes to increment UUIDs when time goes by, to improve database INSERTs.
- * The string value will be unchanged from StringCodec. Only works for UUID type 1.
+ * OrderedTimeCodec encodes and decodes a UUID, optimizing the byte order for
+ * more efficient storage
+ *
+ * For binary representations of version 1 UUID, this codec may be used to
+ * reorganize the time fields, making the UUID closer to sequential when storing
+ * the bytes. According to Percona, this optimization can improve database
+ * INSERTs and SELECTs using the UUID column as a key.
+ *
+ * The string representation of the UUID will remain unchanged. Only the binary
+ * representation is reordered.
+ *
+ * **PLEASE NOTE:** Binary representations of UUIDs encoded with this codec must
+ * be decoded with this codec. Decoding using another codec can result in
+ * malformed UUIDs.
+ *
+ * @link https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ Storing UUID Values in MySQL
+ *
+ * @psalm-immutable
  */
 class OrderedTimeCodec extends StringCodec
 {
-
     /**
-     * Encodes a UuidInterface as an optimized binary representation of a UUID
+     * Returns a binary string representation of a UUID, with the timestamp
+     * fields rearranged for optimized storage
      *
-     * @param UuidInterface $uuid
-     * @return string Binary string representation of a UUID
+     * @inheritDoc
+     * @psalm-return non-empty-string
+     * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
+     * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
      */
-    public function encodeBinary(UuidInterface $uuid)
+    public function encodeBinary(UuidInterface $uuid): string
     {
-        $fields = $uuid->getFieldsHex();
+        if (
+            !($uuid->getFields() instanceof Rfc4122FieldsInterface)
+            || $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME
+        ) {
+            throw new InvalidArgumentException(
+                'Expected RFC 4122 version 1 (time-based) UUID'
+            );
+        }
 
-        $optimized = [
-            $fields['time_hi_and_version'],
-            $fields['time_mid'],
-            $fields['time_low'],
-            $fields['clock_seq_hi_and_reserved'],
-            $fields['clock_seq_low'],
-            $fields['node'],
-        ];
+        $bytes = $uuid->getFields()->getBytes();
 
-        return hex2bin(implode('', $optimized));
+        /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
+        return $bytes[6] . $bytes[7]
+            . $bytes[4] . $bytes[5]
+            . $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3]
+            . substr($bytes, 8);
     }
 
     /**
-     * Decodes an optimized binary representation of a UUID into a UuidInterface object instance
+     * Returns a UuidInterface derived from an ordered-time binary string
+     * representation
      *
-     * @param string $bytes
-     * @return UuidInterface
-     * @throws InvalidArgumentException if string has not 16 characters
+     * @throws InvalidArgumentException if $bytes is an invalid length
+     *
+     * @inheritDoc
      */
-    public function decodeBytes($bytes)
+    public function decodeBytes(string $bytes): UuidInterface
     {
         if (strlen($bytes) !== 16) {
-            throw new InvalidArgumentException('$bytes string should contain 16 characters.');
+            throw new InvalidArgumentException(
+                '$bytes string should contain 16 characters.'
+            );
         }
 
-        $hex = unpack('H*', $bytes)[1];
+        // Rearrange the bytes to their original order.
+        $rearrangedBytes = $bytes[4] . $bytes[5] . $bytes[6] . $bytes[7]
+            . $bytes[2] . $bytes[3]
+            . $bytes[0] . $bytes[1]
+            . substr($bytes, 8);
+
+        $uuid = parent::decodeBytes($rearrangedBytes);
 
-        // Rearrange the fields to their original order
-        $hex = substr($hex, 8, 4) . substr($hex, 12, 4) . substr($hex, 4, 4) . substr($hex, 0, 4) . substr($hex, 16);
+        if (
+            !($uuid->getFields() instanceof Rfc4122FieldsInterface)
+            || $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME
+        ) {
+            throw new UnsupportedOperationException(
+                'Attempting to decode a non-time-based UUID using '
+                . 'OrderedTimeCodec'
+            );
+        }
 
-        return $this->decode($hex);
+        return $uuid;
     }
 }

+ 63 - 95
api/vendor/ramsey/uuid/src/Codec/StringCodec.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,23 +8,31 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Codec;
 
-use InvalidArgumentException;
 use Ramsey\Uuid\Builder\UuidBuilderInterface;
+use Ramsey\Uuid\Exception\InvalidArgumentException;
 use Ramsey\Uuid\Exception\InvalidUuidStringException;
+use Ramsey\Uuid\Rfc4122\FieldsInterface;
 use Ramsey\Uuid\Uuid;
 use Ramsey\Uuid\UuidInterface;
 
+use function hex2bin;
+use function implode;
+use function str_replace;
+use function strlen;
+use function substr;
+
 /**
  * StringCodec encodes and decodes RFC 4122 UUIDs
  *
  * @link http://tools.ietf.org/html/rfc4122
+ *
+ * @psalm-immutable
  */
 class StringCodec implements CodecInterface
 {
@@ -33,138 +42,97 @@ class StringCodec implements CodecInterface
     private $builder;
 
     /**
-     * Constructs a StringCodec for use encoding and decoding UUIDs
+     * Constructs a StringCodec
      *
-     * @param UuidBuilderInterface $builder The UUID builder to use when encoding UUIDs
+     * @param UuidBuilderInterface $builder The builder to use when encoding UUIDs
      */
     public function __construct(UuidBuilderInterface $builder)
     {
         $this->builder = $builder;
     }
 
-    /**
-     * Encodes a UuidInterface as a string representation of a UUID
-     *
-     * @param UuidInterface $uuid
-     * @return string Hexadecimal string representation of a UUID
-     */
-    public function encode(UuidInterface $uuid)
+    public function encode(UuidInterface $uuid): string
     {
-        $fields = array_values($uuid->getFieldsHex());
-
-        return vsprintf(
-            '%08s-%04s-%04s-%02s%02s-%012s',
-            $fields
-        );
+        /** @var FieldsInterface $fields */
+        $fields = $uuid->getFields();
+
+        return $fields->getTimeLow()->toString()
+            . '-'
+            . $fields->getTimeMid()->toString()
+            . '-'
+            . $fields->getTimeHiAndVersion()->toString()
+            . '-'
+            . $fields->getClockSeqHiAndReserved()->toString()
+            . $fields->getClockSeqLow()->toString()
+            . '-'
+            . $fields->getNode()->toString();
     }
 
     /**
-     * Encodes a UuidInterface as a binary representation of a UUID
-     *
-     * @param UuidInterface $uuid
-     * @return string Binary string representation of a UUID
+     * @psalm-return non-empty-string
+     * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
+     * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
      */
-    public function encodeBinary(UuidInterface $uuid)
+    public function encodeBinary(UuidInterface $uuid): string
     {
-        return hex2bin($uuid->getHex());
+        /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
+        return $uuid->getFields()->getBytes();
     }
 
     /**
-     * Decodes a string representation of a UUID into a UuidInterface object instance
-     *
-     * @param string $encodedUuid
-     * @return UuidInterface
      * @throws InvalidUuidStringException
+     *
+     * @inheritDoc
      */
-    public function decode($encodedUuid)
+    public function decode(string $encodedUuid): UuidInterface
     {
-        $components = $this->extractComponents($encodedUuid);
-        $fields = $this->getFields($components);
-
-        return $this->builder->build($this, $fields);
+        return $this->builder->build($this, $this->getBytes($encodedUuid));
     }
 
-    /**
-     * Decodes a binary representation of a UUID into a UuidInterface object instance
-     *
-     * @param string $bytes
-     * @return UuidInterface
-     * @throws InvalidArgumentException if string has not 16 characters
-     */
-    public function decodeBytes($bytes)
+    public function decodeBytes(string $bytes): UuidInterface
     {
         if (strlen($bytes) !== 16) {
-            throw new InvalidArgumentException('$bytes string should contain 16 characters.');
+            throw new InvalidArgumentException(
+                '$bytes string should contain 16 characters.'
+            );
         }
 
-        $hexUuid = unpack('H*', $bytes);
-
-        return $this->decode($hexUuid[1]);
+        return $this->builder->build($this, $bytes);
     }
 
     /**
      * Returns the UUID builder
-     *
-     * @return UuidBuilderInterface
      */
-    protected function getBuilder()
+    protected function getBuilder(): UuidBuilderInterface
     {
         return $this->builder;
     }
 
     /**
-     * Returns an array of UUID components (the UUID exploded on its dashes)
-     *
-     * @param string $encodedUuid
-     * @return array
-     * @throws InvalidUuidStringException
+     * Returns a byte string of the UUID
      */
-    protected function extractComponents($encodedUuid)
+    protected function getBytes(string $encodedUuid): string
     {
-        $nameParsed = str_replace([
-            'urn:',
-            'uuid:',
-            '{',
-            '}',
-            '-'
-        ], '', $encodedUuid);
-
-        // We have stripped out the dashes and are breaking up the string using
-        // substr(). In this way, we can accept a full hex value that doesn't
-        // contain dashes.
+        $parsedUuid = str_replace(
+            ['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}', '-'],
+            '',
+            $encodedUuid
+        );
+
         $components = [
-            substr($nameParsed, 0, 8),
-            substr($nameParsed, 8, 4),
-            substr($nameParsed, 12, 4),
-            substr($nameParsed, 16, 4),
-            substr($nameParsed, 20)
+            substr($parsedUuid, 0, 8),
+            substr($parsedUuid, 8, 4),
+            substr($parsedUuid, 12, 4),
+            substr($parsedUuid, 16, 4),
+            substr($parsedUuid, 20),
         ];
 
-        $nameParsed = implode('-', $components);
-
-        if (!Uuid::isValid($nameParsed)) {
-            throw new InvalidUuidStringException('Invalid UUID string: ' . $encodedUuid);
+        if (!Uuid::isValid(implode('-', $components))) {
+            throw new InvalidUuidStringException(
+                'Invalid UUID string: ' . $encodedUuid
+            );
         }
 
-        return $components;
-    }
-
-    /**
-     * Returns the fields that make up this UUID
-     *
-     * @see \Ramsey\Uuid\UuidInterface::getFieldsHex()
-     * @param array $components
-     * @return array
-     */
-    protected function getFields(array $components)
-    {
-        return [
-            'time_low' => str_pad($components[0], 8, '0', STR_PAD_LEFT),
-            'time_mid' => str_pad($components[1], 4, '0', STR_PAD_LEFT),
-            'time_hi_and_version' => str_pad($components[2], 4, '0', STR_PAD_LEFT),
-            'clock_seq_hi_and_reserved' => str_pad(substr($components[3], 0, 2), 2, '0', STR_PAD_LEFT),
-            'clock_seq_low' => str_pad(substr($components[3], 2), 2, '0', STR_PAD_LEFT),
-            'node' => str_pad($components[4], 12, '0', STR_PAD_LEFT)
-        ];
+        return (string) hex2bin($parsedUuid);
     }
 }

+ 66 - 61
api/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,102 +8,106 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
+
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Codec;
 
 use Ramsey\Uuid\Exception\InvalidUuidStringException;
 use Ramsey\Uuid\UuidInterface;
 
+use function bin2hex;
+use function sprintf;
+use function substr;
+use function substr_replace;
+
 /**
- * TimestampFirstCombCodec encodes and decodes COMB UUIDs which have the timestamp as the first 48 bits.
- * To be used with MySQL, PostgreSQL, Oracle.
+ * TimestampFirstCombCodec encodes and decodes COMBs, with the timestamp as the
+ * first 48 bits
+ *
+ * In contrast with the TimestampLastCombCodec, the TimestampFirstCombCodec
+ * adds the timestamp to the first 48 bits of the COMB. To generate a
+ * timestamp-first COMB, set the TimestampFirstCombCodec as the codec, along
+ * with the CombGenerator as the random generator.
+ *
+ * ``` php
+ * $factory = new UuidFactory();
+ *
+ * $factory->setCodec(new TimestampFirstCombCodec($factory->getUuidBuilder()));
+ *
+ * $factory->setRandomGenerator(new CombGenerator(
+ *     $factory->getRandomGenerator(),
+ *     $factory->getNumberConverter()
+ * ));
+ *
+ * $timestampFirstComb = $factory->uuid4();
+ * ```
+ *
+ * @link https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys
+ *
+ * @psalm-immutable
  */
 class TimestampFirstCombCodec extends StringCodec
 {
     /**
-     * Encodes a UuidInterface as a string representation of a timestamp first COMB UUID
-     *
-     * @param UuidInterface $uuid
-     *
-     * @return string Hexadecimal string representation of a GUID
+     * @psalm-return non-empty-string
+     * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
+     * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
      */
-    public function encode(UuidInterface $uuid)
+    public function encode(UuidInterface $uuid): string
     {
-        $sixPieceComponents = array_values($uuid->getFieldsHex());
-
-        $this->swapTimestampAndRandomBits($sixPieceComponents);
+        $bytes = $this->swapBytes($uuid->getFields()->getBytes());
 
-        return vsprintf(
-            '%08s-%04s-%04s-%02s%02s-%012s',
-            $sixPieceComponents
+        return sprintf(
+            '%08s-%04s-%04s-%04s-%012s',
+            bin2hex(substr($bytes, 0, 4)),
+            bin2hex(substr($bytes, 4, 2)),
+            bin2hex(substr($bytes, 6, 2)),
+            bin2hex(substr($bytes, 8, 2)),
+            bin2hex(substr($bytes, 10))
         );
     }
 
     /**
-     * Encodes a UuidInterface as a binary representation of timestamp first COMB UUID
-     *
-     * @param UuidInterface $uuid
-     *
-     * @return string Binary string representation of timestamp first COMB UUID
+     * @psalm-return non-empty-string
+     * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
+     * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
      */
-    public function encodeBinary(UuidInterface $uuid)
+    public function encodeBinary(UuidInterface $uuid): string
     {
-        $stringEncoding = $this->encode($uuid);
-
-        return hex2bin(str_replace('-', '', $stringEncoding));
+        /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
+        return $this->swapBytes($uuid->getFields()->getBytes());
     }
 
     /**
-     * Decodes a string representation of timestamp first COMB UUID into a UuidInterface object instance
-     *
-     * @param string $encodedUuid
-     *
-     * @return UuidInterface
      * @throws InvalidUuidStringException
+     *
+     * @inheritDoc
      */
-    public function decode($encodedUuid)
+    public function decode(string $encodedUuid): UuidInterface
     {
-        $fivePieceComponents = $this->extractComponents($encodedUuid);
-
-        $this->swapTimestampAndRandomBits($fivePieceComponents);
+        $bytes = $this->getBytes($encodedUuid);
 
-        return $this->getBuilder()->build($this, $this->getFields($fivePieceComponents));
+        return $this->getBuilder()->build($this, $this->swapBytes($bytes));
     }
 
-    /**
-     * Decodes a binary representation of timestamp first COMB UUID into a UuidInterface object instance
-     *
-     * @param string $bytes
-     *
-     * @return UuidInterface
-     * @throws InvalidUuidStringException
-     */
-    public function decodeBytes($bytes)
+    public function decodeBytes(string $bytes): UuidInterface
     {
-        return $this->decode(bin2hex($bytes));
+        return $this->getBuilder()->build($this, $this->swapBytes($bytes));
     }
 
     /**
-     * Swaps the first 48 bits with the last 48 bits
-     *
-     * @param array $components An array of UUID components (the UUID exploded on its dashes)
-     *
-     * @return void
+     * Swaps bytes according to the timestamp-first COMB rules
      */
-    protected function swapTimestampAndRandomBits(array &$components)
+    private function swapBytes(string $bytes): string
     {
-        $last48Bits = $components[4];
-        if (count($components) == 6) {
-            $last48Bits = $components[5];
-            $components[5] = $components[0] . $components[1];
-        } else {
-            $components[4] = $components[0] . $components[1];
-        }
+        $first48Bits = substr($bytes, 0, 6);
+        $last48Bits = substr($bytes, -6);
+
+        $bytes = substr_replace($bytes, $last48Bits, 0, 6);
+        $bytes = substr_replace($bytes, $first48Bits, -6);
 
-        $components[0] = substr($last48Bits, 0, 8);
-        $components[1] = substr($last48Bits, 8, 4);
+        return $bytes;
     }
 }

+ 34 - 5
api/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,15 +8,43 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
+
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Codec;
 
 /**
- * TimestampLastCombCodec encodes and decodes COMB UUIDs which have the timestamp as the last 48 bits.
- * To be used with MSSQL.
+ * TimestampLastCombCodec encodes and decodes COMBs, with the timestamp as the
+ * last 48 bits
+ *
+ * The CombGenerator when used with the StringCodec (and, by proxy, the
+ * TimestampLastCombCodec) adds the timestamp to the last 48 bits of the COMB.
+ * The TimestampLastCombCodec is provided for the sake of consistency. In
+ * practice, it is identical to the standard StringCodec but, it may be used
+ * with the CombGenerator for additional context when reading code.
+ *
+ * Consider the following code. By default, the codec used by UuidFactory is the
+ * StringCodec, but here, we explicitly set the TimestampLastCombCodec. It is
+ * redundant, but it is clear that we intend this COMB to be generated with the
+ * timestamp appearing at the end.
+ *
+ * ``` php
+ * $factory = new UuidFactory();
+ *
+ * $factory->setCodec(new TimestampLastCombCodec($factory->getUuidBuilder()));
+ *
+ * $factory->setRandomGenerator(new CombGenerator(
+ *     $factory->getRandomGenerator(),
+ *     $factory->getNumberConverter()
+ * ));
+ *
+ * $timestampLastComb = $factory->uuid4();
+ * ```
+ *
+ * @link https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys
+ *
+ * @psalm-immutable
  */
 class TimestampLastCombCodec extends StringCodec
 {

+ 27 - 24
api/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,48 +8,50 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Converter\Number;
 
-use Moontoast\Math\BigNumber;
 use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Math\BrickMathCalculator;
 
 /**
- * BigNumberConverter converts UUIDs from hexadecimal characters into
- * moontoast/math `BigNumber` representations of integers and vice versa
+ * Previously used to integrate moontoast/math as a bignum arithmetic library,
+ * BigNumberConverter is deprecated in favor of GenericNumberConverter
+ *
+ * @deprecated Transition to {@see GenericNumberConverter}.
+ *
+ * @psalm-immutable
  */
 class BigNumberConverter implements NumberConverterInterface
 {
     /**
-     * Converts a hexadecimal number into a `Moontoast\Math\BigNumber` representation
-     *
-     * @param string $hex The hexadecimal string representation to convert
-     * @return BigNumber
+     * @var NumberConverterInterface
      */
-    public function fromHex($hex)
-    {
-        $number = BigNumber::convertToBase10($hex, 16);
+    private $converter;
 
-        return new BigNumber($number);
+    public function __construct()
+    {
+        $this->converter = new GenericNumberConverter(new BrickMathCalculator());
     }
 
     /**
-     * Converts an integer or `Moontoast\Math\BigNumber` integer representation
-     * into a hexadecimal string representation
-     *
-     * @param int|string|BigNumber $integer An integer or `Moontoast\Math\BigNumber`
-     * @return string Hexadecimal string
+     * @inheritDoc
+     * @psalm-pure
      */
-    public function toHex($integer)
+    public function fromHex(string $hex): string
     {
-        if (!$integer instanceof BigNumber) {
-            $integer = new BigNumber($integer);
-        }
+        return $this->converter->fromHex($hex);
+    }
 
-        return BigNumber::convertFromBase10($integer, 16);
+    /**
+     * @inheritDoc
+     * @psalm-pure
+     */
+    public function toHex(string $number): string
+    {
+        return $this->converter->toHex($number);
     }
 }

+ 8 - 41
api/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,52 +8,18 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
-namespace Ramsey\Uuid\Converter\Number;
+declare(strict_types=1);
 
-use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
-use Ramsey\Uuid\Converter\NumberConverterInterface;
+namespace Ramsey\Uuid\Converter\Number;
 
 /**
- * DegradedNumberConverter throws `UnsatisfiedDependencyException` exceptions
- * if attempting to use number conversion functionality in an environment that
- * does not support large integers (i.e. when moontoast/math is not available)
+ * @deprecated DegradedNumberConverter is no longer necessary for converting
+ *     numbers on 32-bit systems. Transition to {@see GenericNumberConverter}.
+ *
+ * @psalm-immutable
  */
-class DegradedNumberConverter implements NumberConverterInterface
+class DegradedNumberConverter extends BigNumberConverter
 {
-    /**
-     * Throws an `UnsatisfiedDependencyException`
-     *
-     * @param string $hex The hexadecimal string representation to convert
-     * @return void
-     * @throws UnsatisfiedDependencyException
-     */
-    public function fromHex($hex)
-    {
-        throw new UnsatisfiedDependencyException(
-            'Cannot call ' . __METHOD__ . ' without support for large '
-            . 'integers, since integer is an unsigned '
-            . '128-bit integer; Moontoast\Math\BigNumber is required.'
-        );
-    }
-
-    /**
-     * Throws an `UnsatisfiedDependencyException`
-     *
-     * @param mixed $integer An integer representation to convert
-     * @return void
-     * @throws UnsatisfiedDependencyException
-     */
-    public function toHex($integer)
-    {
-        throw new UnsatisfiedDependencyException(
-            'Cannot call ' . __METHOD__ . ' without support for large '
-            . 'integers, since integer is an unsigned '
-            . '128-bit integer; Moontoast\Math\BigNumber is required. '
-        );
-    }
 }

+ 63 - 0
api/vendor/ramsey/uuid/src/Converter/Number/GenericNumberConverter.php

@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Converter\Number;
+
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Math\CalculatorInterface;
+use Ramsey\Uuid\Type\Integer as IntegerObject;
+
+/**
+ * GenericNumberConverter uses the provided calculator to convert decimal
+ * numbers to and from hexadecimal values
+ *
+ * @psalm-immutable
+ */
+class GenericNumberConverter implements NumberConverterInterface
+{
+    /**
+     * @var CalculatorInterface
+     */
+    private $calculator;
+
+    public function __construct(CalculatorInterface $calculator)
+    {
+        $this->calculator = $calculator;
+    }
+
+    /**
+     * @inheritDoc
+     * @psalm-pure
+     * @psalm-return numeric-string
+     * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
+     * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
+     */
+    public function fromHex(string $hex): string
+    {
+        return $this->calculator->fromBase($hex, 16)->toString();
+    }
+
+    /**
+     * @inheritDoc
+     * @psalm-pure
+     * @psalm-return non-empty-string
+     * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
+     * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
+     */
+    public function toHex(string $number): string
+    {
+        /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
+        return $this->calculator->toBase(new IntegerObject($number), 16);
+    }
+}

+ 28 - 19
api/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,42 +8,50 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
-namespace Ramsey\Uuid\Converter;
+declare(strict_types=1);
 
-use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+namespace Ramsey\Uuid\Converter;
 
 /**
- * NumberConverterInterface converts UUIDs from hexadecimal characters into
+ * A number converter converts UUIDs from hexadecimal characters into
  * representations of integers and vice versa
+ *
+ * @psalm-immutable
  */
 interface NumberConverterInterface
 {
     /**
-     * Converts a hexadecimal number into an integer representation of the number
+     * Converts a hexadecimal number into an string integer representation of
+     * the number
      *
-     * The integer representation returned may be an object or a string
-     * representation of the integer, depending on the implementation.
+     * The integer representation returned is a string representation of the
+     * integer, to accommodate unsigned integers greater than PHP_INT_MAX.
      *
      * @param string $hex The hexadecimal string representation to convert
-     * @return mixed
-     * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+     *
+     * @return string String representation of an integer
+     *
+     * @psalm-return numeric-string
+     *
+     * @psalm-pure
      */
-    public function fromHex($hex);
+    public function fromHex(string $hex): string;
 
     /**
-     * Converts an integer representation into a hexadecimal string representation
-     * of the number
+     * Converts a string integer representation into a hexadecimal string
+     * representation of the number
+     *
+     * @param string $number A string integer representation to convert; this
+     *     must be a numeric string to accommodate unsigned integers greater
+     *     than PHP_INT_MAX.
      *
-     * @param mixed $integer An integer representation to convert; this may be
-     *     a true integer, a string integer, or a object representation that
-     *     this converter can understand
      * @return string Hexadecimal string
-     * @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
+     *
+     * @psalm-return non-empty-string
+     *
+     * @psalm-pure
      */
-    public function toHex($integer);
+    public function toHex(string $number): string;
 }

+ 25 - 33
api/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,53 +8,44 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Converter\Time;
 
-use Moontoast\Math\BigNumber;
 use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Math\BrickMathCalculator;
+use Ramsey\Uuid\Type\Hexadecimal;
+use Ramsey\Uuid\Type\Time;
 
 /**
- * BigNumberTimeConverter uses the moontoast/math library's `BigNumber` to
- * provide facilities for converting parts of time into representations that may
- * be used in UUIDs
+ * Previously used to integrate moontoast/math as a bignum arithmetic library,
+ * BigNumberTimeConverter is deprecated in favor of GenericTimeConverter
+ *
+ * @deprecated Transition to {@see GenericTimeConverter}.
+ *
+ * @psalm-immutable
  */
 class BigNumberTimeConverter implements TimeConverterInterface
 {
     /**
-     * Uses the provided seconds and micro-seconds to calculate the time_low,
-     * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
-     *
-     * @param string $seconds
-     * @param string $microSeconds
-     * @return string[] An array containing `low`, `mid`, and `high` keys
-     * @link http://tools.ietf.org/html/rfc4122#section-4.2.2
+     * @var TimeConverterInterface
      */
-    public function calculateTime($seconds, $microSeconds)
-    {
-        $uuidTime = new BigNumber('0');
-
-        $sec = new BigNumber($seconds);
-        $sec->multiply('10000000');
+    private $converter;
 
-        $usec = new BigNumber($microSeconds);
-        $usec->multiply('10');
-
-        $uuidTime
-            ->add($sec)
-            ->add($usec)
-            ->add('122192928000000000');
+    public function __construct()
+    {
+        $this->converter = new GenericTimeConverter(new BrickMathCalculator());
+    }
 
-        $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16));
+    public function calculateTime(string $seconds, string $microseconds): Hexadecimal
+    {
+        return $this->converter->calculateTime($seconds, $microseconds);
+    }
 
-        return [
-            'low' => substr($uuidTimeHex, 8),
-            'mid' => substr($uuidTimeHex, 4, 4),
-            'hi' => substr($uuidTimeHex, 0, 4),
-        ];
+    public function convertTime(Hexadecimal $uuidTimestamp): Time
+    {
+        return $this->converter->convertTime($uuidTimestamp);
     }
 }

+ 8 - 25
api/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,36 +8,18 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
-namespace Ramsey\Uuid\Converter\Time;
+declare(strict_types=1);
 
-use Ramsey\Uuid\Converter\TimeConverterInterface;
-use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+namespace Ramsey\Uuid\Converter\Time;
 
 /**
- * DegradedTimeConverter throws `UnsatisfiedDependencyException` exceptions
- * if attempting to use time conversion functionality in an environment that
- * does not support large integers (i.e. when moontoast/math is not available)
+ * @deprecated DegradedTimeConverter is no longer necessary for converting
+ *     time on 32-bit systems. Transition to {@see GenericTimeConverter}.
+ *
+ * @psalm-immutable
  */
-class DegradedTimeConverter implements TimeConverterInterface
+class DegradedTimeConverter extends BigNumberTimeConverter
 {
-    /**
-     * Throws an `UnsatisfiedDependencyException`
-     *
-     * @param string $seconds
-     * @param string $microSeconds
-     * @return void
-     * @throws UnsatisfiedDependencyException if called on a 32-bit system and `Moontoast\Math\BigNumber` is not present
-     */
-    public function calculateTime($seconds, $microSeconds)
-    {
-        throw new UnsatisfiedDependencyException(
-            'When calling ' . __METHOD__ . ' on a 32-bit system, '
-            . 'Moontoast\Math\BigNumber must be present.'
-        );
-    }
 }

+ 124 - 0
api/vendor/ramsey/uuid/src/Converter/Time/GenericTimeConverter.php

@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Converter\Time;
+
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Math\CalculatorInterface;
+use Ramsey\Uuid\Math\RoundingMode;
+use Ramsey\Uuid\Type\Hexadecimal;
+use Ramsey\Uuid\Type\Integer as IntegerObject;
+use Ramsey\Uuid\Type\Time;
+
+use function explode;
+use function str_pad;
+
+use const STR_PAD_LEFT;
+
+/**
+ * GenericTimeConverter uses the provided calculator to calculate and convert
+ * time values
+ *
+ * @psalm-immutable
+ */
+class GenericTimeConverter implements TimeConverterInterface
+{
+    /**
+     * The number of 100-nanosecond intervals from the Gregorian calendar epoch
+     * to the Unix epoch.
+     */
+    private const GREGORIAN_TO_UNIX_INTERVALS = '122192928000000000';
+
+    /**
+     * The number of 100-nanosecond intervals in one second.
+     */
+    private const SECOND_INTERVALS = '10000000';
+
+    /**
+     * The number of 100-nanosecond intervals in one microsecond.
+     */
+    private const MICROSECOND_INTERVALS = '10';
+
+    /**
+     * @var CalculatorInterface
+     */
+    private $calculator;
+
+    public function __construct(CalculatorInterface $calculator)
+    {
+        $this->calculator = $calculator;
+    }
+
+    public function calculateTime(string $seconds, string $microseconds): Hexadecimal
+    {
+        $timestamp = new Time($seconds, $microseconds);
+
+        // Convert the seconds into a count of 100-nanosecond intervals.
+        $sec = $this->calculator->multiply(
+            $timestamp->getSeconds(),
+            new IntegerObject(self::SECOND_INTERVALS)
+        );
+
+        // Convert the microseconds into a count of 100-nanosecond intervals.
+        $usec = $this->calculator->multiply(
+            $timestamp->getMicroseconds(),
+            new IntegerObject(self::MICROSECOND_INTERVALS)
+        );
+
+        // Combine the seconds and microseconds intervals and add the count of
+        // 100-nanosecond intervals from the Gregorian calendar epoch to the
+        // Unix epoch. This gives us the correct count of 100-nanosecond
+        // intervals since the Gregorian calendar epoch for the given seconds
+        // and microseconds.
+        /** @var IntegerObject $uuidTime */
+        $uuidTime = $this->calculator->add(
+            $sec,
+            $usec,
+            new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS)
+        );
+
+        $uuidTimeHex = str_pad(
+            $this->calculator->toHexadecimal($uuidTime)->toString(),
+            16,
+            '0',
+            STR_PAD_LEFT
+        );
+
+        return new Hexadecimal($uuidTimeHex);
+    }
+
+    public function convertTime(Hexadecimal $uuidTimestamp): Time
+    {
+        // From the total, subtract the number of 100-nanosecond intervals from
+        // the Gregorian calendar epoch to the Unix epoch. This gives us the
+        // number of 100-nanosecond intervals from the Unix epoch, which also
+        // includes the microtime.
+        $epochNanoseconds = $this->calculator->subtract(
+            $this->calculator->toInteger($uuidTimestamp),
+            new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS)
+        );
+
+        // Convert the 100-nanosecond intervals into seconds and microseconds.
+        $unixTimestamp = $this->calculator->divide(
+            RoundingMode::HALF_UP,
+            6,
+            $epochNanoseconds,
+            new IntegerObject(self::SECOND_INTERVALS)
+        );
+
+        $split = explode('.', (string) $unixTimestamp, 2);
+
+        return new Time($split[0], $split[1] ?? 0);
+    }
+}

+ 152 - 16
api/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,41 +8,176 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Converter\Time;
 
 use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Math\BrickMathCalculator;
+use Ramsey\Uuid\Math\CalculatorInterface;
+use Ramsey\Uuid\Type\Hexadecimal;
+use Ramsey\Uuid\Type\Integer as IntegerObject;
+use Ramsey\Uuid\Type\Time;
+
+use function count;
+use function dechex;
+use function explode;
+use function is_float;
+use function is_int;
+use function str_pad;
+use function strlen;
+use function substr;
+
+use const STR_PAD_LEFT;
+use const STR_PAD_RIGHT;
 
 /**
  * PhpTimeConverter uses built-in PHP functions and standard math operations
  * available to the PHP programming language to provide facilities for
  * converting parts of time into representations that may be used in UUIDs
+ *
+ * @psalm-immutable
  */
 class PhpTimeConverter implements TimeConverterInterface
 {
     /**
-     * Uses the provided seconds and micro-seconds to calculate the time_low,
-     * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
+     * The number of 100-nanosecond intervals from the Gregorian calendar epoch
+     * to the Unix epoch.
+     */
+    private const GREGORIAN_TO_UNIX_INTERVALS = 0x01b21dd213814000;
+
+    /**
+     * The number of 100-nanosecond intervals in one second.
+     */
+    private const SECOND_INTERVALS = 10000000;
+
+    /**
+     * The number of 100-nanosecond intervals in one microsecond.
+     */
+    private const MICROSECOND_INTERVALS = 10;
+
+    /**
+     * @var CalculatorInterface
+     */
+    private $calculator;
+
+    /**
+     * @var TimeConverterInterface
+     */
+    private $fallbackConverter;
+
+    /**
+     * @var int
+     */
+    private $phpPrecision;
+
+    public function __construct(
+        ?CalculatorInterface $calculator = null,
+        ?TimeConverterInterface $fallbackConverter = null
+    ) {
+        if ($calculator === null) {
+            $calculator = new BrickMathCalculator();
+        }
+
+        if ($fallbackConverter === null) {
+            $fallbackConverter = new GenericTimeConverter($calculator);
+        }
+
+        $this->calculator = $calculator;
+        $this->fallbackConverter = $fallbackConverter;
+        $this->phpPrecision = (int) ini_get('precision');
+    }
+
+    public function calculateTime(string $seconds, string $microseconds): Hexadecimal
+    {
+        $seconds = new IntegerObject($seconds);
+        $microseconds = new IntegerObject($microseconds);
+
+        // Calculate the count of 100-nanosecond intervals since the Gregorian
+        // calendar epoch for the given seconds and microseconds.
+        $uuidTime = ((int) $seconds->toString() * self::SECOND_INTERVALS)
+            + ((int) $microseconds->toString() * self::MICROSECOND_INTERVALS)
+            + self::GREGORIAN_TO_UNIX_INTERVALS;
+
+        // Check to see whether we've overflowed the max/min integer size.
+        // If so, we will default to a different time converter.
+        /** @psalm-suppress RedundantCondition */
+        if (!is_int($uuidTime)) {
+            return $this->fallbackConverter->calculateTime(
+                $seconds->toString(),
+                $microseconds->toString()
+            );
+        }
+
+        return new Hexadecimal(str_pad(dechex($uuidTime), 16, '0', STR_PAD_LEFT));
+    }
+
+    public function convertTime(Hexadecimal $uuidTimestamp): Time
+    {
+        $timestamp = $this->calculator->toInteger($uuidTimestamp);
+
+        // Convert the 100-nanosecond intervals into seconds and microseconds.
+        $splitTime = $this->splitTime(
+            ((int) $timestamp->toString() - self::GREGORIAN_TO_UNIX_INTERVALS)
+            / self::SECOND_INTERVALS
+        );
+
+        if (count($splitTime) === 0) {
+            return $this->fallbackConverter->convertTime($uuidTimestamp);
+        }
+
+        return new Time($splitTime['sec'], $splitTime['usec']);
+    }
+
+    /**
+     * @param int|float $time The time to split into seconds and microseconds
      *
-     * @param string $seconds
-     * @param string $microSeconds
-     * @return string[] An array containing `low`, `mid`, and `high` keys
-     * @link http://tools.ietf.org/html/rfc4122#section-4.2.2
+     * @return string[]
      */
-    public function calculateTime($seconds, $microSeconds)
+    private function splitTime($time): array
     {
-        // 0x01b21dd213814000 is the number of 100-ns intervals between the
-        // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
-        $uuidTime = ($seconds * 10000000) + ($microSeconds * 10) + 0x01b21dd213814000;
+        $split = explode('.', (string) $time, 2);
+
+        // If the $time value is a float but $split only has 1 element, then the
+        // float math was rounded up to the next second, so we want to return
+        // an empty array to allow use of the fallback converter.
+        if (is_float($time) && count($split) === 1) {
+            return [];
+        }
+
+        if (count($split) === 1) {
+            return [
+                'sec' => $split[0],
+                'usec' => '0',
+            ];
+        }
+
+        // If the microseconds are less than six characters AND the length of
+        // the number is greater than or equal to the PHP precision, then it's
+        // possible that we lost some precision for the microseconds. Return an
+        // empty array, so that we can choose to use the fallback converter.
+        if (strlen($split[1]) < 6 && strlen((string) $time) >= $this->phpPrecision) {
+            return [];
+        }
+
+        $microseconds = $split[1];
+
+        // Ensure the microseconds are no longer than 6 digits. If they are,
+        // truncate the number to the first 6 digits and round up, if needed.
+        if (strlen($microseconds) > 6) {
+            $roundingDigit = (int) substr($microseconds, 6, 1);
+            $microseconds = (int) substr($microseconds, 0, 6);
+
+            if ($roundingDigit >= 5) {
+                $microseconds++;
+            }
+        }
 
         return [
-            'low' => sprintf('%08x', $uuidTime & 0xffffffff),
-            'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff),
-            'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff),
+            'sec' => $split[0],
+            'usec' => str_pad((string) $microseconds, 6, '0', STR_PAD_RIGHT),
         ];
     }
 }

+ 36 - 15
api/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,31 +8,51 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
+declare(strict_types=1);
+
 namespace Ramsey\Uuid\Converter;
 
-use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use Ramsey\Uuid\Type\Hexadecimal;
+use Ramsey\Uuid\Type\Time;
 
 /**
- * TimeConverterInterface provides facilities for converting parts of time into
- * representations that may be used in UUIDs
+ * A time converter converts timestamps into representations that may be used
+ * in UUIDs
+ *
+ * @psalm-immutable
  */
 interface TimeConverterInterface
 {
     /**
-     * Uses the provided seconds and micro-seconds to calculate the time_low,
-     * time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
+     * Uses the provided seconds and micro-seconds to calculate the count of
+     * 100-nanosecond intervals since UTC 00:00:00.00, 15 October 1582, for
+     * RFC 4122 variant UUIDs
+     *
+     * @link http://tools.ietf.org/html/rfc4122#section-4.2.2 RFC 4122, § 4.2.2: Generation Details
+     *
+     * @param string $seconds A string representation of the number of seconds
+     *     since the Unix epoch for the time to calculate
+     * @param string $microseconds A string representation of the micro-seconds
+     *     associated with the time to calculate
+     *
+     * @return Hexadecimal The full UUID timestamp as a Hexadecimal value
+     *
+     * @psalm-pure
+     */
+    public function calculateTime(string $seconds, string $microseconds): Hexadecimal;
+
+    /**
+     * Converts a timestamp extracted from a UUID to a Unix timestamp
+     *
+     * @param Hexadecimal $uuidTimestamp A hexadecimal representation of a UUID
+     *     timestamp; a UUID timestamp is a count of 100-nanosecond intervals
+     *     since UTC 00:00:00.00, 15 October 1582.
+     *
+     * @return Time An instance of {@see Time}
      *
-     * @param string $seconds
-     * @param string $microSeconds
-     * @return string[] An array guaranteed to contain `low`, `mid`, and `hi` keys
-     * @throws UnsatisfiedDependencyException if called on a 32-bit system and
-     *     `Moontoast\Math\BigNumber` is not present
-     * @link http://tools.ietf.org/html/rfc4122#section-4.2.2
+     * @psalm-pure
      */
-    public function calculateTime($seconds, $microSeconds);
+    public function convertTime(Hexadecimal $uuidTimestamp): Time;
 }

+ 6 - 97
api/vendor/ramsey/uuid/src/DegradedUuid.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,110 +8,18 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
-namespace Ramsey\Uuid;
+declare(strict_types=1);
 
-use DateTime;
-use Moontoast\Math\BigNumber;
-use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
-use Ramsey\Uuid\Exception\UnsupportedOperationException;
+namespace Ramsey\Uuid;
 
 /**
- * DegradedUuid represents an RFC 4122 UUID on 32-bit systems
+ * @deprecated DegradedUuid is no longer necessary to represent UUIDs on 32-bit
+ *     systems. Transition typehints to {@see UuidInterface}.
  *
- * @see Uuid
+ * @psalm-immutable
  */
 class DegradedUuid extends Uuid
 {
-    /**
-     * @inheritdoc
-     */
-    public function getDateTime()
-    {
-        if ($this->getVersion() != 1) {
-            throw new UnsupportedOperationException('Not a time-based UUID');
-        }
-
-        $time = $this->converter->fromHex($this->getTimestampHex());
-
-        $ts = new BigNumber($time, 20);
-        $ts->subtract('122192928000000000');
-        $ts->divide('10000000.0');
-        $ts->floor();
-        $unixTime = $ts->getValue();
-
-        return new DateTime("@{$unixTime}");
-    }
-
-    /**
-     * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
-     * called on a 32-bit system
-     *
-     * @throws UnsatisfiedDependencyException if called on a 32-bit system
-     */
-    public function getFields()
-    {
-        throw new UnsatisfiedDependencyException(
-            'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some '
-            . 'values overflow the system max integer value'
-            . '; consider calling getFieldsHex instead'
-        );
-    }
-
-    /**
-     * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
-     * called on a 32-bit system
-     *
-     * @throws UnsatisfiedDependencyException if called on a 32-bit system
-     */
-    public function getNode()
-    {
-        throw new UnsatisfiedDependencyException(
-            'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node '
-            . 'is an unsigned 48-bit integer and can overflow the system '
-            . 'max integer value'
-            . '; consider calling getNodeHex instead'
-        );
-    }
-
-    /**
-     * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
-     * called on a 32-bit system
-     *
-     * @throws UnsatisfiedDependencyException if called on a 32-bit system
-     */
-    public function getTimeLow()
-    {
-        throw new UnsatisfiedDependencyException(
-            'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low '
-            . 'is an unsigned 32-bit integer and can overflow the system '
-            . 'max integer value'
-            . '; consider calling getTimeLowHex instead'
-        );
-    }
-
-    /**
-     * For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
-     * called on a 32-bit system
-     *
-     * @throws UnsatisfiedDependencyException if called on a 32-bit system
-     * @throws UnsupportedOperationException If this UUID is not a version 1 UUID
-     */
-    public function getTimestamp()
-    {
-        if ($this->getVersion() != 1) {
-            throw new UnsupportedOperationException('Not a time-based UUID');
-        }
-
-        throw new UnsatisfiedDependencyException(
-            'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp '
-            . 'is an unsigned 60-bit integer and can overflow the system '
-            . 'max integer value'
-            . '; consider calling getTimestampHex instead'
-        );
-    }
 }

+ 147 - 0
api/vendor/ramsey/uuid/src/DeprecatedUuidInterface.php

@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid;
+
+use DateTimeInterface;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+
+/**
+ * This interface encapsulates deprecated methods for ramsey/uuid; this
+ * interface and its methods will be removed in ramsey/uuid 5.0.0.
+ *
+ * @psalm-immutable
+ */
+interface DeprecatedUuidInterface
+{
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no alternative
+     *     recommendation, so plan accordingly.
+     */
+    public function getNumberConverter(): NumberConverterInterface;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance.
+     *
+     * @return string[]
+     */
+    public function getFieldsHex(): array;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getClockSeqHiAndReserved()}.
+     */
+    public function getClockSeqHiAndReservedHex(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getClockSeqLow()}.
+     */
+    public function getClockSeqLowHex(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getClockSeq()}.
+     */
+    public function getClockSequenceHex(): string;
+
+    /**
+     * @deprecated In ramsey/uuid version 5.0.0, this will be removed from the
+     *     interface. It is available at {@see UuidV1::getDateTime()}.
+     */
+    public function getDateTime(): DateTimeInterface;
+
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no direct
+     *     alternative, but the same information may be obtained by splitting
+     *     in half the value returned by {@see UuidInterface::getHex()}.
+     */
+    public function getLeastSignificantBitsHex(): string;
+
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no direct
+     *     alternative, but the same information may be obtained by splitting
+     *     in half the value returned by {@see UuidInterface::getHex()}.
+     */
+    public function getMostSignificantBitsHex(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getNode()}.
+     */
+    public function getNodeHex(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimeHiAndVersion()}.
+     */
+    public function getTimeHiAndVersionHex(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimeLow()}.
+     */
+    public function getTimeLowHex(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimeMid()}.
+     */
+    public function getTimeMidHex(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimestamp()}.
+     */
+    public function getTimestampHex(): string;
+
+    /**
+     * @deprecated In ramsey/uuid version 5.0.0, this will be removed from this
+     *     interface. It has moved to {@see \Ramsey\Uuid\Rfc4122\UuidInterface::getUrn()}.
+     */
+    public function getUrn(): string;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVariant()}.
+     */
+    public function getVariant(): ?int;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVersion()}.
+     */
+    public function getVersion(): ?int;
+}

+ 370 - 0
api/vendor/ramsey/uuid/src/DeprecatedUuidMethodsTrait.php

@@ -0,0 +1,370 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid;
+
+use DateTimeImmutable;
+use DateTimeInterface;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Exception\DateTimeException;
+use Ramsey\Uuid\Exception\UnsupportedOperationException;
+use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
+use Throwable;
+
+use function str_pad;
+use function substr;
+
+use const STR_PAD_LEFT;
+
+/**
+ * This trait encapsulates deprecated methods for ramsey/uuid; this trait and
+ * its methods will be removed in ramsey/uuid 5.0.0.
+ *
+ * @psalm-immutable
+ */
+trait DeprecatedUuidMethodsTrait
+{
+    /**
+     * @var Rfc4122FieldsInterface
+     */
+    protected $fields;
+
+    /**
+     * @var NumberConverterInterface
+     */
+    protected $numberConverter;
+
+    /**
+     * @var TimeConverterInterface
+     */
+    protected $timeConverter;
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeqHiAndReserved()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getClockSeqHiAndReserved(): string
+    {
+        return $this->numberConverter->fromHex($this->fields->getClockSeqHiAndReserved()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeqHiAndReserved()}.
+     */
+    public function getClockSeqHiAndReservedHex(): string
+    {
+        return $this->fields->getClockSeqHiAndReserved()->toString();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeqLow()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getClockSeqLow(): string
+    {
+        return $this->numberConverter->fromHex($this->fields->getClockSeqLow()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeqLow()}.
+     */
+    public function getClockSeqLowHex(): string
+    {
+        return $this->fields->getClockSeqLow()->toString();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeq()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getClockSequence(): string
+    {
+        return $this->numberConverter->fromHex($this->fields->getClockSeq()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeq()}.
+     */
+    public function getClockSequenceHex(): string
+    {
+        return $this->fields->getClockSeq()->toString();
+    }
+
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no alternative
+     *     recommendation, so plan accordingly.
+     */
+    public function getNumberConverter(): NumberConverterInterface
+    {
+        return $this->numberConverter;
+    }
+
+    /**
+     * @deprecated In ramsey/uuid version 5.0.0, this will be removed.
+     *     It is available at {@see UuidV1::getDateTime()}.
+     *
+     * @return DateTimeImmutable An immutable instance of DateTimeInterface
+     *
+     * @throws UnsupportedOperationException if UUID is not time-based
+     * @throws DateTimeException if DateTime throws an exception/error
+     */
+    public function getDateTime(): DateTimeInterface
+    {
+        if ($this->fields->getVersion() !== 1) {
+            throw new UnsupportedOperationException('Not a time-based UUID');
+        }
+
+        $time = $this->timeConverter->convertTime($this->fields->getTimestamp());
+
+        try {
+            return new DateTimeImmutable(
+                '@'
+                . $time->getSeconds()->toString()
+                . '.'
+                . str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
+            );
+        } catch (Throwable $e) {
+            throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
+        }
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance.
+     *
+     * @return string[]
+     */
+    public function getFieldsHex(): array
+    {
+        return [
+            'time_low' => $this->fields->getTimeLow()->toString(),
+            'time_mid' => $this->fields->getTimeMid()->toString(),
+            'time_hi_and_version' => $this->fields->getTimeHiAndVersion()->toString(),
+            'clock_seq_hi_and_reserved' => $this->fields->getClockSeqHiAndReserved()->toString(),
+            'clock_seq_low' => $this->fields->getClockSeqLow()->toString(),
+            'node' => $this->fields->getNode()->toString(),
+        ];
+    }
+
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no direct
+     *     alternative, but the same information may be obtained by splitting
+     *     in half the value returned by {@see UuidInterface::getHex()}.
+     */
+    public function getLeastSignificantBits(): string
+    {
+        $leastSignificantHex = substr($this->getHex()->toString(), 16);
+
+        return $this->numberConverter->fromHex($leastSignificantHex);
+    }
+
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no direct
+     *     alternative, but the same information may be obtained by splitting
+     *     in half the value returned by {@see UuidInterface::getHex()}.
+     */
+    public function getLeastSignificantBitsHex(): string
+    {
+        return substr($this->getHex()->toString(), 16);
+    }
+
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no direct
+     *     alternative, but the same information may be obtained by splitting
+     *     in half the value returned by {@see UuidInterface::getHex()}.
+     */
+    public function getMostSignificantBits(): string
+    {
+        $mostSignificantHex = substr($this->getHex()->toString(), 0, 16);
+
+        return $this->numberConverter->fromHex($mostSignificantHex);
+    }
+
+    /**
+     * @deprecated This method will be removed in 5.0.0. There is no direct
+     *     alternative, but the same information may be obtained by splitting
+     *     in half the value returned by {@see UuidInterface::getHex()}.
+     */
+    public function getMostSignificantBitsHex(): string
+    {
+        return substr($this->getHex()->toString(), 0, 16);
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getNode()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getNode(): string
+    {
+        return $this->numberConverter->fromHex($this->fields->getNode()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getNode()}.
+     */
+    public function getNodeHex(): string
+    {
+        return $this->fields->getNode()->toString();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeHiAndVersion()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getTimeHiAndVersion(): string
+    {
+        return $this->numberConverter->fromHex($this->fields->getTimeHiAndVersion()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeHiAndVersion()}.
+     */
+    public function getTimeHiAndVersionHex(): string
+    {
+        return $this->fields->getTimeHiAndVersion()->toString();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeLow()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getTimeLow(): string
+    {
+        return $this->numberConverter->fromHex($this->fields->getTimeLow()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeLow()}.
+     */
+    public function getTimeLowHex(): string
+    {
+        return $this->fields->getTimeLow()->toString();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeMid()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getTimeMid(): string
+    {
+        return $this->numberConverter->fromHex($this->fields->getTimeMid()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeMid()}.
+     */
+    public function getTimeMidHex(): string
+    {
+        return $this->fields->getTimeMid()->toString();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimestamp()}
+     *     and use the arbitrary-precision math library of your choice to
+     *     convert it to a string integer.
+     */
+    public function getTimestamp(): string
+    {
+        if ($this->fields->getVersion() !== 1) {
+            throw new UnsupportedOperationException('Not a time-based UUID');
+        }
+
+        return $this->numberConverter->fromHex($this->fields->getTimestamp()->toString());
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
+     *     instance, you may call {@see Rfc4122FieldsInterface::getTimestamp()}.
+     */
+    public function getTimestampHex(): string
+    {
+        if ($this->fields->getVersion() !== 1) {
+            throw new UnsupportedOperationException('Not a time-based UUID');
+        }
+
+        return $this->fields->getTimestamp()->toString();
+    }
+
+    /**
+     * @deprecated This has moved to {@see Rfc4122FieldsInterface::getUrn()} and
+     *     is available on {@see \Ramsey\Uuid\Rfc4122\UuidV1},
+     *     {@see \Ramsey\Uuid\Rfc4122\UuidV3}, {@see \Ramsey\Uuid\Rfc4122\UuidV4},
+     *     and {@see \Ramsey\Uuid\Rfc4122\UuidV5}.
+     */
+    public function getUrn(): string
+    {
+        return 'urn:uuid:' . $this->toString();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVariant()}.
+     */
+    public function getVariant(): ?int
+    {
+        return $this->fields->getVariant();
+    }
+
+    /**
+     * @deprecated Use {@see UuidInterface::getFields()} to get a
+     *     {@see FieldsInterface} instance. If it is a
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
+     *     {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVersion()}.
+     */
+    public function getVersion(): ?int
+    {
+        return $this->fields->getVersion();
+    }
+}

+ 24 - 0
api/vendor/ramsey/uuid/src/Exception/BuilderNotFoundException.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate that no suitable builder could be found
+ */
+class BuilderNotFoundException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 24 - 0
api/vendor/ramsey/uuid/src/Exception/DateTimeException.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate that the PHP DateTime extension encountered an exception/error
+ */
+class DateTimeException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 25 - 0
api/vendor/ramsey/uuid/src/Exception/DceSecurityException.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate an exception occurred while dealing with DCE Security
+ * (version 2) UUIDs
+ */
+class DceSecurityException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 24 - 0
api/vendor/ramsey/uuid/src/Exception/InvalidArgumentException.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use InvalidArgumentException as PhpInvalidArgumentException;
+
+/**
+ * Thrown to indicate that the argument received is not valid
+ */
+class InvalidArgumentException extends PhpInvalidArgumentException implements UuidExceptionInterface
+{
+}

+ 24 - 0
api/vendor/ramsey/uuid/src/Exception/InvalidBytesException.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate that the bytes being operated on are invalid in some way
+ */
+class InvalidBytesException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 8 - 7
api/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php

@@ -1,4 +1,5 @@
 <?php
+
 /**
  * This file is part of the ramsey/uuid library
  *
@@ -7,18 +8,18 @@
  *
  * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
  * @license http://opensource.org/licenses/MIT MIT
- * @link https://benramsey.com/projects/ramsey-uuid/ Documentation
- * @link https://packagist.org/packages/ramsey/uuid Packagist
- * @link https://github.com/ramsey/uuid GitHub
  */
 
-namespace Ramsey\Uuid\Exception;
+declare(strict_types=1);
 
-use InvalidArgumentException;
+namespace Ramsey\Uuid\Exception;
 
 /**
- * Thrown to indicate that the parsed UUID string is invalid.
+ * Thrown to indicate that the string received is not a valid UUID
+ *
+ * The InvalidArgumentException that this extends is the ramsey/uuid version
+ * of this exception. It exists in the same namespace as this class.
  */
-class InvalidUuidStringException extends InvalidArgumentException
+class InvalidUuidStringException extends InvalidArgumentException implements UuidExceptionInterface
 {
 }

+ 25 - 0
api/vendor/ramsey/uuid/src/Exception/NameException.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate that an error occurred while attempting to hash a
+ * namespace and name
+ */
+class NameException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 24 - 0
api/vendor/ramsey/uuid/src/Exception/NodeException.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate that attempting to fetch or create a node ID encountered an error
+ */
+class NodeException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 27 - 0
api/vendor/ramsey/uuid/src/Exception/RandomSourceException.php

@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate that the source of random data encountered an error
+ *
+ * This exception is used mostly to indicate that random_bytes() or random_int()
+ * threw an exception. However, it may be used for other sources of random data.
+ */
+class RandomSourceException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 24 - 0
api/vendor/ramsey/uuid/src/Exception/TimeSourceException.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate that the source of time encountered an error
+ */
+class TimeSourceException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

+ 24 - 0
api/vendor/ramsey/uuid/src/Exception/UnableToBuildUuidException.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * This file is part of the ramsey/uuid library
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Exception;
+
+use RuntimeException as PhpRuntimeException;
+
+/**
+ * Thrown to indicate a builder is unable to build a UUID
+ */
+class UnableToBuildUuidException extends PhpRuntimeException implements UuidExceptionInterface
+{
+}

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