From a01e2034f8b52fd5ece5d6d60b0f15799da5fe5c Mon Sep 17 00:00:00 2001
From: Mateusz Charytoniuk <mateusz.charytoniuk@protonmail.com>
Date: Mon, 8 Jul 2024 23:32:24 +0200
Subject: [PATCH] feat: support ML models

---
 .../features/ai/machine-learning/index.md     |  140 ++
 .../docs/features/machine-learning/index.md   |   12 -
 docs/pages/index.md                           |  178 ++-
 .../index.md                                  |    2 +-
 examples/machine-learning/.gitignore          |    1 +
 examples/machine-learning/README.md           |   11 -
 .../app/Command/TrainIris.php                 |   66 +
 .../app/HttpResponder/Homepage.php            |   21 -
 .../app/HttpResponder/Predict.php             |   45 +
 .../machine-learning/app/HttpRouteSymbol.php  |   17 -
 examples/machine-learning/composer.json       |    4 +-
 examples/machine-learning/composer.lock       | 1283 ++++++++++++++++-
 .../machine-learning/datasets/iris.ndjson     |  150 ++
 examples/machine-learning/models/.gitignore   |    2 +
 resources/css/docs-page-homepage.css          |   87 +-
 15 files changed, 1790 insertions(+), 229 deletions(-)
 create mode 100644 docs/pages/docs/features/ai/machine-learning/index.md
 delete mode 100644 docs/pages/docs/features/machine-learning/index.md
 create mode 100644 examples/machine-learning/app/Command/TrainIris.php
 delete mode 100644 examples/machine-learning/app/HttpResponder/Homepage.php
 create mode 100644 examples/machine-learning/app/HttpResponder/Predict.php
 delete mode 100644 examples/machine-learning/app/HttpRouteSymbol.php
 create mode 100644 examples/machine-learning/datasets/iris.ndjson
 create mode 100644 examples/machine-learning/models/.gitignore

diff --git a/docs/pages/docs/features/ai/machine-learning/index.md b/docs/pages/docs/features/ai/machine-learning/index.md
new file mode 100644
index 00000000..146b705b
--- /dev/null
+++ b/docs/pages/docs/features/ai/machine-learning/index.md
@@ -0,0 +1,140 @@
+---
+collections: 
+    - documents
+layout: dm:document
+parent: docs/features/ai/index
+title: Machine Learning
+description: >
+    Incorporate Machine Learning models into your application.
+---
+
+# Machine Learning
+
+Resonance integrates with [Rubix ML](https://rubixml.com/) to serve Machine Learning models. Rubix ML is a high-level machine learning library that allows you to train and serve machine learning models.
+
+## Training
+
+Put your datasets in a place from which your application can access to them (for example `datasets` directory) and prepare `models` directory for the outputs.
+
+```php
+<?php
+
+declare(strict_types=1);
+
+namespace App\Command;
+
+use Distantmagic\Resonance\Attribute\ConsoleCommand;
+use Distantmagic\Resonance\Command;
+use Psr\Log\LoggerInterface;
+use Rubix\ML\Classifiers\KNearestNeighbors;
+use Rubix\ML\CrossValidation\Metrics\Accuracy;
+use Rubix\ML\Datasets\Labeled;
+use Rubix\ML\Extractors\NDJSON;
+use Rubix\ML\Persisters\Filesystem;
+use Rubix\ML\Serializers\RBX;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @see https://github.com/RubixML/Iris
+ */
+#[ConsoleCommand(
+    name: 'train:iris',
+    description: 'Train Iris Flower Classifier'
+)]
+final class TrainIris extends Command
+{
+    public function __construct(private LoggerInterface $logger)
+    {
+        parent::__construct();
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $this->logger->info('Loading data into memory');
+
+        $training = Labeled::fromIterator(new NDJSON(DM_ROOT.'/datasets/iris.ndjson'));
+
+        $testing = $training->randomize()->take(10);
+
+        $estimator = new KNearestNeighbors(5);
+
+        $this->logger->info('Training');
+
+        $estimator->train($training);
+
+        $this->logger->info('Making predictions');
+
+        $predictions = $estimator->predict($testing);
+
+        $metric = new Accuracy();
+
+        $score = $metric->score($predictions, $testing->labels());
+
+        $this->logger->info("Accuracy is $score");
+        $this->logger->info('Serializing');
+
+        $serializer = new RBX();
+        $encoding = $serializer->serialize($estimator);
+
+        $filesystemPersister = new Filesystem(DM_ROOT.'/models/iris.model');
+        $filesystemPersister->save($encoding);
+
+        return Command::SUCCESS;
+    }
+}
+```
+
+## Serving
+
+After the model is trained, you can serve responses from a specific responder in your application.
+
+It must be loaded in the constructor so the model will be loaded during runtime. Resonance will keep it in the memory and serve predictions from it. You can use the same server as for the rest of your application.
+
+```php
+<?php
+
+declare(strict_types=1);
+
+namespace App\HttpResponder;
+
+use Distantmagic\Resonance\Attribute\RespondsToHttp;
+use Distantmagic\Resonance\Attribute\Singleton;
+use Distantmagic\Resonance\HttpInterceptableInterface;
+use Distantmagic\Resonance\HttpResponder;
+use Distantmagic\Resonance\RequestMethod;
+use Distantmagic\Resonance\SingletonCollection;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Rubix\ML\Datasets\Unlabeled;
+use Rubix\ML\Estimator;
+use Rubix\ML\PersistentModel;
+use Rubix\ML\Persisters\Filesystem;
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+#[RespondsToHttp(
+    method: RequestMethod::POST,
+    pattern: '/predict',
+)]
+#[Singleton(collection: SingletonCollection::HttpResponder)]
+readonly class Predict extends HttpResponder
+{
+    private Estimator $model;
+
+    public function __construct()
+    {
+        $this->model = PersistentModel::load(new Filesystem(DM_ROOT.'/models/iris.model'));
+    }
+
+    public function respond(
+        ServerRequestInterface $request,
+        ResponseInterface $response,
+    ): HttpInterceptableInterface {
+        $dataset = new Unlabeled($request->getParsedBody());
+
+        $predictions = $this->model->predict($dataset);
+
+        return new JsonResponse($predictions);
+    }
+}
+```
\ No newline at end of file
diff --git a/docs/pages/docs/features/machine-learning/index.md b/docs/pages/docs/features/machine-learning/index.md
deleted file mode 100644
index e500b777..00000000
--- a/docs/pages/docs/features/machine-learning/index.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-collections: 
-    - documents
-draft: true
-layout: dm:document
-parent: docs/features/index
-title: Machine Learning
-description: >
-    Learn how to incorporate Machine Learning features into your application.
----
-
-# Machine Leargning
diff --git a/docs/pages/index.md b/docs/pages/index.md
index f37de498..c075a63c 100644
--- a/docs/pages/index.md
+++ b/docs/pages/index.md
@@ -43,69 +43,74 @@ description: >
         </hgroup>
     </div>
 </div>
-<div class="homepage-drivers">
-    <h3>Backend Drivers Support</h3>
-    <div class="homepage-drivers__items">
-        <a 
-            class="homepage-drivers__item homepage-drivers__item--swoole"
-            href="https://swoole.com/"
-            rel=”noopener noreferrer”
-            target="_blank"
-        >
-            <div class="homepage-drivers__item__background"></div>
-            <div class="homepage-drivers__item__name">
-                Swoole
-            </div>
-            <div class="homepage-drivers__item__state">
-                Supported since v0.1.0
-            </div>
-        </a>
-        <a 
-            class="homepage-drivers__item homepage-drivers__item--openswoole"
-            href="https://openswoole.com/"
-            rel=”noopener noreferrer”
-            target="_blank"
-        >
-            <div class="homepage-drivers__item__background"></div>
-            <div class="homepage-drivers__item__name">
-                OpenSwoole
-            </div>
-            <div class="homepage-drivers__item__state">
-                Supported since v0.1.0
-            </div>
-        </a>
-        <a 
-            class="homepage-drivers__item homepage-drivers__item--amphp"
-            href="https://amphp.org/"
-            rel=”noopener noreferrer”
-            target="_blank"
-        >
-            <div class="homepage-drivers__item__background"></div>
-            <div class="homepage-drivers__item__name">
-                AMPHP
-            </div>
-            <div class="homepage-drivers__item__state">
-                In progress
-            </div>
-        </a>
-        <a 
-            class="homepage-drivers__item homepage-drivers__item--other"
-            href="https://github.com/distantmagic/resonance/discussions"
-            target="_blank"
-        >
-            <div class="homepage-drivers__item__background"></div>
-            <div class="homepage-drivers__item__name">
-                Do you have a driver in mind?
-            </div>
-            <div class="homepage-drivers__item__state">
-                Start a discussion
-            </div>
-        </a>
-    </div>
+<div class="homepage-gallery homepage-gallery--reasons">
+    <h3>Why Resonance?</h3>
+    <ul class="homepage-gallery__grid">
+        <li class="homepage-gallery__item">
+            <h4>
+                <a href="/docs/features/">
+                    Predictable Performance
+                </a>
+            </h4>
+            <p>
+                Resonance is designed with a few priorities: no memory leaks, blocking operations, and garbage collector surprises.<br><br>
+                Most of the internals are read-only and stateless. After the application startup, nothing disturbs JIT and opcode (Reflection is only used during the application startup), so there are no surprise slowdowns during runtime.
+            </p>
+        </li>
+        <li class="homepage-gallery__item">
+            <h4>
+                <a href="/docs/features/">
+                    Opinionated
+                </a>
+            </h4>
+            <p>
+                All the libraries under the hood have been thoroughly tested to ensure they work together correctly, complement each other, and work perfectly under async environments.<br><br>
+                For example, Resonance implements custom <a href="https://www.doctrine-project.org/">Doctrine</a> drivers, so it uses Swoole's connection pools.
+            </p>
+        </li>
+        <li class="homepage-gallery__item">
+            <h4>
+                <a href="/docs/features/">
+                    Resolves Input/Output Issues
+                </a>
+            </h4>
+            <p>
+                Resonance is designed to handle IO-intensive tasks, such as serving Machine Learning models, handling WebSocket connections, and processing long-running HTTP requests.<br><br>
+                It views modern applications as a mix of services that communicate with each other asynchronously, including AI completions and ML inferences, so it provides a set of tools to make this communication as easy as possible.
+            </p>
+        </li>
+        <li class="homepage-gallery__item">
+            <h4>
+                <a href="/docs/features/">
+                    Complete Package
+                </a>
+            </h4>
+            <p>
+                Resonance includes everything you need to build a modern web application, from the HTTP server to the AI capabilities.<br><br>
+                It provides security features, HTML templating, integration with open-source LLMs, and provides capability to serve ML models.
+            </p>
+        </li>
+    </ul>
 </div>
-<div class="homepage-gallery">
+<div class="homepage-gallery homepage-gallery--releases">
     <h3>New Releases</h3>
     <ul class="homepage-gallery__items">
+        <li class="homepage-gallery__item">
+            <h4>
+                <a href="/docs/features/ai/machine-learning/">
+                    Serve Machine Learning Models
+                    <span class="homepage-gallery__version">v0.31.0</span>
+                </a>
+            </h4>
+            <p>
+                Resonance integrates with Rubix ML to serve Machine Learning
+                models in the same codebase as the rest of your application.
+            </p>
+            <a
+                class="homepage-gallery__item__learnmore"
+                href="/docs/features/ai/machine-learning/"
+            >Learn More</a>
+        </li>
         <li class="homepage-gallery__item">
             <h4>
                 <a href="/tutorials/semi-scripted-conversational-applications/">
@@ -346,6 +351,59 @@ readonly class CatAdopt implements PromptSubjectResponderInterface
         $response->write(" ((_((|))_))\n");
         $response->end();
     }
+}</code></pre>
+            </li>
+            <li class="formatted-content homepage__example">
+                <h2 class="homepage__example__title">
+                    Serve Machine Learning Models
+                </h2>
+                <div class="homepage__example__description">
+                    <p>
+                        Resonance integrates with
+                        <a href="https://rubixml.com/" target="_blank">Rubix ML</a>
+                        and allows you to serve Machine Learning models in the
+                        same codebase as the rest of your application.
+                    </p>
+                    <p>
+                        Resonance allows you to serve inferences from your
+                        models through HTTP, WebSocket, and other protocols.
+                    </p>
+                    <a
+                        class="homepage__cta homepage__cta--example"
+                        href="/docs/features/ai/"
+                    >
+                        Learn More
+                    </a>
+                </div>
+                <pre class="homepage__example__code fenced-code"><code
+                        class="language-php"
+                        data-controller="hljs"
+                        data-hljs-language-value="php"
+                    >#[RespondsToHttp(
+    method: RequestMethod::POST,
+    pattern: '/predict',
+)]
+#[Singleton(collection: SingletonCollection::HttpResponder)]
+readonly class Predict extends HttpResponder
+{
+    private Estimator $model;
+
+    public function __construct()
+    {
+        $this->model = PersistentModel::load(new Filesystem(DM_ROOT.'/models/iris.model'));
+    }
+
+    public function respond(
+        ServerRequestInterface $request,
+        ResponseInterface $response,
+    ): HttpInterceptableInterface
+    {
+        $dataset = new Unlabeled($request->getParsedBody());
+
+        $predictions = $this->model->predict($dataset);
+
+        return new JsonResponse($predictions);
+    }
 }</code></pre>
             </li>
             <li class="formatted-content homepage__example">
diff --git a/docs/pages/tutorials/how-to-setup-postfix-for-outgoing-emails/index.md b/docs/pages/tutorials/how-to-setup-postfix-for-outgoing-emails/index.md
index 292162c2..82e8ab83 100644
--- a/docs/pages/tutorials/how-to-setup-postfix-for-outgoing-emails/index.md
+++ b/docs/pages/tutorials/how-to-setup-postfix-for-outgoing-emails/index.md
@@ -32,7 +32,7 @@ warned.
 
 ## The Goal
 
-Our final goal is to be able to send transactional emails from our server and 
+Our final goal is to send transactional emails from our server and
 still be able to both receive and send them through 3rd party service provider. 
 Let me explain.
 
diff --git a/examples/machine-learning/.gitignore b/examples/machine-learning/.gitignore
index 69c3f320..29d06c4e 100644
--- a/examples/machine-learning/.gitignore
+++ b/examples/machine-learning/.gitignore
@@ -1,5 +1,6 @@
 /cache
 /config.ini
 /oauth2
+/repository
 /ssl
 /vendor
diff --git a/examples/machine-learning/README.md b/examples/machine-learning/README.md
index 8f8584a7..e69de29b 100644
--- a/examples/machine-learning/README.md
+++ b/examples/machine-learning/README.md
@@ -1,11 +0,0 @@
-# Resonance Project
-
-To start the project you need to:
-1. Install dependencies with `composer install`
-2. Create `config.ini` (you can copy `config.ini.example`)
-3. Run `php bin/resonance.php serve` in the terminal to start the server
-
-## Using SSL
-
-In order to use SSL you need to [generate SSL certificate for a local development](https://resonance.distantmagic.com/docs/extras/ssl-certificate-for-local-development.html)
-and uncomment SSL related settings in `app/Command/Serve.php`.
diff --git a/examples/machine-learning/app/Command/TrainIris.php b/examples/machine-learning/app/Command/TrainIris.php
new file mode 100644
index 00000000..9a95c6d0
--- /dev/null
+++ b/examples/machine-learning/app/Command/TrainIris.php
@@ -0,0 +1,66 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Command;
+
+use Distantmagic\Resonance\Attribute\ConsoleCommand;
+use Distantmagic\Resonance\Command;
+use Psr\Log\LoggerInterface;
+use Rubix\ML\Classifiers\KNearestNeighbors;
+use Rubix\ML\CrossValidation\Metrics\Accuracy;
+use Rubix\ML\Datasets\Labeled;
+use Rubix\ML\Extractors\NDJSON;
+use Rubix\ML\Persisters\Filesystem;
+use Rubix\ML\Serializers\RBX;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @see https://github.com/RubixML/Iris
+ */
+#[ConsoleCommand(
+    name: 'train:iris',
+    description: 'Train Iris Flower Classifier'
+)]
+final class TrainIris extends Command
+{
+    public function __construct(private LoggerInterface $logger)
+    {
+        parent::__construct();
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $this->logger->info('Loading data into memory');
+
+        $training = Labeled::fromIterator(new NDJSON(DM_ROOT.'/datasets/iris.ndjson'));
+
+        $testing = $training->randomize()->take(10);
+
+        $estimator = new KNearestNeighbors(5);
+
+        $this->logger->info('Training');
+
+        $estimator->train($training);
+
+        $this->logger->info('Making predictions');
+
+        $predictions = $estimator->predict($testing);
+
+        $metric = new Accuracy();
+
+        $score = $metric->score($predictions, $testing->labels());
+
+        $this->logger->info("Accuracy is $score");
+        $this->logger->info('Serializing');
+
+        $serializer = new RBX();
+        $encoding = $serializer->serialize($estimator);
+
+        $filesystemPersister = new Filesystem(DM_ROOT.'/models/iris.model');
+        $filesystemPersister->save($encoding);
+
+        return Command::SUCCESS;
+    }
+}
diff --git a/examples/machine-learning/app/HttpResponder/Homepage.php b/examples/machine-learning/app/HttpResponder/Homepage.php
deleted file mode 100644
index d04ce6ee..00000000
--- a/examples/machine-learning/app/HttpResponder/Homepage.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\HttpResponder;
-
-use App\HttpRouteSymbol;
-use Distantmagic\Resonance\Attribute\RespondsToHttp;
-use Distantmagic\Resonance\HttpInterceptableInterface;
-use Distantmagic\Resonance\RequestMethod;
-use Distantmagic\Resonance\TwigTemplate;
-
-#[RespondsToHttp(
-    method: RequestMethod::GET,
-    pattern: '/',
-    routeSymbol: HttpRouteSymbol::Homepage,
-)]
-function Homepage(): HttpInterceptableInterface
-{
-    return new TwigTemplate('homepage.twig');
-}
diff --git a/examples/machine-learning/app/HttpResponder/Predict.php b/examples/machine-learning/app/HttpResponder/Predict.php
new file mode 100644
index 00000000..276c3900
--- /dev/null
+++ b/examples/machine-learning/app/HttpResponder/Predict.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\HttpResponder;
+
+use Distantmagic\Resonance\Attribute\RespondsToHttp;
+use Distantmagic\Resonance\Attribute\Singleton;
+use Distantmagic\Resonance\HttpInterceptableInterface;
+use Distantmagic\Resonance\HttpResponder;
+use Distantmagic\Resonance\RequestMethod;
+use Distantmagic\Resonance\SingletonCollection;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Rubix\ML\Datasets\Unlabeled;
+use Rubix\ML\Estimator;
+use Rubix\ML\PersistentModel;
+use Rubix\ML\Persisters\Filesystem;
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+#[RespondsToHttp(
+    method: RequestMethod::POST,
+    pattern: '/predict',
+)]
+#[Singleton(collection: SingletonCollection::HttpResponder)]
+readonly class Predict extends HttpResponder
+{
+    private Estimator $model;
+
+    public function __construct()
+    {
+        $this->model = PersistentModel::load(new Filesystem(DM_ROOT.'/models/iris.model'));
+    }
+
+    public function respond(
+        ServerRequestInterface $request,
+        ResponseInterface $response,
+    ): HttpInterceptableInterface {
+        $dataset = new Unlabeled($request->getParsedBody());
+
+        $predictions = $this->model->predict($dataset);
+
+        return new JsonResponse($predictions);
+    }
+}
diff --git a/examples/machine-learning/app/HttpRouteSymbol.php b/examples/machine-learning/app/HttpRouteSymbol.php
deleted file mode 100644
index 19ae41dc..00000000
--- a/examples/machine-learning/app/HttpRouteSymbol.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App;
-
-use Distantmagic\Resonance\CastableEnumTrait;
-use Distantmagic\Resonance\HttpRouteSymbolInterface;
-use Distantmagic\Resonance\NameableEnumTrait;
-
-enum HttpRouteSymbol implements HttpRouteSymbolInterface
-{
-    use CastableEnumTrait;
-    use NameableEnumTrait;
-
-    case Homepage;
-}
diff --git a/examples/machine-learning/composer.json b/examples/machine-learning/composer.json
index 787cb3ec..573d06b9 100644
--- a/examples/machine-learning/composer.json
+++ b/examples/machine-learning/composer.json
@@ -15,7 +15,7 @@
     "repositories": [
         {
             "type": "path",
-            "url": "vendor/distantmagic/resonance",
+            "url": "./repository",
             "options": {
                 "symlink": true
             }
@@ -32,7 +32,7 @@
         "symlink-resonance": [
             "mkdir -p vendor/distantmagic",
             "rm -rf vendor/distantmagic/resonance",
-            "ln -s -f ../../ vendor/distantmagic/resonance"
+            "ln -s -f ../../ ./repository"
         ],
         "pre-install-cmd": "@symlink-resonance",
         "pre-update-cmd": "@symlink-resonance"
diff --git a/examples/machine-learning/composer.lock b/examples/machine-learning/composer.lock
index 13349880..4655dbf3 100644
--- a/examples/machine-learning/composer.lock
+++ b/examples/machine-learning/composer.lock
@@ -4,8 +4,558 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "bb2774153ef8f6246168ad2bebbf7e65",
+    "content-hash": "2ee2a0f3683eaff1e6a4d9f9b814dea8",
     "packages": [
+        {
+            "name": "amphp/amp",
+            "version": "v2.6.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/amp.git",
+                "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/amp/zipball/ded3d9be08f526089eb7ee8d9f16a9768f9dec2d",
+                "reference": "ded3d9be08f526089eb7ee8d9f16a9768f9dec2d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "amphp/phpunit-util": "^1",
+                "ext-json": "*",
+                "jetbrains/phpstorm-stubs": "^2019.3",
+                "phpunit/phpunit": "^7 | ^8 | ^9",
+                "react/promise": "^2",
+                "vimeo/psalm": "^3.12"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "lib/functions.php",
+                    "lib/Internal/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\": "lib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Daniel Lowrey",
+                    "email": "rdlowrey@php.net"
+                },
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Bob Weinand",
+                    "email": "bobwei9@hotmail.com"
+                },
+                {
+                    "name": "Niklas Keller",
+                    "email": "me@kelunik.com"
+                }
+            ],
+            "description": "A non-blocking concurrency framework for PHP applications.",
+            "homepage": "https://amphp.org/amp",
+            "keywords": [
+                "async",
+                "asynchronous",
+                "awaitable",
+                "concurrency",
+                "event",
+                "event-loop",
+                "future",
+                "non-blocking",
+                "promise"
+            ],
+            "support": {
+                "irc": "irc://irc.freenode.org/amphp",
+                "issues": "https://github.com/amphp/amp/issues",
+                "source": "https://github.com/amphp/amp/tree/v2.6.4"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-21T18:52:26+00:00"
+        },
+        {
+            "name": "amphp/byte-stream",
+            "version": "v1.8.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/byte-stream.git",
+                "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/byte-stream/zipball/4f0e968ba3798a423730f567b1b50d3441c16ddc",
+                "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc",
+                "shasum": ""
+            },
+            "require": {
+                "amphp/amp": "^2",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "amphp/phpunit-util": "^1.4",
+                "friendsofphp/php-cs-fixer": "^2.3",
+                "jetbrains/phpstorm-stubs": "^2019.3",
+                "phpunit/phpunit": "^6 || ^7 || ^8",
+                "psalm/phar": "^3.11.4"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\ByteStream\\": "lib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Niklas Keller",
+                    "email": "me@kelunik.com"
+                }
+            ],
+            "description": "A stream abstraction to make working with non-blocking I/O simple.",
+            "homepage": "https://amphp.org/byte-stream",
+            "keywords": [
+                "amp",
+                "amphp",
+                "async",
+                "io",
+                "non-blocking",
+                "stream"
+            ],
+            "support": {
+                "issues": "https://github.com/amphp/byte-stream/issues",
+                "source": "https://github.com/amphp/byte-stream/tree/v1.8.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-04-13T18:00:56+00:00"
+        },
+        {
+            "name": "amphp/parallel",
+            "version": "v1.4.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/parallel.git",
+                "reference": "3aac213ba7858566fd83d38ccb85b91b2d652cb0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/parallel/zipball/3aac213ba7858566fd83d38ccb85b91b2d652cb0",
+                "reference": "3aac213ba7858566fd83d38ccb85b91b2d652cb0",
+                "shasum": ""
+            },
+            "require": {
+                "amphp/amp": "^2",
+                "amphp/byte-stream": "^1.6.1",
+                "amphp/parser": "^1",
+                "amphp/process": "^1",
+                "amphp/serialization": "^1",
+                "amphp/sync": "^1.0.1",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "amphp/phpunit-util": "^1.1",
+                "phpunit/phpunit": "^8 || ^7"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/Context/functions.php",
+                    "lib/Sync/functions.php",
+                    "lib/Worker/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\Parallel\\": "lib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Stephen Coakley",
+                    "email": "me@stephencoakley.com"
+                }
+            ],
+            "description": "Parallel processing component for Amp.",
+            "homepage": "https://github.com/amphp/parallel",
+            "keywords": [
+                "async",
+                "asynchronous",
+                "concurrent",
+                "multi-processing",
+                "multi-threading"
+            ],
+            "support": {
+                "issues": "https://github.com/amphp/parallel/issues",
+                "source": "https://github.com/amphp/parallel/tree/v1.4.3"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-03-23T08:04:23+00:00"
+        },
+        {
+            "name": "amphp/parser",
+            "version": "v1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/parser.git",
+                "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7",
+                "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.4"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "^2",
+                "phpunit/phpunit": "^9",
+                "psalm/phar": "^5.4"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Amp\\Parser\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Niklas Keller",
+                    "email": "me@kelunik.com"
+                }
+            ],
+            "description": "A generator parser to make streaming parsers simple.",
+            "homepage": "https://github.com/amphp/parser",
+            "keywords": [
+                "async",
+                "non-blocking",
+                "parser",
+                "stream"
+            ],
+            "support": {
+                "issues": "https://github.com/amphp/parser/issues",
+                "source": "https://github.com/amphp/parser/tree/v1.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-21T19:16:53+00:00"
+        },
+        {
+            "name": "amphp/process",
+            "version": "v1.1.7",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/process.git",
+                "reference": "1949d85b6d71af2818ff68144304a98495628f19"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/process/zipball/1949d85b6d71af2818ff68144304a98495628f19",
+                "reference": "1949d85b6d71af2818ff68144304a98495628f19",
+                "shasum": ""
+            },
+            "require": {
+                "amphp/amp": "^2",
+                "amphp/byte-stream": "^1.4",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "amphp/phpunit-util": "^1",
+                "phpunit/phpunit": "^6"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\Process\\": "lib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Bob Weinand",
+                    "email": "bobwei9@hotmail.com"
+                },
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Niklas Keller",
+                    "email": "me@kelunik.com"
+                }
+            ],
+            "description": "Asynchronous process manager.",
+            "homepage": "https://github.com/amphp/process",
+            "support": {
+                "issues": "https://github.com/amphp/process/issues",
+                "source": "https://github.com/amphp/process/tree/v1.1.7"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-04-19T03:00:28+00:00"
+        },
+        {
+            "name": "amphp/serialization",
+            "version": "v1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/serialization.git",
+                "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1",
+                "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "phpunit/phpunit": "^9 || ^8 || ^7"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\Serialization\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Niklas Keller",
+                    "email": "me@kelunik.com"
+                }
+            ],
+            "description": "Serialization tools for IPC and data storage in PHP.",
+            "homepage": "https://github.com/amphp/serialization",
+            "keywords": [
+                "async",
+                "asynchronous",
+                "serialization",
+                "serialize"
+            ],
+            "support": {
+                "issues": "https://github.com/amphp/serialization/issues",
+                "source": "https://github.com/amphp/serialization/tree/master"
+            },
+            "time": "2020-03-25T21:39:07+00:00"
+        },
+        {
+            "name": "amphp/sync",
+            "version": "v1.4.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/amphp/sync.git",
+                "reference": "85ab06764f4f36d63b1356b466df6111cf4b89cf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/amphp/sync/zipball/85ab06764f4f36d63b1356b466df6111cf4b89cf",
+                "reference": "85ab06764f4f36d63b1356b466df6111cf4b89cf",
+                "shasum": ""
+            },
+            "require": {
+                "amphp/amp": "^2.2",
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "amphp/php-cs-fixer-config": "dev-master",
+                "amphp/phpunit-util": "^1.1",
+                "phpunit/phpunit": "^9 || ^8 || ^7"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/functions.php",
+                    "src/ConcurrentIterator/functions.php"
+                ],
+                "psr-4": {
+                    "Amp\\Sync\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Piotrowski",
+                    "email": "aaron@trowski.com"
+                },
+                {
+                    "name": "Stephen Coakley",
+                    "email": "me@stephencoakley.com"
+                }
+            ],
+            "description": "Mutex, Semaphore, and other synchronization tools for Amp.",
+            "homepage": "https://github.com/amphp/sync",
+            "keywords": [
+                "async",
+                "asynchronous",
+                "mutex",
+                "semaphore",
+                "synchronization"
+            ],
+            "support": {
+                "issues": "https://github.com/amphp/sync/issues",
+                "source": "https://github.com/amphp/sync/tree/v1.4.2"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/amphp",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-10-25T18:29:10+00:00"
+        },
+        {
+            "name": "andrewdalpino/okbloomer",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/andrewdalpino/OkBloomer.git",
+                "reference": "39321cb515c1e99128d28489b0187120ba7ce84c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/andrewdalpino/OkBloomer/zipball/39321cb515c1e99128d28489b0187120ba7ce84c",
+                "reference": "39321cb515c1e99128d28489b0187120ba7ce84c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.4"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3.0",
+                "phpbench/phpbench": "^1.0",
+                "phpstan/extension-installer": "^1.0",
+                "phpstan/phpstan": "^1.0",
+                "phpstan/phpstan-phpunit": "^1.0",
+                "phpunit/phpunit": "^9.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "OkBloomer\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Andrew DalPino",
+                    "email": "support@andrewdalpino.com",
+                    "homepage": "https://github.com/andrewdalpino",
+                    "role": "Lead Developer"
+                }
+            ],
+            "description": "An autoscaling Bloom filter with ultra-low memory usage for PHP.",
+            "keywords": [
+                "Bloom Filter",
+                "layered bloom filter",
+                "scalable bloom filter"
+            ],
+            "support": {
+                "docs": "https://github.com/andrewdalpino/OkBloomer/README.md",
+                "email": "support@andrewdalpino.com",
+                "issues": "https://github.com/andrewdalpino/OkBloomer/issues",
+                "source": "https://github.com/andrewdalpino/OkBloomer"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sponsors/andrewdalpino",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-01-24T03:41:23+00:00"
+        },
         {
             "name": "beberlei/assert",
             "version": "v3.3.2",
@@ -314,16 +864,10 @@
         {
             "name": "distantmagic/resonance",
             "version": "dev-master",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/distantmagic/resonance.git",
-                "reference": "51b67618b1300cfee7c3e719252c245b72f7b60c"
-            },
             "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/distantmagic/resonance/zipball/51b67618b1300cfee7c3e719252c245b72f7b60c",
-                "reference": "51b67618b1300cfee7c3e719252c245b72f7b60c",
-                "shasum": ""
+                "type": "path",
+                "url": "./repository",
+                "reference": "ac3620798e0b603fccc9d75871088c43946f00e1"
             },
             "require": {
                 "beberlei/assert": "^3.3",
@@ -353,6 +897,7 @@
                 "psr/http-server-handler": "^1.0",
                 "psr/log": "^3.0",
                 "ramsey/uuid": "^4.7",
+                "rubix/ml": "^2.5",
                 "symfony/console": "^7.0",
                 "symfony/doctrine-bridge": "^7.0",
                 "symfony/event-dispatcher": "^7.0",
@@ -386,7 +931,6 @@
                 "ext-redis": "HTTP Sessions driver",
                 "ext-uuid": "Faster UUID generation"
             },
-            "default-branch": true,
             "type": "library",
             "autoload": {
                 "files": [
@@ -400,7 +944,15 @@
                     "Distantmagic\\Resonance\\": "src/"
                 }
             },
-            "notification-url": "https://packagist.org/downloads/",
+            "archive": {
+                "exclude": [
+                    "/app",
+                    "/docs",
+                    "/examples",
+                    "/resources",
+                    "/tools"
+                ]
+            },
             "license": [
                 "MIT"
             ],
@@ -411,11 +963,10 @@
                 }
             ],
             "description": "PHP Framework with AI capabilities.",
-            "support": {
-                "issues": "https://github.com/distantmagic/resonance/issues",
-                "source": "https://github.com/distantmagic/resonance/tree/master"
-            },
-            "time": "2024-06-18T18:01:57+00:00"
+            "transport-options": {
+                "symlink": true,
+                "relative": true
+            }
         },
         {
             "name": "distantmagic/swoole-futures",
@@ -5067,6 +5618,270 @@
             ],
             "time": "2024-04-27T21:32:50+00:00"
         },
+        {
+            "name": "rubix/ml",
+            "version": "2.5.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/RubixML/ML.git",
+                "reference": "d43a5f2cd714277c10f74096cc5776ce4c828354"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/RubixML/ML/zipball/d43a5f2cd714277c10f74096cc5776ce4c828354",
+                "reference": "d43a5f2cd714277c10f74096cc5776ce4c828354",
+                "shasum": ""
+            },
+            "require": {
+                "amphp/parallel": "^1.3",
+                "andrewdalpino/okbloomer": "^1.0",
+                "ext-json": "*",
+                "php": ">=7.4",
+                "psr/log": "^1.1|^2.0|^3.0",
+                "rubix/tensor": "^3.0",
+                "symfony/polyfill-mbstring": "^1.0",
+                "symfony/polyfill-php80": "^1.17",
+                "symfony/polyfill-php82": "^1.27",
+                "symfony/polyfill-php83": "^1.27",
+                "wamania/php-stemmer": "^3.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3.0",
+                "phpbench/phpbench": "^1.0",
+                "phpstan/extension-installer": "^1.0",
+                "phpstan/phpstan": "^1.0",
+                "phpstan/phpstan-phpunit": "^1.0",
+                "phpunit/phpunit": "^9.0"
+            },
+            "suggest": {
+                "ext-gd": "For image support",
+                "ext-mbstring": "For fast multibyte string manipulation",
+                "ext-svm": "For Support Vector Machine engine (libsvm)",
+                "ext-tensor": "For fast Matrix/Vector computing"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/constants.php",
+                    "src/functions.php"
+                ],
+                "psr-4": {
+                    "Rubix\\ML\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Andrew DalPino",
+                    "homepage": "https://github.com/andrewdalpino"
+                },
+                {
+                    "name": "Contributors",
+                    "homepage": "https://github.com/RubixML/ML/graphs/contributors"
+                }
+            ],
+            "description": "A high-level machine learning and deep learning library for the PHP language.",
+            "homepage": "https://rubixml.com",
+            "keywords": [
+                "Algorithm",
+                "Deep learning",
+                "Linear regression",
+                "Neural network",
+                "Rubix",
+                "TF-IDF",
+                "adaboost",
+                "ai",
+                "analytics",
+                "anomaly detection",
+                "artificial intelligence",
+                "cart",
+                "classification",
+                "classifier",
+                "clustering",
+                "cross validation",
+                "data mining",
+                "data science",
+                "dataset",
+                "dbscan",
+                "dimensionality reduction",
+                "ensemble",
+                "estimator",
+                "etl",
+                "feature extraction",
+                "feature importance",
+                "feature selection",
+                "gaussian mixture",
+                "gbm",
+                "gmm",
+                "gradient boost",
+                "grid search",
+                "image recognition",
+                "imputation",
+                "inference",
+                "isolation forest",
+                "k-means",
+                "k-nearest neighbors",
+                "kmeans",
+                "knn",
+                "local outlier factor",
+                "loda",
+                "lof",
+                "logistic regression",
+                "machine learning",
+                "manifold learning",
+                "mean shift",
+                "ml",
+                "mlp",
+                "multilayer perceptron",
+                "naive bayes",
+                "natural language processing",
+                "nearest neighbors",
+                "nlp",
+                "outlier detection",
+                "php",
+                "php ai",
+                "php machine learning",
+                "php ml",
+                "prediction",
+                "predictive modeling",
+                "random forest",
+                "ranking",
+                "recommendation",
+                "regression",
+                "regressor",
+                "ridge",
+                "rubix ml",
+                "rubixml",
+                "softmax",
+                "supervised learning",
+                "support vector machine",
+                "svm",
+                "t-sne",
+                "text mining",
+                "tf idf",
+                "tsne",
+                "unsupervised learning"
+            ],
+            "support": {
+                "chat": "https://t.me/RubixML",
+                "docs": "https://docs.rubixml.com",
+                "issues": "https://github.com/RubixML/ML/issues",
+                "source": "https://github.com/RubixML/ML"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/sponsors/andrewdalpino",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-05-23T17:44:44+00:00"
+        },
+        {
+            "name": "rubix/tensor",
+            "version": "3.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/RubixML/Tensor.git",
+                "reference": "9f0ee170319280dcf081984adccefa8b0e6f06b8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/RubixML/Tensor/zipball/9f0ee170319280dcf081984adccefa8b0e6f06b8",
+                "reference": "9f0ee170319280dcf081984adccefa8b0e6f06b8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.4"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3.0",
+                "phalcon/zephir": "^0.17",
+                "phpbench/phpbench": "^1.0",
+                "phpstan/extension-installer": "^1.0",
+                "phpstan/phpstan": "^1.0",
+                "phpstan/phpstan-phpunit": "^1.0",
+                "phpunit/phpunit": "^9.0"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/constants.php"
+                ],
+                "psr-4": {
+                    "Tensor\\": "src/",
+                    "Zephir\\Optimizers\\FunctionCall\\": "optimizers/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Andrew DalPino",
+                    "email": "support@andrewdalpino.com",
+                    "homepage": "https://github.com/andrewdalpino",
+                    "role": "Project Lead"
+                },
+                {
+                    "name": "Contributors",
+                    "homepage": "https://github.com/RubixML/Tensor/graphs/contributors"
+                }
+            ],
+            "description": "A library and extension that provides objects for scientific computing in PHP.",
+            "homepage": "https://github.com/RubixML/Tensor",
+            "keywords": [
+                "1d convolution",
+                "2d convolution",
+                "arithmetic",
+                "blas",
+                "computation",
+                "computing",
+                "convolution",
+                "decomposition",
+                "dot product",
+                "eigendecomposition",
+                "eigenvalue",
+                "eigenvector",
+                "engineering",
+                "extension",
+                "lapack",
+                "linear algebra",
+                "math",
+                "matmul",
+                "matrix",
+                "matrix multiplication",
+                "multithreaded",
+                "php",
+                "php extension",
+                "pseudoinverse",
+                "scientific computing",
+                "signal processing",
+                "singular value decomposition",
+                "statistics",
+                "svd",
+                "tensor",
+                "trigonometry",
+                "vector",
+                "vector norm"
+            ],
+            "support": {
+                "chat": "https://t.me/RubixML",
+                "email": "support@andrewdalpino.com",
+                "issues": "https://github.com/RubixML/Tensor/issues",
+                "source": "https://github.com/RubixML/Tensor"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/andrewdalpino",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-15T19:43:50+00:00"
+        },
         {
             "name": "symfony/cache",
             "version": "v7.1.2",
@@ -6386,11 +7201,88 @@
             "type": "library",
             "autoload": {
                 "psr-4": {
-                    "Symfony\\Component\\Mime\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
+                    "Symfony\\Component\\Mime\\": ""
+                },
+                "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 manipulating MIME messages",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "mime",
+                "mime-type"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/mime/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/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": [
@@ -6398,22 +7290,24 @@
             ],
             "authors": [
                 {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
                 },
                 {
                     "name": "Symfony Community",
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Allows manipulating MIME messages",
+            "description": "Symfony polyfill for ctype functions",
             "homepage": "https://symfony.com",
             "keywords": [
-                "mime",
-                "mime-type"
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
             ],
             "support": {
-                "source": "https://github.com/symfony/mime/tree/v7.1.2"
+                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
             },
             "funding": [
                 {
@@ -6429,30 +7323,30 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-06-28T10:03:55+00:00"
+            "time": "2024-05-31T15:07:36+00:00"
         },
         {
-            "name": "symfony/polyfill-ctype",
+            "name": "symfony/polyfill-iconv",
             "version": "v1.30.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "0424dff1c58f028c451efff2045f5d92410bd540"
+                "url": "https://github.com/symfony/polyfill-iconv.git",
+                "reference": "c027e6a3c6aee334663ec21f5852e89738abc805"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
-                "reference": "0424dff1c58f028c451efff2045f5d92410bd540",
+                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/c027e6a3c6aee334663ec21f5852e89738abc805",
+                "reference": "c027e6a3c6aee334663ec21f5852e89738abc805",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.1"
             },
             "provide": {
-                "ext-ctype": "*"
+                "ext-iconv": "*"
             },
             "suggest": {
-                "ext-ctype": "For best performance"
+                "ext-iconv": "For best performance"
             },
             "type": "library",
             "extra": {
@@ -6466,7 +7360,7 @@
                     "bootstrap.php"
                 ],
                 "psr-4": {
-                    "Symfony\\Polyfill\\Ctype\\": ""
+                    "Symfony\\Polyfill\\Iconv\\": ""
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -6475,24 +7369,25 @@
             ],
             "authors": [
                 {
-                    "name": "Gert de Pagter",
-                    "email": "BackEndTea@gmail.com"
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
                 },
                 {
                     "name": "Symfony Community",
                     "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Symfony polyfill for ctype functions",
+            "description": "Symfony polyfill for the Iconv extension",
             "homepage": "https://symfony.com",
             "keywords": [
                 "compatibility",
-                "ctype",
+                "iconv",
                 "polyfill",
-                "portable"
+                "portable",
+                "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
+                "source": "https://github.com/symfony/polyfill-iconv/tree/v1.30.0"
             },
             "funding": [
                 {
@@ -6986,6 +7881,82 @@
             ],
             "time": "2024-05-31T15:07:36+00:00"
         },
+        {
+            "name": "symfony/polyfill-php82",
+            "version": "v1.30.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php82.git",
+                "reference": "77ff49780f56906788a88974867ed68bc49fae5b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/77ff49780f56906788a88974867ed68bc49fae5b",
+                "reference": "77ff49780f56906788a88974867ed68bc49fae5b",
+                "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\\Php82\\": ""
+                },
+                "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.2+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php82/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",
@@ -8158,6 +9129,232 @@
             ],
             "time": "2024-05-16T10:04:27+00:00"
         },
+        {
+            "name": "voku/portable-ascii",
+            "version": "2.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/voku/portable-ascii.git",
+                "reference": "b56450eed252f6801410d810c8e1727224ae0743"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743",
+                "reference": "b56450eed252f6801410d810c8e1727224ae0743",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0"
+            },
+            "suggest": {
+                "ext-intl": "Use Intl for transliterator_transliterate() support"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "voku\\": "src/voku/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Lars Moelleken",
+                    "homepage": "http://www.moelleken.org/"
+                }
+            ],
+            "description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
+            "homepage": "https://github.com/voku/portable-ascii",
+            "keywords": [
+                "ascii",
+                "clean",
+                "php"
+            ],
+            "support": {
+                "issues": "https://github.com/voku/portable-ascii/issues",
+                "source": "https://github.com/voku/portable-ascii/tree/2.0.1"
+            },
+            "funding": [
+                {
+                    "url": "https://www.paypal.me/moelleken",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/voku",
+                    "type": "github"
+                },
+                {
+                    "url": "https://opencollective.com/portable-ascii",
+                    "type": "open_collective"
+                },
+                {
+                    "url": "https://www.patreon.com/voku",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-03-08T17:03:00+00:00"
+        },
+        {
+            "name": "voku/portable-utf8",
+            "version": "6.0.13",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/voku/portable-utf8.git",
+                "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/voku/portable-utf8/zipball/b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
+                "reference": "b8ce36bf26593e5c2e81b1850ef0ffb299d2043f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.0",
+                "symfony/polyfill-iconv": "~1.0",
+                "symfony/polyfill-intl-grapheme": "~1.0",
+                "symfony/polyfill-intl-normalizer": "~1.0",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php72": "~1.0",
+                "voku/portable-ascii": "~2.0.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "1.9.*@dev",
+                "phpstan/phpstan-strict-rules": "1.4.*@dev",
+                "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0",
+                "thecodingmachine/phpstan-strict-rules": "1.0.*@dev",
+                "voku/phpstan-rules": "3.1.*@dev"
+            },
+            "suggest": {
+                "ext-ctype": "Use Ctype for e.g. hexadecimal digit detection",
+                "ext-fileinfo": "Use Fileinfo for better binary file detection",
+                "ext-iconv": "Use iconv for best performance",
+                "ext-intl": "Use Intl for best performance",
+                "ext-json": "Use JSON for string detection",
+                "ext-mbstring": "Use Mbstring for best performance"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "voku\\": "src/voku/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "(Apache-2.0 or GPL-2.0)"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Hamid Sarfraz",
+                    "homepage": "http://pageconfig.com/"
+                },
+                {
+                    "name": "Lars Moelleken",
+                    "homepage": "http://www.moelleken.org/"
+                }
+            ],
+            "description": "Portable UTF-8 library - performance optimized (unicode) string functions for php.",
+            "homepage": "https://github.com/voku/portable-utf8",
+            "keywords": [
+                "UTF",
+                "clean",
+                "php",
+                "unicode",
+                "utf-8",
+                "utf8"
+            ],
+            "support": {
+                "issues": "https://github.com/voku/portable-utf8/issues",
+                "source": "https://github.com/voku/portable-utf8/tree/6.0.13"
+            },
+            "funding": [
+                {
+                    "url": "https://www.paypal.me/moelleken",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/voku",
+                    "type": "github"
+                },
+                {
+                    "url": "https://opencollective.com/portable-utf8",
+                    "type": "open_collective"
+                },
+                {
+                    "url": "https://www.patreon.com/voku",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/voku/portable-utf8",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2023-03-08T08:35:38+00:00"
+        },
+        {
+            "name": "wamania/php-stemmer",
+            "version": "v3.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/wamania/php-stemmer.git",
+                "reference": "8ea32b6fa27d6888587fe860b64a8763525c5a66"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/wamania/php-stemmer/zipball/8ea32b6fa27d6888587fe860b64a8763525c5a66",
+                "reference": "8ea32b6fa27d6888587fe860b64a8763525c5a66",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "voku/portable-utf8": "^5.4|^6.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Wamania\\Snowball\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Wamania",
+                    "homepage": "http://wamania.com"
+                }
+            ],
+            "description": "Native PHP Stemmer",
+            "keywords": [
+                "php",
+                "porter",
+                "stemmer"
+            ],
+            "support": {
+                "issues": "https://github.com/wamania/php-stemmer/issues",
+                "source": "https://github.com/wamania/php-stemmer/tree/v3.0.1"
+            },
+            "time": "2023-05-11T10:50:27+00:00"
+        },
         {
             "name": "webmozart/assert",
             "version": "1.11.0",
diff --git a/examples/machine-learning/datasets/iris.ndjson b/examples/machine-learning/datasets/iris.ndjson
new file mode 100644
index 00000000..85e861c8
--- /dev/null
+++ b/examples/machine-learning/datasets/iris.ndjson
@@ -0,0 +1,150 @@
+[5.1,3.5,1.4,0.2,"Iris-setosa"]
+[4.9,3,1.4,0.2,"Iris-setosa"]
+[4.7,3.2,1.3,0.2,"Iris-setosa"]
+[4.6,3.1,1.5,0.2,"Iris-setosa"]
+[5,3.6,1.4,0.2,"Iris-setosa"]
+[5.4,3.9,1.7,0.4,"Iris-setosa"]
+[4.6,3.4,1.4,0.3,"Iris-setosa"]
+[5,3.4,1.5,0.2,"Iris-setosa"]
+[4.4,2.9,1.4,0.2,"Iris-setosa"]
+[4.9,3.1,1.5,0.1,"Iris-setosa"]
+[5.4,3.7,1.5,0.2,"Iris-setosa"]
+[4.8,3.4,1.6,0.2,"Iris-setosa"]
+[4.8,3,1.4,0.1,"Iris-setosa"]
+[4.3,3,1.1,0.1,"Iris-setosa"]
+[5.8,4,1.2,0.2,"Iris-setosa"]
+[5.7,4.4,1.5,0.4,"Iris-setosa"]
+[5.4,3.9,1.3,0.4,"Iris-setosa"]
+[5.1,3.5,1.4,0.3,"Iris-setosa"]
+[5.7,3.8,1.7,0.3,"Iris-setosa"]
+[5.1,3.8,1.5,0.3,"Iris-setosa"]
+[5.4,3.4,1.7,0.2,"Iris-setosa"]
+[5.1,3.7,1.5,0.4,"Iris-setosa"]
+[4.6,3.6,1,0.2,"Iris-setosa"]
+[5.1,3.3,1.7,0.5,"Iris-setosa"]
+[4.8,3.4,1.9,0.2,"Iris-setosa"]
+[5,3,1.6,0.2,"Iris-setosa"]
+[5,3.4,1.6,0.4,"Iris-setosa"]
+[5.2,3.5,1.5,0.2,"Iris-setosa"]
+[5.2,3.4,1.4,0.2,"Iris-setosa"]
+[4.7,3.2,1.6,0.2,"Iris-setosa"]
+[4.8,3.1,1.6,0.2,"Iris-setosa"]
+[5.4,3.4,1.5,0.4,"Iris-setosa"]
+[5.2,4.1,1.5,0.1,"Iris-setosa"]
+[5.5,4.2,1.4,0.2,"Iris-setosa"]
+[4.9,3.1,1.5,0.1,"Iris-setosa"]
+[5,3.2,1.2,0.2,"Iris-setosa"]
+[5.5,3.5,1.3,0.2,"Iris-setosa"]
+[4.9,3.1,1.5,0.1,"Iris-setosa"]
+[4.4,3,1.3,0.2,"Iris-setosa"]
+[5.1,3.4,1.5,0.2,"Iris-setosa"]
+[5,3.5,1.3,0.3,"Iris-setosa"]
+[4.5,2.3,1.3,0.3,"Iris-setosa"]
+[4.4,3.2,1.3,0.2,"Iris-setosa"]
+[5,3.5,1.6,0.6,"Iris-setosa"]
+[5.1,3.8,1.9,0.4,"Iris-setosa"]
+[4.8,3,1.4,0.3,"Iris-setosa"]
+[5.1,3.8,1.6,0.2,"Iris-setosa"]
+[4.6,3.2,1.4,0.2,"Iris-setosa"]
+[5.3,3.7,1.5,0.2,"Iris-setosa"]
+[5,3.3,1.4,0.2,"Iris-setosa"]
+[7,3.2,4.7,1.4,"Iris-versicolor"]
+[6.4,3.2,4.5,1.5,"Iris-versicolor"]
+[6.9,3.1,4.9,1.5,"Iris-versicolor"]
+[5.5,2.3,4,1.3,"Iris-versicolor"]
+[6.5,2.8,4.6,1.5,"Iris-versicolor"]
+[5.7,2.8,4.5,1.3,"Iris-versicolor"]
+[6.3,3.3,4.7,1.6,"Iris-versicolor"]
+[4.9,2.4,3.3,1,"Iris-versicolor"]
+[6.6,2.9,4.6,1.3,"Iris-versicolor"]
+[5.2,2.7,3.9,1.4,"Iris-versicolor"]
+[5,2,3.5,1,"Iris-versicolor"]
+[5.9,3,4.2,1.5,"Iris-versicolor"]
+[6,2.2,4,1,"Iris-versicolor"]
+[6.1,2.9,4.7,1.4,"Iris-versicolor"]
+[5.6,2.9,3.6,1.3,"Iris-versicolor"]
+[6.7,3.1,4.4,1.4,"Iris-versicolor"]
+[5.6,3,4.5,1.5,"Iris-versicolor"]
+[5.8,2.7,4.1,1,"Iris-versicolor"]
+[6.2,2.2,4.5,1.5,"Iris-versicolor"]
+[5.6,2.5,3.9,1.1,"Iris-versicolor"]
+[5.9,3.2,4.8,1.8,"Iris-versicolor"]
+[6.1,2.8,4,1.3,"Iris-versicolor"]
+[6.3,2.5,4.9,1.5,"Iris-versicolor"]
+[6.1,2.8,4.7,1.2,"Iris-versicolor"]
+[6.4,2.9,4.3,1.3,"Iris-versicolor"]
+[6.6,3,4.4,1.4,"Iris-versicolor"]
+[6.8,2.8,4.8,1.4,"Iris-versicolor"]
+[6.7,3,5,1.7,"Iris-versicolor"]
+[6,2.9,4.5,1.5,"Iris-versicolor"]
+[5.7,2.6,3.5,1,"Iris-versicolor"]
+[5.5,2.4,3.8,1.1,"Iris-versicolor"]
+[5.5,2.4,3.7,1,"Iris-versicolor"]
+[5.8,2.7,3.9,1.2,"Iris-versicolor"]
+[6,2.7,5.1,1.6,"Iris-versicolor"]
+[5.4,3,4.5,1.5,"Iris-versicolor"]
+[6,3.4,4.5,1.6,"Iris-versicolor"]
+[6.7,3.1,4.7,1.5,"Iris-versicolor"]
+[6.3,2.3,4.4,1.3,"Iris-versicolor"]
+[5.6,3,4.1,1.3,"Iris-versicolor"]
+[5.5,2.5,4,1.3,"Iris-versicolor"]
+[5.5,2.6,4.4,1.2,"Iris-versicolor"]
+[6.1,3,4.6,1.4,"Iris-versicolor"]
+[5.8,2.6,4,1.2,"Iris-versicolor"]
+[5,2.3,3.3,1,"Iris-versicolor"]
+[5.6,2.7,4.2,1.3,"Iris-versicolor"]
+[5.7,3,4.2,1.2,"Iris-versicolor"]
+[5.7,2.9,4.2,1.3,"Iris-versicolor"]
+[6.2,2.9,4.3,1.3,"Iris-versicolor"]
+[5.1,2.5,3,1.1,"Iris-versicolor"]
+[5.7,2.8,4.1,1.3,"Iris-versicolor"]
+[6.3,3.3,6,2.5,"Iris-virginica"]
+[5.8,2.7,5.1,1.9,"Iris-virginica"]
+[7.1,3,5.9,2.1,"Iris-virginica"]
+[6.3,2.9,5.6,1.8,"Iris-virginica"]
+[6.5,3,5.8,2.2,"Iris-virginica"]
+[7.6,3,6.6,2.1,"Iris-virginica"]
+[4.9,2.5,4.5,1.7,"Iris-virginica"]
+[7.3,2.9,6.3,1.8,"Iris-virginica"]
+[6.7,2.5,5.8,1.8,"Iris-virginica"]
+[7.2,3.6,6.1,2.5,"Iris-virginica"]
+[6.5,3.2,5.1,2,"Iris-virginica"]
+[6.4,2.7,5.3,1.9,"Iris-virginica"]
+[6.8,3,5.5,2.1,"Iris-virginica"]
+[5.7,2.5,5,2,"Iris-virginica"]
+[5.8,2.8,5.1,2.4,"Iris-virginica"]
+[6.4,3.2,5.3,2.3,"Iris-virginica"]
+[6.5,3,5.5,1.8,"Iris-virginica"]
+[7.7,3.8,6.7,2.2,"Iris-virginica"]
+[7.7,2.6,6.9,2.3,"Iris-virginica"]
+[6,2.2,5,1.5,"Iris-virginica"]
+[6.9,3.2,5.7,2.3,"Iris-virginica"]
+[5.6,2.8,4.9,2,"Iris-virginica"]
+[7.7,2.8,6.7,2,"Iris-virginica"]
+[6.3,2.7,4.9,1.8,"Iris-virginica"]
+[6.7,3.3,5.7,2.1,"Iris-virginica"]
+[7.2,3.2,6,1.8,"Iris-virginica"]
+[6.2,2.8,4.8,1.8,"Iris-virginica"]
+[6.1,3,4.9,1.8,"Iris-virginica"]
+[6.4,2.8,5.6,2.1,"Iris-virginica"]
+[7.2,3,5.8,1.6,"Iris-virginica"]
+[7.4,2.8,6.1,1.9,"Iris-virginica"]
+[7.9,3.8,6.4,2,"Iris-virginica"]
+[6.4,2.8,5.6,2.2,"Iris-virginica"]
+[6.3,2.8,5.1,1.5,"Iris-virginica"]
+[6.1,2.6,5.6,1.4,"Iris-virginica"]
+[7.7,3,6.1,2.3,"Iris-virginica"]
+[6.3,3.4,5.6,2.4,"Iris-virginica"]
+[6.4,3.1,5.5,1.8,"Iris-virginica"]
+[6,3,4.8,1.8,"Iris-virginica"]
+[6.9,3.1,5.4,2.1,"Iris-virginica"]
+[6.7,3.1,5.6,2.4,"Iris-virginica"]
+[6.9,3.1,5.1,2.3,"Iris-virginica"]
+[5.8,2.7,5.1,1.9,"Iris-virginica"]
+[6.8,3.2,5.9,2.3,"Iris-virginica"]
+[6.7,3.3,5.7,2.5,"Iris-virginica"]
+[6.7,3,5.2,2.3,"Iris-virginica"]
+[6.3,2.5,5,1.9,"Iris-virginica"]
+[6.5,3,5.2,2,"Iris-virginica"]
+[6.2,3.4,5.4,2.3,"Iris-virginica"]
+[5.9,3,5.1,1.8,"Iris-virginica"]
\ No newline at end of file
diff --git a/examples/machine-learning/models/.gitignore b/examples/machine-learning/models/.gitignore
new file mode 100644
index 00000000..c96a04f0
--- /dev/null
+++ b/examples/machine-learning/models/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/resources/css/docs-page-homepage.css b/resources/css/docs-page-homepage.css
index 7da470a9..36ad7109 100644
--- a/resources/css/docs-page-homepage.css
+++ b/resources/css/docs-page-homepage.css
@@ -18,10 +18,22 @@
   background-color: var(--color-body-background);
 }
 
-.homepage-drivers,
+.homepage-gallery.homepage-gallery--reasons {
+  --homepage-gallery-background: var(--color-block-dark-background);
+  --homepage-gallery-color: var(--color-body-font-dark-background);
+}
+
+.homepage-gallery.homepage-gallery--releases {
+  --homepage-gallery-background: white;
+  --homepage-gallery-color: var(--color-body-font);
+
+  border-bottom: 1px solid var(--color-border);
+  height: 460px;
+}
+
 .homepage-gallery {
-  background-color: var(--color-block-dark-background);
-  color: var(--color-body-font-dark-background);
+  background-color: var(--homepage-gallery-background);
+  color: var(--homepage-gallery-color);
   max-width: 100vw;
   overflow-x: auto;
   overflow-y: hidden;
@@ -39,72 +51,22 @@
   }
 }
 
-.homepage-drivers {
-  border-top: 1px solid var(--color-border);
-  display: flex;
-  flex-direction: column;
-  row-gap: 20px;
-}
-
-.homepage-drivers__items {
-  align-items: center;
-  column-gap: 20px;
-  display: flex;
-  flex-direction: row;
-  list-style-type: none;
-}
-
-.homepage-drivers__item {
-  border: 1px solid var(--color-border);
+.homepage-gallery {
   display: flex;
   flex-direction: column;
-  padding: 40px 20px 20px 20px;
   row-gap: 20px;
-  text-align: center;
-  text-decoration: none;
 }
 
-.homepage-drivers__item.homepage-drivers__item--amphp {
-  --drivers-bg-image: url(../images/amphp.webp);
+.homepage-gallery__grid {
+  display: grid;
+  gap: 20px;
 
-  .homepage-drivers__item__background {
-    width: 450px;
+  @media screen and (max-width: 1023px) {
+    grid-template-columns: 1fr;
+  }
+  @media screen and (min-width: 1024px) {
+    grid-template-columns: repeat(2, 1fr);
   }
-}
-
-.homepage-drivers__item.homepage-drivers__item--openswoole {
-  --drivers-bg-image: url(../images/openswoole.png);
-}
-
-.homepage-drivers__item.homepage-drivers__item--other {
-  --drivers-bg-image: url(../icons/plug-circle-plus-333333.svg);
-}
-
-.homepage-drivers__item.homepage-drivers__item--swoole {
-  --drivers-bg-image: url(../images/swoole.png);
-}
-
-.homepage-drivers__item__background {
-  background-image: var(--drivers-bg-image);
-  background-position: center;
-  background-repeat: no-repeat;
-  height: 140px;
-  width: 350px;
-}
-
-.homepage-drivers__item__name {
-  font-weight: bold;
-}
-
-.homepage-drivers__item__state {
-  font-size: var(--font-size-smaller);
-}
-
-.homepage-gallery {
-  display: flex;
-  flex-direction: column;
-  height: 460px;
-  row-gap: 20px;
 }
 
 .homepage-gallery__items {
@@ -265,6 +227,7 @@ h2.homepage__example__title {
 
 .homepage__title h2 {
   font-weight: bold;
+  line-height: 1.3;
   margin-top: 20px;
 
   @media screen and (min-width: 1024px) {
-- 
GitLab