diff --git a/pandora_console/api/v1/config/routes.php b/pandora_console/api/v1/config/routes.php index aa77df22c3..c36454d725 100644 --- a/pandora_console/api/v1/config/routes.php +++ b/pandora_console/api/v1/config/routes.php @@ -3,6 +3,7 @@ use Slim\App; return function (App $app) { + (include __DIR__.'/../../../include/lib/Modules/Authentication/routes.php')($app); (include __DIR__.'/../../../include/lib/Modules/Events/routes.php')($app); (include __DIR__.'/../../../include/lib/Modules/Groups/routes.php')($app); (include __DIR__.'/../../../include/lib/Modules/Profiles/routes.php')($app); diff --git a/pandora_console/api/v1/public/swagger.json b/pandora_console/api/v1/public/swagger.json index 4a9b5a7317..94679c3584 100644 --- a/pandora_console/api/v1/public/swagger.json +++ b/pandora_console/api/v1/public/swagger.json @@ -22,6 +22,250 @@ } ], "paths": { + "/token": { + "post": { + "tags": ["Authentication"], + "summary": "Creates a new tokens", + "operationId": "d96770381612b0ea2a16df79ab9f78fe", + "requestBody": { + "$ref": "#/components/requestBodies/requestBodyToken" + }, + "responses": { + "200": { + "$ref": "#/components/responses/ResponseToken" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/token/{id}": { + "get": { + "tags": ["Authentication"], + "summary": "show tokens", + "operationId": "5b02f556855bd9d193cacd7bb2de0054", + "parameters": [ + { + "$ref": "#/components/parameters/parameterIdToken" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/ResponseToken" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "put": { + "tags": ["Authentication"], + "summary": "Updates an token", + "operationId": "ea53942de138060aaa842504006fb54a", + "parameters": [ + { + "$ref": "#/components/parameters/parameterIdToken" + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/requestBodyToken" + }, + "responses": { + "200": { + "$ref": "#/components/responses/ResponseToken" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": ["Authentication"], + "summary": "Deletes an token object.", + "operationId": "acca35e6dec0df48759a2ec73b931f21", + "parameters": [ + { + "$ref": "#/components/parameters/parameterIdToken" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/successfullyDeleted" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/token/list": { + "post": { + "tags": ["Authentication"], + "summary": "List tokens", + "operationId": "95caaac7a7f8f31b0bef89c1b771612a", + "parameters": [ + { + "$ref": "#/components/parameters/parameterPage" + }, + { + "$ref": "#/components/parameters/parameterSizePage" + }, + { + "$ref": "#/components/parameters/parameterSortField" + }, + { + "$ref": "#/components/parameters/parameterSortDirection" + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/requestBodyTokenFilter" + }, + "responses": { + "200": { + "description": "List Incidence object", + "content": { + "application/json": { + "schema": { + "properties": { + "paginationData": { + "$ref": "#/components/schemas/paginationData" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Token" + } + } + }, + "type": "object" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/ping": { + "get": { + "tags": ["Authentication"], + "summary": "ping", + "operationId": "d77311e58cba156b64abc8b5bc1c8380", + "responses": { + "200": { + "$ref": "#/components/responses/ResponsePing" + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + }, + "500": { + "$ref": "#/components/responses/InternalServerError" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, "/event/{idEvent}/comment": { "post": { "tags": ["Events"], @@ -1712,6 +1956,66 @@ }, "components": { "schemas": { + "Token": { + "properties": { + "idToken": { + "description": "Id Token", + "type": "integer", + "readOnly": true, + "nullable": false + }, + "label": { + "description": "label of the token", + "type": "string", + "default": null, + "nullable": false + }, + "uuid": { + "description": "uuid of the token", + "type": "string", + "default": null, + "readOnly": true, + "nullable": true + }, + "idUser": { + "description": "id_user of the token", + "type": "string", + "default": null, + "readOnly": true, + "nullable": true + }, + "validity": { + "description": "validity of the token", + "type": "string", + "default": null, + "nullable": true + }, + "lastUsage": { + "description": "last_usage of the token", + "type": "string", + "default": null, + "nullable": true + } + }, + "type": "object" + }, + "TokenFilter": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/Token" + }, + { + "properties": { + "idToken": { + "default": null, + "readOnly": false + } + }, + "type": "object" + } + ] + }, "EventComment": { "properties": { "idEventComment": { @@ -3173,6 +3477,22 @@ } }, "responses": { + "ResponsePing": { + "description": "Ping", + "content": { + "application/json": {} + } + }, + "ResponseToken": { + "description": "Incidence type object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Token" + } + } + } + }, "ResponseEventComment": { "description": "Event comment object", "content": { @@ -3356,6 +3676,16 @@ } }, "parameters": { + "parameterIdToken": { + "name": "id", + "in": "path", + "description": "Token id", + "required": true, + "schema": { + "type": "integer", + "default": 1 + } + }, "parameterIdEventComment": { "name": "idComment", "in": "path", @@ -3479,6 +3809,26 @@ } }, "requestBodies": { + "requestBodyToken": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Token" + } + } + } + }, + "requestBodyTokenFilter": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenFilter" + } + } + } + }, "requestBodyEventComment": { "required": true, "content": { @@ -3641,6 +3991,10 @@ } }, "tags": [ + { + "name": "Authentication", + "description": "API Endpoints of authentication" + }, { "name": "Events", "description": "API Endpoints of events" diff --git a/pandora_console/composer.json b/pandora_console/composer.json index 2e4c48f4fd..3b05d0f000 100644 --- a/pandora_console/composer.json +++ b/pandora_console/composer.json @@ -27,7 +27,8 @@ "laminas/laminas-diactoros": "^3.2", "php-di/php-di": "^7.0", "zircote/swagger-php": "^4.8", - "doctrine/annotations": "^2.0" + "doctrine/annotations": "^2.0", + "ramsey/uuid": "^4.7" }, "repositories": { "phpchartjs": { diff --git a/pandora_console/composer.lock b/pandora_console/composer.lock index 3c613163d6..171c94a267 100644 --- a/pandora_console/composer.lock +++ b/pandora_console/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": "c59ac791bff6b039091a3296023a8da6", + "content-hash": "0d777bd9c0ca68c9ec0fe911e71b1b2a", "packages": [ { "name": "amphp/amp", @@ -620,6 +620,61 @@ "relative": true } }, + { + "name": "brick/math", + "version": "0.11.0", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^9.0", + "vimeo/psalm": "5.0.0" + }, + "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.11.0" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2023-01-15T23:15:59+00:00" + }, { "name": "chrome-php/chrome", "version": "v1.10.0", @@ -834,16 +889,16 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "shasum": "" }, "require": { @@ -875,9 +930,9 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" }, - "time": "2023-09-27T20:04:15+00:00" + "time": "2024-01-30T19:34:25+00:00" }, { "name": "doctrine/lexer", @@ -2620,6 +2675,187 @@ }, "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "ramsey/collection", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.28.3", + "fakerphp/faker": "^1.21", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^1.0", + "mockery/mockery": "^1.5", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpcsstandards/phpcsutils": "^1.0.0-rc1", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5", + "psalm/plugin-mockery": "^1.1", + "psalm/plugin-phpunit": "^0.18.4", + "ramsey/coding-standard": "^2.0.3", + "ramsey/conventional-commits": "^1.3", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "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/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", + "type": "tidelift" + } + ], + "time": "2022-12-31T21:50:55+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.7.5", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", + "ext-json": "*", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "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", + "paragonie/random-lib": "^2", + "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.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "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." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.7.5" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "time": "2023-11-08T05:53:05+00:00" + }, { "name": "setasign/fpdi", "version": "v2.6.0", @@ -3034,16 +3270,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.0.0", + "version": "v7.0.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7" + "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7da8ea2362a283771478c5f7729cfcb43a76b8b7", - "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/2890e3a825bc0c0558526c04499c13f83e1b6b12", + "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12", "shasum": "" }, "require": { @@ -3077,7 +3313,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.0.0" + "source": "https://github.com/symfony/filesystem/tree/v7.0.3" }, "funding": [ { @@ -3093,7 +3329,7 @@ "type": "tidelift" } ], - "time": "2023-07-27T06:33:22+00:00" + "time": "2024-01-23T15:02:46+00:00" }, { "name": "symfony/finder", @@ -3739,16 +3975,16 @@ }, { "name": "symfony/process", - "version": "v7.0.2", + "version": "v7.0.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a" + "reference": "937a195147e0c27b2759ade834169ed006d0bc74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a", - "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a", + "url": "https://api.github.com/repos/symfony/process/zipball/937a195147e0c27b2759ade834169ed006d0bc74", + "reference": "937a195147e0c27b2759ade834169ed006d0bc74", "shasum": "" }, "require": { @@ -3780,7 +4016,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.0.2" + "source": "https://github.com/symfony/process/tree/v7.0.3" }, "funding": [ { @@ -3796,7 +4032,7 @@ "type": "tidelift" } ], - "time": "2023-12-24T09:15:37+00:00" + "time": "2024-01-23T15:02:46+00:00" }, { "name": "symfony/var-dumper", @@ -3881,16 +4117,16 @@ }, { "name": "symfony/yaml", - "version": "v7.0.0", + "version": "v7.0.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0055b230c408428b9b5cde7c55659555be5c0278" + "reference": "2d4fca631c00700597e9442a0b2451ce234513d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0055b230c408428b9b5cde7c55659555be5c0278", - "reference": "0055b230c408428b9b5cde7c55659555be5c0278", + "url": "https://api.github.com/repos/symfony/yaml/zipball/2d4fca631c00700597e9442a0b2451ce234513d3", + "reference": "2d4fca631c00700597e9442a0b2451ce234513d3", "shasum": "" }, "require": { @@ -3932,7 +4168,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.0.0" + "source": "https://github.com/symfony/yaml/tree/v7.0.3" }, "funding": [ { @@ -3948,7 +4184,7 @@ "type": "tidelift" } ], - "time": "2023-11-07T10:26:03+00:00" + "time": "2024-01-23T15:02:46+00:00" }, { "name": "tinymce/tinymce", diff --git a/pandora_console/extras/mr/68.sql b/pandora_console/extras/mr/68.sql index db168d5c22..938d29bf3a 100644 --- a/pandora_console/extras/mr/68.sql +++ b/pandora_console/extras/mr/68.sql @@ -1,5 +1,17 @@ START TRANSACTION; +CREATE TABLE IF NOT EXISTS `ttoken` ( + `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `label` TEXT NOT NULL, + `uuid` TEXT NOT NULL, + `challenge` TEXT NOT NULL, + `id_user` varchar(60) NOT NULL default '', + `validity` datetime, + `last_usage` datetime, + PRIMARY KEY(`id`), + FOREIGN KEY (`id_user`) REFERENCES `tusuario` (`id_user`) ON DELETE CASCADE +) ENGINE = InnoDB DEFAULT CHARSET=UTF8MB4; + CREATE TABLE IF NOT EXISTS `tmerge_error` ( `id` int(10) NOT NULL auto_increment, `id_node` int(10) default 0, diff --git a/pandora_console/include/lib/Modules/Authentication/Actions/CreateTokenAction.php b/pandora_console/include/lib/Modules/Authentication/Actions/CreateTokenAction.php new file mode 100644 index 0000000000..0089b0aea1 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Actions/CreateTokenAction.php @@ -0,0 +1,19 @@ +createTokenService->__invoke($token); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Actions/DeleteTokenAction.php b/pandora_console/include/lib/Modules/Authentication/Actions/DeleteTokenAction.php new file mode 100644 index 0000000000..83ef939314 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Actions/DeleteTokenAction.php @@ -0,0 +1,19 @@ +deleteTokenService->__invoke($token); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Actions/GetTokenAction.php b/pandora_console/include/lib/Modules/Authentication/Actions/GetTokenAction.php new file mode 100644 index 0000000000..9090a2d1c9 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Actions/GetTokenAction.php @@ -0,0 +1,19 @@ +getTokenService->__invoke($idToken); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Actions/ListTokenAction.php b/pandora_console/include/lib/Modules/Authentication/Actions/ListTokenAction.php new file mode 100644 index 0000000000..82bb84e871 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Actions/ListTokenAction.php @@ -0,0 +1,28 @@ +getPage(), + $tokenFilter->getSizePage(), + $this->countTokenService->__invoke($tokenFilter), + $this->listTokenService->__invoke($tokenFilter) + ))->toArray(); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Actions/UpdateTokenAction.php b/pandora_console/include/lib/Modules/Authentication/Actions/UpdateTokenAction.php new file mode 100644 index 0000000000..8bce6d6684 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Actions/UpdateTokenAction.php @@ -0,0 +1,19 @@ +updateTokenService->__invoke($token, $oldToken); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Controllers/CreateTokenController.php b/pandora_console/include/lib/Modules/Authentication/Controllers/CreateTokenController.php new file mode 100644 index 0000000000..152ca45744 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Controllers/CreateTokenController.php @@ -0,0 +1,47 @@ +fromRequest($request, Token::class); + + $this->acl->validate(0, 'UM', ' tried to manage tokens'); + + $result = $this->createTokenAction->__invoke($token); + + return $this->getResponse($response, $result); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Controllers/DeleteTokenController.php b/pandora_console/include/lib/Modules/Authentication/Controllers/DeleteTokenController.php new file mode 100644 index 0000000000..fc94d09ba0 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Controllers/DeleteTokenController.php @@ -0,0 +1,47 @@ +getParam($request, 'id'); + $token = $this->getTokenAction->__invoke($idToken); + + $this->acl->validate(0, 'UM', ' tried to manage token'); + + $result = $this->deleteTokenAction->__invoke($token); + return $this->getResponse($response, $result); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Controllers/GetTokenController.php b/pandora_console/include/lib/Modules/Authentication/Controllers/GetTokenController.php new file mode 100644 index 0000000000..7a41834ce9 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Controllers/GetTokenController.php @@ -0,0 +1,44 @@ +getParam($request, 'id'); + + $this->acl->validate(0, 'UM', ' tried to manage token'); + + $result = $this->getTokenAction->__invoke($idToken); + return $this->getResponse($response, $result); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Controllers/ListTokenController.php b/pandora_console/include/lib/Modules/Authentication/Controllers/ListTokenController.php new file mode 100644 index 0000000000..3dd9e0409b --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Controllers/ListTokenController.php @@ -0,0 +1,73 @@ +fromRequest($request, TokenFilter::class); + + $this->acl->validate(0, 'UM', ' tried to manage token'); + + $result = $this->listTokenAction->__invoke($tokenFilter); + return $this->getResponse($response, $result); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Controllers/PingController.php b/pandora_console/include/lib/Modules/Authentication/Controllers/PingController.php new file mode 100644 index 0000000000..fd69919c80 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Controllers/PingController.php @@ -0,0 +1,51 @@ +getResponse($response, ['valid' => true]); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Controllers/UpdateTokenController.php b/pandora_console/include/lib/Modules/Authentication/Controllers/UpdateTokenController.php new file mode 100644 index 0000000000..69bd0783de --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Controllers/UpdateTokenController.php @@ -0,0 +1,53 @@ +getParam($request, 'id'); + $token = $this->getTokenAction->__invoke($idToken); + + $oldToken = clone $token; + $params = $this->extractParams($request); + $token->fromArray($params); + + $this->acl->validate(0, 'UM', ' tried to manage token'); + + $result = $this->updateTokenAction->__invoke($token, $oldToken); + return $this->getResponse($response, $result); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Entities/Token.php b/pandora_console/include/lib/Modules/Authentication/Entities/Token.php new file mode 100644 index 0000000000..30b3940c40 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Entities/Token.php @@ -0,0 +1,340 @@ + 1, + 'uuid' => 1, + 'challenge' => 1, + 'idUser' => 1, + 'token' => 1, + ]; + } + + public function jsonSerialize(): mixed + { + return [ + 'idToken' => $this->getIdToken(), + 'label' => $this->getLabel(), + 'uuid' => $this->getUuid(), + 'idUser' => $this->getIdUser(), + 'validity' => $this->getValidity(), + 'lastUsage' => $this->getLastUsage(), + 'token' => $this->getToken() + ]; + } + + public function getValidations(): array + { + return [ + 'idToken' => [ + Validator::INTEGER, + Validator::GREATERTHAN, + ], + 'label' => Validator::STRING, + 'uuid' => Validator::STRING, + 'challenge' => Validator::STRING, + 'idUser' => Validator::STRING, + 'validity' => Validator::STRING, + 'lastUsage' => Validator::DATETIME, + ]; + } + + public function validateFields(array $filters): array + { + return (new Validator())->validate($filters); + } + + /** + * Get the value of idToken. + * + * @return ?int + */ + public function getIdToken(): ?int + { + return $this->idToken; + } + + /** + * Set the value of idToken. + * + * @param ?int $idToken + * + */ + public function setIdToken(?int $idToken): self + { + $this->idToken = $idToken; + + return $this; + } + + + /** + * Get the value of label. + * + * @return ?string + */ + public function getLabel(): ?string + { + return $this->label; + } + + /** + * Set the value of label. + * + * @param ?string $label + * + */ + public function setLabel(?string $label): self + { + $this->label = $label; + + return $this; + } + + /** + * Get the value of uuid. + * + * @return ?string + */ + public function getUuid(): ?string + { + return $this->uuid; + } + + /** + * Set the value of uuid. + * + * @param ?string $uuid + * + */ + public function setUuid(?string $uuid): self + { + $this->uuid = $uuid; + + return $this; + } + + /** + * Get the value of challenge. + * + * @return ?string + */ + public function getChallenge(): ?string + { + return $this->challenge; + } + + /** + * Set the value of challenge. + * + * @param ?string $challenge + * + */ + public function setChallenge(?string $challenge): self + { + $this->challenge = $challenge; + + return $this; + } + + /** + * Get the value of idUser. + * + * @return ?string + */ + public function getIdUser(): ?string + { + return $this->idUser; + } + + /** + * Set the value of idUser. + * + * @param ?string $idUser + * + */ + public function setIdUser(?string $idUser): self + { + $this->idUser = $idUser; + + return $this; + } + + /** + * Get the value of validity. + * + * @return ?string + */ + public function getValidity(): ?string + { + return $this->validity; + } + + /** + * Set the value of validity. + * + * @param ?string $validity + * + */ + public function setValidity(?string $validity): self + { + $this->validity = $validity; + + return $this; + } + + /** + * Get the value of lastUsage. + * + * @return ?string + */ + public function getLastUsage(): ?string + { + return $this->lastUsage; + } + + /** + * Set the value of lastUsage. + * + * @param ?string $lastUsage + * + */ + public function setLastUsage(?string $lastUsage): self + { + $this->lastUsage = $lastUsage; + + return $this; + } + + /** + * Get the value of token + * + * @return ?string + */ + public function getToken(): ?string + { + return $this->token; + } + + /** + * Set the value of token + * + * @param ?string $token + * + * @return self + */ + public function setToken(?string $token): self + { + $this->token = $token; + + return $this; + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Entities/TokenDataMapper.php b/pandora_console/include/lib/Modules/Authentication/Entities/TokenDataMapper.php new file mode 100644 index 0000000000..9303f3eeef --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Entities/TokenDataMapper.php @@ -0,0 +1,62 @@ +builder->build(new Token(), [ + 'idToken' => $data[self::ID_TOKEN], + 'label' => $this->repository->safeOutput($data[self::LABEL]), + 'uuid' => $data[self::UUID], + 'challenge' => $data[self::CHALLENGE], + 'idUser' => $data[self::ID_USER], + 'validity' => $data[self::VALIDITY], + 'lastUsage' => $data[self::LAST_USAGE], + ]); + } + + public function toDatabase(MappeableInterface $data): array + { + /** @var Token $data */ + return [ + self::ID_TOKEN => $data->getIdToken(), + self::LABEL => $this->repository->safeInput($data->getLabel()), + self::UUID => $data->getUuid(), + self::CHALLENGE => $data->getChallenge(), + self::ID_USER => $data->getIdUser(), + self::VALIDITY => $data->getValidity(), + self::LAST_USAGE => $data->getLastUsage(), + ]; + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Entities/TokenFilter.php b/pandora_console/include/lib/Modules/Authentication/Entities/TokenFilter.php new file mode 100644 index 0000000000..1674a0958d --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Entities/TokenFilter.php @@ -0,0 +1,81 @@ +setDefaultFieldOrder(TokenDataMapper::LABEL); + $this->setDefaultDirectionOrder($this::DESC); + $this->setEntityFilter(new Token()); + } + + + public function fieldsTranslate(): array + { + return [ + 'idToken' => TokenDataMapper::ID_TOKEN, + 'label' => TokenDataMapper::LABEL, + ]; + } + + + public function fieldsReadOnly(): array + { + return []; + } + + + public function jsonSerialize(): mixed + { + return []; + } + + + public function getValidations(): array + { + $validations = []; + if ($this->getEntityFilter() !== null) { + $validations = $this->getEntityFilter()->getValidations(); + } + + return $validations; + } + + + public function validateFields(array $filters): array + { + return (new Validator())->validate($filters); + } + + +} diff --git a/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepository.php b/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepository.php new file mode 100644 index 0000000000..fdcc53d6b7 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Repositories/TokenRepository.php @@ -0,0 +1,65 @@ +repository->__list( + $tokenFilter, + $this->tokenDataMapper + ); + } + + public function count(TokenFilter $tokenFilter): int + { + return $this->repository->__count( + $tokenFilter, + $this->tokenDataMapper + ); + } + + public function getOne(TokenFilter $tokenFilter): Token + { + return $this->repository->__getOne( + $tokenFilter, + $this->tokenDataMapper + ); + } + + public function create(Token $token): Token + { + $id = $this->repository->__create($token, $this->tokenDataMapper); + return $token->setIdToken($id); + } + + public function update(Token $token): Token + { + return $this->repository->__update( + $token, + $this->tokenDataMapper, + $token->getIdToken() + ); + } + + public function delete(int $id): void + { + $this->repository->__delete($id, $this->tokenDataMapper); + } + +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/CountTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/CountTokenService.php new file mode 100644 index 0000000000..ea6a024255 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/CountTokenService.php @@ -0,0 +1,19 @@ +tokenRepository->count($tokenFilter); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/CreateTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/CreateTokenService.php new file mode 100644 index 0000000000..aa06a5306c --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/CreateTokenService.php @@ -0,0 +1,42 @@ +tokenValidation->__invoke($token); + + $stringToken = $this->generateUserTokenService->__invoke(); + $userUUID = $this->generateUserUUIDService->__invoke(); + $hashedToken = $this->prepareUserTokenService->__invoke($stringToken); + + $token->setUuid($userUUID); + $token->setChallenge($hashedToken); + $token->setToken($userUUID.'-'.$stringToken); + $token = $this->tokenRepository->create($token); + + $this->audit->write( + 'Token Management', + ' Create token #'.$token->getIdToken() + ); + + return $token; + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/DeleteTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/DeleteTokenService.php new file mode 100644 index 0000000000..80b6cb1200 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/DeleteTokenService.php @@ -0,0 +1,29 @@ +getIdToken(); + + $this->tokenRepository->delete($idToken); + + $this->audit->write( + 'Token Management', + ' Deleted token #'.$idToken + ); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/ExistLabelTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/ExistLabelTokenService.php new file mode 100644 index 0000000000..5ad1d10a76 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/ExistLabelTokenService.php @@ -0,0 +1,31 @@ +getEntityFilter(); + $entityFilter->setLabel($label); + + try { + $this->tokenRepository->getOne($tokenFilter); + return true; + } catch (NotFoundException) { + return false; + } + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/GenerateUserTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/GenerateUserTokenService.php new file mode 100644 index 0000000000..0ca78e3502 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/GenerateUserTokenService.php @@ -0,0 +1,22 @@ +toString(); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/GetTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/GetTokenService.php new file mode 100644 index 0000000000..a235acb52d --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/GetTokenService.php @@ -0,0 +1,25 @@ +getEntityFilter(); + $entityFilter->setIdToken($idToken); + + return $this->tokenRepository->getOne($tokenFilter); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/GetUserTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/GetUserTokenService.php new file mode 100644 index 0000000000..57b08c531a --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/GetUserTokenService.php @@ -0,0 +1,27 @@ +getEntityFilter(); + $entityFilter->setUuid($uuid); + + // TODO: Validity. + + return $this->tokenRepository->getOne($tokenFilter); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/ListTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/ListTokenService.php new file mode 100644 index 0000000000..c3cbf07aae --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/ListTokenService.php @@ -0,0 +1,19 @@ +tokenRepository->list($tokenFilter); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/PrepareUserTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/PrepareUserTokenService.php new file mode 100644 index 0000000000..cca16ede44 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/PrepareUserTokenService.php @@ -0,0 +1,15 @@ +tokenValidation->__invoke($token, $oldToken); + + $token = $this->tokenRepository->update($token); + + $this->audit->write( + 'Token Management', + ' Update token #'.$token->getIdToken() + ); + + return $token; + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Services/ValidateUserTokenService.php b/pandora_console/include/lib/Modules/Authentication/Services/ValidateUserTokenService.php new file mode 100644 index 0000000000..ee66c56954 --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Services/ValidateUserTokenService.php @@ -0,0 +1,23 @@ +getUserTokenService->__invoke($uuid)?->getChallenge(); + return password_verify( + $token, + $challenge + ); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/Validations/TokenValidation.php b/pandora_console/include/lib/Modules/Authentication/Validations/TokenValidation.php new file mode 100644 index 0000000000..efbb5202bd --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/Validations/TokenValidation.php @@ -0,0 +1,43 @@ +getLabel()) { + throw new BadRequestException(__('Label is missing')); + } + + if($oldToken === null || $oldToken->getLabel() !== $token->getLabel()) { + if($this->existLabelTokenService->__invoke($token->getLabel()) === true) { + throw new BadRequestException( + __('Label %s is already exists', $token->getLabel()) + ); + } + } + + if($oldToken === null) { + $token->setIdUser($this->config->get('id_user')); + } + } + + protected function getCurrentTimestamp(): string + { + return $this->timestamp->getMysqlCurrentTimestamp(0); + } +} diff --git a/pandora_console/include/lib/Modules/Authentication/routes.php b/pandora_console/include/lib/Modules/Authentication/routes.php new file mode 100644 index 0000000000..5947f3947e --- /dev/null +++ b/pandora_console/include/lib/Modules/Authentication/routes.php @@ -0,0 +1,18 @@ +map(['GET', 'POST'], '/token/list', ListTokenController::class); + $app->get('/token/{id}', GetTokenController::class); + $app->post('/token', CreateTokenController::class); + $app->put('/token/{id}', UpdateTokenController::class); + $app->delete('/token/{id}', DeleteTokenController::class); + $app->get('/ping', PingController::class); +}; diff --git a/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php b/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php index 89f6b1bef5..47ef62594a 100644 --- a/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php +++ b/pandora_console/include/lib/Modules/Shared/Documentation/OpenApi.php @@ -37,6 +37,10 @@ use OpenApi\Annotations as OA; * description="PandoraFMS API Server" * ), * @OA\Tag( + * name="Authentication", + * description="API Endpoints of authentication" + * ), + * @OA\Tag( * name="Events", * description="API Endpoints of events" * ), diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index 43da6c72c9..e13b6e0ceb 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -4653,4 +4653,19 @@ CREATE TABLE IF NOT EXISTS `tmerge_queries` ( `utimestamp` int(20) unsigned NOT NULL default 0, `query` LONGTEXT NOT NULL default "", PRIMARY KEY (`steps`) -) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; + +-- --------------------------------------------------------------------- +-- Table `ttoken` +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `ttoken` ( + `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `label` TEXT NOT NULL, + `uuid` TEXT NOT NULL, + `challenge` TEXT NOT NULL, + `id_user` varchar(60) NOT NULL default '', + `validity` datetime, + `last_usage` datetime, + PRIMARY KEY(`id`), + FOREIGN KEY (`id_user`) REFERENCES `tusuario` (`id_user`) ON DELETE CASCADE +) ENGINE = InnoDB DEFAULT CHARSET=UTF8MB4; \ No newline at end of file diff --git a/pandora_console/vendor/brick/math/CHANGELOG.md b/pandora_console/vendor/brick/math/CHANGELOG.md new file mode 100644 index 0000000000..17cea8d9f9 --- /dev/null +++ b/pandora_console/vendor/brick/math/CHANGELOG.md @@ -0,0 +1,445 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16 + +๐Ÿ’ฅ **Breaking changes** + +- Minimum PHP version is now 8.0 +- Methods accepting a union of types are now strongly typed* +- `MathException` now extends `Exception` instead of `RuntimeException` + +* You may now run into type errors if you were passing `Stringable` objects to `of()` or any of the methods +internally calling `of()`, with `strict_types` enabled. You can fix this by casting `Stringable` objects to `string` +first. + +## [0.10.2](https://github.com/brick/math/releases/tag/0.10.2) - 2022-08-11 + +๐Ÿ‘Œ **Improvements** + +- `BigRational::toFloat()` now simplifies the fraction before performing division (#73) thanks to @olsavmic + +## [0.10.1](https://github.com/brick/math/releases/tag/0.10.1) - 2022-08-02 + +โœจ **New features** + +- `BigInteger::gcdMultiple()` returns the GCD of multiple `BigInteger` numbers + +## [0.10.0](https://github.com/brick/math/releases/tag/0.10.0) - 2022-06-18 + +๐Ÿ’ฅ **Breaking changes** + +- Minimum PHP version is now 7.4 + +## [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 (#60) 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 anymore + - `toBigRational()` does not simplify the fraction anymore; 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` anymore, 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. + diff --git a/pandora_console/vendor/brick/math/LICENSE b/pandora_console/vendor/brick/math/LICENSE new file mode 100644 index 0000000000..f9b724f00a --- /dev/null +++ b/pandora_console/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. diff --git a/pandora_console/vendor/brick/math/composer.json b/pandora_console/vendor/brick/math/composer.json new file mode 100644 index 0000000000..ed817bdd06 --- /dev/null +++ b/pandora_console/vendor/brick/math/composer.json @@ -0,0 +1,34 @@ +{ + "name": "brick/math", + "description": "Arbitrary-precision arithmetic library", + "type": "library", + "keywords": [ + "Brick", + "Math", + "Arbitrary-precision", + "Arithmetic", + "BigInteger", + "BigDecimal", + "BigRational", + "Bignum" + ], + "license": "MIT", + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0", + "php-coveralls/php-coveralls": "^2.2", + "vimeo/psalm": "5.0.0" + }, + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Brick\\Math\\Tests\\": "tests/" + } + } +} diff --git a/pandora_console/vendor/brick/math/src/BigDecimal.php b/pandora_console/vendor/brick/math/src/BigDecimal.php new file mode 100644 index 0000000000..02fc656122 --- /dev/null +++ b/pandora_console/vendor/brick/math/src/BigDecimal.php @@ -0,0 +1,786 @@ +value = $value; + $this->scale = $scale; + } + + /** + * Creates a BigDecimal of the given value. + * + * @throws MathException If the value cannot be converted to a BigDecimal. + * + * @psalm-pure + */ + public static function of(BigNumber|int|float|string $value) : BigDecimal + { + 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. + * + * @throws \InvalidArgumentException If the scale is negative. + * + * @psalm-pure + */ + public static function ofUnscaledValue(BigNumber|int|float|string $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. + * + * @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. + * + * @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. + * + * @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. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function plus(BigNumber|int|float|string $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. + * + * @throws MathException If the number is not valid, or is not convertible to a BigDecimal. + */ + public function minus(BigNumber|int|float|string $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. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal. + */ + public function multipliedBy(BigNumber|int|float|string $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. + * + * @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(BigNumber|int|float|string $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. + * + * @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(BigNumber|int|float|string $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`. + * + * @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. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function quotient(BigNumber|int|float|string $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. + * + * @throws MathException If the divisor is not a valid decimal number, or is zero. + */ + public function remainder(BigNumber|int|float|string $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(BigNumber|int|float|string $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. + * + * @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. + */ + 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. + */ + 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. + */ + 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. + */ + public function abs() : BigDecimal + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the negated value of this number. + */ + public function negated() : BigDecimal + { + return new BigDecimal(Calculator::get()->neg($this->value), $this->scale); + } + + public function compareTo(BigNumber|int|float|string $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); + } + + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + public function getUnscaledValue() : BigInteger + { + return self::newBigInteger($this->value); + } + + public function getScale() : int + { + return $this->scale; + } + + /** + * Returns a string representing the integral part of this decimal number. + * + * Example: `-123.456` => `-123`. + */ + 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` => ''. + */ + 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. + */ + public function hasNonZeroFractionalPart() : bool + { + return $this->getFractionalPart() !== \str_repeat('0', $this->scale); + } + + public function toBigInteger() : BigInteger + { + $zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0); + + return self::newBigInteger($zeroScaleDecimal->value); + } + + public function toBigDecimal() : BigDecimal + { + return $this; + } + + public function toBigRational() : BigRational + { + $numerator = self::newBigInteger($this->value); + $denominator = self::newBigInteger('1' . \str_repeat('0', $this->scale)); + + return self::newBigRational($numerator, $denominator, false); + } + + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + if ($scale === $this->scale) { + return $this; + } + + return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode); + } + + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + public function toFloat() : float + { + return (float) (string) $this; + } + + 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 + * + * @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 + */ + 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 + * + * @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. + * + * @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]; + } + + 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. + */ + 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; + } +} diff --git a/pandora_console/vendor/brick/math/src/BigInteger.php b/pandora_console/vendor/brick/math/src/BigInteger.php new file mode 100644 index 0000000000..435679331a --- /dev/null +++ b/pandora_console/vendor/brick/math/src/BigInteger.php @@ -0,0 +1,1079 @@ +value = $value; + } + + /** + * Creates a BigInteger of the given value. + * + * @throws MathException If the value cannot be converted to a BigInteger. + * + * @psalm-pure + */ + public static function of(BigNumber|int|float|string $value) : BigInteger + { + 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. + * + * @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. + * + * @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. + * + * @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)|null $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. + * + * @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. + * + * @throws MathException If one of the parameters cannot be converted to a BigInteger, + * or `$min` is greater than `$max`. + */ + public static function randomRange( + BigNumber|int|float|string $min, + BigNumber|int|float|string $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. + * + * @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. + * + * @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. + * + * @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; + } + + public static function gcdMultiple(BigInteger $a, BigInteger ...$n): BigInteger + { + $result = $a; + + foreach ($n as $next) { + $result = $result->gcd($next); + + if ($result->isEqualTo(1)) { + return $result; + } + } + + return $result; + } + + /** + * 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. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function plus(BigNumber|int|float|string $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. + * + * @throws MathException If the number is not valid, or is not convertible to a BigInteger. + */ + public function minus(BigNumber|int|float|string $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. + * + * @throws MathException If the multiplier is not a valid number, or is not convertible to a BigInteger. + */ + public function multipliedBy(BigNumber|int|float|string $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. + * + * @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(BigNumber|int|float|string $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. + * + * @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. + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function quotient(BigNumber|int|float|string $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. + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function remainder(BigNumber|int|float|string $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(BigNumber|int|float|string $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. + * + * @throws DivisionByZeroException If the divisor is zero. + */ + public function mod(BigNumber|int|float|string $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. + * + * @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. + * + * @throws NegativeNumberException If any of the operands is negative. + * @throws DivisionByZeroException If the modulus is zero. + */ + public function modPow(BigNumber|int|float|string $exp, BigNumber|int|float|string $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. + */ + public function gcd(BigNumber|int|float|string $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. + * + * @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. + */ + public function abs() : BigInteger + { + return $this->isNegative() ? $this->negated() : $this; + } + + /** + * Returns the inverse of this number. + */ + 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. + */ + public function and(BigNumber|int|float|string $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. + */ + public function or(BigNumber|int|float|string $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. + */ + public function xor(BigNumber|int|float|string $that) : BigInteger + { + $that = BigInteger::of($that); + + return new BigInteger(Calculator::get()->xor($this->value, $that->value)); + } + + /** + * Returns the bitwise-not of this BigInteger. + */ + public function not() : BigInteger + { + return $this->negated()->minus(1); + } + + /** + * Returns the integer left shifted by a given number of bits. + */ + 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. + */ + 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))). + */ + 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. + */ + 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. + */ + public function isEven() : bool + { + return \in_array($this->value[-1], ['0', '2', '4', '6', '8'], true); + } + + /** + * Returns whether this number is odd. + */ + 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<shiftedRight($n)->isOdd(); + } + + public function compareTo(BigNumber|int|float|string $that) : int + { + $that = BigNumber::of($that); + + if ($that instanceof BigInteger) { + return Calculator::get()->cmp($this->value, $that->value); + } + + return - $that->compareTo($this); + } + + public function getSign() : int + { + return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1); + } + + public function toBigInteger() : BigInteger + { + return $this; + } + + public function toBigDecimal() : BigDecimal + { + return self::newBigDecimal($this->value); + } + + public function toBigRational() : BigRational + { + return self::newBigRational($this, BigInteger::one(), false); + } + + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->toBigDecimal()->toScale($scale, $roundingMode); + } + + public function toInt() : int + { + $intValue = (int) $this->value; + + if ($this->value !== (string) $intValue) { + throw IntegerOverflowException::toIntOverflow($this); + } + + return $intValue; + } + + 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. + * + * @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. + * + * @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. + * + * @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); + } + + 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 + * + * @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 + */ + 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 + * + * @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; + } +} diff --git a/pandora_console/vendor/brick/math/src/BigNumber.php b/pandora_console/vendor/brick/math/src/BigNumber.php new file mode 100644 index 0000000000..80146d2079 --- /dev/null +++ b/pandora_console/vendor/brick/math/src/BigNumber.php @@ -0,0 +1,512 @@ +[\-\+])?' . + '(?:' . + '(?:' . + '(?[0-9]+)?' . + '(?\.)?' . + '(?[0-9]+)?' . + '(?:[eE](?[\-\+]?[0-9]+))?' . + ')|(?:' . + '(?[0-9]+)' . + '\/?' . + '(?[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 + * + * @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(BigNumber|int|float|string $value) : BigNumber + { + if ($value instanceof BigNumber) { + return $value; + } + + if (\is_int($value)) { + return new BigInteger((string) $value); + } + + $value = \is_float($value) ? self::floatToString($value) : $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 fn(string $value): ?string => (($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 + * + * @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 BigInteger's protected constructor from sibling classes. + * + * @internal + * @psalm-pure + */ + protected function newBigInteger(string $value) : BigInteger + { + return new BigInteger($value); + } + + /** + * Proxy method to access BigDecimal's protected constructor from sibling classes. + * + * @internal + * @psalm-pure + */ + protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal + { + return new BigDecimal($value, $scale); + } + + /** + * Proxy method to access BigRational's protected constructor from sibling classes. + * + * @internal + * @psalm-pure + */ + protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational + { + return new BigRational($numerator, $denominator, $checkDenominator); + } + + /** + * 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. + * + * @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(BigNumber|int|float|string ...$values) : static + { + $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. + * + * @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(BigNumber|int|float|string ...$values) : static + { + $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. + * + * @throws \InvalidArgumentException If no values are given. + * @throws MathException If an argument is not valid. + * + * @psalm-pure + */ + public static function sum(BigNumber|int|float|string ...$values) : static + { + /** @var static|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...) + * + * @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. + * + * @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. + */ + public function isEqualTo(BigNumber|int|float|string $that) : bool + { + return $this->compareTo($that) === 0; + } + + /** + * Checks if this number is strictly lower than the given one. + */ + public function isLessThan(BigNumber|int|float|string $that) : bool + { + return $this->compareTo($that) < 0; + } + + /** + * Checks if this number is lower than or equal to the given one. + */ + public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool + { + return $this->compareTo($that) <= 0; + } + + /** + * Checks if this number is strictly greater than the given one. + */ + public function isGreaterThan(BigNumber|int|float|string $that) : bool + { + return $this->compareTo($that) > 0; + } + + /** + * Checks if this number is greater than or equal to the given one. + */ + public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool + { + return $this->compareTo($that) >= 0; + } + + /** + * Checks if this number equals zero. + */ + public function isZero() : bool + { + return $this->getSign() === 0; + } + + /** + * Checks if this number is strictly negative. + */ + public function isNegative() : bool + { + return $this->getSign() < 0; + } + + /** + * Checks if this number is negative or zero. + */ + public function isNegativeOrZero() : bool + { + return $this->getSign() <= 0; + } + + /** + * Checks if this number is strictly positive. + */ + public function isPositive() : bool + { + return $this->getSign() > 0; + } + + /** + * Checks if this number is positive or zero. + */ + 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. + * + * @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(BigNumber|int|float|string $that) : int; + + /** + * Converts this number to a BigInteger. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding. + */ + abstract public function toBigInteger() : BigInteger; + + /** + * Converts this number to a BigDecimal. + * + * @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding. + */ + abstract public function toBigDecimal() : BigDecimal; + + /** + * Converts this number to a BigRational. + */ + 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. + * + * @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. + * + * @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. + */ + 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. + */ + abstract public function __toString() : string; + + public function jsonSerialize() : string + { + return $this->__toString(); + } +} diff --git a/pandora_console/vendor/brick/math/src/BigRational.php b/pandora_console/vendor/brick/math/src/BigRational.php new file mode 100644 index 0000000000..31f2904fad --- /dev/null +++ b/pandora_console/vendor/brick/math/src/BigRational.php @@ -0,0 +1,445 @@ +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. + * + * @throws MathException If the value cannot be converted to a BigRational. + * + * @psalm-pure + */ + public static function of(BigNumber|int|float|string $value) : BigRational + { + 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. + * + * @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( + BigNumber|int|float|string $numerator, + BigNumber|int|float|string $denominator, + ) : BigRational { + $numerator = BigInteger::of($numerator); + $denominator = BigInteger::of($denominator); + + return new BigRational($numerator, $denominator, true); + } + + /** + * Returns a BigRational representing zero. + * + * @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. + * + * @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. + * + * @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; + } + + public function getNumerator() : BigInteger + { + return $this->numerator; + } + + public function getDenominator() : BigInteger + { + return $this->denominator; + } + + /** + * Returns the quotient of the division of the numerator by the denominator. + */ + public function quotient() : BigInteger + { + return $this->numerator->quotient($this->denominator); + } + + /** + * Returns the remainder of the division of the numerator by the denominator. + */ + 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. + * + * @throws MathException If the number is not valid. + */ + public function plus(BigNumber|int|float|string $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. + * + * @throws MathException If the number is not valid. + */ + public function minus(BigNumber|int|float|string $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. + * + * @throws MathException If the multiplier is not a valid number. + */ + public function multipliedBy(BigNumber|int|float|string $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. + * + * @throws MathException If the divisor is not a valid number, or is zero. + */ + public function dividedBy(BigNumber|int|float|string $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. + * + * @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. + * + * @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. + */ + public function abs() : BigRational + { + return new BigRational($this->numerator->abs(), $this->denominator, false); + } + + /** + * Returns the negated value of this BigRational. + */ + public function negated() : BigRational + { + return new BigRational($this->numerator->negated(), $this->denominator, false); + } + + /** + * Returns the simplified value of this 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); + } + + public function compareTo(BigNumber|int|float|string $that) : int + { + return $this->minus($that)->getSign(); + } + + public function getSign() : int + { + return $this->numerator->getSign(); + } + + 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; + } + + public function toBigDecimal() : BigDecimal + { + return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator); + } + + public function toBigRational() : BigRational + { + return $this; + } + + public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal + { + return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode); + } + + public function toInt() : int + { + return $this->toBigInteger()->toInt(); + } + + public function toFloat() : float + { + $simplified = $this->simplified(); + return $simplified->numerator->toFloat() / $simplified->denominator->toFloat(); + } + + 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 + * + * @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 + */ + 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 + * + * @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); + } +} diff --git a/pandora_console/vendor/brick/math/src/Exception/DivisionByZeroException.php b/pandora_console/vendor/brick/math/src/Exception/DivisionByZeroException.php new file mode 100644 index 0000000000..ce7769ac2e --- /dev/null +++ b/pandora_console/vendor/brick/math/src/Exception/DivisionByZeroException.php @@ -0,0 +1,35 @@ + 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)); + } +} diff --git a/pandora_console/vendor/brick/math/src/Exception/RoundingNecessaryException.php b/pandora_console/vendor/brick/math/src/Exception/RoundingNecessaryException.php new file mode 100644 index 0000000000..57bfcd8448 --- /dev/null +++ b/pandora_console/vendor/brick/math/src/Exception/RoundingNecessaryException.php @@ -0,0 +1,19 @@ +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. + */ + abstract public function add(string $a, string $b) : string; + + /** + * Subtracts two numbers. + */ + abstract public function sub(string $a, string $b) : string; + + /** + * Multiplies two numbers. + */ + 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 array{string, 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 $b The modulus; must not be zero. + */ + 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 $m The modulus; must not be negative or zero. + */ + 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); + } + + [$g, $x] = $this->gcdExtended($modVal, $m); + + 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. + */ + 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. + * + * @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)); + } + + /** + * @return array{string, string, string} GCD, X, Y + */ + private function gcdExtended(string $a, string $b) : array + { + if ($a === '0') { + return [$b, '0', '1']; + } + + [$gcd, $x1, $y1] = $this->gcdExtended($this->mod($b, $a), $a); + + $x = $this->sub($y1, $this->mul($this->divQ($b, $a), $x1)); + $y = $x1; + + return [$gcd, $x, $y]; + } + + /** + * 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. + */ + 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. + * + * @throws \InvalidArgumentException If the rounding mode is invalid. + * @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary. + * + * @psalm-suppress ImpureFunctionCall + */ + 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. + */ + 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. + */ + 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. + */ + public function xor(string $a, string $b) : string + { + return $this->bitwise('xor', $a, $b); + } + + /** + * Performs a bitwise operation on a decimal number. + * + * @param 'and'|'or'|'xor' $operator The operator to use. + * @param string $a The left operand. + * @param string $b The right operand. + */ + 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. + */ + 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. + */ + 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. + */ + 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; + } +} diff --git a/pandora_console/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php b/pandora_console/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php new file mode 100644 index 0000000000..5457a3c98f --- /dev/null +++ b/pandora_console/vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php @@ -0,0 +1,75 @@ +maxDigits = 9; + break; + + case 8: + $this->maxDigits = 18; + break; + + default: + throw new \RuntimeException('The platform is not 32-bit or 64-bit as expected.'); + } + } + + 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; + } + + public function sub(string $a, string $b) : string + { + return $this->add($a, $this->neg($b)); + } + + 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; + } + + public function divQ(string $a, string $b) : string + { + return $this->divQR($a, $b)[0]; + } + + public function divR(string $a, string $b): string + { + return $this->divQR($a, $b)[1]; + } + + 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]; + } + + 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/ + */ + 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 + */ + 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. + */ + 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. + */ + 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. + */ + 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. + * + * @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. + * + * @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. + * + * @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]; + } +} diff --git a/pandora_console/vendor/brick/math/src/RoundingMode.php b/pandora_console/vendor/brick/math/src/RoundingMode.php new file mode 100644 index 0000000000..06936d8db3 --- /dev/null +++ b/pandora_console/vendor/brick/math/src/RoundingMode.php @@ -0,0 +1,107 @@ += 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; +} diff --git a/pandora_console/vendor/composer/autoload_files.php b/pandora_console/vendor/composer/autoload_files.php index 6c228eb278..6d15dcb42d 100644 --- a/pandora_console/vendor/composer/autoload_files.php +++ b/pandora_console/vendor/composer/autoload_files.php @@ -38,6 +38,7 @@ return array( 'd02cf21124526632320d6f20b1bbf905' => $vendorDir . '/laminas/laminas-diactoros/src/functions/parse_cookie_header.php', 'db356362850385d08a5381de2638b5fd' => $vendorDir . '/mpdf/mpdf/src/functions.php', 'b33e3d135e5d9e47d845c576147bda89' => $vendorDir . '/php-di/php-di/src/functions.php', + 'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php', '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', '11a9819e563d3900ef57275fe1df7d91' => $baseDir . '/include/global_config.php', ); diff --git a/pandora_console/vendor/composer/autoload_psr4.php b/pandora_console/vendor/composer/autoload_psr4.php index bdb1ed61b4..2b2cd523ee 100644 --- a/pandora_console/vendor/composer/autoload_psr4.php +++ b/pandora_console/vendor/composer/autoload_psr4.php @@ -25,6 +25,8 @@ return array( 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'), 'Slim\\Psr7\\' => array($vendorDir . '/slim/psr7/src'), 'Slim\\' => array($vendorDir . '/slim/slim/Slim'), + 'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'), + 'Ramsey\\Collection\\' => array($vendorDir . '/ramsey/collection/src'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), 'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'), @@ -57,6 +59,7 @@ return array( 'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'), 'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), 'DI\\' => array($vendorDir . '/php-di/php-di/src'), + 'Brick\\Math\\' => array($vendorDir . '/brick/math/src'), 'Artica\\PHPChartJS\\' => array($vendorDir . '/artica/phpchartjs/src'), 'Amp\\Sync\\' => array($vendorDir . '/amphp/sync/src'), 'Amp\\Serialization\\' => array($vendorDir . '/amphp/serialization/src'), diff --git a/pandora_console/vendor/composer/autoload_static.php b/pandora_console/vendor/composer/autoload_static.php index 68b58cf029..7338ae1edc 100644 --- a/pandora_console/vendor/composer/autoload_static.php +++ b/pandora_console/vendor/composer/autoload_static.php @@ -39,6 +39,7 @@ class ComposerStaticInit94a17e624d873685991e8ae888e00eb9 'd02cf21124526632320d6f20b1bbf905' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/parse_cookie_header.php', 'db356362850385d08a5381de2638b5fd' => __DIR__ . '/..' . '/mpdf/mpdf/src/functions.php', 'b33e3d135e5d9e47d845c576147bda89' => __DIR__ . '/..' . '/php-di/php-di/src/functions.php', + 'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php', '2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php', '11a9819e563d3900ef57275fe1df7d91' => __DIR__ . '/../..' . '/include/global_config.php', ); @@ -78,6 +79,11 @@ class ComposerStaticInit94a17e624d873685991e8ae888e00eb9 'Slim\\Psr7\\' => 10, 'Slim\\' => 5, ), + 'R' => + array ( + 'Ramsey\\Uuid\\' => 12, + 'Ramsey\\Collection\\' => 18, + ), 'P' => array ( 'Psr\\Log\\' => 8, @@ -143,6 +149,10 @@ class ComposerStaticInit94a17e624d873685991e8ae888e00eb9 'DeepCopy\\' => 9, 'DI\\' => 3, ), + 'B' => + array ( + 'Brick\\Math\\' => 11, + ), 'A' => array ( 'Artica\\PHPChartJS\\' => 18, @@ -235,6 +245,14 @@ class ComposerStaticInit94a17e624d873685991e8ae888e00eb9 array ( 0 => __DIR__ . '/..' . '/slim/slim/Slim', ), + 'Ramsey\\Uuid\\' => + array ( + 0 => __DIR__ . '/..' . '/ramsey/uuid/src', + ), + 'Ramsey\\Collection\\' => + array ( + 0 => __DIR__ . '/..' . '/ramsey/collection/src', + ), 'Psr\\Log\\' => array ( 0 => __DIR__ . '/..' . '/psr/log/src', @@ -365,6 +383,10 @@ class ComposerStaticInit94a17e624d873685991e8ae888e00eb9 array ( 0 => __DIR__ . '/..' . '/php-di/php-di/src', ), + 'Brick\\Math\\' => + array ( + 0 => __DIR__ . '/..' . '/brick/math/src', + ), 'Artica\\PHPChartJS\\' => array ( 0 => __DIR__ . '/..' . '/artica/phpchartjs/src', diff --git a/pandora_console/vendor/composer/installed.json b/pandora_console/vendor/composer/installed.json index 8e8ba83227..3ba9ef68d3 100644 --- a/pandora_console/vendor/composer/installed.json +++ b/pandora_console/vendor/composer/installed.json @@ -641,6 +641,64 @@ }, "install-path": "../artica/phpchartjs" }, + { + "name": "brick/math", + "version": "0.11.0", + "version_normalized": "0.11.0.0", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", + "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^9.0", + "vimeo/psalm": "5.0.0" + }, + "time": "2023-01-15T23:15:59+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.11.0" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "install-path": "../brick/math" + }, { "name": "chrome-php/chrome", "version": "v1.10.0", @@ -864,17 +922,17 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.2", - "version_normalized": "1.1.2.0", + "version": "1.1.3", + "version_normalized": "1.1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", - "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "shasum": "" }, "require": { @@ -892,7 +950,7 @@ "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, - "time": "2023-09-27T20:04:15+00:00", + "time": "2024-01-30T19:34:25+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -908,7 +966,7 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + "source": "https://github.com/doctrine/deprecations/tree/1.1.3" }, "install-path": "../doctrine/deprecations" }, @@ -2737,6 +2795,193 @@ }, "install-path": "../ralouphie/getallheaders" }, + { + "name": "ramsey/collection", + "version": "2.0.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.28.3", + "fakerphp/faker": "^1.21", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^1.0", + "mockery/mockery": "^1.5", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpcsstandards/phpcsutils": "^1.0.0-rc1", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5", + "psalm/plugin-mockery": "^1.1", + "psalm/plugin-phpunit": "^0.18.4", + "ramsey/coding-standard": "^2.0.3", + "ramsey/conventional-commits": "^1.3", + "vimeo/psalm": "^5.4" + }, + "time": "2022-12-31T21:50:55+00:00", + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "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/2.0.0" + }, + "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": "4.7.5", + "version_normalized": "4.7.5.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", + "ext-json": "*", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "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", + "paragonie/random-lib": "^2", + "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.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "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." + }, + "time": "2023-11-08T05:53:05+00:00", + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.7.5" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "install-path": "../ramsey/uuid" + }, { "name": "setasign/fpdi", "version": "v2.6.0", @@ -3166,17 +3411,17 @@ }, { "name": "symfony/filesystem", - "version": "v7.0.0", - "version_normalized": "7.0.0.0", + "version": "v7.0.3", + "version_normalized": "7.0.3.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7" + "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/7da8ea2362a283771478c5f7729cfcb43a76b8b7", - "reference": "7da8ea2362a283771478c5f7729cfcb43a76b8b7", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/2890e3a825bc0c0558526c04499c13f83e1b6b12", + "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12", "shasum": "" }, "require": { @@ -3184,7 +3429,7 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, - "time": "2023-07-27T06:33:22+00:00", + "time": "2024-01-23T15:02:46+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3212,7 +3457,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.0.0" + "source": "https://github.com/symfony/filesystem/tree/v7.0.3" }, "funding": [ { @@ -3898,23 +4143,23 @@ }, { "name": "symfony/process", - "version": "v7.0.2", - "version_normalized": "7.0.2.0", + "version": "v7.0.3", + "version_normalized": "7.0.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a" + "reference": "937a195147e0c27b2759ade834169ed006d0bc74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a", - "reference": "acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a", + "url": "https://api.github.com/repos/symfony/process/zipball/937a195147e0c27b2759ade834169ed006d0bc74", + "reference": "937a195147e0c27b2759ade834169ed006d0bc74", "shasum": "" }, "require": { "php": ">=8.2" }, - "time": "2023-12-24T09:15:37+00:00", + "time": "2024-01-23T15:02:46+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -3942,7 +4187,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.0.2" + "source": "https://github.com/symfony/process/tree/v7.0.3" }, "funding": [ { @@ -4046,17 +4291,17 @@ }, { "name": "symfony/yaml", - "version": "v7.0.0", - "version_normalized": "7.0.0.0", + "version": "v7.0.3", + "version_normalized": "7.0.3.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0055b230c408428b9b5cde7c55659555be5c0278" + "reference": "2d4fca631c00700597e9442a0b2451ce234513d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0055b230c408428b9b5cde7c55659555be5c0278", - "reference": "0055b230c408428b9b5cde7c55659555be5c0278", + "url": "https://api.github.com/repos/symfony/yaml/zipball/2d4fca631c00700597e9442a0b2451ce234513d3", + "reference": "2d4fca631c00700597e9442a0b2451ce234513d3", "shasum": "" }, "require": { @@ -4069,7 +4314,7 @@ "require-dev": { "symfony/console": "^6.4|^7.0" }, - "time": "2023-11-07T10:26:03+00:00", + "time": "2024-01-23T15:02:46+00:00", "bin": [ "Resources/bin/yaml-lint" ], @@ -4100,7 +4345,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.0.0" + "source": "https://github.com/symfony/yaml/tree/v7.0.3" }, "funding": [ { diff --git a/pandora_console/vendor/composer/installed.php b/pandora_console/vendor/composer/installed.php index 2bcfe8acdf..132d3269a2 100644 --- a/pandora_console/vendor/composer/installed.php +++ b/pandora_console/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'pandorafms/console', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => 'b35af80afb452f53ceb175793f2827286508e2df', + 'reference' => '8bf414b51f3333555f84df8b23614ca4b68c7fd4', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -91,6 +91,15 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'brick/math' => array( + 'pretty_version' => '0.11.0', + 'version' => '0.11.0.0', + 'reference' => '0ad82ce168c82ba30d1c01ec86116ab52f589478', + 'type' => 'library', + 'install_path' => __DIR__ . '/../brick/math', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'chrome-php/chrome' => array( 'pretty_version' => 'v1.10.0', 'version' => '1.10.0.0', @@ -119,9 +128,9 @@ 'dev_requirement' => false, ), 'doctrine/deprecations' => array( - 'pretty_version' => '1.1.2', - 'version' => '1.1.2.0', - 'reference' => '4f2d4f2836e7ec4e7a8625e75c6aa916004db931', + 'pretty_version' => '1.1.3', + 'version' => '1.1.3.0', + 'reference' => 'dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/deprecations', 'aliases' => array(), @@ -283,7 +292,7 @@ 'pandorafms/console' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => 'b35af80afb452f53ceb175793f2827286508e2df', + 'reference' => '8bf414b51f3333555f84df8b23614ca4b68c7fd4', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -420,6 +429,30 @@ 'aliases' => array(), 'dev_requirement' => false, ), + 'ramsey/collection' => array( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'reference' => 'a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ramsey/collection', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ramsey/uuid' => array( + 'pretty_version' => '4.7.5', + 'version' => '4.7.5.0', + 'reference' => '5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ramsey/uuid', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'rhumsaa/uuid' => array( + 'dev_requirement' => false, + 'replaced' => array( + 0 => '4.7.5', + ), + ), 'setasign/fpdi' => array( 'pretty_version' => 'v2.6.0', 'version' => '2.6.0.0', @@ -466,9 +499,9 @@ 'dev_requirement' => false, ), 'symfony/filesystem' => array( - 'pretty_version' => 'v7.0.0', - 'version' => '7.0.0.0', - 'reference' => '7da8ea2362a283771478c5f7729cfcb43a76b8b7', + 'pretty_version' => 'v7.0.3', + 'version' => '7.0.3.0', + 'reference' => '2890e3a825bc0c0558526c04499c13f83e1b6b12', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), @@ -547,9 +580,9 @@ 'dev_requirement' => false, ), 'symfony/process' => array( - 'pretty_version' => 'v7.0.2', - 'version' => '7.0.2.0', - 'reference' => 'acd3eb5cb02382c1cb0287ba29b2908cc6ffa83a', + 'pretty_version' => 'v7.0.3', + 'version' => '7.0.3.0', + 'reference' => '937a195147e0c27b2759ade834169ed006d0bc74', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), @@ -565,9 +598,9 @@ 'dev_requirement' => false, ), 'symfony/yaml' => array( - 'pretty_version' => 'v7.0.0', - 'version' => '7.0.0.0', - 'reference' => '0055b230c408428b9b5cde7c55659555be5c0278', + 'pretty_version' => 'v7.0.3', + 'version' => '7.0.3.0', + 'reference' => '2d4fca631c00700597e9442a0b2451ce234513d3', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/yaml', 'aliases' => array(), diff --git a/pandora_console/vendor/ramsey/collection/LICENSE b/pandora_console/vendor/ramsey/collection/LICENSE new file mode 100644 index 0000000000..a7fcf1201e --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2022 Ben Ramsey + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/pandora_console/vendor/ramsey/collection/README.md b/pandora_console/vendor/ramsey/collection/README.md new file mode 100644 index 0000000000..c77ffcb185 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/README.md @@ -0,0 +1,70 @@ +

ramsey/collection

+ +

+ A PHP library for representing and manipulating collections. +

+ +

+ Source Code + Download Package + PHP Programming Language + Read License + Build Status + Codecov Code Coverage + Psalm Type Coverage +

+ +## 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 library may be found in the +[Wiki pages](https://github.com/ramsey/collection/wiki/Examples). + +## Contributing + +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. + +## 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/main/SECURITY.md diff --git a/pandora_console/vendor/ramsey/collection/SECURITY.md b/pandora_console/vendor/ramsey/collection/SECURITY.md new file mode 100644 index 0000000000..3de4c0cbdb --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/SECURITY.md @@ -0,0 +1,169 @@ + + +# Vulnerability Disclosure Policy (VDP) + +## Brand Promise + + + +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 +message using the following public 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----- +``` diff --git a/pandora_console/vendor/ramsey/collection/composer.json b/pandora_console/vendor/ramsey/collection/composer.json new file mode 100644 index 0000000000..56709015a4 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/composer.json @@ -0,0 +1,119 @@ +{ + "name": "ramsey/collection", + "description": "A PHP library for representing and manipulating collections.", + "license": "MIT", + "type": "library", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.28.3", + "fakerphp/faker": "^1.21", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^1.0", + "mockery/mockery": "^1.5", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpcsstandards/phpcsutils": "^1.0.0-rc1", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5", + "psalm/plugin-mockery": "^1.1", + "psalm/plugin-phpunit": "^0.18.4", + "ramsey/coding-standard": "^2.0.3", + "ramsey/conventional-commits": "^1.3", + "vimeo/psalm": "^5.4" + }, + "minimum-stability": "RC", + "prefer-stable": true, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Ramsey\\Collection\\Test\\": "tests/", + "Ramsey\\Test\\Generics\\": "tests/generics/" + }, + "files": [ + "vendor/hamcrest/hamcrest-php/hamcrest/Hamcrest.php" + ] + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "ergebnis/composer-normalize": true, + "phpstan/extension-installer": true, + "captainhook/plugin-composer": true + }, + "sort-packages": true + }, + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "scripts": { + "dev:analyze": [ + "@dev:analyze:phpstan", + "@dev:analyze:psalm" + ], + "dev:analyze:phpstan": "phpstan analyse --ansi --memory-limit=1G", + "dev:analyze:psalm": "psalm", + "dev:build:clean": "git clean -fX build/", + "dev:lint": [ + "@dev:lint:syntax", + "@dev:lint:style" + ], + "dev:lint:fix": "phpcbf", + "dev:lint:style": "phpcs --colors", + "dev:lint:syntax": "parallel-lint --colors src/ tests/", + "dev:test": [ + "@dev:lint", + "@dev:analyze", + "@dev:test:unit" + ], + "dev:test:coverage:ci": "phpunit --colors=always --coverage-text --coverage-clover build/coverage/clover.xml --coverage-cobertura build/coverage/cobertura.xml --coverage-crap4j build/coverage/crap4j.xml --coverage-xml build/coverage/coverage-xml --log-junit build/junit.xml", + "dev:test:coverage:html": "phpunit --colors=always --coverage-html build/coverage/coverage-html/", + "dev:test:unit": "phpunit --colors=always", + "test": "@dev:test" + }, + "scripts-descriptions": { + "dev:analyze": "Runs all static analysis checks.", + "dev:analyze:phpstan": "Runs the PHPStan static analyzer.", + "dev:analyze:psalm": "Runs the Psalm static analyzer.", + "dev:build:clean": "Cleans the build/ directory.", + "dev:lint": "Runs all linting checks.", + "dev:lint:fix": "Auto-fixes coding standards issues, if possible.", + "dev:lint:style": "Checks for coding standards issues.", + "dev:lint:syntax": "Checks for syntax errors.", + "dev:test": "Runs linting, static analysis, and unit tests.", + "dev:test:coverage:ci": "Runs unit tests and generates CI coverage reports.", + "dev:test:coverage:html": "Runs unit tests and generates HTML coverage report.", + "dev:test:unit": "Runs unit tests.", + "test": "Runs linting, static analysis, and unit tests." + } +} diff --git a/pandora_console/vendor/ramsey/collection/conventional-commits.json b/pandora_console/vendor/ramsey/collection/conventional-commits.json new file mode 100644 index 0000000000..5fe21d2fad --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/conventional-commits.json @@ -0,0 +1,22 @@ +{ + "typeCase": "kebab", + "types": [ + "chore", + "ci", + "docs", + "feat", + "fix", + "refactor", + "security", + "style", + "test" + ], + "scopeCase": "kebab", + "scopeRequired": false, + "scopes": [], + "descriptionCase": null, + "descriptionEndMark": "", + "bodyRequired": false, + "bodyWrapWidth": 72, + "requiredFooters": [] +} diff --git a/pandora_console/vendor/ramsey/collection/src/AbstractArray.php b/pandora_console/vendor/ramsey/collection/src/AbstractArray.php new file mode 100644 index 0000000000..5ce622aa79 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/AbstractArray.php @@ -0,0 +1,171 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection; + +use ArrayIterator; +use Traversable; + +use function count; + +/** + * This class provides a basic implementation of `ArrayInterface`, to minimize + * the effort required to implement this interface. + * + * @template T + * @implements ArrayInterface + */ +abstract class AbstractArray implements ArrayInterface +{ + /** + * The items of this array. + * + * @var array + */ + protected array $data = []; + + /** + * Constructs a new array object. + * + * @param array $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 + */ + 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(mixed $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 the value stored at the offset, or null if the offset + * does not exist. + */ + public function offsetGet(mixed $offset): mixed + { + return $this->data[$offset]; + } + + /** + * 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. + */ + public function offsetSet(mixed $offset, mixed $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(mixed $offset): void + { + unset($this->data[$offset]); + } + + /** + * 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 + */ + public function __serialize(): array + { + return $this->data; + } + + /** + * Adds unserialized data to the object. + * + * @param array $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 $this->data === []; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/AbstractCollection.php b/pandora_console/vendor/ramsey/collection/src/AbstractCollection.php new file mode 100644 index 0000000000..8cb21ec022 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/AbstractCollection.php @@ -0,0 +1,393 @@ + + * @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\InvalidPropertyOrMethod; +use Ramsey\Collection\Exception\NoSuchElementException; +use Ramsey\Collection\Exception\UnsupportedOperationException; +use Ramsey\Collection\Tool\TypeTrait; +use Ramsey\Collection\Tool\ValueExtractorTrait; +use Ramsey\Collection\Tool\ValueToStringTrait; + +use function array_filter; +use function array_key_first; +use function array_key_last; +use function array_map; +use function array_merge; +use function array_reduce; +use function array_search; +use function array_udiff; +use function array_uintersect; +use function in_array; +use function is_int; +use function is_object; +use function spl_object_id; +use function sprintf; +use function usort; + +/** + * This class provides a basic implementation of `CollectionInterface`, to + * minimize the effort required to implement this interface + * + * @template T + * @extends AbstractArray + * @implements CollectionInterface + */ +abstract class AbstractCollection extends AbstractArray implements CollectionInterface +{ + use TypeTrait; + use ValueToStringTrait; + use ValueExtractorTrait; + + /** + * @throws InvalidArgumentException if $element is of the wrong type. + */ + public function add(mixed $element): bool + { + $this[] = $element; + + return true; + } + + public function contains(mixed $element, bool $strict = true): bool + { + return in_array($element, $this->data, $strict); + } + + /** + * @throws InvalidArgumentException if $element is of the wrong type. + */ + public function offsetSet(mixed $offset, mixed $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; + } + } + + public function remove(mixed $element): bool + { + if (($position = array_search($element, $this->data, true)) !== false) { + unset($this[$position]); + + return true; + } + + return false; + } + + /** + * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist + * on the elements in this collection. + * @throws UnsupportedOperationException if unable to call column() on this + * collection. + * + * @inheritDoc + */ + public function column(string $propertyOrMethod): array + { + $temp = []; + + foreach ($this->data as $item) { + /** @psalm-suppress MixedAssignment */ + $temp[] = $this->extractValue($item, $propertyOrMethod); + } + + return $temp; + } + + /** + * @return T + * + * @throws NoSuchElementException if this collection is empty. + */ + public function first(): mixed + { + $firstIndex = array_key_first($this->data); + + if ($firstIndex === null) { + throw new NoSuchElementException('Can\'t determine first item. Collection is empty'); + } + + return $this->data[$firstIndex]; + } + + /** + * @return T + * + * @throws NoSuchElementException if this collection is empty. + */ + public function last(): mixed + { + $lastIndex = array_key_last($this->data); + + if ($lastIndex === null) { + throw new NoSuchElementException('Can\'t determine last item. Collection is empty'); + } + + return $this->data[$lastIndex]; + } + + /** + * @return CollectionInterface + * + * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist + * on the elements in this collection. + * @throws UnsupportedOperationException if unable to call sort() on this + * collection. + */ + public function sort(?string $propertyOrMethod = null, Sort $order = Sort::Ascending): CollectionInterface + { + $collection = clone $this; + + usort( + $collection->data, + /** + * @param T $a + * @param T $b + */ + function (mixed $a, mixed $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 === Sort::Descending ? -1 : 1); + }, + ); + + return $collection; + } + + /** + * @param callable(T): bool $callback A callable to use for filtering elements. + * + * @return CollectionInterface + */ + public function filter(callable $callback): CollectionInterface + { + $collection = clone $this; + $collection->data = array_merge([], array_filter($collection->data, $callback)); + + return $collection; + } + + /** + * @return CollectionInterface + * + * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist + * on the elements in this collection. + * @throws UnsupportedOperationException if unable to call where() on this + * collection. + */ + public function where(?string $propertyOrMethod, mixed $value): CollectionInterface + { + return $this->filter( + /** + * @param T $item + */ + function (mixed $item) use ($propertyOrMethod, $value): bool { + /** @var mixed $accessorValue */ + $accessorValue = $this->extractValue($item, $propertyOrMethod); + + return $accessorValue === $value; + }, + ); + } + + /** + * @param callable(T): TCallbackReturn $callback A callable to apply to each + * item of the collection. + * + * @return CollectionInterface + * + * @template TCallbackReturn + */ + public function map(callable $callback): CollectionInterface + { + /** @var Collection */ + return new Collection('mixed', array_map($callback, $this->data)); + } + + /** + * @param callable(TCarry, T): TCarry $callback A callable to apply to each + * item of the collection to reduce it to a single value. + * @param TCarry $initial This is the initial value provided to the callback. + * + * @return TCarry + * + * @template TCarry + */ + public function reduce(callable $callback, mixed $initial): mixed + { + /** @var TCarry */ + return array_reduce($this->data, $callback, $initial); + } + + /** + * @param CollectionInterface $other The collection to check for divergent + * items. + * + * @return CollectionInterface + * + * @throws CollectionMismatchException if the compared collections are of + * differing types. + */ + 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 $diff */ + $diff = array_merge($diffAtoB, $diffBtoA); + + $collection = clone $this; + $collection->data = $diff; + + return $collection; + } + + /** + * @param CollectionInterface $other The collection to check for + * intersecting items. + * + * @return CollectionInterface + * + * @throws CollectionMismatchException if the compared collections are of + * differing types. + */ + public function intersect(CollectionInterface $other): CollectionInterface + { + $this->compareCollectionTypes($other); + + /** @var array $intersect */ + $intersect = array_uintersect($this->data, $other->toArray(), $this->getComparator()); + + $collection = clone $this; + $collection->data = $intersect; + + return $collection; + } + + /** + * @param CollectionInterface ...$collections The collections to merge. + * + * @return CollectionInterface + * + * @throws CollectionMismatchException if unable to merge any of the given + * collections or items within the given collections due to type + * mismatch errors. + */ + 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 ($this->getUniformType($collection) !== $this->getUniformType($this)) { + 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; + } + + /** + * @param CollectionInterface $other + * + * @throws CollectionMismatchException + */ + 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 ($this->getUniformType($other) !== $this->getUniformType($this)) { + throw new CollectionMismatchException('Collection items must be of type ' . $this->getType()); + } + } + + private function getComparator(): Closure + { + return /** + * @param T $a + * @param T $b + */ + function (mixed $a, mixed $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); + }; + } + + /** + * @param CollectionInterface $collection + */ + private function getUniformType(CollectionInterface $collection): string + { + return match ($collection->getType()) { + 'integer' => 'int', + 'boolean' => 'bool', + 'double' => 'float', + default => $collection->getType(), + }; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/AbstractSet.php b/pandora_console/vendor/ramsey/collection/src/AbstractSet.php new file mode 100644 index 0000000000..7186939d7e --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/AbstractSet.php @@ -0,0 +1,44 @@ + + * @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 + */ +abstract class AbstractSet extends AbstractCollection +{ + public function add(mixed $element): bool + { + if ($this->contains($element)) { + return false; + } + + return parent::add($element); + } + + public function offsetSet(mixed $offset, mixed $value): void + { + if ($this->contains($value)) { + return; + } + + parent::offsetSet($offset, $value); + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/ArrayInterface.php b/pandora_console/vendor/ramsey/collection/src/ArrayInterface.php new file mode 100644 index 0000000000..bc7f6f4240 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/ArrayInterface.php @@ -0,0 +1,49 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection; + +use ArrayAccess; +use Countable; +use IteratorAggregate; + +/** + * `ArrayInterface` provides traversable array functionality to data types. + * + * @template T + * @extends ArrayAccess + * @extends IteratorAggregate + */ +interface ArrayInterface extends + ArrayAccess, + Countable, + IteratorAggregate +{ + /** + * Removes all items from this array. + */ + public function clear(): void; + + /** + * Returns a native PHP array representation of this array object. + * + * @return array + */ + public function toArray(): array; + + /** + * Returns `true` if this array is empty. + */ + public function isEmpty(): bool; +} diff --git a/pandora_console/vendor/ramsey/collection/src/Collection.php b/pandora_console/vendor/ramsey/collection/src/Collection.php new file mode 100644 index 0000000000..44d26bf2e9 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Collection.php @@ -0,0 +1,95 @@ + + * @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 + */ +class Collection extends AbstractCollection +{ + /** + * Constructs a collection object of the specified type, optionally with the + * specified data. + * + * @param string $collectionType The type or class name associated with this + * collection. + * @param array $data The initial items to store in the collection. + */ + public function __construct(private readonly string $collectionType, array $data = []) + { + parent::__construct($data); + } + + public function getType(): string + { + return $this->collectionType; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/CollectionInterface.php b/pandora_console/vendor/ramsey/collection/src/CollectionInterface.php new file mode 100644 index 0000000000..e3ad014701 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/CollectionInterface.php @@ -0,0 +1,253 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection; + +use Ramsey\Collection\Exception\CollectionMismatchException; +use Ramsey\Collection\Exception\InvalidArgumentException; +use Ramsey\Collection\Exception\InvalidPropertyOrMethod; +use Ramsey\Collection\Exception\NoSuchElementException; +use Ramsey\Collection\Exception\UnsupportedOperationException; + +/** + * A collection represents a group of values, known as its elements. + * + * Some collections allow duplicate elements and others do not. Some are ordered + * and others unordered. + * + * @template T + * @extends ArrayInterface + */ +interface CollectionInterface extends ArrayInterface +{ + /** + * 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. + * + * @throws InvalidArgumentException if the collection refuses to add the + * $element for any reason other than that it already contains the element. + */ + public function add(mixed $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. + */ + public function contains(mixed $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. + */ + public function remove(mixed $element): bool; + + /** + * Returns the values from the given property, method, or array key. + * + * @param string $propertyOrMethod The name of the property, method, or + * array key to evaluate and return. + * + * @return array + * + * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist + * on the elements in this collection. + * @throws UnsupportedOperationException if unable to call column() on this + * collection. + */ + public function column(string $propertyOrMethod): array; + + /** + * Returns the first item of the collection. + * + * @return T + * + * @throws NoSuchElementException if this collection is empty. + */ + public function first(): mixed; + + /** + * Returns the last item of the collection. + * + * @return T + * + * @throws NoSuchElementException if this collection is empty. + */ + public function last(): mixed; + + /** + * Sort the collection by a property, method, or array key with the given + * sort order. + * + * If $propertyOrMethod is `null`, this will sort by comparing each element. + * + * This will always leave the original collection untouched and will return + * a new one. + * + * @param string | null $propertyOrMethod The property, method, or array key + * to sort by. + * @param Sort $order The sort order for the resulting collection. + * + * @return CollectionInterface + * + * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist + * on the elements in this collection. + * @throws UnsupportedOperationException if unable to call sort() on this + * collection. + */ + public function sort(?string $propertyOrMethod = null, Sort $order = Sort::Ascending): 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 + */ + public function filter(callable $callback): self; + + /** + * Create a new collection where the result of the given property, method, + * or array key of each item in the collection equals the given value. + * + * This will always leave the original collection untouched and will return + * a new one. + * + * @param string | null $propertyOrMethod The property, method, or array key + * to evaluate. If `null`, the element itself is compared to $value. + * @param mixed $value The value to match. + * + * @return CollectionInterface + * + * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist + * on the elements in this collection. + * @throws UnsupportedOperationException if unable to call where() on this + * collection. + */ + public function where(?string $propertyOrMethod, mixed $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 + * + * @template TCallbackReturn + */ + public function map(callable $callback): self; + + /** + * Apply a given callback method on each item of the collection + * to reduce it to a single value. + * + * See the {@link http://php.net/manual/en/function.array-reduce.php PHP array_reduce() documentation} + * for examples of how the `$callback` and `$initial` parameters work. + * + * @param callable(TCarry, T): TCarry $callback A callable to apply to each + * item of the collection to reduce it to a single value. + * @param TCarry $initial This is the initial value provided to the callback. + * + * @return TCarry + * + * @template TCarry + */ + public function reduce(callable $callback, mixed $initial): mixed; + + /** + * Create a new collection with divergent items between current and given + * collection. + * + * @param CollectionInterface $other The collection to check for divergent + * items. + * + * @return CollectionInterface + * + * @throws CollectionMismatchException if the compared collections are of + * differing types. + */ + public function diff(CollectionInterface $other): self; + + /** + * Create a new collection with intersecting item between current and given + * collection. + * + * @param CollectionInterface $other The collection to check for + * intersecting items. + * + * @return CollectionInterface + * + * @throws CollectionMismatchException if the compared collections are of + * differing types. + */ + public function intersect(CollectionInterface $other): self; + + /** + * Merge current items and items of given collections into a new one. + * + * @param CollectionInterface ...$collections The collections to merge. + * + * @return CollectionInterface + * + * @throws CollectionMismatchException if unable to merge any of the given + * collections or items within the given collections due to type + * mismatch errors. + */ + public function merge(CollectionInterface ...$collections): self; +} diff --git a/pandora_console/vendor/ramsey/collection/src/DoubleEndedQueue.php b/pandora_console/vendor/ramsey/collection/src/DoubleEndedQueue.php new file mode 100644 index 0000000000..62947a24f7 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/DoubleEndedQueue.php @@ -0,0 +1,166 @@ + + * @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 function array_key_last; +use function array_pop; +use function array_unshift; + +/** + * This class provides a basic implementation of `DoubleEndedQueueInterface`, to + * minimize the effort required to implement this interface. + * + * @template T + * @extends Queue + * @implements DoubleEndedQueueInterface + */ +class DoubleEndedQueue extends Queue implements DoubleEndedQueueInterface +{ + /** + * Constructs a double-ended queue (dequeue) object of the specified type, + * optionally with the specified data. + * + * @param string $queueType The type or class name associated with this dequeue. + * @param array $data The initial items to store in the dequeue. + */ + public function __construct(private readonly string $queueType, array $data = []) + { + parent::__construct($this->queueType, $data); + } + + /** + * @throws InvalidArgumentException if $element is of the wrong type + */ + public function addFirst(mixed $element): bool + { + if ($this->checkType($this->getType(), $element) === false) { + throw new InvalidArgumentException( + 'Value must be of type ' . $this->getType() . '; value is ' + . $this->toolValueToString($element), + ); + } + + array_unshift($this->data, $element); + + return true; + } + + /** + * @throws InvalidArgumentException if $element is of the wrong type + */ + public function addLast(mixed $element): bool + { + return $this->add($element); + } + + public function offerFirst(mixed $element): bool + { + try { + return $this->addFirst($element); + } catch (InvalidArgumentException) { + return false; + } + } + + public function offerLast(mixed $element): bool + { + return $this->offer($element); + } + + /** + * @return T the first element in this queue. + * + * @throws NoSuchElementException if the queue is empty + */ + public function removeFirst(): mixed + { + return $this->remove(); + } + + /** + * @return T the last element in this queue. + * + * @throws NoSuchElementException if this queue is empty. + */ + public function removeLast(): mixed + { + return $this->pollLast() ?? throw new NoSuchElementException( + 'Can\'t return element from Queue. Queue is empty.', + ); + } + + /** + * @return T | null the head of this queue, or `null` if this queue is empty. + */ + public function pollFirst(): mixed + { + return $this->poll(); + } + + /** + * @return T | null the tail of this queue, or `null` if this queue is empty. + */ + public function pollLast(): mixed + { + return array_pop($this->data); + } + + /** + * @return T the head of this queue. + * + * @throws NoSuchElementException if this queue is empty. + */ + public function firstElement(): mixed + { + return $this->element(); + } + + /** + * @return T the tail of this queue. + * + * @throws NoSuchElementException if this queue is empty. + */ + public function lastElement(): mixed + { + return $this->peekLast() ?? throw new NoSuchElementException( + 'Can\'t return element from Queue. Queue is empty.', + ); + } + + /** + * @return T | null the head of this queue, or `null` if this queue is empty. + */ + public function peekFirst(): mixed + { + return $this->peek(); + } + + /** + * @return T | null the tail of this queue, or `null` if this queue is empty. + */ + public function peekLast(): mixed + { + $lastIndex = array_key_last($this->data); + + if ($lastIndex === null) { + return null; + } + + return $this->data[$lastIndex]; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/DoubleEndedQueueInterface.php b/pandora_console/vendor/ramsey/collection/src/DoubleEndedQueueInterface.php new file mode 100644 index 0000000000..15cc0e97b7 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/DoubleEndedQueueInterface.php @@ -0,0 +1,313 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection; + +use Ramsey\Collection\Exception\NoSuchElementException; +use RuntimeException; + +/** + * 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: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Summary of DoubleEndedQueueInterface methods
First Element (Head)Last Element (Tail)
Throws exceptionSpecial valueThrows exceptionSpecial value
InsertaddFirst()offerFirst()addLast()offerLast()
RemoveremoveFirst()pollFirst()removeLast()pollLast()
ExaminefirstElement()peekFirst()lastElement()peekLast()
+ * + * 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: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Comparison of QueueInterface and DoubleEndedQueueInterface methods
QueueInterface MethodDoubleEndedQueueInterface Method
add()addLast()
offer()offerLast()
remove()removeFirst()
poll()pollFirst()
element()firstElement()
peek()peekFirst()
+ * + * 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: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Comparison of stack concepts and DoubleEndedQueueInterface methods
Stack conceptDoubleEndedQueueInterface Method
pushaddFirst()
popremoveFirst()
peekpeekFirst()
+ * + * 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 + */ +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`. + */ + public function addFirst(mixed $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`. + */ + public function addLast(mixed $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`. + */ + public function offerFirst(mixed $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`. + */ + public function offerLast(mixed $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(): mixed; + + /** + * 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(): mixed; + + /** + * 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(): mixed; + + /** + * 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(): mixed; + + /** + * 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(): mixed; + + /** + * 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(): mixed; + + /** + * 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(): mixed; + + /** + * 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(): mixed; +} diff --git a/pandora_console/vendor/ramsey/collection/src/Exception/CollectionException.php b/pandora_console/vendor/ramsey/collection/src/Exception/CollectionException.php new file mode 100644 index 0000000000..4aa92bed8d --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Exception/CollectionException.php @@ -0,0 +1,21 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Exception; + +use Throwable; + +interface CollectionException extends Throwable +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Exception/CollectionMismatchException.php b/pandora_console/vendor/ramsey/collection/src/Exception/CollectionMismatchException.php new file mode 100644 index 0000000000..42f5be2dfa --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Exception/CollectionMismatchException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Exception; + +use RuntimeException; + +/** + * Thrown when attempting to operate on collections of differing types. + */ +class CollectionMismatchException extends RuntimeException implements CollectionException +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Exception/InvalidArgumentException.php b/pandora_console/vendor/ramsey/collection/src/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..7b41b4a7c6 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Exception/InvalidArgumentException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Exception; + +use InvalidArgumentException as PhpInvalidArgumentException; + +/** + * Thrown to indicate an argument is not of the expected type. + */ +class InvalidArgumentException extends PhpInvalidArgumentException implements CollectionException +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Exception/InvalidPropertyOrMethod.php b/pandora_console/vendor/ramsey/collection/src/Exception/InvalidPropertyOrMethod.php new file mode 100644 index 0000000000..a53be14aab --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Exception/InvalidPropertyOrMethod.php @@ -0,0 +1,26 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Exception; + +use RuntimeException; + +/** + * Thrown when attempting to evaluate a property, method, or array key + * that doesn't exist on an element or cannot otherwise be evaluated in the + * current context. + */ +class InvalidPropertyOrMethod extends RuntimeException implements CollectionException +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Exception/NoSuchElementException.php b/pandora_console/vendor/ramsey/collection/src/Exception/NoSuchElementException.php new file mode 100644 index 0000000000..cd98f0c0f9 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Exception/NoSuchElementException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Exception; + +use RuntimeException; + +/** + * Thrown when attempting to access an element that does not exist. + */ +class NoSuchElementException extends RuntimeException implements CollectionException +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Exception/OutOfBoundsException.php b/pandora_console/vendor/ramsey/collection/src/Exception/OutOfBoundsException.php new file mode 100644 index 0000000000..c75294e53b --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Exception/OutOfBoundsException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Exception; + +use OutOfBoundsException as PhpOutOfBoundsException; + +/** + * Thrown when attempting to access an element out of the range of the collection. + */ +class OutOfBoundsException extends PhpOutOfBoundsException implements CollectionException +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Exception/UnsupportedOperationException.php b/pandora_console/vendor/ramsey/collection/src/Exception/UnsupportedOperationException.php new file mode 100644 index 0000000000..d074f45fda --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Exception/UnsupportedOperationException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Exception; + +use RuntimeException; + +/** + * Thrown to indicate that the requested operation is not supported. + */ +class UnsupportedOperationException extends RuntimeException implements CollectionException +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/GenericArray.php b/pandora_console/vendor/ramsey/collection/src/GenericArray.php new file mode 100644 index 0000000000..2b079aa5e5 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/GenericArray.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection; + +/** + * `GenericArray` represents a standard array object. + * + * @extends AbstractArray + */ +class GenericArray extends AbstractArray +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Map/AbstractMap.php b/pandora_console/vendor/ramsey/collection/src/Map/AbstractMap.php new file mode 100644 index 0000000000..7a851a80f5 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Map/AbstractMap.php @@ -0,0 +1,203 @@ + + * @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 Traversable; + +use function array_key_exists; +use function array_keys; +use function in_array; +use function var_export; + +/** + * This class provides a basic implementation of `MapInterface`, to minimize the + * effort required to implement this interface. + * + * @template K of array-key + * @template T + * @extends AbstractArray + * @implements MapInterface + */ +abstract class AbstractMap extends AbstractArray implements MapInterface +{ + /** + * @param array $data The initial items to add to this map. + */ + public function __construct(array $data = []) + { + parent::__construct($data); + } + + /** + * @return Traversable + */ + public function getIterator(): Traversable + { + return parent::getIterator(); + } + + /** + * @param K $offset The offset to set + * @param T $value The value to set at the given offset. + * + * @inheritDoc + * @psalm-suppress MoreSpecificImplementedParamType,DocblockTypeContradiction + */ + public function offsetSet(mixed $offset, mixed $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; + } + + public function containsKey(int | string $key): bool + { + return array_key_exists($key, $this->data); + } + + public function containsValue(mixed $value): bool + { + return in_array($value, $this->data, true); + } + + /** + * @inheritDoc + */ + public function keys(): array + { + return array_keys($this->data); + } + + /** + * @param K $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. + */ + public function get(int | string $key, mixed $defaultValue = null): mixed + { + return $this[$key] ?? $defaultValue; + } + + /** + * @param K $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`. + */ + public function put(int | string $key, mixed $value): mixed + { + $previousValue = $this->get($key); + $this[$key] = $value; + + return $previousValue; + } + + /** + * @param K $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`. + */ + public function putIfAbsent(int | string $key, mixed $value): mixed + { + $currentValue = $this->get($key); + + if ($currentValue === null) { + $this[$key] = $value; + } + + return $currentValue; + } + + /** + * @param K $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`. + */ + public function remove(int | string $key): mixed + { + $previousValue = $this->get($key); + unset($this[$key]); + + return $previousValue; + } + + public function removeIf(int | string $key, mixed $value): bool + { + if ($this->get($key) === $value) { + unset($this[$key]); + + return true; + } + + return false; + } + + /** + * @param K $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`. + */ + public function replace(int | string $key, mixed $value): mixed + { + $currentValue = $this->get($key); + + if ($this->containsKey($key)) { + $this[$key] = $value; + } + + return $currentValue; + } + + public function replaceIf(int | string $key, mixed $oldValue, mixed $newValue): bool + { + if ($this->get($key) === $oldValue) { + $this[$key] = $newValue; + + return true; + } + + return false; + } + + /** + * @return array + */ + public function __serialize(): array + { + return parent::__serialize(); + } + + /** + * @return array + */ + public function toArray(): array + { + return parent::toArray(); + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/Map/AbstractTypedMap.php b/pandora_console/vendor/ramsey/collection/src/Map/AbstractTypedMap.php new file mode 100644 index 0000000000..92fdcd54c7 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Map/AbstractTypedMap.php @@ -0,0 +1,60 @@ + + * @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 of array-key + * @template T + * @extends AbstractMap + * @implements TypedMapInterface + */ +abstract class AbstractTypedMap extends AbstractMap implements TypedMapInterface +{ + use TypeTrait; + use ValueToStringTrait; + + /** + * @param K $offset + * @param T $value + * + * @inheritDoc + * @psalm-suppress MoreSpecificImplementedParamType + */ + public function offsetSet(mixed $offset, mixed $value): void + { + 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), + ); + } + + parent::offsetSet($offset, $value); + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/Map/AssociativeArrayMap.php b/pandora_console/vendor/ramsey/collection/src/Map/AssociativeArrayMap.php new file mode 100644 index 0000000000..34e4e853bd --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Map/AssociativeArrayMap.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Map; + +/** + * `AssociativeArrayMap` represents a standard associative array object. + * + * @extends AbstractMap + */ +class AssociativeArrayMap extends AbstractMap +{ +} diff --git a/pandora_console/vendor/ramsey/collection/src/Map/MapInterface.php b/pandora_console/vendor/ramsey/collection/src/Map/MapInterface.php new file mode 100644 index 0000000000..22ba1bdd14 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Map/MapInterface.php @@ -0,0 +1,142 @@ + + * @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 K of array-key + * @template T + * @extends ArrayInterface + */ +interface MapInterface extends ArrayInterface +{ + /** + * Returns `true` if this map contains a mapping for the specified key. + * + * @param K $key The key to check in the map. + */ + public function containsKey(int | string $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. + */ + public function containsValue(mixed $value): bool; + + /** + * Return an array of the keys contained in this map. + * + * @return list + */ + 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 K $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. + */ + public function get(int | string $key, mixed $defaultValue = null): mixed; + + /** + * 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 K $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`. + */ + public function put(int | string $key, mixed $value): mixed; + + /** + * 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 K $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`. + */ + public function putIfAbsent(int | string $key, mixed $value): mixed; + + /** + * Removes the mapping for a key from this map if it is present. + * + * @param K $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`. + */ + public function remove(int | string $key): mixed; + + /** + * 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 K $key The key to remove from the map. + * @param T $value The value to match. + * + * @return bool true if the value was removed. + */ + public function removeIf(int | string $key, mixed $value): bool; + + /** + * Replaces the entry for the specified key only if it is currently mapped + * to some value. + * + * @param K $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`. + */ + public function replace(int | string $key, mixed $value): mixed; + + /** + * 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 K $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. + */ + public function replaceIf(int | string $key, mixed $oldValue, mixed $newValue): bool; +} diff --git a/pandora_console/vendor/ramsey/collection/src/Map/NamedParameterMap.php b/pandora_console/vendor/ramsey/collection/src/Map/NamedParameterMap.php new file mode 100644 index 0000000000..f948e476ce --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Map/NamedParameterMap.php @@ -0,0 +1,110 @@ + + * @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 + */ +class NamedParameterMap extends AbstractMap +{ + use TypeTrait; + use ValueToStringTrait; + + /** + * Named parameters defined for this map. + * + * @var array + */ + private readonly array $namedParameters; + + /** + * Constructs a new `NamedParameterMap`. + * + * @param array $namedParameters The named parameters defined for this map. + * @param array $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 + */ + public function getNamedParameters(): array + { + return $this->namedParameters; + } + + public function offsetSet(mixed $offset, mixed $value): void + { + if (!array_key_exists($offset, $this->namedParameters)) { + throw new InvalidArgumentException( + 'Attempting to set value for unconfigured parameter \'' + . $this->toolValueToString($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 $namedParameters The named parameters to filter. + * + * @return array + */ + 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) ?: []; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/Map/TypedMap.php b/pandora_console/vendor/ramsey/collection/src/Map/TypedMap.php new file mode 100644 index 0000000000..f914d9c702 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Map/TypedMap.php @@ -0,0 +1,112 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Map; + +/** + * 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 of array-key + * @template T + * @extends AbstractTypedMap + */ +class TypedMap extends AbstractTypedMap +{ + /** + * 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 $data The initial data to set for this map. + */ + public function __construct( + private readonly string $keyType, + private readonly string $valueType, + array $data = [], + ) { + parent::__construct($data); + } + + public function getKeyType(): string + { + return $this->keyType; + } + + public function getValueType(): string + { + return $this->valueType; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/Map/TypedMapInterface.php b/pandora_console/vendor/ramsey/collection/src/Map/TypedMapInterface.php new file mode 100644 index 0000000000..5a44f0647c --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Map/TypedMapInterface.php @@ -0,0 +1,36 @@ + + * @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 K of array-key + * @template T + * @extends MapInterface + */ +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; +} diff --git a/pandora_console/vendor/ramsey/collection/src/Queue.php b/pandora_console/vendor/ramsey/collection/src/Queue.php new file mode 100644 index 0000000000..0f5b337409 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Queue.php @@ -0,0 +1,148 @@ + + * @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; + +use function array_key_first; + +/** + * This class provides a basic implementation of `QueueInterface`, to minimize + * the effort required to implement this interface. + * + * @template T + * @extends AbstractArray + * @implements QueueInterface + */ +class Queue extends AbstractArray implements QueueInterface +{ + use TypeTrait; + use ValueToStringTrait; + + /** + * Constructs a queue object of the specified type, optionally with the + * specified data. + * + * @param string $queueType The type or class name associated with this queue. + * @param array $data The initial items to store in the queue. + */ + public function __construct(private readonly string $queueType, array $data = []) + { + 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. + * + * @throws InvalidArgumentException if $value is of the wrong type. + */ + public function offsetSet(mixed $offset, mixed $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; + } + + /** + * @throws InvalidArgumentException if $value is of the wrong type. + */ + public function add(mixed $element): bool + { + $this[] = $element; + + return true; + } + + /** + * @return T + * + * @throws NoSuchElementException if this queue is empty. + */ + public function element(): mixed + { + return $this->peek() ?? throw new NoSuchElementException( + 'Can\'t return element from Queue. Queue is empty.', + ); + } + + public function offer(mixed $element): bool + { + try { + return $this->add($element); + } catch (InvalidArgumentException) { + return false; + } + } + + /** + * @return T | null + */ + public function peek(): mixed + { + $index = array_key_first($this->data); + + if ($index === null) { + return null; + } + + return $this[$index]; + } + + /** + * @return T | null + */ + public function poll(): mixed + { + $index = array_key_first($this->data); + + if ($index === null) { + return null; + } + + $head = $this[$index]; + unset($this[$index]); + + return $head; + } + + /** + * @return T + * + * @throws NoSuchElementException if this queue is empty. + */ + public function remove(): mixed + { + return $this->poll() ?? throw new NoSuchElementException( + 'Can\'t return element from Queue. Queue is empty.', + ); + } + + public function getType(): string + { + return $this->queueType; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/QueueInterface.php b/pandora_console/vendor/ramsey/collection/src/QueueInterface.php new file mode 100644 index 0000000000..f29ce43abd --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/QueueInterface.php @@ -0,0 +1,202 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection; + +use Ramsey\Collection\Exception\NoSuchElementException; +use RuntimeException; + +/** + * 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Summary of QueueInterface methods
Throws exceptionReturns special value
Insertadd()offer()
Removeremove()poll()
Examineelement()peek()
+ * + * 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 + */ +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`. + */ + public function add(mixed $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(): mixed; + + /** + * 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`. + */ + public function offer(mixed $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(): mixed; + + /** + * 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(): mixed; + + /** + * 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(): mixed; + + /** + * Returns the type associated with this queue. + */ + public function getType(): string; +} diff --git a/pandora_console/vendor/ramsey/collection/src/Set.php b/pandora_console/vendor/ramsey/collection/src/Set.php new file mode 100644 index 0000000000..aa93351c46 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Set.php @@ -0,0 +1,59 @@ + + * @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 doesn't exist + * $set->add($foo); // returns FALSE, the element already exists + * + * $bar = new \My\Foo(); + * $set->add($bar); // returns TRUE, $bar !== $foo + * ``` + * + * @template T + * @extends AbstractSet + */ +class Set extends AbstractSet +{ + /** + * Constructs a set object of the specified type, optionally with the + * specified data. + * + * @param string $setType The type or class name associated with this set. + * @param array $data The initial items to store in the set. + */ + public function __construct(private readonly string $setType, array $data = []) + { + parent::__construct($data); + } + + public function getType(): string + { + return $this->setType; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/Sort.php b/pandora_console/vendor/ramsey/collection/src/Sort.php new file mode 100644 index 0000000000..0c3c192131 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Sort.php @@ -0,0 +1,31 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection; + +/** + * Collection sorting + */ +enum Sort: string +{ + /** + * Sort items in a collection in ascending order. + */ + case Ascending = 'asc'; + + /** + * Sort items in a collection in descending order. + */ + case Descending = 'desc'; +} diff --git a/pandora_console/vendor/ramsey/collection/src/Tool/TypeTrait.php b/pandora_console/vendor/ramsey/collection/src/Tool/TypeTrait.php new file mode 100644 index 0000000000..ac51b7f101 --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Tool/TypeTrait.php @@ -0,0 +1,57 @@ + + * @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, mixed $value): bool + { + return match ($type) { + 'array' => is_array($value), + 'bool', 'boolean' => is_bool($value), + 'callable' => is_callable($value), + 'float', 'double' => is_float($value), + 'int', 'integer' => is_int($value), + 'null' => $value === null, + 'numeric' => is_numeric($value), + 'object' => is_object($value), + 'resource' => is_resource($value), + 'scalar' => is_scalar($value), + 'string' => is_string($value), + 'mixed' => true, + default => $value instanceof $type, + }; + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/Tool/ValueExtractorTrait.php b/pandora_console/vendor/ramsey/collection/src/Tool/ValueExtractorTrait.php new file mode 100644 index 0000000000..44c422252b --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Tool/ValueExtractorTrait.php @@ -0,0 +1,81 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Tool; + +use Ramsey\Collection\Exception\InvalidPropertyOrMethod; +use Ramsey\Collection\Exception\UnsupportedOperationException; + +use function is_array; +use function is_object; +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, method, or array key from the + * element. + * + * If `$propertyOrMethod` is `null`, we return the element as-is. + * + * @param mixed $element The element to extract the value from. + * @param string | null $propertyOrMethod The property or method for which the + * value should be extracted. + * + * @return mixed the value extracted from the specified property, method, + * or array key, or the element itself. + * + * @throws InvalidPropertyOrMethod + * @throws UnsupportedOperationException + */ + protected function extractValue(mixed $element, ?string $propertyOrMethod): mixed + { + if ($propertyOrMethod === null) { + return $element; + } + + if (!is_object($element) && !is_array($element)) { + throw new UnsupportedOperationException(sprintf( + 'The collection type "%s" does not support the $propertyOrMethod parameter', + $this->getType(), + )); + } + + if (is_array($element)) { + return $element[$propertyOrMethod] ?? throw new InvalidPropertyOrMethod(sprintf( + 'Key or index "%s" not found in collection elements', + $propertyOrMethod, + )); + } + + if (property_exists($element, $propertyOrMethod)) { + return $element->$propertyOrMethod; + } + + if (method_exists($element, $propertyOrMethod)) { + return $element->{$propertyOrMethod}(); + } + + throw new InvalidPropertyOrMethod(sprintf( + 'Method or property "%s" not defined in %s', + $propertyOrMethod, + $element::class, + )); + } +} diff --git a/pandora_console/vendor/ramsey/collection/src/Tool/ValueToStringTrait.php b/pandora_console/vendor/ramsey/collection/src/Tool/ValueToStringTrait.php new file mode 100644 index 0000000000..64fc5fa42c --- /dev/null +++ b/pandora_console/vendor/ramsey/collection/src/Tool/ValueToStringTrait.php @@ -0,0 +1,91 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Collection\Tool; + +use DateTimeInterface; + +use function assert; +use function get_resource_type; +use function is_array; +use function is_bool; +use function is_callable; +use function is_object; +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(mixed $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 . ')'; + } + + // From here, $value should be an object. + assert(is_object($value)); + + // __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 '(' . $value::class . ' Object)'; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/LICENSE b/pandora_console/vendor/ramsey/uuid/LICENSE new file mode 100644 index 0000000000..5b2acc5b78 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012-2023 Ben Ramsey + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pandora_console/vendor/ramsey/uuid/README.md b/pandora_console/vendor/ramsey/uuid/README.md new file mode 100644 index 0000000000..0db8149593 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/README.md @@ -0,0 +1,83 @@ +

ramsey/uuid

+ +

+ A PHP library for generating and working with UUIDs. +

+ +

+ Source Code + Download Package + PHP Programming Language + Read License + Build Status + Codecov Code Coverage + Psalm Type Coverage +

+ +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 +command to install the package and add it as a requirement to your project's +`composer.json`: + +```bash +composer require ramsey/uuid +``` + +## Upgrading to Version 4 + +See the documentation for a thorough upgrade guide: + +* [Upgrading ramsey/uuid Version 3 to 4](https://uuid.ramsey.dev/en/stable/upgrading/3-to-4.html) + +## Documentation + +Please see for documentation, tips, examples, and +frequently asked questions. + +## Contributing + +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. + +## ramsey/uuid for Enterprise + +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 + +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/4.x/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/ +[contributing.md]: https://github.com/ramsey/uuid/blob/4.x/CONTRIBUTING.md +[security.md]: https://github.com/ramsey/uuid/blob/4.x/SECURITY.md +[license]: https://github.com/ramsey/uuid/blob/4.x/LICENSE diff --git a/pandora_console/vendor/ramsey/uuid/composer.json b/pandora_console/vendor/ramsey/uuid/composer.json new file mode 100644 index 0000000000..9ea4e06b3f --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/composer.json @@ -0,0 +1,108 @@ +{ + "name": "ramsey/uuid", + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "license": "MIT", + "type": "library", + "keywords": [ + "uuid", + "identifier", + "guid" + ], + "require": { + "php": "^8.0", + "ext-json": "*", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", + "ramsey/collection": "^1.2 || ^2.0" + }, + "require-dev": { + "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", + "paragonie/random-lib": "^2", + "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.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "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." + }, + "minimum-stability": "dev", + "prefer-stable": true, + "autoload": { + "psr-4": { + "Ramsey\\Uuid\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Ramsey\\Uuid\\Benchmark\\": "tests/benchmark/", + "Ramsey\\Uuid\\StaticAnalysis\\": "tests/static-analysis/", + "Ramsey\\Uuid\\Test\\": "tests/" + } + }, + "config": { + "allow-plugins": { + "captainhook/plugin-composer": true, + "ergebnis/composer-normalize": true, + "phpstan/extension-installer": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "ramsey/composer-repl": true + }, + "sort-packages": true + }, + "extra": { + "captainhook": { + "force-install": true + } + }, + "scripts": { + "analyze": [ + "@phpstan", + "@psalm" + ], + "build:clean": "git clean -fX build/", + "lint": "parallel-lint src tests", + "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 --memory-limit=1G", + "phpstan analyse -c phpstan-tests.neon --no-progress --memory-limit=1G" + ], + "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" + ] + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/BinaryUtils.php b/pandora_console/vendor/ramsey/uuid/src/BinaryUtils.php new file mode 100644 index 0000000000..fb8ba9adc1 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/BinaryUtils.php @@ -0,0 +1,63 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +/** + * Provides binary math utilities + */ +class BinaryUtils +{ + /** + * 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 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(int $clockSeq): int + { + $clockSeq = $clockSeq & 0x3fff; + $clockSeq |= 0x8000; + + return $clockSeq; + } + + /** + * 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 + * + * @psalm-pure + */ + public static function applyVersion(int $timeHi, int $version): int + { + $timeHi = $timeHi & 0x0fff; + $timeHi |= $version << 12; + + return $timeHi; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Builder/BuilderCollection.php b/pandora_console/vendor/ramsey/uuid/src/Builder/BuilderCollection.php new file mode 100644 index 0000000000..9df3110fd6 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Builder/BuilderCollection.php @@ -0,0 +1,85 @@ + + * @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 + * + * @deprecated this class has been deprecated, and will be removed in 5.0.0. The use-case for this class comes from + * a pre-`phpstan/phpstan` and pre-`vimeo/psalm` ecosystem, in which type safety had to be mostly enforced + * at runtime: that is no longer necessary, now that you can safely verify your code to be correct, and use + * more generic types like `iterable` instead. + * + * @extends AbstractCollection + */ +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 $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; + } + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php b/pandora_console/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php new file mode 100644 index 0000000000..7c4a6f8371 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Builder/DefaultUuidBuilder.php @@ -0,0 +1,26 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Builder; + +use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder; + +/** + * @deprecated Transition to {@see Rfc4122UuidBuilder}. + * + * @psalm-immutable + */ +class DefaultUuidBuilder extends Rfc4122UuidBuilder +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php b/pandora_console/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php new file mode 100644 index 0000000000..20b384212e --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Builder/DegradedUuidBuilder.php @@ -0,0 +1,67 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +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; + +/** + * @deprecated DegradedUuid instances are no longer necessary to support 32-bit + * systems. Transition to {@see DefaultUuidBuilder}. + * + * @psalm-immutable + */ +class DegradedUuidBuilder implements UuidBuilderInterface +{ + private TimeConverterInterface $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( + private NumberConverterInterface $numberConverter, + ?TimeConverterInterface $timeConverter = null + ) { + $this->timeConverter = $timeConverter ?: new DegradedTimeConverter(); + } + + /** + * 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 + * + * @psalm-pure + */ + public function build(CodecInterface $codec, string $bytes): UuidInterface + { + return new DegradedUuid( + new Rfc4122Fields($bytes), + $this->numberConverter, + $codec, + $this->timeConverter + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Builder/FallbackBuilder.php b/pandora_console/vendor/ramsey/uuid/src/Builder/FallbackBuilder.php new file mode 100644 index 0000000000..ba5f31fbeb --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Builder/FallbackBuilder.php @@ -0,0 +1,68 @@ + + * @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 +{ + /** + * @param iterable $builders An array of UUID builders + */ + public function __construct(private iterable $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 + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php b/pandora_console/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php new file mode 100644 index 0000000000..8e58b2b43e --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Builder/UuidBuilderInterface.php @@ -0,0 +1,39 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Builder; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\UuidInterface; + +/** + * A UUID builder builds instances of UuidInterface + * + * @psalm-immutable + */ +interface UuidBuilderInterface +{ + /** + * Builds and returns a UuidInterface + * + * @param CodecInterface $codec The codec to use for building this UuidInterface instance + * @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, string $bytes): UuidInterface; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Codec/CodecInterface.php b/pandora_console/vendor/ramsey/uuid/src/Codec/CodecInterface.php new file mode 100644 index 0000000000..85f8a7e991 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Codec/CodecInterface.php @@ -0,0 +1,71 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Codec; + +use Ramsey\Uuid\UuidInterface; + +/** + * A codec encodes and decodes a UUID according to defined rules + * + * @psalm-immutable + */ +interface CodecInterface +{ + /** + * Returns a hexadecimal string representation of a UuidInterface + * + * @param UuidInterface $uuid The UUID for which to create a hexadecimal + * string representation + * + * @return string Hexadecimal string representation of a UUID + * + * @psalm-return non-empty-string + */ + public function encode(UuidInterface $uuid): string; + + /** + * Returns a binary string representation of a UuidInterface + * + * @param UuidInterface $uuid The UUID for which to create a binary string + * representation + * + * @return string Binary string representation of a UUID + * + * @psalm-return non-empty-string + */ + public function encodeBinary(UuidInterface $uuid): string; + + /** + * Returns a UuidInterface derived from a hexadecimal string representation + * + * @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(string $encodedUuid): UuidInterface; + + /** + * Returns a UuidInterface derived from a binary string representation + * + * @param string $bytes The binary string representation to convert into a + * UuidInterface instance + * + * @return UuidInterface An instance of a UUID decoded from a binary string + * representation + */ + public function decodeBytes(string $bytes): UuidInterface; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php b/pandora_console/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php new file mode 100644 index 0000000000..04872e0bce --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Codec/GuidStringCodec.php @@ -0,0 +1,76 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Codec; + +use Ramsey\Uuid\Guid\Guid; +use Ramsey\Uuid\UuidInterface; + +use function bin2hex; +use function sprintf; +use function substr; + +/** + * GuidStringCodec encodes and decodes globally unique identifiers (GUID) + * + * @see Guid + * + * @psalm-immutable + */ +class GuidStringCodec extends StringCodec +{ + public function encode(UuidInterface $uuid): string + { + $hex = bin2hex($uuid->getFields()->getBytes()); + + /** @var non-empty-string */ + return sprintf( + '%02s%02s%02s%02s-%02s%02s-%02s%02s-%04s-%012s', + substr($hex, 6, 2), + substr($hex, 4, 2), + substr($hex, 2, 2), + substr($hex, 0, 2), + substr($hex, 10, 2), + substr($hex, 8, 2), + substr($hex, 14, 2), + substr($hex, 12, 2), + substr($hex, 16, 4), + substr($hex, 20), + ); + } + + public function decode(string $encodedUuid): UuidInterface + { + $bytes = $this->getBytes($encodedUuid); + + return $this->getBuilder()->build($this, $this->swapBytes($bytes)); + } + + public function decodeBytes(string $bytes): UuidInterface + { + // Specifically call parent::decode to preserve correct byte order + return parent::decode(bin2hex($bytes)); + } + + /** + * Swaps bytes according to the GUID rules + */ + private function swapBytes(string $bytes): string + { + return $bytes[3] . $bytes[2] . $bytes[1] . $bytes[0] + . $bytes[5] . $bytes[4] + . $bytes[7] . $bytes[6] + . substr($bytes, 8); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php b/pandora_console/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php new file mode 100644 index 0000000000..0798ebc4db --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Codec/OrderedTimeCodec.php @@ -0,0 +1,113 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Codec; + +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 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 +{ + /** + * Returns a binary string representation of a UUID, with the timestamp + * fields rearranged for optimized storage + * + * @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): string + { + if ( + !($uuid->getFields() instanceof Rfc4122FieldsInterface) + || $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME + ) { + throw new InvalidArgumentException( + 'Expected RFC 4122 version 1 (time-based) UUID' + ); + } + + $bytes = $uuid->getFields()->getBytes(); + + /** @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); + } + + /** + * Returns a UuidInterface derived from an ordered-time binary string + * representation + * + * @throws InvalidArgumentException if $bytes is an invalid length + * + * @inheritDoc + */ + public function decodeBytes(string $bytes): UuidInterface + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException( + '$bytes string should contain 16 characters.' + ); + } + + // 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); + + 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 $uuid; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Codec/StringCodec.php b/pandora_console/vendor/ramsey/uuid/src/Codec/StringCodec.php new file mode 100644 index 0000000000..95f38d2e80 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Codec/StringCodec.php @@ -0,0 +1,131 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Codec; + +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Exception\InvalidUuidStringException; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; + +use function bin2hex; +use function hex2bin; +use function implode; +use function sprintf; +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 +{ + /** + * Constructs a StringCodec + * + * @param UuidBuilderInterface $builder The builder to use when encoding UUIDs + */ + public function __construct(private UuidBuilderInterface $builder) + { + } + + public function encode(UuidInterface $uuid): string + { + $hex = bin2hex($uuid->getFields()->getBytes()); + + /** @var non-empty-string */ + return sprintf( + '%08s-%04s-%04s-%04s-%012s', + substr($hex, 0, 8), + substr($hex, 8, 4), + substr($hex, 12, 4), + substr($hex, 16, 4), + substr($hex, 20), + ); + } + + /** + * @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): string + { + /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ + return $uuid->getFields()->getBytes(); + } + + /** + * @throws InvalidUuidStringException + * + * @inheritDoc + */ + public function decode(string $encodedUuid): UuidInterface + { + return $this->builder->build($this, $this->getBytes($encodedUuid)); + } + + public function decodeBytes(string $bytes): UuidInterface + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException( + '$bytes string should contain 16 characters.' + ); + } + + return $this->builder->build($this, $bytes); + } + + /** + * Returns the UUID builder + */ + protected function getBuilder(): UuidBuilderInterface + { + return $this->builder; + } + + /** + * Returns a byte string of the UUID + */ + protected function getBytes(string $encodedUuid): string + { + $parsedUuid = str_replace( + ['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}', '-'], + '', + $encodedUuid + ); + + $components = [ + substr($parsedUuid, 0, 8), + substr($parsedUuid, 8, 4), + substr($parsedUuid, 12, 4), + substr($parsedUuid, 16, 4), + substr($parsedUuid, 20), + ]; + + if (!Uuid::isValid(implode('-', $components))) { + throw new InvalidUuidStringException( + 'Invalid UUID string: ' . $encodedUuid + ); + } + + return (string) hex2bin($parsedUuid); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php b/pandora_console/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php new file mode 100644 index 0000000000..0e0042d0a3 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Codec/TimestampFirstCombCodec.php @@ -0,0 +1,113 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +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 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 +{ + /** + * @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): string + { + $bytes = $this->swapBytes($uuid->getFields()->getBytes()); + + 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)) + ); + } + + /** + * @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): string + { + /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ + return $this->swapBytes($uuid->getFields()->getBytes()); + } + + /** + * @throws InvalidUuidStringException + * + * @inheritDoc + */ + public function decode(string $encodedUuid): UuidInterface + { + $bytes = $this->getBytes($encodedUuid); + + return $this->getBuilder()->build($this, $this->swapBytes($bytes)); + } + + public function decodeBytes(string $bytes): UuidInterface + { + return $this->getBuilder()->build($this, $this->swapBytes($bytes)); + } + + /** + * Swaps bytes according to the timestamp-first COMB rules + */ + private function swapBytes(string $bytes): string + { + $first48Bits = substr($bytes, 0, 6); + $last48Bits = substr($bytes, -6); + + $bytes = substr_replace($bytes, $last48Bits, 0, 6); + $bytes = substr_replace($bytes, $first48Bits, -6); + + return $bytes; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php b/pandora_console/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php new file mode 100644 index 0000000000..4856deaed9 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Codec/TimestampLastCombCodec.php @@ -0,0 +1,51 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Codec; + +/** + * 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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php new file mode 100644 index 0000000000..99b88b3bfa --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Number/BigNumberConverter.php @@ -0,0 +1,54 @@ + + * @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\BrickMathCalculator; + +/** + * 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 +{ + private NumberConverterInterface $converter; + + public function __construct() + { + $this->converter = new GenericNumberConverter(new BrickMathCalculator()); + } + + /** + * @inheritDoc + * @psalm-pure + */ + public function fromHex(string $hex): string + { + return $this->converter->fromHex($hex); + } + + /** + * @inheritDoc + * @psalm-pure + */ + public function toHex(string $number): string + { + return $this->converter->toHex($number); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php new file mode 100644 index 0000000000..c9cfa68647 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Number/DegradedNumberConverter.php @@ -0,0 +1,25 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Converter\Number; + +/** + * @deprecated DegradedNumberConverter is no longer necessary for converting + * numbers on 32-bit systems. Transition to {@see GenericNumberConverter}. + * + * @psalm-immutable + */ +class DegradedNumberConverter extends BigNumberConverter +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Number/GenericNumberConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Number/GenericNumberConverter.php new file mode 100644 index 0000000000..043c3c43d7 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Number/GenericNumberConverter.php @@ -0,0 +1,57 @@ + + * @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 +{ + public function __construct(private CalculatorInterface $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); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php b/pandora_console/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php new file mode 100644 index 0000000000..b33ec31f90 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/NumberConverterInterface.php @@ -0,0 +1,57 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Converter; + +/** + * 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 string integer representation of + * the number + * + * 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 string String representation of an integer + * + * @psalm-return numeric-string + * + * @psalm-pure + */ + public function fromHex(string $hex): string; + + /** + * 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. + * + * @return string Hexadecimal string + * + * @psalm-return non-empty-string + * + * @psalm-pure + */ + public function toHex(string $number): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php new file mode 100644 index 0000000000..b6bca9ee2f --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/BigNumberTimeConverter.php @@ -0,0 +1,48 @@ + + * @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\BrickMathCalculator; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Time; + +/** + * 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 +{ + private TimeConverterInterface $converter; + + public function __construct() + { + $this->converter = new GenericTimeConverter(new BrickMathCalculator()); + } + + public function calculateTime(string $seconds, string $microseconds): Hexadecimal + { + return $this->converter->calculateTime($seconds, $microseconds); + } + + public function convertTime(Hexadecimal $uuidTimestamp): Time + { + return $this->converter->convertTime($uuidTimestamp); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php new file mode 100644 index 0000000000..cdc28752dd --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/DegradedTimeConverter.php @@ -0,0 +1,25 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Converter\Time; + +/** + * @deprecated DegradedTimeConverter is no longer necessary for converting + * time on 32-bit systems. Transition to {@see GenericTimeConverter}. + * + * @psalm-immutable + */ +class DegradedTimeConverter extends BigNumberTimeConverter +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Time/GenericTimeConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/GenericTimeConverter.php new file mode 100644 index 0000000000..f6b60abbe1 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/GenericTimeConverter.php @@ -0,0 +1,118 @@ + + * @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'; + + public function __construct(private CalculatorInterface $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); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php new file mode 100644 index 0000000000..66009f14d4 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/PhpTimeConverter.php @@ -0,0 +1,172 @@ + + * @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\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 +{ + /** + * 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; + + private int $phpPrecision; + private CalculatorInterface $calculator; + private TimeConverterInterface $fallbackConverter; + + 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 float|int $time The time to split into seconds and microseconds + * + * @return string[] + */ + private function splitTime(float | int $time): array + { + $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 [ + 'sec' => $split[0], + 'usec' => str_pad((string) $microseconds, 6, '0', STR_PAD_RIGHT), + ]; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/Time/UnixTimeConverter.php b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/UnixTimeConverter.php new file mode 100644 index 0000000000..4d6d0a8a72 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/Time/UnixTimeConverter.php @@ -0,0 +1,90 @@ + + * @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; + +/** + * UnixTimeConverter converts Unix Epoch timestamps to/from hexadecimal values + * consisting of milliseconds elapsed since the Unix Epoch + * + * @psalm-immutable + */ +class UnixTimeConverter implements TimeConverterInterface +{ + private const MILLISECONDS = 1000; + + public function __construct(private CalculatorInterface $calculator) + { + } + + public function calculateTime(string $seconds, string $microseconds): Hexadecimal + { + $timestamp = new Time($seconds, $microseconds); + + // Convert the seconds into milliseconds. + $sec = $this->calculator->multiply( + $timestamp->getSeconds(), + new IntegerObject(self::MILLISECONDS), + ); + + // Convert the microseconds into milliseconds; the scale is zero because + // we need to discard the fractional part. + $usec = $this->calculator->divide( + RoundingMode::DOWN, // Always round down to stay in the previous millisecond. + 0, + $timestamp->getMicroseconds(), + new IntegerObject(self::MILLISECONDS), + ); + + /** @var IntegerObject $unixTime */ + $unixTime = $this->calculator->add($sec, $usec); + + $unixTimeHex = str_pad( + $this->calculator->toHexadecimal($unixTime)->toString(), + 12, + '0', + STR_PAD_LEFT + ); + + return new Hexadecimal($unixTimeHex); + } + + public function convertTime(Hexadecimal $uuidTimestamp): Time + { + $milliseconds = $this->calculator->toInteger($uuidTimestamp); + + $unixTimestamp = $this->calculator->divide( + RoundingMode::HALF_UP, + 6, + $milliseconds, + new IntegerObject(self::MILLISECONDS) + ); + + $split = explode('.', (string) $unixTimestamp, 2); + + return new Time($split[0], $split[1] ?? '0'); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php b/pandora_console/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php new file mode 100644 index 0000000000..1e84807018 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Converter/TimeConverterInterface.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Converter; + +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Time; + +/** + * 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 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} + * + * @psalm-pure + */ + public function convertTime(Hexadecimal $uuidTimestamp): Time; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/DegradedUuid.php b/pandora_console/vendor/ramsey/uuid/src/DegradedUuid.php new file mode 100644 index 0000000000..9166042cc1 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/DegradedUuid.php @@ -0,0 +1,25 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +/** + * @deprecated DegradedUuid is no longer necessary to represent UUIDs on 32-bit + * systems. Transition typehints to {@see UuidInterface}. + * + * @psalm-immutable + */ +class DegradedUuid extends Uuid +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/DeprecatedUuidInterface.php b/pandora_console/vendor/ramsey/uuid/src/DeprecatedUuidInterface.php new file mode 100644 index 0000000000..ac01a79cfc --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/DeprecatedUuidInterface.php @@ -0,0 +1,140 @@ + + * @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 + * + * @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 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; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/DeprecatedUuidMethodsTrait.php b/pandora_console/vendor/ramsey/uuid/src/DeprecatedUuidMethodsTrait.php new file mode 100644 index 0000000000..d3fbb0ccb5 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/DeprecatedUuidMethodsTrait.php @@ -0,0 +1,360 @@ + + * @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\Exception\DateTimeException; +use Ramsey\Uuid\Exception\UnsupportedOperationException; +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. + * + * @deprecated This trait and its methods will be removed in ramsey/uuid 5.0.0. + * + * @psalm-immutable + */ +trait DeprecatedUuidMethodsTrait +{ + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + return $this->fields->getClockSeqHiAndReserved()->toString(); + } + + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + return $this->fields->getClockSeqLow()->toString(); + } + + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + 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 \Ramsey\Uuid\Fields\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 \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + return $this->fields->getNode()->toString(); + } + + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + return $this->fields->getTimeHiAndVersion()->toString(); + } + + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + return $this->fields->getTimeLow()->toString(); + } + + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + return $this->fields->getTimeMid()->toString(); + } + + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. If it is a + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call + * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 + { + if ($this->fields->getVersion() !== 1) { + throw new UnsupportedOperationException('Not a time-based UUID'); + } + + return $this->fields->getTimestamp()->toString(); + } + + /** + * @deprecated Use {@see UuidInterface::getFields()} to get a + * {@see \Ramsey\Uuid\Fields\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 \Ramsey\Uuid\Fields\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(); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/BuilderNotFoundException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/BuilderNotFoundException.php new file mode 100644 index 0000000000..220ffedb85 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/BuilderNotFoundException.php @@ -0,0 +1,24 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/DateTimeException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/DateTimeException.php new file mode 100644 index 0000000000..5f0e658bfe --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/DateTimeException.php @@ -0,0 +1,24 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/DceSecurityException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/DceSecurityException.php new file mode 100644 index 0000000000..e6d8001366 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/DceSecurityException.php @@ -0,0 +1,25 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidArgumentException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..2a1fa3ac20 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidArgumentException.php @@ -0,0 +1,24 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidBytesException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidBytesException.php new file mode 100644 index 0000000000..1c94f65962 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidBytesException.php @@ -0,0 +1,24 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php new file mode 100644 index 0000000000..6d97581661 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/InvalidUuidStringException.php @@ -0,0 +1,25 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Exception; + +/** + * 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 implements UuidExceptionInterface +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/NameException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/NameException.php new file mode 100644 index 0000000000..fd96a1fafe --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/NameException.php @@ -0,0 +1,25 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/NodeException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/NodeException.php new file mode 100644 index 0000000000..0dbdd50b4b --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/NodeException.php @@ -0,0 +1,24 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/RandomSourceException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/RandomSourceException.php new file mode 100644 index 0000000000..a44dd34a23 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/RandomSourceException.php @@ -0,0 +1,27 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/TimeSourceException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/TimeSourceException.php new file mode 100644 index 0000000000..fc9cf36b6f --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/TimeSourceException.php @@ -0,0 +1,24 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/UnableToBuildUuidException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/UnableToBuildUuidException.php new file mode 100644 index 0000000000..5ba26d8dc9 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/UnableToBuildUuidException.php @@ -0,0 +1,24 @@ + + * @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 +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/UnsupportedOperationException.php b/pandora_console/vendor/ramsey/uuid/src/Exception/UnsupportedOperationException.php new file mode 100644 index 0000000000..e1b3eda173 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/UnsupportedOperationException.php @@ -0,0 +1,24 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Exception; + +use LogicException as PhpLogicException; + +/** + * Thrown to indicate that the requested operation is not supported + */ +class UnsupportedOperationException extends PhpLogicException implements UuidExceptionInterface +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Exception/UuidExceptionInterface.php b/pandora_console/vendor/ramsey/uuid/src/Exception/UuidExceptionInterface.php new file mode 100644 index 0000000000..a2f1c103b9 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Exception/UuidExceptionInterface.php @@ -0,0 +1,21 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Exception; + +use Throwable; + +interface UuidExceptionInterface extends Throwable +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/FeatureSet.php b/pandora_console/vendor/ramsey/uuid/src/FeatureSet.php new file mode 100644 index 0000000000..b9af869f91 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/FeatureSet.php @@ -0,0 +1,397 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +use Ramsey\Uuid\Builder\FallbackBuilder; +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Codec\GuidStringCodec; +use Ramsey\Uuid\Codec\StringCodec; +use Ramsey\Uuid\Converter\Number\GenericNumberConverter; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\Time\GenericTimeConverter; +use Ramsey\Uuid\Converter\Time\PhpTimeConverter; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Generator\DceSecurityGenerator; +use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface; +use Ramsey\Uuid\Generator\NameGeneratorFactory; +use Ramsey\Uuid\Generator\NameGeneratorInterface; +use Ramsey\Uuid\Generator\PeclUuidNameGenerator; +use Ramsey\Uuid\Generator\PeclUuidRandomGenerator; +use Ramsey\Uuid\Generator\PeclUuidTimeGenerator; +use Ramsey\Uuid\Generator\RandomGeneratorFactory; +use Ramsey\Uuid\Generator\RandomGeneratorInterface; +use Ramsey\Uuid\Generator\TimeGeneratorFactory; +use Ramsey\Uuid\Generator\TimeGeneratorInterface; +use Ramsey\Uuid\Generator\UnixTimeGenerator; +use Ramsey\Uuid\Guid\GuidBuilder; +use Ramsey\Uuid\Math\BrickMathCalculator; +use Ramsey\Uuid\Math\CalculatorInterface; +use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder; +use Ramsey\Uuid\Provider\Dce\SystemDceSecurityProvider; +use Ramsey\Uuid\Provider\DceSecurityProviderInterface; +use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; +use Ramsey\Uuid\Provider\Node\RandomNodeProvider; +use Ramsey\Uuid\Provider\Node\SystemNodeProvider; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Provider\Time\SystemTimeProvider; +use Ramsey\Uuid\Provider\TimeProviderInterface; +use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder; +use Ramsey\Uuid\Validator\GenericValidator; +use Ramsey\Uuid\Validator\ValidatorInterface; + +use const PHP_INT_SIZE; + +/** + * FeatureSet detects and exposes available features in the current environment + * + * A feature set is used by UuidFactory to determine the available features and + * capabilities of the environment. + */ +class FeatureSet +{ + private ?TimeProviderInterface $timeProvider = null; + private CalculatorInterface $calculator; + private CodecInterface $codec; + private DceSecurityGeneratorInterface $dceSecurityGenerator; + private NameGeneratorInterface $nameGenerator; + private NodeProviderInterface $nodeProvider; + private NumberConverterInterface $numberConverter; + private RandomGeneratorInterface $randomGenerator; + private TimeConverterInterface $timeConverter; + private TimeGeneratorInterface $timeGenerator; + private TimeGeneratorInterface $unixTimeGenerator; + private UuidBuilderInterface $builder; + private ValidatorInterface $validator; + + /** + * @param bool $useGuids True build UUIDs using the GuidStringCodec + * @param bool $force32Bit True to force the use of 32-bit functionality + * (primarily for testing purposes) + * @param bool $forceNoBigNumber (obsolete) + * @param bool $ignoreSystemNode True to disable attempts to check for the + * system node ID (primarily for testing purposes) + * @param bool $enablePecl True to enable the use of the PeclUuidTimeGenerator + * to generate version 1 UUIDs + */ + public function __construct( + bool $useGuids = false, + private bool $force32Bit = false, + bool $forceNoBigNumber = false, + private bool $ignoreSystemNode = false, + private bool $enablePecl = false + ) { + $this->randomGenerator = $this->buildRandomGenerator(); + $this->setCalculator(new BrickMathCalculator()); + $this->builder = $this->buildUuidBuilder($useGuids); + $this->codec = $this->buildCodec($useGuids); + $this->nodeProvider = $this->buildNodeProvider(); + $this->nameGenerator = $this->buildNameGenerator(); + $this->setTimeProvider(new SystemTimeProvider()); + $this->setDceSecurityProvider(new SystemDceSecurityProvider()); + $this->validator = new GenericValidator(); + + assert($this->timeProvider !== null); + $this->unixTimeGenerator = $this->buildUnixTimeGenerator(); + } + + /** + * Returns the builder configured for this environment + */ + public function getBuilder(): UuidBuilderInterface + { + return $this->builder; + } + + /** + * Returns the calculator configured for this environment + */ + public function getCalculator(): CalculatorInterface + { + return $this->calculator; + } + + /** + * Returns the codec configured for this environment + */ + public function getCodec(): CodecInterface + { + return $this->codec; + } + + /** + * Returns the DCE Security generator configured for this environment + */ + public function getDceSecurityGenerator(): DceSecurityGeneratorInterface + { + return $this->dceSecurityGenerator; + } + + /** + * Returns the name generator configured for this environment + */ + public function getNameGenerator(): NameGeneratorInterface + { + return $this->nameGenerator; + } + + /** + * Returns the node provider configured for this environment + */ + public function getNodeProvider(): NodeProviderInterface + { + return $this->nodeProvider; + } + + /** + * Returns the number converter configured for this environment + */ + public function getNumberConverter(): NumberConverterInterface + { + return $this->numberConverter; + } + + /** + * Returns the random generator configured for this environment + */ + public function getRandomGenerator(): RandomGeneratorInterface + { + return $this->randomGenerator; + } + + /** + * Returns the time converter configured for this environment + */ + public function getTimeConverter(): TimeConverterInterface + { + return $this->timeConverter; + } + + /** + * Returns the time generator configured for this environment + */ + public function getTimeGenerator(): TimeGeneratorInterface + { + return $this->timeGenerator; + } + + /** + * Returns the Unix Epoch time generator configured for this environment + */ + public function getUnixTimeGenerator(): TimeGeneratorInterface + { + return $this->unixTimeGenerator; + } + + /** + * Returns the validator configured for this environment + */ + public function getValidator(): ValidatorInterface + { + return $this->validator; + } + + /** + * Sets the calculator to use in this environment + */ + public function setCalculator(CalculatorInterface $calculator): void + { + $this->calculator = $calculator; + $this->numberConverter = $this->buildNumberConverter($calculator); + $this->timeConverter = $this->buildTimeConverter($calculator); + + /** @psalm-suppress RedundantPropertyInitializationCheck */ + if (isset($this->timeProvider)) { + $this->timeGenerator = $this->buildTimeGenerator($this->timeProvider); + } + } + + /** + * Sets the DCE Security provider to use in this environment + */ + public function setDceSecurityProvider(DceSecurityProviderInterface $dceSecurityProvider): void + { + $this->dceSecurityGenerator = $this->buildDceSecurityGenerator($dceSecurityProvider); + } + + /** + * Sets the node provider to use in this environment + */ + public function setNodeProvider(NodeProviderInterface $nodeProvider): void + { + $this->nodeProvider = $nodeProvider; + + if (isset($this->timeProvider)) { + $this->timeGenerator = $this->buildTimeGenerator($this->timeProvider); + } + } + + /** + * Sets the time provider to use in this environment + */ + public function setTimeProvider(TimeProviderInterface $timeProvider): void + { + $this->timeProvider = $timeProvider; + $this->timeGenerator = $this->buildTimeGenerator($timeProvider); + } + + /** + * Set the validator to use in this environment + */ + public function setValidator(ValidatorInterface $validator): void + { + $this->validator = $validator; + } + + /** + * Returns a codec configured for this environment + * + * @param bool $useGuids Whether to build UUIDs using the GuidStringCodec + */ + private function buildCodec(bool $useGuids = false): CodecInterface + { + if ($useGuids) { + return new GuidStringCodec($this->builder); + } + + return new StringCodec($this->builder); + } + + /** + * Returns a DCE Security generator configured for this environment + */ + private function buildDceSecurityGenerator( + DceSecurityProviderInterface $dceSecurityProvider + ): DceSecurityGeneratorInterface { + return new DceSecurityGenerator( + $this->numberConverter, + $this->timeGenerator, + $dceSecurityProvider + ); + } + + /** + * Returns a node provider configured for this environment + */ + private function buildNodeProvider(): NodeProviderInterface + { + if ($this->ignoreSystemNode) { + return new RandomNodeProvider(); + } + + return new FallbackNodeProvider([ + new SystemNodeProvider(), + new RandomNodeProvider(), + ]); + } + + /** + * Returns a number converter configured for this environment + */ + private function buildNumberConverter(CalculatorInterface $calculator): NumberConverterInterface + { + return new GenericNumberConverter($calculator); + } + + /** + * Returns a random generator configured for this environment + */ + private function buildRandomGenerator(): RandomGeneratorInterface + { + if ($this->enablePecl) { + return new PeclUuidRandomGenerator(); + } + + return (new RandomGeneratorFactory())->getGenerator(); + } + + /** + * Returns a time generator configured for this environment + * + * @param TimeProviderInterface $timeProvider The time provider to use with + * the time generator + */ + private function buildTimeGenerator(TimeProviderInterface $timeProvider): TimeGeneratorInterface + { + if ($this->enablePecl) { + return new PeclUuidTimeGenerator(); + } + + return (new TimeGeneratorFactory( + $this->nodeProvider, + $this->timeConverter, + $timeProvider + ))->getGenerator(); + } + + /** + * Returns a Unix Epoch time generator configured for this environment + */ + private function buildUnixTimeGenerator(): TimeGeneratorInterface + { + return new UnixTimeGenerator($this->randomGenerator); + } + + /** + * Returns a name generator configured for this environment + */ + private function buildNameGenerator(): NameGeneratorInterface + { + if ($this->enablePecl) { + return new PeclUuidNameGenerator(); + } + + return (new NameGeneratorFactory())->getGenerator(); + } + + /** + * Returns a time converter configured for this environment + */ + private function buildTimeConverter(CalculatorInterface $calculator): TimeConverterInterface + { + $genericConverter = new GenericTimeConverter($calculator); + + if ($this->is64BitSystem()) { + return new PhpTimeConverter($calculator, $genericConverter); + } + + return $genericConverter; + } + + /** + * Returns a UUID builder configured for this environment + * + * @param bool $useGuids Whether to build UUIDs using the GuidStringCodec + */ + private function buildUuidBuilder(bool $useGuids = false): UuidBuilderInterface + { + if ($useGuids) { + return new GuidBuilder($this->numberConverter, $this->timeConverter); + } + + return new FallbackBuilder([ + new Rfc4122UuidBuilder($this->numberConverter, $this->timeConverter), + new NonstandardUuidBuilder($this->numberConverter, $this->timeConverter), + ]); + } + + /** + * Returns true if the PHP build is 64-bit + */ + private function is64BitSystem(): bool + { + return PHP_INT_SIZE === 8 && !$this->force32Bit; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Fields/FieldsInterface.php b/pandora_console/vendor/ramsey/uuid/src/Fields/FieldsInterface.php new file mode 100644 index 0000000000..f1b7a290d4 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Fields/FieldsInterface.php @@ -0,0 +1,32 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Fields; + +use Serializable; + +/** + * UUIDs are comprised of unsigned integers, the bytes of which are separated + * into fields and arranged in a particular layout defined by the specification + * for the variant + * + * @psalm-immutable + */ +interface FieldsInterface extends Serializable +{ + /** + * Returns the bytes that comprise the fields + */ + public function getBytes(): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Fields/SerializableFieldsTrait.php b/pandora_console/vendor/ramsey/uuid/src/Fields/SerializableFieldsTrait.php new file mode 100644 index 0000000000..3d36b6f127 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Fields/SerializableFieldsTrait.php @@ -0,0 +1,87 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Fields; + +use ValueError; + +use function base64_decode; +use function sprintf; +use function strlen; + +/** + * Provides common serialization functionality to fields + * + * @psalm-immutable + */ +trait SerializableFieldsTrait +{ + /** + * @param string $bytes The bytes that comprise the fields + */ + abstract public function __construct(string $bytes); + + /** + * Returns the bytes that comprise the fields + */ + abstract public function getBytes(): string; + + /** + * Returns a string representation of object + */ + public function serialize(): string + { + return $this->getBytes(); + } + + /** + * @return array{bytes: string} + */ + public function __serialize(): array + { + return ['bytes' => $this->getBytes()]; + } + + /** + * Constructs the object from a serialized string representation + * + * @param string $data The serialized string representation of the object + * + * @psalm-suppress UnusedMethodCall + */ + public function unserialize(string $data): void + { + if (strlen($data) === 16) { + $this->__construct($data); + } else { + $this->__construct(base64_decode($data)); + } + } + + /** + * @param array{bytes?: string} $data + * + * @psalm-suppress UnusedMethodCall + */ + public function __unserialize(array $data): void + { + // @codeCoverageIgnoreStart + if (!isset($data['bytes'])) { + throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); + } + // @codeCoverageIgnoreEnd + + $this->unserialize($data['bytes']); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/CombGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/CombGenerator.php new file mode 100644 index 0000000000..0e88706082 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/CombGenerator.php @@ -0,0 +1,115 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; + +use function bin2hex; +use function explode; +use function hex2bin; +use function microtime; +use function str_pad; +use function substr; + +use const STR_PAD_LEFT; + +/** + * CombGenerator generates COMBs (combined UUID/timestamp) + * + * The CombGenerator, when used with the StringCodec (and, by proxy, the + * TimestampLastCombCodec) or the TimestampFirstCombCodec, combines the current + * timestamp with a UUID (hence the name "COMB"). The timestamp either appears + * as the first or last 48 bits of the COMB, depending on the codec used. + * + * By default, COMBs will have the timestamp set as the last 48 bits of the + * identifier. + * + * ``` php + * $factory = new UuidFactory(); + * + * $factory->setRandomGenerator(new CombGenerator( + * $factory->getRandomGenerator(), + * $factory->getNumberConverter() + * )); + * + * $comb = $factory->uuid4(); + * ``` + * + * To generate a COMB with the timestamp as the first 48 bits, set the + * TimestampFirstCombCodec as the codec. + * + * ``` php + * $factory->setCodec(new TimestampFirstCombCodec($factory->getUuidBuilder())); + * ``` + * + * @link https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys + */ +class CombGenerator implements RandomGeneratorInterface +{ + public const TIMESTAMP_BYTES = 6; + + public function __construct( + private RandomGeneratorInterface $generator, + private NumberConverterInterface $numberConverter + ) { + } + + /** + * @throws InvalidArgumentException if $length is not a positive integer + * greater than or equal to CombGenerator::TIMESTAMP_BYTES + * + * @inheritDoc + */ + public function generate(int $length): string + { + if ($length < self::TIMESTAMP_BYTES) { + throw new InvalidArgumentException( + 'Length must be a positive integer greater than or equal to ' . self::TIMESTAMP_BYTES + ); + } + + $hash = ''; + if (self::TIMESTAMP_BYTES > 0 && $length > self::TIMESTAMP_BYTES) { + $hash = $this->generator->generate($length - self::TIMESTAMP_BYTES); + } + + $lsbTime = str_pad( + $this->numberConverter->toHex($this->timestamp()), + self::TIMESTAMP_BYTES * 2, + '0', + STR_PAD_LEFT + ); + + return (string) hex2bin( + str_pad( + bin2hex($hash), + $length - self::TIMESTAMP_BYTES, + '0' + ) + . $lsbTime + ); + } + + /** + * Returns current timestamp a string integer, precise to 0.00001 seconds + */ + private function timestamp(): string + { + $time = explode(' ', microtime(false)); + + return $time[1] . substr($time[0], 2, 5); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/DceSecurityGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/DceSecurityGenerator.php new file mode 100644 index 0000000000..37ba781314 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/DceSecurityGenerator.php @@ -0,0 +1,141 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Exception\DceSecurityException; +use Ramsey\Uuid\Provider\DceSecurityProviderInterface; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\Uuid; + +use function hex2bin; +use function in_array; +use function pack; +use function str_pad; +use function strlen; +use function substr_replace; + +use const STR_PAD_LEFT; + +/** + * DceSecurityGenerator generates strings of binary data based on a local + * domain, local identifier, node ID, clock sequence, and the current time + */ +class DceSecurityGenerator implements DceSecurityGeneratorInterface +{ + private const DOMAINS = [ + Uuid::DCE_DOMAIN_PERSON, + Uuid::DCE_DOMAIN_GROUP, + Uuid::DCE_DOMAIN_ORG, + ]; + + /** + * Upper bounds for the clock sequence in DCE Security UUIDs. + */ + private const CLOCK_SEQ_HIGH = 63; + + /** + * Lower bounds for the clock sequence in DCE Security UUIDs. + */ + private const CLOCK_SEQ_LOW = 0; + + public function __construct( + private NumberConverterInterface $numberConverter, + private TimeGeneratorInterface $timeGenerator, + private DceSecurityProviderInterface $dceSecurityProvider + ) { + } + + public function generate( + int $localDomain, + ?IntegerObject $localIdentifier = null, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): string { + if (!in_array($localDomain, self::DOMAINS)) { + throw new DceSecurityException( + 'Local domain must be a valid DCE Security domain' + ); + } + + if ($localIdentifier && $localIdentifier->isNegative()) { + throw new DceSecurityException( + 'Local identifier out of bounds; it must be a value between 0 and 4294967295' + ); + } + + if ($clockSeq > self::CLOCK_SEQ_HIGH || $clockSeq < self::CLOCK_SEQ_LOW) { + throw new DceSecurityException( + 'Clock sequence out of bounds; it must be a value between 0 and 63' + ); + } + + switch ($localDomain) { + case Uuid::DCE_DOMAIN_ORG: + if ($localIdentifier === null) { + throw new DceSecurityException( + 'A local identifier must be provided for the org domain' + ); + } + + break; + case Uuid::DCE_DOMAIN_PERSON: + if ($localIdentifier === null) { + $localIdentifier = $this->dceSecurityProvider->getUid(); + } + + break; + case Uuid::DCE_DOMAIN_GROUP: + default: + if ($localIdentifier === null) { + $localIdentifier = $this->dceSecurityProvider->getGid(); + } + + break; + } + + $identifierHex = $this->numberConverter->toHex($localIdentifier->toString()); + + // The maximum value for the local identifier is 0xffffffff, or + // 4294967295. This is 8 hexadecimal digits, so if the length of + // hexadecimal digits is greater than 8, we know the value is greater + // than 0xffffffff. + if (strlen($identifierHex) > 8) { + throw new DceSecurityException( + 'Local identifier out of bounds; it must be a value between 0 and 4294967295' + ); + } + + $domainByte = pack('n', $localDomain)[1]; + $identifierBytes = (string) hex2bin(str_pad($identifierHex, 8, '0', STR_PAD_LEFT)); + + if ($node instanceof Hexadecimal) { + $node = $node->toString(); + } + + // Shift the clock sequence 8 bits to the left, so it matches 0x3f00. + if ($clockSeq !== null) { + $clockSeq = $clockSeq << 8; + } + + $bytes = $this->timeGenerator->generate($node, $clockSeq); + + // Replace bytes in the time-based UUID with DCE Security values. + $bytes = substr_replace($bytes, $identifierBytes, 0, 4); + + return substr_replace($bytes, $domainByte, 9, 1); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/DceSecurityGeneratorInterface.php b/pandora_console/vendor/ramsey/uuid/src/Generator/DceSecurityGeneratorInterface.php new file mode 100644 index 0000000000..faa29a53d2 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/DceSecurityGeneratorInterface.php @@ -0,0 +1,53 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Rfc4122\UuidV2; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; + +/** + * A DCE Security generator generates strings of binary data based on a local + * domain, local identifier, node ID, clock sequence, and the current time + * + * @see UuidV2 + */ +interface DceSecurityGeneratorInterface +{ + /** + * Generate a binary string from a local domain, local identifier, node ID, + * clock sequence, and current time + * + * @param int $localDomain The local domain to use when generating bytes, + * according to DCE Security + * @param IntegerObject|null $localIdentifier The local identifier for the + * given domain; this may be a UID or GID on POSIX systems, if the local + * domain is person or group, or it may be a site-defined identifier + * if the local domain is org + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return string A binary string + */ + public function generate( + int $localDomain, + ?IntegerObject $localIdentifier = null, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/DefaultNameGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/DefaultNameGenerator.php new file mode 100644 index 0000000000..7303e9fa27 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/DefaultNameGenerator.php @@ -0,0 +1,48 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Exception\NameException; +use Ramsey\Uuid\UuidInterface; +use ValueError; + +use function hash; + +/** + * DefaultNameGenerator generates strings of binary data based on a namespace, + * name, and hashing algorithm + */ +class DefaultNameGenerator implements NameGeneratorInterface +{ + /** @psalm-pure */ + public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string + { + try { + /** @var string|bool $bytes */ + $bytes = @hash($hashAlgorithm, $ns->getBytes() . $name, true); + } catch (ValueError $e) { + $bytes = false; // keep same behavior than PHP 7 + } + + if ($bytes === false) { + throw new NameException(sprintf( + 'Unable to hash namespace and name with algorithm \'%s\'', + $hashAlgorithm + )); + } + + return (string) $bytes; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/DefaultTimeGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/DefaultTimeGenerator.php new file mode 100644 index 0000000000..ea1e2a6ff3 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/DefaultTimeGenerator.php @@ -0,0 +1,129 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Exception\RandomSourceException; +use Ramsey\Uuid\Exception\TimeSourceException; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Provider\TimeProviderInterface; +use Ramsey\Uuid\Type\Hexadecimal; +use Throwable; + +use function dechex; +use function hex2bin; +use function is_int; +use function pack; +use function preg_match; +use function sprintf; +use function str_pad; +use function strlen; + +use const STR_PAD_LEFT; + +/** + * DefaultTimeGenerator generates strings of binary data based on a node ID, + * clock sequence, and the current time + */ +class DefaultTimeGenerator implements TimeGeneratorInterface +{ + public function __construct( + private NodeProviderInterface $nodeProvider, + private TimeConverterInterface $timeConverter, + private TimeProviderInterface $timeProvider + ) { + } + + /** + * @throws InvalidArgumentException if the parameters contain invalid values + * @throws RandomSourceException if random_int() throws an exception/error + * + * @inheritDoc + */ + public function generate($node = null, ?int $clockSeq = null): string + { + if ($node instanceof Hexadecimal) { + $node = $node->toString(); + } + + $node = $this->getValidNode($node); + + if ($clockSeq === null) { + try { + // This does not use "stable storage"; see RFC 4122, Section 4.2.1.1. + $clockSeq = random_int(0, 0x3fff); + } catch (Throwable $exception) { + throw new RandomSourceException( + $exception->getMessage(), + (int) $exception->getCode(), + $exception + ); + } + } + + $time = $this->timeProvider->getTime(); + + $uuidTime = $this->timeConverter->calculateTime( + $time->getSeconds()->toString(), + $time->getMicroseconds()->toString() + ); + + $timeHex = str_pad($uuidTime->toString(), 16, '0', STR_PAD_LEFT); + + if (strlen($timeHex) !== 16) { + throw new TimeSourceException(sprintf( + 'The generated time of \'%s\' is larger than expected', + $timeHex + )); + } + + $timeBytes = (string) hex2bin($timeHex); + + return $timeBytes[4] . $timeBytes[5] . $timeBytes[6] . $timeBytes[7] + . $timeBytes[2] . $timeBytes[3] + . $timeBytes[0] . $timeBytes[1] + . pack('n*', $clockSeq) + . $node; + } + + /** + * Uses the node provider given when constructing this instance to get + * the node ID (usually a MAC address) + * + * @param int|string|null $node A node value that may be used to override the node provider + * + * @return string 6-byte binary string representation of the node + * + * @throws InvalidArgumentException + */ + private function getValidNode(int | string | null $node): string + { + if ($node === null) { + $node = $this->nodeProvider->getNode(); + } + + // Convert the node to hex, if it is still an integer. + if (is_int($node)) { + $node = dechex($node); + } + + if (!preg_match('/^[A-Fa-f0-9]+$/', (string) $node) || strlen((string) $node) > 12) { + throw new InvalidArgumentException('Invalid node value'); + } + + return (string) hex2bin(str_pad((string) $node, 12, '0', STR_PAD_LEFT)); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/NameGeneratorFactory.php b/pandora_console/vendor/ramsey/uuid/src/Generator/NameGeneratorFactory.php new file mode 100644 index 0000000000..6f08e29104 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/NameGeneratorFactory.php @@ -0,0 +1,30 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +/** + * NameGeneratorFactory retrieves a default name generator, based on the + * environment + */ +class NameGeneratorFactory +{ + /** + * Returns a default name generator, based on the current environment + */ + public function getGenerator(): NameGeneratorInterface + { + return new DefaultNameGenerator(); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/NameGeneratorInterface.php b/pandora_console/vendor/ramsey/uuid/src/Generator/NameGeneratorInterface.php new file mode 100644 index 0000000000..cc43dd0290 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/NameGeneratorInterface.php @@ -0,0 +1,38 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\UuidInterface; + +/** + * A name generator generates strings of binary data created by hashing together + * a namespace with a name, according to a hashing algorithm + */ +interface NameGeneratorInterface +{ + /** + * Generate a binary string from a namespace and name hashed together with + * the specified hashing algorithm + * + * @param UuidInterface $ns The namespace + * @param string $name The name to use for creating a UUID + * @param string $hashAlgorithm The hashing algorithm to use + * + * @return string A binary string + * + * @psalm-pure + */ + public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidNameGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidNameGenerator.php new file mode 100644 index 0000000000..6a6d1aec3b --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidNameGenerator.php @@ -0,0 +1,49 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Exception\NameException; +use Ramsey\Uuid\UuidInterface; + +use function sprintf; +use function uuid_generate_md5; +use function uuid_generate_sha1; +use function uuid_parse; + +/** + * PeclUuidNameGenerator generates strings of binary data from a namespace and a + * name, using ext-uuid + * + * @link https://pecl.php.net/package/uuid ext-uuid + */ +class PeclUuidNameGenerator implements NameGeneratorInterface +{ + /** @psalm-pure */ + public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string + { + $uuid = match ($hashAlgorithm) { + 'md5' => uuid_generate_md5($ns->toString(), $name), + 'sha1' => uuid_generate_sha1($ns->toString(), $name), + default => throw new NameException( + sprintf( + 'Unable to hash namespace and name with algorithm \'%s\'', + $hashAlgorithm + ) + ), + }; + + return uuid_parse($uuid); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php new file mode 100644 index 0000000000..07c47d2652 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidRandomGenerator.php @@ -0,0 +1,35 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use function uuid_create; +use function uuid_parse; + +use const UUID_TYPE_RANDOM; + +/** + * PeclUuidRandomGenerator generates strings of random binary data using ext-uuid + * + * @link https://pecl.php.net/package/uuid ext-uuid + */ +class PeclUuidRandomGenerator implements RandomGeneratorInterface +{ + public function generate(int $length): string + { + $uuid = uuid_create(UUID_TYPE_RANDOM); + + return uuid_parse($uuid); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php new file mode 100644 index 0000000000..e01f44e525 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/PeclUuidTimeGenerator.php @@ -0,0 +1,39 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use function uuid_create; +use function uuid_parse; + +use const UUID_TYPE_TIME; + +/** + * PeclUuidTimeGenerator generates strings of binary data for time-base UUIDs, + * using ext-uuid + * + * @link https://pecl.php.net/package/uuid ext-uuid + */ +class PeclUuidTimeGenerator implements TimeGeneratorInterface +{ + /** + * @inheritDoc + */ + public function generate($node = null, ?int $clockSeq = null): string + { + $uuid = uuid_create(UUID_TYPE_TIME); + + return uuid_parse($uuid); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/RandomBytesGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomBytesGenerator.php new file mode 100644 index 0000000000..12edb96ae7 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomBytesGenerator.php @@ -0,0 +1,45 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Exception\RandomSourceException; +use Throwable; + +/** + * RandomBytesGenerator generates strings of random binary data using the + * built-in `random_bytes()` PHP function + * + * @link http://php.net/random_bytes random_bytes() + */ +class RandomBytesGenerator implements RandomGeneratorInterface +{ + /** + * @throws RandomSourceException if random_bytes() throws an exception/error + * + * @inheritDoc + */ + public function generate(int $length): string + { + try { + return random_bytes($length); + } catch (Throwable $exception) { + throw new RandomSourceException( + $exception->getMessage(), + (int) $exception->getCode(), + $exception + ); + } + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/RandomGeneratorFactory.php b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomGeneratorFactory.php new file mode 100644 index 0000000000..b723ac29e8 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomGeneratorFactory.php @@ -0,0 +1,30 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +/** + * RandomGeneratorFactory retrieves a default random generator, based on the + * environment + */ +class RandomGeneratorFactory +{ + /** + * Returns a default random generator, based on the current environment + */ + public function getGenerator(): RandomGeneratorInterface + { + return new RandomBytesGenerator(); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/RandomGeneratorInterface.php b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomGeneratorInterface.php new file mode 100644 index 0000000000..1180b97647 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomGeneratorInterface.php @@ -0,0 +1,30 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +/** + * A random generator generates strings of random binary data + */ +interface RandomGeneratorInterface +{ + /** + * Generates a string of randomized binary data + * + * @param int<1, max> $length The number of bytes of random binary data to generate + * + * @return string A binary string + */ + public function generate(int $length): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/RandomLibAdapter.php b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomLibAdapter.php new file mode 100644 index 0000000000..fd0ccc8aa2 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/RandomLibAdapter.php @@ -0,0 +1,56 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use RandomLib\Factory; +use RandomLib\Generator; + +/** + * RandomLibAdapter generates strings of random binary data using the + * paragonie/random-lib library + * + * @deprecated This class will be removed in 5.0.0. Use the default + * RandomBytesGenerator or implement your own generator that implements + * RandomGeneratorInterface. + * + * @link https://packagist.org/packages/paragonie/random-lib paragonie/random-lib + */ +class RandomLibAdapter implements RandomGeneratorInterface +{ + private Generator $generator; + + /** + * Constructs a RandomLibAdapter + * + * By default, if no Generator is passed in, this creates a high-strength + * generator to use when generating random binary data. + * + * @param Generator|null $generator The generator to use when generating binary data + */ + public function __construct(?Generator $generator = null) + { + if ($generator === null) { + $factory = new Factory(); + $generator = $factory->getHighStrengthGenerator(); + } + + $this->generator = $generator; + } + + public function generate(int $length): string + { + return $this->generator->generate($length); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/TimeGeneratorFactory.php b/pandora_console/vendor/ramsey/uuid/src/Generator/TimeGeneratorFactory.php new file mode 100644 index 0000000000..8d06fc3ae6 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/TimeGeneratorFactory.php @@ -0,0 +1,45 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Provider\TimeProviderInterface; + +/** + * TimeGeneratorFactory retrieves a default time generator, based on the + * environment + */ +class TimeGeneratorFactory +{ + public function __construct( + private NodeProviderInterface $nodeProvider, + private TimeConverterInterface $timeConverter, + private TimeProviderInterface $timeProvider + ) { + } + + /** + * Returns a default time generator, based on the current environment + */ + public function getGenerator(): TimeGeneratorInterface + { + return new DefaultTimeGenerator( + $this->nodeProvider, + $this->timeConverter, + $this->timeProvider + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/TimeGeneratorInterface.php b/pandora_console/vendor/ramsey/uuid/src/Generator/TimeGeneratorInterface.php new file mode 100644 index 0000000000..18f21c4b60 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/TimeGeneratorInterface.php @@ -0,0 +1,38 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Ramsey\Uuid\Type\Hexadecimal; + +/** + * A time generator generates strings of binary data based on a node ID, + * clock sequence, and the current time + */ +interface TimeGeneratorInterface +{ + /** + * Generate a binary string from a node ID, clock sequence, and current time + * + * @param Hexadecimal|int|string|null $node A 48-bit number representing the + * hardware address; this number may be represented as an integer or a + * hexadecimal string + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return string A binary string + */ + public function generate($node = null, ?int $clockSeq = null): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Generator/UnixTimeGenerator.php b/pandora_console/vendor/ramsey/uuid/src/Generator/UnixTimeGenerator.php new file mode 100644 index 0000000000..d7c8ed4eee --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Generator/UnixTimeGenerator.php @@ -0,0 +1,169 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Generator; + +use Brick\Math\BigInteger; +use DateTimeImmutable; +use DateTimeInterface; +use Ramsey\Uuid\Type\Hexadecimal; + +use function hash; +use function pack; +use function str_pad; +use function strlen; +use function substr; +use function substr_replace; +use function unpack; + +use const PHP_INT_SIZE; +use const STR_PAD_LEFT; + +/** + * UnixTimeGenerator generates bytes that combine a 48-bit timestamp in + * milliseconds since the Unix Epoch with 80 random bits + * + * Code and concepts within this class are borrowed from the symfony/uid package + * and are used under the terms of the MIT license distributed with symfony/uid. + * + * symfony/uid is copyright (c) Fabien Potencier. + * + * @link https://symfony.com/components/Uid Symfony Uid component + * @link https://github.com/symfony/uid/blob/4f9f537e57261519808a7ce1d941490736522bbc/UuidV7.php Symfony UuidV7 class + * @link https://github.com/symfony/uid/blob/6.2/LICENSE MIT License + */ +class UnixTimeGenerator implements TimeGeneratorInterface +{ + private static string $time = ''; + private static ?string $seed = null; + private static int $seedIndex = 0; + + /** @var int[] */ + private static array $rand = []; + + /** @var int[] */ + private static array $seedParts; + + public function __construct( + private RandomGeneratorInterface $randomGenerator, + private int $intSize = PHP_INT_SIZE + ) { + } + + /** + * @param Hexadecimal|int|string|null $node Unused in this generator + * @param int|null $clockSeq Unused in this generator + * @param DateTimeInterface $dateTime A date-time instance to use when + * generating bytes + * + * @inheritDoc + */ + public function generate($node = null, ?int $clockSeq = null, ?DateTimeInterface $dateTime = null): string + { + $time = ($dateTime ?? new DateTimeImmutable('now'))->format('Uv'); + + if ($time > self::$time || ($dateTime !== null && $time !== self::$time)) { + $this->randomize($time); + } else { + $time = $this->increment(); + } + + if ($this->intSize >= 8) { + $time = substr(pack('J', (int) $time), -6); + } else { + $time = str_pad(BigInteger::of($time)->toBytes(false), 6, "\x00", STR_PAD_LEFT); + } + + /** @var non-empty-string */ + return $time . pack('n*', self::$rand[1], self::$rand[2], self::$rand[3], self::$rand[4], self::$rand[5]); + } + + private function randomize(string $time): void + { + if (self::$seed === null) { + $seed = $this->randomGenerator->generate(16); + self::$seed = $seed; + } else { + $seed = $this->randomGenerator->generate(10); + } + + /** @var int[] $rand */ + $rand = unpack('n*', $seed); + $rand[1] &= 0x03ff; + + self::$rand = $rand; + self::$time = $time; + } + + /** + * Special thanks to Nicolas Grekas for sharing the following information: + * + * Within the same ms, we increment the rand part by a random 24-bit number. + * + * Instead of getting this number from random_bytes(), which is slow, we get + * it by sha512-hashing self::$seed. This produces 64 bytes of entropy, + * which we need to split in a list of 24-bit numbers. unpack() first splits + * them into 16 x 32-bit numbers; we take the first byte of each of these + * numbers to get 5 extra 24-bit numbers. Then, we consume those numbers + * one-by-one and run this logic every 21 iterations. + * + * self::$rand holds the random part of the UUID, split into 5 x 16-bit + * numbers for x86 portability. We increment this random part by the next + * 24-bit number in the self::$seedParts list and decrement + * self::$seedIndex. + * + * @link https://twitter.com/nicolasgrekas/status/1583356938825261061 Tweet from Nicolas Grekas + */ + private function increment(): string + { + if (self::$seedIndex === 0 && self::$seed !== null) { + self::$seed = hash('sha512', self::$seed, true); + + /** @var int[] $s */ + $s = unpack('l*', self::$seed); + $s[] = ($s[1] >> 8 & 0xff0000) | ($s[2] >> 16 & 0xff00) | ($s[3] >> 24 & 0xff); + $s[] = ($s[4] >> 8 & 0xff0000) | ($s[5] >> 16 & 0xff00) | ($s[6] >> 24 & 0xff); + $s[] = ($s[7] >> 8 & 0xff0000) | ($s[8] >> 16 & 0xff00) | ($s[9] >> 24 & 0xff); + $s[] = ($s[10] >> 8 & 0xff0000) | ($s[11] >> 16 & 0xff00) | ($s[12] >> 24 & 0xff); + $s[] = ($s[13] >> 8 & 0xff0000) | ($s[14] >> 16 & 0xff00) | ($s[15] >> 24 & 0xff); + + self::$seedParts = $s; + self::$seedIndex = 21; + } + + self::$rand[5] = 0xffff & $carry = self::$rand[5] + 1 + (self::$seedParts[self::$seedIndex--] & 0xffffff); + self::$rand[4] = 0xffff & $carry = self::$rand[4] + ($carry >> 16); + self::$rand[3] = 0xffff & $carry = self::$rand[3] + ($carry >> 16); + self::$rand[2] = 0xffff & $carry = self::$rand[2] + ($carry >> 16); + self::$rand[1] += $carry >> 16; + + if (0xfc00 & self::$rand[1]) { + $time = self::$time; + $mtime = (int) substr($time, -9); + + if ($this->intSize >= 8 || strlen($time) < 10) { + $time = (string) ((int) $time + 1); + } elseif ($mtime === 999999999) { + $time = (1 + (int) substr($time, 0, -9)) . '000000000'; + } else { + $mtime++; + $time = substr_replace($time, str_pad((string) $mtime, 9, '0', STR_PAD_LEFT), -9); + } + + $this->randomize($time); + } + + return self::$time; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Guid/Fields.php b/pandora_console/vendor/ramsey/uuid/src/Guid/Fields.php new file mode 100644 index 0000000000..0fc5d1c9ba --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Guid/Fields.php @@ -0,0 +1,195 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Guid; + +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Fields\SerializableFieldsTrait; +use Ramsey\Uuid\Rfc4122\FieldsInterface; +use Ramsey\Uuid\Rfc4122\MaxTrait; +use Ramsey\Uuid\Rfc4122\NilTrait; +use Ramsey\Uuid\Rfc4122\VariantTrait; +use Ramsey\Uuid\Rfc4122\VersionTrait; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Uuid; + +use function bin2hex; +use function dechex; +use function hexdec; +use function pack; +use function sprintf; +use function str_pad; +use function strlen; +use function substr; +use function unpack; + +use const STR_PAD_LEFT; + +/** + * GUIDs are comprised of a set of named fields, according to RFC 4122 + * + * @see Guid + * + * @psalm-immutable + */ +final class Fields implements FieldsInterface +{ + use MaxTrait; + use NilTrait; + use SerializableFieldsTrait; + use VariantTrait; + use VersionTrait; + + /** + * @param string $bytes A 16-byte binary string representation of a UUID + * + * @throws InvalidArgumentException if the byte string is not exactly 16 bytes + * @throws InvalidArgumentException if the byte string does not represent a GUID + * @throws InvalidArgumentException if the byte string does not contain a valid version + */ + public function __construct(private string $bytes) + { + if (strlen($this->bytes) !== 16) { + throw new InvalidArgumentException( + 'The byte string must be 16 bytes long; ' + . 'received ' . strlen($this->bytes) . ' bytes' + ); + } + + if (!$this->isCorrectVariant()) { + throw new InvalidArgumentException( + 'The byte string received does not conform to the RFC ' + . '4122 or Microsoft Corporation variants' + ); + } + + if (!$this->isCorrectVersion()) { + throw new InvalidArgumentException( + 'The byte string received does not contain a valid version' + ); + } + } + + public function getBytes(): string + { + return $this->bytes; + } + + public function getTimeLow(): Hexadecimal + { + // Swap the bytes from little endian to network byte order. + /** @var array $hex */ + $hex = unpack( + 'H*', + pack( + 'v*', + hexdec(bin2hex(substr($this->bytes, 2, 2))), + hexdec(bin2hex(substr($this->bytes, 0, 2))) + ) + ); + + return new Hexadecimal((string) ($hex[1] ?? '')); + } + + public function getTimeMid(): Hexadecimal + { + // Swap the bytes from little endian to network byte order. + /** @var array $hex */ + $hex = unpack( + 'H*', + pack( + 'v', + hexdec(bin2hex(substr($this->bytes, 4, 2))) + ) + ); + + return new Hexadecimal((string) ($hex[1] ?? '')); + } + + public function getTimeHiAndVersion(): Hexadecimal + { + // Swap the bytes from little endian to network byte order. + /** @var array $hex */ + $hex = unpack( + 'H*', + pack( + 'v', + hexdec(bin2hex(substr($this->bytes, 6, 2))) + ) + ); + + return new Hexadecimal((string) ($hex[1] ?? '')); + } + + public function getTimestamp(): Hexadecimal + { + return new Hexadecimal(sprintf( + '%03x%04s%08s', + hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff, + $this->getTimeMid()->toString(), + $this->getTimeLow()->toString() + )); + } + + public function getClockSeq(): Hexadecimal + { + if ($this->isMax()) { + $clockSeq = 0xffff; + } elseif ($this->isNil()) { + $clockSeq = 0x0000; + } else { + $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff; + } + + return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT)); + } + + public function getClockSeqHiAndReserved(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 8, 1))); + } + + public function getClockSeqLow(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 9, 1))); + } + + public function getNode(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 10))); + } + + public function getVersion(): ?int + { + if ($this->isNil() || $this->isMax()) { + return null; + } + + /** @var array $parts */ + $parts = unpack('n*', $this->bytes); + + return ((int) $parts[4] >> 4) & 0x00f; + } + + private function isCorrectVariant(): bool + { + if ($this->isNil() || $this->isMax()) { + return true; + } + + $variant = $this->getVariant(); + + return $variant === Uuid::RFC_4122 || $variant === Uuid::RESERVED_MICROSOFT; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Guid/Guid.php b/pandora_console/vendor/ramsey/uuid/src/Guid/Guid.php new file mode 100644 index 0000000000..b3ed096ab0 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Guid/Guid.php @@ -0,0 +1,61 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Guid; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Uuid; + +/** + * Guid represents a UUID with "native" (little-endian) byte order + * + * From Wikipedia: + * + * > The first three fields are unsigned 32- and 16-bit integers and are subject + * > to swapping, while the last two fields consist of uninterpreted bytes, not + * > subject to swapping. This byte swapping applies even for versions 3, 4, and + * > 5, where the canonical fields do not correspond to the content of the UUID. + * + * The first three fields of a GUID are encoded in little-endian byte order, + * while the last three fields are in network (big-endian) byte order. This is + * according to the history of the Microsoft definition of a GUID. + * + * According to the .NET Guid.ToByteArray method documentation: + * + * > Note that the order of bytes in the returned byte array is different from + * > the string representation of a Guid value. The order of the beginning + * > four-byte group and the next two two-byte groups is reversed, whereas the + * > order of the last two-byte group and the closing six-byte group is the + * > same. + * + * @link https://en.wikipedia.org/wiki/Universally_unique_identifier#Variants UUID Variants on Wikipedia + * @link https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid Windows GUID structure + * @link https://docs.microsoft.com/en-us/dotnet/api/system.guid .NET Guid Struct + * @link https://docs.microsoft.com/en-us/dotnet/api/system.guid.tobytearray .NET Guid.ToByteArray Method + * + * @psalm-immutable + */ +final class Guid extends Uuid +{ + public function __construct( + Fields $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Guid/GuidBuilder.php b/pandora_console/vendor/ramsey/uuid/src/Guid/GuidBuilder.php new file mode 100644 index 0000000000..c036bb20b0 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Guid/GuidBuilder.php @@ -0,0 +1,77 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Guid; + +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\UnableToBuildUuidException; +use Ramsey\Uuid\UuidInterface; +use Throwable; + +/** + * GuidBuilder builds instances of Guid + * + * @see Guid + * + * @psalm-immutable + */ +class GuidBuilder implements UuidBuilderInterface +{ + /** + * @param NumberConverterInterface $numberConverter The number converter to + * use when constructing the Guid + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to Unix timestamps + */ + public function __construct( + private NumberConverterInterface $numberConverter, + private TimeConverterInterface $timeConverter + ) { + } + + /** + * Builds and returns a Guid + * + * @param CodecInterface $codec The codec to use for building this Guid instance + * @param string $bytes The byte string from which to construct a UUID + * + * @return Guid The GuidBuilder returns an instance of Ramsey\Uuid\Guid\Guid + * + * @psalm-pure + */ + public function build(CodecInterface $codec, string $bytes): UuidInterface + { + try { + return new Guid( + $this->buildFields($bytes), + $this->numberConverter, + $codec, + $this->timeConverter + ); + } catch (Throwable $e) { + throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); + } + } + + /** + * Proxy method to allow injecting a mock, for testing + */ + protected function buildFields(string $bytes): Fields + { + return new Fields($bytes); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Lazy/LazyUuidFromString.php b/pandora_console/vendor/ramsey/uuid/src/Lazy/LazyUuidFromString.php new file mode 100644 index 0000000000..c0b47bbf2f --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Lazy/LazyUuidFromString.php @@ -0,0 +1,572 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Lazy; + +use DateTimeInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Exception\UnsupportedOperationException; +use Ramsey\Uuid\Fields\FieldsInterface; +use Ramsey\Uuid\Rfc4122\UuidV1; +use Ramsey\Uuid\Rfc4122\UuidV6; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\UuidFactory; +use Ramsey\Uuid\UuidInterface; +use ValueError; + +use function assert; +use function bin2hex; +use function hex2bin; +use function sprintf; +use function str_replace; +use function substr; + +/** + * Lazy version of a UUID: its format has not been determined yet, so it is mostly only usable for string/bytes + * conversion. This object optimizes instantiation, serialization and string conversion time, at the cost of + * increased overhead for more advanced UUID operations. + * + * @internal this type is used internally for performance reasons, and is not supposed to be directly referenced + * in consumer libraries. + * + * @psalm-immutable + * + * Note: the {@see FieldsInterface} does not declare methods that deprecated API + * relies upon: the API has been ported from the {@see \Ramsey\Uuid\Uuid} definition, + * and is deprecated anyway. + * Note: the deprecated API from {@see \Ramsey\Uuid\Uuid} is in use here (on purpose): it will be removed + * once the deprecated API is gone from this class too. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + */ +final class LazyUuidFromString implements UuidInterface +{ + public const VALID_REGEX = '/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/ms'; + + private ?UuidInterface $unwrapped = null; + + /** + * @psalm-param non-empty-string $uuid + */ + public function __construct(private string $uuid) + { + } + + /** @psalm-pure */ + public static function fromBytes(string $bytes): self + { + $base16Uuid = bin2hex($bytes); + + return new self( + substr($base16Uuid, 0, 8) + . '-' + . substr($base16Uuid, 8, 4) + . '-' + . substr($base16Uuid, 12, 4) + . '-' + . substr($base16Uuid, 16, 4) + . '-' + . substr($base16Uuid, 20, 12) + ); + } + + public function serialize(): string + { + return $this->uuid; + } + + /** + * @return array{string: string} + * + * @psalm-return array{string: non-empty-string} + */ + public function __serialize(): array + { + return ['string' => $this->uuid]; + } + + /** + * {@inheritDoc} + * + * @param string $data + * + * @psalm-param non-empty-string $data + */ + public function unserialize(string $data): void + { + $this->uuid = $data; + } + + /** + * @param array{string?: string} $data + * + * @psalm-param array{string?: non-empty-string} $data + * @psalm-suppress UnusedMethodCall + */ + public function __unserialize(array $data): void + { + // @codeCoverageIgnoreStart + if (!isset($data['string'])) { + throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); + } + // @codeCoverageIgnoreEnd + + $this->unserialize($data['string']); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getNumberConverter(): NumberConverterInterface + { + return ($this->unwrapped ?? $this->unwrap()) + ->getNumberConverter(); + } + + /** + * {@inheritDoc} + * + * @psalm-suppress DeprecatedMethod + */ + public function getFieldsHex(): array + { + return ($this->unwrapped ?? $this->unwrap()) + ->getFieldsHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getClockSeqHiAndReservedHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getClockSeqHiAndReservedHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getClockSeqLowHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getClockSeqLowHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getClockSequenceHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getClockSequenceHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getDateTime(): DateTimeInterface + { + return ($this->unwrapped ?? $this->unwrap()) + ->getDateTime(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getLeastSignificantBitsHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getLeastSignificantBitsHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getMostSignificantBitsHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getMostSignificantBitsHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getNodeHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getNodeHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getTimeHiAndVersionHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getTimeHiAndVersionHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getTimeLowHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getTimeLowHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getTimeMidHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getTimeMidHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getTimestampHex(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getTimestampHex(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getUrn(): string + { + return ($this->unwrapped ?? $this->unwrap()) + ->getUrn(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getVariant(): ?int + { + return ($this->unwrapped ?? $this->unwrap()) + ->getVariant(); + } + + /** @psalm-suppress DeprecatedMethod */ + public function getVersion(): ?int + { + return ($this->unwrapped ?? $this->unwrap()) + ->getVersion(); + } + + public function compareTo(UuidInterface $other): int + { + return ($this->unwrapped ?? $this->unwrap()) + ->compareTo($other); + } + + public function equals(?object $other): bool + { + if (! $other instanceof UuidInterface) { + return false; + } + + return $this->uuid === $other->toString(); + } + + /** + * {@inheritDoc} + * + * @psalm-suppress MoreSpecificReturnType + * @psalm-suppress LessSpecificReturnStatement we know that {@see self::$uuid} is a non-empty string, so + * we know that {@see hex2bin} will retrieve a non-empty string too. + */ + public function getBytes(): string + { + /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ + return (string) hex2bin(str_replace('-', '', $this->uuid)); + } + + public function getFields(): FieldsInterface + { + return ($this->unwrapped ?? $this->unwrap()) + ->getFields(); + } + + public function getHex(): Hexadecimal + { + return ($this->unwrapped ?? $this->unwrap()) + ->getHex(); + } + + public function getInteger(): IntegerObject + { + return ($this->unwrapped ?? $this->unwrap()) + ->getInteger(); + } + + public function toString(): string + { + return $this->uuid; + } + + public function __toString(): string + { + return $this->uuid; + } + + public function jsonSerialize(): string + { + return $this->uuid; + } + + /** + * @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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getClockSeqHiAndReserved(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex( + $instance->getFields() + ->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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getClockSeqLow(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex( + $instance->getFields() + ->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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getClockSequence(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex( + $instance->getFields() + ->getClockSeq() + ->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()}. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getLeastSignificantBits(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex(substr($instance->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()}. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getMostSignificantBits(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex(substr($instance->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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getNode(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex( + $instance->getFields() + ->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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getTimeHiAndVersion(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex( + $instance->getFields() + ->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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getTimeLow(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex( + $instance->getFields() + ->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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getTimeMid(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + return $instance->getNumberConverter() + ->fromHex( + $instance->getFields() + ->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. + * + * @psalm-suppress UndefinedInterfaceMethod + * @psalm-suppress DeprecatedMethod + * @psalm-suppress MixedArgument + * @psalm-suppress MixedMethodCall + */ + public function getTimestamp(): string + { + $instance = ($this->unwrapped ?? $this->unwrap()); + $fields = $instance->getFields(); + + if ($fields->getVersion() !== 1) { + throw new UnsupportedOperationException('Not a time-based UUID'); + } + + return $instance->getNumberConverter() + ->fromHex($fields->getTimestamp()->toString()); + } + + public function toUuidV1(): UuidV1 + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + if ($instance instanceof UuidV1) { + return $instance; + } + + assert($instance instanceof UuidV6); + + return $instance->toUuidV1(); + } + + public function toUuidV6(): UuidV6 + { + $instance = ($this->unwrapped ?? $this->unwrap()); + + assert($instance instanceof UuidV6); + + return $instance; + } + + /** + * @psalm-suppress ImpureMethodCall the retrieval of the factory is a clear violation of purity here: this is a + * known pitfall of the design of this library, where a value object contains + * a mutable reference to a factory. We use a fixed factory here, so the violation + * will not have real-world effects, as this object is only instantiated with the + * default factory settings/features. + * @psalm-suppress InaccessibleProperty property {@see $unwrapped} is used as a cache: we don't expose it to the + * outside world, so we should be fine here. + */ + private function unwrap(): UuidInterface + { + return $this->unwrapped = (new UuidFactory()) + ->fromString($this->uuid); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Math/BrickMathCalculator.php b/pandora_console/vendor/ramsey/uuid/src/Math/BrickMathCalculator.php new file mode 100644 index 0000000000..f2d86788cd --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Math/BrickMathCalculator.php @@ -0,0 +1,144 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Math; + +use Brick\Math\BigDecimal; +use Brick\Math\BigInteger; +use Brick\Math\Exception\MathException; +use Brick\Math\RoundingMode as BrickMathRounding; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Type\Decimal; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\Type\NumberInterface; + +/** + * A calculator using the brick/math library for arbitrary-precision arithmetic + * + * @psalm-immutable + */ +final class BrickMathCalculator implements CalculatorInterface +{ + private const ROUNDING_MODE_MAP = [ + RoundingMode::UNNECESSARY => BrickMathRounding::UNNECESSARY, + RoundingMode::UP => BrickMathRounding::UP, + RoundingMode::DOWN => BrickMathRounding::DOWN, + RoundingMode::CEILING => BrickMathRounding::CEILING, + RoundingMode::FLOOR => BrickMathRounding::FLOOR, + RoundingMode::HALF_UP => BrickMathRounding::HALF_UP, + RoundingMode::HALF_DOWN => BrickMathRounding::HALF_DOWN, + RoundingMode::HALF_CEILING => BrickMathRounding::HALF_CEILING, + RoundingMode::HALF_FLOOR => BrickMathRounding::HALF_FLOOR, + RoundingMode::HALF_EVEN => BrickMathRounding::HALF_EVEN, + ]; + + public function add(NumberInterface $augend, NumberInterface ...$addends): NumberInterface + { + $sum = BigInteger::of($augend->toString()); + + foreach ($addends as $addend) { + $sum = $sum->plus($addend->toString()); + } + + return new IntegerObject((string) $sum); + } + + public function subtract(NumberInterface $minuend, NumberInterface ...$subtrahends): NumberInterface + { + $difference = BigInteger::of($minuend->toString()); + + foreach ($subtrahends as $subtrahend) { + $difference = $difference->minus($subtrahend->toString()); + } + + return new IntegerObject((string) $difference); + } + + public function multiply(NumberInterface $multiplicand, NumberInterface ...$multipliers): NumberInterface + { + $product = BigInteger::of($multiplicand->toString()); + + foreach ($multipliers as $multiplier) { + $product = $product->multipliedBy($multiplier->toString()); + } + + return new IntegerObject((string) $product); + } + + public function divide( + int $roundingMode, + int $scale, + NumberInterface $dividend, + NumberInterface ...$divisors + ): NumberInterface { + $brickRounding = $this->getBrickRoundingMode($roundingMode); + + $quotient = BigDecimal::of($dividend->toString()); + + foreach ($divisors as $divisor) { + $quotient = $quotient->dividedBy($divisor->toString(), $scale, $brickRounding); + } + + if ($scale === 0) { + return new IntegerObject((string) $quotient->toBigInteger()); + } + + return new Decimal((string) $quotient); + } + + public function fromBase(string $value, int $base): IntegerObject + { + try { + return new IntegerObject((string) BigInteger::fromBase($value, $base)); + } catch (MathException | \InvalidArgumentException $exception) { + throw new InvalidArgumentException( + $exception->getMessage(), + (int) $exception->getCode(), + $exception + ); + } + } + + public function toBase(IntegerObject $value, int $base): string + { + try { + return BigInteger::of($value->toString())->toBase($base); + } catch (MathException | \InvalidArgumentException $exception) { + throw new InvalidArgumentException( + $exception->getMessage(), + (int) $exception->getCode(), + $exception + ); + } + } + + public function toHexadecimal(IntegerObject $value): Hexadecimal + { + return new Hexadecimal($this->toBase($value, 16)); + } + + public function toInteger(Hexadecimal $value): IntegerObject + { + return $this->fromBase($value->toString(), 16); + } + + /** + * Maps ramsey/uuid rounding modes to those used by brick/math + */ + private function getBrickRoundingMode(int $roundingMode): int + { + return self::ROUNDING_MODE_MAP[$roundingMode] ?? 0; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Math/CalculatorInterface.php b/pandora_console/vendor/ramsey/uuid/src/Math/CalculatorInterface.php new file mode 100644 index 0000000000..f03645d0f2 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Math/CalculatorInterface.php @@ -0,0 +1,106 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Math; + +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\Type\NumberInterface; + +/** + * A calculator performs arithmetic operations on numbers + * + * @psalm-immutable + */ +interface CalculatorInterface +{ + /** + * Returns the sum of all the provided parameters + * + * @param NumberInterface $augend The first addend (the integer being added to) + * @param NumberInterface ...$addends The additional integers to a add to the augend + * + * @return NumberInterface The sum of all the parameters + */ + public function add(NumberInterface $augend, NumberInterface ...$addends): NumberInterface; + + /** + * Returns the difference of all the provided parameters + * + * @param NumberInterface $minuend The integer being subtracted from + * @param NumberInterface ...$subtrahends The integers to subtract from the minuend + * + * @return NumberInterface The difference after subtracting all parameters + */ + public function subtract(NumberInterface $minuend, NumberInterface ...$subtrahends): NumberInterface; + + /** + * Returns the product of all the provided parameters + * + * @param NumberInterface $multiplicand The integer to be multiplied + * @param NumberInterface ...$multipliers The factors by which to multiply the multiplicand + * + * @return NumberInterface The product of multiplying all the provided parameters + */ + public function multiply(NumberInterface $multiplicand, NumberInterface ...$multipliers): NumberInterface; + + /** + * Returns the quotient of the provided parameters divided left-to-right + * + * @param int $roundingMode The RoundingMode constant to use for this operation + * @param int $scale The scale to use for this operation + * @param NumberInterface $dividend The integer to be divided + * @param NumberInterface ...$divisors The integers to divide $dividend by, in + * the order in which the division operations should take place + * (left-to-right) + * + * @return NumberInterface The quotient of dividing the provided parameters left-to-right + */ + public function divide( + int $roundingMode, + int $scale, + NumberInterface $dividend, + NumberInterface ...$divisors + ): NumberInterface; + + /** + * Converts a value from an arbitrary base to a base-10 integer value + * + * @param string $value The value to convert + * @param int $base The base to convert from (i.e., 2, 16, 32, etc.) + * + * @return IntegerObject The base-10 integer value of the converted value + */ + public function fromBase(string $value, int $base): IntegerObject; + + /** + * Converts a base-10 integer value to an arbitrary base + * + * @param IntegerObject $value The integer value to convert + * @param int $base The base to convert to (i.e., 2, 16, 32, etc.) + * + * @return string The value represented in the specified base + */ + public function toBase(IntegerObject $value, int $base): string; + + /** + * Converts an Integer instance to a Hexadecimal instance + */ + public function toHexadecimal(IntegerObject $value): Hexadecimal; + + /** + * Converts a Hexadecimal instance to an Integer instance + */ + public function toInteger(Hexadecimal $value): IntegerObject; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Math/RoundingMode.php b/pandora_console/vendor/ramsey/uuid/src/Math/RoundingMode.php new file mode 100644 index 0000000000..e710270d0e --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Math/RoundingMode.php @@ -0,0 +1,146 @@ += 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; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Nonstandard/Fields.php b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/Fields.php new file mode 100644 index 0000000000..5dfe610760 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/Fields.php @@ -0,0 +1,131 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Nonstandard; + +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Fields\SerializableFieldsTrait; +use Ramsey\Uuid\Rfc4122\FieldsInterface; +use Ramsey\Uuid\Rfc4122\VariantTrait; +use Ramsey\Uuid\Type\Hexadecimal; + +use function bin2hex; +use function dechex; +use function hexdec; +use function sprintf; +use function str_pad; +use function strlen; +use function substr; + +use const STR_PAD_LEFT; + +/** + * Nonstandard UUID fields do not conform to the RFC 4122 standard + * + * Since some systems may create nonstandard UUIDs, this implements the + * Rfc4122\FieldsInterface, so that functionality of a nonstandard UUID is not + * degraded, in the event these UUIDs are expected to contain RFC 4122 fields. + * + * Internally, this class represents the fields together as a 16-byte binary + * string. + * + * @psalm-immutable + */ +final class Fields implements FieldsInterface +{ + use SerializableFieldsTrait; + use VariantTrait; + + /** + * @param string $bytes A 16-byte binary string representation of a UUID + * + * @throws InvalidArgumentException if the byte string is not exactly 16 bytes + */ + public function __construct(private string $bytes) + { + if (strlen($this->bytes) !== 16) { + throw new InvalidArgumentException( + 'The byte string must be 16 bytes long; ' + . 'received ' . strlen($this->bytes) . ' bytes' + ); + } + } + + public function getBytes(): string + { + return $this->bytes; + } + + public function getClockSeq(): Hexadecimal + { + $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff; + + return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT)); + } + + public function getClockSeqHiAndReserved(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 8, 1))); + } + + public function getClockSeqLow(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 9, 1))); + } + + public function getNode(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 10))); + } + + public function getTimeHiAndVersion(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 6, 2))); + } + + public function getTimeLow(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 0, 4))); + } + + public function getTimeMid(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 4, 2))); + } + + public function getTimestamp(): Hexadecimal + { + return new Hexadecimal(sprintf( + '%03x%04s%08s', + hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff, + $this->getTimeMid()->toString(), + $this->getTimeLow()->toString() + )); + } + + public function getVersion(): ?int + { + return null; + } + + public function isNil(): bool + { + return false; + } + + public function isMax(): bool + { + return false; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Nonstandard/Uuid.php b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/Uuid.php new file mode 100644 index 0000000000..715f825547 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/Uuid.php @@ -0,0 +1,37 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Nonstandard; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Uuid as BaseUuid; + +/** + * Nonstandard\Uuid is a UUID that doesn't conform to RFC 4122 + * + * @psalm-immutable + */ +final class Uuid extends BaseUuid +{ + public function __construct( + Fields $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Nonstandard/UuidBuilder.php b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/UuidBuilder.php new file mode 100644 index 0000000000..82efd402fa --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/UuidBuilder.php @@ -0,0 +1,76 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Nonstandard; + +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\UnableToBuildUuidException; +use Ramsey\Uuid\UuidInterface; +use Throwable; + +/** + * Nonstandard\UuidBuilder builds instances of Nonstandard\Uuid + * + * @psalm-immutable + */ +class UuidBuilder implements UuidBuilderInterface +{ + /** + * @param NumberConverterInterface $numberConverter The number converter to + * use when constructing the Nonstandard\Uuid + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to Unix timestamps + */ + public function __construct( + private NumberConverterInterface $numberConverter, + private TimeConverterInterface $timeConverter + ) { + } + + /** + * Builds and returns a Nonstandard\Uuid + * + * @param CodecInterface $codec The codec to use for building this instance + * @param string $bytes The byte string from which to construct a UUID + * + * @return Uuid The Nonstandard\UuidBuilder returns an instance of + * Nonstandard\Uuid + * + * @psalm-pure + */ + public function build(CodecInterface $codec, string $bytes): UuidInterface + { + try { + return new Uuid( + $this->buildFields($bytes), + $this->numberConverter, + $codec, + $this->timeConverter + ); + } catch (Throwable $e) { + throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); + } + } + + /** + * Proxy method to allow injecting a mock, for testing + */ + protected function buildFields(string $bytes): Fields + { + return new Fields($bytes); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Nonstandard/UuidV6.php b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/UuidV6.php new file mode 100644 index 0000000000..7497dd1014 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Nonstandard/UuidV6.php @@ -0,0 +1,105 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Nonstandard; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Lazy\LazyUuidFromString; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Rfc4122\TimeTrait; +use Ramsey\Uuid\Rfc4122\UuidInterface; +use Ramsey\Uuid\Rfc4122\UuidV1; +use Ramsey\Uuid\Uuid as BaseUuid; + +/** + * Reordered time, or version 6, UUIDs include timestamp, clock sequence, and + * node values that are combined into a 128-bit unsigned integer + * + * @deprecated Use {@see \Ramsey\Uuid\Rfc4122\UuidV6} instead. + * + * @link https://github.com/uuid6/uuid6-ietf-draft UUID version 6 IETF draft + * @link http://gh.peabody.io/uuidv6/ "Version 6" UUIDs + * + * @psalm-immutable + */ +class UuidV6 extends BaseUuid implements UuidInterface +{ + use TimeTrait; + + /** + * Creates a version 6 (reordered time) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_REORDERED_TIME) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV6 must represent a ' + . 'version 6 (reordered time) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } + + /** + * Converts this UUID into an instance of a version 1 UUID + */ + public function toUuidV1(): UuidV1 + { + $hex = $this->getHex()->toString(); + $hex = substr($hex, 7, 5) + . substr($hex, 13, 3) + . substr($hex, 3, 4) + . '1' . substr($hex, 0, 3) + . substr($hex, 16); + + /** @var LazyUuidFromString $uuid */ + $uuid = Uuid::fromBytes((string) hex2bin($hex)); + + return $uuid->toUuidV1(); + } + + /** + * Converts a version 1 UUID into an instance of a version 6 UUID + */ + public static function fromUuidV1(UuidV1 $uuidV1): \Ramsey\Uuid\Rfc4122\UuidV6 + { + $hex = $uuidV1->getHex()->toString(); + $hex = substr($hex, 13, 3) + . substr($hex, 8, 4) + . substr($hex, 0, 5) + . '6' . substr($hex, 5, 3) + . substr($hex, 16); + + /** @var LazyUuidFromString $uuid */ + $uuid = Uuid::fromBytes((string) hex2bin($hex)); + + return $uuid->toUuidV6(); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Dce/SystemDceSecurityProvider.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Dce/SystemDceSecurityProvider.php new file mode 100644 index 0000000000..d5b6cf0c06 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Dce/SystemDceSecurityProvider.php @@ -0,0 +1,231 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Dce; + +use Ramsey\Uuid\Exception\DceSecurityException; +use Ramsey\Uuid\Provider\DceSecurityProviderInterface; +use Ramsey\Uuid\Type\Integer as IntegerObject; + +use function escapeshellarg; +use function preg_split; +use function str_getcsv; +use function strrpos; +use function strtolower; +use function strtoupper; +use function substr; +use function trim; + +use const PREG_SPLIT_NO_EMPTY; + +/** + * SystemDceSecurityProvider retrieves the user or group identifiers from the system + */ +class SystemDceSecurityProvider implements DceSecurityProviderInterface +{ + /** + * @throws DceSecurityException if unable to get a user identifier + * + * @inheritDoc + */ + public function getUid(): IntegerObject + { + /** @var int|float|string|IntegerObject|null $uid */ + static $uid = null; + + if ($uid instanceof IntegerObject) { + return $uid; + } + + if ($uid === null) { + $uid = $this->getSystemUid(); + } + + if ($uid === '') { + throw new DceSecurityException( + 'Unable to get a user identifier using the system DCE ' + . 'Security provider; please provide a custom identifier or ' + . 'use a different provider' + ); + } + + $uid = new IntegerObject($uid); + + return $uid; + } + + /** + * @throws DceSecurityException if unable to get a group identifier + * + * @inheritDoc + */ + public function getGid(): IntegerObject + { + /** @var int|float|string|IntegerObject|null $gid */ + static $gid = null; + + if ($gid instanceof IntegerObject) { + return $gid; + } + + if ($gid === null) { + $gid = $this->getSystemGid(); + } + + if ($gid === '') { + throw new DceSecurityException( + 'Unable to get a group identifier using the system DCE ' + . 'Security provider; please provide a custom identifier or ' + . 'use a different provider' + ); + } + + $gid = new IntegerObject($gid); + + return $gid; + } + + /** + * Returns the UID from the system + */ + private function getSystemUid(): string + { + if (!$this->hasShellExec()) { + return ''; + } + + return match ($this->getOs()) { + 'WIN' => $this->getWindowsUid(), + default => trim((string) shell_exec('id -u')), + }; + } + + /** + * Returns the GID from the system + */ + private function getSystemGid(): string + { + if (!$this->hasShellExec()) { + return ''; + } + + return match ($this->getOs()) { + 'WIN' => $this->getWindowsGid(), + default => trim((string) shell_exec('id -g')), + }; + } + + /** + * Returns true if shell_exec() is available for use + */ + private function hasShellExec(): bool + { + $disabledFunctions = strtolower((string) ini_get('disable_functions')); + + return !str_contains($disabledFunctions, 'shell_exec'); + } + + /** + * Returns the PHP_OS string + */ + private function getOs(): string + { + /** + * @psalm-suppress UnnecessaryVarAnnotation + * @var string $phpOs + */ + $phpOs = constant('PHP_OS'); + + return strtoupper(substr($phpOs, 0, 3)); + } + + /** + * Returns the user identifier for a user on a Windows system + * + * Windows does not have the same concept as an effective POSIX UID for the + * running script. Instead, each user is uniquely identified by an SID + * (security identifier). The SID includes three 32-bit unsigned integers + * that make up a unique domain identifier, followed by an RID (relative + * identifier) that we will use as the UID. The primary caveat is that this + * UID may not be unique to the system, since it is, instead, unique to the + * domain. + * + * @link https://www.lifewire.com/what-is-an-sid-number-2626005 What Is an SID Number? + * @link https://bit.ly/30vE7NM Well-known SID Structures + * @link https://bit.ly/2FWcYKJ Well-known security identifiers in Windows operating systems + * @link https://www.windows-commandline.com/get-sid-of-user/ Get SID of user + */ + private function getWindowsUid(): string + { + $response = shell_exec('whoami /user /fo csv /nh'); + + if ($response === null) { + return ''; + } + + $sid = str_getcsv(trim((string) $response))[1] ?? ''; + + if (($lastHyphen = strrpos($sid, '-')) === false) { + return ''; + } + + return trim(substr($sid, $lastHyphen + 1)); + } + + /** + * Returns a group identifier for a user on a Windows system + * + * Since Windows does not have the same concept as an effective POSIX GID + * for the running script, we will get the local group memberships for the + * user running the script. Then, we will get the SID (security identifier) + * for the first group that appears in that list. Finally, we will return + * the RID (relative identifier) for the group and use that as the GID. + * + * @link https://www.windows-commandline.com/list-of-user-groups-command-line/ List of user groups command line + */ + private function getWindowsGid(): string + { + $response = shell_exec('net user %username% | findstr /b /i "Local Group Memberships"'); + + if ($response === null) { + return ''; + } + + /** @var string[] $userGroups */ + $userGroups = preg_split('/\s{2,}/', (string) $response, -1, PREG_SPLIT_NO_EMPTY); + + $firstGroup = trim($userGroups[1] ?? '', "* \t\n\r\0\x0B"); + + if ($firstGroup === '') { + return ''; + } + + $response = shell_exec('wmic group get name,sid | findstr /b /i ' . escapeshellarg($firstGroup)); + + if ($response === null) { + return ''; + } + + /** @var string[] $userGroup */ + $userGroup = preg_split('/\s{2,}/', (string) $response, -1, PREG_SPLIT_NO_EMPTY); + + $sid = $userGroup[1] ?? ''; + + if (($lastHyphen = strrpos($sid, '-')) === false) { + return ''; + } + + return trim(substr($sid, $lastHyphen + 1)); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/DceSecurityProviderInterface.php b/pandora_console/vendor/ramsey/uuid/src/Provider/DceSecurityProviderInterface.php new file mode 100644 index 0000000000..8325da696f --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/DceSecurityProviderInterface.php @@ -0,0 +1,41 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider; + +use Ramsey\Uuid\Rfc4122\UuidV2; +use Ramsey\Uuid\Type\Integer as IntegerObject; + +/** + * A DCE provider provides access to local domain identifiers for version 2, + * DCE Security, UUIDs + * + * @see UuidV2 + */ +interface DceSecurityProviderInterface +{ + /** + * Returns a user identifier for the system + * + * @link https://en.wikipedia.org/wiki/User_identifier User identifier + */ + public function getUid(): IntegerObject; + + /** + * Returns a group identifier for the system + * + * @link https://en.wikipedia.org/wiki/Group_identifier Group identifier + */ + public function getGid(): IntegerObject; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php new file mode 100644 index 0000000000..d2eb20b708 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/FallbackNodeProvider.php @@ -0,0 +1,54 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Uuid\Exception\NodeException; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Type\Hexadecimal; + +/** + * FallbackNodeProvider retrieves the system node ID by stepping through a list + * of providers until a node ID can be obtained + */ +class FallbackNodeProvider implements NodeProviderInterface +{ + /** + * @param iterable $providers Array of node providers + */ + public function __construct(private iterable $providers) + { + } + + public function getNode(): Hexadecimal + { + $lastProviderException = null; + + foreach ($this->providers as $provider) { + try { + return $provider->getNode(); + } catch (NodeException $exception) { + $lastProviderException = $exception; + + continue; + } + } + + throw new NodeException( + 'Unable to find a suitable node provider', + 0, + $lastProviderException + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Node/NodeProviderCollection.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/NodeProviderCollection.php new file mode 100644 index 0000000000..1b979faee6 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/NodeProviderCollection.php @@ -0,0 +1,66 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Collection\AbstractCollection; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Type\Hexadecimal; + +/** + * A collection of NodeProviderInterface objects + * + * @deprecated this class has been deprecated, and will be removed in 5.0.0. The use-case for this class comes from + * a pre-`phpstan/phpstan` and pre-`vimeo/psalm` ecosystem, in which type safety had to be mostly enforced + * at runtime: that is no longer necessary, now that you can safely verify your code to be correct, and use + * more generic types like `iterable` instead. + * + * @extends AbstractCollection + */ +class NodeProviderCollection extends AbstractCollection +{ + public function getType(): string + { + return NodeProviderInterface::class; + } + + /** + * 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 $data */ + $data = unserialize($serialized, [ + 'allowed_classes' => [ + Hexadecimal::class, + RandomNodeProvider::class, + StaticNodeProvider::class, + SystemNodeProvider::class, + ], + ]); + + $this->data = array_filter( + $data, + function ($unserialized): bool { + return $unserialized instanceof NodeProviderInterface; + } + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php new file mode 100644 index 0000000000..76141361bd --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/RandomNodeProvider.php @@ -0,0 +1,69 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Uuid\Exception\RandomSourceException; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Type\Hexadecimal; +use Throwable; + +use function bin2hex; +use function dechex; +use function hex2bin; +use function hexdec; +use function str_pad; +use function substr; + +use const STR_PAD_LEFT; + +/** + * RandomNodeProvider generates a random node ID + * + * @link http://tools.ietf.org/html/rfc4122#section-4.5 RFC 4122, ยง 4.5: Node IDs that Do Not Identify the Host + */ +class RandomNodeProvider implements NodeProviderInterface +{ + public function getNode(): Hexadecimal + { + try { + $nodeBytes = random_bytes(6); + } catch (Throwable $exception) { + throw new RandomSourceException( + $exception->getMessage(), + (int) $exception->getCode(), + $exception + ); + } + + // Split the node bytes for math on 32-bit systems. + $nodeMsb = substr($nodeBytes, 0, 3); + $nodeLsb = substr($nodeBytes, 3); + + // Set the multicast bit; see RFC 4122, section 4.5. + $nodeMsb = hex2bin( + str_pad( + dechex(hexdec(bin2hex($nodeMsb)) | 0x010000), + 6, + '0', + STR_PAD_LEFT + ) + ); + + // Recombine the node bytes. + $node = $nodeMsb . $nodeLsb; + + return new Hexadecimal(str_pad(bin2hex($node), 12, '0', STR_PAD_LEFT)); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Node/StaticNodeProvider.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/StaticNodeProvider.php new file mode 100644 index 0000000000..0f7536a82e --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/StaticNodeProvider.php @@ -0,0 +1,73 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Type\Hexadecimal; + +use function dechex; +use function hexdec; +use function str_pad; +use function substr; + +use const STR_PAD_LEFT; + +/** + * StaticNodeProvider provides a static node value with the multicast bit set + * + * @link http://tools.ietf.org/html/rfc4122#section-4.5 RFC 4122, ยง 4.5: Node IDs that Do Not Identify the Host + */ +class StaticNodeProvider implements NodeProviderInterface +{ + private Hexadecimal $node; + + /** + * @param Hexadecimal $node The static node value to use + */ + public function __construct(Hexadecimal $node) + { + if (strlen($node->toString()) > 12) { + throw new InvalidArgumentException( + 'Static node value cannot be greater than 12 hexadecimal characters' + ); + } + + $this->node = $this->setMulticastBit($node); + } + + public function getNode(): Hexadecimal + { + return $this->node; + } + + /** + * Set the multicast bit for the static node value + */ + private function setMulticastBit(Hexadecimal $node): Hexadecimal + { + $nodeHex = str_pad($node->toString(), 12, '0', STR_PAD_LEFT); + $firstOctet = substr($nodeHex, 0, 2); + + $firstOctet = str_pad( + dechex(hexdec($firstOctet) | 0x01), + 2, + '0', + STR_PAD_LEFT + ); + + return new Hexadecimal($firstOctet . substr($nodeHex, 2)); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php new file mode 100644 index 0000000000..a03c93b4d0 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Node/SystemNodeProvider.php @@ -0,0 +1,193 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Uuid\Exception\NodeException; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Type\Hexadecimal; + +use function array_filter; +use function array_map; +use function array_walk; +use function count; +use function ob_get_clean; +use function ob_start; +use function preg_match; +use function preg_match_all; +use function reset; +use function str_contains; +use function str_replace; +use function strtolower; +use function strtoupper; +use function substr; + +use const GLOB_NOSORT; +use const PREG_PATTERN_ORDER; + +/** + * SystemNodeProvider retrieves the system node ID, if possible + * + * The system node ID, or host ID, is often the same as the MAC address for a + * network interface on the host. + */ +class SystemNodeProvider implements NodeProviderInterface +{ + /** + * Pattern to match nodes in ifconfig and ipconfig output. + */ + private const IFCONFIG_PATTERN = '/[^:]([0-9a-f]{2}([:-])[0-9a-f]{2}(\2[0-9a-f]{2}){4})[^:]/i'; + + /** + * Pattern to match nodes in sysfs stream output. + */ + private const SYSFS_PATTERN = '/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i'; + + public function getNode(): Hexadecimal + { + $node = $this->getNodeFromSystem(); + + if ($node === '') { + throw new NodeException( + 'Unable to fetch a node for this system' + ); + } + + return new Hexadecimal($node); + } + + /** + * Returns the system node, if it can find it + */ + protected function getNodeFromSystem(): string + { + static $node = null; + + if ($node !== null) { + return (string) $node; + } + + // First, try a Linux-specific approach. + $node = $this->getSysfs(); + + if ($node === '') { + // Search ifconfig output for MAC addresses & return the first one. + $node = $this->getIfconfig(); + } + + $node = str_replace([':', '-'], '', $node); + + return $node; + } + + /** + * Returns the network interface configuration for the system + * + * @codeCoverageIgnore + */ + protected function getIfconfig(): string + { + $disabledFunctions = strtolower((string) ini_get('disable_functions')); + + if (str_contains($disabledFunctions, 'passthru')) { + return ''; + } + + /** + * @psalm-suppress UnnecessaryVarAnnotation + * @var string $phpOs + */ + $phpOs = constant('PHP_OS'); + + ob_start(); + switch (strtoupper(substr($phpOs, 0, 3))) { + case 'WIN': + passthru('ipconfig /all 2>&1'); + + break; + case 'DAR': + passthru('ifconfig 2>&1'); + + break; + case 'FRE': + passthru('netstat -i -f link 2>&1'); + + break; + case 'LIN': + default: + passthru('netstat -ie 2>&1'); + + break; + } + + $ifconfig = (string) ob_get_clean(); + + if (preg_match_all(self::IFCONFIG_PATTERN, $ifconfig, $matches, PREG_PATTERN_ORDER)) { + foreach ($matches[1] as $iface) { + if ($iface !== '00:00:00:00:00:00' && $iface !== '00-00-00-00-00-00') { + return $iface; + } + } + } + + return ''; + } + + /** + * Returns MAC address from the first system interface via the sysfs interface + */ + protected function getSysfs(): string + { + $mac = ''; + + /** + * @psalm-suppress UnnecessaryVarAnnotation + * @var string $phpOs + */ + $phpOs = constant('PHP_OS'); + + if (strtoupper($phpOs) === 'LINUX') { + $addressPaths = glob('/sys/class/net/*/address', GLOB_NOSORT); + + if ($addressPaths === false || count($addressPaths) === 0) { + return ''; + } + + /** @var array $macs */ + $macs = []; + + array_walk($addressPaths, function (string $addressPath) use (&$macs): void { + if (is_readable($addressPath)) { + $macs[] = file_get_contents($addressPath); + } + }); + + /** @var callable $trim */ + $trim = 'trim'; + + $macs = array_map($trim, $macs); + + // Remove invalid entries. + $macs = array_filter($macs, function (string $address) { + return $address !== '00:00:00:00:00:00' + && preg_match(self::SYSFS_PATTERN, $address); + }); + + /** @var string|bool $mac */ + $mac = reset($macs); + } + + return (string) $mac; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/NodeProviderInterface.php b/pandora_console/vendor/ramsey/uuid/src/Provider/NodeProviderInterface.php new file mode 100644 index 0000000000..d536b45583 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/NodeProviderInterface.php @@ -0,0 +1,30 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider; + +use Ramsey\Uuid\Type\Hexadecimal; + +/** + * A node provider retrieves or generates a node ID + */ +interface NodeProviderInterface +{ + /** + * Returns a node ID + * + * @return Hexadecimal The node ID as a hexadecimal string + */ + public function getNode(): Hexadecimal; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php new file mode 100644 index 0000000000..526c8ff461 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Time/FixedTimeProvider.php @@ -0,0 +1,57 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Time; + +use Ramsey\Uuid\Provider\TimeProviderInterface; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\Type\Time; + +/** + * FixedTimeProvider uses a known time to provide the time + * + * This provider allows the use of a previously-generated, or known, time + * when generating time-based UUIDs. + */ +class FixedTimeProvider implements TimeProviderInterface +{ + public function __construct(private Time $time) + { + } + + /** + * Sets the `usec` component of the time + * + * @param int|string|IntegerObject $value The `usec` value to set + */ + public function setUsec($value): void + { + $this->time = new Time($this->time->getSeconds(), $value); + } + + /** + * Sets the `sec` component of the time + * + * @param int|string|IntegerObject $value The `sec` value to set + */ + public function setSec($value): void + { + $this->time = new Time($value, $this->time->getMicroseconds()); + } + + public function getTime(): Time + { + return $this->time; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php b/pandora_console/vendor/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php new file mode 100644 index 0000000000..3a1e09cb45 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/Time/SystemTimeProvider.php @@ -0,0 +1,33 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Time; + +use Ramsey\Uuid\Provider\TimeProviderInterface; +use Ramsey\Uuid\Type\Time; + +use function gettimeofday; + +/** + * SystemTimeProvider retrieves the current time using built-in PHP functions + */ +class SystemTimeProvider implements TimeProviderInterface +{ + public function getTime(): Time + { + $time = gettimeofday(); + + return new Time($time['sec'], $time['usec']); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Provider/TimeProviderInterface.php b/pandora_console/vendor/ramsey/uuid/src/Provider/TimeProviderInterface.php new file mode 100644 index 0000000000..43588e0bdd --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Provider/TimeProviderInterface.php @@ -0,0 +1,28 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider; + +use Ramsey\Uuid\Type\Time; + +/** + * A time provider retrieves the current time + */ +interface TimeProviderInterface +{ + /** + * Returns a time object + */ + public function getTime(): Time; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/Fields.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/Fields.php new file mode 100644 index 0000000000..9acf810c21 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/Fields.php @@ -0,0 +1,195 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Fields\SerializableFieldsTrait; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Uuid; + +use function bin2hex; +use function dechex; +use function hexdec; +use function sprintf; +use function str_pad; +use function strlen; +use function substr; +use function unpack; + +use const STR_PAD_LEFT; + +/** + * RFC 4122 variant UUIDs are comprised of a set of named fields + * + * Internally, this class represents the fields together as a 16-byte binary + * string. + * + * @psalm-immutable + */ +final class Fields implements FieldsInterface +{ + use MaxTrait; + use NilTrait; + use SerializableFieldsTrait; + use VariantTrait; + use VersionTrait; + + /** + * @param string $bytes A 16-byte binary string representation of a UUID + * + * @throws InvalidArgumentException if the byte string is not exactly 16 bytes + * @throws InvalidArgumentException if the byte string does not represent an RFC 4122 UUID + * @throws InvalidArgumentException if the byte string does not contain a valid version + */ + public function __construct(private string $bytes) + { + if (strlen($this->bytes) !== 16) { + throw new InvalidArgumentException( + 'The byte string must be 16 bytes long; ' + . 'received ' . strlen($this->bytes) . ' bytes' + ); + } + + if (!$this->isCorrectVariant()) { + throw new InvalidArgumentException( + 'The byte string received does not conform to the RFC 4122 variant' + ); + } + + if (!$this->isCorrectVersion()) { + throw new InvalidArgumentException( + 'The byte string received does not contain a valid RFC 4122 version' + ); + } + } + + public function getBytes(): string + { + return $this->bytes; + } + + public function getClockSeq(): Hexadecimal + { + if ($this->isMax()) { + $clockSeq = 0xffff; + } elseif ($this->isNil()) { + $clockSeq = 0x0000; + } else { + $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff; + } + + return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT)); + } + + public function getClockSeqHiAndReserved(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 8, 1))); + } + + public function getClockSeqLow(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 9, 1))); + } + + public function getNode(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 10))); + } + + public function getTimeHiAndVersion(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 6, 2))); + } + + public function getTimeLow(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 0, 4))); + } + + public function getTimeMid(): Hexadecimal + { + return new Hexadecimal(bin2hex(substr($this->bytes, 4, 2))); + } + + /** + * Returns the full 60-bit timestamp, without the version + * + * For version 2 UUIDs, the time_low field is the local identifier and + * should not be returned as part of the time. For this reason, we set the + * bottom 32 bits of the timestamp to 0's. As a result, there is some loss + * of fidelity of the timestamp, for version 2 UUIDs. The timestamp can be + * off by a range of 0 to 429.4967295 seconds (or 7 minutes, 9 seconds, and + * 496730 microseconds). + * + * For version 6 UUIDs, the timestamp order is reversed from the typical RFC + * 4122 order (the time bits are in the correct bit order, so that it is + * monotonically increasing). In returning the timestamp value, we put the + * bits in the order: time_low + time_mid + time_hi. + */ + public function getTimestamp(): Hexadecimal + { + $timestamp = match ($this->getVersion()) { + Uuid::UUID_TYPE_DCE_SECURITY => sprintf( + '%03x%04s%08s', + hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff, + $this->getTimeMid()->toString(), + '' + ), + Uuid::UUID_TYPE_REORDERED_TIME => sprintf( + '%08s%04s%03x', + $this->getTimeLow()->toString(), + $this->getTimeMid()->toString(), + hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff + ), + // The Unix timestamp in version 7 UUIDs is a 48-bit number, + // but for consistency, we will return a 60-bit number, padded + // to the left with zeros. + Uuid::UUID_TYPE_UNIX_TIME => sprintf( + '%011s%04s', + $this->getTimeLow()->toString(), + $this->getTimeMid()->toString(), + ), + default => sprintf( + '%03x%04s%08s', + hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff, + $this->getTimeMid()->toString(), + $this->getTimeLow()->toString() + ), + }; + + return new Hexadecimal($timestamp); + } + + public function getVersion(): ?int + { + if ($this->isNil() || $this->isMax()) { + return null; + } + + /** @var int[] $parts */ + $parts = unpack('n*', $this->bytes); + + return $parts[4] >> 12; + } + + private function isCorrectVariant(): bool + { + if ($this->isNil() || $this->isMax()) { + return true; + } + + return $this->getVariant() === Uuid::RFC_4122; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/FieldsInterface.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/FieldsInterface.php new file mode 100644 index 0000000000..2241cf574d --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/FieldsInterface.php @@ -0,0 +1,128 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Fields\FieldsInterface as BaseFieldsInterface; +use Ramsey\Uuid\Type\Hexadecimal; + +/** + * RFC 4122 defines fields for a specific variant of UUID + * + * The fields of an RFC 4122 variant UUID are: + * + * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer + * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer + * * **time_hi_and_version**: The high field of the timestamp multiplexed with + * the version number, an unsigned 16-bit integer + * * **clock_seq_hi_and_reserved**: The high field of the clock sequence + * multiplexed with the variant, an unsigned 8-bit integer + * * **clock_seq_low**: The low field of the clock sequence, an unsigned + * 8-bit integer + * * **node**: The spatially unique node identifier, an unsigned 48-bit + * integer + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1 RFC 4122, ยง 4.1: Format + * + * @psalm-immutable + */ +interface FieldsInterface extends BaseFieldsInterface +{ + /** + * Returns the full 16-bit clock sequence, with the variant bits (two most + * significant bits) masked out + */ + public function getClockSeq(): Hexadecimal; + + /** + * Returns the high field of the clock sequence multiplexed with the variant + */ + public function getClockSeqHiAndReserved(): Hexadecimal; + + /** + * Returns the low field of the clock sequence + */ + public function getClockSeqLow(): Hexadecimal; + + /** + * Returns the node field + */ + public function getNode(): Hexadecimal; + + /** + * Returns the high field of the timestamp multiplexed with the version + */ + public function getTimeHiAndVersion(): Hexadecimal; + + /** + * Returns the low field of the timestamp + */ + public function getTimeLow(): Hexadecimal; + + /** + * Returns the middle field of the timestamp + */ + public function getTimeMid(): Hexadecimal; + + /** + * Returns the full 60-bit timestamp, without the version + */ + public function getTimestamp(): Hexadecimal; + + /** + * Returns the variant + * + * The variant number describes the layout of the UUID. The variant + * number has the following meaning: + * + * - 0 - Reserved for NCS backward compatibility + * - 2 - The RFC 4122 variant + * - 6 - Reserved, Microsoft Corporation backward compatibility + * - 7 - Reserved for future definition + * + * For RFC 4122 variant UUIDs, this value should always be the integer `2`. + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, ยง 4.1.1: Variant + */ + public function getVariant(): int; + + /** + * Returns the version + * + * The version number describes how the UUID was generated and has the + * following meaning: + * + * 1. Gregorian time UUID + * 2. DCE security UUID + * 3. Name-based UUID hashed with MD5 + * 4. Randomly generated UUID + * 5. Name-based UUID hashed with SHA-1 + * 6. Reordered time UUID + * 7. Unix Epoch time UUID + * + * This returns `null` if the UUID is not an RFC 4122 variant, since version + * is only meaningful for this variant. + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, ยง 4.1.3: Version + */ + public function getVersion(): ?int; + + /** + * Returns true if these fields represent a nil UUID + * + * The nil UUID is special form of UUID that is specified to have all 128 + * bits set to zero. + */ + public function isNil(): bool; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/MaxTrait.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/MaxTrait.php new file mode 100644 index 0000000000..dedb727980 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/MaxTrait.php @@ -0,0 +1,41 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +/** + * Provides common functionality for max UUIDs + * + * The max UUID is special form of UUID that is specified to have all 128 bits + * set to one. It is the inverse of the nil UUID. + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID + * + * @psalm-immutable + */ +trait MaxTrait +{ + /** + * Returns the bytes that comprise the fields + */ + abstract public function getBytes(): string; + + /** + * Returns true if the byte string represents a max UUID + */ + public function isMax(): bool + { + return $this->getBytes() === "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/MaxUuid.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/MaxUuid.php new file mode 100644 index 0000000000..e5ffa72c6b --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/MaxUuid.php @@ -0,0 +1,27 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Uuid; + +/** + * The max UUID is special form of UUID that is specified to have all 128 bits + * set to one + * + * @psalm-immutable + */ +final class MaxUuid extends Uuid implements UuidInterface +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/NilTrait.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/NilTrait.php new file mode 100644 index 0000000000..9a9774d896 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/NilTrait.php @@ -0,0 +1,41 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +/** + * Provides common functionality for nil UUIDs + * + * The nil UUID is special form of UUID that is specified to have all 128 bits + * set to zero. + * + * @link https://tools.ietf.org/html/rfc4122#section-4.1.7 RFC 4122, ยง 4.1.7: Nil UUID + * + * @psalm-immutable + */ +trait NilTrait +{ + /** + * Returns the bytes that comprise the fields + */ + abstract public function getBytes(): string; + + /** + * Returns true if the byte string represents a nil UUID + */ + public function isNil(): bool + { + return $this->getBytes() === "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/NilUuid.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/NilUuid.php new file mode 100644 index 0000000000..c49b9945d6 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/NilUuid.php @@ -0,0 +1,27 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Uuid; + +/** + * The nil UUID is special form of UUID that is specified to have all 128 bits + * set to zero + * + * @psalm-immutable + */ +final class NilUuid extends Uuid implements UuidInterface +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/TimeTrait.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/TimeTrait.php new file mode 100644 index 0000000000..5d939fac64 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/TimeTrait.php @@ -0,0 +1,55 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use DateTimeImmutable; +use DateTimeInterface; +use Ramsey\Uuid\Exception\DateTimeException; +use Throwable; + +use function str_pad; + +use const STR_PAD_LEFT; + +/** + * Provides common functionality for getting the time from a time-based UUID + * + * @psalm-immutable + */ +trait TimeTrait +{ + /** + * Returns a DateTimeInterface object representing the timestamp associated + * with the UUID + * + * @return DateTimeImmutable A PHP DateTimeImmutable instance representing + * the timestamp of a time-based UUID + */ + public function getDateTime(): DateTimeInterface + { + $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); + } + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidBuilder.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidBuilder.php new file mode 100644 index 0000000000..2c2677db76 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidBuilder.php @@ -0,0 +1,118 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\Time\UnixTimeConverter; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\UnableToBuildUuidException; +use Ramsey\Uuid\Exception\UnsupportedOperationException; +use Ramsey\Uuid\Math\BrickMathCalculator; +use Ramsey\Uuid\Rfc4122\UuidInterface as Rfc4122UuidInterface; +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\UuidInterface; +use Throwable; + +/** + * UuidBuilder builds instances of RFC 4122 UUIDs + * + * @psalm-immutable + */ +class UuidBuilder implements UuidBuilderInterface +{ + private TimeConverterInterface $unixTimeConverter; + + /** + * Constructs the DefaultUuidBuilder + * + * @param NumberConverterInterface $numberConverter The number converter to + * use when constructing the Uuid + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting Gregorian time extracted from version 1, 2, and 6 + * UUIDs to Unix timestamps + * @param TimeConverterInterface|null $unixTimeConverter The time converter + * to use for converter Unix Epoch time extracted from version 7 UUIDs + * to Unix timestamps + */ + public function __construct( + private NumberConverterInterface $numberConverter, + private TimeConverterInterface $timeConverter, + ?TimeConverterInterface $unixTimeConverter = null + ) { + $this->unixTimeConverter = $unixTimeConverter ?? new UnixTimeConverter(new BrickMathCalculator()); + } + + /** + * Builds and returns a Uuid + * + * @param CodecInterface $codec The codec to use for building this Uuid instance + * @param string $bytes The byte string from which to construct a UUID + * + * @return Rfc4122UuidInterface UuidBuilder returns instances of Rfc4122UuidInterface + * + * @psalm-pure + */ + public function build(CodecInterface $codec, string $bytes): UuidInterface + { + try { + /** @var Fields $fields */ + $fields = $this->buildFields($bytes); + + if ($fields->isNil()) { + return new NilUuid($fields, $this->numberConverter, $codec, $this->timeConverter); + } + + if ($fields->isMax()) { + return new MaxUuid($fields, $this->numberConverter, $codec, $this->timeConverter); + } + + switch ($fields->getVersion()) { + case Uuid::UUID_TYPE_TIME: + return new UuidV1($fields, $this->numberConverter, $codec, $this->timeConverter); + case Uuid::UUID_TYPE_DCE_SECURITY: + return new UuidV2($fields, $this->numberConverter, $codec, $this->timeConverter); + case Uuid::UUID_TYPE_HASH_MD5: + return new UuidV3($fields, $this->numberConverter, $codec, $this->timeConverter); + case Uuid::UUID_TYPE_RANDOM: + return new UuidV4($fields, $this->numberConverter, $codec, $this->timeConverter); + case Uuid::UUID_TYPE_HASH_SHA1: + return new UuidV5($fields, $this->numberConverter, $codec, $this->timeConverter); + case Uuid::UUID_TYPE_REORDERED_TIME: + return new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter); + case Uuid::UUID_TYPE_UNIX_TIME: + return new UuidV7($fields, $this->numberConverter, $codec, $this->unixTimeConverter); + case Uuid::UUID_TYPE_CUSTOM: + return new UuidV8($fields, $this->numberConverter, $codec, $this->timeConverter); + } + + throw new UnsupportedOperationException( + 'The UUID version in the given fields is not supported ' + . 'by this UUID builder' + ); + } catch (Throwable $e) { + throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); + } + } + + /** + * Proxy method to allow injecting a mock, for testing + */ + protected function buildFields(string $bytes): FieldsInterface + { + return new Fields($bytes); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidInterface.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidInterface.php new file mode 100644 index 0000000000..e80f33bef4 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidInterface.php @@ -0,0 +1,29 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\UuidInterface as BaseUuidInterface; + +/** + * Also known as a Leach-Salz variant UUID, an RFC 4122 variant UUID is a + * universally unique identifier defined by RFC 4122 + * + * @link https://tools.ietf.org/html/rfc4122 RFC 4122 + * + * @psalm-immutable + */ +interface UuidInterface extends BaseUuidInterface +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV1.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV1.php new file mode 100644 index 0000000000..515c038d99 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV1.php @@ -0,0 +1,60 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Uuid; + +/** + * Gregorian time, or version 1, UUIDs include timestamp, clock sequence, and node + * values that are combined into a 128-bit unsigned integer + * + * @psalm-immutable + */ +final class UuidV1 extends Uuid implements UuidInterface +{ + use TimeTrait; + + /** + * Creates a version 1 (Gregorian time) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_TIME) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV1 must represent a ' + . 'version 1 (time-based) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV2.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV2.php new file mode 100644 index 0000000000..c8ccbe4228 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV2.php @@ -0,0 +1,115 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\Uuid; + +use function hexdec; + +/** + * DCE Security version, or version 2, UUIDs include local domain identifier, + * local ID for the specified domain, and node values that are combined into a + * 128-bit unsigned integer + * + * It is important to note that a version 2 UUID suffers from some loss of + * fidelity of the timestamp, due to replacing the time_low field with the + * local identifier. When constructing the timestamp value for date + * purposes, we replace the local identifier bits with zeros. As a result, + * the timestamp can be off by a range of 0 to 429.4967295 seconds (or 7 + * minutes, 9 seconds, and 496730 microseconds). + * + * Astute observers might note this value directly corresponds to 2^32 - 1, + * or 0xffffffff. The local identifier is 32-bits, and we have set each of + * these bits to 0, so the maximum range of timestamp drift is 0x00000000 + * to 0xffffffff (counted in 100-nanosecond intervals). + * + * @link https://publications.opengroup.org/c311 DCE 1.1: Authentication and Security Services + * @link https://publications.opengroup.org/c706 DCE 1.1: Remote Procedure Call + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01 DCE 1.1: Auth & Sec, ยง5.2.1.1 + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1: Auth & Sec, ยง11.5.1.1 + * @link https://pubs.opengroup.org/onlinepubs/9629399/apdxa.htm DCE 1.1: RPC, Appendix A + * @link https://github.com/google/uuid Go package for UUIDs (includes DCE implementation) + * + * @psalm-immutable + */ +final class UuidV2 extends Uuid implements UuidInterface +{ + use TimeTrait; + + /** + * Creates a version 2 (DCE Security) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_DCE_SECURITY) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV2 must represent a ' + . 'version 2 (DCE Security) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } + + /** + * Returns the local domain used to create this version 2 UUID + */ + public function getLocalDomain(): int + { + /** @var Rfc4122FieldsInterface $fields */ + $fields = $this->getFields(); + + return (int) hexdec($fields->getClockSeqLow()->toString()); + } + + /** + * Returns the string name of the local domain + */ + public function getLocalDomainName(): string + { + return Uuid::DCE_DOMAIN_NAMES[$this->getLocalDomain()]; + } + + /** + * Returns the local identifier for the domain used to create this version 2 UUID + */ + public function getLocalIdentifier(): IntegerObject + { + /** @var Rfc4122FieldsInterface $fields */ + $fields = $this->getFields(); + + return new IntegerObject( + $this->numberConverter->fromHex($fields->getTimeLow()->toString()) + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV3.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV3.php new file mode 100644 index 0000000000..deaa54eb03 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV3.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Uuid; + +/** + * Version 3 UUIDs are named-based, using combination of a namespace and name + * that are hashed into a 128-bit unsigned integer using MD5 + * + * @psalm-immutable + */ +final class UuidV3 extends Uuid implements UuidInterface +{ + /** + * Creates a version 3 (name-based, MD5-hashed) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_HASH_MD5) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV3 must represent a ' + . 'version 3 (name-based, MD5-hashed) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV4.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV4.php new file mode 100644 index 0000000000..2e57246208 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV4.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Uuid; + +/** + * Random, or version 4, UUIDs are randomly or pseudo-randomly generated 128-bit + * integers + * + * @psalm-immutable + */ +final class UuidV4 extends Uuid implements UuidInterface +{ + /** + * Creates a version 4 (random) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_RANDOM) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV4 must represent a ' + . 'version 4 (random) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV5.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV5.php new file mode 100644 index 0000000000..2ef6ab3f16 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV5.php @@ -0,0 +1,58 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Uuid; + +/** + * Version 5 UUIDs are named-based, using combination of a namespace and name + * that are hashed into a 128-bit unsigned integer using SHA1 + * + * @psalm-immutable + */ +final class UuidV5 extends Uuid implements UuidInterface +{ + /** + * Creates a version 5 (name-based, SHA1-hashed) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_HASH_SHA1) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV5 must represent a ' + . 'version 5 (named-based, SHA1-hashed) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV6.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV6.php new file mode 100644 index 0000000000..7e3743391b --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV6.php @@ -0,0 +1,29 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Nonstandard\UuidV6 as NonstandardUuidV6; + +/** + * Reordered time, or version 6, UUIDs include timestamp, clock sequence, and + * node values that are combined into a 128-bit unsigned integer + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6 + * + * @psalm-immutable + */ +final class UuidV6 extends NonstandardUuidV6 implements UuidInterface +{ +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV7.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV7.php new file mode 100644 index 0000000000..5b524c486a --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV7.php @@ -0,0 +1,62 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Uuid; + +/** + * Unix Epoch time, or version 7, UUIDs include a timestamp in milliseconds + * since the Unix Epoch, along with random bytes + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7 + * + * @psalm-immutable + */ +final class UuidV7 extends Uuid implements UuidInterface +{ + use TimeTrait; + + /** + * Creates a version 7 (Unix Epoch time) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_UNIX_TIME) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV7 must represent a ' + . 'version 7 (Unix Epoch time) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV8.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV8.php new file mode 100644 index 0000000000..78b0290c7a --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/UuidV8.php @@ -0,0 +1,65 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\InvalidArgumentException; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Uuid; + +/** + * Version 8, Custom UUIDs provide an RFC 4122 compatible format for + * experimental or vendor-specific uses + * + * The only requirement for version 8 UUIDs is that the version and variant bits + * must be set. Otherwise, implementations are free to set the other bits + * according to their needs. As a result, the uniqueness of version 8 UUIDs is + * implementation-specific and should not be assumed. + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8 + * + * @psalm-immutable + */ +final class UuidV8 extends Uuid implements UuidInterface +{ + /** + * Creates a version 8 (custom) UUID + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + if ($fields->getVersion() !== Uuid::UUID_TYPE_CUSTOM) { + throw new InvalidArgumentException( + 'Fields used to create a UuidV8 must represent a ' + . 'version 8 (custom) UUID' + ); + } + + parent::__construct($fields, $numberConverter, $codec, $timeConverter); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/Validator.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/Validator.php new file mode 100644 index 0000000000..e82a11e6e8 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/Validator.php @@ -0,0 +1,50 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Uuid; +use Ramsey\Uuid\Validator\ValidatorInterface; + +use function preg_match; +use function str_replace; + +/** + * Rfc4122\Validator validates strings as UUIDs of the RFC 4122 variant + * + * @psalm-immutable + */ +final class Validator implements ValidatorInterface +{ + private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-' + . '[1-8][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z'; + + /** + * @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 getPattern(): string + { + return self::VALID_PATTERN; + } + + public function validate(string $uuid): bool + { + $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); + $uuid = strtolower($uuid); + + return $uuid === Uuid::NIL || $uuid === Uuid::MAX || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/VariantTrait.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/VariantTrait.php new file mode 100644 index 0000000000..1041de51ea --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/VariantTrait.php @@ -0,0 +1,94 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Exception\InvalidBytesException; +use Ramsey\Uuid\Uuid; + +use function decbin; +use function str_pad; +use function str_starts_with; +use function strlen; +use function substr; +use function unpack; + +use const STR_PAD_LEFT; + +/** + * Provides common functionality for handling the variant, as defined by RFC 4122 + * + * @psalm-immutable + */ +trait VariantTrait +{ + /** + * Returns the bytes that comprise the fields + */ + abstract public function getBytes(): string; + + /** + * Returns the variant identifier, according to RFC 4122, for the given bytes + * + * The following values may be returned: + * + * - `0` -- Reserved, NCS backward compatibility. + * - `2` -- The variant specified in RFC 4122. + * - `6` -- Reserved, Microsoft Corporation backward compatibility. + * - `7` -- Reserved for future definition. + * + * @link https://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, ยง 4.1.1: Variant + * + * @return int The variant identifier, according to RFC 4122 + */ + public function getVariant(): int + { + if (strlen($this->getBytes()) !== 16) { + throw new InvalidBytesException('Invalid number of bytes'); + } + + if ($this->isMax() || $this->isNil()) { + // RFC 4122 defines these special types of UUID, so we will consider + // them as belonging to the RFC 4122 variant. + return Uuid::RFC_4122; + } + + /** @var int[] $parts */ + $parts = unpack('n*', $this->getBytes()); + + // $parts[5] is a 16-bit, unsigned integer containing the variant bits + // of the UUID. We convert this integer into a string containing a + // binary representation, padded to 16 characters. We analyze the first + // three characters (three most-significant bits) to determine the + // variant. + $binary = str_pad( + decbin($parts[5]), + 16, + '0', + STR_PAD_LEFT + ); + + $msb = substr($binary, 0, 3); + + if ($msb === '111') { + return Uuid::RESERVED_FUTURE; + } elseif ($msb === '110') { + return Uuid::RESERVED_MICROSOFT; + } elseif (str_starts_with($msb, '10')) { + return Uuid::RFC_4122; + } + + return Uuid::RESERVED_NCS; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Rfc4122/VersionTrait.php b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/VersionTrait.php new file mode 100644 index 0000000000..0195e46c7e --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Rfc4122/VersionTrait.php @@ -0,0 +1,60 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Rfc4122; + +use Ramsey\Uuid\Uuid; + +/** + * Provides common functionality for handling the version, as defined by RFC 4122 + * + * @psalm-immutable + */ +trait VersionTrait +{ + /** + * Returns the version + */ + abstract public function getVersion(): ?int; + + /** + * Returns true if these fields represent a max UUID + */ + abstract public function isMax(): bool; + + /** + * Returns true if these fields represent a nil UUID + */ + abstract public function isNil(): bool; + + /** + * Returns true if the version matches one of those defined by RFC 4122 + * + * @return bool True if the UUID version is valid, false otherwise + */ + private function isCorrectVersion(): bool + { + if ($this->isNil() || $this->isMax()) { + return true; + } + + return match ($this->getVersion()) { + Uuid::UUID_TYPE_TIME, Uuid::UUID_TYPE_DCE_SECURITY, + Uuid::UUID_TYPE_HASH_MD5, Uuid::UUID_TYPE_RANDOM, + Uuid::UUID_TYPE_HASH_SHA1, Uuid::UUID_TYPE_REORDERED_TIME, + Uuid::UUID_TYPE_UNIX_TIME, Uuid::UUID_TYPE_CUSTOM => true, + default => false, + }; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Type/Decimal.php b/pandora_console/vendor/ramsey/uuid/src/Type/Decimal.php new file mode 100644 index 0000000000..acc5e754be --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Type/Decimal.php @@ -0,0 +1,129 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Type; + +use Ramsey\Uuid\Exception\InvalidArgumentException; +use ValueError; + +use function is_numeric; +use function sprintf; +use function str_starts_with; + +/** + * A value object representing a decimal + * + * This class exists for type-safety purposes, to ensure that decimals + * returned from ramsey/uuid methods as strings are truly decimals and not some + * other kind of string. + * + * To support values as true decimals and not as floats or doubles, we store the + * decimals as strings. + * + * @psalm-immutable + */ +final class Decimal implements NumberInterface +{ + private string $value; + private bool $isNegative = false; + + public function __construct(float | int | string | self $value) + { + $value = (string) $value; + + if (!is_numeric($value)) { + throw new InvalidArgumentException( + 'Value must be a signed decimal or a string containing only ' + . 'digits 0-9 and, optionally, a decimal point or sign (+ or -)' + ); + } + + // Remove the leading +-symbol. + if (str_starts_with($value, '+')) { + $value = substr($value, 1); + } + + // For cases like `-0` or `-0.0000`, convert the value to `0`. + if (abs((float) $value) === 0.0) { + $value = '0'; + } + + if (str_starts_with($value, '-')) { + $this->isNegative = true; + } + + $this->value = $value; + } + + public function isNegative(): bool + { + return $this->isNegative; + } + + public function toString(): string + { + return $this->value; + } + + public function __toString(): string + { + return $this->toString(); + } + + public function jsonSerialize(): string + { + return $this->toString(); + } + + public function serialize(): string + { + return $this->toString(); + } + + /** + * @return array{string: string} + */ + public function __serialize(): array + { + return ['string' => $this->toString()]; + } + + /** + * Constructs the object from a serialized string representation + * + * @param string $data The serialized string representation of the object + * + * @psalm-suppress UnusedMethodCall + */ + public function unserialize(string $data): void + { + $this->__construct($data); + } + + /** + * @param array{string?: string} $data + * + * @psalm-suppress UnusedMethodCall + */ + public function __unserialize(array $data): void + { + // @codeCoverageIgnoreStart + if (!isset($data['string'])) { + throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); + } + // @codeCoverageIgnoreEnd + + $this->unserialize($data['string']); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Type/Hexadecimal.php b/pandora_console/vendor/ramsey/uuid/src/Type/Hexadecimal.php new file mode 100644 index 0000000000..bf71ec4b1d --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Type/Hexadecimal.php @@ -0,0 +1,115 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Type; + +use Ramsey\Uuid\Exception\InvalidArgumentException; +use ValueError; + +use function preg_match; +use function sprintf; +use function substr; + +/** + * A value object representing a hexadecimal number + * + * This class exists for type-safety purposes, to ensure that hexadecimal numbers + * returned from ramsey/uuid methods as strings are truly hexadecimal and not some + * other kind of string. + * + * @psalm-immutable + */ +final class Hexadecimal implements TypeInterface +{ + private string $value; + + /** + * @param self|string $value The hexadecimal value to store + */ + public function __construct(self | string $value) + { + $this->value = $value instanceof self ? (string) $value : $this->prepareValue($value); + } + + public function toString(): string + { + return $this->value; + } + + public function __toString(): string + { + return $this->toString(); + } + + public function jsonSerialize(): string + { + return $this->toString(); + } + + public function serialize(): string + { + return $this->toString(); + } + + /** + * @return array{string: string} + */ + public function __serialize(): array + { + return ['string' => $this->toString()]; + } + + /** + * Constructs the object from a serialized string representation + * + * @param string $data The serialized string representation of the object + * + * @psalm-suppress UnusedMethodCall + */ + public function unserialize(string $data): void + { + $this->__construct($data); + } + + /** + * @param array{string?: string} $data + */ + public function __unserialize(array $data): void + { + // @codeCoverageIgnoreStart + if (!isset($data['string'])) { + throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); + } + // @codeCoverageIgnoreEnd + + $this->unserialize($data['string']); + } + + private function prepareValue(string $value): string + { + $value = strtolower($value); + + if (str_starts_with($value, '0x')) { + $value = substr($value, 2); + } + + if (!preg_match('/^[A-Fa-f0-9]+$/', $value)) { + throw new InvalidArgumentException( + 'Value must be a hexadecimal number' + ); + } + + return $value; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Type/Integer.php b/pandora_console/vendor/ramsey/uuid/src/Type/Integer.php new file mode 100644 index 0000000000..50dac9934c --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Type/Integer.php @@ -0,0 +1,158 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Type; + +use Ramsey\Uuid\Exception\InvalidArgumentException; +use ValueError; + +use function assert; +use function is_numeric; +use function preg_match; +use function sprintf; +use function substr; + +/** + * A value object representing an integer + * + * This class exists for type-safety purposes, to ensure that integers + * returned from ramsey/uuid methods as strings are truly integers and not some + * other kind of string. + * + * To support large integers beyond PHP_INT_MAX and PHP_INT_MIN on both 64-bit + * and 32-bit systems, we store the integers as strings. + * + * @psalm-immutable + */ +final class Integer implements NumberInterface +{ + /** + * @psalm-var numeric-string + */ + private string $value; + + private bool $isNegative = false; + + public function __construct(float | int | string | self $value) + { + $this->value = $value instanceof self ? (string) $value : $this->prepareValue($value); + } + + public function isNegative(): bool + { + return $this->isNegative; + } + + /** + * @psalm-return numeric-string + */ + public function toString(): string + { + return $this->value; + } + + /** + * @psalm-return numeric-string + */ + public function __toString(): string + { + return $this->toString(); + } + + public function jsonSerialize(): string + { + return $this->toString(); + } + + public function serialize(): string + { + return $this->toString(); + } + + /** + * @return array{string: string} + */ + public function __serialize(): array + { + return ['string' => $this->toString()]; + } + + /** + * Constructs the object from a serialized string representation + * + * @param string $data The serialized string representation of the object + * + * @psalm-suppress UnusedMethodCall + */ + public function unserialize(string $data): void + { + $this->__construct($data); + } + + /** + * @param array{string?: string} $data + */ + public function __unserialize(array $data): void + { + // @codeCoverageIgnoreStart + if (!isset($data['string'])) { + throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); + } + // @codeCoverageIgnoreEnd + + $this->unserialize($data['string']); + } + + /** + * @return numeric-string + */ + private function prepareValue(float | int | string $value): string + { + $value = (string) $value; + $sign = '+'; + + // If the value contains a sign, remove it for digit pattern check. + if (str_starts_with($value, '-') || str_starts_with($value, '+')) { + $sign = substr($value, 0, 1); + $value = substr($value, 1); + } + + if (!preg_match('/^\d+$/', $value)) { + throw new InvalidArgumentException( + 'Value must be a signed integer or a string containing only ' + . 'digits 0-9 and, optionally, a sign (+ or -)' + ); + } + + // Trim any leading zeros. + $value = ltrim($value, '0'); + + // Set to zero if the string is empty after trimming zeros. + if ($value === '') { + $value = '0'; + } + + // Add the negative sign back to the value. + if ($sign === '-' && $value !== '0') { + $value = $sign . $value; + + /** @psalm-suppress InaccessibleProperty */ + $this->isNegative = true; + } + + assert(is_numeric($value)); + + return $value; + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Type/NumberInterface.php b/pandora_console/vendor/ramsey/uuid/src/Type/NumberInterface.php new file mode 100644 index 0000000000..bf4ae9db8a --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Type/NumberInterface.php @@ -0,0 +1,28 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Type; + +/** + * NumberInterface ensures consistency in numeric values returned by ramsey/uuid + * + * @psalm-immutable + */ +interface NumberInterface extends TypeInterface +{ + /** + * Returns true if this number is less than zero + */ + public function isNegative(): bool; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Type/Time.php b/pandora_console/vendor/ramsey/uuid/src/Type/Time.php new file mode 100644 index 0000000000..0cedb44765 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Type/Time.php @@ -0,0 +1,128 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Type; + +use Ramsey\Uuid\Exception\UnsupportedOperationException; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use ValueError; + +use function json_decode; +use function json_encode; +use function sprintf; + +/** + * A value object representing a timestamp + * + * This class exists for type-safety purposes, to ensure that timestamps used + * by ramsey/uuid are truly timestamp integers and not some other kind of string + * or integer. + * + * @psalm-immutable + */ +final class Time implements TypeInterface +{ + private IntegerObject $seconds; + private IntegerObject $microseconds; + + public function __construct( + float | int | string | IntegerObject $seconds, + float | int | string | IntegerObject $microseconds = 0, + ) { + $this->seconds = new IntegerObject($seconds); + $this->microseconds = new IntegerObject($microseconds); + } + + public function getSeconds(): IntegerObject + { + return $this->seconds; + } + + public function getMicroseconds(): IntegerObject + { + return $this->microseconds; + } + + public function toString(): string + { + return $this->seconds->toString() . '.' . sprintf('%06s', $this->microseconds->toString()); + } + + public function __toString(): string + { + return $this->toString(); + } + + /** + * @return string[] + */ + public function jsonSerialize(): array + { + return [ + 'seconds' => $this->getSeconds()->toString(), + 'microseconds' => $this->getMicroseconds()->toString(), + ]; + } + + public function serialize(): string + { + return (string) json_encode($this); + } + + /** + * @return array{seconds: string, microseconds: string} + */ + public function __serialize(): array + { + return [ + 'seconds' => $this->getSeconds()->toString(), + 'microseconds' => $this->getMicroseconds()->toString(), + ]; + } + + /** + * Constructs the object from a serialized string representation + * + * @param string $data The serialized string representation of the object + * + * @psalm-suppress UnusedMethodCall + */ + public function unserialize(string $data): void + { + /** @var array{seconds?: int|float|string, microseconds?: int|float|string} $time */ + $time = json_decode($data, true); + + if (!isset($time['seconds']) || !isset($time['microseconds'])) { + throw new UnsupportedOperationException( + 'Attempted to unserialize an invalid value' + ); + } + + $this->__construct($time['seconds'], $time['microseconds']); + } + + /** + * @param array{seconds?: string, microseconds?: string} $data + */ + public function __unserialize(array $data): void + { + // @codeCoverageIgnoreStart + if (!isset($data['seconds']) || !isset($data['microseconds'])) { + throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); + } + // @codeCoverageIgnoreEnd + + $this->__construct($data['seconds'], $data['microseconds']); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Type/TypeInterface.php b/pandora_console/vendor/ramsey/uuid/src/Type/TypeInterface.php new file mode 100644 index 0000000000..da2d8b2034 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Type/TypeInterface.php @@ -0,0 +1,30 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Type; + +use JsonSerializable; +use Serializable; + +/** + * TypeInterface ensures consistency in typed values returned by ramsey/uuid + * + * @psalm-immutable + */ +interface TypeInterface extends JsonSerializable, Serializable +{ + public function toString(): string; + + public function __toString(): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Uuid.php b/pandora_console/vendor/ramsey/uuid/src/Uuid.php new file mode 100644 index 0000000000..e0384a50c1 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Uuid.php @@ -0,0 +1,758 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +use BadMethodCallException; +use DateTimeInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Exception\UnsupportedOperationException; +use Ramsey\Uuid\Fields\FieldsInterface; +use Ramsey\Uuid\Lazy\LazyUuidFromString; +use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use ValueError; + +use function assert; +use function bin2hex; +use function method_exists; +use function preg_match; +use function sprintf; +use function str_replace; +use function strcmp; +use function strlen; +use function strtolower; +use function substr; + +/** + * Uuid provides constants and static methods for working with and generating UUIDs + * + * @psalm-immutable + */ +class Uuid implements UuidInterface +{ + use DeprecatedUuidMethodsTrait; + + /** + * When this namespace is specified, the name string is a fully-qualified + * domain name + * + * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs + */ + public const NAMESPACE_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; + + /** + * When this namespace is specified, the name string is a URL + * + * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs + */ + public const NAMESPACE_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; + + /** + * When this namespace is specified, the name string is an ISO OID + * + * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs + */ + public const NAMESPACE_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'; + + /** + * When this namespace is specified, the name string is an X.500 DN in DER + * or a text output format + * + * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs + */ + public const NAMESPACE_X500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'; + + /** + * The nil UUID is a special form of UUID that is specified to have all 128 + * bits set to zero + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1.7 RFC 4122, ยง 4.1.7: Nil UUID + */ + public const NIL = '00000000-0000-0000-0000-000000000000'; + + /** + * The max UUID is a special form of UUID that is specified to have all 128 + * bits set to one + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID + */ + public const MAX = 'ffffffff-ffff-ffff-ffff-ffffffffffff'; + + /** + * Variant: reserved, NCS backward compatibility + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, ยง 4.1.1: Variant + */ + public const RESERVED_NCS = 0; + + /** + * Variant: the UUID layout specified in RFC 4122 + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, ยง 4.1.1: Variant + */ + public const RFC_4122 = 2; + + /** + * Variant: reserved, Microsoft Corporation backward compatibility + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, ยง 4.1.1: Variant + */ + public const RESERVED_MICROSOFT = 6; + + /** + * Variant: reserved for future definition + * + * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, ยง 4.1.1: Variant + */ + public const RESERVED_FUTURE = 7; + + /** + * @deprecated Use {@see ValidatorInterface::getPattern()} instead. + */ + public const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$'; + + /** + * Version 1 (Gregorian time) UUID + * + * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, ยง 4.1.3: Version + */ + public const UUID_TYPE_TIME = 1; + + /** + * Version 2 (DCE Security) UUID + * + * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, ยง 4.1.3: Version + */ + public const UUID_TYPE_DCE_SECURITY = 2; + + /** + * @deprecated Use {@see Uuid::UUID_TYPE_DCE_SECURITY} instead. + */ + public const UUID_TYPE_IDENTIFIER = 2; + + /** + * Version 3 (name-based and hashed with MD5) UUID + * + * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, ยง 4.1.3: Version + */ + public const UUID_TYPE_HASH_MD5 = 3; + + /** + * Version 4 (random) UUID + * + * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, ยง 4.1.3: Version + */ + public const UUID_TYPE_RANDOM = 4; + + /** + * Version 5 (name-based and hashed with SHA1) UUID + * + * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, ยง 4.1.3: Version + */ + public const UUID_TYPE_HASH_SHA1 = 5; + + /** + * @deprecated Use {@see Uuid::UUID_TYPE_REORDERED_TIME} instead. + */ + public const UUID_TYPE_PEABODY = 6; + + /** + * Version 6 (reordered time) UUID + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6 + */ + public const UUID_TYPE_REORDERED_TIME = 6; + + /** + * Version 7 (Unix Epoch time) UUID + * + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7 + */ + public const UUID_TYPE_UNIX_TIME = 7; + + /** + * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8 + */ + public const UUID_TYPE_CUSTOM = 8; + + /** + * DCE Security principal domain + * + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, ยง11.5.1.1 + */ + public const DCE_DOMAIN_PERSON = 0; + + /** + * DCE Security group domain + * + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, ยง11.5.1.1 + */ + public const DCE_DOMAIN_GROUP = 1; + + /** + * DCE Security organization domain + * + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, ยง11.5.1.1 + */ + public const DCE_DOMAIN_ORG = 2; + + /** + * DCE Security domain string names + * + * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, ยง11.5.1.1 + */ + public const DCE_DOMAIN_NAMES = [ + self::DCE_DOMAIN_PERSON => 'person', + self::DCE_DOMAIN_GROUP => 'group', + self::DCE_DOMAIN_ORG => 'org', + ]; + + private static ?UuidFactoryInterface $factory = null; + + /** + * @var bool flag to detect if the UUID factory was replaced internally, + * which disables all optimizations for the default/happy path internal + * scenarios + */ + private static bool $factoryReplaced = false; + + protected CodecInterface $codec; + protected NumberConverterInterface $numberConverter; + protected Rfc4122FieldsInterface $fields; + protected TimeConverterInterface $timeConverter; + + /** + * Creates a universally unique identifier (UUID) from an array of fields + * + * Unless you're making advanced use of this library to generate identifiers + * that deviate from RFC 4122, you probably do not want to instantiate a + * UUID directly. Use the static methods, instead: + * + * ``` + * use Ramsey\Uuid\Uuid; + * + * $timeBasedUuid = Uuid::uuid1(); + * $namespaceMd5Uuid = Uuid::uuid3(Uuid::NAMESPACE_URL, 'http://php.net/'); + * $randomUuid = Uuid::uuid4(); + * $namespaceSha1Uuid = Uuid::uuid5(Uuid::NAMESPACE_URL, 'http://php.net/'); + * ``` + * + * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID + * @param NumberConverterInterface $numberConverter The number converter to use + * for converting hex values to/from integers + * @param CodecInterface $codec The codec to use when encoding or decoding + * UUID strings + * @param TimeConverterInterface $timeConverter The time converter to use + * for converting timestamps extracted from a UUID to unix timestamps + */ + public function __construct( + Rfc4122FieldsInterface $fields, + NumberConverterInterface $numberConverter, + CodecInterface $codec, + TimeConverterInterface $timeConverter + ) { + $this->fields = $fields; + $this->codec = $codec; + $this->numberConverter = $numberConverter; + $this->timeConverter = $timeConverter; + } + + /** + * @psalm-return non-empty-string + */ + public function __toString(): string + { + return $this->toString(); + } + + /** + * Converts the UUID to a string for JSON serialization + */ + public function jsonSerialize(): string + { + return $this->toString(); + } + + /** + * Converts the UUID to a string for PHP serialization + */ + public function serialize(): string + { + return $this->codec->encode($this); + } + + /** + * @return array{bytes: string} + */ + public function __serialize(): array + { + return ['bytes' => $this->serialize()]; + } + + /** + * Re-constructs the object from its serialized form + * + * @param string $data The serialized PHP string to unserialize into + * a UuidInterface instance + */ + public function unserialize(string $data): void + { + if (strlen($data) === 16) { + /** @var Uuid $uuid */ + $uuid = self::getFactory()->fromBytes($data); + } else { + /** @var Uuid $uuid */ + $uuid = self::getFactory()->fromString($data); + } + + $this->codec = $uuid->codec; + $this->numberConverter = $uuid->numberConverter; + $this->fields = $uuid->fields; + $this->timeConverter = $uuid->timeConverter; + } + + /** + * @param array{bytes?: string} $data + */ + public function __unserialize(array $data): void + { + // @codeCoverageIgnoreStart + if (!isset($data['bytes'])) { + throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); + } + // @codeCoverageIgnoreEnd + + $this->unserialize($data['bytes']); + } + + public function compareTo(UuidInterface $other): int + { + $compare = strcmp($this->toString(), $other->toString()); + + if ($compare < 0) { + return -1; + } + + if ($compare > 0) { + return 1; + } + + return 0; + } + + public function equals(?object $other): bool + { + if (!$other instanceof UuidInterface) { + return false; + } + + return $this->compareTo($other) === 0; + } + + /** + * @psalm-return non-empty-string + */ + public function getBytes(): string + { + return $this->codec->encodeBinary($this); + } + + public function getFields(): FieldsInterface + { + return $this->fields; + } + + public function getHex(): Hexadecimal + { + return new Hexadecimal(str_replace('-', '', $this->toString())); + } + + public function getInteger(): IntegerObject + { + return new IntegerObject($this->numberConverter->fromHex($this->getHex()->toString())); + } + + public function getUrn(): string + { + return 'urn:uuid:' . $this->toString(); + } + + /** + * @psalm-return non-empty-string + */ + public function toString(): string + { + return $this->codec->encode($this); + } + + /** + * Returns the factory used to create UUIDs + */ + public static function getFactory(): UuidFactoryInterface + { + if (self::$factory === null) { + self::$factory = new UuidFactory(); + } + + return self::$factory; + } + + /** + * Sets the factory used to create UUIDs + * + * @param UuidFactoryInterface $factory A factory that will be used by this + * class to create UUIDs + */ + public static function setFactory(UuidFactoryInterface $factory): void + { + // Note: non-strict equality is intentional here. If the factory is configured differently, every assumption + // around purity is broken, and we have to internally decide everything differently. + // phpcs:ignore SlevomatCodingStandard.Operators.DisallowEqualOperators.DisallowedNotEqualOperator + self::$factoryReplaced = ($factory != new UuidFactory()); + + self::$factory = $factory; + } + + /** + * Creates a UUID from a byte string + * + * @param string $bytes A binary string + * + * @return UuidInterface A UuidInterface instance created from a binary + * string representation + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + * + * @psalm-suppress ImpureStaticProperty we know that the factory being replaced can lead to massive + * havoc across all consumers: that should never happen, and + * is generally to be discouraged. Until the factory is kept + * un-replaced, this method is effectively pure. + */ + public static function fromBytes(string $bytes): UuidInterface + { + if (!self::$factoryReplaced && strlen($bytes) === 16) { + $base16Uuid = bin2hex($bytes); + + // Note: we are calling `fromString` internally because we don't know if the given `$bytes` is a valid UUID + return self::fromString( + substr($base16Uuid, 0, 8) + . '-' + . substr($base16Uuid, 8, 4) + . '-' + . substr($base16Uuid, 12, 4) + . '-' + . substr($base16Uuid, 16, 4) + . '-' + . substr($base16Uuid, 20, 12) + ); + } + + return self::getFactory()->fromBytes($bytes); + } + + /** + * Creates a UUID from the string standard representation + * + * @param string $uuid A hexadecimal string + * + * @return UuidInterface A UuidInterface instance created from a hexadecimal + * string representation + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + * + * @psalm-suppress ImpureStaticProperty we know that the factory being replaced can lead to massive + * havoc across all consumers: that should never happen, and + * is generally to be discouraged. Until the factory is kept + * un-replaced, this method is effectively pure. + */ + public static function fromString(string $uuid): UuidInterface + { + $uuid = strtolower($uuid); + if (!self::$factoryReplaced && preg_match(LazyUuidFromString::VALID_REGEX, $uuid) === 1) { + assert($uuid !== ''); + + return new LazyUuidFromString($uuid); + } + + return self::getFactory()->fromString($uuid); + } + + /** + * Creates a UUID from a DateTimeInterface instance + * + * @param DateTimeInterface $dateTime The date and time + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return UuidInterface A UuidInterface instance that represents a + * version 1 UUID created from a DateTimeInterface instance + */ + public static function fromDateTime( + DateTimeInterface $dateTime, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): UuidInterface { + return self::getFactory()->fromDateTime($dateTime, $node, $clockSeq); + } + + /** + * Creates a UUID from the Hexadecimal object + * + * @param Hexadecimal $hex Hexadecimal object representing a hexadecimal number + * + * @return UuidInterface A UuidInterface instance created from the Hexadecimal + * object representing a hexadecimal number + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + * @psalm-suppress MixedInferredReturnType,MixedReturnStatement + */ + public static function fromHexadecimal(Hexadecimal $hex): UuidInterface + { + $factory = self::getFactory(); + + if (method_exists($factory, 'fromHexadecimal')) { + /** + * @phpstan-ignore-next-line + * @psalm-suppress UndefinedInterfaceMethod + */ + return self::getFactory()->fromHexadecimal($hex); + } + + throw new BadMethodCallException('The method fromHexadecimal() does not exist on the provided factory'); + } + + /** + * Creates a UUID from a 128-bit integer string + * + * @param string $integer String representation of 128-bit integer + * + * @return UuidInterface A UuidInterface instance created from the string + * representation of a 128-bit integer + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + */ + public static function fromInteger(string $integer): UuidInterface + { + /** @psalm-suppress ImpureMethodCall */ + return self::getFactory()->fromInteger($integer); + } + + /** + * Returns true if the provided string is a valid UUID + * + * @param string $uuid A string to validate as a UUID + * + * @return bool True if the string is a valid UUID, false otherwise + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + * + * @psalm-assert-if-true =non-empty-string $uuid + */ + public static function isValid(string $uuid): bool + { + /** @psalm-suppress ImpureMethodCall */ + return self::getFactory()->getValidator()->validate($uuid); + } + + /** + * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number, + * and the current time + * + * @param Hexadecimal|int|string|null $node A 48-bit number representing the + * hardware address; this number may be represented as an integer or a + * hexadecimal string + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes + * + * @return UuidInterface A UuidInterface instance that represents a + * version 1 UUID + */ + public static function uuid1($node = null, ?int $clockSeq = null): UuidInterface + { + return self::getFactory()->uuid1($node, $clockSeq); + } + + /** + * Returns a version 2 (DCE Security) UUID from a local domain, local + * identifier, host ID, clock sequence, and the current time + * + * @param int $localDomain The local domain to use when generating bytes, + * according to DCE Security + * @param IntegerObject|null $localIdentifier The local identifier for the + * given domain; this may be a UID or GID on POSIX systems, if the local + * domain is person or group, or it may be a site-defined identifier + * if the local domain is org + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes (in a version 2 UUID, the lower 8 bits of this number + * are replaced with the domain). + * + * @return UuidInterface A UuidInterface instance that represents a + * version 2 UUID + */ + public static function uuid2( + int $localDomain, + ?IntegerObject $localIdentifier = null, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): UuidInterface { + return self::getFactory()->uuid2($localDomain, $localIdentifier, $node, $clockSeq); + } + + /** + * Returns a version 3 (name-based) UUID based on the MD5 hash of a + * namespace ID and a name + * + * @param string|UuidInterface $ns The namespace (must be a valid UUID) + * @param string $name The name to use for creating a UUID + * + * @return UuidInterface A UuidInterface instance that represents a + * version 3 UUID + * + * @psalm-suppress ImpureMethodCall we know that the factory being replaced can lead to massive + * havoc across all consumers: that should never happen, and + * is generally to be discouraged. Until the factory is kept + * un-replaced, this method is effectively pure. + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + */ + public static function uuid3($ns, string $name): UuidInterface + { + return self::getFactory()->uuid3($ns, $name); + } + + /** + * Returns a version 4 (random) UUID + * + * @return UuidInterface A UuidInterface instance that represents a + * version 4 UUID + */ + public static function uuid4(): UuidInterface + { + return self::getFactory()->uuid4(); + } + + /** + * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a + * namespace ID and a name + * + * @param string|UuidInterface $ns The namespace (must be a valid UUID) + * @param string $name The name to use for creating a UUID + * + * @return UuidInterface A UuidInterface instance that represents a + * version 5 UUID + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + * + * @psalm-suppress ImpureMethodCall we know that the factory being replaced can lead to massive + * havoc across all consumers: that should never happen, and + * is generally to be discouraged. Until the factory is kept + * un-replaced, this method is effectively pure. + */ + public static function uuid5($ns, string $name): UuidInterface + { + return self::getFactory()->uuid5($ns, $name); + } + + /** + * Returns a version 6 (reordered time) UUID from a host ID, sequence number, + * and the current time + * + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes + * + * @return UuidInterface A UuidInterface instance that represents a + * version 6 UUID + */ + public static function uuid6( + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): UuidInterface { + return self::getFactory()->uuid6($node, $clockSeq); + } + + /** + * Returns a version 7 (Unix Epoch time) UUID + * + * @param DateTimeInterface|null $dateTime An optional date/time from which + * to create the version 7 UUID. If not provided, the UUID is generated + * using the current date/time. + * + * @return UuidInterface A UuidInterface instance that represents a + * version 7 UUID + */ + public static function uuid7(?DateTimeInterface $dateTime = null): UuidInterface + { + $factory = self::getFactory(); + + if (method_exists($factory, 'uuid7')) { + /** @var UuidInterface */ + return $factory->uuid7($dateTime); + } + + throw new UnsupportedOperationException( + 'The provided factory does not support the uuid7() method', + ); + } + + /** + * Returns a version 8 (custom) UUID + * + * The bytes provided may contain any value according to your application's + * needs. Be aware, however, that other applications may not understand the + * semantics of the value. + * + * @param string $bytes A 16-byte octet string. This is an open blob + * of data that you may fill with 128 bits of information. Be aware, + * however, bits 48 through 51 will be replaced with the UUID version + * field, and bits 64 and 65 will be replaced with the UUID variant. You + * MUST NOT rely on these bits for your application needs. + * + * @return UuidInterface A UuidInterface instance that represents a + * version 8 UUID + */ + public static function uuid8(string $bytes): UuidInterface + { + $factory = self::getFactory(); + + if (method_exists($factory, 'uuid8')) { + /** @var UuidInterface */ + return $factory->uuid8($bytes); + } + + throw new UnsupportedOperationException( + 'The provided factory does not support the uuid8() method', + ); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/UuidFactory.php b/pandora_console/vendor/ramsey/uuid/src/UuidFactory.php new file mode 100644 index 0000000000..1b06ea6ed8 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/UuidFactory.php @@ -0,0 +1,513 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +use DateTimeInterface; +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; +use Ramsey\Uuid\Converter\TimeConverterInterface; +use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface; +use Ramsey\Uuid\Generator\DefaultTimeGenerator; +use Ramsey\Uuid\Generator\NameGeneratorInterface; +use Ramsey\Uuid\Generator\RandomGeneratorInterface; +use Ramsey\Uuid\Generator\TimeGeneratorInterface; +use Ramsey\Uuid\Generator\UnixTimeGenerator; +use Ramsey\Uuid\Lazy\LazyUuidFromString; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Provider\Time\FixedTimeProvider; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\Type\Time; +use Ramsey\Uuid\Validator\ValidatorInterface; + +use function bin2hex; +use function hex2bin; +use function pack; +use function str_pad; +use function strtolower; +use function substr; +use function substr_replace; +use function unpack; + +use const STR_PAD_LEFT; + +class UuidFactory implements UuidFactoryInterface +{ + private CodecInterface $codec; + private DceSecurityGeneratorInterface $dceSecurityGenerator; + private NameGeneratorInterface $nameGenerator; + private NodeProviderInterface $nodeProvider; + private NumberConverterInterface $numberConverter; + private RandomGeneratorInterface $randomGenerator; + private TimeConverterInterface $timeConverter; + private TimeGeneratorInterface $timeGenerator; + private TimeGeneratorInterface $unixTimeGenerator; + private UuidBuilderInterface $uuidBuilder; + private ValidatorInterface $validator; + + /** + * @var bool whether the feature set was provided from outside, or we can + * operate under "default" assumptions + */ + private bool $isDefaultFeatureSet; + + /** + * @param FeatureSet|null $features A set of available features in the current environment + */ + public function __construct(?FeatureSet $features = null) + { + $this->isDefaultFeatureSet = $features === null; + + $features = $features ?: new FeatureSet(); + + $this->codec = $features->getCodec(); + $this->dceSecurityGenerator = $features->getDceSecurityGenerator(); + $this->nameGenerator = $features->getNameGenerator(); + $this->nodeProvider = $features->getNodeProvider(); + $this->numberConverter = $features->getNumberConverter(); + $this->randomGenerator = $features->getRandomGenerator(); + $this->timeConverter = $features->getTimeConverter(); + $this->timeGenerator = $features->getTimeGenerator(); + $this->uuidBuilder = $features->getBuilder(); + $this->validator = $features->getValidator(); + $this->unixTimeGenerator = $features->getUnixTimeGenerator(); + } + + /** + * Returns the codec used by this factory + */ + public function getCodec(): CodecInterface + { + return $this->codec; + } + + /** + * Sets the codec to use for this factory + * + * @param CodecInterface $codec A UUID encoder-decoder + */ + public function setCodec(CodecInterface $codec): void + { + $this->isDefaultFeatureSet = false; + + $this->codec = $codec; + } + + /** + * Returns the name generator used by this factory + */ + public function getNameGenerator(): NameGeneratorInterface + { + return $this->nameGenerator; + } + + /** + * Sets the name generator to use for this factory + * + * @param NameGeneratorInterface $nameGenerator A generator to generate + * binary data, based on a namespace and name + */ + public function setNameGenerator(NameGeneratorInterface $nameGenerator): void + { + $this->isDefaultFeatureSet = false; + + $this->nameGenerator = $nameGenerator; + } + + /** + * Returns the node provider used by this factory + */ + public function getNodeProvider(): NodeProviderInterface + { + return $this->nodeProvider; + } + + /** + * Returns the random generator used by this factory + */ + public function getRandomGenerator(): RandomGeneratorInterface + { + return $this->randomGenerator; + } + + /** + * Returns the time generator used by this factory + */ + public function getTimeGenerator(): TimeGeneratorInterface + { + return $this->timeGenerator; + } + + /** + * Sets the time generator to use for this factory + * + * @param TimeGeneratorInterface $generator A generator to generate binary + * data, based on the time + */ + public function setTimeGenerator(TimeGeneratorInterface $generator): void + { + $this->isDefaultFeatureSet = false; + + $this->timeGenerator = $generator; + } + + /** + * Returns the DCE Security generator used by this factory + */ + public function getDceSecurityGenerator(): DceSecurityGeneratorInterface + { + return $this->dceSecurityGenerator; + } + + /** + * Sets the DCE Security generator to use for this factory + * + * @param DceSecurityGeneratorInterface $generator A generator to generate + * binary data, based on a local domain and local identifier + */ + public function setDceSecurityGenerator(DceSecurityGeneratorInterface $generator): void + { + $this->isDefaultFeatureSet = false; + + $this->dceSecurityGenerator = $generator; + } + + /** + * Returns the number converter used by this factory + */ + public function getNumberConverter(): NumberConverterInterface + { + return $this->numberConverter; + } + + /** + * Sets the random generator to use for this factory + * + * @param RandomGeneratorInterface $generator A generator to generate binary + * data, based on some random input + */ + public function setRandomGenerator(RandomGeneratorInterface $generator): void + { + $this->isDefaultFeatureSet = false; + + $this->randomGenerator = $generator; + } + + /** + * Sets the number converter to use for this factory + * + * @param NumberConverterInterface $converter A converter to use for working + * with large integers (i.e. integers greater than PHP_INT_MAX) + */ + public function setNumberConverter(NumberConverterInterface $converter): void + { + $this->isDefaultFeatureSet = false; + + $this->numberConverter = $converter; + } + + /** + * Returns the UUID builder used by this factory + */ + public function getUuidBuilder(): UuidBuilderInterface + { + return $this->uuidBuilder; + } + + /** + * Sets the UUID builder to use for this factory + * + * @param UuidBuilderInterface $builder A builder for constructing instances + * of UuidInterface + */ + public function setUuidBuilder(UuidBuilderInterface $builder): void + { + $this->isDefaultFeatureSet = false; + + $this->uuidBuilder = $builder; + } + + /** + * @psalm-mutation-free + */ + public function getValidator(): ValidatorInterface + { + return $this->validator; + } + + /** + * Sets the validator to use for this factory + * + * @param ValidatorInterface $validator A validator to use for validating + * whether a string is a valid UUID + */ + public function setValidator(ValidatorInterface $validator): void + { + $this->isDefaultFeatureSet = false; + + $this->validator = $validator; + } + + /** + * @psalm-pure + */ + public function fromBytes(string $bytes): UuidInterface + { + return $this->codec->decodeBytes($bytes); + } + + /** + * @psalm-pure + */ + public function fromString(string $uuid): UuidInterface + { + $uuid = strtolower($uuid); + + return $this->codec->decode($uuid); + } + + /** + * @psalm-pure + */ + public function fromInteger(string $integer): UuidInterface + { + $hex = $this->numberConverter->toHex($integer); + $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); + + return $this->fromString($hex); + } + + public function fromDateTime( + DateTimeInterface $dateTime, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): UuidInterface { + $timeProvider = new FixedTimeProvider( + new Time($dateTime->format('U'), $dateTime->format('u')) + ); + + $timeGenerator = new DefaultTimeGenerator( + $this->nodeProvider, + $this->timeConverter, + $timeProvider + ); + + $nodeHex = $node ? $node->toString() : null; + + $bytes = $timeGenerator->generate($nodeHex, $clockSeq); + + return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME); + } + + /** + * @psalm-pure + */ + public function fromHexadecimal(Hexadecimal $hex): UuidInterface + { + return $this->codec->decode($hex->__toString()); + } + + /** + * @inheritDoc + */ + public function uuid1($node = null, ?int $clockSeq = null): UuidInterface + { + $bytes = $this->timeGenerator->generate($node, $clockSeq); + + return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME); + } + + public function uuid2( + int $localDomain, + ?IntegerObject $localIdentifier = null, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): UuidInterface { + $bytes = $this->dceSecurityGenerator->generate( + $localDomain, + $localIdentifier, + $node, + $clockSeq + ); + + return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_DCE_SECURITY); + } + + /** + * @inheritDoc + * @psalm-pure + */ + public function uuid3($ns, string $name): UuidInterface + { + return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_MD5, 'md5'); + } + + public function uuid4(): UuidInterface + { + $bytes = $this->randomGenerator->generate(16); + + return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_RANDOM); + } + + /** + * @inheritDoc + * @psalm-pure + */ + public function uuid5($ns, string $name): UuidInterface + { + return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_SHA1, 'sha1'); + } + + public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface + { + $nodeHex = $node ? $node->toString() : null; + $bytes = $this->timeGenerator->generate($nodeHex, $clockSeq); + + // Rearrange the bytes, according to the UUID version 6 specification. + $v6 = $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5] + . $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3]; + $v6 = bin2hex($v6); + + // Drop the first four bits, while adding an empty four bits for the + // version field. This allows us to reconstruct the correct time from + // the bytes of this UUID. + $v6Bytes = hex2bin(substr($v6, 1, 12) . '0' . substr($v6, -3)); + $v6Bytes .= substr($bytes, 8); + + return $this->uuidFromBytesAndVersion($v6Bytes, Uuid::UUID_TYPE_REORDERED_TIME); + } + + /** + * Returns a version 7 (Unix Epoch time) UUID + * + * @param DateTimeInterface|null $dateTime An optional date/time from which + * to create the version 7 UUID. If not provided, the UUID is generated + * using the current date/time. + * + * @return UuidInterface A UuidInterface instance that represents a + * version 7 UUID + */ + public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface + { + assert($this->unixTimeGenerator instanceof UnixTimeGenerator); + $bytes = $this->unixTimeGenerator->generate(null, null, $dateTime); + + return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME); + } + + /** + * Returns a version 8 (Custom) UUID + * + * The bytes provided may contain any value according to your application's + * needs. Be aware, however, that other applications may not understand the + * semantics of the value. + * + * @param string $bytes A 16-byte octet string. This is an open blob + * of data that you may fill with 128 bits of information. Be aware, + * however, bits 48 through 51 will be replaced with the UUID version + * field, and bits 64 and 65 will be replaced with the UUID variant. You + * MUST NOT rely on these bits for your application needs. + * + * @return UuidInterface A UuidInterface instance that represents a + * version 8 UUID + */ + public function uuid8(string $bytes): UuidInterface + { + return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM); + } + + /** + * Returns a Uuid created from the provided byte string + * + * Uses the configured builder and codec and the provided byte string to + * construct a Uuid object. + * + * @param string $bytes The byte string from which to construct a UUID + * + * @return UuidInterface An instance of UuidInterface, created from the + * provided bytes + * + * @psalm-pure + */ + public function uuid(string $bytes): UuidInterface + { + /** @psalm-suppress ImpurePropertyFetch */ + return $this->uuidBuilder->build($this->codec, $bytes); + } + + /** + * Returns a version 3 or 5 namespaced Uuid + * + * @param string|UuidInterface $ns The namespace (must be a valid UUID) + * @param string $name The name to hash together with the namespace + * @param int $version The version of UUID to create (3 or 5) + * @param string $hashAlgorithm The hashing algorithm to use when hashing + * together the namespace and name + * + * @return UuidInterface An instance of UuidInterface, created by hashing + * together the provided namespace and name + * + * @psalm-pure + */ + private function uuidFromNsAndName( + UuidInterface | string $ns, + string $name, + int $version, + string $hashAlgorithm + ): UuidInterface { + if (!($ns instanceof UuidInterface)) { + $ns = $this->fromString($ns); + } + + $bytes = $this->nameGenerator->generate($ns, $name, $hashAlgorithm); + + return $this->uuidFromBytesAndVersion(substr($bytes, 0, 16), $version); + } + + /** + * Returns an RFC 4122 variant Uuid, created from the provided bytes and version + * + * @param string $bytes The byte string to convert to a UUID + * @param int $version The RFC 4122 version to apply to the UUID + * + * @return UuidInterface An instance of UuidInterface, created from the + * byte string and version + * + * @psalm-pure + */ + private function uuidFromBytesAndVersion(string $bytes, int $version): UuidInterface + { + /** @var array $unpackedTime */ + $unpackedTime = unpack('n*', substr($bytes, 6, 2)); + $timeHi = (int) $unpackedTime[1]; + $timeHiAndVersion = pack('n*', BinaryUtils::applyVersion($timeHi, $version)); + + /** @var array $unpackedClockSeq */ + $unpackedClockSeq = unpack('n*', substr($bytes, 8, 2)); + $clockSeqHi = (int) $unpackedClockSeq[1]; + $clockSeqHiAndReserved = pack('n*', BinaryUtils::applyVariant($clockSeqHi)); + + $bytes = substr_replace($bytes, $timeHiAndVersion, 6, 2); + $bytes = substr_replace($bytes, $clockSeqHiAndReserved, 8, 2); + + if ($this->isDefaultFeatureSet) { + return LazyUuidFromString::fromBytes($bytes); + } + + /** @psalm-suppress ImpureVariable */ + return $this->uuid($bytes); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/UuidFactoryInterface.php b/pandora_console/vendor/ramsey/uuid/src/UuidFactoryInterface.php new file mode 100644 index 0000000000..d99fc9d584 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/UuidFactoryInterface.php @@ -0,0 +1,182 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +use DateTimeInterface; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Ramsey\Uuid\Validator\ValidatorInterface; + +/** + * UuidFactoryInterface defines common functionality all `UuidFactory` instances + * must implement + */ +interface UuidFactoryInterface +{ + /** + * Creates a UUID from a byte string + * + * @param string $bytes A binary string + * + * @return UuidInterface A UuidInterface instance created from a binary + * string representation + * + * @psalm-pure + */ + public function fromBytes(string $bytes): UuidInterface; + + /** + * Creates a UUID from a DateTimeInterface instance + * + * @param DateTimeInterface $dateTime The date and time + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return UuidInterface A UuidInterface instance that represents a + * version 1 UUID created from a DateTimeInterface instance + */ + public function fromDateTime( + DateTimeInterface $dateTime, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): UuidInterface; + + /** + * Creates a UUID from a 128-bit integer string + * + * @param string $integer String representation of 128-bit integer + * + * @return UuidInterface A UuidInterface instance created from the string + * representation of a 128-bit integer + * + * @psalm-pure + */ + public function fromInteger(string $integer): UuidInterface; + + /** + * Creates a UUID from the string standard representation + * + * @param string $uuid A hexadecimal string + * + * @return UuidInterface A UuidInterface instance created from a hexadecimal + * string representation + * + * @psalm-pure + */ + public function fromString(string $uuid): UuidInterface; + + /** + * Returns the validator to use for the factory + * + * @psalm-mutation-free + */ + public function getValidator(): ValidatorInterface; + + /** + * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number, + * and the current time + * + * @param Hexadecimal|int|string|null $node A 48-bit number representing the + * hardware address; this number may be represented as an integer or a + * hexadecimal string + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return UuidInterface A UuidInterface instance that represents a + * version 1 UUID + */ + public function uuid1($node = null, ?int $clockSeq = null): UuidInterface; + + /** + * Returns a version 2 (DCE Security) UUID from a local domain, local + * identifier, host ID, clock sequence, and the current time + * + * @param int $localDomain The local domain to use when generating bytes, + * according to DCE Security + * @param IntegerObject|null $localIdentifier The local identifier for the + * given domain; this may be a UID or GID on POSIX systems, if the local + * domain is person or group, or it may be a site-defined identifier + * if the local domain is org + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return UuidInterface A UuidInterface instance that represents a + * version 2 UUID + */ + public function uuid2( + int $localDomain, + ?IntegerObject $localIdentifier = null, + ?Hexadecimal $node = null, + ?int $clockSeq = null + ): UuidInterface; + + /** + * Returns a version 3 (name-based) UUID based on the MD5 hash of a + * namespace ID and a name + * + * @param string|UuidInterface $ns The namespace (must be a valid UUID) + * @param string $name The name to use for creating a UUID + * + * @return UuidInterface A UuidInterface instance that represents a + * version 3 UUID + * + * @psalm-pure + */ + public function uuid3($ns, string $name): UuidInterface; + + /** + * Returns a version 4 (random) UUID + * + * @return UuidInterface A UuidInterface instance that represents a + * version 4 UUID + */ + public function uuid4(): UuidInterface; + + /** + * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a + * namespace ID and a name + * + * @param string|UuidInterface $ns The namespace (must be a valid UUID) + * @param string $name The name to use for creating a UUID + * + * @return UuidInterface A UuidInterface instance that represents a + * version 5 UUID + * + * @psalm-pure + */ + public function uuid5($ns, string $name): UuidInterface; + + /** + * Returns a version 6 (reordered time) UUID from a host ID, sequence number, + * and the current time + * + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return UuidInterface A UuidInterface instance that represents a + * version 6 UUID + */ + public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/UuidInterface.php b/pandora_console/vendor/ramsey/uuid/src/UuidInterface.php new file mode 100644 index 0000000000..cac9457de1 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/UuidInterface.php @@ -0,0 +1,109 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +use JsonSerializable; +use Ramsey\Uuid\Fields\FieldsInterface; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; +use Serializable; +use Stringable; + +/** + * A UUID is a universally unique identifier adhering to an agreed-upon + * representation format and standard for generation + * + * @psalm-immutable + */ +interface UuidInterface extends + DeprecatedUuidInterface, + JsonSerializable, + Serializable, + Stringable +{ + /** + * Returns -1, 0, or 1 if the UUID is less than, equal to, or greater than + * the other UUID + * + * The first of two UUIDs is greater than the second if the most + * significant field in which the UUIDs differ is greater for the first + * UUID. + * + * * Q. What's the value of being able to sort UUIDs? + * * A. Use them as keys in a B-Tree or similar mapping. + * + * @param UuidInterface $other The UUID to compare + * + * @return int<-1,1> -1, 0, or 1 if the UUID is less than, equal to, or greater than $other + */ + public function compareTo(UuidInterface $other): int; + + /** + * Returns true if the UUID is equal to the provided object + * + * The result is true if and only if the argument is not null, is a UUID + * object, has the same variant, and contains the same value, bit for bit, + * as the UUID. + * + * @param object|null $other An object to test for equality with this UUID + * + * @return bool True if the other object is equal to this UUID + */ + public function equals(?object $other): bool; + + /** + * Returns the binary string representation of the UUID + * + * @psalm-return non-empty-string + */ + public function getBytes(): string; + + /** + * Returns the fields that comprise this UUID + */ + public function getFields(): FieldsInterface; + + /** + * Returns the hexadecimal representation of the UUID + */ + public function getHex(): Hexadecimal; + + /** + * Returns the integer representation of the UUID + */ + public function getInteger(): IntegerObject; + + /** + * Returns the string standard representation of the UUID as a URN + * + * @link http://en.wikipedia.org/wiki/Uniform_Resource_Name Uniform Resource Name + * @link https://tools.ietf.org/html/rfc4122#section-3 RFC 4122, ยง 3: Namespace Registration Template + */ + public function getUrn(): string; + + /** + * Returns the string standard representation of the UUID + * + * @psalm-return non-empty-string + */ + public function toString(): string; + + /** + * Casts the UUID to the string standard representation + * + * @psalm-return non-empty-string + */ + public function __toString(): string; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Validator/GenericValidator.php b/pandora_console/vendor/ramsey/uuid/src/Validator/GenericValidator.php new file mode 100644 index 0000000000..fd60955115 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Validator/GenericValidator.php @@ -0,0 +1,50 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Validator; + +use Ramsey\Uuid\Uuid; + +use function preg_match; +use function str_replace; + +/** + * GenericValidator validates strings as UUIDs of any variant + * + * @psalm-immutable + */ +final class GenericValidator implements ValidatorInterface +{ + /** + * Regular expression pattern for matching a UUID of any variant. + */ + private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\z'; + + /** + * @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 getPattern(): string + { + return self::VALID_PATTERN; + } + + public function validate(string $uuid): bool + { + $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); + + return $uuid === Uuid::NIL || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid); + } +} diff --git a/pandora_console/vendor/ramsey/uuid/src/Validator/ValidatorInterface.php b/pandora_console/vendor/ramsey/uuid/src/Validator/ValidatorInterface.php new file mode 100644 index 0000000000..3d4bd6f286 --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/Validator/ValidatorInterface.php @@ -0,0 +1,41 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Validator; + +/** + * A validator validates a string as a proper UUID + * + * @psalm-immutable + */ +interface ValidatorInterface +{ + /** + * Returns the regular expression pattern used by this validator + * + * @return string The regular expression pattern this validator uses + * + * @psalm-return non-empty-string + */ + public function getPattern(): string; + + /** + * Returns true if the provided string represents a UUID + * + * @param string $uuid The string to validate as a UUID + * + * @return bool True if the string is a valid UUID, false otherwise + */ + public function validate(string $uuid): bool; +} diff --git a/pandora_console/vendor/ramsey/uuid/src/functions.php b/pandora_console/vendor/ramsey/uuid/src/functions.php new file mode 100644 index 0000000000..1b3ce00f7f --- /dev/null +++ b/pandora_console/vendor/ramsey/uuid/src/functions.php @@ -0,0 +1,158 @@ + + * @license http://opensource.org/licenses/MIT MIT + * phpcs:disable Squiz.Functions.GlobalFunction + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid; + +use DateTimeInterface; +use Ramsey\Uuid\Type\Hexadecimal; +use Ramsey\Uuid\Type\Integer as IntegerObject; + +/** + * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number, + * and the current time + * + * @param Hexadecimal|int|string|null $node A 48-bit number representing the + * hardware address; this number may be represented as an integer or a + * hexadecimal string + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes + * + * @return non-empty-string Version 1 UUID as a string + */ +function v1($node = null, ?int $clockSeq = null): string +{ + return Uuid::uuid1($node, $clockSeq)->toString(); +} + +/** + * Returns a version 2 (DCE Security) UUID from a local domain, local + * identifier, host ID, clock sequence, and the current time + * + * @param int $localDomain The local domain to use when generating bytes, + * according to DCE Security + * @param IntegerObject|null $localIdentifier The local identifier for the + * given domain; this may be a UID or GID on POSIX systems, if the local + * domain is person or group, or it may be a site-defined identifier + * if the local domain is org + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates + * that could arise when the clock is set backwards in time or if the + * node ID changes + * + * @return non-empty-string Version 2 UUID as a string + */ +function v2( + int $localDomain, + ?IntegerObject $localIdentifier = null, + ?Hexadecimal $node = null, + ?int $clockSeq = null +): string { + return Uuid::uuid2($localDomain, $localIdentifier, $node, $clockSeq)->toString(); +} + +/** + * Returns a version 3 (name-based) UUID based on the MD5 hash of a + * namespace ID and a name + * + * @param string|UuidInterface $ns The namespace (must be a valid UUID) + * + * @return non-empty-string Version 3 UUID as a string + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + */ +function v3($ns, string $name): string +{ + return Uuid::uuid3($ns, $name)->toString(); +} + +/** + * Returns a version 4 (random) UUID + * + * @return non-empty-string Version 4 UUID as a string + */ +function v4(): string +{ + return Uuid::uuid4()->toString(); +} + +/** + * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a + * namespace ID and a name + * + * @param string|UuidInterface $ns The namespace (must be a valid UUID) + * + * @return non-empty-string Version 5 UUID as a string + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + */ +function v5($ns, string $name): string +{ + return Uuid::uuid5($ns, $name)->toString(); +} + +/** + * Returns a version 6 (reordered time) UUID from a host ID, sequence number, + * and the current time + * + * @param Hexadecimal|null $node A 48-bit number representing the hardware + * address + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that + * could arise when the clock is set backwards in time or if the node ID + * changes + * + * @return non-empty-string Version 6 UUID as a string + */ +function v6(?Hexadecimal $node = null, ?int $clockSeq = null): string +{ + return Uuid::uuid6($node, $clockSeq)->toString(); +} + +/** + * Returns a version 7 (Unix Epoch time) UUID + * + * @param DateTimeInterface|null $dateTime An optional date/time from which + * to create the version 7 UUID. If not provided, the UUID is generated + * using the current date/time. + * + * @return non-empty-string Version 7 UUID as a string + */ +function v7(?DateTimeInterface $dateTime = null): string +{ + return Uuid::uuid7($dateTime)->toString(); +} + +/** + * Returns a version 8 (custom) UUID + * + * The bytes provided may contain any value according to your application's + * needs. Be aware, however, that other applications may not understand the + * semantics of the value. + * + * @param string $bytes A 16-byte octet string. This is an open blob + * of data that you may fill with 128 bits of information. Be aware, + * however, bits 48 through 51 will be replaced with the UUID version + * field, and bits 64 and 65 will be replaced with the UUID variant. You + * MUST NOT rely on these bits for your application needs. + * + * @return non-empty-string Version 8 UUID as a string + */ +function v8(string $bytes): string +{ + return Uuid::uuid8($bytes)->toString(); +} diff --git a/pandora_console/vendor/symfony/filesystem/Exception/FileNotFoundException.php b/pandora_console/vendor/symfony/filesystem/Exception/FileNotFoundException.php index 48b6408095..06b732b168 100644 --- a/pandora_console/vendor/symfony/filesystem/Exception/FileNotFoundException.php +++ b/pandora_console/vendor/symfony/filesystem/Exception/FileNotFoundException.php @@ -19,7 +19,7 @@ namespace Symfony\Component\Filesystem\Exception; */ class FileNotFoundException extends IOException { - public function __construct(string $message = null, int $code = 0, \Throwable $previous = null, string $path = null) + public function __construct(?string $message = null, int $code = 0, ?\Throwable $previous = null, ?string $path = null) { if (null === $message) { if (null === $path) { diff --git a/pandora_console/vendor/symfony/filesystem/Exception/IOException.php b/pandora_console/vendor/symfony/filesystem/Exception/IOException.php index a3c5445534..df3a0850a0 100644 --- a/pandora_console/vendor/symfony/filesystem/Exception/IOException.php +++ b/pandora_console/vendor/symfony/filesystem/Exception/IOException.php @@ -22,7 +22,7 @@ class IOException extends \RuntimeException implements IOExceptionInterface { private ?string $path; - public function __construct(string $message, int $code = 0, \Throwable $previous = null, string $path = null) + public function __construct(string $message, int $code = 0, ?\Throwable $previous = null, ?string $path = null) { $this->path = $path; diff --git a/pandora_console/vendor/symfony/filesystem/Filesystem.php b/pandora_console/vendor/symfony/filesystem/Filesystem.php index e8ba4958df..b7fc701182 100644 --- a/pandora_console/vendor/symfony/filesystem/Filesystem.php +++ b/pandora_console/vendor/symfony/filesystem/Filesystem.php @@ -125,7 +125,7 @@ class Filesystem * * @throws IOException When touch fails */ - public function touch(string|iterable $files, int $time = null, int $atime = null): void + public function touch(string|iterable $files, ?int $time = null, ?int $atime = null): void { foreach ($this->toIterable($files) as $file) { if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) { @@ -508,7 +508,7 @@ class Filesystem * * @throws IOException When file type is unknown */ - public function mirror(string $originDir, string $targetDir, \Traversable $iterator = null, array $options = []): void + public function mirror(string $originDir, string $targetDir, ?\Traversable $iterator = null, array $options = []): void { $targetDir = rtrim($targetDir, '/\\'); $originDir = rtrim($originDir, '/\\'); diff --git a/pandora_console/vendor/symfony/filesystem/Path.php b/pandora_console/vendor/symfony/filesystem/Path.php index 6643962351..01b5617248 100644 --- a/pandora_console/vendor/symfony/filesystem/Path.php +++ b/pandora_console/vendor/symfony/filesystem/Path.php @@ -254,7 +254,7 @@ final class Path * @param string|null $extension if specified, only that extension is cut * off (may contain leading dot) */ - public static function getFilenameWithoutExtension(string $path, string $extension = null): string + public static function getFilenameWithoutExtension(string $path, ?string $extension = null): string { if ('' === $path) { return ''; diff --git a/pandora_console/vendor/symfony/process/ExecutableFinder.php b/pandora_console/vendor/symfony/process/ExecutableFinder.php index 2f0f68c12c..a47477078b 100644 --- a/pandora_console/vendor/symfony/process/ExecutableFinder.php +++ b/pandora_console/vendor/symfony/process/ExecutableFinder.php @@ -44,7 +44,7 @@ class ExecutableFinder * @param string|null $default The default to return if no executable is found * @param array $extraDirs Additional dirs to check into */ - public function find(string $name, string $default = null, array $extraDirs = []): ?string + public function find(string $name, ?string $default = null, array $extraDirs = []): ?string { $dirs = array_merge( explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')), diff --git a/pandora_console/vendor/symfony/process/InputStream.php b/pandora_console/vendor/symfony/process/InputStream.php index d0517de22b..cd91029e8c 100644 --- a/pandora_console/vendor/symfony/process/InputStream.php +++ b/pandora_console/vendor/symfony/process/InputStream.php @@ -29,7 +29,7 @@ class InputStream implements \IteratorAggregate /** * Sets a callback that is called when the write buffer becomes empty. */ - public function onEmpty(callable $onEmpty = null): void + public function onEmpty(?callable $onEmpty = null): void { $this->onEmpty = null !== $onEmpty ? $onEmpty(...) : null; } diff --git a/pandora_console/vendor/symfony/process/PhpExecutableFinder.php b/pandora_console/vendor/symfony/process/PhpExecutableFinder.php index ae053641e9..4a882e0f25 100644 --- a/pandora_console/vendor/symfony/process/PhpExecutableFinder.php +++ b/pandora_console/vendor/symfony/process/PhpExecutableFinder.php @@ -33,7 +33,7 @@ class PhpExecutableFinder { if ($php = getenv('PHP_BINARY')) { if (!is_executable($php)) { - $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v'; + $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v --'; if (\function_exists('exec') && $php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) { if (!is_executable($php)) { return false; diff --git a/pandora_console/vendor/symfony/process/PhpProcess.php b/pandora_console/vendor/symfony/process/PhpProcess.php index 0d31e26fa8..01d88954dc 100644 --- a/pandora_console/vendor/symfony/process/PhpProcess.php +++ b/pandora_console/vendor/symfony/process/PhpProcess.php @@ -32,7 +32,7 @@ class PhpProcess extends Process * @param int $timeout The timeout in seconds * @param array|null $php Path to the PHP binary to use with any additional arguments */ - public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60, array $php = null) + public function __construct(string $script, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) { if (null === $php) { $executableFinder = new PhpExecutableFinder(); @@ -50,12 +50,12 @@ class PhpProcess extends Process parent::__construct($php, $cwd, $env, $script, $timeout); } - public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); } - public function start(callable $callback = null, array $env = []): void + public function start(?callable $callback = null, array $env = []): void { if (null === $this->getCommandLine()) { throw new RuntimeException('Unable to find the PHP executable.'); diff --git a/pandora_console/vendor/symfony/process/PhpSubprocess.php b/pandora_console/vendor/symfony/process/PhpSubprocess.php index 0720520f31..a97f8b26e0 100644 --- a/pandora_console/vendor/symfony/process/PhpSubprocess.php +++ b/pandora_console/vendor/symfony/process/PhpSubprocess.php @@ -51,7 +51,7 @@ class PhpSubprocess extends Process * @param int $timeout The timeout in seconds * @param array|null $php Path to the PHP binary to use with any additional arguments */ - public function __construct(array $command, string $cwd = null, array $env = null, int $timeout = 60, array $php = null) + public function __construct(array $command, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) { if (null === $php) { $executableFinder = new PhpExecutableFinder(); @@ -73,12 +73,12 @@ class PhpSubprocess extends Process parent::__construct($command, $cwd, $env, null, $timeout); } - public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { throw new LogicException(sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); } - public function start(callable $callback = null, array $env = []): void + public function start(?callable $callback = null, array $env = []): void { if (null === $this->getCommandLine()) { throw new RuntimeException('Unable to find the PHP executable.'); diff --git a/pandora_console/vendor/symfony/process/Process.php b/pandora_console/vendor/symfony/process/Process.php index 6b73c31d42..ed0507ecea 100644 --- a/pandora_console/vendor/symfony/process/Process.php +++ b/pandora_console/vendor/symfony/process/Process.php @@ -140,7 +140,7 @@ class Process implements \IteratorAggregate * * @throws LogicException When proc_open is not installed */ - public function __construct(array $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60) + public function __construct(array $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60) { if (!\function_exists('proc_open')) { throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.'); @@ -186,7 +186,7 @@ class Process implements \IteratorAggregate * * @throws LogicException When proc_open is not installed */ - public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, mixed $input = null, ?float $timeout = 60): static + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): static { $process = new static([], $cwd, $env, $input, $timeout); $process->commandline = $command; @@ -241,7 +241,7 @@ class Process implements \IteratorAggregate * * @final */ - public function run(callable $callback = null, array $env = []): int + public function run(?callable $callback = null, array $env = []): int { $this->start($callback, $env); @@ -260,7 +260,7 @@ class Process implements \IteratorAggregate * * @final */ - public function mustRun(callable $callback = null, array $env = []): static + public function mustRun(?callable $callback = null, array $env = []): static { if (0 !== $this->run($callback, $env)) { throw new ProcessFailedException($this); @@ -288,7 +288,7 @@ class Process implements \IteratorAggregate * @throws RuntimeException When process is already running * @throws LogicException In case a callback is provided and output has been disabled */ - public function start(callable $callback = null, array $env = []): void + public function start(?callable $callback = null, array $env = []): void { if ($this->isRunning()) { throw new RuntimeException('Process is already running.'); @@ -373,7 +373,7 @@ class Process implements \IteratorAggregate * * @final */ - public function restart(callable $callback = null, array $env = []): static + public function restart(?callable $callback = null, array $env = []): static { if ($this->isRunning()) { throw new RuntimeException('Process is already running.'); @@ -400,7 +400,7 @@ class Process implements \IteratorAggregate * @throws ProcessSignaledException When process stopped after receiving signal * @throws LogicException When process is not yet started */ - public function wait(callable $callback = null): int + public function wait(?callable $callback = null): int { $this->requireProcessIsStarted(__FUNCTION__); @@ -873,7 +873,7 @@ class Process implements \IteratorAggregate * * @return int|null The exit-code of the process or null if it's not running */ - public function stop(float $timeout = 10, int $signal = null): ?int + public function stop(float $timeout = 10, ?int $signal = null): ?int { $timeoutMicro = microtime(true) + $timeout; if ($this->isRunning()) { @@ -1247,7 +1247,7 @@ class Process implements \IteratorAggregate * * @param callable|null $callback The user defined PHP callback */ - protected function buildCallback(callable $callback = null): \Closure + protected function buildCallback(?callable $callback = null): \Closure { if ($this->outputDisabled) { return fn ($type, $data): bool => null !== $callback && $callback($type, $data); diff --git a/pandora_console/vendor/symfony/yaml/Command/LintCommand.php b/pandora_console/vendor/symfony/yaml/Command/LintCommand.php index d9a09092a7..75c09f51ed 100644 --- a/pandora_console/vendor/symfony/yaml/Command/LintCommand.php +++ b/pandora_console/vendor/symfony/yaml/Command/LintCommand.php @@ -42,7 +42,7 @@ class LintCommand extends Command private ?\Closure $directoryIteratorProvider; private ?\Closure $isReadableProvider; - public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null) + public function __construct(?string $name = null, ?callable $directoryIteratorProvider = null, ?callable $isReadableProvider = null) { parent::__construct($name); @@ -124,7 +124,7 @@ EOF return $this->display($io, $filesInfo); } - private function validate(string $content, int $flags, string $file = null): array + private function validate(string $content, int $flags, ?string $file = null): array { $prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) { if (\E_USER_DEPRECATED === $level) { diff --git a/pandora_console/vendor/symfony/yaml/Exception/ParseException.php b/pandora_console/vendor/symfony/yaml/Exception/ParseException.php index cb77f43136..246478f894 100644 --- a/pandora_console/vendor/symfony/yaml/Exception/ParseException.php +++ b/pandora_console/vendor/symfony/yaml/Exception/ParseException.php @@ -29,7 +29,7 @@ class ParseException extends RuntimeException * @param string|null $snippet The snippet of code near the problem * @param string|null $parsedFile The file name where the error occurred */ - public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null) + public function __construct(string $message, int $parsedLine = -1, ?string $snippet = null, ?string $parsedFile = null, ?\Throwable $previous = null) { $this->parsedFile = $parsedFile; $this->parsedLine = $parsedLine; diff --git a/pandora_console/vendor/symfony/yaml/Inline.php b/pandora_console/vendor/symfony/yaml/Inline.php index 382fa51c24..1ba90dc51b 100644 --- a/pandora_console/vendor/symfony/yaml/Inline.php +++ b/pandora_console/vendor/symfony/yaml/Inline.php @@ -34,7 +34,7 @@ class Inline private static bool $objectForMap = false; private static bool $constantSupport = false; - public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null): void + public static function initialize(int $flags, ?int $parsedLineNumber = null, ?string $parsedFilename = null): void { self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags); self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags); @@ -267,7 +267,7 @@ class Inline * * @throws ParseException When malformed inline YAML string is parsed */ - public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], bool &$isQuoted = null): mixed + public static function parseScalar(string $scalar, int $flags = 0, ?array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], ?bool &$isQuoted = null): mixed { if (\in_array($scalar[$i], ['"', "'"], true)) { // quoted scalar @@ -556,7 +556,7 @@ class Inline * * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved */ - private static function evaluateScalar(string $scalar, int $flags, array &$references = [], bool &$isQuotedString = null): mixed + private static function evaluateScalar(string $scalar, int $flags, array &$references = [], ?bool &$isQuotedString = null): mixed { $isQuotedString = false; $scalar = trim($scalar); diff --git a/pandora_console/vendor/symfony/yaml/Parser.php b/pandora_console/vendor/symfony/yaml/Parser.php index 14e8c089d9..1109f8568d 100644 --- a/pandora_console/vendor/symfony/yaml/Parser.php +++ b/pandora_console/vendor/symfony/yaml/Parser.php @@ -556,7 +556,7 @@ class Parser * * @throws ParseException When indentation problem are detected */ - private function getNextEmbedBlock(int $indentation = null, bool $inSequence = false): string + private function getNextEmbedBlock(?int $indentation = null, bool $inSequence = false): string { $oldLineIndentation = $this->getCurrentLineIndentation(); @@ -1038,7 +1038,7 @@ class Parser * * @internal */ - public static function preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int + public static function preg_match(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): int { if (false === $ret = preg_match($pattern, $subject, $matches, $flags, $offset)) { throw new ParseException(preg_last_error_msg());