diff --git a/README.md b/README.md index b2a6855..182ee50 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,98 @@ -# Telegram-robot for registering for tasks +# huesos -Synchronizes accounts with the site, displays a list of published applications with a selection by date, and also register to tasks \ No newline at end of file +Basis for developing chat-robots with "Web App" technology for Telegram + +## Installation + +### AnangoDB + +1. Create a View in ArangoDB for the document "product" +` +"links": { + "product": { + "fields": { + "description": { + "analyzers": [ + "text_ru" + ] + } + } + } +} +` + +2. Create a Graph with the specified values +**Name:** hierarchy + +**edgeDefinition:** entry +**fromCollections:** part, product... +**toCollections:** category, part... + +3. Create indexes for the "product" collection +**Type:** "Inverted Index" +**Fields:** title.RU +**Analyzer:** "text_ru" +**Search field:** true +**Name:** title_ru + +4. Create a View with the specified values +**Name:** products_search + +**type:** search-alias (you can also use "arangosearch") +**indexes:** +` +"indexes": [ + { + "collection": "product", + "index": "title_ru" (THIS IS AN EXAMPLE) + } + ] +` + +### NGINX + +1. Add this to a NGINX config: `try_files $uri $uri/ /index.php;` + +2. Add this to a NGINX config +` +location /images { + alias /PATH/TO/public/themes/default/images; +} +` + +## Settings +Settings of chat-robot and Web App + +Make sure you have a "settings" collection (can be created automatically) and at least one document with the "status" parameter set to "active" +` +{ + "status": "active" +} +` + +### language +Language for system messages if user language could not be determined + +**Value:** en + +## Suspensions +System of suspensions of chat-robot and Web App + +Make sure you have a "suspension" collection (can be created automatically) +` +{ + "end": 1726068961, + "targets": { + "chat-robot": true, + "web app": true + } + "access": { + "tester": true, + "developer": true + }, + "description": { + "ru": "Разрабатываю каталог, поиск и корзину", + "en": "I am developing a catalog, search and cart" + } +} +` diff --git a/composer.json b/composer.json index 8f776a5..2eba5e3 100755 --- a/composer.json +++ b/composer.json @@ -1,31 +1,39 @@ { "name": "mirzaev/arming_bot", - "type": "robot", - "tags": [ + "description": "Chat-robot for tuning weapons", + "homepage": "https://t.me/arming_bot", + "type": "chat-robot", + "keywords": [ "telegram", "chat-robot", "military", "shop" ], - "require": { - "triagens/arangodb": "^3.8", - "mirzaev/arangodb": "^1.0", - "badfarm/zanzara": "^0.9.1", - "nyholm/psr7": "^1.8", - "react/filesystem": "^0.1.2" - }, - "license": "WTFPL", - "autoload": { - "psr-4": { - "mirzaev\\arming_bot\\": "mirzaev/arming_bot/system/" - } - }, + "readme": "README.md", + "license": "WTFPL", "authors": [ { "name": "Arsen Mirzaev Tatyano-Muradovich", "email": "arsen@mirzaev.sexy" } ], + "require": { + "triagens/arangodb": "^3.8", + "mirzaev/minimal": "^2.2", + "mirzaev/arangodb": "^1.3", + "badfarm/zanzara": "^0.9.1", + "nyholm/psr7": "^1.8", + "react/filesystem": "^0.1.2", + "twig/twig": "^3.10", + "twig/extra-bundle": "^3.7", + "twig/intl-extra": "^3.10", + "phpoffice/phpspreadsheet": "^2.1" + }, + "autoload": { + "psr-4": { + "mirzaev\\arming_bot\\": "mirzaev/arming_bot/system/" + } + }, "minimum-stability": "stable", "config": { "allow-plugins": { diff --git a/composer.lock b/composer.lock index 423e4eb..9d4df12 100755 --- a/composer.lock +++ b/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": "7bbb4679029cfe777db1bfa0bebac18e", + "content-hash": "61697600b2677e22a6133cff9768d9eb", "packages": [ { "name": "badfarm/zanzara", @@ -193,16 +193,16 @@ }, { "name": "clue/http-proxy-react", - "version": "v1.8.0", + "version": "v1.9.0", "source": { "type": "git", "url": "https://github.com/clue/reactphp-http-proxy.git", - "reference": "09366dd3e13b36b90f8e47a6acaf5a2c96b79fb5" + "reference": "f3b02835273036a9370ac1c144b55df8e2b98430" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/clue/reactphp-http-proxy/zipball/09366dd3e13b36b90f8e47a6acaf5a2c96b79fb5", - "reference": "09366dd3e13b36b90f8e47a6acaf5a2c96b79fb5", + "url": "https://api.github.com/repos/clue/reactphp-http-proxy/zipball/f3b02835273036a9370ac1c144b55df8e2b98430", + "reference": "f3b02835273036a9370ac1c144b55df8e2b98430", "shasum": "" }, "require": { @@ -212,10 +212,11 @@ "ringcentral/psr7": "^1.2" }, "require-dev": { - "clue/block-react": "^1.5", - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4 || ^3 || ^2", "react/event-loop": "^1.2", - "react/http": "^1.5" + "react/http": "^1.5", + "react/promise-timer": "^1.10" }, "type": "library", "autoload": { @@ -244,7 +245,7 @@ ], "support": { "issues": "https://github.com/clue/reactphp-http-proxy/issues", - "source": "https://github.com/clue/reactphp-http-proxy/tree/v1.8.0" + "source": "https://github.com/clue/reactphp-http-proxy/tree/v1.9.0" }, "funding": [ { @@ -256,7 +257,7 @@ "type": "github" } ], - "time": "2022-09-01T14:36:49+00:00" + "time": "2024-04-10T14:46:11+00:00" }, { "name": "doctrine/inflector", @@ -421,28 +422,28 @@ }, { "name": "evenement/evenement", - "version": "v3.0.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/igorw/evenement.git", - "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7" + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7", - "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", "shasum": "" }, "require": { "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9 || ^6" }, "type": "library", "autoload": { - "psr-0": { - "Evenement": "src" + "psr-4": { + "Evenement\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -462,9 +463,9 @@ ], "support": { "issues": "https://github.com/igorw/evenement/issues", - "source": "https://github.com/igorw/evenement/tree/master" + "source": "https://github.com/igorw/evenement/tree/v3.0.2" }, - "time": "2017-07-23T21:35:13+00:00" + "time": "2023-08-08T05:53:35+00:00" }, { "name": "fig/http-message-util", @@ -524,26 +525,27 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.0", + "version": "v1.3.4", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37" + "reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/61b87392d986dc49ad5ef64e75b1ff5fee24ef81", + "reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81", "shasum": "" }, "require": { "php": "^7.3|^8.0" }, "require-dev": { - "nesbot/carbon": "^2.61", + "illuminate/support": "^8.0|^9.0|^10.0|^11.0", + "nesbot/carbon": "^2.61|^3.0", "pestphp/pest": "^1.21.3", "phpstan/phpstan": "^1.8.2", - "symfony/var-dumper": "^5.4.11" + "symfony/var-dumper": "^5.4.11|^6.2.0|^7.0.0" }, "type": "library", "extra": { @@ -580,18 +582,206 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-01-30T18:31:20+00:00" + "time": "2024-08-02T07:48:17+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/b8174494eda667f7d13876b4a7bfef0f62a7c0d1", + "reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.1" + }, + "require-dev": { + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.16", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^10.0", + "vimeo/psalm": "^5.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.0" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + }, + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "time": "2023-06-21T14:59:35+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" }, { "name": "mirzaev/arangodb", - "version": "1.0.2", + "version": "1.3.0", "source": { "type": "git", "url": "https://git.mirzaev.sexy/mirzaev/arangodb", - "reference": "e7da9978d01d3f8bdef6c74809dfb4eb8989f92c" + "reference": "d0ce9e47af189821bb6a3b7f54e228fb8c129aa3" }, "require": { - "php": "^8.1", + "php": "^8.2", "triagens/arangodb": "~3.8" }, "require-dev": { @@ -631,20 +821,62 @@ "type": "funding" } ], - "time": "2022-11-06T00:03:56+00:00" + "time": "2023-12-21T16:26:50+00:00" + }, + { + "name": "mirzaev/minimal", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://git.mirzaev.sexy/mirzaev/minimal", + "reference": "95ddffba30b1c63018b6afd2f540060c2cd81897" + }, + "require": { + "php": "~8.2" + }, + "type": "framework", + "autoload": { + "psr-4": { + "mirzaev\\minimal\\": "mirzaev/minimal/system" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Arsen Mirzaev Tatyano-Muradovich", + "email": "arsen@mirzaev.sexy", + "homepage": "https://mirzaev.sexy", + "role": "Developer" + } + ], + "description": "Lightweight MVC framework that manages only the basic mechanisms, leaving the development of the programmer and not overloading the project", + "homepage": "https://git.mirzaev.sexy/mirzaev/minimal", + "keywords": [ + "framework", + "lightweight", + "mvc" + ], + "support": { + "docs": "https://git.mirzaev.sexy/mirzaev/minimal/wiki", + "issues": "https://git.mirzaev.sexy/mirzaev/minimal/issues" + }, + "time": "2024-01-03T21:08:44+00:00" }, { "name": "netresearch/jsonmapper", - "version": "v4.2.0", + "version": "v4.4.1", "source": { "type": "git", "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" + "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0", + "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0", "shasum": "" }, "require": { @@ -655,7 +887,7 @@ "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", "squizlabs/php_codesniffer": "~3.5" }, "type": "library", @@ -680,22 +912,22 @@ "support": { "email": "cweiske@cweiske.de", "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" + "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1" }, - "time": "2023-04-09T17:37:40+00:00" + "time": "2024-01-31T06:18:54+00:00" }, { "name": "nyholm/psr7", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/Nyholm/psr7.git", - "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be" + "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7/zipball/3cb4d163b58589e47b35103e8e5e6a6a475b47be", - "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/aa5fc277a4f5508013d571341ade0c3886d4d00e", + "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e", "shasum": "" }, "require": { @@ -748,7 +980,7 @@ ], "support": { "issues": "https://github.com/Nyholm/psr7/issues", - "source": "https://github.com/Nyholm/psr7/tree/1.8.0" + "source": "https://github.com/Nyholm/psr7/tree/1.8.1" }, "funding": [ { @@ -760,7 +992,7 @@ "type": "github" } ], - "time": "2023-05-02T11:26:24+00:00" + "time": "2023-11-13T09:31:12+00:00" }, { "name": "opis/closure", @@ -879,16 +1111,16 @@ }, { "name": "php-di/invoker", - "version": "2.3.3", + "version": "2.3.4", "source": { "type": "git", "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786" + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/cd6d9f267d1a3474bdddf1be1da079f01b942786", - "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", "shasum": "" }, "require": { @@ -922,7 +1154,7 @@ ], "support": { "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.3" + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" }, "funding": [ { @@ -930,7 +1162,7 @@ "type": "github" } ], - "time": "2021-12-13T09:22:56+00:00" + "time": "2023-09-08T09:24:21+00:00" }, { "name": "php-di/php-di", @@ -1052,16 +1284,16 @@ }, { "name": "php-http/discovery", - "version": "1.18.1", + "version": "1.19.4", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "f258b3a1d16acb7b21f3b42d7a2494a733365237" + "reference": "0700efda8d7526335132360167315fdab3aeb599" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/f258b3a1d16acb7b21f3b42d7a2494a733365237", - "reference": "f258b3a1d16acb7b21f3b42d7a2494a733365237", + "url": "https://api.github.com/repos/php-http/discovery/zipball/0700efda8d7526335132360167315fdab3aeb599", + "reference": "0700efda8d7526335132360167315fdab3aeb599", "shasum": "" }, "require": { @@ -1085,7 +1317,8 @@ "php-http/httplug": "^1.0 || ^2.0", "php-http/message-factory": "^1.0", "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", - "symfony/phpunit-bridge": "^6.2" + "sebastian/comparator": "^3.0.5 || ^4.0.8", + "symfony/phpunit-bridge": "^6.4.4 || ^7.0.1" }, "type": "composer-plugin", "extra": { @@ -1124,22 +1357,22 @@ ], "support": { "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.18.1" + "source": "https://github.com/php-http/discovery/tree/1.19.4" }, - "time": "2023-05-17T08:53:10+00:00" + "time": "2024-03-29T13:00:05+00:00" }, { "name": "php-http/multipart-stream-builder", - "version": "1.3.0", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/php-http/multipart-stream-builder.git", - "reference": "f5938fd135d9fa442cc297dc98481805acfe2b6a" + "reference": "10086e6de6f53489cca5ecc45b6f468604d3460e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/multipart-stream-builder/zipball/f5938fd135d9fa442cc297dc98481805acfe2b6a", - "reference": "f5938fd135d9fa442cc297dc98481805acfe2b6a", + "url": "https://api.github.com/repos/php-http/multipart-stream-builder/zipball/10086e6de6f53489cca5ecc45b6f468604d3460e", + "reference": "10086e6de6f53489cca5ecc45b6f468604d3460e", "shasum": "" }, "require": { @@ -1180,9 +1413,162 @@ ], "support": { "issues": "https://github.com/php-http/multipart-stream-builder/issues", - "source": "https://github.com/php-http/multipart-stream-builder/tree/1.3.0" + "source": "https://github.com/php-http/multipart-stream-builder/tree/1.4.2" }, - "time": "2023-04-28T14:10:22+00:00" + "time": "2024-09-04T13:22:54+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "2.2.2", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "ffbcee68069b073bff07a71eb321dcd9f2763513" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/ffbcee68069b073bff07a71eb321dcd9f2763513", + "reference": "ffbcee68069b073bff07a71eb321dcd9f2763513", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^8.1", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^2.0 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^9.6 || ^10.5", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/2.2.2" + }, + "time": "2024-08-08T02:31:26+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" }, { "name": "psr/container", @@ -1233,21 +1619,123 @@ "time": "2021-11-05T16:50:12+00:00" }, { - "name": "psr/http-factory", - "version": "1.0.2", + "name": "psr/event-dispatcher", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -1271,7 +1759,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -1283,9 +1771,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -1390,6 +1878,57 @@ }, "time": "2021-05-03T11:20:27+00:00" }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, { "name": "react/cache", "version": "v1.2.0", @@ -1543,28 +2082,28 @@ }, { "name": "react/dns", - "version": "v1.11.0", + "version": "v1.13.0", "source": { "type": "git", "url": "https://github.com/reactphp/dns.git", - "reference": "3be0fc8f1eb37d6875cd6f0c6c7d0be81435de9f" + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/dns/zipball/3be0fc8f1eb37d6875cd6f0c6c7d0be81435de9f", - "reference": "3be0fc8f1eb37d6875cd6f0c6c7d0be81435de9f", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", "shasum": "" }, "require": { "php": ">=5.3.0", "react/cache": "^1.0 || ^0.6 || ^0.5", "react/event-loop": "^1.2", - "react/promise": "^3.0 || ^2.7 || ^1.2.1" + "react/promise": "^3.2 || ^2.7 || ^1.2.1" }, "require-dev": { - "phpunit/phpunit": "^9.5 || ^4.8.35", - "react/async": "^4 || ^3 || ^2", - "react/promise-timer": "^1.9" + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" }, "type": "library", "autoload": { @@ -1607,7 +2146,7 @@ ], "support": { "issues": "https://github.com/reactphp/dns/issues", - "source": "https://github.com/reactphp/dns/tree/v1.11.0" + "source": "https://github.com/reactphp/dns/tree/v1.13.0" }, "funding": [ { @@ -1615,20 +2154,20 @@ "type": "open_collective" } ], - "time": "2023-06-02T12:45:26+00:00" + "time": "2024-06-13T14:18:03+00:00" }, { "name": "react/event-loop", - "version": "v1.4.0", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/reactphp/event-loop.git", - "reference": "6e7e587714fff7a83dcc7025aee42ab3b265ae05" + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/event-loop/zipball/6e7e587714fff7a83dcc7025aee42ab3b265ae05", - "reference": "6e7e587714fff7a83dcc7025aee42ab3b265ae05", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", "shasum": "" }, "require": { @@ -1679,7 +2218,7 @@ ], "support": { "issues": "https://github.com/reactphp/event-loop/issues", - "source": "https://github.com/reactphp/event-loop/tree/v1.4.0" + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" }, "funding": [ { @@ -1687,7 +2226,7 @@ "type": "open_collective" } ], - "time": "2023-05-05T10:11:24+00:00" + "time": "2023-11-13T13:48:05+00:00" }, { "name": "react/filesystem", @@ -1752,16 +2291,16 @@ }, { "name": "react/http", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/reactphp/http.git", - "reference": "bb3154dbaf2dfe3f0467f956a05f614a69d5f1d0" + "reference": "8111281ee57f22b7194f5dba225e609ba7ce4d20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/http/zipball/bb3154dbaf2dfe3f0467f956a05f614a69d5f1d0", - "reference": "bb3154dbaf2dfe3f0467f956a05f614a69d5f1d0", + "url": "https://api.github.com/repos/reactphp/http/zipball/8111281ee57f22b7194f5dba225e609ba7ce4d20", + "reference": "8111281ee57f22b7194f5dba225e609ba7ce4d20", "shasum": "" }, "require": { @@ -1772,14 +2311,13 @@ "react/event-loop": "^1.2", "react/promise": "^3 || ^2.3 || ^1.2.1", "react/socket": "^1.12", - "react/stream": "^1.2", - "ringcentral/psr7": "^1.2" + "react/stream": "^1.2" }, "require-dev": { "clue/http-proxy-react": "^1.8", "clue/reactphp-ssh-proxy": "^1.4", "clue/socks-react": "^1.4", - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", "react/async": "^4 || ^3 || ^2", "react/promise-stream": "^1.4", "react/promise-timer": "^1.9" @@ -1832,7 +2370,7 @@ ], "support": { "issues": "https://github.com/reactphp/http/issues", - "source": "https://github.com/reactphp/http/tree/v1.9.0" + "source": "https://github.com/reactphp/http/tree/v1.10.0" }, "funding": [ { @@ -1840,27 +2378,27 @@ "type": "open_collective" } ], - "time": "2023-04-26T10:29:24+00:00" + "time": "2024-03-27T17:20:46+00:00" }, { "name": "react/promise", - "version": "v2.10.0", + "version": "v2.11.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38" + "reference": "1a8460931ea36dc5c76838fec5734d55c88c6831" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", - "reference": "f913fb8cceba1e6644b7b90c4bfb678ed8a3ef38", + "url": "https://api.github.com/repos/reactphp/promise/zipball/1a8460931ea36dc5c76838fec5734d55c88c6831", + "reference": "1a8460931ea36dc5c76838fec5734d55c88c6831", "shasum": "" }, "require": { "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.36" + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" }, "type": "library", "autoload": { @@ -1904,7 +2442,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v2.10.0" + "source": "https://github.com/reactphp/promise/tree/v2.11.0" }, "funding": [ { @@ -1912,7 +2450,7 @@ "type": "open_collective" } ], - "time": "2023-05-02T15:15:43+00:00" + "time": "2023-11-16T16:16:50+00:00" }, { "name": "react/promise-stream", @@ -2074,36 +2612,36 @@ }, { "name": "react/socket", - "version": "v1.13.0", + "version": "v1.16.0", "source": { "type": "git", "url": "https://github.com/reactphp/socket.git", - "reference": "cff482bbad5848ecbe8b57da57e4e213b03619aa" + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/socket/zipball/cff482bbad5848ecbe8b57da57e4e213b03619aa", - "reference": "cff482bbad5848ecbe8b57da57e4e213b03619aa", + "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", "shasum": "" }, "require": { "evenement/evenement": "^3.0 || ^2.0 || ^1.0", "php": ">=5.3.0", - "react/dns": "^1.11", + "react/dns": "^1.13", "react/event-loop": "^1.2", - "react/promise": "^3 || ^2.6 || ^1.2.1", - "react/stream": "^1.2" + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" }, "require-dev": { - "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", - "react/async": "^4 || ^3 || ^2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", "react/promise-stream": "^1.4", - "react/promise-timer": "^1.9" + "react/promise-timer": "^1.11" }, "type": "library", "autoload": { "psr-4": { - "React\\Socket\\": "src" + "React\\Socket\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2142,7 +2680,7 @@ ], "support": { "issues": "https://github.com/reactphp/socket/issues", - "source": "https://github.com/reactphp/socket/tree/v1.13.0" + "source": "https://github.com/reactphp/socket/tree/v1.16.0" }, "funding": [ { @@ -2150,20 +2688,20 @@ "type": "open_collective" } ], - "time": "2023-06-07T10:28:34+00:00" + "time": "2024-07-26T10:38:09+00:00" }, { "name": "react/stream", - "version": "v1.2.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/reactphp/stream.git", - "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9" + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/stream/zipball/7a423506ee1903e89f1e08ec5f0ed430ff784ae9", - "reference": "7a423506ee1903e89f1e08ec5f0ed430ff784ae9", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", "shasum": "" }, "require": { @@ -2173,12 +2711,12 @@ }, "require-dev": { "clue/stream-filter": "~1.2", - "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35" + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" }, "type": "library", "autoload": { "psr-4": { - "React\\Stream\\": "src" + "React\\Stream\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2220,19 +2758,15 @@ ], "support": { "issues": "https://github.com/reactphp/stream/issues", - "source": "https://github.com/reactphp/stream/tree/v1.2.0" + "source": "https://github.com/reactphp/stream/tree/v1.4.0" }, "funding": [ { - "url": "https://github.com/WyriHaximus", - "type": "github" - }, - { - "url": "https://github.com/clue", - "type": "github" + "url": "https://opencollective.com/reactphp", + "type": "open_collective" } ], - "time": "2021-07-11T12:37:55+00:00" + "time": "2024-06-11T12:45:25+00:00" }, { "name": "ringcentral/psr7", @@ -2295,6 +2829,2091 @@ }, "time": "2018-05-29T20:21:04+00:00" }, + { + "name": "symfony/cache", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "b61e464d7687bb7e8f677d5031c632bf3820df18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/b61e464d7687bb7e8f677d5031c632bf3820df18", + "reference": "b61e464d7687bb7e8f677d5031c632bf3820df18", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^2.5|^3", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-12T09:59:40+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/df6a1a44c890faded49a5fca33c2d5c5fd3c2197", + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/config", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "2210fc99fa42a259eb6c89d1f724ce0c4d62d5d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/2210fc99fa42a259eb6c89d1f724ce0c4d62d5d2", + "reference": "2210fc99fa42a259eb6c89d1f724ce0c4d62d5d2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "5320e0bc2c9e2d7450bb4091e497a305a68b28ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5320e0bc2c9e2d7450bb4091e497a305a68b28ed", + "reference": "5320e0bc2c9e2d7450bb4091e497a305a68b28ed", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^3.5", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "symfony/config": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-29T08:16:25+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "432bb369952795c61ca1def65e078c4a80dad13c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/432bb369952795c61ca1def65e078c4a80dad13c", + "reference": "432bb369952795c61ca1def65e078c4a80dad13c", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v7.1.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-07-26T13:02:51+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7", + "reference": "9fa7f7a21beb22a39a8f3f28618b29e50d7a55a7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "92a91985250c251de9b947a14bb2c9390b1a562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c", + "reference": "92a91985250c251de9b947a14bb2c9390b1a562c", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.1.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-28T10:03:55+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/d95bbf319f7d052082fb7af147e0f835a695e823", + "reference": "d95bbf319f7d052082fb7af147e0f835a695e823", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-13T14:28:19+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "711af4eefcb4054a9c93e44b403626e1826bcddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/711af4eefcb4054a9c93e44b403626e1826bcddd", + "reference": "711af4eefcb4054a9c93e44b403626e1826bcddd", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.2", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^7.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/filesystem": "^7.1", + "symfony/finder": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/routing": "^6.4|^7.0" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/asset": "<6.4", + "symfony/asset-mapper": "<6.4", + "symfony/clock": "<6.4", + "symfony/console": "<6.4", + "symfony/dom-crawler": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/lock": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", + "symfony/security-core": "<6.4", + "symfony/security-csrf": "<6.4", + "symfony/serializer": "<6.4", + "symfony/stopwatch": "<6.4", + "symfony/translation": "<6.4", + "symfony/twig-bridge": "<6.4", + "symfony/twig-bundle": "<6.4", + "symfony/validator": "<6.4", + "symfony/web-profiler-bundle": "<6.4", + "symfony/workflow": "<6.4" + }, + "require-dev": { + "doctrine/persistence": "^1.3|^2|^3", + "dragonmantank/cron-expression": "^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "seld/jsonlint": "^1.10", + "symfony/asset": "^6.4|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/dotenv": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/mailer": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/scheduler": "^6.4.4|^7.0.4", + "symfony/security-bundle": "^6.4|^7.0", + "symfony/semaphore": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/string": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0", + "symfony/type-info": "^7.1", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/workflow": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.0.4" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-11T16:10:02+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.1.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "f602d5c17d1fa02f8019ace2687d9d136b7f4a1a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f602d5c17d1fa02f8019ace2687d9d136b7f4a1a", + "reference": "f602d5c17d1fa02f8019ace2687d9d136b7f4a1a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.1.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-07-26T12:41:01+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "6efcbd1b3f444f631c386504fc83eeca25963747" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6efcbd1b3f444f631c386504fc83eeca25963747", + "reference": "6efcbd1b3f444f631c386504fc83eeca25963747", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.0.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^7.1", + "symfony/routing": "^6.4|^7.0", + "symfony/serializer": "^7.1", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "twig/twig": "^3.0.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-30T17:02:28+00:00" + }, + { + "name": "symfony/intl", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/intl.git", + "reference": "66c1ecda092b1130ada2cf5f59dacfd5b6e9c99c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/intl/zipball/66c1ecda092b1130ada2cf5f59dacfd5b6e9c99c", + "reference": "66c1ecda092b1130ada2cf5f59dacfd5b6e9c99c", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/string": "<7.1" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Intl\\": "" + }, + "exclude-from-classmap": [ + "/Tests/", + "/Resources/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Eriksen Costa", + "email": "eriksen.costa@infranology.com.br" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides access to the localization data of the ICU library", + "homepage": "https://symfony.com", + "keywords": [ + "i18n", + "icu", + "internationalization", + "intl", + "l10n", + "localization" + ], + "support": { + "source": "https://github.com/symfony/intl/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/3fb075789fb91f9ad9af537c4012d523085bd5af", + "reference": "3fb075789fb91f9ad9af537c4012d523085bd5af", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", + "reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:35:24+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "1500aee0094a3ce1c92626ed8cf3c2037e86f5a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/1500aee0094a3ce1c92626ed8cf3c2037e86f5a7", + "reference": "1500aee0094a3ce1c92626ed8cf3c2037e86f5a7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-29T08:16:25+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/twig-bridge", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bridge.git", + "reference": "2db32cfe8fc57797908ef0bee232b90dbe42af66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/2db32cfe8fc57797908ef0bee232b90dbe42af66", + "reference": "2db32cfe8fc57797908ef0bee232b90dbe42af66", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/translation-contracts": "^2.5|^3", + "twig/twig": "^3.9" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/console": "<6.4", + "symfony/form": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/mime": "<6.4", + "symfony/serializer": "<6.4", + "symfony/translation": "<6.4", + "symfony/workflow": "<6.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^6.4|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/emoji": "^7.1", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/security-acl": "^2.8|^3.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/security-csrf": "^6.4|^7.0", + "symfony/security-http": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/workflow": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/cssinliner-extra": "^2.12|^3", + "twig/inky-extra": "^2.12|^3", + "twig/markdown-extra": "^2.12|^3" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Twig\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Twig with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bridge/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-29T08:16:25+00:00" + }, + { + "name": "symfony/twig-bundle", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bundle.git", + "reference": "d48c2f08c2f315e749f0e18fc4945b7be8afe1e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d48c2f08c2f315e749f0e18fc4945b7be8afe1e5", + "reference": "d48c2f08c2f315e749f0e18fc4945b7be8afe1e5", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "php": ">=8.2", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0", + "twig/twig": "^3.0.4" + }, + "conflict": { + "symfony/framework-bundle": "<6.4", + "symfony/translation": "<6.4" + }, + "require-dev": { + "symfony/asset": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\TwigBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of Twig into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bundle/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.1.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "a5fa7481b199090964d6fd5dab6294d5a870c7aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a5fa7481b199090964d6fd5dab6294d5a870c7aa", + "reference": "a5fa7481b199090964d6fd5dab6294d5a870c7aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.0.4" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.1.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-08-30T16:12:47+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v7.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "b80a669a2264609f07f1667f891dbfca25eba44c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/b80a669a2264609f07f1667f891dbfca25eba44c", + "reference": "b80a669a2264609f07f1667f891dbfca25eba44c", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.1.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-28T08:00:31+00:00" + }, { "name": "thecodingmachine/safe", "version": "v1.3.3", @@ -2547,6 +5166,223 @@ }, "time": "2021-06-18T12:06:02+00:00" }, + { + "name": "twig/extra-bundle", + "version": "v3.13.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/twig-extra-bundle.git", + "reference": "21a9a7aa9f79d4493bb6fed4eb2794339f9551f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/21a9a7aa9f79d4493bb6fed4eb2794339f9551f5", + "reference": "21a9a7aa9f79d4493bb6fed4eb2794339f9551f5", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/framework-bundle": "^5.4|^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0", + "twig/twig": "^3.0|^4.0" + }, + "require-dev": { + "league/commonmark": "^1.0|^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0", + "twig/cache-extra": "^3.0", + "twig/cssinliner-extra": "^3.0", + "twig/html-extra": "^3.0", + "twig/inky-extra": "^3.0", + "twig/intl-extra": "^3.0", + "twig/markdown-extra": "^3.0", + "twig/string-extra": "^3.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Twig\\Extra\\TwigExtraBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Symfony bundle for extra Twig extensions", + "homepage": "https://twig.symfony.com", + "keywords": [ + "bundle", + "extra", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.13.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2024-09-01T20:39:12+00:00" + }, + { + "name": "twig/intl-extra", + "version": "v3.13.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/intl-extra.git", + "reference": "1b8d78c5db08bdc61015fd55009d2e84b3aa7e38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/1b8d78c5db08bdc61015fd55009d2e84b3aa7e38", + "reference": "1b8d78c5db08bdc61015fd55009d2e84b3aa7e38", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/intl": "^5.4|^6.4|^7.0", + "twig/twig": "^3.13|^4.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Twig\\Extra\\Intl\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Twig extension for Intl", + "homepage": "https://twig.symfony.com", + "keywords": [ + "intl", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/intl-extra/tree/v3.13.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2024-09-03T13:08:40+00:00" + }, + { + "name": "twig/twig", + "version": "v3.13.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "afc0eb63dc66c248c5a94504dc2b255bc9b86575" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/afc0eb63dc66c248c5a94504dc2b255bc9b86575", + "reference": "afc0eb63dc66c248c5a94504dc2b255bc9b86575", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php81": "^1.29" + }, + "require-dev": { + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.13.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2024-09-07T08:01:12+00:00" + }, { "name": "wyrihaximus/composer-update-bin-autoload-path", "version": "1.1.1", @@ -3133,5 +5969,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.6.0" } diff --git a/mirzaev/arming_bot/system/controllers/catalog.php b/mirzaev/arming_bot/system/controllers/catalog.php new file mode 100755 index 0000000..34cfce4 --- /dev/null +++ b/mirzaev/arming_bot/system/controllers/catalog.php @@ -0,0 +1,280 @@ + + */ +final class catalog extends core +{ + /** + * Registry of errors + */ + protected array $errors = [ + 'session' => [], + 'account' => [], + 'catalog' => [] + ]; + + /** + * Catalog + * + * @param array $parameters Parameters of the request (POST + GET) + */ + public function index(array $parameters = []): ?string + { + if (!empty($parameters['categories']) && $parameters['categories'] !== ['/']) { + // Переданы категории ["category1", "category2", "category3"] (иерархия) + + // Инициализация актуальной категории + $category = end($parameters['categories']); + + if ($model = categories::category($category)) { + // Найдена модель обработки актуальной категории + + if (method_exists($model, 'entries')) { + // Найден метод поиска вхождений + + // Поиск категорий или товаров входящих в актуальную категорию + $entries = $model::entries( + category: $model->getId(), + filter: 'v.deleted != true && v.hidden != true', + amount: 30, + errors: $this->errors['catalog'] + ); + + // Объявление буферов категорий и товаров (важно - в единственном числе, по параметру из базы данных) + $category = $product = []; + + foreach ($entries as $entry) { + // Перебор вхождений + + // Запись массивов категорий и товаров ($category и $product) в буфер глобальной переменной шаблонизатора + ${$entry->_type}[] = $entry; + } + + // Запись категорий из буфера в глобальную переменную шаблонизатора + $this->view->categories = $category; + + // Запись товаров из буфера в глобальную переменную шаблонизатора + $this->view->products = $product; + } + } + } else { + // Не переданы категории + + // Поиск категорий: "categories" + // @todo сделать автоматический поиск "самой верхней" категории + $this->view->categories = category::_read( + filter: 'd.deleted != true && d.hidden != true', + sort: 'd.position ASC, d.name ASC, d.created DESC', + amount: 30, + errors: $this->errors['catalog'] + ); + + // Search for products + /* $this->view->products = product::read( + filter: 'd.deleted != true && d.hidden != true', + sort: 'd.promoting ASC, d.position ASC, d.created DESC', + amount: 6, + errors: $this->errors['catalog'] + ); */ + } + + if ($_SERVER['REQUEST_METHOD'] === 'GET') { + // GET request + + // Exit (success) + return $this->view->render('catalog/page.html'); + } else if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // POST request + + // Initializing a response headers + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Initializing of the output buffer + ob_start(); + + // Generating the reponse + echo json_encode( + [ + 'title' => $title ?? '', + 'html' => [ + 'categories' => $this->view->render('catalog/elements/categories.html'), + 'products' => $this->view->render('catalog/elements/products/2columns.html') + ], + 'errors' => $this->errors + ] + ); + + // Initializing a response headers + header('Content-Length: ' . ob_get_length()); + + // Sending and deinitializing of the output buffer + ob_end_flush(); + flush(); + + // Exit (success) + return null; + } + + // Exit (fail) + return null; + } + + /** + * Search + * + * @param array $parameters Parameters of the request (POST + GET) + */ + public function search(array $parameters = []): ?string + { + // Initializing of text fore search + preg_match('/[\w\s]+/u', $parameters['text'] ?? '', $matches); + $text = $matches[0] ?? null; + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // POST request + + // Search for products + $this->view->products = isset($text) ? product::read( + search: $text, + filter: 'd.deleted != true && d.hidden != true', + sort: 'd.position ASC, d.name ASC, d.created DESC', + amount: 30, + errors: $this->errors['catalog'] + ) : []; + + // Initializing a response headers + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Initializing of the output buffer + ob_start(); + + // Generating the reponse + echo json_encode( + [ + 'title' => $title ?? '', + 'html' => [ + 'products' => $this->view->render('catalog/elements/products.html') + ], + 'errors' => $this->errors + ] + ); + + // Initializing a response headers + header('Content-Length: ' . ob_get_length()); + + // Sending and deinitializing of the output buffer + ob_end_flush(); + flush(); + + // Exit (success) + return null; + } + + // Exit (fail) + return null; + } + + /** + * Product + * + * @param array $parameters Parameters of the request (POST + GET) + */ + public function product(array $parameters = []): ?string + { + // Initializing of text fore search + preg_match('/[\d]+/', $parameters['id'] ?? '', $matches); + $_key = $matches[0] ?? null; + + if (!empty($_key)) { + // Received id of prouct (_key) + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // POST request + + // Search for products + $product = product::read( + filter: "d._key == \"$_key\" && d.deleted != true && d.hidden != true", + sort: 'd.created DESC', + amount: 1, + return: '{id: d._key, title: d.title.ru, description: d.description.ru, cost: d.cost, weight: d.weight, dimensions: d.dimensions, brand: d.brand.ru, compatibility: d.compatibility.ru}', + errors: $this->errors['catalog'] + )[0]?->getAll(); + + if (!empty($product)) { + // Found the product + + // Initializing buffer of images + $images = []; + + foreach ( + glob(INDEX . + DIRECTORY_SEPARATOR . + 'themes' . + DIRECTORY_SEPARATOR . + (THEME ?? 'default') . + DIRECTORY_SEPARATOR . + 'images' . + DIRECTORY_SEPARATOR . + $_key . + DIRECTORY_SEPARATOR . + "*.{jpg,png,gif}", GLOB_BRACE) as $file + ) { + // Iterate over images of the product + + // Write to buffer of images + $images[] = "/images/$_key/" . basename($file); + } + + $product = $product + ['images' => $images]; + } + + // Initializing a response headers + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Initializing of the output buffer + ob_start(); + + // Generating the reponse + echo json_encode( + [ + 'product' => $product, + 'errors' => $this->errors + ] + ); + + // Initializing a response headers + header('Content-Length: ' . ob_get_length()); + + // Sending and deinitializing of the output buffer + ob_end_flush(); + flush(); + + // Exit (success) + return null; + } + } + + // Exit (fail) + return null; + } +} diff --git a/mirzaev/arming_bot/system/controllers/core.php b/mirzaev/arming_bot/system/controllers/core.php new file mode 100755 index 0000000..96b245f --- /dev/null +++ b/mirzaev/arming_bot/system/controllers/core.php @@ -0,0 +1,193 @@ + + */ +class core extends controller +{ + /** + * Postfix for name of controllers files + */ + final public const string POSTFIX = ''; + + /** + * Instance of the settings + */ + public static settings $settings; + + /** + * Instance of a session + */ + protected readonly session $session; + + /** + * Instance of an account + */ + protected readonly ?account $account; + + /** + * Registry of errors + */ + protected array $errors = [ + 'session' => [], + 'account' => [] + ]; + + /** + * Constructor of an instance + * + * @param bool $initialize Initialize a controller? + * + * @return void + */ + public function __construct(bool $initialize = true) + { + // Blocking requests from CloudFlare (better to write this blocking into nginx config file) + if (isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] === 'nginx-ssl early hints') return; + + // For the extends system + parent::__construct($initialize); + + if ($initialize) { + // Initializing is requested + + // Initializing of models core (connect to ArangoDB...) + new models(); + + // Initializing of the date until which the session will be active + $expires = strtotime('+1 week'); + + // Initializing of default value of hash of the session + $_COOKIE["session"] ??= null; + + // Initializing of a session + $this->session = new session($_COOKIE["session"], $expires, $this->errors['session']); + + // Handle a problems with initializing a session + if (!empty($this->errors['session'])) exit(1); + + // телеграм не сохраняет куки + /* else if ($_COOKIE["session"] !== $this->session->hash) { + // Hash of the session is changed (implies that the session has expired and recreated) + + // Write a new hash of the session to cookies + setcookie( + 'session', + $this->session->hash, + [ + 'expires' => $expires, + 'path' => '/', + 'secure' => true, + 'httponly' => true, + 'samesite' => 'strict' + ] + ); + } */ + + // Initializing of the account + $this->account = $this->session->account($this->errors['account']); + + // Initializing of the settings + self::$settings = settings::active(); + + // Initializing of preprocessor of views + $this->view = new templater($this->session, $this->account); + + // @todo перенести в middleware + + // Search for suspensions + $suspension = suspension::search(); + + if ($suspension && $suspension->targets['web app']) { + // Found a suspension + + if ($this->account) { + // Initialized account + + foreach ($suspension->access as $type => $status) { + // Перебор статусов доступа + + if ($status && $this->account->{$type}) { + // Authorized account + + // Exit (success) + return $this; + } + } + + // Exit (success) + goto suspension; + } else { + // Not initialized account + + // Send the suspension page and exit (success) + suspension: + + // Write title of the page to templater global variables + $this->view->title = match ($account?->language ?? self::$settings?->language) { + 'ru' => 'Приостановлено', + 'en' => 'Suspended', + default => 'Suspended' + }; + + // Write description of the suspension to templater global variables + $this->view->description = $suspension->description[$account?->language ?? self::$settings?->language] ?? array_values($suspension->description)[0]; + + // Write message of remaining time of the suspension to templater global variables + $this->view->remain = [ + 'title' => match ($account?->language ?? self::$settings?->language) { + 'ru' => 'Осталось времени: ', + 'en' => 'Time remaining: ', + default => 'Time remaining: ' + }, + 'value' => $suspension?->message() + ]; + + // Send the suspension page + echo $this->view->render('suspension/page.html'); + + // Exit (success) + exit(0); + } + } + } + } + + /** + * Check of initialization + * + * Checks whether a property is initialized in a document instance from ArangoDB + * + * @param string $name Name of the property from ArangoDB + * + * @return bool The property is initialized? + */ + public function __isset(string $name): bool + { + // Check of initialization of the property and exit (success) + return match ($name) { + default => isset($this->{$name}) + }; + } +} diff --git a/mirzaev/arming_bot/system/controllers/index.php b/mirzaev/arming_bot/system/controllers/index.php new file mode 100755 index 0000000..8313b4c --- /dev/null +++ b/mirzaev/arming_bot/system/controllers/index.php @@ -0,0 +1,35 @@ + + */ +final class index extends core +{ + /** + * Render the main page + * + * @param array $parameters Parameters of the request (POST + GET) + */ + public function index(array $parameters = []): ?string + { + // Поиск товаров + /* $this->view->products = product::read(); */ + + // Exit (success) + if ($_SERVER['REQUEST_METHOD'] === 'GET') return $this->view->render('catalog.html'); + + // Exit (fail) + return null; + } +} diff --git a/mirzaev/arming_bot/system/controllers/session.php b/mirzaev/arming_bot/system/controllers/session.php new file mode 100755 index 0000000..fcc5643 --- /dev/null +++ b/mirzaev/arming_bot/system/controllers/session.php @@ -0,0 +1,134 @@ + + */ +final class session extends core +{ + /** + * Registry of errors + */ + protected array $errors = [ + 'session' => [], + 'account' => [] + ]; + + /** + * Connect session to the telegram account + * + * @param array $parameters Parameters of the request (POST + GET) + */ + public function telegram(array $parameters = []): ?string + { + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // POST request + + if ($connected = isset($this->account)) { + // Found the account + + // Initializing language of the account + $language = $this->account->language; + } else { + // Not found the account + + if (count($parameters) > 1 && isset($parameters['hash'])) { + + $buffer = $parameters; + + unset($buffer['authentication'], $buffer['hash']); + ksort($buffer); + + $prepared = []; + foreach ($buffer as $key => $value) { + if (is_array($value)) { + $prepared[] = $key . '=' . json_encode($value, JSON_UNESCAPED_UNICODE); + } else { + $prepared[] = $key . '=' . $value; + } + } + + $key = hash_hmac('sha256', require(SETTINGS . DIRECTORY_SEPARATOR . 'key.php'), 'WebAppData', true); + $hash = bin2hex(hash_hmac('sha256', implode(PHP_EOL, $prepared), $key, true)); + + if (hash_equals($hash, $parameters['hash'])) { + // Data confirmed (according to telegram documentation) + + if (time() - $parameters['auth_date'] < 86400) { + // Authorization date less than 1 day ago + + // Initializing data of the account + $data = json_decode($parameters['user']); + + // Initializing of the account + $account = account::initialization( + $data->id, + [ + 'id' => $data->id, + 'name' => [ + 'first' => $data->first_name, + 'last' => $data->last_name + ], + 'domain' => $data->username, + 'language' => $data->language_code, + 'messages' => $data->allows_write_to_pm + ], + $this->errors['account'] + ); + + if ($account instanceof account) { + // Initialized the account + + // Connecting the account to the session + $connected = $this->session->connect($account, $this->errors['session']); + + // Initializing language of the account + $language = $account->language; + } + } + } + } + } + + // Initializing a response headers + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Initializing of the output buffer + ob_start(); + + // Generating the reponse + echo json_encode( + [ + 'connected' => (bool) $connected, + 'language' => $language ?? null, + 'errors' => $this->errors + ] + ); + + // Initializing a response headers + header('Content-Length: ' . ob_get_length()); + + // Sending and deinitializing of the output buffer + ob_end_flush(); + flush(); + + // Exit (success) + return null; + } + + // Exit (fail) + return null; + } +} diff --git a/mirzaev/arming_bot/system/emojis.txt b/mirzaev/arming_bot/system/emojis.txt deleted file mode 100755 index 7b69344..0000000 --- a/mirzaev/arming_bot/system/emojis.txt +++ /dev/null @@ -1,4210 +0,0 @@ -U+1F601 -U+1F602 -U+1F603 -U+1F604 -U+1F605 -U+1F606 -U+1F609 -U+1F60A -U+1F60B -U+1F60C -U+1F60D -U+1F60F -U+1F612 -U+1F613 -U+1F614 -U+1F616 -U+1F618 -U+1F61A -U+1F61C -U+1F61D -U+1F61E -U+1F620 -U+1F621 -U+1F622 -U+1F623 -U+1F624 -U+1F625 -U+1F628 -U+1F629 -U+1F62A -U+1F62B -U+1F62D -U+1F630 -U+1F631 -U+1F632 -U+1F633 -U+1F635 -U+1F637 -U+1F638 -U+1F639 -U+1F63A -U+1F63B -U+1F63C -U+1F63D -U+1F63E -U+1F63F -U+1F640 -U+1F645 -U+1F646 -U+1F647 -U+1F648 -U+1F649 -U+1F64A -U+1F64B -U+1F64C -U+1F64D -U+1F64E -U+1F64F -U+2702 -U+2705 -U+2708 -U+2709 -U+270A -U+270B -U+270C -U+270F -U+2712 -U+2714 -U+2716 -U+2728 -U+2733 -U+2734 -U+2744 -U+2747 -U+274C -U+274E -U+2753 -U+2754 -U+2755 -U+2757 -U+2764 -U+2795 -U+2796 -U+2797 -U+27A1 -U+27B0 -U+1F680 -U+1F683 -U+1F684 -U+1F685 -U+1F687 -U+1F689 -U+1F68C -U+1F68F -U+1F691 -U+1F692 -U+1F693 -U+1F695 -U+1F697 -U+1F699 -U+1F69A -U+1F6A2 -U+1F6A4 -U+1F6A5 -U+1F6A7 -U+1F6A8 -U+1F6A9 -U+1F6AA -U+1F6AB -U+1F6AC -U+1F6AD -U+1F6B2 -U+1F6B6 -U+1F6B9 -U+1F6BA -U+1F6BB -U+1F6BC -U+1F6BD -U+1F6BE -U+1F6C0 -U+24C2 -U+1F170 -U+1F171 -U+1F17E -U+1F17F -U+1F18E -U+1F191 -U+1F192 -U+1F193 -U+1F194 -U+1F195 -U+1F196 -U+1F197 -U+1F198 -U+1F199 -U+1F19A -U+1F1E9 U+1F1EA -U+1F1EC U+1F1E7 -U+1F1E8 U+1F1F3 -U+1F1EF U+1F1F5 -U+1F1EB U+1F1F7 -U+1F1F0 U+1F1F7 -U+1F1EA U+1F1F8 -U+1F1EE U+1F1F9 -U+1F1F7 U+1F1FA -U+1F1FA U+1F1F8 -U+1F201 -U+1F202 -U+1F21A -U+1F22F -U+1F232 -U+1F233 -U+1F234 -U+1F235 -U+1F236 -U+1F237 -U+1F238 -U+1F239 -U+1F23A -U+1F250 -U+1F251 -U+00A9 -U+00AE -U+203C -U+2049 -U+0023 U+20E3 -U+0038 U+20E3 -U+0039 U+20E3 -U+0037 U+20E3 -U+0030 U+20E3 -U+0036 U+20E3 -U+0035 U+20E3 -U+0034 U+20E3 -U+0033 U+20E3 -U+0032 U+20E3 -U+0031 U+20E3 -U+2122 -U+2139 -U+2194 -U+2195 -U+2196 -U+2197 -U+2198 -U+2199 -U+21A9 -U+21AA -U+231A -U+231B -U+23E9 -U+23EA -U+23EB -U+23EC -U+23F0 -U+23F3 -U+25AA -U+25AB -U+25B6 -U+25C0 -U+25FB -U+25FC -U+25FD -U+25FE -U+2600 -U+2601 -U+260E -U+2611 -U+2614 -U+2615 -U+261D -U+263A -U+2648 -U+2649 -U+264A -U+264B -U+264C -U+264D -U+264E -U+264F -U+2650 -U+2651 -U+2652 -U+2653 -U+2660 -U+2663 -U+2665 -U+2666 -U+2668 -U+267B -U+267F -U+2693 -U+26A0 -U+26A1 -U+26AA -U+26AB -U+26BD -U+26BE -U+26C4 -U+26C5 -U+26CE -U+26D4 -U+26EA -U+26F2 -U+26F3 -U+26F5 -U+26FA -U+26FD -U+2934 -U+2935 -U+2B05 -U+2B06 -U+2B07 -U+2B1B -U+2B1C -U+2B50 -U+2B55 -U+3030 -U+303D -U+3297 -U+3299 -U+1F004 -U+1F0CF -U+1F300 -U+1F301 -U+1F302 -U+1F303 -U+1F304 -U+1F305 -U+1F306 -U+1F307 -U+1F308 -U+1F309 -U+1F30A -U+1F30B -U+1F30C -U+1F30F -U+1F311 -U+1F313 -U+1F314 -U+1F315 -U+1F319 -U+1F31B -U+1F31F -U+1F320 -U+1F330 -U+1F331 -U+1F334 -U+1F335 -U+1F337 -U+1F338 -U+1F339 -U+1F33A -U+1F33B -U+1F33C -U+1F33D -U+1F33E -U+1F33F -U+1F340 -U+1F341 -U+1F342 -U+1F343 -U+1F344 -U+1F345 -U+1F346 -U+1F347 -U+1F348 -U+1F349 -U+1F34A -U+1F34C -U+1F34D -U+1F34E -U+1F34F -U+1F351 -U+1F352 -U+1F353 -U+1F354 -U+1F355 -U+1F356 -U+1F357 -U+1F358 -U+1F359 -U+1F35A -U+1F35B -U+1F35C -U+1F35D -U+1F35E -U+1F35F -U+1F360 -U+1F361 -U+1F362 -U+1F363 -U+1F364 -U+1F365 -U+1F366 -U+1F367 -U+1F368 -U+1F369 -U+1F36A -U+1F36B -U+1F36C -U+1F36D -U+1F36E -U+1F36F -U+1F370 -U+1F371 -U+1F372 -U+1F373 -U+1F374 -U+1F375 -U+1F376 -U+1F377 -U+1F378 -U+1F379 -U+1F37A -U+1F37B -U+1F380 -U+1F381 -U+1F382 -U+1F383 -U+1F384 -U+1F385 -U+1F386 -U+1F387 -U+1F388 -U+1F389 -U+1F38A -U+1F38B -U+1F38C -U+1F38D -U+1F38E -U+1F38F -U+1F390 -U+1F391 -U+1F392 -U+1F393 -U+1F3A0 -U+1F3A1 -U+1F3A2 -U+1F3A3 -U+1F3A4 -U+1F3A5 -U+1F3A6 -U+1F3A7 -U+1F3A8 -U+1F3A9 -U+1F3AA -U+1F3AB -U+1F3AC -U+1F3AD -U+1F3AE -U+1F3AF -U+1F3B0 -U+1F3B1 -U+1F3B2 -U+1F3B3 -U+1F3B4 -U+1F3B5 -U+1F3B6 -U+1F3B7 -U+1F3B8 -U+1F3B9 -U+1F3BA -U+1F3BB -U+1F3BC -U+1F3BD -U+1F3BE -U+1F3BF -U+1F3C0 -U+1F3C1 -U+1F3C2 -U+1F3C3 -U+1F3C4 -U+1F3C6 -U+1F3C8 -U+1F3CA -U+1F3E0 -U+1F3E1 -U+1F3E2 -U+1F3E3 -U+1F3E5 -U+1F3E6 -U+1F3E7 -U+1F3E8 -U+1F3E9 -U+1F3EA -U+1F3EB -U+1F3EC -U+1F3ED -U+1F3EE -U+1F3EF -U+1F3F0 -U+1F40C -U+1F40D -U+1F40E -U+1F411 -U+1F412 -U+1F414 -U+1F417 -U+1F418 -U+1F419 -U+1F41A -U+1F41B -U+1F41C -U+1F41D -U+1F41E -U+1F41F -U+1F420 -U+1F421 -U+1F422 -U+1F423 -U+1F424 -U+1F425 -U+1F426 -U+1F427 -U+1F428 -U+1F429 -U+1F42B -U+1F42C -U+1F42D -U+1F42E -U+1F42F -U+1F430 -U+1F431 -U+1F432 -U+1F433 -U+1F434 -U+1F435 -U+1F436 -U+1F437 -U+1F438 -U+1F439 -U+1F43A -U+1F43B -U+1F43C -U+1F43D -U+1F43E -U+1F440 -U+1F442 -U+1F443 -U+1F444 -U+1F445 -U+1F446 -U+1F447 -U+1F448 -U+1F449 -U+1F44A -U+1F44B -U+1F44C -U+1F44D -U+1F44E -U+1F44F -U+1F450 -U+1F451 -U+1F452 -U+1F453 -U+1F454 -U+1F455 -U+1F456 -U+1F457 -U+1F458 -U+1F459 -U+1F45A -U+1F45B -U+1F45C -U+1F45D -U+1F45E -U+1F45F -U+1F460 -U+1F461 -U+1F462 -U+1F463 -U+1F464 -U+1F466 -U+1F467 -U+1F468 -U+1F469 -U+1F46A -U+1F46B -U+1F46E -U+1F46F -U+1F470 -U+1F471 -U+1F472 -U+1F473 -U+1F474 -U+1F475 -U+1F476 -U+1F477 -U+1F478 -U+1F479 -U+1F47A -U+1F47B -U+1F47C -U+1F47D -U+1F47E -U+1F47F -U+1F480 -U+1F481 -U+1F482 -U+1F483 -U+1F484 -U+1F485 -U+1F486 -U+1F487 -U+1F488 -U+1F489 -U+1F48A -U+1F48B -U+1F48C -U+1F48D -U+1F48E -U+1F48F -U+1F490 -U+1F491 -U+1F492 -U+1F493 -U+1F494 -U+1F495 -U+1F496 -U+1F497 -U+1F498 -U+1F499 -U+1F49A -U+1F49B -U+1F49C -U+1F49D -U+1F49E -U+1F49F -U+1F4A0 -U+1F4A1 -U+1F4A2 -U+1F4A3 -U+1F4A4 -U+1F4A5 -U+1F4A6 -U+1F4A7 -U+1F4A8 -U+1F4A9 -U+1F4AA -U+1F4AB -U+1F4AC -U+1F4AE -U+1F4AF -U+1F4B0 -U+1F4B1 -U+1F4B2 -U+1F4B3 -U+1F4B4 -U+1F4B5 -U+1F4B8 -U+1F4B9 -U+1F4BA -U+1F4BB -U+1F4BC -U+1F4BD -U+1F4BE -U+1F4BF -U+1F4C0 -U+1F4C1 -U+1F4C2 -U+1F4C3 -U+1F4C4 -U+1F4C5 -U+1F4C6 -U+1F4C7 -U+1F4C8 -U+1F4C9 -U+1F4CA -U+1F4CB -U+1F4CC -U+1F4CD -U+1F4CE -U+1F4CF -U+1F4D0 -U+1F4D1 -U+1F4D2 -U+1F4D3 -U+1F4D4 -U+1F4D5 -U+1F4D6 -U+1F4D7 -U+1F4D8 -U+1F4D9 -U+1F4DA -U+1F4DB -U+1F4DC -U+1F4DD -U+1F4DE -U+1F4DF -U+1F4E0 -U+1F4E1 -U+1F4E2 -U+1F4E3 -U+1F4E4 -U+1F4E5 -U+1F4E6 -U+1F4E7 -U+1F4E8 -U+1F4E9 -U+1F4EA -U+1F4EB -U+1F4EE -U+1F4F0 -U+1F4F1 -U+1F4F2 -U+1F4F3 -U+1F4F4 -U+1F4F6 -U+1F4F7 -U+1F4F9 -U+1F4FA -U+1F4FB -U+1F4FC -U+1F503 -U+1F50A -U+1F50B -U+1F50C -U+1F50D -U+1F50E -U+1F50F -U+1F510 -U+1F511 -U+1F512 -U+1F513 -U+1F514 -U+1F516 -U+1F517 -U+1F518 -U+1F519 -U+1F51A -U+1F51B -U+1F51C -U+1F51D -U+1F51E -U+1F51F -U+1F520 -U+1F521 -U+1F522 -U+1F523 -U+1F524 -U+1F525 -U+1F526 -U+1F527 -U+1F528 -U+1F529 -U+1F52A -U+1F52B -U+1F52E -U+1F52F -U+1F530 -U+1F531 -U+1F532 -U+1F533 -U+1F534 -U+1F535 -U+1F536 -U+1F537 -U+1F538 -U+1F539 -U+1F53A -U+1F53B -U+1F53C -U+1F53D -U+1F550 -U+1F551 -U+1F552 -U+1F553 -U+1F554 -U+1F555 -U+1F556 -U+1F557 -U+1F558 -U+1F559 -U+1F55A -U+1F55B -U+1F5FB -U+1F5FC -U+1F5FD -U+1F5FE -U+1F5FF -U+1F600 -U+1F607 -U+1F608 -U+1F60E -U+1F610 -U+1F611 -U+1F615 -U+1F617 -U+1F619 -U+1F61B -U+1F61F -U+1F626 -U+1F627 -U+1F62C -U+1F62E -U+1F62F -U+1F634 -U+1F636 -U+1F681 -U+1F682 -U+1F686 -U+1F688 -U+1F68A -U+1F68D -U+1F68E -U+1F690 -U+1F694 -U+1F696 -U+1F698 -U+1F69B -U+1F69C -U+1F69D -U+1F69E -U+1F69F -U+1F6A0 -U+1F6A1 -U+1F6A3 -U+1F6A6 -U+1F6AE -U+1F6AF -U+1F6B0 -U+1F6B1 -U+1F6B3 -U+1F6B4 -U+1F6B5 -U+1F6B7 -U+1F6B8 -U+1F6BF -U+1F6C1 -U+1F6C2 -U+1F6C3 -U+1F6C4 -U+1F6C5 -U+1F30D -U+1F30E -U+1F310 -U+1F312 -U+1F316 -U+1F317 -U+1F318 -U+1F31A -U+1F31C -U+1F31D -U+1F31E -U+1F332 -U+1F333 -U+1F34B -U+1F350 -U+1F37C -U+1F3C7 -U+1F3C9 -U+1F3E4 -U+1F400 -U+1F401 -U+1F402 -U+1F403 -U+1F404 -U+1F405 -U+1F406 -U+1F407 -U+1F408 -U+1F409 -U+1F40A -U+1F40B -U+1F40F -U+1F410 -U+1F413 -U+1F415 -U+1F416 -U+1F42A -U+1F465 -U+1F46C -U+1F46D -U+1F4AD -U+1F4B6 -U+1F4B7 -U+1F4EC -U+1F4ED -U+1F4EF -U+1F4F5 -U+1F500 -U+1F501 -U+1F502 -U+1F504 -U+1F505 -U+1F506 -U+1F507 -U+1F509 -U+1F515 -U+1F52C -U+1F52D -U+1F55C -U+1F55D -U+1F55E -U+1F55F -U+1F560 -U+1F561 -U+1F562 -U+1F563 -U+1F564 -U+1F565 -U+1F566 -U+1F567 -U+1F601 -U+1F602 -U+1F603 -U+1F604 -U+1F605 -U+1F606 -U+1F609 -U+1F60A -U+1F60B -U+1F60C -U+1F60D -U+1F60F -U+1F612 -U+1F613 -U+1F614 -U+1F616 -U+1F618 -U+1F61A -U+1F61C -U+1F61D -U+1F61E -U+1F620 -U+1F621 -U+1F622 -U+1F623 -U+1F624 -U+1F625 -U+1F628 -U+1F629 -U+1F62A -U+1F62B -U+1F62D -U+1F630 -U+1F631 -U+1F632 -U+1F633 -U+1F635 -U+1F637 -U+1F638 -U+1F639 -U+1F63A -U+1F63B -U+1F63C -U+1F63D -U+1F63E -U+1F63F -U+1F640 -U+1F645 -U+1F646 -U+1F647 -U+1F648 -U+1F649 -U+1F64A -U+1F64B -U+1F64C -U+1F64D -U+1F64E -U+1F64F -U+2702 -U+2705 -U+2708 -U+2709 -U+270A -U+270B -U+270C -U+270F -U+2712 -U+2714 -U+2716 -U+2728 -U+2733 -U+2734 -U+2744 -U+2747 -U+274C -U+274E -U+2753 -U+2754 -U+2755 -U+2757 -U+2764 -U+2795 -U+2796 -U+2797 -U+27A1 -U+27B0 -U+1F680 -U+1F683 -U+1F684 -U+1F685 -U+1F687 -U+1F689 -U+1F68C -U+1F68F -U+1F691 -U+1F692 -U+1F693 -U+1F695 -U+1F697 -U+1F699 -U+1F69A -U+1F6A2 -U+1F6A4 -U+1F6A5 -U+1F6A7 -U+1F6A8 -U+1F6A9 -U+1F6AA -U+1F6AB -U+1F6AC -U+1F6AD -U+1F6B2 -U+1F6B6 -U+1F6B9 -U+1F6BA -U+1F6BB -U+1F6BC -U+1F6BD -U+1F6BE -U+1F6C0 -U+24C2 -U+1F170 -U+1F171 -U+1F17E -U+1F17F -U+1F18E -U+1F191 -U+1F192 -U+1F193 -U+1F194 -U+1F195 -U+1F196 -U+1F197 -U+1F198 -U+1F199 -U+1F19A -U+1F1E9 U+1F1EA -U+1F1EC U+1F1E7 -U+1F1E8 U+1F1F3 -U+1F1EF U+1F1F5 -U+1F1EB U+1F1F7 -U+1F1F0 U+1F1F7 -U+1F1EA U+1F1F8 -U+1F1EE U+1F1F9 -U+1F1F7 U+1F1FA -U+1F1FA U+1F1F8 -U+1F201 -U+1F202 -U+1F21A -U+1F22F -U+1F232 -U+1F233 -U+1F234 -U+1F235 -U+1F236 -U+1F237 -U+1F238 -U+1F239 -U+1F23A -U+1F250 -U+1F251 -U+00A9 -U+00AE -U+203C -U+2049 -U+0023 U+20E3 -U+0038 U+20E3 -U+0039 U+20E3 -U+0037 U+20E3 -U+0030 U+20E3 -U+0036 U+20E3 -U+0035 U+20E3 -U+0034 U+20E3 -U+0033 U+20E3 -U+0032 U+20E3 -U+0031 U+20E3 -U+2122 -U+2139 -U+2194 -U+2195 -U+2196 -U+2197 -U+2198 -U+2199 -U+21A9 -U+21AA -U+231A -U+231B -U+23E9 -U+23EA -U+23EB -U+23EC -U+23F0 -U+23F3 -U+25AA -U+25AB -U+25B6 -U+25C0 -U+25FB -U+25FC -U+25FD -U+25FE -U+2600 -U+2601 -U+260E -U+2611 -U+2614 -U+2615 -U+261D -U+263A -U+2648 -U+2649 -U+264A -U+264B -U+264C -U+264D -U+264E -U+264F -U+2650 -U+2651 -U+2652 -U+2653 -U+2660 -U+2663 -U+2665 -U+2666 -U+2668 -U+267B -U+267F -U+2693 -U+26A0 -U+26A1 -U+26AA -U+26AB -U+26BD -U+26BE -U+26C4 -U+26C5 -U+26CE -U+26D4 -U+26EA -U+26F2 -U+26F3 -U+26F5 -U+26FA -U+26FD -U+2934 -U+2935 -U+2B05 -U+2B06 -U+2B07 -U+2B1B -U+2B1C -U+2B50 -U+2B55 -U+3030 -U+303D -U+3297 -U+3299 -U+1F004 -U+1F0CF -U+1F300 -U+1F301 -U+1F302 -U+1F303 -U+1F304 -U+1F305 -U+1F306 -U+1F307 -U+1F308 -U+1F309 -U+1F30A -U+1F30B -U+1F30C -U+1F30F -U+1F311 -U+1F313 -U+1F314 -U+1F315 -U+1F319 -U+1F31B -U+1F31F -U+1F320 -U+1F330 -U+1F331 -U+1F334 -U+1F335 -U+1F337 -U+1F338 -U+1F339 -U+1F33A -U+1F33B -U+1F33C -U+1F33D -U+1F33E -U+1F33F -U+1F340 -U+1F341 -U+1F342 -U+1F343 -U+1F344 -U+1F345 -U+1F346 -U+1F347 -U+1F348 -U+1F349 -U+1F34A -U+1F34C -U+1F34D -U+1F34E -U+1F34F -U+1F351 -U+1F352 -U+1F353 -U+1F354 -U+1F355 -U+1F356 -U+1F357 -U+1F358 -U+1F359 -U+1F35A -U+1F35B -U+1F35C -U+1F35D -U+1F35E -U+1F35F -U+1F360 -U+1F361 -U+1F362 -U+1F363 -U+1F364 -U+1F365 -U+1F366 -U+1F367 -U+1F368 -U+1F369 -U+1F36A -U+1F36B -U+1F36C -U+1F36D -U+1F36E -U+1F36F -U+1F370 -U+1F371 -U+1F372 -U+1F373 -U+1F374 -U+1F375 -U+1F376 -U+1F377 -U+1F378 -U+1F379 -U+1F37A -U+1F37B -U+1F380 -U+1F381 -U+1F382 -U+1F383 -U+1F384 -U+1F385 -U+1F386 -U+1F387 -U+1F388 -U+1F389 -U+1F38A -U+1F38B -U+1F38C -U+1F38D -U+1F38E -U+1F38F -U+1F390 -U+1F391 -U+1F392 -U+1F393 -U+1F3A0 -U+1F3A1 -U+1F3A2 -U+1F3A3 -U+1F3A4 -U+1F3A5 -U+1F3A6 -U+1F3A7 -U+1F3A8 -U+1F3A9 -U+1F3AA -U+1F3AB -U+1F3AC -U+1F3AD -U+1F3AE -U+1F3AF -U+1F3B0 -U+1F3B1 -U+1F3B2 -U+1F3B3 -U+1F3B4 -U+1F3B5 -U+1F3B6 -U+1F3B7 -U+1F3B8 -U+1F3B9 -U+1F3BA -U+1F3BB -U+1F3BC -U+1F3BD -U+1F3BE -U+1F3BF -U+1F3C0 -U+1F3C1 -U+1F3C2 -U+1F3C3 -U+1F3C4 -U+1F3C6 -U+1F3C8 -U+1F3CA -U+1F3E0 -U+1F3E1 -U+1F3E2 -U+1F3E3 -U+1F3E5 -U+1F3E6 -U+1F3E7 -U+1F3E8 -U+1F3E9 -U+1F3EA -U+1F3EB -U+1F3EC -U+1F3ED -U+1F3EE -U+1F3EF -U+1F3F0 -U+1F40C -U+1F40D -U+1F40E -U+1F411 -U+1F412 -U+1F414 -U+1F417 -U+1F418 -U+1F419 -U+1F41A -U+1F41B -U+1F41C -U+1F41D -U+1F41E -U+1F41F -U+1F420 -U+1F421 -U+1F422 -U+1F423 -U+1F424 -U+1F425 -U+1F426 -U+1F427 -U+1F428 -U+1F429 -U+1F42B -U+1F42C -U+1F42D -U+1F42E -U+1F42F -U+1F430 -U+1F431 -U+1F432 -U+1F433 -U+1F434 -U+1F435 -U+1F436 -U+1F437 -U+1F438 -U+1F439 -U+1F43A -U+1F43B -U+1F43C -U+1F43D -U+1F43E -U+1F440 -U+1F442 -U+1F443 -U+1F444 -U+1F445 -U+1F446 -U+1F447 -U+1F448 -U+1F449 -U+1F44A -U+1F44B -U+1F44C -U+1F44D -U+1F44E -U+1F44F -U+1F450 -U+1F451 -U+1F452 -U+1F453 -U+1F454 -U+1F455 -U+1F456 -U+1F457 -U+1F458 -U+1F459 -U+1F45A -U+1F45B -U+1F45C -U+1F45D -U+1F45E -U+1F45F -U+1F460 -U+1F461 -U+1F462 -U+1F463 -U+1F464 -U+1F466 -U+1F467 -U+1F468 -U+1F469 -U+1F46A -U+1F46B -U+1F46E -U+1F46F -U+1F470 -U+1F471 -U+1F472 -U+1F473 -U+1F474 -U+1F475 -U+1F476 -U+1F477 -U+1F478 -U+1F479 -U+1F47A -U+1F47B -U+1F47C -U+1F47D -U+1F47E -U+1F47F -U+1F480 -U+1F481 -U+1F482 -U+1F483 -U+1F484 -U+1F485 -U+1F486 -U+1F487 -U+1F488 -U+1F489 -U+1F48A -U+1F48B -U+1F48C -U+1F48D -U+1F48E -U+1F48F -U+1F490 -U+1F491 -U+1F492 -U+1F493 -U+1F494 -U+1F495 -U+1F496 -U+1F497 -U+1F498 -U+1F499 -U+1F49A -U+1F49B -U+1F49C -U+1F49D -U+1F49E -U+1F49F -U+1F4A0 -U+1F4A1 -U+1F4A2 -U+1F4A3 -U+1F4A4 -U+1F4A5 -U+1F4A6 -U+1F4A7 -U+1F4A8 -U+1F4A9 -U+1F4AA -U+1F4AB -U+1F4AC -U+1F4AE -U+1F4AF -U+1F4B0 -U+1F4B1 -U+1F4B2 -U+1F4B3 -U+1F4B4 -U+1F4B5 -U+1F4B8 -U+1F4B9 -U+1F4BA -U+1F4BB -U+1F4BC -U+1F4BD -U+1F4BE -U+1F4BF -U+1F4C0 -U+1F4C1 -U+1F4C2 -U+1F4C3 -U+1F4C4 -U+1F4C5 -U+1F4C6 -U+1F4C7 -U+1F4C8 -U+1F4C9 -U+1F4CA -U+1F4CB -U+1F4CC -U+1F4CD -U+1F4CE -U+1F4CF -U+1F4D0 -U+1F4D1 -U+1F4D2 -U+1F4D3 -U+1F4D4 -U+1F4D5 -U+1F4D6 -U+1F4D7 -U+1F4D8 -U+1F4D9 -U+1F4DA -U+1F4DB -U+1F4DC -U+1F4DD -U+1F4DE -U+1F4DF -U+1F4E0 -U+1F4E1 -U+1F4E2 -U+1F4E3 -U+1F4E4 -U+1F4E5 -U+1F4E6 -U+1F4E7 -U+1F4E8 -U+1F4E9 -U+1F4EA -U+1F4EB -U+1F4EE -U+1F4F0 -U+1F4F1 -U+1F4F2 -U+1F4F3 -U+1F4F4 -U+1F4F6 -U+1F4F7 -U+1F4F9 -U+1F4FA -U+1F4FB -U+1F4FC -U+1F503 -U+1F50A -U+1F50B -U+1F50C -U+1F50D -U+1F50E -U+1F50F -U+1F510 -U+1F511 -U+1F512 -U+1F513 -U+1F514 -U+1F516 -U+1F517 -U+1F518 -U+1F519 -U+1F51A -U+1F51B -U+1F51C -U+1F51D -U+1F51E -U+1F51F -U+1F520 -U+1F521 -U+1F522 -U+1F523 -U+1F524 -U+1F525 -U+1F526 -U+1F527 -U+1F528 -U+1F529 -U+1F52A -U+1F52B -U+1F52E -U+1F52F -U+1F530 -U+1F531 -U+1F532 -U+1F533 -U+1F534 -U+1F535 -U+1F536 -U+1F537 -U+1F538 -U+1F539 -U+1F53A -U+1F53B -U+1F53C -U+1F53D -U+1F550 -U+1F551 -U+1F552 -U+1F553 -U+1F554 -U+1F555 -U+1F556 -U+1F557 -U+1F558 -U+1F559 -U+1F55A -U+1F55B -U+1F5FB -U+1F5FC -U+1F5FD -U+1F5FE -U+1F5FF -U+1F600 -U+1F607 -U+1F608 -U+1F60E -U+1F610 -U+1F611 -U+1F615 -U+1F617 -U+1F619 -U+1F61B -U+1F61F -U+1F626 -U+1F627 -U+1F62C -U+1F62E -U+1F62F -U+1F634 -U+1F636 -U+1F681 -U+1F682 -U+1F686 -U+1F688 -U+1F68A -U+1F68D -U+1F68E -U+1F690 -U+1F694 -U+1F696 -U+1F698 -U+1F69B -U+1F69C -U+1F69D -U+1F69E -U+1F69F -U+1F6A0 -U+1F6A1 -U+1F6A3 -U+1F6A6 -U+1F6AE -U+1F6AF -U+1F6B0 -U+1F6B1 -U+1F6B3 -U+1F6B4 -U+1F6B5 -U+1F6B7 -U+1F6B8 -U+1F6BF -U+1F6C1 -U+1F6C2 -U+1F6C3 -U+1F6C4 -U+1F6C5 -U+1F30D -U+1F30E -U+1F310 -U+1F312 -U+1F316 -U+1F317 -U+1F318 -U+1F31A -U+1F31C -U+1F31D -U+1F31E -U+1F332 -U+1F333 -U+1F34B -U+1F350 -U+1F37C -U+1F3C7 -U+1F3C9 -U+1F3E4 -U+1F400 -U+1F401 -U+1F402 -U+1F403 -U+1F404 -U+1F405 -U+1F406 -U+1F407 -U+1F408 -U+1F409 -U+1F40A -U+1F40B -U+1F40F -U+1F410 -U+1F413 -U+1F415 -U+1F416 -U+1F42A -U+1F465 -U+1F46C -U+1F46D -U+1F4AD -U+1F4B6 -U+1F4B7 -U+1F4EC -U+1F4ED -U+1F4EF -U+1F4F5 -U+1F500 -U+1F501 -U+1F502 -U+1F504 -U+1F505 -U+1F506 -U+1F507 -U+1F509 -U+1F515 -U+1F52C -U+1F52D -U+1F55C -U+1F55D -U+1F55E -U+1F55F -U+1F560 -U+1F561 -U+1F562 -U+1F563 -U+1F564 -U+1F565 -U+1F566 -U+1F567 -U+1F601 -U+1F602 -U+1F603 -U+1F604 -U+1F605 -U+1F606 -U+1F609 -U+1F60A -U+1F60B -U+1F60C -U+1F60D -U+1F60F -U+1F612 -U+1F613 -U+1F614 -U+1F616 -U+1F618 -U+1F61A -U+1F61C -U+1F61D -U+1F61E -U+1F620 -U+1F621 -U+1F622 -U+1F623 -U+1F624 -U+1F625 -U+1F628 -U+1F629 -U+1F62A -U+1F62B -U+1F62D -U+1F630 -U+1F631 -U+1F632 -U+1F633 -U+1F635 -U+1F637 -U+1F638 -U+1F639 -U+1F63A -U+1F63B -U+1F63C -U+1F63D -U+1F63E -U+1F63F -U+1F640 -U+1F645 -U+1F646 -U+1F647 -U+1F648 -U+1F649 -U+1F64A -U+1F64B -U+1F64C -U+1F64D -U+1F64E -U+1F64F -U+2702 -U+2705 -U+2708 -U+2709 -U+270A -U+270B -U+270C -U+270F -U+2712 -U+2714 -U+2716 -U+2728 -U+2733 -U+2734 -U+2744 -U+2747 -U+274C -U+274E -U+2753 -U+2754 -U+2755 -U+2757 -U+2764 -U+2795 -U+2796 -U+2797 -U+27A1 -U+27B0 -U+1F680 -U+1F683 -U+1F684 -U+1F685 -U+1F687 -U+1F689 -U+1F68C -U+1F68F -U+1F691 -U+1F692 -U+1F693 -U+1F695 -U+1F697 -U+1F699 -U+1F69A -U+1F6A2 -U+1F6A4 -U+1F6A5 -U+1F6A7 -U+1F6A8 -U+1F6A9 -U+1F6AA -U+1F6AB -U+1F6AC -U+1F6AD -U+1F6B2 -U+1F6B6 -U+1F6B9 -U+1F6BA -U+1F6BB -U+1F6BC -U+1F6BD -U+1F6BE -U+1F6C0 -U+24C2 -U+1F170 -U+1F171 -U+1F17E -U+1F17F -U+1F18E -U+1F191 -U+1F192 -U+1F193 -U+1F194 -U+1F195 -U+1F196 -U+1F197 -U+1F198 -U+1F199 -U+1F19A -U+1F1E9 U+1F1EA -U+1F1EC U+1F1E7 -U+1F1E8 U+1F1F3 -U+1F1EF U+1F1F5 -U+1F1EB U+1F1F7 -U+1F1F0 U+1F1F7 -U+1F1EA U+1F1F8 -U+1F1EE U+1F1F9 -U+1F1F7 U+1F1FA -U+1F1FA U+1F1F8 -U+1F201 -U+1F202 -U+1F21A -U+1F22F -U+1F232 -U+1F233 -U+1F234 -U+1F235 -U+1F236 -U+1F237 -U+1F238 -U+1F239 -U+1F23A -U+1F250 -U+1F251 -U+00A9 -U+00AE -U+203C -U+2049 -U+0023 U+20E3 -U+0038 U+20E3 -U+0039 U+20E3 -U+0037 U+20E3 -U+0030 U+20E3 -U+0036 U+20E3 -U+0035 U+20E3 -U+0034 U+20E3 -U+0033 U+20E3 -U+0032 U+20E3 -U+0031 U+20E3 -U+2122 -U+2139 -U+2194 -U+2195 -U+2196 -U+2197 -U+2198 -U+2199 -U+21A9 -U+21AA -U+231A -U+231B -U+23E9 -U+23EA -U+23EB -U+23EC -U+23F0 -U+23F3 -U+25AA -U+25AB -U+25B6 -U+25C0 -U+25FB -U+25FC -U+25FD -U+25FE -U+2600 -U+2601 -U+260E -U+2611 -U+2614 -U+2615 -U+261D -U+263A -U+2648 -U+2649 -U+264A -U+264B -U+264C -U+264D -U+264E -U+264F -U+2650 -U+2651 -U+2652 -U+2653 -U+2660 -U+2663 -U+2665 -U+2666 -U+2668 -U+267B -U+267F -U+2693 -U+26A0 -U+26A1 -U+26AA -U+26AB -U+26BD -U+26BE -U+26C4 -U+26C5 -U+26CE -U+26D4 -U+26EA -U+26F2 -U+26F3 -U+26F5 -U+26FA -U+26FD -U+2934 -U+2935 -U+2B05 -U+2B06 -U+2B07 -U+2B1B -U+2B1C -U+2B50 -U+2B55 -U+3030 -U+303D -U+3297 -U+3299 -U+1F004 -U+1F0CF -U+1F300 -U+1F301 -U+1F302 -U+1F303 -U+1F304 -U+1F305 -U+1F306 -U+1F307 -U+1F308 -U+1F309 -U+1F30A -U+1F30B -U+1F30C -U+1F30F -U+1F311 -U+1F313 -U+1F314 -U+1F315 -U+1F319 -U+1F31B -U+1F31F -U+1F320 -U+1F330 -U+1F331 -U+1F334 -U+1F335 -U+1F337 -U+1F338 -U+1F339 -U+1F33A -U+1F33B -U+1F33C -U+1F33D -U+1F33E -U+1F33F -U+1F340 -U+1F341 -U+1F342 -U+1F343 -U+1F344 -U+1F345 -U+1F346 -U+1F347 -U+1F348 -U+1F349 -U+1F34A -U+1F34C -U+1F34D -U+1F34E -U+1F34F -U+1F351 -U+1F352 -U+1F353 -U+1F354 -U+1F355 -U+1F356 -U+1F357 -U+1F358 -U+1F359 -U+1F35A -U+1F35B -U+1F35C -U+1F35D -U+1F35E -U+1F35F -U+1F360 -U+1F361 -U+1F362 -U+1F363 -U+1F364 -U+1F365 -U+1F366 -U+1F367 -U+1F368 -U+1F369 -U+1F36A -U+1F36B -U+1F36C -U+1F36D -U+1F36E -U+1F36F -U+1F370 -U+1F371 -U+1F372 -U+1F373 -U+1F374 -U+1F375 -U+1F376 -U+1F377 -U+1F378 -U+1F379 -U+1F37A -U+1F37B -U+1F380 -U+1F381 -U+1F382 -U+1F383 -U+1F384 -U+1F385 -U+1F386 -U+1F387 -U+1F388 -U+1F389 -U+1F38A -U+1F38B -U+1F38C -U+1F38D -U+1F38E -U+1F38F -U+1F390 -U+1F391 -U+1F392 -U+1F393 -U+1F3A0 -U+1F3A1 -U+1F3A2 -U+1F3A3 -U+1F3A4 -U+1F3A5 -U+1F3A6 -U+1F3A7 -U+1F3A8 -U+1F3A9 -U+1F3AA -U+1F3AB -U+1F3AC -U+1F3AD -U+1F3AE -U+1F3AF -U+1F3B0 -U+1F3B1 -U+1F3B2 -U+1F3B3 -U+1F3B4 -U+1F3B5 -U+1F3B6 -U+1F3B7 -U+1F3B8 -U+1F3B9 -U+1F3BA -U+1F3BB -U+1F3BC -U+1F3BD -U+1F3BE -U+1F3BF -U+1F3C0 -U+1F3C1 -U+1F3C2 -U+1F3C3 -U+1F3C4 -U+1F3C6 -U+1F3C8 -U+1F3CA -U+1F3E0 -U+1F3E1 -U+1F3E2 -U+1F3E3 -U+1F3E5 -U+1F3E6 -U+1F3E7 -U+1F3E8 -U+1F3E9 -U+1F3EA -U+1F3EB -U+1F3EC -U+1F3ED -U+1F3EE -U+1F3EF -U+1F3F0 -U+1F40C -U+1F40D -U+1F40E -U+1F411 -U+1F412 -U+1F414 -U+1F417 -U+1F418 -U+1F419 -U+1F41A -U+1F41B -U+1F41C -U+1F41D -U+1F41E -U+1F41F -U+1F420 -U+1F421 -U+1F422 -U+1F423 -U+1F424 -U+1F425 -U+1F426 -U+1F427 -U+1F428 -U+1F429 -U+1F42B -U+1F42C -U+1F42D -U+1F42E -U+1F42F -U+1F430 -U+1F431 -U+1F432 -U+1F433 -U+1F434 -U+1F435 -U+1F436 -U+1F437 -U+1F438 -U+1F439 -U+1F43A -U+1F43B -U+1F43C -U+1F43D -U+1F43E -U+1F440 -U+1F442 -U+1F443 -U+1F444 -U+1F445 -U+1F446 -U+1F447 -U+1F448 -U+1F449 -U+1F44A -U+1F44B -U+1F44C -U+1F44D -U+1F44E -U+1F44F -U+1F450 -U+1F451 -U+1F452 -U+1F453 -U+1F454 -U+1F455 -U+1F456 -U+1F457 -U+1F458 -U+1F459 -U+1F45A -U+1F45B -U+1F45C -U+1F45D -U+1F45E -U+1F45F -U+1F460 -U+1F461 -U+1F462 -U+1F463 -U+1F464 -U+1F466 -U+1F467 -U+1F468 -U+1F469 -U+1F46A -U+1F46B -U+1F46E -U+1F46F -U+1F470 -U+1F471 -U+1F472 -U+1F473 -U+1F474 -U+1F475 -U+1F476 -U+1F477 -U+1F478 -U+1F479 -U+1F47A -U+1F47B -U+1F47C -U+1F47D -U+1F47E -U+1F47F -U+1F480 -U+1F481 -U+1F482 -U+1F483 -U+1F484 -U+1F485 -U+1F486 -U+1F487 -U+1F488 -U+1F489 -U+1F48A -U+1F48B -U+1F48C -U+1F48D -U+1F48E -U+1F48F -U+1F490 -U+1F491 -U+1F492 -U+1F493 -U+1F494 -U+1F495 -U+1F496 -U+1F497 -U+1F498 -U+1F499 -U+1F49A -U+1F49B -U+1F49C -U+1F49D -U+1F49E -U+1F49F -U+1F4A0 -U+1F4A1 -U+1F4A2 -U+1F4A3 -U+1F4A4 -U+1F4A5 -U+1F4A6 -U+1F4A7 -U+1F4A8 -U+1F4A9 -U+1F4AA -U+1F4AB -U+1F4AC -U+1F4AE -U+1F4AF -U+1F4B0 -U+1F4B1 -U+1F4B2 -U+1F4B3 -U+1F4B4 -U+1F4B5 -U+1F4B8 -U+1F4B9 -U+1F4BA -U+1F4BB -U+1F4BC -U+1F4BD -U+1F4BE -U+1F4BF -U+1F4C0 -U+1F4C1 -U+1F4C2 -U+1F4C3 -U+1F4C4 -U+1F4C5 -U+1F4C6 -U+1F4C7 -U+1F4C8 -U+1F4C9 -U+1F4CA -U+1F4CB -U+1F4CC -U+1F4CD -U+1F4CE -U+1F4CF -U+1F4D0 -U+1F4D1 -U+1F4D2 -U+1F4D3 -U+1F4D4 -U+1F4D5 -U+1F4D6 -U+1F4D7 -U+1F4D8 -U+1F4D9 -U+1F4DA -U+1F4DB -U+1F4DC -U+1F4DD -U+1F4DE -U+1F4DF -U+1F4E0 -U+1F4E1 -U+1F4E2 -U+1F4E3 -U+1F4E4 -U+1F4E5 -U+1F4E6 -U+1F4E7 -U+1F4E8 -U+1F4E9 -U+1F4EA -U+1F4EB -U+1F4EE -U+1F4F0 -U+1F4F1 -U+1F4F2 -U+1F4F3 -U+1F4F4 -U+1F4F6 -U+1F4F7 -U+1F4F9 -U+1F4FA -U+1F4FB -U+1F4FC -U+1F503 -U+1F50A -U+1F50B -U+1F50C -U+1F50D -U+1F50E -U+1F50F -U+1F510 -U+1F511 -U+1F512 -U+1F513 -U+1F514 -U+1F516 -U+1F517 -U+1F518 -U+1F519 -U+1F51A -U+1F51B -U+1F51C -U+1F51D -U+1F51E -U+1F51F -U+1F520 -U+1F521 -U+1F522 -U+1F523 -U+1F524 -U+1F525 -U+1F526 -U+1F527 -U+1F528 -U+1F529 -U+1F52A -U+1F52B -U+1F52E -U+1F52F -U+1F530 -U+1F531 -U+1F532 -U+1F533 -U+1F534 -U+1F535 -U+1F536 -U+1F537 -U+1F538 -U+1F539 -U+1F53A -U+1F53B -U+1F53C -U+1F53D -U+1F550 -U+1F551 -U+1F552 -U+1F553 -U+1F554 -U+1F555 -U+1F556 -U+1F557 -U+1F558 -U+1F559 -U+1F55A -U+1F55B -U+1F5FB -U+1F5FC -U+1F5FD -U+1F5FE -U+1F5FF -U+1F600 -U+1F607 -U+1F608 -U+1F60E -U+1F610 -U+1F611 -U+1F615 -U+1F617 -U+1F619 -U+1F61B -U+1F61F -U+1F626 -U+1F627 -U+1F62C -U+1F62E -U+1F62F -U+1F634 -U+1F636 -U+1F681 -U+1F682 -U+1F686 -U+1F688 -U+1F68A -U+1F68D -U+1F68E -U+1F690 -U+1F694 -U+1F696 -U+1F698 -U+1F69B -U+1F69C -U+1F69D -U+1F69E -U+1F69F -U+1F6A0 -U+1F6A1 -U+1F6A3 -U+1F6A6 -U+1F6AE -U+1F6AF -U+1F6B0 -U+1F6B1 -U+1F6B3 -U+1F6B4 -U+1F6B5 -U+1F6B7 -U+1F6B8 -U+1F6BF -U+1F6C1 -U+1F6C2 -U+1F6C3 -U+1F6C4 -U+1F6C5 -U+1F30D -U+1F30E -U+1F310 -U+1F312 -U+1F316 -U+1F317 -U+1F318 -U+1F31A -U+1F31C -U+1F31D -U+1F31E -U+1F332 -U+1F333 -U+1F34B -U+1F350 -U+1F37C -U+1F3C7 -U+1F3C9 -U+1F3E4 -U+1F400 -U+1F401 -U+1F402 -U+1F403 -U+1F404 -U+1F405 -U+1F406 -U+1F407 -U+1F408 -U+1F409 -U+1F40A -U+1F40B -U+1F40F -U+1F410 -U+1F413 -U+1F415 -U+1F416 -U+1F42A -U+1F465 -U+1F46C -U+1F46D -U+1F4AD -U+1F4B6 -U+1F4B7 -U+1F4EC -U+1F4ED -U+1F4EF -U+1F4F5 -U+1F500 -U+1F501 -U+1F502 -U+1F504 -U+1F505 -U+1F506 -U+1F507 -U+1F509 -U+1F515 -U+1F52C -U+1F52D -U+1F55C -U+1F55D -U+1F55E -U+1F55F -U+1F560 -U+1F561 -U+1F562 -U+1F563 -U+1F564 -U+1F565 -U+1F566 -U+1F567 -U+1F601 -U+1F602 -U+1F603 -U+1F604 -U+1F605 -U+1F606 -U+1F609 -U+1F60A -U+1F60B -U+1F60C -U+1F60D -U+1F60F -U+1F612 -U+1F613 -U+1F614 -U+1F616 -U+1F618 -U+1F61A -U+1F61C -U+1F61D -U+1F61E -U+1F620 -U+1F621 -U+1F622 -U+1F623 -U+1F624 -U+1F625 -U+1F628 -U+1F629 -U+1F62A -U+1F62B -U+1F62D -U+1F630 -U+1F631 -U+1F632 -U+1F633 -U+1F635 -U+1F637 -U+1F638 -U+1F639 -U+1F63A -U+1F63B -U+1F63C -U+1F63D -U+1F63E -U+1F63F -U+1F640 -U+1F645 -U+1F646 -U+1F647 -U+1F648 -U+1F649 -U+1F64A -U+1F64B -U+1F64C -U+1F64D -U+1F64E -U+1F64F -U+2702 -U+2705 -U+2708 -U+2709 -U+270A -U+270B -U+270C -U+270F -U+2712 -U+2714 -U+2716 -U+2728 -U+2733 -U+2734 -U+2744 -U+2747 -U+274C -U+274E -U+2753 -U+2754 -U+2755 -U+2757 -U+2764 -U+2795 -U+2796 -U+2797 -U+27A1 -U+27B0 -U+1F680 -U+1F683 -U+1F684 -U+1F685 -U+1F687 -U+1F689 -U+1F68C -U+1F68F -U+1F691 -U+1F692 -U+1F693 -U+1F695 -U+1F697 -U+1F699 -U+1F69A -U+1F6A2 -U+1F6A4 -U+1F6A5 -U+1F6A7 -U+1F6A8 -U+1F6A9 -U+1F6AA -U+1F6AB -U+1F6AC -U+1F6AD -U+1F6B2 -U+1F6B6 -U+1F6B9 -U+1F6BA -U+1F6BB -U+1F6BC -U+1F6BD -U+1F6BE -U+1F6C0 -U+24C2 -U+1F170 -U+1F171 -U+1F17E -U+1F17F -U+1F18E -U+1F191 -U+1F192 -U+1F193 -U+1F194 -U+1F195 -U+1F196 -U+1F197 -U+1F198 -U+1F199 -U+1F19A -U+1F1E9 U+1F1EA -U+1F1EC U+1F1E7 -U+1F1E8 U+1F1F3 -U+1F1EF U+1F1F5 -U+1F1EB U+1F1F7 -U+1F1F0 U+1F1F7 -U+1F1EA U+1F1F8 -U+1F1EE U+1F1F9 -U+1F1F7 U+1F1FA -U+1F1FA U+1F1F8 -U+1F201 -U+1F202 -U+1F21A -U+1F22F -U+1F232 -U+1F233 -U+1F234 -U+1F235 -U+1F236 -U+1F237 -U+1F238 -U+1F239 -U+1F23A -U+1F250 -U+1F251 -U+00A9 -U+00AE -U+203C -U+2049 -U+0023 U+20E3 -U+0038 U+20E3 -U+0039 U+20E3 -U+0037 U+20E3 -U+0030 U+20E3 -U+0036 U+20E3 -U+0035 U+20E3 -U+0034 U+20E3 -U+0033 U+20E3 -U+0032 U+20E3 -U+0031 U+20E3 -U+2122 -U+2139 -U+2194 -U+2195 -U+2196 -U+2197 -U+2198 -U+2199 -U+21A9 -U+21AA -U+231A -U+231B -U+23E9 -U+23EA -U+23EB -U+23EC -U+23F0 -U+23F3 -U+25AA -U+25AB -U+25B6 -U+25C0 -U+25FB -U+25FC -U+25FD -U+25FE -U+2600 -U+2601 -U+260E -U+2611 -U+2614 -U+2615 -U+261D -U+263A -U+2648 -U+2649 -U+264A -U+264B -U+264C -U+264D -U+264E -U+264F -U+2650 -U+2651 -U+2652 -U+2653 -U+2660 -U+2663 -U+2665 -U+2666 -U+2668 -U+267B -U+267F -U+2693 -U+26A0 -U+26A1 -U+26AA -U+26AB -U+26BD -U+26BE -U+26C4 -U+26C5 -U+26CE -U+26D4 -U+26EA -U+26F2 -U+26F3 -U+26F5 -U+26FA -U+26FD -U+2934 -U+2935 -U+2B05 -U+2B06 -U+2B07 -U+2B1B -U+2B1C -U+2B50 -U+2B55 -U+3030 -U+303D -U+3297 -U+3299 -U+1F004 -U+1F0CF -U+1F300 -U+1F301 -U+1F302 -U+1F303 -U+1F304 -U+1F305 -U+1F306 -U+1F307 -U+1F308 -U+1F309 -U+1F30A -U+1F30B -U+1F30C -U+1F30F -U+1F311 -U+1F313 -U+1F314 -U+1F315 -U+1F319 -U+1F31B -U+1F31F -U+1F320 -U+1F330 -U+1F331 -U+1F334 -U+1F335 -U+1F337 -U+1F338 -U+1F339 -U+1F33A -U+1F33B -U+1F33C -U+1F33D -U+1F33E -U+1F33F -U+1F340 -U+1F341 -U+1F342 -U+1F343 -U+1F344 -U+1F345 -U+1F346 -U+1F347 -U+1F348 -U+1F349 -U+1F34A -U+1F34C -U+1F34D -U+1F34E -U+1F34F -U+1F351 -U+1F352 -U+1F353 -U+1F354 -U+1F355 -U+1F356 -U+1F357 -U+1F358 -U+1F359 -U+1F35A -U+1F35B -U+1F35C -U+1F35D -U+1F35E -U+1F35F -U+1F360 -U+1F361 -U+1F362 -U+1F363 -U+1F364 -U+1F365 -U+1F366 -U+1F367 -U+1F368 -U+1F369 -U+1F36A -U+1F36B -U+1F36C -U+1F36D -U+1F36E -U+1F36F -U+1F370 -U+1F371 -U+1F372 -U+1F373 -U+1F374 -U+1F375 -U+1F376 -U+1F377 -U+1F378 -U+1F379 -U+1F37A -U+1F37B -U+1F380 -U+1F381 -U+1F382 -U+1F383 -U+1F384 -U+1F385 -U+1F386 -U+1F387 -U+1F388 -U+1F389 -U+1F38A -U+1F38B -U+1F38C -U+1F38D -U+1F38E -U+1F38F -U+1F390 -U+1F391 -U+1F392 -U+1F393 -U+1F3A0 -U+1F3A1 -U+1F3A2 -U+1F3A3 -U+1F3A4 -U+1F3A5 -U+1F3A6 -U+1F3A7 -U+1F3A8 -U+1F3A9 -U+1F3AA -U+1F3AB -U+1F3AC -U+1F3AD -U+1F3AE -U+1F3AF -U+1F3B0 -U+1F3B1 -U+1F3B2 -U+1F3B3 -U+1F3B4 -U+1F3B5 -U+1F3B6 -U+1F3B7 -U+1F3B8 -U+1F3B9 -U+1F3BA -U+1F3BB -U+1F3BC -U+1F3BD -U+1F3BE -U+1F3BF -U+1F3C0 -U+1F3C1 -U+1F3C2 -U+1F3C3 -U+1F3C4 -U+1F3C6 -U+1F3C8 -U+1F3CA -U+1F3E0 -U+1F3E1 -U+1F3E2 -U+1F3E3 -U+1F3E5 -U+1F3E6 -U+1F3E7 -U+1F3E8 -U+1F3E9 -U+1F3EA -U+1F3EB -U+1F3EC -U+1F3ED -U+1F3EE -U+1F3EF -U+1F3F0 -U+1F40C -U+1F40D -U+1F40E -U+1F411 -U+1F412 -U+1F414 -U+1F417 -U+1F418 -U+1F419 -U+1F41A -U+1F41B -U+1F41C -U+1F41D -U+1F41E -U+1F41F -U+1F420 -U+1F421 -U+1F422 -U+1F423 -U+1F424 -U+1F425 -U+1F426 -U+1F427 -U+1F428 -U+1F429 -U+1F42B -U+1F42C -U+1F42D -U+1F42E -U+1F42F -U+1F430 -U+1F431 -U+1F432 -U+1F433 -U+1F434 -U+1F435 -U+1F436 -U+1F437 -U+1F438 -U+1F439 -U+1F43A -U+1F43B -U+1F43C -U+1F43D -U+1F43E -U+1F440 -U+1F442 -U+1F443 -U+1F444 -U+1F445 -U+1F446 -U+1F447 -U+1F448 -U+1F449 -U+1F44A -U+1F44B -U+1F44C -U+1F44D -U+1F44E -U+1F44F -U+1F450 -U+1F451 -U+1F452 -U+1F453 -U+1F454 -U+1F455 -U+1F456 -U+1F457 -U+1F458 -U+1F459 -U+1F45A -U+1F45B -U+1F45C -U+1F45D -U+1F45E -U+1F45F -U+1F460 -U+1F461 -U+1F462 -U+1F463 -U+1F464 -U+1F466 -U+1F467 -U+1F468 -U+1F469 -U+1F46A -U+1F46B -U+1F46E -U+1F46F -U+1F470 -U+1F471 -U+1F472 -U+1F473 -U+1F474 -U+1F475 -U+1F476 -U+1F477 -U+1F478 -U+1F479 -U+1F47A -U+1F47B -U+1F47C -U+1F47D -U+1F47E -U+1F47F -U+1F480 -U+1F481 -U+1F482 -U+1F483 -U+1F484 -U+1F485 -U+1F486 -U+1F487 -U+1F488 -U+1F489 -U+1F48A -U+1F48B -U+1F48C -U+1F48D -U+1F48E -U+1F48F -U+1F490 -U+1F491 -U+1F492 -U+1F493 -U+1F494 -U+1F495 -U+1F496 -U+1F497 -U+1F498 -U+1F499 -U+1F49A -U+1F49B -U+1F49C -U+1F49D -U+1F49E -U+1F49F -U+1F4A0 -U+1F4A1 -U+1F4A2 -U+1F4A3 -U+1F4A4 -U+1F4A5 -U+1F4A6 -U+1F4A7 -U+1F4A8 -U+1F4A9 -U+1F4AA -U+1F4AB -U+1F4AC -U+1F4AE -U+1F4AF -U+1F4B0 -U+1F4B1 -U+1F4B2 -U+1F4B3 -U+1F4B4 -U+1F4B5 -U+1F4B8 -U+1F4B9 -U+1F4BA -U+1F4BB -U+1F4BC -U+1F4BD -U+1F4BE -U+1F4BF -U+1F4C0 -U+1F4C1 -U+1F4C2 -U+1F4C3 -U+1F4C4 -U+1F4C5 -U+1F4C6 -U+1F4C7 -U+1F4C8 -U+1F4C9 -U+1F4CA -U+1F4CB -U+1F4CC -U+1F4CD -U+1F4CE -U+1F4CF -U+1F4D0 -U+1F4D1 -U+1F4D2 -U+1F4D3 -U+1F4D4 -U+1F4D5 -U+1F4D6 -U+1F4D7 -U+1F4D8 -U+1F4D9 -U+1F4DA -U+1F4DB -U+1F4DC -U+1F4DD -U+1F4DE -U+1F4DF -U+1F4E0 -U+1F4E1 -U+1F4E2 -U+1F4E3 -U+1F4E4 -U+1F4E5 -U+1F4E6 -U+1F4E7 -U+1F4E8 -U+1F4E9 -U+1F4EA -U+1F4EB -U+1F4EE -U+1F4F0 -U+1F4F1 -U+1F4F2 -U+1F4F3 -U+1F4F4 -U+1F4F6 -U+1F4F7 -U+1F4F9 -U+1F4FA -U+1F4FB -U+1F4FC -U+1F503 -U+1F50A -U+1F50B -U+1F50C -U+1F50D -U+1F50E -U+1F50F -U+1F510 -U+1F511 -U+1F512 -U+1F513 -U+1F514 -U+1F516 -U+1F517 -U+1F518 -U+1F519 -U+1F51A -U+1F51B -U+1F51C -U+1F51D -U+1F51E -U+1F51F -U+1F520 -U+1F521 -U+1F522 -U+1F523 -U+1F524 -U+1F525 -U+1F526 -U+1F527 -U+1F528 -U+1F529 -U+1F52A -U+1F52B -U+1F52E -U+1F52F -U+1F530 -U+1F531 -U+1F532 -U+1F533 -U+1F534 -U+1F535 -U+1F536 -U+1F537 -U+1F538 -U+1F539 -U+1F53A -U+1F53B -U+1F53C -U+1F53D -U+1F550 -U+1F551 -U+1F552 -U+1F553 -U+1F554 -U+1F555 -U+1F556 -U+1F557 -U+1F558 -U+1F559 -U+1F55A -U+1F55B -U+1F5FB -U+1F5FC -U+1F5FD -U+1F5FE -U+1F5FF -U+1F600 -U+1F607 -U+1F608 -U+1F60E -U+1F610 -U+1F611 -U+1F615 -U+1F617 -U+1F619 -U+1F61B -U+1F61F -U+1F626 -U+1F627 -U+1F62C -U+1F62E -U+1F62F -U+1F634 -U+1F636 -U+1F681 -U+1F682 -U+1F686 -U+1F688 -U+1F68A -U+1F68D -U+1F68E -U+1F690 -U+1F694 -U+1F696 -U+1F698 -U+1F69B -U+1F69C -U+1F69D -U+1F69E -U+1F69F -U+1F6A0 -U+1F6A1 -U+1F6A3 -U+1F6A6 -U+1F6AE -U+1F6AF -U+1F6B0 -U+1F6B1 -U+1F6B3 -U+1F6B4 -U+1F6B5 -U+1F6B7 -U+1F6B8 -U+1F6BF -U+1F6C1 -U+1F6C2 -U+1F6C3 -U+1F6C4 -U+1F6C5 -U+1F30D -U+1F30E -U+1F310 -U+1F312 -U+1F316 -U+1F317 -U+1F318 -U+1F31A -U+1F31C -U+1F31D -U+1F31E -U+1F332 -U+1F333 -U+1F34B -U+1F350 -U+1F37C -U+1F3C7 -U+1F3C9 -U+1F3E4 -U+1F400 -U+1F401 -U+1F402 -U+1F403 -U+1F404 -U+1F405 -U+1F406 -U+1F407 -U+1F408 -U+1F409 -U+1F40A -U+1F40B -U+1F40F -U+1F410 -U+1F413 -U+1F415 -U+1F416 -U+1F42A -U+1F465 -U+1F46C -U+1F46D -U+1F4AD -U+1F4B6 -U+1F4B7 -U+1F4EC -U+1F4ED -U+1F4EF -U+1F4F5 -U+1F500 -U+1F501 -U+1F502 -U+1F504 -U+1F505 -U+1F506 -U+1F507 -U+1F509 -U+1F515 -U+1F52C -U+1F52D -U+1F55C -U+1F55D -U+1F55E -U+1F55F -U+1F560 -U+1F561 -U+1F562 -U+1F563 -U+1F564 -U+1F565 -U+1F566 -U+1F567 -U+1F601 -U+1F602 -U+1F603 -U+1F604 -U+1F605 -U+1F606 -U+1F609 -U+1F60A -U+1F60B -U+1F60C -U+1F60D -U+1F60F -U+1F612 -U+1F613 -U+1F614 -U+1F616 -U+1F618 -U+1F61A -U+1F61C -U+1F61D -U+1F61E -U+1F620 -U+1F621 -U+1F622 -U+1F623 -U+1F624 -U+1F625 -U+1F628 -U+1F629 -U+1F62A -U+1F62B -U+1F62D -U+1F630 -U+1F631 -U+1F632 -U+1F633 -U+1F635 -U+1F637 -U+1F638 -U+1F639 -U+1F63A -U+1F63B -U+1F63C -U+1F63D -U+1F63E -U+1F63F -U+1F640 -U+1F645 -U+1F646 -U+1F647 -U+1F648 -U+1F649 -U+1F64A -U+1F64B -U+1F64C -U+1F64D -U+1F64E -U+1F64F -U+2702 -U+2705 -U+2708 -U+2709 -U+270A -U+270B -U+270C -U+270F -U+2712 -U+2714 -U+2716 -U+2728 -U+2733 -U+2734 -U+2744 -U+2747 -U+274C -U+274E -U+2753 -U+2754 -U+2755 -U+2757 -U+2764 -U+2795 -U+2796 -U+2797 -U+27A1 -U+27B0 -U+1F680 -U+1F683 -U+1F684 -U+1F685 -U+1F687 -U+1F689 -U+1F68C -U+1F68F -U+1F691 -U+1F692 -U+1F693 -U+1F695 -U+1F697 -U+1F699 -U+1F69A -U+1F6A2 -U+1F6A4 -U+1F6A5 -U+1F6A7 -U+1F6A8 -U+1F6A9 -U+1F6AA -U+1F6AB -U+1F6AC -U+1F6AD -U+1F6B2 -U+1F6B6 -U+1F6B9 -U+1F6BA -U+1F6BB -U+1F6BC -U+1F6BD -U+1F6BE -U+1F6C0 -U+24C2 -U+1F170 -U+1F171 -U+1F17E -U+1F17F -U+1F18E -U+1F191 -U+1F192 -U+1F193 -U+1F194 -U+1F195 -U+1F196 -U+1F197 -U+1F198 -U+1F199 -U+1F19A -U+1F1E9 U+1F1EA -U+1F1EC U+1F1E7 -U+1F1E8 U+1F1F3 -U+1F1EF U+1F1F5 -U+1F1EB U+1F1F7 -U+1F1F0 U+1F1F7 -U+1F1EA U+1F1F8 -U+1F1EE U+1F1F9 -U+1F1F7 U+1F1FA -U+1F1FA U+1F1F8 -U+1F201 -U+1F202 -U+1F21A -U+1F22F -U+1F232 -U+1F233 -U+1F234 -U+1F235 -U+1F236 -U+1F237 -U+1F238 -U+1F239 -U+1F23A -U+1F250 -U+1F251 -U+00A9 -U+00AE -U+203C -U+2049 -U+0023 U+20E3 -U+0038 U+20E3 -U+0039 U+20E3 -U+0037 U+20E3 -U+0030 U+20E3 -U+0036 U+20E3 -U+0035 U+20E3 -U+0034 U+20E3 -U+0033 U+20E3 -U+0032 U+20E3 -U+0031 U+20E3 -U+2122 -U+2139 -U+2194 -U+2195 -U+2196 -U+2197 -U+2198 -U+2199 -U+21A9 -U+21AA -U+231A -U+231B -U+23E9 -U+23EA -U+23EB -U+23EC -U+23F0 -U+23F3 -U+25AA -U+25AB -U+25B6 -U+25C0 -U+25FB -U+25FC -U+25FD -U+25FE -U+2600 -U+2601 -U+260E -U+2611 -U+2614 -U+2615 -U+261D -U+263A -U+2648 -U+2649 -U+264A -U+264B -U+264C -U+264D -U+264E -U+264F -U+2650 -U+2651 -U+2652 -U+2653 -U+2660 -U+2663 -U+2665 -U+2666 -U+2668 -U+267B -U+267F -U+2693 -U+26A0 -U+26A1 -U+26AA -U+26AB -U+26BD -U+26BE -U+26C4 -U+26C5 -U+26CE -U+26D4 -U+26EA -U+26F2 -U+26F3 -U+26F5 -U+26FA -U+26FD -U+2934 -U+2935 -U+2B05 -U+2B06 -U+2B07 -U+2B1B -U+2B1C -U+2B50 -U+2B55 -U+3030 -U+303D -U+3297 -U+3299 -U+1F004 -U+1F0CF -U+1F300 -U+1F301 -U+1F302 -U+1F303 -U+1F304 -U+1F305 -U+1F306 -U+1F307 -U+1F308 -U+1F309 -U+1F30A -U+1F30B -U+1F30C -U+1F30F -U+1F311 -U+1F313 -U+1F314 -U+1F315 -U+1F319 -U+1F31B -U+1F31F -U+1F320 -U+1F330 -U+1F331 -U+1F334 -U+1F335 -U+1F337 -U+1F338 -U+1F339 -U+1F33A -U+1F33B -U+1F33C -U+1F33D -U+1F33E -U+1F33F -U+1F340 -U+1F341 -U+1F342 -U+1F343 -U+1F344 -U+1F345 -U+1F346 -U+1F347 -U+1F348 -U+1F349 -U+1F34A -U+1F34C -U+1F34D -U+1F34E -U+1F34F -U+1F351 -U+1F352 -U+1F353 -U+1F354 -U+1F355 -U+1F356 -U+1F357 -U+1F358 -U+1F359 -U+1F35A -U+1F35B -U+1F35C -U+1F35D -U+1F35E -U+1F35F -U+1F360 -U+1F361 -U+1F362 -U+1F363 -U+1F364 -U+1F365 -U+1F366 -U+1F367 -U+1F368 -U+1F369 -U+1F36A -U+1F36B -U+1F36C -U+1F36D -U+1F36E -U+1F36F -U+1F370 -U+1F371 -U+1F372 -U+1F373 -U+1F374 -U+1F375 -U+1F376 -U+1F377 -U+1F378 -U+1F379 -U+1F37A -U+1F37B -U+1F380 -U+1F381 -U+1F382 -U+1F383 -U+1F384 -U+1F385 -U+1F386 -U+1F387 -U+1F388 -U+1F389 -U+1F38A -U+1F38B -U+1F38C -U+1F38D -U+1F38E -U+1F38F -U+1F390 -U+1F391 -U+1F392 -U+1F393 -U+1F3A0 -U+1F3A1 -U+1F3A2 -U+1F3A3 -U+1F3A4 -U+1F3A5 -U+1F3A6 -U+1F3A7 -U+1F3A8 -U+1F3A9 -U+1F3AA -U+1F3AB -U+1F3AC -U+1F3AD -U+1F3AE -U+1F3AF -U+1F3B0 -U+1F3B1 -U+1F3B2 -U+1F3B3 -U+1F3B4 -U+1F3B5 -U+1F3B6 -U+1F3B7 -U+1F3B8 -U+1F3B9 -U+1F3BA -U+1F3BB -U+1F3BC -U+1F3BD -U+1F3BE -U+1F3BF -U+1F3C0 -U+1F3C1 -U+1F3C2 -U+1F3C3 -U+1F3C4 -U+1F3C6 -U+1F3C8 -U+1F3CA -U+1F3E0 -U+1F3E1 -U+1F3E2 -U+1F3E3 -U+1F3E5 -U+1F3E6 -U+1F3E7 -U+1F3E8 -U+1F3E9 -U+1F3EA -U+1F3EB -U+1F3EC -U+1F3ED -U+1F3EE -U+1F3EF -U+1F3F0 -U+1F40C -U+1F40D -U+1F40E -U+1F411 -U+1F412 -U+1F414 -U+1F417 -U+1F418 -U+1F419 -U+1F41A -U+1F41B -U+1F41C -U+1F41D -U+1F41E -U+1F41F -U+1F420 -U+1F421 -U+1F422 -U+1F423 -U+1F424 -U+1F425 -U+1F426 -U+1F427 -U+1F428 -U+1F429 -U+1F42B -U+1F42C -U+1F42D -U+1F42E -U+1F42F -U+1F430 -U+1F431 -U+1F432 -U+1F433 -U+1F434 -U+1F435 -U+1F436 -U+1F437 -U+1F438 -U+1F439 -U+1F43A -U+1F43B -U+1F43C -U+1F43D -U+1F43E -U+1F440 -U+1F442 -U+1F443 -U+1F444 -U+1F445 -U+1F446 -U+1F447 -U+1F448 -U+1F449 -U+1F44A -U+1F44B -U+1F44C -U+1F44D -U+1F44E -U+1F44F -U+1F450 -U+1F451 -U+1F452 -U+1F453 -U+1F454 -U+1F455 -U+1F456 -U+1F457 -U+1F458 -U+1F459 -U+1F45A -U+1F45B -U+1F45C -U+1F45D -U+1F45E -U+1F45F -U+1F460 -U+1F461 -U+1F462 -U+1F463 -U+1F464 -U+1F466 -U+1F467 -U+1F468 -U+1F469 -U+1F46A -U+1F46B -U+1F46E -U+1F46F -U+1F470 -U+1F471 -U+1F472 -U+1F473 -U+1F474 -U+1F475 -U+1F476 -U+1F477 -U+1F478 -U+1F479 -U+1F47A -U+1F47B -U+1F47C -U+1F47D -U+1F47E -U+1F47F -U+1F480 -U+1F481 -U+1F482 -U+1F483 -U+1F484 -U+1F485 -U+1F486 -U+1F487 -U+1F488 -U+1F489 -U+1F48A -U+1F48B -U+1F48C -U+1F48D -U+1F48E -U+1F48F -U+1F490 -U+1F491 -U+1F492 -U+1F493 -U+1F494 -U+1F495 -U+1F496 -U+1F497 -U+1F498 -U+1F499 -U+1F49A -U+1F49B -U+1F49C -U+1F49D -U+1F49E -U+1F49F -U+1F4A0 -U+1F4A1 -U+1F4A2 -U+1F4A3 -U+1F4A4 -U+1F4A5 -U+1F4A6 -U+1F4A7 -U+1F4A8 -U+1F4A9 -U+1F4AA -U+1F4AB -U+1F4AC -U+1F4AE -U+1F4AF -U+1F4B0 -U+1F4B1 -U+1F4B2 -U+1F4B3 -U+1F4B4 -U+1F4B5 -U+1F4B8 -U+1F4B9 -U+1F4BA -U+1F4BB -U+1F4BC -U+1F4BD -U+1F4BE -U+1F4BF -U+1F4C0 -U+1F4C1 -U+1F4C2 -U+1F4C3 -U+1F4C4 -U+1F4C5 -U+1F4C6 -U+1F4C7 -U+1F4C8 -U+1F4C9 -U+1F4CA -U+1F4CB -U+1F4CC -U+1F4CD -U+1F4CE -U+1F4CF -U+1F4D0 -U+1F4D1 -U+1F4D2 -U+1F4D3 -U+1F4D4 -U+1F4D5 -U+1F4D6 -U+1F4D7 -U+1F4D8 -U+1F4D9 -U+1F4DA -U+1F4DB -U+1F4DC -U+1F4DD -U+1F4DE -U+1F4DF -U+1F4E0 -U+1F4E1 -U+1F4E2 -U+1F4E3 -U+1F4E4 -U+1F4E5 -U+1F4E6 -U+1F4E7 -U+1F4E8 -U+1F4E9 -U+1F4EA -U+1F4EB -U+1F4EE -U+1F4F0 -U+1F4F1 -U+1F4F2 -U+1F4F3 -U+1F4F4 -U+1F4F6 -U+1F4F7 -U+1F4F9 -U+1F4FA -U+1F4FB -U+1F4FC -U+1F503 -U+1F50A -U+1F50B -U+1F50C -U+1F50D -U+1F50E -U+1F50F -U+1F510 -U+1F511 -U+1F512 -U+1F513 -U+1F514 -U+1F516 -U+1F517 -U+1F518 -U+1F519 -U+1F51A -U+1F51B -U+1F51C -U+1F51D -U+1F51E -U+1F51F -U+1F520 -U+1F521 -U+1F522 -U+1F523 -U+1F524 -U+1F525 -U+1F526 -U+1F527 -U+1F528 -U+1F529 -U+1F52A -U+1F52B -U+1F52E -U+1F52F -U+1F530 -U+1F531 -U+1F532 -U+1F533 -U+1F534 -U+1F535 -U+1F536 -U+1F537 -U+1F538 -U+1F539 -U+1F53A -U+1F53B -U+1F53C -U+1F53D -U+1F550 -U+1F551 -U+1F552 -U+1F553 -U+1F554 -U+1F555 -U+1F556 -U+1F557 -U+1F558 -U+1F559 -U+1F55A -U+1F55B -U+1F5FB -U+1F5FC -U+1F5FD -U+1F5FE -U+1F5FF -U+1F600 -U+1F607 -U+1F608 -U+1F60E -U+1F610 -U+1F611 -U+1F615 -U+1F617 -U+1F619 -U+1F61B -U+1F61F -U+1F626 -U+1F627 -U+1F62C -U+1F62E -U+1F62F -U+1F634 -U+1F636 -U+1F681 -U+1F682 -U+1F686 -U+1F688 -U+1F68A -U+1F68D -U+1F68E -U+1F690 -U+1F694 -U+1F696 -U+1F698 -U+1F69B -U+1F69C -U+1F69D -U+1F69E -U+1F69F -U+1F6A0 -U+1F6A1 -U+1F6A3 -U+1F6A6 -U+1F6AE -U+1F6AF -U+1F6B0 -U+1F6B1 -U+1F6B3 -U+1F6B4 -U+1F6B5 -U+1F6B7 -U+1F6B8 -U+1F6BF -U+1F6C1 -U+1F6C2 -U+1F6C3 -U+1F6C4 -U+1F6C5 -U+1F30D -U+1F30E -U+1F310 -U+1F312 -U+1F316 -U+1F317 -U+1F318 -U+1F31A -U+1F31C -U+1F31D -U+1F31E -U+1F332 -U+1F333 -U+1F34B -U+1F350 -U+1F37C -U+1F3C7 -U+1F3C9 -U+1F3E4 -U+1F400 -U+1F401 -U+1F402 -U+1F403 -U+1F404 -U+1F405 -U+1F406 -U+1F407 -U+1F408 -U+1F409 -U+1F40A -U+1F40B -U+1F40F -U+1F410 -U+1F413 -U+1F415 -U+1F416 -U+1F42A -U+1F465 -U+1F46C -U+1F46D -U+1F4AD -U+1F4B6 -U+1F4B7 -U+1F4EC -U+1F4ED -U+1F4EF -U+1F4F5 -U+1F500 -U+1F501 -U+1F502 -U+1F504 -U+1F505 -U+1F506 -U+1F507 -U+1F509 -U+1F515 -U+1F52C -U+1F52D -U+1F55C -U+1F55D -U+1F55E -U+1F55F -U+1F560 -U+1F561 -U+1F562 -U+1F563 -U+1F564 -U+1F565 -U+1F566 -U+1F567 diff --git a/mirzaev/arming_bot/system/models/account.php b/mirzaev/arming_bot/system/models/account.php new file mode 100755 index 0000000..f83fc6e --- /dev/null +++ b/mirzaev/arming_bot/system/models/account.php @@ -0,0 +1,124 @@ + + */ +final class account extends core implements arangodb_document_interface +{ + use status, arangodb_document_trait; + + /** + * Name of the collection in ArangoDB + */ + final public const string COLLECTION = 'account'; + + /** + * Инициализация + * + * @param int $id Идентификатор Telegram + * @param telegram|array|null $registration Данные для регистрация, если аккаунт не найден + * @param array &$errors Registry of errors + * + * @return static|null Объект аккаунта, если найден + */ + public static function initialization(int $id, telegram|array|null $registration = null, array &$errors = []): static|null + { + try { + if (collection::init(core::$arangodb->session, self::COLLECTION)) { + if ($document = collection::search(core::$arangodb->session, sprintf("FOR d IN %s FILTER d.id == %u RETURN d", self::COLLECTION, $id))) { + // Найден аккаунт + + // Инициализация объекта аккаунта + $account = new static; + + // Запись инстанции документа в объект + $account->document = $document; + + // Возврат (успех) + return $account; + } else if ($registration) { + // Не найден аккаунт и запрошена его регистрация + + // Создание аккаунта + document::write( + core::$arangodb->session, + self::COLLECTION, + (is_array($registration) + ? $registration : + [ + 'id' => $registration->getId(), + 'name' => [ + 'first' => $registration->getFirstName(), + 'last' => $registration->getLastName() + ], + 'domain' => $registration->getUsername(), + 'robot' => $registration->isBot(), + 'banned' => false, + 'tester' => false, + 'developer' => false, + 'access' => [ + 'settings' => false + ], + 'menus' => [ + 'attachments' => $registration->getAddedToAttachmentMenu() + ], + 'messages' => true, + 'groups' => [ + 'join' => $registration->getCanJoinGroups(), + 'messages' => $registration->getCanReadAllGroupMessages() + ], + 'premium' => $registration->isPremium(), + 'language' => $registration->getLanguageCode(), + 'queries' => [ + 'inline' => $registration->getSupportsInlineQueries() + ] + ]) + [ + 'version' => ROBOT_VERSION, + 'active' => true + ] + ); + + // Инициализация (без регистрации) + return static::initialization($id, errors: $errors); + } else throw new exception('Account not found'); + } else throw new exception('Failed to initialize document collection: ' . self::COLLECTION); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return null; + } +} diff --git a/mirzaev/arming_bot/system/models/categories.php b/mirzaev/arming_bot/system/models/categories.php new file mode 100755 index 0000000..ce3a973 --- /dev/null +++ b/mirzaev/arming_bot/system/models/categories.php @@ -0,0 +1,294 @@ + + */ +class categories extends core implements arangodb_document_interface +{ + use arangodb_document_trait; + + /** + * Name of the collection in ArangoDB + */ + public const string COLLECTION = 'THIS_COLLECTION_SHOULD_NOT_EXIST'; + + /** + * Запись категории + * + * @param string $name Название + * @param arrau $labels Ярлыки для отображения в интерфейсе ['EN' => "Label"] + * @param array $hierarchy Иерархия вложенности (от родителей к потомкам: [ model, model ... ]) + * @param array &$errors Registry of errors + * + * @return string|null Идентификатор (_id) документа, если создан + */ + public static function write( + string $name, + array $labels = ['RU' => 'Без названия'], + array $hierarchy = [], + array &$errors = [] + ): string|null { + try { + if (collection::init(core::$arangodb->session, static::COLLECTION)) { + // Инициализирована коллекция + + // Создание категории + $category = document::write( + core::$arangodb->session, + static::COLLECTION, + [ + 'name' => $name, + 'labels' => $labels, + 'version' => ROBOT_VERSION + ] + ); + + if ($category) { + // Создана категория + + /* if (collection::init(core::$arangodb->session, 'entry', true)) { + // Инициализирована коллекция + + foreach ($hierarchy as $model) { + // Перебор иерархической структуры категорий + + // Инициализация вложенной категории (следующей в массиве) + $next = current($hierarchy); + + // Поиск ребра описывающего иерархическую связь + + document::write(core::$arangodb->session, 'entry'); + } + } else throw new exception('Failed to initialize document collection: ' . static::COLLECTION); */ + } + } else throw new exception('Failed to initialize edge collection: entry'); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return null; + } + + /** + * Поиск вхождений (подкатегории или товары) + * + * Находит вхождения через ребро entry + * Генерирует _type со значениями "category" и "product" + * относительно того есть ли у документа ещё вложения (у product вложений быть не может) + * Объединяет возвращаемые объекты документа с переменной _type + * + * @param string|null $category Category identifier (_id) + * @param string|null $filter Expression for filtering (AQL) + * @param string|null $sort Expression for sorting (AQL) + * @param int $page Страница + * @param int $amount Количество товаров на странице + * @param array &$errors Registry of errors + * + * @return array Массив с найденными вхождениями (может быть пустым) + */ + public static function entries( + ?string $category = null, + ?string $filter = null, + ?string $sort = 'v.promotion DESC, v.position ASC, v.created DESC', + int $page = 1, + int $amount = 100, + array &$errors = [] + ): array { + try { + if (collection::init(core::$arangodb->session, static::COLLECTION)) { + // Инициализирована коллекция + + if ($documents = collection::search( + core::$arangodb->session, + sprintf( + << $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return []; + } + + /** + * Поиск категорий и товаров + * + * Ищет категории и товары по коллекции рёбер entry из _from и _to + * + * @param array &$errors Registry of errors + * + * @return array Массив с уникализированными найденными коллекциями (может быть пустым) + */ + protected static function collections( + array &$errors = [] + ): array { + try { + if (collection::init(core::$arangodb->session, $collection = 'entry')) { + // Инициализирована коллекция + + if ($names = collection::search( + core::$arangodb->session, + sprintf( + <<getAll(); + } else return []; + } else throw new exception('Failed to initialize edge collection: entry'); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return []; + } + + /** + * Поиск категории по названияю + * + * Перебирает все коллекции из self::collections() и ищет в них соответствие с параметром name + * ВНИМАНИЕ: НЕЛЬЗЯ ДОПУСКАТЬ ОДИНАКОВЫЕ НАЗВАНИЯ СРЕДИ РАЗНЫХ КАТЕГОРИЙ + * + * @param string $name Name of a collection + * @param array &$errors Registry of errors + * + * @return categories|null Модель имплементирующая документ с категорией, если была найдена + */ + public static function category( + string $name, + array &$errors = [] + ): ?categories { + try { + // Инициалиация списка коллекций + $collections = self::collections($errors); + + if (count($collections) > 0) { + // Найдены коллекции + + // Инициализация буфера части запроса со списком коллекций для аргументов UNION() + $union = []; + foreach ($collections as $collection) $union[] = "FOR d IN $collection RETURN d"; + unset($collection); + + if ($document = collection::search( + core::$arangodb->session, + sprintf( + <<getId())[0]; + + if (class_exists($model = "mirzaev\\arming_bot\\models\\$collection")) { + // Найдена модель имплементирующая документы из этой коллекции + + // Инициализация объекта модели + $object = new $model; + + if ($object instanceof categories) { + // Объект является инстанцией категории (то есть не товара) + + // Запись инстанции документа в объект модели + $object->document = $document; + + // Возврат (успех) + return $object; + } + } + } else return null; + } + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return null; + } +} diff --git a/mirzaev/arming_bot/system/models/category.php b/mirzaev/arming_bot/system/models/category.php new file mode 100755 index 0000000..cc7b4b0 --- /dev/null +++ b/mirzaev/arming_bot/system/models/category.php @@ -0,0 +1,22 @@ + + */ +final class category extends categories +{ + /** + * Name of the collection in ArangoDB + */ + final public const string COLLECTION = 'category'; +} diff --git a/mirzaev/arming_bot/system/models/chat.php b/mirzaev/arming_bot/system/models/chat.php new file mode 100755 index 0000000..05e682a --- /dev/null +++ b/mirzaev/arming_bot/system/models/chat.php @@ -0,0 +1,602 @@ + + */ +final class chat extends core +{ + /** + * Экранирование символов для Markdown + * + * @param string $text Текст для экранирования + * @param array $exception Символы которые будут исключены из списка для экранирования + * + * @return string Экранированный текст + */ + public static function unmarkdown(string $text, array $exceptions = []): string + { + // Инициализация реестра символом для конвертации + $from = array_diff( + [ + '#', + '*', + '_', + '=', + '.', + '[', + ']', + '(', + ')', + '-', + '>', + '<', + '!', + '`' + ], + $exceptions + ); + + // Инициализация реестра целей для конвертации + $to = []; + foreach ($from as $symbol) $to[] = "\\$symbol"; + + // Конвертация и выход (успех) + return str_replace($from, $to, $text); + } + + /** + * Инициализация запчасти + * + * Проверяет существование запчасти + * + * @param string $spare Запчасть + * + * @return string|bool Запчасть, если найдена, иначе false + */ + public static function spares(string $spare): string|bool + { + // Поиск запчастей и выход (успех) + return match (mb_strtolower($spare)) { + 'цевьё' => 'Цевьё', + default => false + }; + } + + /** + * Главное меню + * + * Команда: /start + * + * @param Context $ctx + * + * @return void + */ + public static function menu(Context $ctx): void + { + // Инициализация клавиатуры + $keyboard = [ + [ + ['text' => '🛒 Каталог', 'web_app' => ['url' => 'https://arming.dev.mirzaev.sexy']] + ], + [ + ['text' => '🏛️ О компании'], + ['text' => '💬 Контакты'] + ], + [ + ['text' => '🎯 Сообщество'] + ] + ]; + + if ($ctx->get('account')?->access['settings']) $keyboard[] = [['text' => '⚙️ Настройки']]; + + // Отправка сообщения + $ctx->sendMessage( + static::unmarkdown(<< [ + 'keyboard' => $keyboard, + 'resize_keyboard' => true + ], + 'disable_notification' => true + ] + ); + } + + /** + * Начало работы с чат-роботом + * + * Команда: /start + * + * @param Context $ctx + * + * @return void + */ + public static function start(Context $ctx): void + { + // Главное меню + static::menu($ctx); + } + + /** + * Контакты + * + * Команда: /contacts + * + * @param Context $ctx + * + * @return void + */ + public static function contacts(Context $ctx): void + { + // Отправка сообщения + $ctx->sendMessage(static::unmarkdown(<< [ + 'inline_keyboard' => [ + [ + ['text' => '⚡ Связь с менеджером', 'url' => 'https://t.me/iarming'], + ], + [ + ['text' => '📨 Почта', 'callback_data' => 'mail'] + ], + [ + ['text' => '🪖 Сайт', 'url' => 'https://arming.ru'], + ['text' => '🛒 Wildberries', 'url' => 'https://arming.ru'] + ] + ] + ], + 'link_preview_options' => [ + 'is_disabled' => true + ], + 'disable_notification' => true + ]); + } + + /** + * Почта + * + * @param Context $ctx + * + * @return void + */ + public static function _mail(Context $ctx): void + { + // Отправка сообщения + $ctx->sendMessage(static::unmarkdown(<< [ + 'is_disabled' => true + ], + 'disable_notification' => true + ]); + } + + /** + * Компания + * + * Команда: /company + * + * @param Context $ctx + * + * @return void + */ + public static function company(Context $ctx): void + { + // Отправка сообщения + $ctx->sendMessage( + static::unmarkdown(<< [ + 'inline_keyboard' => [ + [ + ['text' => '⚡ Связь с менеджером', 'url' => 'https://git.mirzaev.sexy/mirzaev/mashtrash'], + ['text' => '📨 Почта', 'text' => ''], + ], + [ + ['text' => '🪖 Сайт', 'url' => ''] + ['text' => '🛒 Wildberries', 'url' => ''] + ] + ] + ], + 'link_preview_options' => [ + 'is_disabled' => true + ] + ] */ + ); + } + + /** + * Сообщество + * + * Команда: /community + * + * @param Context $ctx + * + * @return void + */ + public static function community(Context $ctx): void + { + // Отправка сообщения + $ctx->sendMessage(static::unmarkdown(<< [ + 'inline_keyboard' => [ + [ + ['text' => '💬 Основной чат', 'url' => 'https://t.me/arming_zone'], + ] + ] + ], + 'link_preview_options' => [ + 'is_disabled' => true + ], + 'disable_notification' => true + ]); + } + + /** + * Настройки (доступ только авторизованным) + * + * Команда: /settings + * + * @param Context $ctx + * + * @return void + */ + public static function settings(Context $ctx): void + { + if ($ctx->get('account')?->access['settings']) { + // Авторизован доступ к настройкам + + // Отправка сообщения + $ctx->sendMessage( + static::unmarkdown(<< [ + 'inline_keyboard' => [ + [ + ['text' => '📦 Импорт товаров', 'callback_data' => 'import_request'], + ] + ] + ], + 'link_preview_options' => [ + 'is_disabled' => true + ], + 'disable_notification' => true + ] + ); + } else { + // Не авторизован доступ к настройкам + + // Отправка сообщения + $ctx->sendMessage('⛔ *Нет доступа*'); + } + } + + /** + * Запросить файл для импорта товаров (доступ только авторизованным) + * + * @param Context $ctx + * + * @return void + */ + public static function import_request(Context $ctx): void + { + if ($ctx->get('account')?->access['settings']) { + // Авторизован доступ к настройкам + + // Отправка сообщения + $ctx->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров')) + ->then(function ($message) use ($ctx) { + // Отправка файла + $ctx->sendDocument(new InputFile(CATALOG_EXAMPLE), ['disable_notification' => true]); + + // Импорт файла + $ctx->nextStep("import"); + }); + } else { + // Не авторизован доступ к настройкам + + // Отправка сообщения + $ctx->sendMessage('⛔ *Нет доступа*'); + } + } + + /** + * Импорт товаров (доступ только авторизованным) + * + * @param Context $ctx + * + * @return void + */ + public static function import(Context $ctx): void + { + if ($ctx->get('account')?->access['settings']) { + // Авторизован доступ к настройкам + + // Инициализация документа + $document = $ctx->getMessage()?->getDocument(); + + if ($document instanceof telegram_document) { + // Инициализирован документ + + // Инициализация файла + $ctx->getFile($document->getFileId())->then(function ($file) use ($ctx) { + + if ($file->getFileSize() <= 50000000) { + // Не превышает 50 мегабайт (50000000 байт) размер файла + + if ($file->getFilePath()['extension'] === 'xlsx') { + // Имеет расширение xlsx файл + + // Сохранение файла + file_put_contents(STORAGE . DIRECTORY_SEPARATOR . 'import.xlsx', file_get_contents('https://api.telegram.org/file/bot' . KEY . '/' . $file->getFilePath())); + + // Инициализация счётчика загруженных товаров + $loaded = $created = $updated = $deleted = $old = $new = 0; + + + + // Отправка сообщения + $ctx->sendMessage(<< *$new* + TXT) + ->then(function ($message) use ($ctx) { + // Завершение диалога + $ctx->endConversation(); + }); + } else { + // Не имеет расширение xlsx файл + + // Отправка сообщения + $ctx->sendMessage(static::unmarkdown('Файл должен иметь расширение xlsx')); + } + } else { + // Превышает 50 мегабайт (50000000 байт) размер файла + + // Отправка сообщения + $ctx->sendMessage(static::unmarkdown('Размер файла не должен превышать 50 мегабайт')); + } + }); + } else { + // Не инициализирован документ + + // Отправка сообщения + $ctx->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров')); + } + } else { + // Не авторизован доступ к настройкам + + // Отправка сообщения + $ctx->sendMessage('⛔ *Нет доступа*'); + } + } + + /** + * Инициализация аккаунта (middleware) + * + * @param Context $ctx + * @param Node $next + * + * @return void + */ + public static function account(Context $ctx, Node $next): void + { + // Выполнение заблокировано? + if ($ctx->get('stop')) return; + + // Инициализация аккаунта Telegram + $telegram = $ctx->getEffectiveUser(); + + // Инициализация аккаунта + $account = account::initialization($telegram->getId(), $telegram); + + if ($account) { + // Инициализирован аккаунт + + if ($account->banned) { + // Заблокирован аккаунт + + // Отправка сообщения + $ctx->sendMessage('⛔ *Ты заблокирован*') + ->then(function ($message) use ($ctx) { + // Завершение диалога + $ctx->endConversation(); + }); + + // Блокировка дальнейшего выполнения + $ctx->set('stop', true); + } else { + // Не заблокирован аккаунт + + // Запись в буфер + $ctx->set('account', $account); + + // Продолжение выполнения + $next($ctx); + } + } else { + // Не инициализирован аккаунт + } + } + + /** + * Инициализация статуса технических работ (middleware) + * + * @param Context $ctx + * @param Node $next + * + * @return void + */ + public static function suspension(Context $ctx, Node $next): void + { + // Выполнение заблокировано? + if ($ctx->get('stop')) return; + + // Поиск технических работ + $suspension = suspension::search(); + + if ($suspension && $suspension->targets['chat-robot']) { + // Найдена активная приостановка + + // Инициализация аккаунта + $account = $ctx->get('account'); + + if ($account) { + // Инициализирован аккаунт + + foreach ($suspension->access as $type => $status) { + // Перебор статусов доступа + + if ($status && $account->{$type}) { + // Авторизован аккаунт + + // Продолжение выполнения + $next($ctx); + + // Выход (успех) + return; + } + } + } + + // Инициализация сообщения + $message = "⚠️ *Работа приостановлена*\n*Оставшееся время\:* " . $suspension->message($account->language ?? controller::$settings?->language); + + // Добавление описания причины приостановки, если найдена + if (!empty($suspension->description)) $message .= "\n\n" . $suspension->description[$account->language ?? controller::$settings?->language] ?? array_values($suspension->description)[0]; + + // Отправка сообщения + $ctx->sendMessage($message) + ->then(function ($message) use ($ctx) { + // Завершение диалога + $ctx->endConversation(); + }); + + // Блокировка дальнейшего выполнения + $ctx->set('stop', true); + } else { + // Не найдена активная приостановка + + // Продолжение выполнения + $next($ctx); + } + } + + /** + * Write + * + * Write a property into an instance of the ArangoDB document + * + * @param string $name Name of the property + * @param mixed $value Content of the property + * + * @return void + */ + public function __set(string $name, mixed $value = null): void + { + // Write to the property into an instance of the ArangoDB document and exit (success) + $this->document->{$name} = $value; + } + + /** + * Read + * + * Read a property from an instance of the ArangoDB docuemnt + * + * @param string $name Name of the property + * + * @return mixed Content of the property + */ + public function __get(string $name): mixed + { + // Read a property from an instance of the ArangoDB document and exit (success) + return match ($name) { + 'arangodb' => $this::$arangodb, + default => $this->document->{$name} + }; + } + + /** + * Delete + * + * Deinitialize the property in an instance of the ArangoDB document + * + * @param string $name Name of the property + * + * @return void + */ + public function __unset(string $name): void + { + // Delete the property in an instance of the ArangoDB document and exit (success) + unset($this->document->{$name}); + } + + /** + * Check of initialization + * + * Check of initialization of the property into an instance of the ArangoDB document + * + * @param string $name Name of the property + * + * @return bool The property is initialized? + */ + public function __isset(string $name): bool + { + // Check of initializatio nof the property and exit (success) + return isset($this->document->{$name}); + } + + /** + * Execute a method + * + * Execute a method from an instance of the ArangoDB document + * + * @param string $name Name of the method + * @param array $arguments Arguments for the method + * + * @return mixed Result of execution of the method + */ + public function __call(string $name, array $arguments = []): mixed + { + // Execute the method and exit (success) + if (method_exists($this->document, $name)) return $this->document->{$name}($arguments); + } +} diff --git a/mirzaev/arming_bot/system/models/core.php b/mirzaev/arming_bot/system/models/core.php new file mode 100755 index 0000000..a6762ac --- /dev/null +++ b/mirzaev/arming_bot/system/models/core.php @@ -0,0 +1,291 @@ + + */ +class core extends model +{ + /** + * Postfix for name of models files + */ + final public const string POSTFIX = ''; + + /** + * Path to the file with settings of connecting to the ArangoDB + */ + final public const string ARANGODB = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'settings' . DIRECTORY_SEPARATOR . 'arangodb.php'; + + /** + * Instance of the session of ArangoDB + */ + protected static arangodb $arangodb; + + /** + * Name of the collection in ArangoDB + */ + public const string COLLECTION = 'THIS_COLLECTION_SHOULD_NOT_EXIST'; + + /** + * Constructor of an instance + * + * @param bool $initialize Initialize a model? + * @param ?arangodb $arangodb Instance of a session of ArangoDB + * + * @return void + */ + public function __construct(bool $initialize = true, ?arangodb $arangodb = null) + { + // For the extends system + parent::__construct($initialize); + + if ($initialize) { + // Initializing is requested + + if (isset($arangodb)) { + // Recieved an instance of a session of ArangoDB + + // Write an instance of a session of ArangoDB to the property + $this->__set('arangodb', $arangodb); + } else { + // Not recieved an instance of a session of ArangoDB + + // Initializing of an instance of a session of ArangoDB + $this->__get('arangodb'); + } + } + } + + /** + * Read from ArangoDB + * + * @param string $filter Expression for filtering (AQL) + * @param string $sort Expression for sorting (AQL) + * @param int $amount Amount of documents for collect + * @param int $page Page + * @param string $return Expression describing the parameters to return (AQL) + * @param array &$errors The registry on errors + * + * @return mixed An array of instances of documents from ArangoDB, if they are found + */ + public static function _read( + string $filter = '', + string $sort = 'd.created DESC, d._key DESC', + int $amount = 1, + int $page = 1, + string $return = 'd', + array &$errors = [] + ): _document|array|null { + try { + if (collection::init(static::$arangodb->session, static::COLLECTION)) { + // Initialized the collection + + // Read from ArangoDB and exit (success) + $result = collection::search( + static::$arangodb->session, + sprintf( + <<<'AQL' + FOR d IN %s + %s + %s + LIMIT %d, %d + RETURN %s + AQL, + static::COLLECTION, + empty($filter) ? '' : "FILTER $filter", + empty($sort) ? '' : "SORT $sort", + --$page <= 0 ? 0 : $page * $amount, + $amount, + $return + ) + ); + + // Выход (успех) + return is_array($result) ? $result : [$result]; + } else throw new exception('Failed to initialize the collection'); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Update in ArangoDB + * + * @param _document $instance Instance of the document from ArangoDB + * + * @return bool Writed to ArangoDB without errors? + */ + public static function _update(_document $instance): bool + { + // Update in ArangoDB and exit (success) + return document::update(static::$arangodb->session, $instance); + } + + /** + * Delete from ArangoDB + * + * @param _document $instance Instance of the document from ArangoDB + * @param array &$errors The registry on errors + * + * @return bool Deleted from ArangoDB without errors? + */ + public static function _delete(_document $instance, array &$errors = []): bool + { + try { + if (collection::init(static::$arangodb->session, static::COLLECTION)) { + // Initialized the collection + + // Delete from ArangoDB and exit (success) + return (new _document_handler(static::$arangodb->session))->remove($instance); + } else throw new exception('Failed to initialize the collection'); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return false; + } + + /** + * Write + * + * @param string $name Name of the property + * @param mixed $value Value of the property + * + * @return void + */ + public function __set(string $name, mixed $value = null): void + { + match ($name) { + 'arangodb' => (function () use ($value) { + if ($this->__isset('arangodb')) { + // Is alredy initialized + + // Exit (fail) + throw new exception('Forbidden to reinitialize the session of ArangoDB ($this::$arangodb)', 500); + } else { + // Is not already initialized + + if ($value instanceof arangodb) { + // Recieved an appropriate value + + // Write the property and exit (success) + self::$arangodb = $value; + } else { + // Recieved an inappropriate value + + // Exit (fail) + throw new exception('Session of ArangoDB ($this::$arangodb) is need to be mirzaev\arangodb\connection', 500); + } + } + })(), + default => parent::__set($name, $value) + }; + } + + /** + * Read + * + * @param string $name Name of the property + * + * @return mixed Content of the property, if they are found + */ + public function __get(string $name): mixed + { + return match ($name) { + 'arangodb' => (function () { + try { + if (!$this->__isset('arangodb')) { + // Is not initialized + + // Initializing of a default value from settings + $this->__set('arangodb', new arangodb(require static::ARANGODB)); + } + + // Exit (success) + return self::$arangodb; + } catch (exception) { + // Exit (fail) + return null; + } + })(), + default => parent::__get($name) + }; + } + + /** + * Delete + * + * @param string $name Name of the property + * + * @return void + */ + public function __unset(string $name): void + { + // Deleting a property and exit (success) + parent::__unset($name); + } + + /** + * Check of initialization + * + * @param string $name Name of the property + * + * @return bool The property is initialized? + */ + public function __isset(string $name): bool + { + // Check of initialization of the property and exit (success) + return parent::__isset($name); + } + + /** + * Call a static property or method + * + * @param string $name Name of the property or the method + * @param array $arguments Arguments for the method + */ + public static function __callStatic(string $name, array $arguments): mixed + { + return match ($name) { + 'arangodb' => (new static)->__get('arangodb'), + default => throw new exception("Not found: $name", 500) + }; + } +} diff --git a/mirzaev/arming_bot/system/models/enumerations/session.php b/mirzaev/arming_bot/system/models/enumerations/session.php new file mode 100644 index 0000000..29f648f --- /dev/null +++ b/mirzaev/arming_bot/system/models/enumerations/session.php @@ -0,0 +1,11 @@ + + */ +interface document +{ + /** + * Write + * + * Write a property into an instance of the ArangoDB document + * + * @param string $name Name of the property + * @param mixed $value Content of the property + * + * @return void + */ + public function __set(string $name, mixed $value = null): void; + + /** + * Read + * + * Read a property from an instance of the ArangoDB docuemnt + * + * @param string $name Name of the property + * + * @return mixed Content of the property + */ + public function __get(string $name): mixed; + + + /** + * Delete + * + * Deinitialize the property in an instance of the ArangoDB document + * + * @param string $name Name of the property + * + * @return void + */ + public function __unset(string $name): void; + + /** + * Check of initialization + * + * Check of initialization of the property into an instance of the ArangoDB document + * + * @param string $name Name of the property + * + * @return bool The property is initialized? + */ + public function __isset(string $name): bool; + + /** + * Execute a method + * + * Execute a method from an instance of the ArangoDB document + * + * @param string $name Name of the method + * @param array $arguments Arguments for the method + * + * @return mixed Result of execution of the method + */ + public function __call(string $name, array $arguments = []): mixed; +} diff --git a/mirzaev/arming_bot/system/models/part.php b/mirzaev/arming_bot/system/models/part.php new file mode 100755 index 0000000..a9284f0 --- /dev/null +++ b/mirzaev/arming_bot/system/models/part.php @@ -0,0 +1,22 @@ + + */ +final class part extends categories +{ + /** + * Name of the collection in ArangoDB + */ + final public const string COLLECTION = 'part'; +} diff --git a/mirzaev/arming_bot/system/models/product.php b/mirzaev/arming_bot/system/models/product.php new file mode 100755 index 0000000..bb9a0c8 --- /dev/null +++ b/mirzaev/arming_bot/system/models/product.php @@ -0,0 +1,218 @@ + + */ +final class product extends core +{ + /** + * Name of the collection in ArangoDB + */ + final public const string COLLECTION = 'product'; + + /** + * Чтение товаров + * + * @param string|null $search Поиск + * @param string|null $filter Фильтр + * @param string|null $sort Сортировка + * @param int $page Страница + * @param int $amount Количество товаров на странице + * @param string|null $return + * @param array &$errors Registry of errors + * + * @return array Массив с найденными товарами (может быть пустым) + */ + public static function read( + ?string $search = null, + ?string $filter = 'd.deleted != true && d.hidden != true', + ?string $sort = 'd.promotion DESC, d.position ASC, d.created DESC', + int $page = 1, + int $amount = 100, + ?string $return = 'd', + array &$errors = [] + ): array { + try { + if (collection::init(core::$arangodb->session, self::COLLECTION)) { + // Инициализирована коллекция + + // Инициализация строки запроса + $aql = sprintf( + <<session, + sprintf( + $aql . << $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return []; + } + + /** + * Запись товара + * + * @param string $title Заголовок + * @param string|null $description Описание + * @param float $cost Цена + * @param float $weight Вес + * @param array $dimensions Габариты (float) + * @param array $images Изображения (первое - обложка) (https, путь в storage, иначе будет поиск в storage) + * @param array $hierarchy Иерархия вложенности (от родителей к потомкам: [ model, model ... ]) + * @param array $data Дополнительные данные + * @param array &$errors Registry of errors + * + * @return string|null Идентификатор (_id) документа (товара), если создан + */ + public static function write( + string $title, + ?string $description = null, + float $cost = 0, + float $weight = 0, + array $dimensions = ['x' => 0, 'y' => 0, 'z' => 0], + array $images = [], + array $hierarchy = [], + array $data = [], + array &$errors = [] + ): string|null { + try { + if (collection::init(core::$arangodb->session, self::COLLECTION)) { + // Инициализирована коллекция + + // Создание товара + $product = document::write( + core::$arangodb->session, + self::COLLECTION, + [ + 'title' => $title, + 'description' => $description, + 'cost' => $cost ?? 0, + 'weight' => $weight ?? 0, + 'dimensions' => [ + 'x' => $dimensions['x'] ?? 0, + 'y' => $dimensions['y'] ?? 0, + 'z' => $dimensions['z'] ?? 0, + ], + 'images' => $images, + 'version' => ROBOT_VERSION + ] + $data + ); + + if ($product) { + // Создан товар + + if (collection::init(core::$arangodb->session, 'entry', true)) { + // Инициализирована коллекция + + foreach ($hierarchy as $model) { + // Перебор иерархической структуры категорий + + // Инициализация вложенной категории (следующей в массиве) + $next = current($hierarchy); + + // Поиск ребра описывающего иерархическую связь + + document::write(core::$arangodb->session, 'entry'); + } + } else throw new exception('Failed to initialize document collection: ' . self::COLLECTION); + } + } else throw new exception('Failed to initialize document collection: entry'); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return null; + } +} diff --git a/mirzaev/arming_bot/system/models/session.php b/mirzaev/arming_bot/system/models/session.php new file mode 100755 index 0000000..059e455 --- /dev/null +++ b/mirzaev/arming_bot/system/models/session.php @@ -0,0 +1,338 @@ + + */ +final class session extends core implements arangodb_document_interface +{ + use status, arangodb_document_trait; + + /** + * Name of the collection in ArangoDB + */ + final public const string COLLECTION = 'session'; + + /** + * Type of session verification( + */ + public const verification VERIFICATION = verification::hash_else_address; + + /** + * Constructor of an instance + * + * Initialize of a session and write them to the $this->document property + * + * @param ?string $hash Hash of the session in ArangoDB + * @param ?int $expires Date of expiring of the session (used for creating a new session) + * @param array &$errors Registry of errors + * + * @return static instance of the ArangoDB document of session + */ + public function __construct(?string $hash = null, ?int $expires = null, array &$errors = []) + { + try { + if (collection::init(static::$arangodb->session, self::COLLECTION)) { + // Initialized the collection + + if (isset($hash) && $document = $this->hash($hash, $errors)) { + // Found an instance of the ArangoDB document of session and received a session hash + + // Writing document instance of the session from ArangoDB to the property of the implementing object + $this->document = $document; + } else if (static::VERIFICATION === verification::hash_else_address && $document = $this->address($_SERVER['REMOTE_ADDR'], $errors)) { + // Found an instance of the ArangoDB document of session and received a session hash + + // Writing document instance of the session from ArangoDB to the property of the implementing object + $this->document = $document; + } else { + // Not found an instance of the ArangoDB document of session + + // Initializing a new session and write they into ArangoDB + $_id = document::write($this::$arangodb->session, self::COLLECTION, [ + 'active' => true, + 'expires' => $expires ?? time() + 604800, + 'address' => $_SERVER['REMOTE_ADDR'], + 'x-forwarded-for' => $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null, + 'referer' => $_SERVER['HTTP_REFERER'] ?? null, + 'useragent' => $_SERVER['HTTP_USER_AGENT'] ?? null + ]); + + if ($session = collection::search($this::$arangodb->session, sprintf( + << %d && d.active == true + RETURN d + AQL, + self::COLLECTION, + $_id, + time() + ))) { + // Found an instance of just created new session + + // Generate a hash and write into an instance of the ArangoDB document of session property + $session->hash = sodium_bin2hex(sodium_crypto_generichash($_id)); + + if (document::update($this::$arangodb->session, $session)) { + // Is writed update + + // Writing document instance of the session from ArangoDB to the property of the implementing object + $this->document = $session; + } else throw new exception('Could not write the session data'); + } else throw new exception('Could not create or find just created session'); + } + } else throw new exception('Could not initialize the collection'); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + } + + /** + * Search for a connected account + * + * @param array &$errors Registry of errors + * + * @return account|null An object implementing the account instance from the database, if found + */ + public function account(array &$errors = []): ?account + { + try { + if (collection::init(core::$arangodb->session, static::COLLECTION)) { + if (collection::init(core::$arangodb->session, 'connect', true)) { + if (collection::init(core::$arangodb->session, account::COLLECTION)) { + // Инициализирована коллекция + + if ($document = collection::search( + core::$arangodb->session, + sprintf( + <<getId(), + ) + )) { + // Найден аккаунт + + // Инициализация объекта аккаунта + $account = new account; + + // Запись инстанции документа в объект + $account->__document($document); + + // Exit (success) + return $account; + } else return null; + } else throw new exception('Failed to initialize document collection: ' . account::COLLECTION); + } else throw new exception('Failed to initialize edge collection: connect'); + } else throw new exception('Failed to initialize document collection: ' . static::COLLECTION); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Connect account to session + * + * @param account $account Account + * @param array &$errors Registry of errors + * + * @return string|null The identifier of the created edge of the "connect" collection, if created + */ + public function connect(account $account, array &$errors = []): ?string + { + try { + if (collection::init(core::$arangodb->session, static::COLLECTION)) { + if (collection::init(core::$arangodb->session, 'connect', true)) { + if (collection::init(core::$arangodb->session, account::COLLECTION)) { + // Collections initialized + + // Writing document and exit (success) + return document::write( + core::$arangodb->session, + 'connect', + [ + '_from' => $account->getId(), + '_to' => $this->document->getId() + ] + ); + } else throw new exception('Failed to initialize document collection: ' . account::COLLECTION); + } else throw new exception('Failed to initialize edge collection: connect'); + } else throw new exception('Failed to initialize document collection: ' . static::COLLECTION); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Search by hash + * + * Search for the session in ArangoDB by hash + * + * @param string $hash Hash of the session in ArangoDB + * @param array &$errors Registry of errors + * + * @return _document|null instance of document of the session in ArangoDB + */ + public static function hash(string $hash, array &$errors = []): ?_document + { + try { + if (collection::init(core::$arangodb->session, static::COLLECTION)) { + // Collection initialized + + // Search the session data in ArangoDB + return collection::search(static::$arangodb->session, sprintf( + << %d && d.active == true + RETURN d + AQL, + static::COLLECTION, + $hash, + time() + )); + } else throw new exception('Failed to initialize document collection: ' . static::COLLECTION); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Search by IP-address + * + * Search for the session in ArangoDB by IP-address + * + * @param string $address IP-address writed to the session in ArangoDB + * @param array &$errors Registry of errors + * + * @return _document|null instance of document of the session in ArangoDB + */ + public static function address(string $address, array &$errors = []): ?_document + { + try { + if (collection::init(core::$arangodb->session, static::COLLECTION)) { + // Collection initialized + + // Search the session data in ArangoDB + return collection::search(static::$arangodb->session, sprintf( + << %d && d.active == true + RETURN d + AQL, + static::COLLECTION, + $address, + time() + )); + } else throw new exception('Failed to initialize document collection: ' . static::COLLECTION); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Write to buffer of the session + * + * @param array $data Data for merging + * @param array &$errors Registry of errors + * + * @return bool Is data has written into the session buffer? + */ + public function write(array $data, array &$errors = []): bool + { + try { + if (collection::init($this::$arangodb->session, self::COLLECTION)) { + // Initialized the collection + + // An instance of the ArangoDB document of session is initialized? + if (!isset($this->document)) throw new exception('An instance of the ArangoDB document of session is not initialized'); + + // Write data into buffwer of an instance of the ArangoDB document of session + $this->document->buffer = array_replace_recursive( + $this->document->buffer ?? [], + [$_SERVER['INTERFACE'] => array_replace_recursive($this->document->buffer[$_SERVER['INTERFACE']] ?? [], $data)] + ); + + // Write to ArangoDB and exit (success) + return document::update($this::$arangodb->session, $this->document) ? true : throw new exception('Не удалось записать данные в буфер сессии'); + } else throw new exception('Could not initialize the collection'); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + return false; + } +} diff --git a/mirzaev/arming_bot/system/models/settings.php b/mirzaev/arming_bot/system/models/settings.php new file mode 100755 index 0000000..4cb1a47 --- /dev/null +++ b/mirzaev/arming_bot/system/models/settings.php @@ -0,0 +1,83 @@ + + */ +final class settings extends core implements arangodb_document_interface +{ + use arangodb_document_trait; + + /** + * Name of the collection in ArangoDB + */ + final public const string COLLECTION = 'settings'; + + /** + * Search for active settings + * + * @param array|null $create Данные для создания, если настройки не найдены + * @param array &$errors Registry of errors + * + * @return static|null Object implements an instance of settngs document from ArangoDB + */ + public static function active(array|null $create = null, array &$errors = []): static|null + { + try { + if (collection::init(core::$arangodb->session, self::COLLECTION)) { + if ($document = collection::search(core::$arangodb->session, sprintf("FOR d IN %s FILTER d.status == 'active' SORT d.updated DESC LIMIT 1 RETURN d", self::COLLECTION))) { + // Найдены активные настройки + + // Инициализация объекта настроек + $settings = new static; + + // Запись инстанции документа в объект + $settings->document = $document; + + // Возврат (успех) + return $settings; + } else if ($create) { + // Не найдены активные настройки и запрошено создание + + // Создание настроек + document::write(core::$arangodb->session, self::COLLECTION, ['status' => 'active'] + $create); + + // Инициализация (без создания) + return static::active(errors: $errors); + } else throw new exception('Settings not found'); + } else throw new exception('Failed to initialize document collection: ' . self::COLLECTION); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Выход (провал) + return null; + } +} diff --git a/mirzaev/arming_bot/system/models/suspension.php b/mirzaev/arming_bot/system/models/suspension.php new file mode 100755 index 0000000..28a59e1 --- /dev/null +++ b/mirzaev/arming_bot/system/models/suspension.php @@ -0,0 +1,166 @@ + + */ +final class suspension extends core implements arangodb_document_interface +{ + use arangodb_document_trait; + + /** + * Name of the collection in ArangoDB + */ + final public const string COLLECTION = 'suspension'; + + /** + * Search for active suspension + * + * @param array &$errors Registry of errors + * + * @return static|null Object implements an instance of suspension from ArangoDB + */ + public static function search(array &$errors = []): static|null + { + try { + if (collection::init(core::$arangodb->session, self::COLLECTION)) { + if ($document = collection::search(core::$arangodb->session, sprintf("FOR d IN %s FILTER d.end > %u SORT d.end DESC LIMIT 1 RETURN d", self::COLLECTION, time()))) { + // Найдены активные настройки + + // Инициализация объекта настроек + $suspension = new static; + + // Запись инстанции документа в объект + $suspension->document = $document; + + // Возврат (успех) + return $suspension; + } else return null; + } else throw new exception('Failed to initialize document collection: ' . self::COLLECTION); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } + + /** + * Generate message about remaining time + * + * @param string|null $language Language of the generated text (otherwise used from settings.language) + * @param array &$errors Registry of errors + * + * @return string|null Text: "? days, ? hours and ? minutes" + */ + public function message(?string $language = null, array &$errors = []): ?string + { + try { + // Initializing default value + $language ??= controller::$settings?->language ?? 'en'; + + // Initializing the time until the suspension ends + $difference = date_diff(new datetime('@' . $this->document->end), new datetime()); + + // Generate text about remaining time and exit (success) + return sprintf( + '%u %s, %u %s и %u %s', + $difference->d, + match ($difference->d > 20 ? $difference->d % 10 : $difference->d % 100) { + 1 => match ($language) { + 'ru' => 'день', + 'en' => 'day', + default => 'day' + }, + 2, 3, 4 => match ($language) { + 'ru' => 'дня', + 'en' => 'days', + default => 'days' + }, + default => match ($language) { + 'ru' => 'дней', + 'en' => 'days', + default => 'days' + } + }, + $difference->h, + match ($difference->h > 20 ? $difference->h % 10 : $difference->h % 100) { + 1 => match ($language) { + 'ru' => 'час', + 'en' => 'hours', + default => 'hour' + }, + 2, 3, 4 => match ($language) { + 'ru' => 'часа', + 'en' => 'hours', + default => 'hours' + }, + default => match ($language) { + 'ru' => 'часов', + 'en' => 'hours', + default => 'hours' + } + }, + $difference->i, + match ($difference->i > 20 ? $difference->i % 10 : $difference->i % 100) { + 1 => match ($language) { + 'ru' => 'минута', + 'en' => 'minute', + default => 'minute' + }, + 2, 3, 4 => match ($language) { + 'ru' => 'минуты', + 'en' => 'minutes', + default => 'minutes' + }, + default => match ($language) { + 'ru' => 'минут', + 'en' => 'minutes', + default => 'minutes' + } + } + ); + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } +} diff --git a/mirzaev/arming_bot/system/models/traits/document.php b/mirzaev/arming_bot/system/models/traits/document.php new file mode 100755 index 0000000..135c103 --- /dev/null +++ b/mirzaev/arming_bot/system/models/traits/document.php @@ -0,0 +1,121 @@ + + */ +trait document +{ + /** + * An instance of the ArangoDB document from ArangoDB + */ + protected readonly _document $document; + + /** + * Write or read document + * + * @param _document|null $document Instance of document from ArangoDB + * + * @return _document|null Instance of document from ArangoDB + */ + public function __document(?_document $document): ?_document + { + // Write a property storing a document instance to ArangoDB + if ($document) $this->document = $document; + + // Read a property storing a document instance to ArangoDB and exit (success) + return $this->document; + } + + /** + * Write + * + * Write a property into an instance of the ArangoDB document + * + * @param string $name Name of the property + * @param mixed $value Content of the property + * + * @return void + */ + public function __set(string $name, mixed $value = null): void + { + // Write to the property into an instance of the ArangoDB document and exit (success) + $this->document->{$name} = $value; + } + + /** + * Read + * + * Read a property from an instance of the ArangoDB docuemnt + * + * @param string $name Name of the property + * + * @return mixed Content of the property + */ + public function __get(string $name): mixed + { + // Read a property from an instance of the ArangoDB document and exit (success) + return match ($name) { + 'arangodb' => core::$arangodb, + default => $this->document->{$name} + }; + } + + /** + * Delete + * + * Deinitialize the property in an instance of the ArangoDB document + * + * @param string $name Name of the property + * + * @return void + */ + public function __unset(string $name): void + { + // Delete the property in an instance of the ArangoDB document and exit (success) + unset($this->document->{$name}); + } + + /** + * Check of initialization + * + * Check of initialization of the property into an instance of the ArangoDB document + * + * @param string $name Name of the property + * + * @return bool The property is initialized? + */ + public function __isset(string $name): bool + { + // Check of initializatio nof the property and exit (success) + return isset($this->document->{$name}); + } + + /** + * Execute a method + * + * Execute a method from an instance of the ArangoDB document + * + * @param string $name Name of the method + * @param array $arguments Arguments for the method + * + * @return mixed Result of execution of the method + */ + public function __call(string $name, array $arguments = []): mixed + { + // Execute the method and exit (success) + return method_exists($this->document, $name) ?$this->document->{$name}($arguments) ?? null : null; + } +} diff --git a/mirzaev/arming_bot/system/models/traits/status.php b/mirzaev/arming_bot/system/models/traits/status.php new file mode 100755 index 0000000..d23f3cb --- /dev/null +++ b/mirzaev/arming_bot/system/models/traits/status.php @@ -0,0 +1,44 @@ + + */ +trait status +{ + /** + * Initialize of a status + * + * @param array &$errors Registry of errors + * + * @return ?bool Status, if they are found + */ + public function status(array &$errors = []): ?bool + { + try { + // Read from ArangoDB and exit (success) + return $this->document->active ?? false; + } catch (exception $e) { + // Write to the registry of errors + $errors[] = [ + 'text' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'stack' => $e->getTrace() + ]; + } + + // Exit (fail) + return null; + } +} + diff --git a/mirzaev/arming_bot/system/public/index.php b/mirzaev/arming_bot/system/public/index.php new file mode 100755 index 0000000..938a499 --- /dev/null +++ b/mirzaev/arming_bot/system/public/index.php @@ -0,0 +1,71 @@ +write('/', 'catalog', 'index', 'GET') + ->write('/search', 'catalog', 'search', 'POST') + ->write('/session/connect/telegram', 'session', 'telegram', 'POST') + ->write('/product/$id', 'catalog', 'product', 'POST') + ->write('/$categories...', 'catalog', 'index', 'POST'); + +/* + +// Initializing of routes +$router + ->write('/', 'catalog', 'index', 'GET') + ->write('/$sex', 'catalog', 'search', 'POST') + ->write('/$search', 'catalog', 'search', 'POST') + ->write('/search', 'catalog', 'search', 'POST') + ->write('/search/$asdasdasd', 'catalog', 'search', 'POST') + ->write('/ebala/$sex/$categories...', 'catalog', 'index', 'POST') + ->write('/$sex/$categories...', 'catalog', 'index', 'POST') + ->write('/$categories...', 'catalog', 'index', 'POST') + ->write('/ebala/$categories...', 'catalog', 'index', 'POST'); + +var_dump($router->routes); +echo "\n\n\n\n\n\n"; +$router + ->sort(); +var_dump($router->routes); */ + +// Инициализация ядра +$core = new core(namespace: __NAMESPACE__, router: $router, controller: new controller(false), model: new model(false)); + +// Обработка запроса +echo $core->start(); diff --git a/mirzaev/arming_bot/system/public/js/authentication.js b/mirzaev/arming_bot/system/public/js/authentication.js new file mode 100755 index 0000000..fdf3a03 --- /dev/null +++ b/mirzaev/arming_bot/system/public/js/authentication.js @@ -0,0 +1,62 @@ +"use strict"; + +// Import dependencies +import("/js/core.js").then(() => + import("/js/damper.js").then(() => { + import("/js/telegram.js").then(() => { + const dependencies = setInterval(() => { + if ( + typeof core === "function" && + typeof core.damper === "function" && + typeof core.telegram === "function" + ) { + clearInterval(dependencies); + clearTimeout(timeout); + initialization(); + } + }, 10); + const timeout = setTimeout(() => clearInterval(dependencies), 5000); + + function initialization() { + const timer_for_response = setTimeout(() => { + core.loading.setAttribute("disabled", true); + + const p = document.createElement("p"); + p.innerText = "Not authenticated"; + + core.footer.appendChild(p); + }, 3000); + + core.request( + "/session/connect/telegram", + "authentication=telegram&" + core.telegram.api.initData, + ) + .then((json) => { + if ( + json.errors !== null && + typeof json.errors === "object" && + json.errors.length > 0 + ) { + // Errors received + } else { + // Errors not received + + if (json.connected === true) { + core.loading.setAttribute("disabled", true); + + clearTimeout(timer_for_response); + } + + if ( + json.language !== null && + typeof json.language === "string" && + json.langiage.length === 2 + ) { + core.language = json.language; + } + } + }); + } + }); + }) +); diff --git a/mirzaev/arming_bot/system/public/js/cart.js b/mirzaev/arming_bot/system/public/js/cart.js new file mode 100755 index 0000000..e211050 --- /dev/null +++ b/mirzaev/arming_bot/system/public/js/cart.js @@ -0,0 +1,30 @@ +"use strict"; + +// Import dependencies +import("/js/core.js").then(() => + import("/js/damper.js").then(() => { + const dependencies = setInterval(() => { + if (typeof core === "function" && + typeof core.damper === "function") { + clearInterval(dependencies); + clearTimeout(timeout); + initialization(); + } + }, 10); + const timeout = setTimeout(() => clearInterval(dependencies), 5000); + + function initialization() { + if (typeof core.cart === "undefined") { + // Not initialized + + // Write to the core + core.cart = class cart { + /** + * Products in cart ["product/148181", "product/148181", "product/148181"...] + */ + static cart = []; + }; + } + } + }) +); diff --git a/mirzaev/arming_bot/system/public/js/catalog.js b/mirzaev/arming_bot/system/public/js/catalog.js new file mode 100755 index 0000000..b2d6eb4 --- /dev/null +++ b/mirzaev/arming_bot/system/public/js/catalog.js @@ -0,0 +1,628 @@ +"use strict"; + +// Import dependencies +import("/js/core.js").then(() => + import("/js/damper.js").then(() => { + import("/js/telegram.js").then(() => { + import("/js/hotline.js").then(() => { + const dependencies = setInterval(() => { + console.log(typeof core, typeof core.damper, typeof core.telegram, typeof core.hotline); + if ( + typeof core === "function" && + typeof core.damper === "function" && + typeof core.telegram === "function" && + typeof core.hotline === "function" + ) { + clearInterval(dependencies); + clearTimeout(timeout); + initialization(); + } + }, 10); + const timeout = setTimeout(() => clearInterval(dependencies), 5000); + + function initialization() { + if (typeof core.catalog === "undefined") { + // Not initialized + + // Write to the core + core.catalog = class catalog { + /** + * Current position in hierarchy of the categories + */ + static categories = []; + + /** + * Select a category (interface) + * + * @param {HTMLElement} button Button of category + * @param {bool} clean Clear search bar? + * @param {bool} force Ignore the damper? + * + * @return {void} + */ + static category(button, clean = true, force = false) { + // Initialize of the new category name + const category = button.getAttribute("data-category-name"); + + this._category(category, clean, force); + } + + /** + * Select a category (damper) + * + * @param {HTMLElement} button Button of category + * @param {bool} clean Clear search bar? + * @param {bool} force Ignore the damper? + * + * @return {void} + */ + static _category = core.damper( + (...variables) => this.__category(...variables), + 400, + 2, + ); + + /** + * Select a category (system) + * + * @param {HTMLElement} button Button of category + * @param {bool} clean Clear search bar? + * + * @return {Promise} Request to the server + */ + static __category(category = "", clean = true) { + if (typeof category === "string") { + // + + let urn; + if (category === "/" || category === "") urn = "/"; + else {urn = this.categories.length > 0 + ? `/${this.categories.join("/")}/${category}` + : `/${category}`;} + + return core.request(urn) + .then((json) => { + if ( + json.errors !== null && + typeof json.errors === "object" && + json.errors.length > 0 + ) { + // Errors received + } else { + // Errors not received + + if (clean) { + // Clearing the search bar + const search = core.main.querySelector( + 'search[data-section="search"]>input', + ); + if (search instanceof HTMLElement) search.value = ""; + } + + // Write the category to position in the categories hierarchy + if (category !== "/" && category !== "") { + this.categories.push(category); + } + + if ( + typeof json.title === "string" && + json.title.length > 0 + ) { + // Received the page title + + // Initialize a link to the categories list + const title = core.main.getElementsByTagName("h2")[0]; + + // Write the title + title.innerText = json.title; + } + + if ( + typeof json.html.categories === "string" && + json.html.categories.length > 0 + ) { + // Received categories (reinitialization of the categories) + + const categories = core.main.querySelector( + 'section[data-catalog-type="categories"]', + ); + + if (categories instanceof HTMLElement) { + // Found list of categories + + categories.outerHTML = json.html.categories; + } else { + // Not found list of categories + + const element = document.createElement("section"); + + const search = core.main.querySelector( + 'search[data-section="search"]', + ); + + if (search instanceof HTMLElement) { + core.main.insertBefore( + element, + search.nextSibling, + ); + + element.outerHTML = json.html.categories; + } + } + } else { + // Not received categories (deinitialization of the categories) + + const categories = core.main.querySelector( + 'section[data-catalog-type="categories"', + ); + if (categories instanceof HTMLElement) { + categories.remove(); + } + } + + if ( + typeof json.html.products === "string" && + json.html.products.length > 0 + ) { + // Received products (reinitialization of the products) + + const products = core.main.querySelector( + 'section[data-catalog-type="products"]', + ); + + if (products instanceof HTMLElement) { + // Found list of products + + products.outerHTML = json.html.products; + } else { + // Not found list of products + + const element = document.createElement("section"); + + const categories = core.main.querySelector( + 'section[data-catalog-type="categories"]', + ); + + if (categories instanceof HTMLElement) { + core.main.insertBefore( + element, + categories.nextSibling, + ); + + element.outerHTML = json.html.products; + } else { + const search = core.main.querySelector( + 'search[data-section="search"]', + ); + + if (search instanceof HTMLElement) { + core.main.insertBefore( + element, + search.nextSibling, + ); + + element.outerHTML = json.html.products; + } + } + } + } else { + // Not received products (deinitialization of the products) + + const products = core.main.querySelector( + 'section[data-catalog-type="products"', + ); + if (products instanceof HTMLElement) { + products + .remove(); + } + } + } + }); + } + } + + /** + * Select a category (interface) + * + * @param {Event} event Event (keyup) + * @param {HTMLElement} element Search bar + * @param {bool} force Ignore the damper? + * + * @return {void} + */ + static search(event, element, force = false) { + element.classList.remove("error"); + + if (element.innerText.length === 1) { + return; + } else if (event.keyCode === 13) { + // Button: "enter" + + element.setAttribute("disabled", true); + + this.__search(element); + } else { + // Button: any + + this._search(element, force); + } + } + + /** + * Search in the catalog (damper) + * + * @param {HTMLElement} button Button of category + * @param {bool} clean Clear search bar? + * @param {bool} force Ignore the damper? + * + * @return {void} + */ + static _search = core.damper( + (...variables) => this.__search(...variables), + 1400, + 2, + ); + + /** + * Search in the catalog (system) + * + * @param {HTMLElement} element Search bar + * + * @return {Promise} Request to the server + * + * @todo add animations of errors + */ + static __search(element) { + // Deinitialization of position in the categories hierarchy + this.categories = []; + + return this.__category("/", false) + .then(function () { + core.request("/search", `text=${element.value}`) + .then((json) => { + element.removeAttribute("disabled"); + element.focus(); + + if ( + json.errors !== null && + typeof json.errors === "object" && + json.errors.length > 0 + ) { + // Errors received + + element.classList.add("error"); + } else { + // Errors not received + + if ( + typeof json.title === "string" && + json.title.length > 0 + ) { + // Received the page title + + // Initialize a link to the categories list + const title = + core.main.getElementsByTagName("h2")[0]; + + // Write the title + title.innerText = json.title; + } + + // Deinitialization of the categories + const categories = core.main.querySelector( + 'section[data-catalog-type="categories"]', + ); + // if (categories instanceof HTMLElement) categories.remove(); + + if ( + typeof json.html.products === "string" && + json.html.products.length > 0 + ) { + // Received products (reinitialization of the products) + + const products = core.main.querySelector( + 'section[data-catalog-type="products"]', + ); + + if (products instanceof HTMLElement) { + // Found list of products + + products.outerHTML = json.html.products; + } else { + // Not found list of products + + const element = document.createElement("section"); + + const categories = core.main.querySelector( + 'section[data-catalog-type="categories"', + ); + + if (categories instanceof HTMLElement) { + core.main.insertBefore( + element, + categories.nextSibling, + ); + + element.outerHTML = json.html.products; + } else { + const search = core.main.querySelector( + 'search[data-section="search"]', + ); + + if (search instanceof HTMLElement) { + core.main.insertBefore( + element, + search.nextSibling, + ); + + element.outerHTML = json.html.products; + } + } + } + } else { + // Not received products (deinitialization of the products) + + const products = core.main.querySelector( + 'section[data-catalog-type="products"]', + ); + if (products instanceof HTMLElement) { + products.remove(); + } + } + } + }); + }); + } + + /** + * Open product card (interface) + * + * @param {string} id Identifier of a product + * @param {bool} force Ignore the damper? + * + * @return {void} + */ + static product(id, force = false) { + this._product(id, force); + } + + /** + * Open product card (damper) + * + * @param {string} id Identifier of a product + * @param {bool} force Ignore the damper? + * + * @return {void} + */ + static _product = core.damper( + (...variables) => this.__product(...variables), + 400, + 1, + ); + + /** + * Open product card (system) + * + * @param {string} id Identifier of a product + * + * @return {Promise} Request to the server + */ + static __product(id) { + if (typeof id === "number") { + // + + return core.request(`/product/${id}`) + .then((json) => { + if ( + json.errors !== null && + typeof json.errors === "object" && + json.errors.length > 0 + ) { + // Errors received + } else { + // Errors not received + + if ( + json.product !== null && + typeof json.product === "object" + ) { + // Received data of the product + + // Deinitializing of the old winow + const old = document.getElementById("window"); + if (old instanceof HTMLElement) old.remove(); + + const wrap = document.createElement("section"); + wrap.setAttribute("id", "window"); + + const card = document.createElement("div"); + // card.classList.add("product", "card"); + card.classList.add("card", "unselectable"); + + const h3 = document.createElement("h3"); + h3.setAttribute("title", json.product.id); + + const title = document.createElement("span"); + title.classList.add("title"); + title.innerText = json.product.title; + + const brand = document.createElement("small"); + brand.classList.add("brand"); + brand.innerText = json.product.brand; + + const images = document.createElement("div"); + images.classList.add("images", "unselectable"); + + for (const uri of json.product.images) { + const image = document.createElement("img"); + image.setAttribute("src", uri); + image.setAttribute("ondragstart", "return false;"); + + const button = core.telegram.api.isVisible; + + const open = (event) => { + if (event.target === from) { + if (typeof images.hotline === "object") { + if (images.hotline.moving) return; + images.hotline.stop(); + } + + image.classList.add("extend"); + + if (button) core.telegram.api.MainButton.hide(); + + setTimeout(() => { + image.addEventListener("click", close); + image.addEventListener("touch", close); + }, 300); + image.removeEventListener("mouseup", open); + image.removeEventListener("touchend", open); + } + }; + + const close = () => { + if (typeof images.hotline === "object") { + images.hotline.start(); + } + + image.classList.remove("extend"); + + if (button) core.telegram.api.MainButton.show(); + + image.removeEventListener("click", close); + image.removeEventListener("touch", close); + image.addEventListener("mousedown", start); + image.addEventListener("touchstart", start); + }; + + const start = (event) => { + if ( + event.type === "touchstart" || + event.button === 0 + ) { + image.removeEventListener("mousedown", start); + image.removeEventListener("touchstart", start); + image.addEventListener("mouseup", open); + image.addEventListener("touchend", open); + } + }; + + image.addEventListener("mousedown", start); + image.addEventListener("touchstart", start); + + images.append(image); + } + + const description = document.createElement("p"); + description.classList.add("description"); + description.innerText = json.product.description; + + const compatibility = document.createElement("p"); + compatibility.classList.add("compatibility"); + compatibility.innerText = json.product.compatibility; + + const footer = document.createElement("div"); + footer.classList.add("footer"); + footer.classList.add("footer"); + + const dimensions = document.createElement("small"); + dimensions.classList.add("dimensions"); + dimensions.innerText = json.product.dimensions.x + + "x" + + json.product.dimensions.y + "x" + + json.product.dimensions.z; + + const weight = document.createElement("small"); + weight.classList.add("weight"); + weight.innerText = json.product.weight + "г"; + + const cost = document.createElement("p"); + cost.classList.add("cost"); + cost.innerText = json.product.cost + "р"; + + h3.append(title); + h3.append(brand); + card.append(h3); + card.append(images); + card.append(description); + card.append(compatibility); + footer.append(dimensions); + footer.append(weight); + footer.append(cost); + card.append(footer); + wrap.append(card); + core.main.append(wrap); + + let width = 0; + let buffer; + [...images.children].forEach((child) => + width += child.offsetWidth + (isNaN( + buffer = parseFloat( + getComputedStyle(child).marginRight, + ), + ) + ? 0 + : buffer) + ); + + history.pushState( + { product_card: json.product.id }, + json.product.title, + ); + + // блокировка закрытия карточки + let from; + const _from = (event) => from = event.target; + wrap.addEventListener("mousedown", _from); + wrap.addEventListener("touchstart", _from); + + const remove = () => { + wrap.remove(); + wrap.removeEventListener("mousedown", _from); + wrap.removeEventListener("touchstart", _from); + document.removeEventListener("click", close); + document.removeEventListener("touch", close); + window.removeEventListener("popstate", remove); + }; + + const close = (event) => { + if ( + from === wrap && + !card.contains(event.target) && + !!card && + !!(card.offsetWidth || + card.offsetHeight || + card.getClientRects().length) + ) { + remove(); + } + + from = undefined; + }; + + document.addEventListener("click", close); + document.addEventListener("touch", close); + window.addEventListener("popstate", remove); + + if (width > card.offsetWidth) { + images.hotline = new core.hotline( + json.product.id, + images, + ); + images.hotline.step = -0.3; + images.hotline.wheel = true; + images.hotline.touch = true; + images.hotline.start(); + } + } + } + }); + } + } + }; + } + } + }); + }); + }) +); diff --git a/mirzaev/arming_bot/system/public/js/core.js b/mirzaev/arming_bot/system/public/js/core.js new file mode 100755 index 0000000..b35dd0d --- /dev/null +++ b/mirzaev/arming_bot/system/public/js/core.js @@ -0,0 +1,52 @@ +"use strict"; + +// Initialize of the class in global namespace +const core = class core { + // Domain + static domain = window.location.hostname; + + // Language + static language = "ru"; + + // Label for the "loding" element + static loading = document.getElementById("loading"); + + // Label for the
element + static header = document.body.getElementsByTagName("header")[0]; + + // Label for the