NobGit
public nobgit read

NobMail

Based on mailcow: dockerized

Languages

Repository composition by tracked source files.

PHP
PHP 49% JavaScript 35% HTML 9% CSS 4% Shell 2% Python 1% Lua 0% Perl 0% Ruby 0% SCSS 0%
Create file Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git

Commit

Update dependency twig/twig to v3.14.0 (#6071)

5a0f20b9
Peter <[email protected]> 1 year, 9 months ago
data/web/inc/lib/composer.lock                     |  178 +-
 data/web/inc/lib/vendor/autoload.php               |   17 +-
 data/web/inc/lib/vendor/composer/ClassLoader.php   |  137 +-
 .../inc/lib/vendor/composer/InstalledVersions.php  |   17 +-
 .../inc/lib/vendor/composer/autoload_classmap.php  |    2 +
 .../web/inc/lib/vendor/composer/autoload_files.php |    6 +
 data/web/inc/lib/vendor/composer/autoload_psr4.php |    1 +
 data/web/inc/lib/vendor/composer/autoload_real.php |   27 +-
 .../inc/lib/vendor/composer/autoload_static.php    |   13 +
 data/web/inc/lib/vendor/composer/installed.json    |  184 +-
 data/web/inc/lib/vendor/composer/installed.php     |   28 +-
 .../web/inc/lib/vendor/composer/platform_check.php |    4 +-
 .../symfony/deprecation-contracts/CHANGELOG.md     |    5 +
 .../vendor/symfony/deprecation-contracts/LICENSE   |   19 +
 .../vendor/symfony/deprecation-contracts/README.md |   26 +
 .../symfony/deprecation-contracts/composer.json    |   35 +
 .../symfony/deprecation-contracts/function.php     |   27 +
 .../inc/lib/vendor/symfony/polyfill-php81/LICENSE  |   19 +
 .../lib/vendor/symfony/polyfill-php81/Php81.php    |   37 +
 .../lib/vendor/symfony/polyfill-php81/README.md    |   18 +
 .../Resources/stubs/CURLStringFile.php             |   51 +
 .../Resources/stubs/ReturnTypeWillChange.php       |   20 +
 .../vendor/symfony/polyfill-php81/bootstrap.php    |   28 +
 .../vendor/symfony/polyfill-php81/composer.json    |   33 +
 data/web/inc/lib/vendor/twig/twig/.editorconfig    |   18 -
 data/web/inc/lib/vendor/twig/twig/.gitattributes   |    4 -
 .../lib/vendor/twig/twig/.github/workflows/ci.yml  |  149 --
 .../twig/twig/.github/workflows/documentation.yml  |   64 -
 data/web/inc/lib/vendor/twig/twig/.gitignore       |    6 -
 .../lib/vendor/twig/twig/.php-cs-fixer.dist.php    |   20 -
 data/web/inc/lib/vendor/twig/twig/CHANGELOG        |  177 +-
 data/web/inc/lib/vendor/twig/twig/LICENSE          |    2 +-
 data/web/inc/lib/vendor/twig/twig/README.rst       |    2 +-
 data/web/inc/lib/vendor/twig/twig/composer.json    |   21 +-
 .../vendor/twig/twig/src/AbstractTwigCallable.php  |  136 ++
 .../src/Attribute/FirstClassTwigCallableReady.php  |   20 +
 .../vendor/twig/twig/src/Attribute/YieldReady.php  |   20 +
 .../lib/vendor/twig/twig/src/Cache/ChainCache.php  |   79 +
 .../vendor/twig/twig/src/Cache/FilesystemCache.php |    8 +-
 .../twig/src/Cache/ReadOnlyFilesystemCache.php     |   25 +
 data/web/inc/lib/vendor/twig/twig/src/Compiler.php |   69 +-
 .../inc/lib/vendor/twig/twig/src/Environment.php   |  123 +-
 .../inc/lib/vendor/twig/twig/src/Error/Error.php   |   18 +-
 .../lib/vendor/twig/twig/src/Error/SyntaxError.php |    4 +-
 .../lib/vendor/twig/twig/src/ExpressionParser.php  |  400 +--
 .../twig/twig/src/Extension/AbstractExtension.php  |    2 +-
 .../twig/twig/src/Extension/CoreExtension.php      | 2553 +++++++++++---------
 .../twig/twig/src/Extension/DebugExtension.php     |   60 +-
 .../twig/twig/src/Extension/EscaperExtension.php   |  384 +--
 .../twig/twig/src/Extension/ExtensionInterface.php |    7 +
 .../twig/twig/src/Extension/GlobalsInterface.php   |    8 +-
 .../twig/twig/src/Extension/OptimizerExtension.php |    8 +-
 .../twig/twig/src/Extension/SandboxExtension.php   |   34 +-
 .../twig/twig/src/Extension/StagingExtension.php   |    8 +-
 .../twig/src/Extension/StringLoaderExtension.php   |   38 +-
 .../twig/src/Extension/YieldNotReadyExtension.php  |   30 +
 .../inc/lib/vendor/twig/twig/src/ExtensionSet.php  |  101 +-
 .../twig/src/FileExtensionEscapingStrategy.php     |    2 +-
 data/web/inc/lib/vendor/twig/twig/src/Lexer.php    |  147 +-
 .../vendor/twig/twig/src/Loader/ArrayLoader.php    |   14 +-
 .../vendor/twig/twig/src/Loader/ChainLoader.php    |   43 +-
 .../twig/twig/src/Loader/FilesystemLoader.php      |   20 +-
 data/web/inc/lib/vendor/twig/twig/src/Markup.php   |    4 +-
 .../vendor/twig/twig/src/Node/AutoEscapeNode.php   |    6 +-
 .../lib/vendor/twig/twig/src/Node/BlockNode.php    |   12 +-
 .../twig/twig/src/Node/BlockReferenceNode.php      |    8 +-
 .../inc/lib/vendor/twig/twig/src/Node/BodyNode.php |    3 +
 .../lib/vendor/twig/twig/src/Node/CaptureNode.php  |   57 +
 .../twig/twig/src/Node/CheckSecurityCallNode.php   |    4 +-
 .../twig/twig/src/Node/CheckSecurityNode.php       |   31 +-
 .../twig/twig/src/Node/CheckToStringNode.php       |    4 +-
 .../vendor/twig/twig/src/Node/DeprecatedNode.php   |   40 +-
 .../inc/lib/vendor/twig/twig/src/Node/DoNode.php   |    6 +-
 .../lib/vendor/twig/twig/src/Node/EmbedNode.php    |    6 +-
 .../src/Node/Expression/AbstractExpression.php     |    4 +
 .../twig/src/Node/Expression/ArrayExpression.php   |   66 +-
 .../Node/Expression/ArrowFunctionExpression.php    |    4 +-
 .../src/Node/Expression/Binary/EndsWithBinary.php  |    6 +-
 .../src/Node/Expression/Binary/EqualBinary.php     |    2 +-
 .../src/Node/Expression/Binary/GreaterBinary.php   |    2 +-
 .../Node/Expression/Binary/GreaterEqualBinary.php  |    2 +-
 .../src/Node/Expression/Binary/HasEveryBinary.php  |   33 +
 .../src/Node/Expression/Binary/HasSomeBinary.php   |   33 +
 .../twig/src/Node/Expression/Binary/InBinary.php   |    2 +-
 .../twig/src/Node/Expression/Binary/LessBinary.php |    2 +-
 .../src/Node/Expression/Binary/LessEqualBinary.php |    2 +-
 .../src/Node/Expression/Binary/MatchesBinary.php   |    2 +-
 .../src/Node/Expression/Binary/NotEqualBinary.php  |    2 +-
 .../src/Node/Expression/Binary/NotInBinary.php     |    2 +-
 .../Node/Expression/Binary/StartsWithBinary.php    |    6 +-
 .../Node/Expression/BlockReferenceExpression.php   |    9 +-
 .../twig/src/Node/Expression/CallExpression.php    |  197 +-
 .../src/Node/Expression/ConditionalExpression.php  |   27 +-
 .../src/Node/Expression/ConstantExpression.php     |    3 +
 .../src/Node/Expression/Filter/DefaultFilter.php   |   23 +-
 .../twig/src/Node/Expression/Filter/RawFilter.php  |   36 +
 .../twig/src/Node/Expression/FilterExpression.php  |   57 +-
 .../src/Node/Expression/FunctionExpression.php     |   51 +-
 .../Expression/FunctionNode/EnumCasesFunction.php  |   41 +
 .../twig/src/Node/Expression/GetAttrExpression.php |    2 +-
 .../twig/twig/src/Node/Expression/InlinePrint.php  |    3 +-
 .../src/Node/Expression/MethodCallExpression.php   |    6 +-
 .../twig/src/Node/Expression/NameExpression.php    |   14 +-
 .../src/Node/Expression/NullCoalesceExpression.php |    5 +-
 .../twig/src/Node/Expression/ParentExpression.php  |    6 +-
 .../twig/src/Node/Expression/Test/ConstantTest.php |    6 +-
 .../twig/src/Node/Expression/Test/DefinedTest.php  |    9 +-
 .../src/Node/Expression/Test/DivisiblebyTest.php   |    2 +-
 .../twig/src/Node/Expression/Test/SameasTest.php   |    2 +-
 .../twig/src/Node/Expression/TestExpression.php    |   40 +-
 .../lib/vendor/twig/twig/src/Node/FlushNode.php    |   17 +-
 .../lib/vendor/twig/twig/src/Node/ForLoopNode.php  |    8 +-
 .../inc/lib/vendor/twig/twig/src/Node/ForNode.php  |   19 +-
 .../inc/lib/vendor/twig/twig/src/Node/IfNode.php   |   13 +-
 .../lib/vendor/twig/twig/src/Node/ImportNode.php   |   16 +-
 .../lib/vendor/twig/twig/src/Node/IncludeNode.php  |   22 +-
 .../lib/vendor/twig/twig/src/Node/MacroNode.php    |   45 +-
 .../lib/vendor/twig/twig/src/Node/ModuleNode.php   |   99 +-
 .../vendor/twig/twig/src/Node/NameDeprecation.php  |   46 +
 .../web/inc/lib/vendor/twig/twig/src/Node/Node.php |  142 +-
 .../lib/vendor/twig/twig/src/Node/PrintNode.php    |   13 +-
 .../lib/vendor/twig/twig/src/Node/SandboxNode.php  |    6 +-
 .../inc/lib/vendor/twig/twig/src/Node/SetNode.php  |   51 +-
 .../inc/lib/vendor/twig/twig/src/Node/TextNode.php |    7 +-
 .../lib/vendor/twig/twig/src/Node/TypesNode.php    |   28 +
 .../inc/lib/vendor/twig/twig/src/Node/WithNode.php |   20 +-
 .../twig/src/NodeVisitor/AbstractNodeVisitor.php   |    4 +-
 .../twig/src/NodeVisitor/EscaperNodeVisitor.php    |   35 +-
 .../src/NodeVisitor/MacroAutoImportNodeVisitor.php |   10 +-
 .../twig/src/NodeVisitor/OptimizerNodeVisitor.php  |   70 +-
 .../src/NodeVisitor/SafeAnalysisNodeVisitor.php    |   28 +-
 .../twig/src/NodeVisitor/SandboxNodeVisitor.php    |   15 +-
 .../src/NodeVisitor/YieldNotReadyNodeVisitor.php   |   59 +
 data/web/inc/lib/vendor/twig/twig/src/Parser.php   |   77 +-
 .../twig/twig/src/Profiler/Dumper/BaseDumper.php   |    2 +-
 .../twig/src/Profiler/Dumper/BlackfireDumper.php   |    6 +-
 .../twig/twig/src/Profiler/Dumper/HtmlDumper.php   |    6 +-
 .../twig/twig/src/Profiler/Dumper/TextDumper.php   |    6 +-
 .../twig/src/Profiler/Node/EnterProfileNode.php    |    6 +-
 .../twig/src/Profiler/Node/LeaveProfileNode.php    |    4 +-
 .../Profiler/NodeVisitor/ProfilerNodeVisitor.php   |    9 +-
 .../lib/vendor/twig/twig/src/Profiler/Profile.php  |   17 +-
 .../lib/vendor/twig/twig/src/Resources/core.php    |  541 +++++
 .../lib/vendor/twig/twig/src/Resources/debug.php   |   25 +
 .../lib/vendor/twig/twig/src/Resources/escaper.php |   51 +
 .../twig/twig/src/Resources/string_loader.php      |   26 +
 .../twig/twig/src/Runtime/EscaperRuntime.php       |  327 +++
 .../src/RuntimeLoader/ContainerRuntimeLoader.php   |    8 +-
 .../src/RuntimeLoader/FactoryRuntimeLoader.php     |    8 +-
 .../twig/twig/src/Sandbox/SecurityPolicy.php       |   26 +-
 .../twig/src/Sandbox/SourcePolicyInterface.php     |   24 +
 data/web/inc/lib/vendor/twig/twig/src/Source.php   |   14 +-
 data/web/inc/lib/vendor/twig/twig/src/Template.php |  309 ++-
 .../lib/vendor/twig/twig/src/TemplateWrapper.php   |   39 +-
 .../twig/twig/src/Test/IntegrationTestCase.php     |   59 +-
 .../lib/vendor/twig/twig/src/Test/NodeTestCase.php |   74 +-
 data/web/inc/lib/vendor/twig/twig/src/Token.php    |   32 +-
 .../twig/twig/src/TokenParser/ApplyTokenParser.php |    8 +-
 .../twig/src/TokenParser/AutoEscapeTokenParser.php |    8 +-
 .../twig/twig/src/TokenParser/BlockTokenParser.php |   15 +-
 .../twig/src/TokenParser/DeprecatedTokenParser.php |   29 +-
 .../twig/twig/src/TokenParser/DoTokenParser.php    |    4 +-
 .../twig/twig/src/TokenParser/EmbedTokenParser.php |   18 +-
 .../twig/src/TokenParser/ExtendsTokenParser.php    |    7 +-
 .../twig/twig/src/TokenParser/FlushTokenParser.php |    4 +-
 .../twig/twig/src/TokenParser/ForTokenParser.php   |   16 +-
 .../twig/twig/src/TokenParser/FromTokenParser.php  |   16 +-
 .../twig/twig/src/TokenParser/IfTokenParser.php    |   12 +-
 .../twig/src/TokenParser/ImportTokenParser.php     |    8 +-
 .../twig/src/TokenParser/IncludeTokenParser.php    |   14 +-
 .../twig/twig/src/TokenParser/MacroTokenParser.php |   14 +-
 .../twig/src/TokenParser/SandboxTokenParser.php    |    6 +-
 .../twig/twig/src/TokenParser/SetTokenParser.php   |   10 +-
 .../twig/twig/src/TokenParser/TypesTokenParser.php |   86 +
 .../twig/twig/src/TokenParser/UseTokenParser.php   |   14 +-
 .../twig/twig/src/TokenParser/WithTokenParser.php  |   10 +-
 .../inc/lib/vendor/twig/twig/src/TokenStream.php   |   23 +-
 .../vendor/twig/twig/src/TwigCallableInterface.php |   53 +
 .../inc/lib/vendor/twig/twig/src/TwigFilter.php    |   78 +-
 .../inc/lib/vendor/twig/twig/src/TwigFunction.php  |   79 +-
 data/web/inc/lib/vendor/twig/twig/src/TwigTest.php |   67 +-
 .../twig/src/Util/CallableArgumentsExtractor.php   |  204 ++
 .../twig/twig/src/Util/DeprecationCollector.php    |   10 +-
 .../twig/twig/src/Util/ReflectionCallable.php      |   92 +
 184 files changed, 6730 insertions(+), 3290 deletions(-)
 create mode 100644 data/web/inc/lib/vendor/symfony/deprecation-contracts/CHANGELOG.md
 create mode 100644 data/web/inc/lib/vendor/symfony/deprecation-contracts/LICENSE
 create mode 100644 data/web/inc/lib/vendor/symfony/deprecation-contracts/README.md
 create mode 100644 data/web/inc/lib/vendor/symfony/deprecation-contracts/composer.json
 create mode 100644 data/web/inc/lib/vendor/symfony/deprecation-contracts/function.php
 create mode 100644 data/web/inc/lib/vendor/symfony/polyfill-php81/LICENSE
 create mode 100644 data/web/inc/lib/vendor/symfony/polyfill-php81/Php81.php
 create mode 100644 data/web/inc/lib/vendor/symfony/polyfill-php81/README.md
 create mode 100644 data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php
 create mode 100644 data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php
 create mode 100644 data/web/inc/lib/vendor/symfony/polyfill-php81/bootstrap.php
 create mode 100644 data/web/inc/lib/vendor/symfony/polyfill-php81/composer.json
 delete mode 100644 data/web/inc/lib/vendor/twig/twig/.editorconfig
 delete mode 100644 data/web/inc/lib/vendor/twig/twig/.gitattributes
 delete mode 100644 data/web/inc/lib/vendor/twig/twig/.github/workflows/ci.yml
 delete mode 100644 data/web/inc/lib/vendor/twig/twig/.github/workflows/documentation.yml
 delete mode 100644 data/web/inc/lib/vendor/twig/twig/.gitignore
 delete mode 100644 data/web/inc/lib/vendor/twig/twig/.php-cs-fixer.dist.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/AbstractTwigCallable.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Attribute/FirstClassTwigCallableReady.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Attribute/YieldReady.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Cache/ChainCache.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Cache/ReadOnlyFilesystemCache.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Extension/YieldNotReadyExtension.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Node/CaptureNode.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionNode/EnumCasesFunction.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Node/NameDeprecation.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Node/TypesNode.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Resources/core.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Resources/debug.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Resources/escaper.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Resources/string_loader.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Runtime/EscaperRuntime.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Sandbox/SourcePolicyInterface.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/TokenParser/TypesTokenParser.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/TwigCallableInterface.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Util/CallableArgumentsExtractor.php
 create mode 100644 data/web/inc/lib/vendor/twig/twig/src/Util/ReflectionCallable.php

Diff

diff --git a/data/web/inc/lib/composer.lock b/data/web/inc/lib/composer.lock
index 75853537..422d353a 100644
--- a/data/web/inc/lib/composer.lock
+++ b/data/web/inc/lib/composer.lock
@@ -1039,6 +1039,73 @@
             },
             "time": "2017-04-19T22:01:50+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": "[email protected]"
+                },
+                {
+                    "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/polyfill-ctype",
             "version": "v1.24.0",
@@ -1287,6 +1354,82 @@
             ],
             "time": "2021-09-13T13:58:33+00:00"
         },
+        {
+            "name": "symfony/polyfill-php81",
+            "version": "v1.31.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php81.git",
+                "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+                "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2"
+            },
+            "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": "[email protected]"
+                },
+                {
+                    "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.31.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-09-09T11:45:10+00:00"
+        },
         {
             "name": "symfony/translation",
             "version": "v6.0.5",
@@ -1604,34 +1747,37 @@
         },
         {
             "name": "twig/twig",
-            "version": "v3.4.3",
+            "version": "v3.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/twigphp/Twig.git",
-                "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
+                "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
-                "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
+                "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.2.5",
+                "php": ">=8.0.2",
+                "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/polyfill-ctype": "^1.8",
-                "symfony/polyfill-mbstring": "^1.3"
+                "symfony/polyfill-mbstring": "^1.3",
+                "symfony/polyfill-php81": "^1.29"
             },
             "require-dev": {
-                "psr/container": "^1.0",
-                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+                "psr/container": "^1.0|^2.0",
+                "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
             },
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
             "autoload": {
+                "files": [
+                    "src/Resources/core.php",
+                    "src/Resources/debug.php",
+                    "src/Resources/escaper.php",
+                    "src/Resources/string_loader.php"
+                ],
                 "psr-4": {
                     "Twig\\": "src/"
                 }
@@ -1664,7 +1810,7 @@
             ],
             "support": {
                 "issues": "https://github.com/twigphp/Twig/issues",
-                "source": "https://github.com/twigphp/Twig/tree/v3.4.3"
+                "source": "https://github.com/twigphp/Twig/tree/v3.14.0"
             },
             "funding": [
                 {
@@ -1676,7 +1822,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-09-28T08:42:51+00:00"
+            "time": "2024-09-09T17:55:12+00:00"
         },
         {
             "name": "yubico/u2flib-server",
@@ -1728,5 +1874,5 @@
     "prefer-lowest": false,
     "platform": [],
     "platform-dev": [],
-    "plugin-api-version": "2.3.0"
+    "plugin-api-version": "2.6.0"
 }
diff --git a/data/web/inc/lib/vendor/autoload.php b/data/web/inc/lib/vendor/autoload.php
index c21364e8..a0fb8f4a 100644
--- a/data/web/inc/lib/vendor/autoload.php
+++ b/data/web/inc/lib/vendor/autoload.php
@@ -3,8 +3,21 @@
 // autoload.php @generated by Composer
 
 if (PHP_VERSION_ID < 50600) {
-    echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
-    exit(1);
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, $err);
+        } elseif (!headers_sent()) {
+            echo $err;
+        }
+    }
+    trigger_error(
+        $err,
+        E_USER_ERROR
+    );
 }
 
 require_once __DIR__ . '/composer/autoload_real.php';
diff --git a/data/web/inc/lib/vendor/composer/ClassLoader.php b/data/web/inc/lib/vendor/composer/ClassLoader.php
index afef3fa2..7824d8f7 100644
--- a/data/web/inc/lib/vendor/composer/ClassLoader.php
+++ b/data/web/inc/lib/vendor/composer/ClassLoader.php
@@ -42,35 +42,37 @@ namespace Composer\Autoload;
  */
 class ClassLoader
 {
-    /** @var ?string */
+    /** @var \Closure(string):void */
+    private static $includeFile;
+
+    /** @var string|null */
     private $vendorDir;
 
     // PSR-4
     /**
-     * @var array[]
-     * @psalm-var array<string, array<string, int>>
+     * @var array<string, array<string, int>>
      */
     private $prefixLengthsPsr4 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, array<int, string>>
+     * @var array<string, list<string>>
      */
     private $prefixDirsPsr4 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, string>
+     * @var list<string>
      */
     private $fallbackDirsPsr4 = array();
 
     // PSR-0
     /**
-     * @var array[]
-     * @psalm-var array<string, array<string, string[]>>
+     * List of PSR-0 prefixes
+     *
+     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
+     *
+     * @var array<string, array<string, list<string>>>
      */
     private $prefixesPsr0 = array();
     /**
-     * @var array[]
-     * @psalm-var array<string, string>
+     * @var list<string>
      */
     private $fallbackDirsPsr0 = array();
 
@@ -78,8 +80,7 @@ class ClassLoader
     private $useIncludePath = false;
 
     /**
-     * @var string[]
-     * @psalm-var array<string, string>
+     * @var array<string, string>
      */
     private $classMap = array();
 
@@ -87,29 +88,29 @@ class ClassLoader
     private $classMapAuthoritative = false;
 
     /**
-     * @var bool[]
-     * @psalm-var array<string, bool>
+     * @var array<string, bool>
      */
     private $missingClasses = array();
 
-    /** @var ?string */
+    /** @var string|null */
     private $apcuPrefix;
 
     /**
-     * @var self[]
+     * @var array<string, self>
      */
     private static $registeredLoaders = array();
 
     /**
-     * @param ?string $vendorDir
+     * @param string|null $vendorDir
      */
     public function __construct($vendorDir = null)
     {
         $this->vendorDir = $vendorDir;
+        self::initializeIncludeClosure();
     }
 
     /**
-     * @return string[]
+     * @return array<string, list<string>>
      */
     public function getPrefixes()
     {
@@ -121,8 +122,7 @@ class ClassLoader
     }
 
     /**
-     * @return array[]
-     * @psalm-return array<string, array<int, string>>
+     * @return array<string, list<string>>
      */
     public function getPrefixesPsr4()
     {
@@ -130,8 +130,7 @@ class ClassLoader
     }
 
     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirs()
     {
@@ -139,8 +138,7 @@ class ClassLoader
     }
 
     /**
-     * @return array[]
-     * @psalm-return array<string, string>
+     * @return list<string>
      */
     public function getFallbackDirsPsr4()
     {
@@ -148,8 +146,7 @@ class ClassLoader
     }
 
     /**
-     * @return string[] Array of classname => path
-     * @psalm-return array<string, string>
+     * @return array<string, string> Array of classname => path
      */
     public function getClassMap()
     {
@@ -157,8 +154,7 @@ class ClassLoader
     }
 
     /**
-     * @param string[] $classMap Class to filename map
-     * @psalm-param array<string, string> $classMap
+     * @param array<string, string> $classMap Class to filename map
      *
      * @return void
      */
@@ -175,24 +171,25 @@ class ClassLoader
      * Registers a set of PSR-0 directories for a given prefix, either
      * appending or prepending to the ones previously set for this prefix.
      *
-     * @param string          $prefix  The prefix
-     * @param string[]|string $paths   The PSR-0 root directories
-     * @param bool            $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix
+     * @param list<string>|string $paths   The PSR-0 root directories
+     * @param bool                $prepend Whether to prepend the directories
      *
      * @return void
      */
     public function add($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             if ($prepend) {
                 $this->fallbackDirsPsr0 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr0
                 );
             } else {
                 $this->fallbackDirsPsr0 = array_merge(
                     $this->fallbackDirsPsr0,
-                    (array) $paths
+                    $paths
                 );
             }
 
@@ -201,19 +198,19 @@ class ClassLoader
 
         $first = $prefix[0];
         if (!isset($this->prefixesPsr0[$first][$prefix])) {
-            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+            $this->prefixesPsr0[$first][$prefix] = $paths;
 
             return;
         }
         if ($prepend) {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixesPsr0[$first][$prefix]
             );
         } else {
             $this->prefixesPsr0[$first][$prefix] = array_merge(
                 $this->prefixesPsr0[$first][$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -222,9 +219,9 @@ class ClassLoader
      * Registers a set of PSR-4 directories for a given namespace, either
      * appending or prepending to the ones previously set for this namespace.
      *
-     * @param string          $prefix  The prefix/namespace, with trailing '\\'
-     * @param string[]|string $paths   The PSR-4 base directories
-     * @param bool            $prepend Whether to prepend the directories
+     * @param string              $prefix  The prefix/namespace, with trailing '\\'
+     * @param list<string>|string $paths   The PSR-4 base directories
+     * @param bool                $prepend Whether to prepend the directories
      *
      * @throws \InvalidArgumentException
      *
@@ -232,17 +229,18 @@ class ClassLoader
      */
     public function addPsr4($prefix, $paths, $prepend = false)
     {
+        $paths = (array) $paths;
         if (!$prefix) {
             // Register directories for the root namespace.
             if ($prepend) {
                 $this->fallbackDirsPsr4 = array_merge(
-                    (array) $paths,
+                    $paths,
                     $this->fallbackDirsPsr4
                 );
             } else {
                 $this->fallbackDirsPsr4 = array_merge(
                     $this->fallbackDirsPsr4,
-                    (array) $paths
+                    $paths
                 );
             }
         } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -252,18 +250,18 @@ class ClassLoader
                 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
             }
             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
-            $this->prefixDirsPsr4[$prefix] = (array) $paths;
+            $this->prefixDirsPsr4[$prefix] = $paths;
         } elseif ($prepend) {
             // Prepend directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
-                (array) $paths,
+                $paths,
                 $this->prefixDirsPsr4[$prefix]
             );
         } else {
             // Append directories for an already registered namespace.
             $this->prefixDirsPsr4[$prefix] = array_merge(
                 $this->prefixDirsPsr4[$prefix],
-                (array) $paths
+                $paths
             );
         }
     }
@@ -272,8 +270,8 @@ class ClassLoader
      * Registers a set of PSR-0 directories for a given prefix,
      * replacing any others previously set for this prefix.
      *
-     * @param string          $prefix The prefix
-     * @param string[]|string $paths  The PSR-0 base directories
+     * @param string              $prefix The prefix
+     * @param list<string>|string $paths  The PSR-0 base directories
      *
      * @return void
      */
@@ -290,8 +288,8 @@ class ClassLoader
      * Registers a set of PSR-4 directories for a given namespace,
      * replacing any others previously set for this namespace.
      *
-     * @param string          $prefix The prefix/namespace, with trailing '\\'
-     * @param string[]|string $paths  The PSR-4 base directories
+     * @param string              $prefix The prefix/namespace, with trailing '\\'
+     * @param list<string>|string $paths  The PSR-4 base directories
      *
      * @throws \InvalidArgumentException
      *
@@ -425,7 +423,8 @@ class ClassLoader
     public function loadClass($class)
     {
         if ($file = $this->findFile($class)) {
-            includeFile($file);
+            $includeFile = self::$includeFile;
+            $includeFile($file);
 
             return true;
         }
@@ -476,9 +475,9 @@ class ClassLoader
     }
 
     /**
-     * Returns the currently registered loaders indexed by their corresponding vendor directories.
+     * Returns the currently registered loaders keyed by their corresponding vendor directories.
      *
-     * @return self[]
+     * @return array<string, self>
      */
     public static function getRegisteredLoaders()
     {
@@ -555,18 +554,26 @@ class ClassLoader
 
         return false;
     }
-}
 
-/**
- * Scope isolated include.
- *
- * Prevents access to $this/self from included files.
- *
- * @param  string $file
- * @return void
- * @private
- */
-function includeFile($file)
-{
-    include $file;
+    /**
+     * @return void
+     */
+    private static function initializeIncludeClosure()
+    {
+        if (self::$includeFile !== null) {
+            return;
+        }
+
+        /**
+         * Scope isolated include.
+         *
+         * Prevents access to $this/self from included files.
+         *
+         * @param  string $file
+         * @return void
+         */
+        self::$includeFile = \Closure::bind(static function($file) {
+            include $file;
+        }, null, null);
+    }
 }
diff --git a/data/web/inc/lib/vendor/composer/InstalledVersions.php b/data/web/inc/lib/vendor/composer/InstalledVersions.php
index c6b54af7..51e734a7 100644
--- a/data/web/inc/lib/vendor/composer/InstalledVersions.php
+++ b/data/web/inc/lib/vendor/composer/InstalledVersions.php
@@ -98,7 +98,7 @@ class InstalledVersions
     {
         foreach (self::getInstalled() as $installed) {
             if (isset($installed['versions'][$packageName])) {
-                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
+                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
             }
         }
 
@@ -119,7 +119,7 @@ class InstalledVersions
      */
     public static function satisfies(VersionParser $parser, $packageName, $constraint)
     {
-        $constraint = $parser->parseConstraints($constraint);
+        $constraint = $parser->parseConstraints((string) $constraint);
         $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
 
         return $provided->matches($constraint);
@@ -328,7 +328,9 @@ class InstalledVersions
                 if (isset(self::$installedByVendor[$vendorDir])) {
                     $installed[] = self::$installedByVendor[$vendorDir];
                 } elseif (is_file($vendorDir.'/composer/installed.php')) {
-                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
+                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                    $required = require $vendorDir.'/composer/installed.php';
+                    $installed[] = self::$installedByVendor[$vendorDir] = $required;
                     if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
                         self::$installed = $installed[count($installed) - 1];
                     }
@@ -340,12 +342,17 @@ class InstalledVersions
             // only require the installed.php file if this file is loaded from its dumped location,
             // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
             if (substr(__DIR__, -8, 1) !== 'C') {
-                self::$installed = require __DIR__ . '/installed.php';
+                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
+                $required = require __DIR__ . '/installed.php';
+                self::$installed = $required;
             } else {
                 self::$installed = array();
             }
         }
-        $installed[] = self::$installed;
+
+        if (self::$installed !== array()) {
+            $installed[] = self::$installed;
+        }
 
         return $installed;
     }
diff --git a/data/web/inc/lib/vendor/composer/autoload_classmap.php b/data/web/inc/lib/vendor/composer/autoload_classmap.php
index f3327f11..83b86c26 100644
--- a/data/web/inc/lib/vendor/composer/autoload_classmap.php
+++ b/data/web/inc/lib/vendor/composer/autoload_classmap.php
@@ -7,7 +7,9 @@ $baseDir = dirname($vendorDir);
 
 return array(
     'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
+    'CURLStringFile' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
     'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
+    'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
     'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
     'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
     'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
diff --git a/data/web/inc/lib/vendor/composer/autoload_files.php b/data/web/inc/lib/vendor/composer/autoload_files.php
index 502893f7..526f6b6f 100644
--- a/data/web/inc/lib/vendor/composer/autoload_files.php
+++ b/data/web/inc/lib/vendor/composer/autoload_files.php
@@ -10,8 +10,14 @@ return array(
     'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
     'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
     '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
+    '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
     '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
+    '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
     'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',
     'caf31cc6ec7cf2241cb6f12c226c3846' => $vendorDir . '/tightenco/collect/src/Collect/Support/alias.php',
     '04c6c5c2f7095ccf6c481d3e53e1776f' => $vendorDir . '/mustangostang/spyc/Spyc.php',
+    '89efb1254ef2d1c5d80096acd12c4098' => $vendorDir . '/twig/twig/src/Resources/core.php',
+    'ffecb95d45175fd40f75be8a23b34f90' => $vendorDir . '/twig/twig/src/Resources/debug.php',
+    'c7baa00073ee9c61edf148c51917cfb4' => $vendorDir . '/twig/twig/src/Resources/escaper.php',
+    'f844ccf1d25df8663951193c3fc307c8' => $vendorDir . '/twig/twig/src/Resources/string_loader.php',
 );
diff --git a/data/web/inc/lib/vendor/composer/autoload_psr4.php b/data/web/inc/lib/vendor/composer/autoload_psr4.php
index 83d1f565..0a55fb6c 100644
--- a/data/web/inc/lib/vendor/composer/autoload_psr4.php
+++ b/data/web/inc/lib/vendor/composer/autoload_psr4.php
@@ -8,6 +8,7 @@ $baseDir = dirname($vendorDir);
 return array(
     'Twig\\' => array($vendorDir . '/twig/twig/src'),
     'Tightenco\\Collect\\' => array($vendorDir . '/tightenco/collect/src/Collect'),
+    'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'),
     'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
     'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
     'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
diff --git a/data/web/inc/lib/vendor/composer/autoload_real.php b/data/web/inc/lib/vendor/composer/autoload_real.php
index 6891b0c9..5e208253 100644
--- a/data/web/inc/lib/vendor/composer/autoload_real.php
+++ b/data/web/inc/lib/vendor/composer/autoload_real.php
@@ -33,25 +33,18 @@ class ComposerAutoloaderInit873464e4bd965a3168f133248b1b218b
 
         $loader->register(true);
 
-        $includeFiles = \Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::$files;
-        foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire873464e4bd965a3168f133248b1b218b($fileIdentifier, $file);
+        $filesToLoad = \Composer\Autoload\ComposerStaticInit873464e4bd965a3168f133248b1b218b::$files;
+        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
+            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+
+                require $file;
+            }
+        }, null, null);
+        foreach ($filesToLoad as $fileIdentifier => $file) {
+            $requireFile($fileIdentifier, $file);
         }
 
         return $loader;
     }
 }
-
-/**
- * @param string $fileIdentifier
- * @param string $file
- * @return void
- */
-function composerRequire873464e4bd965a3168f133248b1b218b($fileIdentifier, $file)
-{
-    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
-        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
-
-        require $file;
-    }
-}
diff --git a/data/web/inc/lib/vendor/composer/autoload_static.php b/data/web/inc/lib/vendor/composer/autoload_static.php
index 94606e83..6b2f04a5 100644
--- a/data/web/inc/lib/vendor/composer/autoload_static.php
+++ b/data/web/inc/lib/vendor/composer/autoload_static.php
@@ -11,10 +11,16 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
         'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
         'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
         '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
+        '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
         '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
+        '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
         'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
         'caf31cc6ec7cf2241cb6f12c226c3846' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/alias.php',
         '04c6c5c2f7095ccf6c481d3e53e1776f' => __DIR__ . '/..' . '/mustangostang/spyc/Spyc.php',
+        '89efb1254ef2d1c5d80096acd12c4098' => __DIR__ . '/..' . '/twig/twig/src/Resources/core.php',
+        'ffecb95d45175fd40f75be8a23b34f90' => __DIR__ . '/..' . '/twig/twig/src/Resources/debug.php',
+        'c7baa00073ee9c61edf148c51917cfb4' => __DIR__ . '/..' . '/twig/twig/src/Resources/escaper.php',
+        'f844ccf1d25df8663951193c3fc307c8' => __DIR__ . '/..' . '/twig/twig/src/Resources/string_loader.php',
     );
 
     public static $prefixLengthsPsr4 = array (
@@ -25,6 +31,7 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
         ),
         'S' => 
         array (
+            'Symfony\\Polyfill\\Php81\\' => 23,
             'Symfony\\Polyfill\\Php80\\' => 23,
             'Symfony\\Polyfill\\Mbstring\\' => 26,
             'Symfony\\Polyfill\\Ctype\\' => 23,
@@ -80,6 +87,10 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
         array (
             0 => __DIR__ . '/..' . '/tightenco/collect/src/Collect',
         ),
+        'Symfony\\Polyfill\\Php81\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-php81',
+        ),
         'Symfony\\Polyfill\\Php80\\' => 
         array (
             0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
@@ -170,7 +181,9 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
 
     public static $classMap = array (
         'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
+        'CURLStringFile' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php',
         'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+        'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php',
         'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
         'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
         'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
diff --git a/data/web/inc/lib/vendor/composer/installed.json b/data/web/inc/lib/vendor/composer/installed.json
index e21edcc6..dfb2fb0c 100644
--- a/data/web/inc/lib/vendor/composer/installed.json
+++ b/data/web/inc/lib/vendor/composer/installed.json
@@ -1068,6 +1068,76 @@
             ],
             "install-path": "../soundasleep/html2text"
         },
+        {
+            "name": "symfony/deprecation-contracts",
+            "version": "v3.5.0",
+            "version_normalized": "3.5.0.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"
+            },
+            "time": "2024-04-18T09:32:20+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.5-dev"
+                },
+                "thanks": {
+                    "name": "symfony/contracts",
+                    "url": "https://github.com/symfony/contracts"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "function.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "[email protected]"
+                },
+                {
+                    "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"
+                }
+            ],
+            "install-path": "../symfony/deprecation-contracts"
+        },
         {
             "name": "symfony/polyfill-ctype",
             "version": "v1.24.0",
@@ -1325,6 +1395,85 @@
             ],
             "install-path": "../symfony/polyfill-php80"
         },
+        {
+            "name": "symfony/polyfill-php81",
+            "version": "v1.31.0",
+            "version_normalized": "1.31.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php81.git",
+                "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+                "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2"
+            },
+            "time": "2024-09-09T11:45:10+00:00",
+            "type": "library",
+            "extra": {
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php81\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "[email protected]"
+                },
+                {
+                    "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.31.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/polyfill-php81"
+        },
         {
             "name": "symfony/translation",
             "version": "v6.0.5",
@@ -1654,37 +1803,40 @@
         },
         {
             "name": "twig/twig",
-            "version": "v3.4.3",
-            "version_normalized": "3.4.3.0",
+            "version": "v3.14.0",
+            "version_normalized": "3.14.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/twigphp/Twig.git",
-                "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
+                "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
-                "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
+                "reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.2.5",
+                "php": ">=8.0.2",
+                "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/polyfill-ctype": "^1.8",
-                "symfony/polyfill-mbstring": "^1.3"
+                "symfony/polyfill-mbstring": "^1.3",
+                "symfony/polyfill-php81": "^1.29"
             },
             "require-dev": {
-                "psr/container": "^1.0",
-                "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
+                "psr/container": "^1.0|^2.0",
+                "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
             },
-            "time": "2022-09-28T08:42:51+00:00",
+            "time": "2024-09-09T17:55:12+00:00",
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
             "installation-source": "dist",
             "autoload": {
+                "files": [
+                    "src/Resources/core.php",
+                    "src/Resources/debug.php",
+                    "src/Resources/escaper.php",
+                    "src/Resources/string_loader.php"
+                ],
                 "psr-4": {
                     "Twig\\": "src/"
                 }
@@ -1717,7 +1869,7 @@
             ],
             "support": {
                 "issues": "https://github.com/twigphp/Twig/issues",
-                "source": "https://github.com/twigphp/Twig/tree/v3.4.3"
+                "source": "https://github.com/twigphp/Twig/tree/v3.14.0"
             },
             "funding": [
                 {
diff --git a/data/web/inc/lib/vendor/composer/installed.php b/data/web/inc/lib/vendor/composer/installed.php
index c45f177e..5d78fc9f 100644
--- a/data/web/inc/lib/vendor/composer/installed.php
+++ b/data/web/inc/lib/vendor/composer/installed.php
@@ -3,7 +3,7 @@
         'name' => '__root__',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => '8e0b1d8aee4af02311692cb031695cc2ac3850fd',
+        'reference' => '220fdbb168792c07493db330d898b345cc902055',
         'type' => 'library',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -13,7 +13,7 @@
         '__root__' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => '8e0b1d8aee4af02311692cb031695cc2ac3850fd',
+            'reference' => '220fdbb168792c07493db330d898b345cc902055',
             'type' => 'library',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
@@ -175,6 +175,15 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'symfony/deprecation-contracts' => array(
+            'pretty_version' => 'v3.5.0',
+            'version' => '3.5.0.0',
+            'reference' => '0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'symfony/polyfill-ctype' => array(
             'pretty_version' => 'v1.24.0',
             'version' => '1.24.0.0',
@@ -202,6 +211,15 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'symfony/polyfill-php81' => array(
+            'pretty_version' => 'v1.31.0',
+            'version' => '1.31.0.0',
+            'reference' => '4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/polyfill-php81',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'symfony/translation' => array(
             'pretty_version' => 'v6.0.5',
             'version' => '6.0.5.0',
@@ -245,9 +263,9 @@
             'dev_requirement' => false,
         ),
         'twig/twig' => array(
-            'pretty_version' => 'v3.4.3',
-            'version' => '3.4.3.0',
-            'reference' => 'c38fd6b0b7f370c198db91ffd02e23b517426b58',
+            'pretty_version' => 'v3.14.0',
+            'version' => '3.14.0.0',
+            'reference' => '126b2c97818dbff0cdf3fbfc881aedb3d40aae72',
             'type' => 'library',
             'install_path' => __DIR__ . '/../twig/twig',
             'aliases' => array(),
diff --git a/data/web/inc/lib/vendor/composer/platform_check.php b/data/web/inc/lib/vendor/composer/platform_check.php
index b168ddd5..4c3a5d68 100644
--- a/data/web/inc/lib/vendor/composer/platform_check.php
+++ b/data/web/inc/lib/vendor/composer/platform_check.php
@@ -4,8 +4,8 @@
 
 $issues = array();
 
-if (!(PHP_VERSION_ID >= 80002)) {
-    $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.2". You are running ' . PHP_VERSION . '.';
+if (!(PHP_VERSION_ID >= 80100)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
 }
 
 if ($issues) {
diff --git a/data/web/inc/lib/vendor/symfony/deprecation-contracts/CHANGELOG.md b/data/web/inc/lib/vendor/symfony/deprecation-contracts/CHANGELOG.md
new file mode 100644
index 00000000..7932e261
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/deprecation-contracts/CHANGELOG.md
@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/main/CHANGELOG.md
diff --git a/data/web/inc/lib/vendor/symfony/deprecation-contracts/LICENSE b/data/web/inc/lib/vendor/symfony/deprecation-contracts/LICENSE
new file mode 100644
index 00000000..0ed3a246
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/deprecation-contracts/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2020-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/data/web/inc/lib/vendor/symfony/deprecation-contracts/README.md b/data/web/inc/lib/vendor/symfony/deprecation-contracts/README.md
new file mode 100644
index 00000000..9814864c
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/deprecation-contracts/README.md
@@ -0,0 +1,26 @@
+Symfony Deprecation Contracts
+=============================
+
+A generic function and convention to trigger deprecation notices.
+
+This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices.
+
+By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component,
+the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments.
+
+The function requires at least 3 arguments:
+ - the name of the Composer package that is triggering the deprecation
+ - the version of the package that introduced the deprecation
+ - the message of the deprecation
+ - more arguments can be provided: they will be inserted in the message using `printf()` formatting
+
+Example:
+```php
+trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin');
+```
+
+This will generate the following message:
+`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.`
+
+While not recommended, the deprecation notices can be completely ignored by declaring an empty
+`function trigger_deprecation() {}` in your application.
diff --git a/data/web/inc/lib/vendor/symfony/deprecation-contracts/composer.json b/data/web/inc/lib/vendor/symfony/deprecation-contracts/composer.json
new file mode 100644
index 00000000..ceb6c079
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/deprecation-contracts/composer.json
@@ -0,0 +1,35 @@
+{
+    "name": "symfony/deprecation-contracts",
+    "type": "library",
+    "description": "A generic function and convention to trigger deprecation notices",
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "[email protected]"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=8.1"
+    },
+    "autoload": {
+        "files": [
+            "function.php"
+        ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "branch-alias": {
+            "dev-main": "3.5-dev"
+        },
+        "thanks": {
+            "name": "symfony/contracts",
+            "url": "https://github.com/symfony/contracts"
+        }
+    }
+}
diff --git a/data/web/inc/lib/vendor/symfony/deprecation-contracts/function.php b/data/web/inc/lib/vendor/symfony/deprecation-contracts/function.php
new file mode 100644
index 00000000..2d56512b
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/deprecation-contracts/function.php
@@ -0,0 +1,27 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (!function_exists('trigger_deprecation')) {
+    /**
+     * Triggers a silenced deprecation notice.
+     *
+     * @param string $package The name of the Composer package that is triggering the deprecation
+     * @param string $version The version of the package that introduced the deprecation
+     * @param string $message The message of the deprecation
+     * @param mixed  ...$args Values to insert in the message using printf() formatting
+     *
+     * @author Nicolas Grekas <[email protected]>
+     */
+    function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void
+    {
+        @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
+    }
+}
diff --git a/data/web/inc/lib/vendor/symfony/polyfill-php81/LICENSE b/data/web/inc/lib/vendor/symfony/polyfill-php81/LICENSE
new file mode 100644
index 00000000..99c6bdf3
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/polyfill-php81/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2021-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/data/web/inc/lib/vendor/symfony/polyfill-php81/Php81.php b/data/web/inc/lib/vendor/symfony/polyfill-php81/Php81.php
new file mode 100644
index 00000000..f0507b76
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/polyfill-php81/Php81.php
@@ -0,0 +1,37 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Php81;
+
+/**
+ * @author Nicolas Grekas <[email protected]>
+ *
+ * @internal
+ */
+final class Php81
+{
+    public static function array_is_list(array $array): bool
+    {
+        if ([] === $array || $array === array_values($array)) {
+            return true;
+        }
+
+        $nextKey = -1;
+
+        foreach ($array as $k => $v) {
+            if ($k !== ++$nextKey) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/data/web/inc/lib/vendor/symfony/polyfill-php81/README.md b/data/web/inc/lib/vendor/symfony/polyfill-php81/README.md
new file mode 100644
index 00000000..c07ef782
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/polyfill-php81/README.md
@@ -0,0 +1,18 @@
+Symfony Polyfill / Php81
+========================
+
+This component provides features added to PHP 8.1 core:
+
+- [`array_is_list`](https://php.net/array_is_list)
+- [`enum_exists`](https://php.net/enum-exists)
+- [`MYSQLI_REFRESH_REPLICA`](https://php.net/mysqli.constants#constantmysqli-refresh-replica) constant
+- [`ReturnTypeWillChange`](https://wiki.php.net/rfc/internal_method_return_types)
+- [`CURLStringFile`](https://php.net/CURLStringFile) (but only if PHP >= 7.4 is used)
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php b/data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php
new file mode 100644
index 00000000..5ff93fca
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php
@@ -0,0 +1,51 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID >= 70400 && extension_loaded('curl')) {
+    /**
+     * @property string $data
+     */
+    class CURLStringFile extends CURLFile
+    {
+        private $data;
+
+        public function __construct(string $data, string $postname, string $mime = 'application/octet-stream')
+        {
+            $this->data = $data;
+            parent::__construct('data://application/octet-stream;base64,'.base64_encode($data), $mime, $postname);
+        }
+
+        public function __set(string $name, $value): void
+        {
+            if ('data' !== $name) {
+                $this->$name = $value;
+
+                return;
+            }
+
+            if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) {
+                throw new TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string');
+            }
+
+            $this->name = 'data://application/octet-stream;base64,'.base64_encode($value);
+        }
+
+        public function __isset(string $name): bool
+        {
+            return isset($this->$name);
+        }
+
+        public function &__get(string $name)
+        {
+            return $this->$name;
+        }
+    }
+}
diff --git a/data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php b/data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php
new file mode 100644
index 00000000..cb7720a8
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php
@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+if (\PHP_VERSION_ID < 80100) {
+    #[Attribute(Attribute::TARGET_METHOD)]
+    final class ReturnTypeWillChange
+    {
+        public function __construct()
+        {
+        }
+    }
+}
diff --git a/data/web/inc/lib/vendor/symfony/polyfill-php81/bootstrap.php b/data/web/inc/lib/vendor/symfony/polyfill-php81/bootstrap.php
new file mode 100644
index 00000000..9f872e02
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/polyfill-php81/bootstrap.php
@@ -0,0 +1,28 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Php81 as p;
+
+if (\PHP_VERSION_ID >= 80100) {
+    return;
+}
+
+if (defined('MYSQLI_REFRESH_SLAVE') && !defined('MYSQLI_REFRESH_REPLICA')) {
+    define('MYSQLI_REFRESH_REPLICA', 64);
+}
+
+if (!function_exists('array_is_list')) {
+    function array_is_list(array $array): bool { return p\Php81::array_is_list($array); }
+}
+
+if (!function_exists('enum_exists')) {
+    function enum_exists(string $enum, bool $autoload = true): bool { return $autoload && class_exists($enum) && false; }
+}
diff --git a/data/web/inc/lib/vendor/symfony/polyfill-php81/composer.json b/data/web/inc/lib/vendor/symfony/polyfill-php81/composer.json
new file mode 100644
index 00000000..28b6408e
--- /dev/null
+++ b/data/web/inc/lib/vendor/symfony/polyfill-php81/composer.json
@@ -0,0 +1,33 @@
+{
+    "name": "symfony/polyfill-php81",
+    "type": "library",
+    "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+    "keywords": ["polyfill", "shim", "compatibility", "portable"],
+    "homepage": "https://symfony.com",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Nicolas Grekas",
+            "email": "[email protected]"
+        },
+        {
+            "name": "Symfony Community",
+            "homepage": "https://symfony.com/contributors"
+        }
+    ],
+    "require": {
+        "php": ">=7.2"
+    },
+    "autoload": {
+        "psr-4": { "Symfony\\Polyfill\\Php81\\": "" },
+        "files": [ "bootstrap.php" ],
+        "classmap": [ "Resources/stubs" ]
+    },
+    "minimum-stability": "dev",
+    "extra": {
+        "thanks": {
+            "name": "symfony/polyfill",
+            "url": "https://github.com/symfony/polyfill"
+        }
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/.editorconfig b/data/web/inc/lib/vendor/twig/twig/.editorconfig
deleted file mode 100644
index 270f1d1b..00000000
--- a/data/web/inc/lib/vendor/twig/twig/.editorconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-; top-most EditorConfig file
-root = true
-
-; Unix-style newlines
-[*]
-end_of_line = LF
-
-[*.php]
-indent_style = space
-indent_size = 4
-
-[*.test]
-indent_style = space
-indent_size = 4
-
-[*.rst]
-indent_style = space
-indent_size = 4
diff --git a/data/web/inc/lib/vendor/twig/twig/.gitattributes b/data/web/inc/lib/vendor/twig/twig/.gitattributes
deleted file mode 100644
index 06bc3671..00000000
--- a/data/web/inc/lib/vendor/twig/twig/.gitattributes
+++ /dev/null
@@ -1,4 +0,0 @@
-/doc/ export-ignore
-/extra/ export-ignore
-/tests/ export-ignore
-/phpunit.xml.dist export-ignore
diff --git a/data/web/inc/lib/vendor/twig/twig/.github/workflows/ci.yml b/data/web/inc/lib/vendor/twig/twig/.github/workflows/ci.yml
deleted file mode 100644
index 65c2c407..00000000
--- a/data/web/inc/lib/vendor/twig/twig/.github/workflows/ci.yml
+++ /dev/null
@@ -1,149 +0,0 @@
-name: "CI"
-
-on:
-    pull_request:
-    push:
-        branches:
-            - '3.x'
-
-env:
-    SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE: 1
-
-permissions:
-  contents: read
-
-jobs:
-    tests:
-        name: "PHP ${{ matrix.php-version }}"
-
-        runs-on: 'ubuntu-latest'
-
-        continue-on-error: ${{ matrix.experimental }}
-
-        strategy:
-            matrix:
-                php-version:
-                    - '7.2.5'
-                    - '7.3'
-                    - '7.4'
-                    - '8.0'
-                    - '8.1'
-                experimental: [false]
-
-        steps:
-            - name: "Checkout code"
-              uses: actions/checkout@v4
-
-            - name: "Install PHP with extensions"
-              uses: shivammathur/setup-php@v2
-              with:
-                  coverage: "none"
-                  php-version: ${{ matrix.php-version }}
-                  ini-values: memory_limit=-1
-
-            - name: "Add PHPUnit matcher"
-              run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
-
-            - run: composer install
-
-            - name: "Install PHPUnit"
-              run: vendor/bin/simple-phpunit install
-
-            - name: "PHPUnit version"
-              run: vendor/bin/simple-phpunit --version
-
-            - name: "Run tests"
-              run: vendor/bin/simple-phpunit
-
-    extension-tests:
-        needs:
-            - 'tests'
-
-        name: "${{ matrix.extension }} with PHP ${{ matrix.php-version }}"
-
-        runs-on: 'ubuntu-latest'
-
-        continue-on-error: true
-
-        strategy:
-            matrix:
-                php-version:
-                    - '7.2.5'
-                    - '7.3'
-                    - '7.4'
-                    - '8.0'
-                    - '8.1'
-                extension:
-                    - 'extra/cache-extra'
-                    - 'extra/cssinliner-extra'
-                    - 'extra/html-extra'
-                    - 'extra/inky-extra'
-                    - 'extra/intl-extra'
-                    - 'extra/markdown-extra'
-                    - 'extra/string-extra'
-                    - 'extra/twig-extra-bundle'
-                experimental: [false]
-
-        steps:
-            - name: "Checkout code"
-              uses: actions/checkout@v4
-
-            - name: "Install PHP with extensions"
-              uses: shivammathur/setup-php@v2
-              with:
-                  coverage: "none"
-                  php-version: ${{ matrix.php-version }}
-                  ini-values: memory_limit=-1
-
-            - name: "Add PHPUnit matcher"
-              run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
-
-            - run: composer install
-
-            - name: "Install PHPUnit"
-              run: vendor/bin/simple-phpunit install
-
-            - name: "PHPUnit version"
-              run: vendor/bin/simple-phpunit --version
-
-            - name: "Composer install"
-              working-directory: ${{ matrix.extension}}
-              run: composer install
-
-            - name: "Run tests"
-              working-directory: ${{ matrix.extension}}
-              run: ../../vendor/bin/simple-phpunit
-
-#
-#    Drupal does not support Twig 3 now!
-#
-#    integration-tests:
-#        needs:
-#            - 'tests'
-#
-#        name: "Integration tests with PHP ${{ matrix.php-version }}"
-#
-#        runs-on: 'ubuntu-20.04'
-#
-#        continue-on-error: true
-#
-#        strategy:
-#            matrix:
-#                php-version:
-#                    - '7.3'
-#
-#        steps:
-#            - name: "Checkout code"
-#              uses: actions/checkout@v2
-#
-#            - name: "Install PHP with extensions"
-#              uses: shivammathur/setup-php@2
-#              with:
-#                  coverage: "none"
-#                  extensions: "gd, pdo_sqlite"
-#                  php-version: ${{ matrix.php-version }}
-#                  ini-values: memory_limit=-1
-#                  tools: composer:v2
-#
-#            - run: bash ./tests/drupal_test.sh
-#              shell: "bash"
diff --git a/data/web/inc/lib/vendor/twig/twig/.github/workflows/documentation.yml b/data/web/inc/lib/vendor/twig/twig/.github/workflows/documentation.yml
deleted file mode 100644
index 5caa8a33..00000000
--- a/data/web/inc/lib/vendor/twig/twig/.github/workflows/documentation.yml
+++ /dev/null
@@ -1,64 +0,0 @@
-name: "Documentation"
-
-on:
-    pull_request:
-    push:
-        branches:
-            - '2.x'
-            - '3.x'
-
-permissions:
-  contents: read
-
-jobs:
-    build:
-        name: "Build"
-
-        runs-on: ubuntu-latest
-
-        steps:
-            -   name: "Checkout code"
-                uses: actions/checkout@v4
-
-            -   name: "Set-up PHP"
-                uses: shivammathur/setup-php@v2
-                with:
-                    php-version: 8.1
-                    coverage: none
-                    tools: "composer:v2"
-
-            -   name: Get composer cache directory
-                id: composercache
-                working-directory: doc/_build
-                run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
-            -   name: Cache dependencies
-                uses: actions/cache@v3
-                with:
-                    path: ${{ steps.composercache.outputs.dir }}
-                    key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
-                    restore-keys: ${{ runner.os }}-composer-
-
-            -   name: "Install dependencies"
-                working-directory: doc/_build
-                run: composer install --prefer-dist --no-progress
-
-            -   name: "Build the docs"
-                working-directory: doc/_build
-                run: php build.php --disable-cache
-
-    doctor-rst:
-        name: "DOCtor-RST"
-
-        runs-on: ubuntu-latest
-
-        steps:
-            - name: "Checkout code"
-              uses: actions/checkout@v4
-
-            - name: "Run DOCtor-RST"
-              uses: docker://oskarstark/doctor-rst
-              with:
-                  args: --short
-              env:
-                  DOCS_DIR: 'doc/'
diff --git a/data/web/inc/lib/vendor/twig/twig/.gitignore b/data/web/inc/lib/vendor/twig/twig/.gitignore
deleted file mode 100644
index b197246b..00000000
--- a/data/web/inc/lib/vendor/twig/twig/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/doc/_build/vendor
-/doc/_build/output
-/composer.lock
-/phpunit.xml
-/vendor
-.phpunit.result.cache
diff --git a/data/web/inc/lib/vendor/twig/twig/.php-cs-fixer.dist.php b/data/web/inc/lib/vendor/twig/twig/.php-cs-fixer.dist.php
deleted file mode 100644
index b07ac7fc..00000000
--- a/data/web/inc/lib/vendor/twig/twig/.php-cs-fixer.dist.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-return (new PhpCsFixer\Config())
-    ->setRules([
-        '@Symfony' => true,
-        '@Symfony:risky' => true,
-        '@PHPUnit75Migration:risky' => true,
-        'php_unit_dedicate_assert' => ['target' => '5.6'],
-        'array_syntax' => ['syntax' => 'short'],
-        'php_unit_fqcn_annotation' => true,
-        'no_unreachable_default_argument_value' => false,
-        'braces' => ['allow_single_line_closure' => true],
-        'heredoc_to_nowdoc' => false,
-        'ordered_imports' => true,
-        'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
-        'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'all'],
-    ])
-    ->setRiskyAllowed(true)
-    ->setFinder((new PhpCsFixer\Finder())->in(__DIR__))
-;
diff --git a/data/web/inc/lib/vendor/twig/twig/CHANGELOG b/data/web/inc/lib/vendor/twig/twig/CHANGELOG
index 37938764..44c79b13 100644
--- a/data/web/inc/lib/vendor/twig/twig/CHANGELOG
+++ b/data/web/inc/lib/vendor/twig/twig/CHANGELOG
@@ -1,3 +1,178 @@
+# 3.14.0 (2024-09-09)
+
+ * Fix a security issue when an included sandboxed template has been loaded before without the sandbox context
+ * Add the possibility to reset globals via `Environment::resetGlobals()`
+ * Deprecate `Environment::mergeGlobals()`
+
+# 3.13.0 (2024-09-07)
+
+ * Add the `types` tag (experimental)
+ * Deprecate the `Twig\Test\NodeTestCase::getTests()` data provider, override `provideTests()` instead.
+ * Mark `Twig\Test\NodeTestCase::getEnvironment()` as final, override `createEnvironment()` instead.
+ * Deprecate `Twig\Test\NodeTestCase::getVariableGetter()`, call `createVariableGetter()` instead.
+ * Deprecate `Twig\Test\NodeTestCase::getAttributeGetter()`, call `createAttributeGetter()` instead.
+ * Deprecate not overriding `Twig\Test\IntegrationTestCase::getFixturesDirectory()`, this method will be abstract in 4.0
+ * Marked `Twig\Test\IntegrationTestCase::getTests()` and `getLegacyTests()` as final
+
+# 3.12.0 (2024-08-29)
+
+ * Deprecate the fact that the `extends` and `use` tags are always allowed in a sandboxed template.
+   This behavior will change in 4.0 where these tags will need to be explicitly allowed like any other tag.
+ * Deprecate the "tag" constructor argument of the "Twig\Node\Node" class as the tag is now automatically set by the Parser when needed
+ * Fix precedence of two-word tests when the first word is a valid test
+ * Deprecate the `spaceless` filter
+ * Deprecate some internal methods from `Parser`: `getBlockStack()`, `hasBlock()`, `getBlock()`, `hasMacro()`, `hasTraits()`, `getParent()`
+ * Deprecate passing `null` to `Twig\Parser::setParent()`
+ * Update `Node::__toString()` to include the node tag if set
+ * Add support for integers in methods of `Twig\Node\Node` that take a Node name
+ * Deprecate not passing a `BodyNode` instance as the body of a `ModuleNode` or `MacroNode` constructor
+ * Deprecate returning "null" from "TokenParserInterface::parse()".
+ * Deprecate `OptimizerNodeVisitor::OPTIMIZE_TEXT_NODES`
+ * Fix performance regression when `use_yield` is `false` (which is the default)
+ * Improve compatibility when `use_yield` is `false` (as extensions still using `echo` will work as is)
+ * Accept colons (`:`) in addition to equals (`=`) to separate argument names and values in named arguments
+ * Add the `html_cva` function (in the HTML extra package)
+ * Add support for named arguments to the `block` and `attribute` functions
+ * Throw a SyntaxError exception at compile time when a Twig callable has not the minimum number of required arguments
+ * Add a `CallableArgumentsExtractor` class
+ * Deprecate passing a name to `FunctionExpression`, `FilterExpression`, and `TestExpression`;
+   pass a `TwigFunction`, `TwigFilter`, or `TestFilter` instead
+ * Deprecate all Twig callable attributes on `FunctionExpression`, `FilterExpression`, and `TestExpression`
+ * Deprecate the `filter` node of `FilterExpression`
+ * Add the notion of Twig callables (functions, filters, and tests)
+ * Bump minimum PHP version to 8.0
+ * Fix integration tests when a test has more than one data/expect section and deprecations
+ * Add the `enum_cases` function
+
+# 3.11.0 (2024-08-08)
+
+ * Deprecate `OptimizerNodeVisitor::OPTIMIZE_RAW_FILTER`
+ * Add `Twig\Cache\ChainCache` and `Twig\Cache\ReadOnlyFilesystemCache`
+ * Add the possibility to deprecate attributes and nodes on `Node`
+ * Add the possibility to add a package and a version to the `deprecated` tag
+ * Add the possibility to add a package for filter/function/test deprecations
+ * Mark `ConstantExpression` as being `@final`
+ * Add the `find` filter
+ * Fix optimizer mode validation in `OptimizerNodeVisitor`
+ * Add the possibility to yield from a generator in `PrintNode`
+ * Add the `shuffle` filter
+ * Add the `singular` and `plural` filters in `StringExtension`
+ * Deprecate the second argument of `Twig\Node\Expression\CallExpression::compileArguments()`
+ * Deprecate `Twig\ExpressionParser\parseHashExpression()` in favor of
+   `Twig\ExpressionParser::parseMappingExpression()`
+ * Deprecate `Twig\ExpressionParser\parseArrayExpression()` in favor of
+   `Twig\ExpressionParser::parseSequenceExpression()`
+ * Add `sequence` and `mapping` tests
+ * Deprecate `Twig\Node\Expression\NameExpression::isSimple()` and
+    `Twig\Node\Expression\NameExpression::isSpecial()`
+
+# 3.10.3 (2024-05-16)
+
+ * Fix missing ; in generated code
+
+# 3.10.2 (2024-05-14)
+
+ * Fix support for the deprecated escaper signature
+
+# 3.10.1 (2024-05-12)
+
+ * Fix BC break on escaper extension
+ * Fix constant return type
+
+# 3.10.0 (2024-05-11)
+
+ * Make `CoreExtension::formatDate`, `CoreExtension::convertDate`, and
+   `CoreExtension::formatNumber` part of the public API
+ * Add `needs_charset` option for filters and functions
+ * Extract the escaping logic from the `EscaperExtension` class to a new
+   `EscaperRuntime` class.
+
+   The following methods from ``Twig\\Extension\\EscaperExtension`` are
+   deprecated: ``setEscaper()``, ``getEscapers()``, ``setSafeClasses``,
+   ``addSafeClasses()``. Use the same methods on the
+   ``Twig\\Runtime\\EscaperRuntime`` class instead.
+  * Fix capturing output from extensions that still use echo
+  * Fix a PHP warning in the Lexer on malformed templates
+  * Fix blocks not available under some circumstances
+  * Synchronize source context in templates when setting a Node on a Node
+
+# 3.9.3 (2024-04-18)
+
+ * Add missing `twig_escape_filter_is_safe` deprecated function
+ * Fix yield usage with CaptureNode
+ * Add missing unwrap call when using a TemplateWrapper instance internally
+ * Ensure Lexer is initialized early on
+
+# 3.9.2 (2024-04-17)
+
+ * Fix usage of display_end hook
+
+# 3.9.1 (2024-04-17)
+
+ * Fix missing `$blocks` variable in `CaptureNode`
+
+# 3.9.0 (2024-04-16)
+
+ * Add support for PHP 8.4
+ * Deprecate AbstractNodeVisitor
+ * Deprecate passing Template to Environment::resolveTemplate(), Environment::load(), and Template::loadTemplate()
+ * Add a new "yield" mode for output generation;
+   Node implementations that use "echo" or "print" should use "yield" instead;
+   all Node implementations should be flagged with `#[YieldReady]` once they've been made ready for "yield";
+   the "use_yield" Environment option can be turned on when all nodes have been made `#[YieldReady]`;
+   "yield" will be the only strategy supported in the next major version
+ * Add return type for Symfony 7 compatibility
+ * Fix premature loop exit in Security Policy lookup of allowed methods/properties
+ * Deprecate all internal extension functions in favor of methods on the extension classes
+ * Mark all extension functions as @internal
+ * Add SourcePolicyInterface to selectively enable the Sandbox based on a template's Source
+ * Throw a proper Twig exception when using cycle on an empty array
+
+# 3.8.0 (2023-11-21)
+
+ * Catch errors thrown during template rendering
+ * Fix IntlExtension::formatDateTime use of date formatter prototype
+ * Fix premature loop exit in Security Policy lookup of allowed methods/properties
+ * Remove NumberFormatter::TYPE_CURRENCY (deprecated in PHP 8.3)
+ * Restore return type annotations
+ * Allow Symfony 7 packages to be installed
+ * Deprecate `twig_test_iterable` function. Use the native `is_iterable` instead.
+
+# 3.7.1 (2023-08-28)
+
+ * Fix some phpdocs
+
+# 3.7.0 (2023-07-26)
+
+ * Add support for the ...spread operator on arrays and hashes
+
+# 3.6.1 (2023-06-08)
+
+ * Suppress some native return type deprecation messages
+
+# 3.6.0 (2023-05-03)
+
+ * Allow psr/container 2.0
+ * Add the new PHP 8.0 IntlDateFormatter::RELATIVE_* constants for date formatting
+ * Make the Lexer initialize itself lazily
+
+# 3.5.1 (2023-02-08)
+
+ * Arrow functions passed to the "reduce" filter now accept the current key as a third argument
+ * Restores the leniency of the matches twig comparison
+ * Fix error messages in sandboxed mode for "has some" and "has every"
+
+# 3.5.0 (2022-12-27)
+
+ * Make Twig\ExpressionParser non-internal
+ * Add "has some" and "has every" operators
+ * Add Compile::reset()
+ * Throw a better runtime error when the "matches" regexp is not valid
+ * Add "twig *_names" intl functions
+ * Fix optimizing closures callbacks
+ * Add a better exception when getting an undefined constant via `constant`
+ * Fix `if` nodes when outside of a block and with an empty body
+
 # 3.4.3 (2022-09-28)
 
  * Fix a security issue on filesystem loader (possibility to load a template outside a configured directory)
@@ -141,7 +316,7 @@
  * removed Parser::isReservedMacroName()
  * removed SanboxedPrintNode
  * removed Node::setTemplateName()
- * made classes maked as "@final" final
+ * made classes marked as "@final" final
  * removed InitRuntimeInterface, ExistsLoaderInterface, and SourceContextLoaderInterface
  * removed the "spaceless" tag
  * removed Twig\Environment::getBaseTemplateClass() and Twig\Environment::setBaseTemplateClass()
diff --git a/data/web/inc/lib/vendor/twig/twig/LICENSE b/data/web/inc/lib/vendor/twig/twig/LICENSE
index 8711927f..fd8234e5 100644
--- a/data/web/inc/lib/vendor/twig/twig/LICENSE
+++ b/data/web/inc/lib/vendor/twig/twig/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2022 by the Twig Team.
+Copyright (c) 2009-present by the Twig Team.
 
 All rights reserved.
 
diff --git a/data/web/inc/lib/vendor/twig/twig/README.rst b/data/web/inc/lib/vendor/twig/twig/README.rst
index fbe7e9a9..7bf8c673 100644
--- a/data/web/inc/lib/vendor/twig/twig/README.rst
+++ b/data/web/inc/lib/vendor/twig/twig/README.rst
@@ -11,7 +11,7 @@ Sponsors
 
 .. raw:: html
 
-    <a href="https://blackfire.io/docs/introduction?utm_source=twig&utm_medium=github_readme&utm_campaign=logo">
+    <a href="https://docs.blackfire.io/introduction?utm_source=twig&utm_medium=github_readme&utm_campaign=logo">
         <img src="https://static.blackfire.io/assets/intemporals/logo/png/blackfire-io_secondary_horizontal_transparent.png?1" width="255px" alt="Blackfire.io">
     </a>
 
diff --git a/data/web/inc/lib/vendor/twig/twig/composer.json b/data/web/inc/lib/vendor/twig/twig/composer.json
index 33e46405..e0c3e6c6 100644
--- a/data/web/inc/lib/vendor/twig/twig/composer.json
+++ b/data/web/inc/lib/vendor/twig/twig/composer.json
@@ -24,15 +24,23 @@
         }
     ],
     "require": {
-        "php": ">=7.2.5",
+        "php": ">=8.0.2",
+        "symfony/deprecation-contracts": "^2.5|^3",
         "symfony/polyfill-mbstring": "^1.3",
-        "symfony/polyfill-ctype": "^1.8"
+        "symfony/polyfill-ctype": "^1.8",
+        "symfony/polyfill-php81": "^1.29"
     },
     "require-dev": {
-        "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0",
-        "psr/container": "^1.0"
+        "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0",
+        "psr/container": "^1.0|^2.0"
     },
     "autoload": {
+        "files": [
+            "src/Resources/core.php",
+            "src/Resources/debug.php",
+            "src/Resources/escaper.php",
+            "src/Resources/string_loader.php"
+        ],
         "psr-4" : {
             "Twig\\" : "src/"
         }
@@ -41,10 +49,5 @@
         "psr-4" : {
             "Twig\\Tests\\" : "tests/"
         }
-    },
-    "extra": {
-        "branch-alias": {
-            "dev-master": "3.4-dev"
-        }
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/AbstractTwigCallable.php b/data/web/inc/lib/vendor/twig/twig/src/AbstractTwigCallable.php
new file mode 100644
index 00000000..f6718430
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/AbstractTwigCallable.php
@@ -0,0 +1,136 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig;
+
+/**
+ * @author Fabien Potencier <[email protected]>
+ */
+abstract class AbstractTwigCallable implements TwigCallableInterface
+{
+    protected $options;
+
+    private $name;
+    private $dynamicName;
+    private $callable;
+    private $arguments;
+
+    public function __construct(string $name, $callable = null, array $options = [])
+    {
+        $this->name = $this->dynamicName = $name;
+        $this->callable = $callable;
+        $this->arguments = [];
+        $this->options = array_merge([
+            'needs_environment' => false,
+            'needs_context' => false,
+            'needs_charset' => false,
+            'is_variadic' => false,
+            'deprecated' => false,
+            'deprecating_package' => '',
+            'alternative' => null,
+        ], $options);
+    }
+
+    public function __toString(): string
+    {
+        return \sprintf('%s(%s)', static::class, $this->name);
+    }
+
+    public function getName(): string
+    {
+        return $this->name;
+    }
+
+    public function getDynamicName(): string
+    {
+        return $this->dynamicName;
+    }
+
+    public function getCallable()
+    {
+        return $this->callable;
+    }
+
+    public function getNodeClass(): string
+    {
+        return $this->options['node_class'];
+    }
+
+    public function needsCharset(): bool
+    {
+        return $this->options['needs_charset'];
+    }
+
+    public function needsEnvironment(): bool
+    {
+        return $this->options['needs_environment'];
+    }
+
+    public function needsContext(): bool
+    {
+        return $this->options['needs_context'];
+    }
+
+    public function withDynamicArguments(string $name, string $dynamicName, array $arguments): self
+    {
+        $new = clone $this;
+        $new->name = $name;
+        $new->dynamicName = $dynamicName;
+        $new->arguments = $arguments;
+
+        return $new;
+    }
+
+    /**
+     * @deprecated since Twig 3.12, use withDynamicArguments() instead
+     */
+    public function setArguments(array $arguments): void
+    {
+        trigger_deprecation('twig/twig', '3.12', 'The "%s::setArguments()" method is deprecated, use "%s::withDynamicArguments()" instead.', static::class, static::class);
+
+        $this->arguments = $arguments;
+    }
+
+    public function getArguments(): array
+    {
+        return $this->arguments;
+    }
+
+    public function isVariadic(): bool
+    {
+        return $this->options['is_variadic'];
+    }
+
+    public function isDeprecated(): bool
+    {
+        return (bool) $this->options['deprecated'];
+    }
+
+    public function getDeprecatingPackage(): string
+    {
+        return $this->options['deprecating_package'];
+    }
+
+    public function getDeprecatedVersion(): string
+    {
+        return \is_bool($this->options['deprecated']) ? '' : $this->options['deprecated'];
+    }
+
+    public function getAlternative(): ?string
+    {
+        return $this->options['alternative'];
+    }
+
+    public function getMinimalNumberOfRequiredArguments(): int
+    {
+        return ($this->options['needs_charset'] ? 1 : 0) + ($this->options['needs_environment'] ? 1 : 0) + ($this->options['needs_context'] ? 1 : 0) + \count($this->arguments);
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Attribute/FirstClassTwigCallableReady.php b/data/web/inc/lib/vendor/twig/twig/src/Attribute/FirstClassTwigCallableReady.php
new file mode 100644
index 00000000..ffd8cffc
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Attribute/FirstClassTwigCallableReady.php
@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Attribute;
+
+/**
+ * Marks nodes that are ready to accept a TwigCallable instead of its name.
+ */
+#[\Attribute(\Attribute::TARGET_METHOD)]
+final class FirstClassTwigCallableReady
+{
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Attribute/YieldReady.php b/data/web/inc/lib/vendor/twig/twig/src/Attribute/YieldReady.php
new file mode 100644
index 00000000..335c4351
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Attribute/YieldReady.php
@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Attribute;
+
+/**
+ * Marks nodes that are ready for using "yield" instead of "echo" or "print()" for rendering.
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+final class YieldReady
+{
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Cache/ChainCache.php b/data/web/inc/lib/vendor/twig/twig/src/Cache/ChainCache.php
new file mode 100644
index 00000000..c94afdb4
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Cache/ChainCache.php
@@ -0,0 +1,79 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Cache;
+
+/**
+ * Chains several caches together.
+ *
+ * Cached items are fetched from the first cache having them in its data store.
+ * They are saved and deleted in all adapters at once.
+ *
+ * @author Quentin Devos <[email protected]>
+ */
+final class ChainCache implements CacheInterface
+{
+    /**
+     * @param iterable<CacheInterface> $caches The ordered list of caches used to store and fetch cached items
+     */
+    public function __construct(
+        private iterable $caches,
+    ) {
+    }
+
+    public function generateKey(string $name, string $className): string
+    {
+        return $className.'#'.$name;
+    }
+
+    public function write(string $key, string $content): void
+    {
+        $splitKey = $this->splitKey($key);
+
+        foreach ($this->caches as $cache) {
+            $cache->write($cache->generateKey(...$splitKey), $content);
+        }
+    }
+
+    public function load(string $key): void
+    {
+        [$name, $className] = $this->splitKey($key);
+
+        foreach ($this->caches as $cache) {
+            $cache->load($cache->generateKey($name, $className));
+
+            if (class_exists($className, false)) {
+                break;
+            }
+        }
+    }
+
+    public function getTimestamp(string $key): int
+    {
+        $splitKey = $this->splitKey($key);
+
+        foreach ($this->caches as $cache) {
+            if (0 < $timestamp = $cache->getTimestamp($cache->generateKey(...$splitKey))) {
+                return $timestamp;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * @return string[]
+     */
+    private function splitKey(string $key): array
+    {
+        return array_reverse(explode('#', $key, 2));
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Cache/FilesystemCache.php b/data/web/inc/lib/vendor/twig/twig/src/Cache/FilesystemCache.php
index e075563a..2e79fac0 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Cache/FilesystemCache.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Cache/FilesystemCache.php
@@ -50,11 +50,11 @@ class FilesystemCache implements CacheInterface
             if (false === @mkdir($dir, 0777, true)) {
                 clearstatcache(true, $dir);
                 if (!is_dir($dir)) {
-                    throw new \RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
+                    throw new \RuntimeException(\sprintf('Unable to create the cache directory (%s).', $dir));
                 }
             }
         } elseif (!is_writable($dir)) {
-            throw new \RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
+            throw new \RuntimeException(\sprintf('Unable to write in the cache directory (%s).', $dir));
         }
 
         $tmpFile = tempnam($dir, basename($key));
@@ -63,7 +63,7 @@ class FilesystemCache implements CacheInterface
 
             if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) {
                 // Compile cached file into bytecode cache
-                if (\function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) {
+                if (\function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) {
                     @opcache_invalidate($key, true);
                 } elseif (\function_exists('apc_compile_file')) {
                     apc_compile_file($key);
@@ -73,7 +73,7 @@ class FilesystemCache implements CacheInterface
             return;
         }
 
-        throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $key));
+        throw new \RuntimeException(\sprintf('Failed to write cache file "%s".', $key));
     }
 
     public function getTimestamp(string $key): int
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Cache/ReadOnlyFilesystemCache.php b/data/web/inc/lib/vendor/twig/twig/src/Cache/ReadOnlyFilesystemCache.php
new file mode 100644
index 00000000..3ba6514c
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Cache/ReadOnlyFilesystemCache.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Cache;
+
+/**
+ * Implements a cache on the filesystem that can only be read, not written to.
+ *
+ * @author Quentin Devos <[email protected]>
+ */
+class ReadOnlyFilesystemCache extends FilesystemCache
+{
+    public function write(string $key, string $content): void
+    {
+        // Do nothing with the content, it's a read-only filesystem.
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Compiler.php b/data/web/inc/lib/vendor/twig/twig/src/Compiler.php
index 95e1f183..1a43aa7f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Compiler.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Compiler.php
@@ -22,15 +22,16 @@ class Compiler
     private $lastLine;
     private $source;
     private $indentation;
-    private $env;
     private $debugInfo = [];
     private $sourceOffset;
     private $sourceLine;
     private $varNameSalt = 0;
+    private $didUseEcho = false;
+    private $didUseEchoStack = [];
 
-    public function __construct(Environment $env)
-    {
-        $this->env = $env;
+    public function __construct(
+        private Environment $env,
+    ) {
     }
 
     public function getEnvironment(): Environment
@@ -46,7 +47,7 @@ class Compiler
     /**
      * @return $this
      */
-    public function compile(Node $node, int $indentation = 0)
+    public function reset(int $indentation = 0)
     {
         $this->lastLine = null;
         $this->source = '';
@@ -57,23 +58,54 @@ class Compiler
         $this->indentation = $indentation;
         $this->varNameSalt = 0;
 
-        $node->compile($this);
-
         return $this;
     }
 
+    /**
+     * @return $this
+     */
+    public function compile(Node $node, int $indentation = 0)
+    {
+        $this->reset($indentation);
+        $this->didUseEchoStack[] = $this->didUseEcho;
+
+        try {
+            $this->didUseEcho = false;
+            $node->compile($this);
+
+            if ($this->didUseEcho) {
+                trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[YieldReady].', $this->didUseEcho, \get_class($node));
+            }
+
+            return $this;
+        } finally {
+            $this->didUseEcho = array_pop($this->didUseEchoStack);
+        }
+    }
+
     /**
      * @return $this
      */
     public function subcompile(Node $node, bool $raw = true)
     {
-        if (false === $raw) {
+        if (!$raw) {
             $this->source .= str_repeat(' ', $this->indentation * 4);
         }
 
-        $node->compile($this);
+        $this->didUseEchoStack[] = $this->didUseEcho;
 
-        return $this;
+        try {
+            $this->didUseEcho = false;
+            $node->compile($this);
+
+            if ($this->didUseEcho) {
+                trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[YieldReady].', $this->didUseEcho, \get_class($node));
+            }
+
+            return $this;
+        } finally {
+            $this->didUseEcho = array_pop($this->didUseEchoStack);
+        }
     }
 
     /**
@@ -83,6 +115,7 @@ class Compiler
      */
     public function raw(string $string)
     {
+        $this->checkForEcho($string);
         $this->source .= $string;
 
         return $this;
@@ -96,6 +129,7 @@ class Compiler
     public function write(...$strings)
     {
         foreach ($strings as $string) {
+            $this->checkForEcho($string);
             $this->source .= str_repeat(' ', $this->indentation * 4).$string;
         }
 
@@ -109,7 +143,7 @@ class Compiler
      */
     public function string(string $value)
     {
-        $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
+        $this->source .= \sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
 
         return $this;
     }
@@ -161,7 +195,7 @@ class Compiler
     public function addDebugInfo(Node $node)
     {
         if ($node->getTemplateLine() != $this->lastLine) {
-            $this->write(sprintf("// line %d\n", $node->getTemplateLine()));
+            $this->write(\sprintf("// line %d\n", $node->getTemplateLine()));
 
             $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
             $this->sourceOffset = \strlen($this->source);
@@ -209,6 +243,15 @@ class Compiler
 
     public function getVarName(): string
     {
-        return sprintf('__internal_compile_%d', $this->varNameSalt++);
+        return \sprintf('__internal_compile_%d', $this->varNameSalt++);
+    }
+
+    private function checkForEcho(string $string): void
+    {
+        if ($this->didUseEcho) {
+            return;
+        }
+
+        $this->didUseEcho = preg_match('/^\s*+(echo|print)\b/', $string, $m) ? $m[1] : false;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Environment.php b/data/web/inc/lib/vendor/twig/twig/src/Environment.php
index 85aaab91..24e55e97 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Environment.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Environment.php
@@ -22,12 +22,17 @@ use Twig\Extension\CoreExtension;
 use Twig\Extension\EscaperExtension;
 use Twig\Extension\ExtensionInterface;
 use Twig\Extension\OptimizerExtension;
+use Twig\Extension\YieldNotReadyExtension;
 use Twig\Loader\ArrayLoader;
 use Twig\Loader\ChainLoader;
 use Twig\Loader\LoaderInterface;
+use Twig\Node\Expression\Binary\AbstractBinary;
+use Twig\Node\Expression\Unary\AbstractUnary;
 use Twig\Node\ModuleNode;
 use Twig\Node\Node;
 use Twig\NodeVisitor\NodeVisitorInterface;
+use Twig\Runtime\EscaperRuntime;
+use Twig\RuntimeLoader\FactoryRuntimeLoader;
 use Twig\RuntimeLoader\RuntimeLoaderInterface;
 use Twig\TokenParser\TokenParserInterface;
 
@@ -38,11 +43,11 @@ use Twig\TokenParser\TokenParserInterface;
  */
 class Environment
 {
-    public const VERSION = '3.4.3';
-    public const VERSION_ID = 30403;
+    public const VERSION = '3.14.0';
+    public const VERSION_ID = 31400;
     public const MAJOR_VERSION = 3;
-    public const MINOR_VERSION = 4;
-    public const RELEASE_VERSION = 3;
+    public const MINOR_VERSION = 14;
+    public const RELEASE_VERSION = 0;
     public const EXTRA_VERSION = '';
 
     private $charset;
@@ -53,16 +58,19 @@ class Environment
     private $lexer;
     private $parser;
     private $compiler;
+    /** @var array<string, mixed> */
     private $globals = [];
     private $resolvedGlobals;
     private $loadedTemplates;
     private $strictVariables;
-    private $templateClassPrefix = '__TwigTemplate_';
     private $originalCache;
     private $extensionSet;
     private $runtimeLoaders = [];
     private $runtimes = [];
     private $optionsHash;
+    /** @var bool */
+    private $useYield;
+    private $defaultRuntimeLoader;
 
     /**
      * Constructor.
@@ -94,8 +102,12 @@ class Environment
      *  * optimizations: A flag that indicates which optimizations to apply
      *                   (default to -1 which means that all optimizations are enabled;
      *                   set it to 0 to disable).
+     *
+     *  * use_yield: true: forces templates to exclusively use "yield" instead of "echo" (all extensions must be yield ready)
+     *               false (default): allows templates to use a mix of "yield" and "echo" calls to allow for a progressive migration
+     *               Switch to "true" when possible as this will be the only supported mode in Twig 4.0
      */
-    public function __construct(LoaderInterface $loader, $options = [])
+    public function __construct(LoaderInterface $loader, array $options = [])
     {
         $this->setLoader($loader);
 
@@ -107,20 +119,38 @@ class Environment
             'cache' => false,
             'auto_reload' => null,
             'optimizations' => -1,
+            'use_yield' => false,
         ], $options);
 
+        $this->useYield = (bool) $options['use_yield'];
         $this->debug = (bool) $options['debug'];
         $this->setCharset($options['charset'] ?? 'UTF-8');
         $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
         $this->strictVariables = (bool) $options['strict_variables'];
         $this->setCache($options['cache']);
         $this->extensionSet = new ExtensionSet();
+        $this->defaultRuntimeLoader = new FactoryRuntimeLoader([
+            EscaperRuntime::class => function () { return new EscaperRuntime($this->charset); },
+        ]);
 
         $this->addExtension(new CoreExtension());
-        $this->addExtension(new EscaperExtension($options['autoescape']));
+        $escaperExt = new EscaperExtension($options['autoescape']);
+        $escaperExt->setEnvironment($this, false);
+        $this->addExtension($escaperExt);
+        if (\PHP_VERSION_ID >= 80000) {
+            $this->addExtension(new YieldNotReadyExtension($this->useYield));
+        }
         $this->addExtension(new OptimizerExtension($options['optimizations']));
     }
 
+    /**
+     * @internal
+     */
+    public function useYield(): bool
+    {
+        return $this->useYield;
+    }
+
     /**
      * Enables debugging mode.
      */
@@ -246,7 +276,6 @@ class Environment
      *
      *  * The cache key for the given template;
      *  * The currently enabled extensions;
-     *  * Whether the Twig C extension is available or not;
      *  * PHP version;
      *  * Twig version;
      *  * Options with what environment was created.
@@ -256,11 +285,11 @@ class Environment
      *
      * @internal
      */
-    public function getTemplateClass(string $name, int $index = null): string
+    public function getTemplateClass(string $name, ?int $index = null): string
     {
         $key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
 
-        return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
+        return '__TwigTemplate_'.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index);
     }
 
     /**
@@ -305,6 +334,11 @@ class Environment
         if ($name instanceof TemplateWrapper) {
             return $name;
         }
+        if ($name instanceof Template) {
+            trigger_deprecation('twig/twig', '3.9', 'Passing a "%s" instance to "%s" is deprecated.', self::class, __METHOD__);
+
+            return $name;
+        }
 
         return new TemplateWrapper($this, $this->loadTemplate($this->getTemplateClass($name), $name));
     }
@@ -315,8 +349,8 @@ class Environment
      * This method is for internal use only and should never be called
      * directly.
      *
-     * @param string $name  The template name
-     * @param int    $index The index if it is an embedded template
+     * @param string   $name  The template name
+     * @param int|null $index The index if it is an embedded template
      *
      * @throws LoaderError  When the template cannot be found
      * @throws RuntimeError When a previously generated cache is corrupted
@@ -324,7 +358,7 @@ class Environment
      *
      * @internal
      */
-    public function loadTemplate(string $cls, string $name, int $index = null): Template
+    public function loadTemplate(string $cls, string $name, ?int $index = null): Template
     {
         $mainCls = $cls;
         if (null !== $index) {
@@ -342,7 +376,6 @@ class Environment
                 $this->cache->load($key);
             }
 
-            $source = null;
             if (!class_exists($cls, false)) {
                 $source = $this->getLoader()->getSourceContext($name);
                 $content = $this->compileSource($source);
@@ -359,7 +392,7 @@ class Environment
                 }
 
                 if (!class_exists($cls, false)) {
-                    throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
+                    throw new RuntimeError(\sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source);
                 }
             }
         }
@@ -374,19 +407,19 @@ class Environment
      *
      * This method should not be used as a generic way to load templates.
      *
-     * @param string $template The template source
-     * @param string $name     An optional name of the template to be used in error messages
+     * @param string      $template The template source
+     * @param string|null $name     An optional name of the template to be used in error messages
      *
      * @throws LoaderError When the template cannot be found
      * @throws SyntaxError When an error occurred during compilation
      */
-    public function createTemplate(string $template, string $name = null): TemplateWrapper
+    public function createTemplate(string $template, ?string $name = null): TemplateWrapper
     {
         $hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false);
         if (null !== $name) {
-            $name = sprintf('%s (string template %s)', $name, $hash);
+            $name = \sprintf('%s (string template %s)', $name, $hash);
         } else {
-            $name = sprintf('__string_template__%s', $hash);
+            $name = \sprintf('__string_template__%s', $hash);
         }
 
         $loader = new ChainLoader([
@@ -419,10 +452,10 @@ class Environment
     /**
      * Tries to load a template consecutively from an array.
      *
-     * Similar to load() but it also accepts instances of \Twig\Template and
-     * \Twig\TemplateWrapper, and an array of templates where each is tried to be loaded.
+     * Similar to load() but it also accepts instances of \Twig\TemplateWrapper
+     * and an array of templates where each is tried to be loaded.
      *
-     * @param string|TemplateWrapper|array $names A template or an array of templates to try consecutively
+     * @param string|TemplateWrapper|array<string|TemplateWrapper> $names A template or an array of templates to try consecutively
      *
      * @throws LoaderError When none of the templates can be found
      * @throws SyntaxError When an error occurred during compilation
@@ -436,7 +469,9 @@ class Environment
         $count = \count($names);
         foreach ($names as $name) {
             if ($name instanceof Template) {
-                return $name;
+                trigger_deprecation('twig/twig', '3.9', 'Passing a "%s" instance to "%s" is deprecated.', Template::class, __METHOD__);
+
+                return new TemplateWrapper($this, $name);
             }
             if ($name instanceof TemplateWrapper) {
                 return $name;
@@ -449,7 +484,7 @@ class Environment
             return $this->load($name);
         }
 
-        throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
+        throw new LoaderError(\sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
     }
 
     public function setLexer(Lexer $lexer)
@@ -518,7 +553,7 @@ class Environment
             $e->setSourceContext($source);
             throw $e;
         } catch (\Exception $e) {
-            throw new SyntaxError(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
+            throw new SyntaxError(\sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
         }
     }
 
@@ -534,7 +569,7 @@ class Environment
 
     public function setCharset(string $charset)
     {
-        if ('UTF8' === $charset = null === $charset ? null : strtoupper($charset)) {
+        if ('UTF8' === $charset = strtoupper($charset ?: '')) {
             // iconv on Windows requires "UTF-8" instead of "UTF8"
             $charset = 'UTF-8';
         }
@@ -592,7 +627,11 @@ class Environment
             }
         }
 
-        throw new RuntimeError(sprintf('Unable to load the "%s" runtime.', $class));
+        if (null !== $runtime = $this->defaultRuntimeLoader->load($class)) {
+            return $this->runtimes[$class] = $runtime;
+        }
+
+        throw new RuntimeError(\sprintf('Unable to load the "%s" runtime.', $class));
     }
 
     public function addExtension(ExtensionInterface $extension)
@@ -763,7 +802,7 @@ class Environment
     public function addGlobal(string $name, $value)
     {
         if ($this->extensionSet->isInitialized() && !\array_key_exists($name, $this->getGlobals())) {
-            throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
+            throw new \LogicException(\sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
         }
 
         if (null !== $this->resolvedGlobals) {
@@ -775,6 +814,8 @@ class Environment
 
     /**
      * @internal
+     *
+     * @return array<string, mixed>
      */
     public function getGlobals(): array
     {
@@ -789,21 +830,26 @@ class Environment
         return array_merge($this->extensionSet->getGlobals(), $this->globals);
     }
 
+    public function resetGlobals(): void
+    {
+        $this->resolvedGlobals = null;
+        $this->extensionSet->resetGlobals();
+    }
+
+    /**
+     * @deprecated since Twig 3.14
+     */
     public function mergeGlobals(array $context): array
     {
-        // we don't use array_merge as the context being generally
-        // bigger than globals, this code is faster.
-        foreach ($this->getGlobals() as $key => $value) {
-            if (!\array_key_exists($key, $context)) {
-                $context[$key] = $value;
-            }
-        }
+        trigger_deprecation('twig/twig', '3.14', 'The "%s" method is deprecated.', __METHOD__);
 
-        return $context;
+        return $context + $this->getGlobals();
     }
 
     /**
      * @internal
+     *
+     * @return array<string, array{precedence: int, class: class-string<AbstractUnary>}>
      */
     public function getUnaryOperators(): array
     {
@@ -812,6 +858,8 @@ class Environment
 
     /**
      * @internal
+     *
+     * @return array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
      */
     public function getBinaryOperators(): array
     {
@@ -827,6 +875,7 @@ class Environment
             self::VERSION,
             (int) $this->debug,
             (int) $this->strictVariables,
+            $this->useYield ? '1' : '0',
         ]);
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Error/Error.php b/data/web/inc/lib/vendor/twig/twig/src/Error/Error.php
index a68be65f..61c309fa 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Error/Error.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Error/Error.php
@@ -53,7 +53,7 @@ class Error extends \Exception
      * @param int         $lineno  The template line where the error occurred
      * @param Source|null $source  The source context where the error occurred
      */
-    public function __construct(string $message, int $lineno = -1, Source $source = null, \Exception $previous = null)
+    public function __construct(string $message, int $lineno = -1, ?Source $source = null, ?\Throwable $previous = null)
     {
         parent::__construct('', 0, $previous);
 
@@ -93,7 +93,7 @@ class Error extends \Exception
         return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null;
     }
 
-    public function setSourceContext(Source $source = null): void
+    public function setSourceContext(?Source $source = null): void
     {
         if (null === $source) {
             $this->sourceCode = $this->name = $this->sourcePath = null;
@@ -130,28 +130,28 @@ class Error extends \Exception
         }
 
         $dot = false;
-        if ('.' === substr($this->message, -1)) {
+        if (str_ends_with($this->message, '.')) {
             $this->message = substr($this->message, 0, -1);
             $dot = true;
         }
 
         $questionMark = false;
-        if ('?' === substr($this->message, -1)) {
+        if (str_ends_with($this->message, '?')) {
             $this->message = substr($this->message, 0, -1);
             $questionMark = true;
         }
 
         if ($this->name) {
-            if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name, '__toString'))) {
-                $name = sprintf('"%s"', $this->name);
+            if (\is_string($this->name) || $this->name instanceof \Stringable) {
+                $name = \sprintf('"%s"', $this->name);
             } else {
                 $name = json_encode($this->name);
             }
-            $this->message .= sprintf(' in %s', $name);
+            $this->message .= \sprintf(' in %s', $name);
         }
 
         if ($this->lineno && $this->lineno >= 0) {
-            $this->message .= sprintf(' at line %d', $this->lineno);
+            $this->message .= \sprintf(' at line %d', $this->lineno);
         }
 
         if ($dot) {
@@ -172,7 +172,7 @@ class Error extends \Exception
         foreach ($backtrace as $trace) {
             if (isset($trace['object']) && $trace['object'] instanceof Template) {
                 $currentClass = \get_class($trace['object']);
-                $isEmbedContainer = null === $templateClass ? false : 0 === strpos($templateClass, $currentClass);
+                $isEmbedContainer = null === $templateClass ? false : str_starts_with($templateClass, $currentClass);
                 if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
                     $template = $trace['object'];
                     $templateClass = \get_class($trace['object']);
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Error/SyntaxError.php b/data/web/inc/lib/vendor/twig/twig/src/Error/SyntaxError.php
index 726b3309..841b653f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Error/SyntaxError.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Error/SyntaxError.php
@@ -30,7 +30,7 @@ class SyntaxError extends Error
         $alternatives = [];
         foreach ($items as $item) {
             $lev = levenshtein($name, $item);
-            if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) {
+            if ($lev <= \strlen($name) / 3 || str_contains($item, $name)) {
                 $alternatives[$item] = $lev;
             }
         }
@@ -41,6 +41,6 @@ class SyntaxError extends Error
 
         asort($alternatives);
 
-        $this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
+        $this->appendMessage(\sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives))));
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/ExpressionParser.php b/data/web/inc/lib/vendor/twig/twig/src/ExpressionParser.php
index 70b6eb05..dc4a6015 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/ExpressionParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/ExpressionParser.php
@@ -12,20 +12,21 @@
 
 namespace Twig;
 
+use Twig\Attribute\FirstClassTwigCallableReady;
 use Twig\Error\SyntaxError;
 use Twig\Node\Expression\AbstractExpression;
 use Twig\Node\Expression\ArrayExpression;
 use Twig\Node\Expression\ArrowFunctionExpression;
 use Twig\Node\Expression\AssignNameExpression;
+use Twig\Node\Expression\Binary\AbstractBinary;
 use Twig\Node\Expression\Binary\ConcatBinary;
-use Twig\Node\Expression\BlockReferenceExpression;
 use Twig\Node\Expression\ConditionalExpression;
 use Twig\Node\Expression\ConstantExpression;
 use Twig\Node\Expression\GetAttrExpression;
 use Twig\Node\Expression\MethodCallExpression;
 use Twig\Node\Expression\NameExpression;
-use Twig\Node\Expression\ParentExpression;
 use Twig\Node\Expression\TestExpression;
+use Twig\Node\Expression\Unary\AbstractUnary;
 use Twig\Node\Expression\Unary\NegUnary;
 use Twig\Node\Expression\Unary\NotUnary;
 use Twig\Node\Expression\Unary\PosUnary;
@@ -40,23 +41,22 @@ use Twig\Node\Node;
  * @see https://en.wikipedia.org/wiki/Operator-precedence_parser
  *
  * @author Fabien Potencier <[email protected]>
- *
- * @internal
  */
 class ExpressionParser
 {
     public const OPERATOR_LEFT = 1;
     public const OPERATOR_RIGHT = 2;
 
-    private $parser;
-    private $env;
+    /** @var array<string, array{precedence: int, class: class-string<AbstractUnary>}> */
     private $unaryOperators;
+    /** @var array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: self::OPERATOR_*}> */
     private $binaryOperators;
+    private $readyNodes = [];
 
-    public function __construct(Parser $parser, Environment $env)
-    {
-        $this->parser = $parser;
-        $this->env = $env;
+    public function __construct(
+        private Parser $parser,
+        private Environment $env,
+    ) {
         $this->unaryOperators = $env->getUnaryOperators();
         $this->binaryOperators = $env->getBinaryOperators();
     }
@@ -80,7 +80,7 @@ class ExpressionParser
             } elseif (isset($op['callable'])) {
                 $expr = $op['callable']($this->parser, $expr);
             } else {
-                $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
+                $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence'], true);
                 $class = $op['class'];
                 $expr = new $class($expr, $expr1, $token->getLine());
             }
@@ -103,52 +103,52 @@ class ExpressionParser
         $stream = $this->parser->getStream();
 
         // short array syntax (one argument, no parentheses)?
-        if ($stream->look(1)->test(/* Token::ARROW_TYPE */ 12)) {
+        if ($stream->look(1)->test(Token::ARROW_TYPE)) {
             $line = $stream->getCurrent()->getLine();
-            $token = $stream->expect(/* Token::NAME_TYPE */ 5);
+            $token = $stream->expect(Token::NAME_TYPE);
             $names = [new AssignNameExpression($token->getValue(), $token->getLine())];
-            $stream->expect(/* Token::ARROW_TYPE */ 12);
+            $stream->expect(Token::ARROW_TYPE);
 
             return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
         }
 
         // first, determine if we are parsing an arrow function by finding => (long form)
         $i = 0;
-        if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
+        if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, '(')) {
             return null;
         }
         ++$i;
         while (true) {
             // variable name
             ++$i;
-            if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
+            if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ',')) {
                 break;
             }
             ++$i;
         }
-        if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
+        if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ')')) {
             return null;
         }
         ++$i;
-        if (!$stream->look($i)->test(/* Token::ARROW_TYPE */ 12)) {
+        if (!$stream->look($i)->test(Token::ARROW_TYPE)) {
             return null;
         }
 
         // yes, let's parse it properly
-        $token = $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(');
+        $token = $stream->expect(Token::PUNCTUATION_TYPE, '(');
         $line = $token->getLine();
 
         $names = [];
         while (true) {
-            $token = $stream->expect(/* Token::NAME_TYPE */ 5);
+            $token = $stream->expect(Token::NAME_TYPE);
             $names[] = new AssignNameExpression($token->getValue(), $token->getLine());
 
-            if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
+            if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) {
                 break;
             }
         }
-        $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')');
-        $stream->expect(/* Token::ARROW_TYPE */ 12);
+        $stream->expect(Token::PUNCTUATION_TYPE, ')');
+        $stream->expect(Token::ARROW_TYPE);
 
         return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line);
     }
@@ -164,10 +164,10 @@ class ExpressionParser
             $class = $operator['class'];
 
             return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
-        } elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
+        } elseif ($token->test(Token::PUNCTUATION_TYPE, '(')) {
             $this->parser->getStream()->next();
             $expr = $this->parseExpression();
-            $this->parser->getStream()->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'An opened parenthesis is not properly closed');
+            $this->parser->getStream()->expect(Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
 
             return $this->parsePostfixExpression($expr);
         }
@@ -177,15 +177,18 @@ class ExpressionParser
 
     private function parseConditionalExpression($expr): AbstractExpression
     {
-        while ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, '?')) {
-            if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
+        while ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, '?')) {
+            if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) {
                 $expr2 = $this->parseExpression();
-                if ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
+                if ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) {
+                    // Ternary operator (expr ? expr2 : expr3)
                     $expr3 = $this->parseExpression();
                 } else {
+                    // Ternary without else (expr ? expr2)
                     $expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine());
                 }
             } else {
+                // Ternary without then (expr ?: expr3)
                 $expr2 = $expr;
                 $expr3 = $this->parseExpression();
             }
@@ -198,19 +201,19 @@ class ExpressionParser
 
     private function isUnary(Token $token): bool
     {
-        return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->unaryOperators[$token->getValue()]);
+        return $token->test(Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
     }
 
     private function isBinary(Token $token): bool
     {
-        return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->binaryOperators[$token->getValue()]);
+        return $token->test(Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
     }
 
     public function parsePrimaryExpression()
     {
         $token = $this->parser->getCurrentToken();
         switch ($token->getType()) {
-            case /* Token::NAME_TYPE */ 5:
+            case Token::NAME_TYPE:
                 $this->parser->getStream()->next();
                 switch ($token->getValue()) {
                     case 'true':
@@ -239,17 +242,17 @@ class ExpressionParser
                 }
                 break;
 
-            case /* Token::NUMBER_TYPE */ 6:
+            case Token::NUMBER_TYPE:
                 $this->parser->getStream()->next();
                 $node = new ConstantExpression($token->getValue(), $token->getLine());
                 break;
 
-            case /* Token::STRING_TYPE */ 7:
-            case /* Token::INTERPOLATION_START_TYPE */ 10:
+            case Token::STRING_TYPE:
+            case Token::INTERPOLATION_START_TYPE:
                 $node = $this->parseStringExpression();
                 break;
 
-            case /* Token::OPERATOR_TYPE */ 8:
+            case Token::OPERATOR_TYPE:
                 if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
                     // in this context, string operators are variable names
                     $this->parser->getStream()->next();
@@ -260,7 +263,7 @@ class ExpressionParser
                 if (isset($this->unaryOperators[$token->getValue()])) {
                     $class = $this->unaryOperators[$token->getValue()]['class'];
                     if (!\in_array($class, [NegUnary::class, PosUnary::class])) {
-                        throw new SyntaxError(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
+                        throw new SyntaxError(\sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
                     }
 
                     $this->parser->getStream()->next();
@@ -272,14 +275,14 @@ class ExpressionParser
 
                 // no break
             default:
-                if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) {
-                    $node = $this->parseArrayExpression();
-                } elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) {
-                    $node = $this->parseHashExpression();
-                } elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
-                    throw new SyntaxError(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
+                if ($token->test(Token::PUNCTUATION_TYPE, '[')) {
+                    $node = $this->parseSequenceExpression();
+                } elseif ($token->test(Token::PUNCTUATION_TYPE, '{')) {
+                    $node = $this->parseMappingExpression();
+                } elseif ($token->test(Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
+                    throw new SyntaxError(\sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
                 } else {
-                    throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
+                    throw new SyntaxError(\sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
                 }
         }
 
@@ -294,12 +297,12 @@ class ExpressionParser
         // a string cannot be followed by another string in a single expression
         $nextCanBeString = true;
         while (true) {
-            if ($nextCanBeString && $token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) {
+            if ($nextCanBeString && $token = $stream->nextIf(Token::STRING_TYPE)) {
                 $nodes[] = new ConstantExpression($token->getValue(), $token->getLine());
                 $nextCanBeString = false;
-            } elseif ($stream->nextIf(/* Token::INTERPOLATION_START_TYPE */ 10)) {
+            } elseif ($stream->nextIf(Token::INTERPOLATION_START_TYPE)) {
                 $nodes[] = $this->parseExpression();
-                $stream->expect(/* Token::INTERPOLATION_END_TYPE */ 11);
+                $stream->expect(Token::INTERPOLATION_END_TYPE);
                 $nextCanBeString = true;
             } else {
                 break;
@@ -314,56 +317,91 @@ class ExpressionParser
         return $expr;
     }
 
+    /**
+     * @deprecated since 3.11, use parseSequenceExpression() instead
+     */
     public function parseArrayExpression()
+    {
+        trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseSequenceExpression()" instead.', __METHOD__);
+
+        return $this->parseSequenceExpression();
+    }
+
+    public function parseSequenceExpression()
     {
         $stream = $this->parser->getStream();
-        $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected');
+        $stream->expect(Token::PUNCTUATION_TYPE, '[', 'A sequence element was expected');
 
         $node = new ArrayExpression([], $stream->getCurrent()->getLine());
         $first = true;
-        while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
+        while (!$stream->test(Token::PUNCTUATION_TYPE, ']')) {
             if (!$first) {
-                $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma');
+                $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A sequence element must be followed by a comma');
 
                 // trailing ,?
-                if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
+                if ($stream->test(Token::PUNCTUATION_TYPE, ']')) {
                     break;
                 }
             }
             $first = false;
 
-            $node->addElement($this->parseExpression());
+            if ($stream->test(Token::SPREAD_TYPE)) {
+                $stream->next();
+                $expr = $this->parseExpression();
+                $expr->setAttribute('spread', true);
+                $node->addElement($expr);
+            } else {
+                $node->addElement($this->parseExpression());
+            }
         }
-        $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed');
+        $stream->expect(Token::PUNCTUATION_TYPE, ']', 'An opened sequence is not properly closed');
 
         return $node;
     }
 
+    /**
+     * @deprecated since 3.11, use parseMappingExpression() instead
+     */
     public function parseHashExpression()
+    {
+        trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseMappingExpression()" instead.', __METHOD__);
+
+        return $this->parseMappingExpression();
+    }
+
+    public function parseMappingExpression()
     {
         $stream = $this->parser->getStream();
-        $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '{', 'A hash element was expected');
+        $stream->expect(Token::PUNCTUATION_TYPE, '{', 'A mapping element was expected');
 
         $node = new ArrayExpression([], $stream->getCurrent()->getLine());
         $first = true;
-        while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
+        while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) {
             if (!$first) {
-                $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma');
+                $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A mapping value must be followed by a comma');
 
                 // trailing ,?
-                if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) {
+                if ($stream->test(Token::PUNCTUATION_TYPE, '}')) {
                     break;
                 }
             }
             $first = false;
 
-            // a hash key can be:
+            if ($stream->test(Token::SPREAD_TYPE)) {
+                $stream->next();
+                $value = $this->parseExpression();
+                $value->setAttribute('spread', true);
+                $node->addElement($value);
+                continue;
+            }
+
+            // a mapping key can be:
             //
             //  * a number -- 12
             //  * a string -- 'a'
             //  * a name, which is equivalent to a string -- a
             //  * an expression, which must be enclosed in parentheses -- (1 + 2)
-            if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) {
+            if ($token = $stream->nextIf(Token::NAME_TYPE)) {
                 $key = new ConstantExpression($token->getValue(), $token->getLine());
 
                 // {a} is a shortcut for {a:a}
@@ -372,22 +410,22 @@ class ExpressionParser
                     $node->addElement($value, $key);
                     continue;
                 }
-            } elseif (($token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) || $token = $stream->nextIf(/* Token::NUMBER_TYPE */ 6)) {
+            } elseif (($token = $stream->nextIf(Token::STRING_TYPE)) || $token = $stream->nextIf(Token::NUMBER_TYPE)) {
                 $key = new ConstantExpression($token->getValue(), $token->getLine());
-            } elseif ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
+            } elseif ($stream->test(Token::PUNCTUATION_TYPE, '(')) {
                 $key = $this->parseExpression();
             } else {
                 $current = $stream->getCurrent();
 
-                throw new SyntaxError(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
+                throw new SyntaxError(\sprintf('A mapping key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext());
             }
 
-            $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ':', 'A hash key must be followed by a colon (:)');
+            $stream->expect(Token::PUNCTUATION_TYPE, ':', 'A mapping key must be followed by a colon (:)');
             $value = $this->parseExpression();
 
             $node->addElement($value, $key);
         }
-        $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed');
+        $stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened mapping is not properly closed');
 
         return $node;
     }
@@ -396,7 +434,7 @@ class ExpressionParser
     {
         while (true) {
             $token = $this->parser->getCurrentToken();
-            if (/* Token::PUNCTUATION_TYPE */ 9 == $token->getType()) {
+            if (Token::PUNCTUATION_TYPE == $token->getType()) {
                 if ('.' == $token->getValue() || '[' == $token->getValue()) {
                     $node = $this->parseSubscriptExpression($node);
                 } elseif ('|' == $token->getValue()) {
@@ -414,50 +452,37 @@ class ExpressionParser
 
     public function getFunctionNode($name, $line)
     {
-        switch ($name) {
-            case 'parent':
-                $this->parseArguments();
-                if (!\count($this->parser->getBlockStack())) {
-                    throw new SyntaxError('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
-                }
+        if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
+            $arguments = new ArrayExpression([], $line);
+            foreach ($this->parseArguments() as $n) {
+                $arguments->addElement($n);
+            }
 
-                if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
-                    throw new SyntaxError('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
-                }
+            $node = new MethodCallExpression($alias['node'], $alias['name'], $arguments, $line);
+            $node->setAttribute('safe', true);
 
-                return new ParentExpression($this->parser->peekBlockStack(), $line);
-            case 'block':
-                $args = $this->parseArguments();
-                if (\count($args) < 1) {
-                    throw new SyntaxError('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
-                }
+            return $node;
+        }
 
-                return new BlockReferenceExpression($args->getNode(0), \count($args) > 1 ? $args->getNode(1) : null, $line);
-            case 'attribute':
-                $args = $this->parseArguments();
-                if (\count($args) < 2) {
-                    throw new SyntaxError('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
-                }
+        $args = $this->parseArguments(true);
+        $function = $this->getFunction($name, $line);
 
-                return new GetAttrExpression($args->getNode(0), $args->getNode(1), \count($args) > 2 ? $args->getNode(2) : null, Template::ANY_CALL, $line);
-            default:
-                if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
-                    $arguments = new ArrayExpression([], $line);
-                    foreach ($this->parseArguments() as $n) {
-                        $arguments->addElement($n);
-                    }
-
-                    $node = new MethodCallExpression($alias['node'], $alias['name'], $arguments, $line);
-                    $node->setAttribute('safe', true);
+        if ($function->getParserCallable()) {
+            $fakeNode = new Node(lineno: $line);
+            $fakeNode->setSourceContext($this->parser->getStream()->getSourceContext());
 
-                    return $node;
-                }
+            return ($function->getParserCallable())($this->parser, $fakeNode, $args, $line);
+        }
 
-                $args = $this->parseArguments(true);
-                $class = $this->getFunctionNodeClass($name, $line);
+        if (!isset($this->readyNodes[$class = $function->getNodeClass()])) {
+            $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class);
+        }
 
-                return new $class($name, $args, $line);
+        if (!$ready = $this->readyNodes[$class]) {
+            trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFunction" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class);
         }
+
+        return new $class($ready ? $function : $function->getName(), $args, $line);
     }
 
     public function parseSubscriptExpression($node)
@@ -470,29 +495,25 @@ class ExpressionParser
         if ('.' == $token->getValue()) {
             $token = $stream->next();
             if (
-                /* Token::NAME_TYPE */ 5 == $token->getType()
+                Token::NAME_TYPE == $token->getType()
                 ||
-                /* Token::NUMBER_TYPE */ 6 == $token->getType()
+                Token::NUMBER_TYPE == $token->getType()
                 ||
-                (/* Token::OPERATOR_TYPE */ 8 == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue()))
+                (Token::OPERATOR_TYPE == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue()))
             ) {
                 $arg = new ConstantExpression($token->getValue(), $lineno);
 
-                if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
+                if ($stream->test(Token::PUNCTUATION_TYPE, '(')) {
                     $type = Template::METHOD_CALL;
                     foreach ($this->parseArguments() as $n) {
                         $arguments->addElement($n);
                     }
                 }
             } else {
-                throw new SyntaxError(sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
+                throw new SyntaxError(\sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext());
             }
 
             if ($node instanceof NameExpression && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
-                if (!$arg instanceof ConstantExpression) {
-                    throw new SyntaxError(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
-                }
-
                 $name = $arg->getAttribute('value');
 
                 $node = new MethodCallExpression($node, 'macro_'.$name, $arguments, $lineno);
@@ -505,34 +526,34 @@ class ExpressionParser
 
             // slice?
             $slice = false;
-            if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
+            if ($stream->test(Token::PUNCTUATION_TYPE, ':')) {
                 $slice = true;
                 $arg = new ConstantExpression(0, $token->getLine());
             } else {
                 $arg = $this->parseExpression();
             }
 
-            if ($stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) {
+            if ($stream->nextIf(Token::PUNCTUATION_TYPE, ':')) {
                 $slice = true;
             }
 
             if ($slice) {
-                if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) {
+                if ($stream->test(Token::PUNCTUATION_TYPE, ']')) {
                     $length = new ConstantExpression(null, $token->getLine());
                 } else {
                     $length = $this->parseExpression();
                 }
 
-                $class = $this->getFilterNodeClass('slice', $token->getLine());
+                $filter = $this->getFilter('slice', $token->getLine());
                 $arguments = new Node([$arg, $length]);
-                $filter = new $class($node, new ConstantExpression('slice', $token->getLine()), $arguments, $token->getLine());
+                $filter = new ($filter->getNodeClass())($node, $filter, $arguments, $token->getLine());
 
-                $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
+                $stream->expect(Token::PUNCTUATION_TYPE, ']');
 
                 return $filter;
             }
 
-            $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']');
+            $stream->expect(Token::PUNCTUATION_TYPE, ']');
         }
 
         return new GetAttrExpression($node, $arg, $arguments, $type, $lineno);
@@ -545,23 +566,35 @@ class ExpressionParser
         return $this->parseFilterExpressionRaw($node);
     }
 
-    public function parseFilterExpressionRaw($node, $tag = null)
+    public function parseFilterExpressionRaw($node)
     {
+        if (\func_num_args() > 1) {
+            trigger_deprecation('twig/twig', '3.12', 'Passing a second argument to "%s()" is deprecated.', __METHOD__);
+        }
+
         while (true) {
-            $token = $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5);
+            $token = $this->parser->getStream()->expect(Token::NAME_TYPE);
 
-            $name = new ConstantExpression($token->getValue(), $token->getLine());
-            if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
+            if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '(')) {
                 $arguments = new Node();
             } else {
                 $arguments = $this->parseArguments(true, false, true);
             }
 
-            $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
+            $filter = $this->getFilter($token->getValue(), $token->getLine());
 
-            $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
+            $ready = true;
+            if (!isset($this->readyNodes[$class = $filter->getNodeClass()])) {
+                $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class);
+            }
 
-            if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '|')) {
+            if (!$ready = $this->readyNodes[$class]) {
+                trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFilter" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class);
+            }
+
+            $node = new $class($node, $ready ? $filter : new ConstantExpression($filter->getName(), $token->getLine()), $arguments, $token->getLine());
+
+            if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '|')) {
                 break;
             }
 
@@ -575,7 +608,7 @@ class ExpressionParser
      * Parses arguments.
      *
      * @param bool $namedArguments Whether to allow named arguments or not
-     * @param bool $definition     Whether we are parsing arguments for a function definition
+     * @param bool $definition     Whether we are parsing arguments for a function (or macro) definition
      *
      * @return Node
      *
@@ -586,28 +619,28 @@ class ExpressionParser
         $args = [];
         $stream = $this->parser->getStream();
 
-        $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(', 'A list of arguments must begin with an opening parenthesis');
-        while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
+        $stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
+        while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) {
             if (!empty($args)) {
-                $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'Arguments must be separated by a comma');
+                $stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
 
                 // if the comma above was a trailing comma, early exit the argument parse loop
-                if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) {
+                if ($stream->test(Token::PUNCTUATION_TYPE, ')')) {
                     break;
                 }
             }
 
             if ($definition) {
-                $token = $stream->expect(/* Token::NAME_TYPE */ 5, null, 'An argument must be a name');
+                $token = $stream->expect(Token::NAME_TYPE, null, 'An argument must be a name');
                 $value = new NameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine());
             } else {
                 $value = $this->parseExpression(0, $allowArrow);
             }
 
             $name = null;
-            if ($namedArguments && $token = $stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) {
+            if ($namedArguments && (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':')))) {
                 if (!$value instanceof NameExpression) {
-                    throw new SyntaxError(sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext());
+                    throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext());
                 }
                 $name = $value->getAttribute('name');
 
@@ -615,7 +648,7 @@ class ExpressionParser
                     $value = $this->parsePrimaryExpression();
 
                     if (!$this->checkConstantExpression($value)) {
-                        throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $stream->getSourceContext());
+                        throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).', $token->getLine(), $stream->getSourceContext());
                     }
                 } else {
                     $value = $this->parseExpression(0, $allowArrow);
@@ -626,6 +659,7 @@ class ExpressionParser
                 if (null === $name) {
                     $name = $value->getAttribute('name');
                     $value = new ConstantExpression(null, $this->parser->getCurrentToken()->getLine());
+                    $value->setAttribute('is_implicit', true);
                 }
                 $args[$name] = $value;
             } else {
@@ -636,7 +670,7 @@ class ExpressionParser
                 }
             }
         }
-        $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'A list of arguments must be closed by a parenthesis');
+        $stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
 
         return new Node($args);
     }
@@ -647,19 +681,19 @@ class ExpressionParser
         $targets = [];
         while (true) {
             $token = $this->parser->getCurrentToken();
-            if ($stream->test(/* Token::OPERATOR_TYPE */ 8) && preg_match(Lexer::REGEX_NAME, $token->getValue())) {
+            if ($stream->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue())) {
                 // in this context, string operators are variable names
                 $this->parser->getStream()->next();
             } else {
-                $stream->expect(/* Token::NAME_TYPE */ 5, null, 'Only variables can be assigned to');
+                $stream->expect(Token::NAME_TYPE, null, 'Only variables can be assigned to');
             }
             $value = $token->getValue();
             if (\in_array(strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), ['true', 'false', 'none', 'null'])) {
-                throw new SyntaxError(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
+                throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
             }
             $targets[] = new AssignNameExpression($value, $token->getLine());
 
-            if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
+            if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) {
                 break;
             }
         }
@@ -672,7 +706,7 @@ class ExpressionParser
         $targets = [];
         while (true) {
             $targets[] = $this->parseExpression();
-            if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
+            if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ',')) {
                 break;
             }
         }
@@ -688,121 +722,115 @@ class ExpressionParser
     private function parseTestExpression(Node $node): TestExpression
     {
         $stream = $this->parser->getStream();
-        list($name, $test) = $this->getTest($node->getTemplateLine());
+        $test = $this->getTest($node->getTemplateLine());
 
-        $class = $this->getTestNodeClass($test);
         $arguments = null;
-        if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) {
+        if ($stream->test(Token::PUNCTUATION_TYPE, '(')) {
             $arguments = $this->parseArguments(true);
         } elseif ($test->hasOneMandatoryArgument()) {
             $arguments = new Node([0 => $this->parsePrimaryExpression()]);
         }
 
-        if ('defined' === $name && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) {
+        if ('defined' === $test->getName() && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) {
             $node = new MethodCallExpression($alias['node'], $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine());
             $node->setAttribute('safe', true);
         }
 
-        return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
+        $ready = $test instanceof TwigTest;
+        if (!isset($this->readyNodes[$class = $test->getNodeClass()])) {
+            $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class);
+        }
+
+        if (!$ready = $this->readyNodes[$class]) {
+            trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigTest" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class);
+        }
+
+        return new $class($node, $ready ? $test : $test->getName(), $arguments, $this->parser->getCurrentToken()->getLine());
     }
 
-    private function getTest(int $line): array
+    private function getTest(int $line): TwigTest
     {
         $stream = $this->parser->getStream();
-        $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
+        $name = $stream->expect(Token::NAME_TYPE)->getValue();
 
-        if ($test = $this->env->getTest($name)) {
-            return [$name, $test];
-        }
-
-        if ($stream->test(/* Token::NAME_TYPE */ 5)) {
+        if ($stream->test(Token::NAME_TYPE)) {
             // try 2-words tests
             $name = $name.' '.$this->parser->getCurrentToken()->getValue();
 
             if ($test = $this->env->getTest($name)) {
                 $stream->next();
-
-                return [$name, $test];
             }
+        } else {
+            $test = $this->env->getTest($name);
         }
 
-        $e = new SyntaxError(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
-        $e->addSuggestions($name, array_keys($this->env->getTests()));
+        if (!$test) {
+            $e = new SyntaxError(\sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
+            $e->addSuggestions($name, array_keys($this->env->getTests()));
 
-        throw $e;
-    }
+            throw $e;
+        }
 
-    private function getTestNodeClass(TwigTest $test): string
-    {
         if ($test->isDeprecated()) {
             $stream = $this->parser->getStream();
-            $message = sprintf('Twig Test "%s" is deprecated', $test->getName());
+            $message = \sprintf('Twig Test "%s" is deprecated', $test->getName());
 
-            if ($test->getDeprecatedVersion()) {
-                $message .= sprintf(' since version %s', $test->getDeprecatedVersion());
-            }
             if ($test->getAlternative()) {
-                $message .= sprintf('. Use "%s" instead', $test->getAlternative());
+                $message .= \sprintf('. Use "%s" instead', $test->getAlternative());
             }
             $src = $stream->getSourceContext();
-            $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
+            $message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine());
 
-            @trigger_error($message, \E_USER_DEPRECATED);
+            trigger_deprecation($test->getDeprecatingPackage(), $test->getDeprecatedVersion(), $message);
         }
 
-        return $test->getNodeClass();
+        return $test;
     }
 
-    private function getFunctionNodeClass(string $name, int $line): string
+    private function getFunction(string $name, int $line): TwigFunction
     {
         if (!$function = $this->env->getFunction($name)) {
-            $e = new SyntaxError(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
+            $e = new SyntaxError(\sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
             $e->addSuggestions($name, array_keys($this->env->getFunctions()));
 
             throw $e;
         }
 
         if ($function->isDeprecated()) {
-            $message = sprintf('Twig Function "%s" is deprecated', $function->getName());
-            if ($function->getDeprecatedVersion()) {
-                $message .= sprintf(' since version %s', $function->getDeprecatedVersion());
-            }
+            $message = \sprintf('Twig Function "%s" is deprecated', $function->getName());
             if ($function->getAlternative()) {
-                $message .= sprintf('. Use "%s" instead', $function->getAlternative());
+                $message .= \sprintf('. Use "%s" instead', $function->getAlternative());
             }
             $src = $this->parser->getStream()->getSourceContext();
-            $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
+            $message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
 
-            @trigger_error($message, \E_USER_DEPRECATED);
+            trigger_deprecation($function->getDeprecatingPackage(), $function->getDeprecatedVersion(), $message);
         }
 
-        return $function->getNodeClass();
+        return $function;
     }
 
-    private function getFilterNodeClass(string $name, int $line): string
+    private function getFilter(string $name, int $line): TwigFilter
     {
         if (!$filter = $this->env->getFilter($name)) {
-            $e = new SyntaxError(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
+            $e = new SyntaxError(\sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
             $e->addSuggestions($name, array_keys($this->env->getFilters()));
 
             throw $e;
         }
 
         if ($filter->isDeprecated()) {
-            $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
-            if ($filter->getDeprecatedVersion()) {
-                $message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
-            }
+            $message = \sprintf('Twig Filter "%s" is deprecated', $filter->getName());
             if ($filter->getAlternative()) {
-                $message .= sprintf('. Use "%s" instead', $filter->getAlternative());
+                $message .= \sprintf('. Use "%s" instead', $filter->getAlternative());
             }
             $src = $this->parser->getStream()->getSourceContext();
-            $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
+            $message .= \sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line);
 
-            @trigger_error($message, \E_USER_DEPRECATED);
+            trigger_deprecation($filter->getDeprecatingPackage(), $filter->getDeprecatedVersion(), $message);
         }
 
-        return $filter->getNodeClass();
+        return $filter;
     }
 
     // checks that the node only contains "constant" elements
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/AbstractExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/AbstractExtension.php
index 422925f3..a1b083b6 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/AbstractExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/AbstractExtension.php
@@ -40,6 +40,6 @@ abstract class AbstractExtension implements ExtensionInterface
 
     public function getOperators()
     {
-        return [];
+        return [[], []];
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/CoreExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/CoreExtension.php
index b7798585..3ed27a35 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/CoreExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/CoreExtension.php
@@ -9,8 +9,15 @@
  * file that was distributed with this source code.
  */
 
-namespace Twig\Extension {
+namespace Twig\Extension;
+
+use Twig\Environment;
+use Twig\Error\LoaderError;
+use Twig\Error\RuntimeError;
+use Twig\Error\SyntaxError;
 use Twig\ExpressionParser;
+use Twig\Markup;
+use Twig\Node\Expression\AbstractExpression;
 use Twig\Node\Expression\Binary\AddBinary;
 use Twig\Node\Expression\Binary\AndBinary;
 use Twig\Node\Expression\Binary\BitwiseAndBinary;
@@ -23,6 +30,8 @@ use Twig\Node\Expression\Binary\EqualBinary;
 use Twig\Node\Expression\Binary\FloorDivBinary;
 use Twig\Node\Expression\Binary\GreaterBinary;
 use Twig\Node\Expression\Binary\GreaterEqualBinary;
+use Twig\Node\Expression\Binary\HasEveryBinary;
+use Twig\Node\Expression\Binary\HasSomeBinary;
 use Twig\Node\Expression\Binary\InBinary;
 use Twig\Node\Expression\Binary\LessBinary;
 use Twig\Node\Expression\Binary\LessEqualBinary;
@@ -37,8 +46,12 @@ use Twig\Node\Expression\Binary\RangeBinary;
 use Twig\Node\Expression\Binary\SpaceshipBinary;
 use Twig\Node\Expression\Binary\StartsWithBinary;
 use Twig\Node\Expression\Binary\SubBinary;
+use Twig\Node\Expression\BlockReferenceExpression;
 use Twig\Node\Expression\Filter\DefaultFilter;
+use Twig\Node\Expression\FunctionNode\EnumCasesFunction;
+use Twig\Node\Expression\GetAttrExpression;
 use Twig\Node\Expression\NullCoalesceExpression;
+use Twig\Node\Expression\ParentExpression;
 use Twig\Node\Expression\Test\ConstantTest;
 use Twig\Node\Expression\Test\DefinedTest;
 use Twig\Node\Expression\Test\DivisiblebyTest;
@@ -49,7 +62,12 @@ use Twig\Node\Expression\Test\SameasTest;
 use Twig\Node\Expression\Unary\NegUnary;
 use Twig\Node\Expression\Unary\NotUnary;
 use Twig\Node\Expression\Unary\PosUnary;
+use Twig\Node\Node;
 use Twig\NodeVisitor\MacroAutoImportNodeVisitor;
+use Twig\Parser;
+use Twig\Source;
+use Twig\Template;
+use Twig\TemplateWrapper;
 use Twig\TokenParser\ApplyTokenParser;
 use Twig\TokenParser\BlockTokenParser;
 use Twig\TokenParser\DeprecatedTokenParser;
@@ -64,11 +82,13 @@ use Twig\TokenParser\ImportTokenParser;
 use Twig\TokenParser\IncludeTokenParser;
 use Twig\TokenParser\MacroTokenParser;
 use Twig\TokenParser\SetTokenParser;
+use Twig\TokenParser\TypesTokenParser;
 use Twig\TokenParser\UseTokenParser;
 use Twig\TokenParser\WithTokenParser;
 use Twig\TwigFilter;
 use Twig\TwigFunction;
 use Twig\TwigTest;
+use Twig\Util\CallableArgumentsExtractor;
 
 final class CoreExtension extends AbstractExtension
 {
@@ -79,8 +99,8 @@ final class CoreExtension extends AbstractExtension
     /**
      * Sets the default format to be used by the date filter.
      *
-     * @param string $format             The default date format string
-     * @param string $dateIntervalFormat The default date interval format string
+     * @param string|null $format             The default date format string
+     * @param string|null $dateIntervalFormat The default date interval format string
      */
     public function setDateFormat($format = null, $dateIntervalFormat = null)
     {
@@ -163,6 +183,7 @@ final class CoreExtension extends AbstractExtension
             new ImportTokenParser(),
             new FromTokenParser(),
             new SetTokenParser(),
+            new TypesTokenParser(),
             new FlushTokenParser(),
             new DoTokenParser(),
             new EmbedTokenParser(),
@@ -175,65 +196,71 @@ final class CoreExtension extends AbstractExtension
     {
         return [
             // formatting filters
-            new TwigFilter('date', 'twig_date_format_filter', ['needs_environment' => true]),
-            new TwigFilter('date_modify', 'twig_date_modify_filter', ['needs_environment' => true]),
-            new TwigFilter('format', 'twig_sprintf'),
-            new TwigFilter('replace', 'twig_replace_filter'),
-            new TwigFilter('number_format', 'twig_number_format_filter', ['needs_environment' => true]),
+            new TwigFilter('date', [$this, 'formatDate']),
+            new TwigFilter('date_modify', [$this, 'modifyDate']),
+            new TwigFilter('format', [self::class, 'sprintf']),
+            new TwigFilter('replace', [self::class, 'replace']),
+            new TwigFilter('number_format', [$this, 'formatNumber']),
             new TwigFilter('abs', 'abs'),
-            new TwigFilter('round', 'twig_round'),
+            new TwigFilter('round', [self::class, 'round']),
 
             // encoding
-            new TwigFilter('url_encode', 'twig_urlencode_filter'),
+            new TwigFilter('url_encode', [self::class, 'urlencode']),
             new TwigFilter('json_encode', 'json_encode'),
-            new TwigFilter('convert_encoding', 'twig_convert_encoding'),
+            new TwigFilter('convert_encoding', [self::class, 'convertEncoding']),
 
             // string filters
-            new TwigFilter('title', 'twig_title_string_filter', ['needs_environment' => true]),
-            new TwigFilter('capitalize', 'twig_capitalize_string_filter', ['needs_environment' => true]),
-            new TwigFilter('upper', 'twig_upper_filter', ['needs_environment' => true]),
-            new TwigFilter('lower', 'twig_lower_filter', ['needs_environment' => true]),
-            new TwigFilter('striptags', 'twig_striptags'),
-            new TwigFilter('trim', 'twig_trim_filter'),
-            new TwigFilter('nl2br', 'twig_nl2br', ['pre_escape' => 'html', 'is_safe' => ['html']]),
-            new TwigFilter('spaceless', 'twig_spaceless', ['is_safe' => ['html']]),
+            new TwigFilter('title', [self::class, 'titleCase'], ['needs_charset' => true]),
+            new TwigFilter('capitalize', [self::class, 'capitalize'], ['needs_charset' => true]),
+            new TwigFilter('upper', [self::class, 'upper'], ['needs_charset' => true]),
+            new TwigFilter('lower', [self::class, 'lower'], ['needs_charset' => true]),
+            new TwigFilter('striptags', [self::class, 'striptags']),
+            new TwigFilter('trim', [self::class, 'trim']),
+            new TwigFilter('nl2br', [self::class, 'nl2br'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
+            new TwigFilter('spaceless', [self::class, 'spaceless'], ['is_safe' => ['html'], 'deprecated' => '3.12', 'deprecating_package' => 'twig/twig']),
 
             // array helpers
-            new TwigFilter('join', 'twig_join_filter'),
-            new TwigFilter('split', 'twig_split_filter', ['needs_environment' => true]),
-            new TwigFilter('sort', 'twig_sort_filter', ['needs_environment' => true]),
-            new TwigFilter('merge', 'twig_array_merge'),
-            new TwigFilter('batch', 'twig_array_batch'),
-            new TwigFilter('column', 'twig_array_column'),
-            new TwigFilter('filter', 'twig_array_filter', ['needs_environment' => true]),
-            new TwigFilter('map', 'twig_array_map', ['needs_environment' => true]),
-            new TwigFilter('reduce', 'twig_array_reduce', ['needs_environment' => true]),
+            new TwigFilter('join', [self::class, 'join']),
+            new TwigFilter('split', [self::class, 'split'], ['needs_charset' => true]),
+            new TwigFilter('sort', [self::class, 'sort'], ['needs_environment' => true]),
+            new TwigFilter('merge', [self::class, 'merge']),
+            new TwigFilter('batch', [self::class, 'batch']),
+            new TwigFilter('column', [self::class, 'column']),
+            new TwigFilter('filter', [self::class, 'filter'], ['needs_environment' => true]),
+            new TwigFilter('map', [self::class, 'map'], ['needs_environment' => true]),
+            new TwigFilter('reduce', [self::class, 'reduce'], ['needs_environment' => true]),
+            new TwigFilter('find', [self::class, 'find'], ['needs_environment' => true]),
 
             // string/array filters
-            new TwigFilter('reverse', 'twig_reverse_filter', ['needs_environment' => true]),
-            new TwigFilter('length', 'twig_length_filter', ['needs_environment' => true]),
-            new TwigFilter('slice', 'twig_slice', ['needs_environment' => true]),
-            new TwigFilter('first', 'twig_first', ['needs_environment' => true]),
-            new TwigFilter('last', 'twig_last', ['needs_environment' => true]),
+            new TwigFilter('reverse', [self::class, 'reverse'], ['needs_charset' => true]),
+            new TwigFilter('shuffle', [self::class, 'shuffle'], ['needs_charset' => true]),
+            new TwigFilter('length', [self::class, 'length'], ['needs_charset' => true]),
+            new TwigFilter('slice', [self::class, 'slice'], ['needs_charset' => true]),
+            new TwigFilter('first', [self::class, 'first'], ['needs_charset' => true]),
+            new TwigFilter('last', [self::class, 'last'], ['needs_charset' => true]),
 
             // iteration and runtime
-            new TwigFilter('default', '_twig_default_filter', ['node_class' => DefaultFilter::class]),
-            new TwigFilter('keys', 'twig_get_array_keys_filter'),
+            new TwigFilter('default', [self::class, 'default'], ['node_class' => DefaultFilter::class]),
+            new TwigFilter('keys', [self::class, 'keys']),
         ];
     }
 
     public function getFunctions(): array
     {
         return [
+            new TwigFunction('parent', null, ['parser_callable' => [self::class, 'parseParentFunction']]),
+            new TwigFunction('block', null, ['parser_callable' => [self::class, 'parseBlockFunction']]),
+            new TwigFunction('attribute', null, ['parser_callable' => [self::class, 'parseAttributeFunction']]),
             new TwigFunction('max', 'max'),
             new TwigFunction('min', 'min'),
             new TwigFunction('range', 'range'),
-            new TwigFunction('constant', 'twig_constant'),
-            new TwigFunction('cycle', 'twig_cycle'),
-            new TwigFunction('random', 'twig_random', ['needs_environment' => true]),
-            new TwigFunction('date', 'twig_date_converter', ['needs_environment' => true]),
-            new TwigFunction('include', 'twig_include', ['needs_environment' => true, 'needs_context' => true, 'is_safe' => ['all']]),
-            new TwigFunction('source', 'twig_source', ['needs_environment' => true, 'is_safe' => ['all']]),
+            new TwigFunction('constant', [self::class, 'constant']),
+            new TwigFunction('cycle', [self::class, 'cycle']),
+            new TwigFunction('random', [self::class, 'random'], ['needs_charset' => true]),
+            new TwigFunction('date', [$this, 'convertDate']),
+            new TwigFunction('include', [self::class, 'include'], ['needs_environment' => true, 'needs_context' => true, 'is_safe' => ['all']]),
+            new TwigFunction('source', [self::class, 'source'], ['needs_environment' => true, 'is_safe' => ['all']]),
+            new TwigFunction('enum_cases', [self::class, 'enumCases'], ['node_class' => EnumCasesFunction::class]),
         ];
     }
 
@@ -248,8 +275,10 @@ final class CoreExtension extends AbstractExtension
             new TwigTest('null', null, ['node_class' => NullTest::class]),
             new TwigTest('divisible by', null, ['node_class' => DivisiblebyTest::class, 'one_mandatory_argument' => true]),
             new TwigTest('constant', null, ['node_class' => ConstantTest::class]),
-            new TwigTest('empty', 'twig_test_empty'),
-            new TwigTest('iterable', 'twig_test_iterable'),
+            new TwigTest('empty', [self::class, 'testEmpty']),
+            new TwigTest('iterable', 'is_iterable'),
+            new TwigTest('sequence', [self::class, 'testSequence']),
+            new TwigTest('mapping', [self::class, 'testMapping']),
         ];
     }
 
@@ -284,6 +313,8 @@ final class CoreExtension extends AbstractExtension
                 'matches' => ['precedence' => 20, 'class' => MatchesBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                 'starts with' => ['precedence' => 20, 'class' => StartsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                 'ends with' => ['precedence' => 20, 'class' => EndsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
+                'has some' => ['precedence' => 20, 'class' => HasSomeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
+                'has every' => ['precedence' => 20, 'class' => HasEveryBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                 '..' => ['precedence' => 25, 'class' => RangeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                 '+' => ['precedence' => 30, 'class' => AddBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
                 '-' => ['precedence' => 30, 'class' => SubBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT],
@@ -299,193 +330,226 @@ final class CoreExtension extends AbstractExtension
             ],
         ];
     }
-}
-}
 
-namespace {
-    use Twig\Environment;
-    use Twig\Error\LoaderError;
-    use Twig\Error\RuntimeError;
-    use Twig\Extension\CoreExtension;
-    use Twig\Extension\SandboxExtension;
-    use Twig\Markup;
-    use Twig\Source;
-    use Twig\Template;
-    use Twig\TemplateWrapper;
-
-/**
- * Cycles over a value.
- *
- * @param \ArrayAccess|array $values
- * @param int                $position The cycle position
- *
- * @return string The next value in the cycle
- */
-function twig_cycle($values, $position)
-{
-    if (!\is_array($values) && !$values instanceof \ArrayAccess) {
-        return $values;
-    }
+    /**
+     * Cycles over a sequence.
+     *
+     * @param array|\ArrayAccess $values   A non-empty sequence of values
+     * @param positive-int       $position The position of the value to return in the cycle
+     *
+     * @return mixed The value at the given position in the sequence, wrapping around as needed
+     *
+     * @internal
+     */
+    public static function cycle($values, $position): mixed
+    {
+        if (!\is_array($values)) {
+            if (!$values instanceof \ArrayAccess) {
+                throw new RuntimeError('The "cycle" function expects an array or "ArrayAccess" as first argument.');
+            }
 
-    return $values[$position % \count($values)];
-}
+            if (!is_countable($values)) {
+                // To be uncommented in 4.0
+                // throw new RuntimeError('The "cycle" function expects a countable sequence as first argument.');
 
-/**
- * Returns a random value depending on the supplied parameter type:
- * - a random item from a \Traversable or array
- * - a random character from a string
- * - a random integer between 0 and the integer parameter.
- *
- * @param \Traversable|array|int|float|string $values The values to pick a random item from
- * @param int|null                            $max    Maximum value used when $values is an int
- *
- * @throws RuntimeError when $values is an empty array (does not apply to an empty string which is returned as is)
- *
- * @return mixed A random value from the given sequence
- */
-function twig_random(Environment $env, $values = null, $max = null)
-{
-    if (null === $values) {
-        return null === $max ? mt_rand() : mt_rand(0, (int) $max);
-    }
+                trigger_deprecation('twig/twig', '3.12', 'Passing a non-countable sequence of values to "%s()" is deprecated.', __METHOD__);
 
-    if (\is_int($values) || \is_float($values)) {
-        if (null === $max) {
-            if ($values < 0) {
-                $max = 0;
-                $min = $values;
-            } else {
-                $max = $values;
-                $min = 0;
+                return $values;
             }
-        } else {
-            $min = $values;
-            $max = $max;
+
+            $values = self::toArray($values, false);
+        }
+
+        if (!$count = \count($values)) {
+            throw new RuntimeError('The "cycle" function does not work on empty sequences.');
         }
 
-        return mt_rand((int) $min, (int) $max);
+        return $values[$position % $count];
     }
 
-    if (\is_string($values)) {
-        if ('' === $values) {
-            return '';
+    /**
+     * Returns a random value depending on the supplied parameter type:
+     * - a random item from a \Traversable or array
+     * - a random character from a string
+     * - a random integer between 0 and the integer parameter.
+     *
+     * @param \Traversable|array|int|float|string $values The values to pick a random item from
+     * @param int|null                            $max    Maximum value used when $values is an int
+     *
+     * @return mixed A random value from the given sequence
+     *
+     * @throws RuntimeError when $values is an empty array (does not apply to an empty string which is returned as is)
+     *
+     * @internal
+     */
+    public static function random(string $charset, $values = null, $max = null)
+    {
+        if (null === $values) {
+            return null === $max ? mt_rand() : mt_rand(0, (int) $max);
         }
 
-        $charset = $env->getCharset();
+        if (\is_int($values) || \is_float($values)) {
+            if (null === $max) {
+                if ($values < 0) {
+                    $max = 0;
+                    $min = $values;
+                } else {
+                    $max = $values;
+                    $min = 0;
+                }
+            } else {
+                $min = $values;
+            }
 
-        if ('UTF-8' !== $charset) {
-            $values = twig_convert_encoding($values, 'UTF-8', $charset);
+            return mt_rand((int) $min, (int) $max);
         }
 
-        // unicode version of str_split()
-        // split at all positions, but not after the start and not before the end
-        $values = preg_split('/(?<!^)(?!$)/u', $values);
+        if (\is_string($values)) {
+            if ('' === $values) {
+                return '';
+            }
 
-        if ('UTF-8' !== $charset) {
-            foreach ($values as $i => $value) {
-                $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
+            if ('UTF-8' !== $charset) {
+                $values = self::convertEncoding($values, 'UTF-8', $charset);
+            }
+
+            // unicode version of str_split()
+            // split at all positions, but not after the start and not before the end
+            $values = preg_split('/(?<!^)(?!$)/u', $values);
+
+            if ('UTF-8' !== $charset) {
+                foreach ($values as $i => $value) {
+                    $values[$i] = self::convertEncoding($value, $charset, 'UTF-8');
+                }
             }
         }
-    }
 
-    if (!twig_test_iterable($values)) {
-        return $values;
+        if (!is_iterable($values)) {
+            return $values;
+        }
+
+        $values = self::toArray($values);
+
+        if (0 === \count($values)) {
+            throw new RuntimeError('The random function cannot pick from an empty sequence/mapping.');
+        }
+
+        return $values[array_rand($values, 1)];
     }
 
-    $values = twig_to_array($values);
+    /**
+     * Formats a date.
+     *
+     *   {{ post.published_at|date("m/d/Y") }}
+     *
+     * @param \DateTimeInterface|\DateInterval|string $date     A date
+     * @param string|null                             $format   The target format, null to use the default
+     * @param \DateTimeZone|string|false|null         $timezone The target timezone, null to use the default, false to leave unchanged
+     */
+    public function formatDate($date, $format = null, $timezone = null): string
+    {
+        if (null === $format) {
+            $formats = $this->getDateFormat();
+            $format = $date instanceof \DateInterval ? $formats[1] : $formats[0];
+        }
+
+        if ($date instanceof \DateInterval) {
+            return $date->format($format);
+        }
 
-    if (0 === \count($values)) {
-        throw new RuntimeError('The random function cannot pick from an empty array.');
+        return $this->convertDate($date, $timezone)->format($format);
     }
 
-    return $values[array_rand($values, 1)];
-}
+    /**
+     * Returns a new date object modified.
+     *
+     *   {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
+     *
+     * @param \DateTimeInterface|string $date     A date
+     * @param string                    $modifier A modifier string
+     *
+     * @return \DateTime|\DateTimeImmutable
+     *
+     * @internal
+     */
+    public function modifyDate($date, $modifier)
+    {
+        return $this->convertDate($date, false)->modify($modifier);
+    }
 
-/**
- * Converts a date to the given format.
- *
- *   {{ post.published_at|date("m/d/Y") }}
- *
- * @param \DateTimeInterface|\DateInterval|string $date     A date
- * @param string|null                             $format   The target format, null to use the default
- * @param \DateTimeZone|string|false|null         $timezone The target timezone, null to use the default, false to leave unchanged
- *
- * @return string The formatted date
- */
-function twig_date_format_filter(Environment $env, $date, $format = null, $timezone = null)
-{
-    if (null === $format) {
-        $formats = $env->getExtension(CoreExtension::class)->getDateFormat();
-        $format = $date instanceof \DateInterval ? $formats[1] : $formats[0];
+    /**
+     * Returns a formatted string.
+     *
+     * @param string|null $format
+     * @param ...$values
+     *
+     * @internal
+     */
+    public static function sprintf($format, ...$values): string
+    {
+        return \sprintf($format ?? '', ...$values);
     }
 
-    if ($date instanceof \DateInterval) {
-        return $date->format($format);
+    /**
+     * @internal
+     */
+    public static function dateConverter(Environment $env, $date, $format = null, $timezone = null): string
+    {
+        return $env->getExtension(self::class)->formatDate($date, $format, $timezone);
     }
 
-    return twig_date_converter($env, $date, $timezone)->format($format);
-}
+    /**
+     * Converts an input to a \DateTime instance.
+     *
+     *    {% if date(user.created_at) < date('+2days') %}
+     *      {# do something #}
+     *    {% endif %}
+     *
+     * @param \DateTimeInterface|string|null  $date     A date or null to use the current time
+     * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
+     *
+     * @return \DateTime|\DateTimeImmutable
+     */
+    public function convertDate($date = null, $timezone = null)
+    {
+        // determine the timezone
+        if (false !== $timezone) {
+            if (null === $timezone) {
+                $timezone = $this->getTimezone();
+            } elseif (!$timezone instanceof \DateTimeZone) {
+                $timezone = new \DateTimeZone($timezone);
+            }
+        }
 
-/**
- * Returns a new date object modified.
- *
- *   {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
- *
- * @param \DateTimeInterface|string $date     A date
- * @param string                    $modifier A modifier string
- *
- * @return \DateTimeInterface
- */
-function twig_date_modify_filter(Environment $env, $date, $modifier)
-{
-    $date = twig_date_converter($env, $date, false);
+        // immutable dates
+        if ($date instanceof \DateTimeImmutable) {
+            return false !== $timezone ? $date->setTimezone($timezone) : $date;
+        }
 
-    return $date->modify($modifier);
-}
+        if ($date instanceof \DateTime) {
+            $date = clone $date;
+            if (false !== $timezone) {
+                $date->setTimezone($timezone);
+            }
 
-/**
- * Returns a formatted string.
- *
- * @param string|null $format
- * @param ...$values
- *
- * @return string
- */
-function twig_sprintf($format, ...$values)
-{
-    return sprintf($format ?? '', ...$values);
-}
+            return $date;
+        }
 
-/**
- * Converts an input to a \DateTime instance.
- *
- *    {% if date(user.created_at) < date('+2days') %}
- *      {# do something #}
- *    {% endif %}
- *
- * @param \DateTimeInterface|string|null  $date     A date or null to use the current time
- * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
- *
- * @return \DateTimeInterface
- */
-function twig_date_converter(Environment $env, $date = null, $timezone = null)
-{
-    // determine the timezone
-    if (false !== $timezone) {
-        if (null === $timezone) {
-            $timezone = $env->getExtension(CoreExtension::class)->getTimezone();
-        } elseif (!$timezone instanceof \DateTimeZone) {
-            $timezone = new \DateTimeZone($timezone);
+        if (null === $date || 'now' === $date) {
+            if (null === $date) {
+                $date = 'now';
+            }
+
+            return new \DateTime($date, false !== $timezone ? $timezone : $this->getTimezone());
         }
-    }
 
-    // immutable dates
-    if ($date instanceof \DateTimeImmutable) {
-        return false !== $timezone ? $date->setTimezone($timezone) : $date;
-    }
+        $asString = (string) $date;
+        if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
+            $date = new \DateTime('@'.$date);
+        } else {
+            $date = new \DateTime($date, $this->getTimezone());
+        }
 
-    if ($date instanceof \DateTimeInterface) {
-        $date = clone $date;
         if (false !== $timezone) {
             $date->setTimezone($timezone);
         }
@@ -493,968 +557,1086 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null)
         return $date;
     }
 
-    if (null === $date || 'now' === $date) {
-        if (null === $date) {
-            $date = 'now';
+    /**
+     * Replaces strings within a string.
+     *
+     * @param string|null        $str  String to replace in
+     * @param array|\Traversable $from Replace values
+     *
+     * @internal
+     */
+    public static function replace($str, $from): string
+    {
+        if (!is_iterable($from)) {
+            throw new RuntimeError(\sprintf('The "replace" filter expects a sequence/mapping or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
         }
 
-        return new \DateTime($date, false !== $timezone ? $timezone : $env->getExtension(CoreExtension::class)->getTimezone());
+        return strtr($str ?? '', self::toArray($from));
     }
 
-    $asString = (string) $date;
-    if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
-        $date = new \DateTime('@'.$date);
-    } else {
-        $date = new \DateTime($date, $env->getExtension(CoreExtension::class)->getTimezone());
-    }
+    /**
+     * Rounds a number.
+     *
+     * @param int|float|string|null $value     The value to round
+     * @param int|float             $precision The rounding precision
+     * @param string                $method    The method to use for rounding
+     *
+     * @return int|float The rounded number
+     *
+     * @internal
+     */
+    public static function round($value, $precision = 0, $method = 'common')
+    {
+        $value = (float) $value;
 
-    if (false !== $timezone) {
-        $date->setTimezone($timezone);
-    }
+        if ('common' === $method) {
+            return round($value, $precision);
+        }
 
-    return $date;
-}
+        if ('ceil' !== $method && 'floor' !== $method) {
+            throw new RuntimeError('The round filter only supports the "common", "ceil", and "floor" methods.');
+        }
 
-/**
- * Replaces strings within a string.
- *
- * @param string|null        $str  String to replace in
- * @param array|\Traversable $from Replace values
- *
- * @return string
- */
-function twig_replace_filter($str, $from)
-{
-    if (!twig_test_iterable($from)) {
-        throw new RuntimeError(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from)));
+        return $method($value * 10 ** $precision) / 10 ** $precision;
     }
 
-    return strtr($str ?? '', twig_to_array($from));
-}
+    /**
+     * Formats a number.
+     *
+     * All of the formatting options can be left null, in that case the defaults will
+     * be used. Supplying any of the parameters will override the defaults set in the
+     * environment object.
+     *
+     * @param mixed       $number       A float/int/string of the number to format
+     * @param int|null    $decimal      the number of decimal points to display
+     * @param string|null $decimalPoint the character(s) to use for the decimal point
+     * @param string|null $thousandSep  the character(s) to use for the thousands separator
+     */
+    public function formatNumber($number, $decimal = null, $decimalPoint = null, $thousandSep = null): string
+    {
+        $defaults = $this->getNumberFormat();
+        if (null === $decimal) {
+            $decimal = $defaults[0];
+        }
 
-/**
- * Rounds a number.
- *
- * @param int|float|string|null $value     The value to round
- * @param int|float             $precision The rounding precision
- * @param string                $method    The method to use for rounding
- *
- * @return int|float The rounded number
- */
-function twig_round($value, $precision = 0, $method = 'common')
-{
-    $value = (float) $value;
+        if (null === $decimalPoint) {
+            $decimalPoint = $defaults[1];
+        }
 
-    if ('common' === $method) {
-        return round($value, $precision);
-    }
+        if (null === $thousandSep) {
+            $thousandSep = $defaults[2];
+        }
 
-    if ('ceil' !== $method && 'floor' !== $method) {
-        throw new RuntimeError('The round filter only supports the "common", "ceil", and "floor" methods.');
+        return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
     }
 
-    return $method($value * 10 ** $precision) / 10 ** $precision;
-}
+    /**
+     * URL encodes (RFC 3986) a string as a path segment or an array as a query string.
+     *
+     * @param string|array|null $url A URL or an array of query parameters
+     *
+     * @internal
+     */
+    public static function urlencode($url): string
+    {
+        if (\is_array($url)) {
+            return http_build_query($url, '', '&', \PHP_QUERY_RFC3986);
+        }
 
-/**
- * Number format filter.
- *
- * All of the formatting options can be left null, in that case the defaults will
- * be used. Supplying any of the parameters will override the defaults set in the
- * environment object.
- *
- * @param mixed  $number       A float/int/string of the number to format
- * @param int    $decimal      the number of decimal points to display
- * @param string $decimalPoint the character(s) to use for the decimal point
- * @param string $thousandSep  the character(s) to use for the thousands separator
- *
- * @return string The formatted number
- */
-function twig_number_format_filter(Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
-{
-    $defaults = $env->getExtension(CoreExtension::class)->getNumberFormat();
-    if (null === $decimal) {
-        $decimal = $defaults[0];
+        return rawurlencode($url ?? '');
     }
 
-    if (null === $decimalPoint) {
-        $decimalPoint = $defaults[1];
-    }
+    /**
+     * Merges any number of arrays or Traversable objects.
+     *
+     *  {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
+     *
+     *  {% set items = items|merge({ 'peugeot': 'car' }, { 'banana': 'fruit' }) %}
+     *
+     *  {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car', 'banana': 'fruit' } #}
+     *
+     * @param array|\Traversable ...$arrays Any number of arrays or Traversable objects to merge
+     *
+     * @internal
+     */
+    public static function merge(...$arrays): array
+    {
+        $result = [];
+
+        foreach ($arrays as $argNumber => $array) {
+            if (!is_iterable($array)) {
+                throw new RuntimeError(\sprintf('The merge filter only works with sequences/mappings or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1));
+            }
 
-    if (null === $thousandSep) {
-        $thousandSep = $defaults[2];
+            $result = array_merge($result, self::toArray($array));
+        }
+
+        return $result;
     }
 
-    return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
-}
+    /**
+     * Slices a variable.
+     *
+     * @param mixed $item         A variable
+     * @param int   $start        Start of the slice
+     * @param int   $length       Size of the slice
+     * @param bool  $preserveKeys Whether to preserve key or not (when the input is an array)
+     *
+     * @return mixed The sliced variable
+     *
+     * @internal
+     */
+    public static function slice(string $charset, $item, $start, $length = null, $preserveKeys = false)
+    {
+        if ($item instanceof \Traversable) {
+            while ($item instanceof \IteratorAggregate) {
+                $item = $item->getIterator();
+            }
 
-/**
- * URL encodes (RFC 3986) a string as a path segment or an array as a query string.
- *
- * @param string|array|null $url A URL or an array of query parameters
- *
- * @return string The URL encoded value
- */
-function twig_urlencode_filter($url)
-{
-    if (\is_array($url)) {
-        return http_build_query($url, '', '&', \PHP_QUERY_RFC3986);
+            if ($start >= 0 && $length >= 0 && $item instanceof \Iterator) {
+                try {
+                    return iterator_to_array(new \LimitIterator($item, $start, $length ?? -1), $preserveKeys);
+                } catch (\OutOfBoundsException $e) {
+                    return [];
+                }
+            }
+
+            $item = iterator_to_array($item, $preserveKeys);
+        }
+
+        if (\is_array($item)) {
+            return \array_slice($item, $start, $length, $preserveKeys);
+        }
+
+        return mb_substr((string) $item, $start, $length, $charset);
     }
 
-    return rawurlencode($url ?? '');
-}
+    /**
+     * Returns the first element of the item.
+     *
+     * @param mixed $item A variable
+     *
+     * @return mixed The first element of the item
+     *
+     * @internal
+     */
+    public static function first(string $charset, $item)
+    {
+        $elements = self::slice($charset, $item, 0, 1, false);
 
-/**
- * Merges an array with another one.
- *
- *  {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
- *
- *  {% set items = items|merge({ 'peugeot': 'car' }) %}
- *
- *  {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
- *
- * @param array|\Traversable $arr1 An array
- * @param array|\Traversable $arr2 An array
- *
- * @return array The merged array
- */
-function twig_array_merge($arr1, $arr2)
-{
-    if (!twig_test_iterable($arr1)) {
-        throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($arr1)));
+        return \is_string($elements) ? $elements : current($elements);
     }
 
-    if (!twig_test_iterable($arr2)) {
-        throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as second argument.', \gettype($arr2)));
+    /**
+     * Returns the last element of the item.
+     *
+     * @param mixed $item A variable
+     *
+     * @return mixed The last element of the item
+     *
+     * @internal
+     */
+    public static function last(string $charset, $item)
+    {
+        $elements = self::slice($charset, $item, -1, 1, false);
+
+        return \is_string($elements) ? $elements : current($elements);
     }
 
-    return array_merge(twig_to_array($arr1), twig_to_array($arr2));
-}
+    /**
+     * Joins the values to a string.
+     *
+     * The separators between elements are empty strings per default, you can define them with the optional parameters.
+     *
+     *  {{ [1, 2, 3]|join(', ', ' and ') }}
+     *  {# returns 1, 2 and 3 #}
+     *
+     *  {{ [1, 2, 3]|join('|') }}
+     *  {# returns 1|2|3 #}
+     *
+     *  {{ [1, 2, 3]|join }}
+     *  {# returns 123 #}
+     *
+     * @param array       $value An array
+     * @param string      $glue  The separator
+     * @param string|null $and   The separator for the last pair
+     *
+     * @internal
+     */
+    public static function join($value, $glue = '', $and = null): string
+    {
+        if (!is_iterable($value)) {
+            $value = (array) $value;
+        }
 
-/**
- * Slices a variable.
- *
- * @param mixed $item         A variable
- * @param int   $start        Start of the slice
- * @param int   $length       Size of the slice
- * @param bool  $preserveKeys Whether to preserve key or not (when the input is an array)
- *
- * @return mixed The sliced variable
- */
-function twig_slice(Environment $env, $item, $start, $length = null, $preserveKeys = false)
-{
-    if ($item instanceof \Traversable) {
-        while ($item instanceof \IteratorAggregate) {
-            $item = $item->getIterator();
+        $value = self::toArray($value, false);
+
+        if (0 === \count($value)) {
+            return '';
         }
 
-        if ($start >= 0 && $length >= 0 && $item instanceof \Iterator) {
-            try {
-                return iterator_to_array(new \LimitIterator($item, $start, null === $length ? -1 : $length), $preserveKeys);
-            } catch (\OutOfBoundsException $e) {
-                return [];
-            }
+        if (null === $and || $and === $glue) {
+            return implode($glue, $value);
         }
 
-        $item = iterator_to_array($item, $preserveKeys);
-    }
+        if (1 === \count($value)) {
+            return $value[0];
+        }
 
-    if (\is_array($item)) {
-        return \array_slice($item, $start, $length, $preserveKeys);
+        return implode($glue, \array_slice($value, 0, -1)).$and.$value[\count($value) - 1];
     }
 
-    return (string) mb_substr((string) $item, $start, $length, $env->getCharset());
-}
+    /**
+     * Splits the string into an array.
+     *
+     *  {{ "one,two,three"|split(',') }}
+     *  {# returns [one, two, three] #}
+     *
+     *  {{ "one,two,three,four,five"|split(',', 3) }}
+     *  {# returns [one, two, "three,four,five"] #}
+     *
+     *  {{ "123"|split('') }}
+     *  {# returns [1, 2, 3] #}
+     *
+     *  {{ "aabbcc"|split('', 2) }}
+     *  {# returns [aa, bb, cc] #}
+     *
+     * @param string|null $value     A string
+     * @param string      $delimiter The delimiter
+     * @param int|null    $limit     The limit
+     *
+     * @internal
+     */
+    public static function split(string $charset, $value, $delimiter, $limit = null): array
+    {
+        $value = $value ?? '';
 
-/**
- * Returns the first element of the item.
- *
- * @param mixed $item A variable
- *
- * @return mixed The first element of the item
- */
-function twig_first(Environment $env, $item)
-{
-    $elements = twig_slice($env, $item, 0, 1, false);
+        if ('' !== $delimiter) {
+            return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
+        }
 
-    return \is_string($elements) ? $elements : current($elements);
-}
+        if ($limit <= 1) {
+            return preg_split('/(?<!^)(?!$)/u', $value);
+        }
 
-/**
- * Returns the last element of the item.
- *
- * @param mixed $item A variable
- *
- * @return mixed The last element of the item
- */
-function twig_last(Environment $env, $item)
-{
-    $elements = twig_slice($env, $item, -1, 1, false);
+        $length = mb_strlen($value, $charset);
+        if ($length < $limit) {
+            return [$value];
+        }
 
-    return \is_string($elements) ? $elements : current($elements);
-}
+        $r = [];
+        for ($i = 0; $i < $length; $i += $limit) {
+            $r[] = mb_substr($value, $i, $limit, $charset);
+        }
 
-/**
- * Joins the values to a string.
- *
- * The separators between elements are empty strings per default, you can define them with the optional parameters.
- *
- *  {{ [1, 2, 3]|join(', ', ' and ') }}
- *  {# returns 1, 2 and 3 #}
- *
- *  {{ [1, 2, 3]|join('|') }}
- *  {# returns 1|2|3 #}
- *
- *  {{ [1, 2, 3]|join }}
- *  {# returns 123 #}
- *
- * @param array       $value An array
- * @param string      $glue  The separator
- * @param string|null $and   The separator for the last pair
- *
- * @return string The concatenated string
- */
-function twig_join_filter($value, $glue = '', $and = null)
-{
-    if (!twig_test_iterable($value)) {
-        $value = (array) $value;
+        return $r;
     }
 
-    $value = twig_to_array($value, false);
-
-    if (0 === \count($value)) {
-        return '';
-    }
+    /**
+     * @internal
+     */
+    public static function default($value, $default = '')
+    {
+        if (self::testEmpty($value)) {
+            return $default;
+        }
 
-    if (null === $and || $and === $glue) {
-        return implode($glue, $value);
+        return $value;
     }
 
-    if (1 === \count($value)) {
-        return $value[0];
-    }
+    /**
+     * Returns the keys for the given array.
+     *
+     * It is useful when you want to iterate over the keys of an array:
+     *
+     *  {% for key in array|keys %}
+     *      {# ... #}
+     *  {% endfor %}
+     *
+     * @internal
+     */
+    public static function keys($array): array
+    {
+        if ($array instanceof \Traversable) {
+            while ($array instanceof \IteratorAggregate) {
+                $array = $array->getIterator();
+            }
 
-    return implode($glue, \array_slice($value, 0, -1)).$and.$value[\count($value) - 1];
-}
+            $keys = [];
+            if ($array instanceof \Iterator) {
+                $array->rewind();
+                while ($array->valid()) {
+                    $keys[] = $array->key();
+                    $array->next();
+                }
 
-/**
- * Splits the string into an array.
- *
- *  {{ "one,two,three"|split(',') }}
- *  {# returns [one, two, three] #}
- *
- *  {{ "one,two,three,four,five"|split(',', 3) }}
- *  {# returns [one, two, "three,four,five"] #}
- *
- *  {{ "123"|split('') }}
- *  {# returns [1, 2, 3] #}
- *
- *  {{ "aabbcc"|split('', 2) }}
- *  {# returns [aa, bb, cc] #}
- *
- * @param string|null $value     A string
- * @param string      $delimiter The delimiter
- * @param int         $limit     The limit
- *
- * @return array The split string as an array
- */
-function twig_split_filter(Environment $env, $value, $delimiter, $limit = null)
-{
-    $value = $value ?? '';
+                return $keys;
+            }
 
-    if (\strlen($delimiter) > 0) {
-        return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
-    }
+            foreach ($array as $key => $item) {
+                $keys[] = $key;
+            }
 
-    if ($limit <= 1) {
-        return preg_split('/(?<!^)(?!$)/u', $value);
-    }
+            return $keys;
+        }
 
-    $length = mb_strlen($value, $env->getCharset());
-    if ($length < $limit) {
-        return [$value];
-    }
+        if (!\is_array($array)) {
+            return [];
+        }
 
-    $r = [];
-    for ($i = 0; $i < $length; $i += $limit) {
-        $r[] = mb_substr($value, $i, $limit, $env->getCharset());
+        return array_keys($array);
     }
 
-    return $r;
-}
+    /**
+     * Reverses a variable.
+     *
+     * @param array|\Traversable|string|null $item         An array, a \Traversable instance, or a string
+     * @param bool                           $preserveKeys Whether to preserve key or not
+     *
+     * @return mixed The reversed input
+     *
+     * @internal
+     */
+    public static function reverse(string $charset, $item, $preserveKeys = false)
+    {
+        if ($item instanceof \Traversable) {
+            return array_reverse(iterator_to_array($item), $preserveKeys);
+        }
 
-// The '_default' filter is used internally to avoid using the ternary operator
-// which costs a lot for big contexts (before PHP 5.4). So, on average,
-// a function call is cheaper.
-/**
- * @internal
- */
-function _twig_default_filter($value, $default = '')
-{
-    if (twig_test_empty($value)) {
-        return $default;
-    }
+        if (\is_array($item)) {
+            return array_reverse($item, $preserveKeys);
+        }
 
-    return $value;
-}
+        $string = (string) $item;
 
-/**
- * Returns the keys for the given array.
- *
- * It is useful when you want to iterate over the keys of an array:
- *
- *  {% for key in array|keys %}
- *      {# ... #}
- *  {% endfor %}
- *
- * @param array $array An array
- *
- * @return array The keys
- */
-function twig_get_array_keys_filter($array)
-{
-    if ($array instanceof \Traversable) {
-        while ($array instanceof \IteratorAggregate) {
-            $array = $array->getIterator();
+        if ('UTF-8' !== $charset) {
+            $string = self::convertEncoding($string, 'UTF-8', $charset);
         }
 
-        $keys = [];
-        if ($array instanceof \Iterator) {
-            $array->rewind();
-            while ($array->valid()) {
-                $keys[] = $array->key();
-                $array->next();
-            }
+        preg_match_all('/./us', $string, $matches);
 
-            return $keys;
-        }
+        $string = implode('', array_reverse($matches[0]));
 
-        foreach ($array as $key => $item) {
-            $keys[] = $key;
+        if ('UTF-8' !== $charset) {
+            $string = self::convertEncoding($string, $charset, 'UTF-8');
         }
 
-        return $keys;
+        return $string;
     }
 
-    if (!\is_array($array)) {
-        return [];
-    }
-
-    return array_keys($array);
-}
+    /**
+     * Shuffles an array, a \Traversable instance, or a string.
+     * The function does not preserve keys.
+     *
+     * @param array|\Traversable|string|null $item
+     *
+     * @return mixed
+     *
+     * @internal
+     */
+    public static function shuffle(string $charset, $item)
+    {
+        if (\is_string($item)) {
+            if ('UTF-8' !== $charset) {
+                $item = self::convertEncoding($item, 'UTF-8', $charset);
+            }
 
-/**
- * Reverses a variable.
- *
- * @param array|\Traversable|string|null $item         An array, a \Traversable instance, or a string
- * @param bool                           $preserveKeys Whether to preserve key or not
- *
- * @return mixed The reversed input
- */
-function twig_reverse_filter(Environment $env, $item, $preserveKeys = false)
-{
-    if ($item instanceof \Traversable) {
-        return array_reverse(iterator_to_array($item), $preserveKeys);
-    }
+            $item = preg_split('/(?<!^)(?!$)/u', $item, -1);
+            shuffle($item);
+            $item = implode('', $item);
 
-    if (\is_array($item)) {
-        return array_reverse($item, $preserveKeys);
-    }
+            if ('UTF-8' !== $charset) {
+                $item = self::convertEncoding($item, $charset, 'UTF-8');
+            }
 
-    $string = (string) $item;
+            return $item;
+        }
 
-    $charset = $env->getCharset();
+        if (is_iterable($item)) {
+            $item = self::toArray($item, false);
+            shuffle($item);
+        }
 
-    if ('UTF-8' !== $charset) {
-        $string = twig_convert_encoding($string, 'UTF-8', $charset);
+        return $item;
     }
 
-    preg_match_all('/./us', $string, $matches);
+    /**
+     * Sorts an array.
+     *
+     * @param array|\Traversable $array
+     *
+     * @internal
+     */
+    public static function sort(Environment $env, $array, $arrow = null): array
+    {
+        if ($array instanceof \Traversable) {
+            $array = iterator_to_array($array);
+        } elseif (!\is_array($array)) {
+            throw new RuntimeError(\sprintf('The sort filter only works with sequences/mappings or "Traversable", got "%s".', \gettype($array)));
+        }
+
+        if (null !== $arrow) {
+            self::checkArrowInSandbox($env, $arrow, 'sort', 'filter');
 
-    $string = implode('', array_reverse($matches[0]));
+            uasort($array, $arrow);
+        } else {
+            asort($array);
+        }
 
-    if ('UTF-8' !== $charset) {
-        $string = twig_convert_encoding($string, $charset, 'UTF-8');
+        return $array;
     }
 
-    return $string;
-}
+    /**
+     * @internal
+     */
+    public static function inFilter($value, $compare)
+    {
+        if ($value instanceof Markup) {
+            $value = (string) $value;
+        }
+        if ($compare instanceof Markup) {
+            $compare = (string) $compare;
+        }
 
-/**
- * Sorts an array.
- *
- * @param array|\Traversable $array
- *
- * @return array
- */
-function twig_sort_filter(Environment $env, $array, $arrow = null)
-{
-    if ($array instanceof \Traversable) {
-        $array = iterator_to_array($array);
-    } elseif (!\is_array($array)) {
-        throw new RuntimeError(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array)));
-    }
+        if (\is_string($compare)) {
+            if (\is_string($value) || \is_int($value) || \is_float($value)) {
+                return '' === $value || str_contains($compare, (string) $value);
+            }
 
-    if (null !== $arrow) {
-        twig_check_arrow_in_sandbox($env, $arrow, 'sort', 'filter');
+            return false;
+        }
 
-        uasort($array, $arrow);
-    } else {
-        asort($array);
-    }
+        if (!is_iterable($compare)) {
+            return false;
+        }
 
-    return $array;
-}
+        if (\is_object($value) || \is_resource($value)) {
+            if (!\is_array($compare)) {
+                foreach ($compare as $item) {
+                    if ($item === $value) {
+                        return true;
+                    }
+                }
 
-/**
- * @internal
- */
-function twig_in_filter($value, $compare)
-{
-    if ($value instanceof Markup) {
-        $value = (string) $value;
-    }
-    if ($compare instanceof Markup) {
-        $compare = (string) $compare;
-    }
+                return false;
+            }
 
-    if (\is_string($compare)) {
-        if (\is_string($value) || \is_int($value) || \is_float($value)) {
-            return '' === $value || false !== strpos($compare, (string) $value);
+            return \in_array($value, $compare, true);
         }
 
-        return false;
-    }
+        foreach ($compare as $item) {
+            if (0 === self::compare($value, $item)) {
+                return true;
+            }
+        }
 
-    if (!is_iterable($compare)) {
         return false;
     }
 
-    if (\is_object($value) || \is_resource($value)) {
-        if (!\is_array($compare)) {
-            foreach ($compare as $item) {
-                if ($item === $value) {
-                    return true;
-                }
+    /**
+     * Compares two values using a more strict version of the PHP non-strict comparison operator.
+     *
+     * @see https://wiki.php.net/rfc/string_to_number_comparison
+     * @see https://wiki.php.net/rfc/trailing_whitespace_numerics
+     *
+     * @internal
+     */
+    public static function compare($a, $b)
+    {
+        // int <=> string
+        if (\is_int($a) && \is_string($b)) {
+            $bTrim = trim($b, " \t\n\r\v\f");
+            if (!is_numeric($bTrim)) {
+                return (string) $a <=> $b;
+            }
+            if ((int) $bTrim == $bTrim) {
+                return $a <=> (int) $bTrim;
+            } else {
+                return (float) $a <=> (float) $bTrim;
+            }
+        }
+        if (\is_string($a) && \is_int($b)) {
+            $aTrim = trim($a, " \t\n\r\v\f");
+            if (!is_numeric($aTrim)) {
+                return $a <=> (string) $b;
+            }
+            if ((int) $aTrim == $aTrim) {
+                return (int) $aTrim <=> $b;
+            } else {
+                return (float) $aTrim <=> (float) $b;
             }
-
-            return false;
         }
 
-        return \in_array($value, $compare, true);
-    }
+        // float <=> string
+        if (\is_float($a) && \is_string($b)) {
+            if (is_nan($a)) {
+                return 1;
+            }
+            $bTrim = trim($b, " \t\n\r\v\f");
+            if (!is_numeric($bTrim)) {
+                return (string) $a <=> $b;
+            }
 
-    foreach ($compare as $item) {
-        if (0 === twig_compare($value, $item)) {
-            return true;
+            return $a <=> (float) $bTrim;
         }
-    }
-
-    return false;
-}
+        if (\is_string($a) && \is_float($b)) {
+            if (is_nan($b)) {
+                return 1;
+            }
+            $aTrim = trim($a, " \t\n\r\v\f");
+            if (!is_numeric($aTrim)) {
+                return $a <=> (string) $b;
+            }
 
-/**
- * Compares two values using a more strict version of the PHP non-strict comparison operator.
- *
- * @see https://wiki.php.net/rfc/string_to_number_comparison
- * @see https://wiki.php.net/rfc/trailing_whitespace_numerics
- *
- * @internal
- */
-function twig_compare($a, $b)
-{
-    // int <=> string
-    if (\is_int($a) && \is_string($b)) {
-        $bTrim = trim($b, " \t\n\r\v\f");
-        if (!is_numeric($bTrim)) {
-            return (string) $a <=> $b;
-        }
-        if ((int) $bTrim == $bTrim) {
-            return $a <=> (int) $bTrim;
-        } else {
-            return (float) $a <=> (float) $bTrim;
+            return (float) $aTrim <=> $b;
         }
+
+        // fallback to <=>
+        return $a <=> $b;
     }
-    if (\is_string($a) && \is_int($b)) {
-        $aTrim = trim($a, " \t\n\r\v\f");
-        if (!is_numeric($aTrim)) {
-            return $a <=> (string) $b;
-        }
-        if ((int) $aTrim == $aTrim) {
-            return (int) $aTrim <=> $b;
-        } else {
-            return (float) $aTrim <=> (float) $b;
+
+    /**
+     * @throws RuntimeError When an invalid pattern is used
+     *
+     * @internal
+     */
+    public static function matches(string $regexp, ?string $str): int
+    {
+        set_error_handler(function ($t, $m) use ($regexp) {
+            throw new RuntimeError(\sprintf('Regexp "%s" passed to "matches" is not valid', $regexp).substr($m, 12));
+        });
+        try {
+            return preg_match($regexp, $str ?? '');
+        } finally {
+            restore_error_handler();
         }
     }
 
-    // float <=> string
-    if (\is_float($a) && \is_string($b)) {
-        if (is_nan($a)) {
-            return 1;
+    /**
+     * Returns a trimmed string.
+     *
+     * @param string|null $string
+     * @param string|null $characterMask
+     * @param string      $side
+     *
+     * @throws RuntimeError When an invalid trimming side is used (not a string or not 'left', 'right', or 'both')
+     *
+     * @internal
+     */
+    public static function trim($string, $characterMask = null, $side = 'both'): string
+    {
+        if (null === $characterMask) {
+            $characterMask = " \t\n\r\0\x0B";
         }
-        $bTrim = trim($b, " \t\n\r\v\f");
-        if (!is_numeric($bTrim)) {
-            return (string) $a <=> $b;
+
+        switch ($side) {
+            case 'both':
+                return trim($string ?? '', $characterMask);
+            case 'left':
+                return ltrim($string ?? '', $characterMask);
+            case 'right':
+                return rtrim($string ?? '', $characterMask);
+            default:
+                throw new RuntimeError('Trimming side must be "left", "right" or "both".');
         }
+    }
 
-        return $a <=> (float) $bTrim;
+    /**
+     * Inserts HTML line breaks before all newlines in a string.
+     *
+     * @param string|null $string
+     *
+     * @internal
+     */
+    public static function nl2br($string): string
+    {
+        return nl2br($string ?? '');
     }
-    if (\is_string($a) && \is_float($b)) {
-        if (is_nan($b)) {
-            return 1;
-        }
-        $aTrim = trim($a, " \t\n\r\v\f");
-        if (!is_numeric($aTrim)) {
-            return $a <=> (string) $b;
-        }
 
-        return (float) $aTrim <=> $b;
+    /**
+     * Removes whitespaces between HTML tags.
+     *
+     * @param string|null $content
+     *
+     * @internal
+     */
+    public static function spaceless($content): string
+    {
+        return trim(preg_replace('/>\s+</', '><', $content ?? ''));
     }
 
-    // fallback to <=>
-    return $a <=> $b;
-}
+    /**
+     * @param string|null $string
+     * @param string      $to
+     * @param string      $from
+     *
+     * @internal
+     */
+    public static function convertEncoding($string, $to, $from): string
+    {
+        if (!\function_exists('iconv')) {
+            throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
+        }
 
-/**
- * Returns a trimmed string.
- *
- * @param string|null $string
- * @param string|null $characterMask
- * @param string      $side
- *
- * @return string
- *
- * @throws RuntimeError When an invalid trimming side is used (not a string or not 'left', 'right', or 'both')
- */
-function twig_trim_filter($string, $characterMask = null, $side = 'both')
-{
-    if (null === $characterMask) {
-        $characterMask = " \t\n\r\0\x0B";
+        return iconv($from, $to, $string ?? '');
     }
 
-    switch ($side) {
-        case 'both':
-            return trim($string ?? '', $characterMask);
-        case 'left':
-            return ltrim($string ?? '', $characterMask);
-        case 'right':
-            return rtrim($string ?? '', $characterMask);
-        default:
-            throw new RuntimeError('Trimming side must be "left", "right" or "both".');
-    }
-}
+    /**
+     * Returns the length of a variable.
+     *
+     * @param mixed $thing A variable
+     *
+     * @internal
+     */
+    public static function length(string $charset, $thing): int
+    {
+        if (null === $thing) {
+            return 0;
+        }
 
-/**
- * Inserts HTML line breaks before all newlines in a string.
- *
- * @param string|null $string
- *
- * @return string
- */
-function twig_nl2br($string)
-{
-    return nl2br($string ?? '');
-}
+        if (\is_scalar($thing)) {
+            return mb_strlen($thing, $charset);
+        }
 
-/**
- * Removes whitespaces between HTML tags.
- *
- * @param string|null $string
- *
- * @return string
- */
-function twig_spaceless($content)
-{
-    return trim(preg_replace('/>\s+</', '><', $content ?? ''));
-}
+        if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) {
+            return \count($thing);
+        }
 
-/**
- * @param string|null $string
- * @param string      $to
- * @param string      $from
- *
- * @return string
- */
-function twig_convert_encoding($string, $to, $from)
-{
-    if (!\function_exists('iconv')) {
-        throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
-    }
+        if ($thing instanceof \Traversable) {
+            return iterator_count($thing);
+        }
 
-    return iconv($from, $to, $string ?? '');
-}
+        if ($thing instanceof \Stringable) {
+            return mb_strlen((string) $thing, $charset);
+        }
 
-/**
- * Returns the length of a variable.
- *
- * @param mixed $thing A variable
- *
- * @return int The length of the value
- */
-function twig_length_filter(Environment $env, $thing)
-{
-    if (null === $thing) {
-        return 0;
+        return 1;
     }
 
-    if (is_scalar($thing)) {
-        return mb_strlen($thing, $env->getCharset());
+    /**
+     * Converts a string to uppercase.
+     *
+     * @param string|null $string A string
+     *
+     * @internal
+     */
+    public static function upper(string $charset, $string): string
+    {
+        return mb_strtoupper($string ?? '', $charset);
     }
 
-    if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) {
-        return \count($thing);
+    /**
+     * Converts a string to lowercase.
+     *
+     * @param string|null $string A string
+     *
+     * @internal
+     */
+    public static function lower(string $charset, $string): string
+    {
+        return mb_strtolower($string ?? '', $charset);
     }
 
-    if ($thing instanceof \Traversable) {
-        return iterator_count($thing);
+    /**
+     * Strips HTML and PHP tags from a string.
+     *
+     * @param string|null          $string
+     * @param string[]|string|null $allowable_tags
+     *
+     * @internal
+     */
+    public static function striptags($string, $allowable_tags = null): string
+    {
+        return strip_tags($string ?? '', $allowable_tags);
     }
 
-    if (method_exists($thing, '__toString') && !$thing instanceof \Countable) {
-        return mb_strlen((string) $thing, $env->getCharset());
+    /**
+     * Returns a titlecased string.
+     *
+     * @param string|null $string A string
+     *
+     * @internal
+     */
+    public static function titleCase(string $charset, $string): string
+    {
+        return mb_convert_case($string ?? '', \MB_CASE_TITLE, $charset);
     }
 
-    return 1;
-}
-
-/**
- * Converts a string to uppercase.
- *
- * @param string|null $string A string
- *
- * @return string The uppercased string
- */
-function twig_upper_filter(Environment $env, $string)
-{
-    return mb_strtoupper($string ?? '', $env->getCharset());
-}
+    /**
+     * Returns a capitalized string.
+     *
+     * @param string|null $string A string
+     *
+     * @internal
+     */
+    public static function capitalize(string $charset, $string): string
+    {
+        return mb_strtoupper(mb_substr($string ?? '', 0, 1, $charset), $charset).mb_strtolower(mb_substr($string ?? '', 1, null, $charset), $charset);
+    }
 
-/**
- * Converts a string to lowercase.
- *
- * @param string|null $string A string
- *
- * @return string The lowercased string
- */
-function twig_lower_filter(Environment $env, $string)
-{
-    return mb_strtolower($string ?? '', $env->getCharset());
-}
+    /**
+     * @internal
+     */
+    public static function callMacro(Template $template, string $method, array $args, int $lineno, array $context, Source $source)
+    {
+        if (!method_exists($template, $method)) {
+            $parent = $template;
+            while ($parent = $parent->getParent($context)) {
+                if (method_exists($parent, $method)) {
+                    return $parent->$method(...$args);
+                }
+            }
 
-/**
- * Strips HTML and PHP tags from a string.
- *
- * @param string|null $string
- * @param string[]|string|null $string
- *
- * @return string
- */
-function twig_striptags($string, $allowable_tags = null)
-{
-    return strip_tags($string ?? '', $allowable_tags);
-}
+            throw new RuntimeError(\sprintf('Macro "%s" is not defined in template "%s".', substr($method, \strlen('macro_')), $template->getTemplateName()), $lineno, $source);
+        }
 
-/**
- * Returns a titlecased string.
- *
- * @param string|null $string A string
- *
- * @return string The titlecased string
- */
-function twig_title_string_filter(Environment $env, $string)
-{
-    if (null !== $charset = $env->getCharset()) {
-        return mb_convert_case($string ?? '', \MB_CASE_TITLE, $charset);
+        return $template->$method(...$args);
     }
 
-    return ucwords(strtolower($string ?? ''));
-}
+    /**
+     * @template TSequence
+     *
+     * @param TSequence $seq
+     *
+     * @return ($seq is iterable ? TSequence : array{})
+     *
+     * @internal
+     */
+    public static function ensureTraversable($seq)
+    {
+        if (is_iterable($seq)) {
+            return $seq;
+        }
 
-/**
- * Returns a capitalized string.
- *
- * @param string|null $string A string
- *
- * @return string The capitalized string
- */
-function twig_capitalize_string_filter(Environment $env, $string)
-{
-    $charset = $env->getCharset();
+        return [];
+    }
 
-    return mb_strtoupper(mb_substr($string ?? '', 0, 1, $charset), $charset).mb_strtolower(mb_substr($string ?? '', 1, null, $charset), $charset);
-}
+    /**
+     * @internal
+     */
+    public static function toArray($seq, $preserveKeys = true)
+    {
+        if ($seq instanceof \Traversable) {
+            return iterator_to_array($seq, $preserveKeys);
+        }
 
-/**
- * @internal
- */
-function twig_call_macro(Template $template, string $method, array $args, int $lineno, array $context, Source $source)
-{
-    if (!method_exists($template, $method)) {
-        $parent = $template;
-        while ($parent = $parent->getParent($context)) {
-            if (method_exists($parent, $method)) {
-                return $parent->$method(...$args);
-            }
+        if (!\is_array($seq)) {
+            return $seq;
         }
 
-        throw new RuntimeError(sprintf('Macro "%s" is not defined in template "%s".', substr($method, \strlen('macro_')), $template->getTemplateName()), $lineno, $source);
+        return $preserveKeys ? $seq : array_values($seq);
     }
 
-    return $template->$method(...$args);
-}
-
-/**
- * @internal
- */
-function twig_ensure_traversable($seq)
-{
-    if ($seq instanceof \Traversable || \is_array($seq)) {
-        return $seq;
-    }
+    /**
+     * Checks if a variable is empty.
+     *
+     *    {# evaluates to true if the foo variable is null, false, or the empty string #}
+     *    {% if foo is empty %}
+     *        {# ... #}
+     *    {% endif %}
+     *
+     * @param mixed $value A variable
+     *
+     * @internal
+     */
+    public static function testEmpty($value): bool
+    {
+        if ($value instanceof \Countable) {
+            return 0 === \count($value);
+        }
 
-    return [];
-}
+        if ($value instanceof \Traversable) {
+            return !iterator_count($value);
+        }
 
-/**
- * @internal
- */
-function twig_to_array($seq, $preserveKeys = true)
-{
-    if ($seq instanceof \Traversable) {
-        return iterator_to_array($seq, $preserveKeys);
-    }
+        if ($value instanceof \Stringable) {
+            return '' === (string) $value;
+        }
 
-    if (!\is_array($seq)) {
-        return $seq;
+        return '' === $value || false === $value || null === $value || [] === $value;
     }
 
-    return $preserveKeys ? $seq : array_values($seq);
-}
-
-/**
- * Checks if a variable is empty.
- *
- *    {# evaluates to true if the foo variable is null, false, or the empty string #}
- *    {% if foo is empty %}
- *        {# ... #}
- *    {% endif %}
- *
- * @param mixed $value A variable
- *
- * @return bool true if the value is empty, false otherwise
- */
-function twig_test_empty($value)
-{
-    if ($value instanceof \Countable) {
-        return 0 === \count($value);
-    }
+    /**
+     * Checks if a variable is a sequence.
+     *
+     *    {# evaluates to true if the foo variable is a sequence #}
+     *    {% if foo is sequence %}
+     *        {# ... #}
+     *    {% endif %}
+     *
+     * @param mixed $value
+     *
+     * @internal
+     */
+    public static function testSequence($value): bool
+    {
+        if ($value instanceof \ArrayObject) {
+            $value = $value->getArrayCopy();
+        }
 
-    if ($value instanceof \Traversable) {
-        return !iterator_count($value);
-    }
+        if ($value instanceof \Traversable) {
+            $value = iterator_to_array($value);
+        }
 
-    if (\is_object($value) && method_exists($value, '__toString')) {
-        return '' === (string) $value;
+        return \is_array($value) && array_is_list($value);
     }
 
-    return '' === $value || false === $value || null === $value || [] === $value;
-}
-
-/**
- * Checks if a variable is traversable.
- *
- *    {# evaluates to true if the foo variable is an array or a traversable object #}
- *    {% if foo is iterable %}
- *        {# ... #}
- *    {% endif %}
- *
- * @param mixed $value A variable
- *
- * @return bool true if the value is traversable
- */
-function twig_test_iterable($value)
-{
-    return $value instanceof \Traversable || \is_array($value);
-}
+    /**
+     * Checks if a variable is a mapping.
+     *
+     *    {# evaluates to true if the foo variable is a mapping #}
+     *    {% if foo is mapping %}
+     *        {# ... #}
+     *    {% endif %}
+     *
+     * @param mixed $value
+     *
+     * @internal
+     */
+    public static function testMapping($value): bool
+    {
+        if ($value instanceof \ArrayObject) {
+            $value = $value->getArrayCopy();
+        }
 
-/**
- * Renders a template.
- *
- * @param array        $context
- * @param string|array $template      The template to render or an array of templates to try consecutively
- * @param array        $variables     The variables to pass to the template
- * @param bool         $withContext
- * @param bool         $ignoreMissing Whether to ignore missing templates or not
- * @param bool         $sandboxed     Whether to sandbox the template or not
- *
- * @return string The rendered template
- */
-function twig_include(Environment $env, $context, $template, $variables = [], $withContext = true, $ignoreMissing = false, $sandboxed = false)
-{
-    $alreadySandboxed = false;
-    $sandbox = null;
-    if ($withContext) {
-        $variables = array_merge($context, $variables);
+        if ($value instanceof \Traversable) {
+            $value = iterator_to_array($value);
+        }
+
+        return (\is_array($value) && !array_is_list($value)) || \is_object($value);
     }
 
-    if ($isSandboxed = $sandboxed && $env->hasExtension(SandboxExtension::class)) {
-        $sandbox = $env->getExtension(SandboxExtension::class);
-        if (!$alreadySandboxed = $sandbox->isSandboxed()) {
-            $sandbox->enableSandbox();
+    /**
+     * Renders a template.
+     *
+     * @param array                        $context
+     * @param string|array|TemplateWrapper $template      The template to render or an array of templates to try consecutively
+     * @param array                        $variables     The variables to pass to the template
+     * @param bool                         $withContext
+     * @param bool                         $ignoreMissing Whether to ignore missing templates or not
+     * @param bool                         $sandboxed     Whether to sandbox the template or not
+     *
+     * @internal
+     */
+    public static function include(Environment $env, $context, $template, $variables = [], $withContext = true, $ignoreMissing = false, $sandboxed = false): string
+    {
+        $alreadySandboxed = false;
+        $sandbox = null;
+        if ($withContext) {
+            $variables = array_merge($context, $variables);
+        }
+
+        if ($isSandboxed = $sandboxed && $env->hasExtension(SandboxExtension::class)) {
+            $sandbox = $env->getExtension(SandboxExtension::class);
+            if (!$alreadySandboxed = $sandbox->isSandboxed()) {
+                $sandbox->enableSandbox();
+            }
         }
 
-        foreach ((\is_array($template) ? $template : [$template]) as $name) {
-            // if a Template instance is passed, it might have been instantiated outside of a sandbox, check security
-            if ($name instanceof TemplateWrapper || $name instanceof Template) {
-                $name->unwrap()->checkSecurity();
+        try {
+            $loaded = null;
+            try {
+                $loaded = $env->resolveTemplate($template);
+            } catch (LoaderError $e) {
+                if (!$ignoreMissing) {
+                    throw $e;
+                }
+
+                return '';
+            }
+
+            if ($isSandboxed) {
+                $loaded->unwrap()->checkSecurity();
+            }
+
+            return $loaded->render($variables);
+        } finally {
+            if ($isSandboxed && !$alreadySandboxed) {
+                $sandbox->disableSandbox();
             }
         }
     }
 
-    try {
-        $loaded = null;
+    /**
+     * Returns a template content without rendering it.
+     *
+     * @param string $name          The template name
+     * @param bool   $ignoreMissing Whether to ignore missing templates or not
+     *
+     * @internal
+     */
+    public static function source(Environment $env, $name, $ignoreMissing = false): string
+    {
+        $loader = $env->getLoader();
         try {
-            $loaded = $env->resolveTemplate($template);
+            return $loader->getSourceContext($name)->getCode();
         } catch (LoaderError $e) {
             if (!$ignoreMissing) {
                 throw $e;
             }
-        }
 
-        return $loaded ? $loaded->render($variables) : '';
-    } finally {
-        if ($isSandboxed && !$alreadySandboxed) {
-            $sandbox->disableSandbox();
+            return '';
         }
     }
-}
 
-/**
- * Returns a template content without rendering it.
- *
- * @param string $name          The template name
- * @param bool   $ignoreMissing Whether to ignore missing templates or not
- *
- * @return string The template source
- */
-function twig_source(Environment $env, $name, $ignoreMissing = false)
-{
-    $loader = $env->getLoader();
-    try {
-        return $loader->getSourceContext($name)->getCode();
-    } catch (LoaderError $e) {
-        if (!$ignoreMissing) {
-            throw $e;
+    /**
+     * Returns the list of cases of the enum.
+     *
+     * @template T of \UnitEnum
+     *
+     * @param class-string<T> $enum
+     *
+     * @return list<T>
+     *
+     * @internal
+     */
+    public static function enumCases(string $enum): array
+    {
+        if (!enum_exists($enum)) {
+            throw new RuntimeError(\sprintf('Enum "%s" does not exist.', $enum));
         }
+
+        return $enum::cases();
     }
-}
 
-/**
- * Provides the ability to get constants from instances as well as class/global constants.
- *
- * @param string      $constant The name of the constant
- * @param object|null $object   The object to get the constant from
- *
- * @return string
- */
-function twig_constant($constant, $object = null)
-{
-    if (null !== $object) {
-        if ('class' === $constant) {
-            return \get_class($object);
+    /**
+     * Provides the ability to get constants from instances as well as class/global constants.
+     *
+     * @param string      $constant     The name of the constant
+     * @param object|null $object       The object to get the constant from
+     * @param bool        $checkDefined Whether to check if the constant is defined or not
+     *
+     * @return mixed Class constants can return many types like scalars, arrays, and
+     *               objects depending on the PHP version (\BackedEnum, \UnitEnum, etc.)
+     *               When $checkDefined is true, returns true when the constant is defined, false otherwise
+     *
+     * @internal
+     */
+    public static function constant($constant, $object = null, bool $checkDefined = false)
+    {
+        if (null !== $object) {
+            if ('class' === $constant) {
+                return $checkDefined ? true : \get_class($object);
+            }
+
+            $constant = \get_class($object).'::'.$constant;
         }
 
-        $constant = \get_class($object).'::'.$constant;
-    }
+        if (!\defined($constant)) {
+            if ($checkDefined) {
+                return false;
+            }
 
-    return \constant($constant);
-}
+            if ('::class' === strtolower(substr($constant, -7))) {
+                throw new RuntimeError(\sprintf('You cannot use the Twig function "constant()" to access "%s". You could provide an object and call constant("class", $object) or use the class name directly as a string.', $constant));
+            }
 
-/**
- * Checks if a constant exists.
- *
- * @param string      $constant The name of the constant
- * @param object|null $object   The object to get the constant from
- *
- * @return bool
- */
-function twig_constant_is_defined($constant, $object = null)
-{
-    if (null !== $object) {
-        if ('class' === $constant) {
-            return true;
+            throw new RuntimeError(\sprintf('Constant "%s" is undefined.', $constant));
         }
 
-        $constant = \get_class($object).'::'.$constant;
+        return $checkDefined ? true : \constant($constant);
     }
 
-    return \defined($constant);
-}
-
-/**
- * Batches item.
- *
- * @param array $items An array of items
- * @param int   $size  The size of the batch
- * @param mixed $fill  A value used to fill missing items
- *
- * @return array
- */
-function twig_array_batch($items, $size, $fill = null, $preserveKeys = true)
-{
-    if (!twig_test_iterable($items)) {
-        throw new RuntimeError(sprintf('The "batch" filter expects an array or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
-    }
+    /**
+     * Batches item.
+     *
+     * @param array $items An array of items
+     * @param int   $size  The size of the batch
+     * @param mixed $fill  A value used to fill missing items
+     *
+     * @internal
+     */
+    public static function batch($items, $size, $fill = null, $preserveKeys = true): array
+    {
+        if (!is_iterable($items)) {
+            throw new RuntimeError(\sprintf('The "batch" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($items) ? \get_class($items) : \gettype($items)));
+        }
 
-    $size = ceil($size);
+        $size = (int) ceil($size);
 
-    $result = array_chunk(twig_to_array($items, $preserveKeys), $size, $preserveKeys);
+        $result = array_chunk(self::toArray($items, $preserveKeys), $size, $preserveKeys);
 
-    if (null !== $fill && $result) {
-        $last = \count($result) - 1;
-        if ($fillCount = $size - \count($result[$last])) {
-            for ($i = 0; $i < $fillCount; ++$i) {
-                $result[$last][] = $fill;
+        if (null !== $fill && $result) {
+            $last = \count($result) - 1;
+            if ($fillCount = $size - \count($result[$last])) {
+                for ($i = 0; $i < $fillCount; ++$i) {
+                    $result[$last][] = $fill;
+                }
             }
         }
-    }
 
-    return $result;
-}
+        return $result;
+    }
 
-/**
- * Returns the attribute value for a given array/object.
- *
- * @param mixed  $object            The object or array from where to get the item
- * @param mixed  $item              The item to get from the array or object
- * @param array  $arguments         An array of arguments to pass if the item is an object method
- * @param string $type              The type of attribute (@see \Twig\Template constants)
- * @param bool   $isDefinedTest     Whether this is only a defined check
- * @param bool   $ignoreStrictCheck Whether to ignore the strict attribute check or not
- * @param int    $lineno            The template line where the attribute was called
- *
- * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
- *
- * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
- *
- * @internal
- */
-function twig_get_attribute(Environment $env, Source $source, $object, $item, array $arguments = [], $type = /* Template::ANY_CALL */ 'any', $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false, int $lineno = -1)
-{
-    // array
-    if (/* Template::METHOD_CALL */ 'method' !== $type) {
-        $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item;
+    /**
+     * Returns the attribute value for a given array/object.
+     *
+     * @param mixed  $object            The object or array from where to get the item
+     * @param mixed  $item              The item to get from the array or object
+     * @param array  $arguments         An array of arguments to pass if the item is an object method
+     * @param string $type              The type of attribute (@see \Twig\Template constants)
+     * @param bool   $isDefinedTest     Whether this is only a defined check
+     * @param bool   $ignoreStrictCheck Whether to ignore the strict attribute check or not
+     * @param int    $lineno            The template line where the attribute was called
+     *
+     * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true
+     *
+     * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false
+     *
+     * @internal
+     */
+    public static function getAttribute(Environment $env, Source $source, $object, $item, array $arguments = [], $type = Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false, int $lineno = -1)
+    {
+        // array
+        if (Template::METHOD_CALL !== $type) {
+            $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item;
+
+            if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object)))
+                || ($object instanceof \ArrayAccess && isset($object[$arrayItem]))
+            ) {
+                if ($isDefinedTest) {
+                    return true;
+                }
 
-        if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object)))
-            || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
-        ) {
-            if ($isDefinedTest) {
-                return true;
+                return $object[$arrayItem];
             }
 
-            return $object[$arrayItem];
+            if (Template::ARRAY_CALL === $type || !\is_object($object)) {
+                if ($isDefinedTest) {
+                    return false;
+                }
+
+                if ($ignoreStrictCheck || !$env->isStrictVariables()) {
+                    return;
+                }
+
+                if ($object instanceof \ArrayAccess) {
+                    $message = \sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object));
+                } elseif (\is_object($object)) {
+                    $message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object));
+                } elseif (\is_array($object)) {
+                    if (empty($object)) {
+                        $message = \sprintf('Key "%s" does not exist as the sequence/mapping is empty.', $arrayItem);
+                    } else {
+                        $message = \sprintf('Key "%s" for sequence/mapping with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
+                    }
+                } elseif (Template::ARRAY_CALL === $type) {
+                    if (null === $object) {
+                        $message = \sprintf('Impossible to access a key ("%s") on a null variable.', $item);
+                    } else {
+                        $message = \sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
+                    }
+                } elseif (null === $object) {
+                    $message = \sprintf('Impossible to access an attribute ("%s") on a null variable.', $item);
+                } else {
+                    $message = \sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
+                }
+
+                throw new RuntimeError($message, $lineno, $source);
+            }
         }
 
-        if (/* Template::ARRAY_CALL */ 'array' === $type || !\is_object($object)) {
+        if (!\is_object($object)) {
             if ($isDefinedTest) {
                 return false;
             }
@@ -1463,233 +1645,326 @@ function twig_get_attribute(Environment $env, Source $source, $object, $item, ar
                 return;
             }
 
-            if ($object instanceof ArrayAccess) {
-                $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object));
-            } elseif (\is_object($object)) {
-                $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object));
+            if (null === $object) {
+                $message = \sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
             } elseif (\is_array($object)) {
-                if (empty($object)) {
-                    $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem);
-                } else {
-                    $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object)));
-                }
-            } elseif (/* Template::ARRAY_CALL */ 'array' === $type) {
-                if (null === $object) {
-                    $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item);
-                } else {
-                    $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
-                }
-            } elseif (null === $object) {
-                $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item);
+                $message = \sprintf('Impossible to invoke a method ("%s") on a sequence/mapping.', $item);
             } else {
-                $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
+                $message = \sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
             }
 
             throw new RuntimeError($message, $lineno, $source);
         }
-    }
 
-    if (!\is_object($object)) {
-        if ($isDefinedTest) {
-            return false;
+        if ($object instanceof Template) {
+            throw new RuntimeError('Accessing \Twig\Template attributes is forbidden.', $lineno, $source);
         }
 
-        if ($ignoreStrictCheck || !$env->isStrictVariables()) {
-            return;
-        }
+        // object property
+        if (Template::METHOD_CALL !== $type) {
+            if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) {
+                if ($isDefinedTest) {
+                    return true;
+                }
 
-        if (null === $object) {
-            $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item);
-        } elseif (\is_array($object)) {
-            $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item);
-        } else {
-            $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object);
+                if ($sandboxed) {
+                    $env->getExtension(SandboxExtension::class)->checkPropertyAllowed($object, $item, $lineno, $source);
+                }
+
+                return $object->$item;
+            }
         }
 
-        throw new RuntimeError($message, $lineno, $source);
-    }
+        static $cache = [];
+
+        $class = \get_class($object);
+
+        // object method
+        // precedence: getXxx() > isXxx() > hasXxx()
+        if (!isset($cache[$class])) {
+            $methods = get_class_methods($object);
+            sort($methods);
+            $lcMethods = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, $methods);
+            $classCache = [];
+            foreach ($methods as $i => $method) {
+                $classCache[$method] = $method;
+                $classCache[$lcName = $lcMethods[$i]] = $method;
+
+                if ('g' === $lcName[0] && str_starts_with($lcName, 'get')) {
+                    $name = substr($method, 3);
+                    $lcName = substr($lcName, 3);
+                } elseif ('i' === $lcName[0] && str_starts_with($lcName, 'is')) {
+                    $name = substr($method, 2);
+                    $lcName = substr($lcName, 2);
+                } elseif ('h' === $lcName[0] && str_starts_with($lcName, 'has')) {
+                    $name = substr($method, 3);
+                    $lcName = substr($lcName, 3);
+                    if (\in_array('is'.$lcName, $lcMethods)) {
+                        continue;
+                    }
+                } else {
+                    continue;
+                }
 
-    if ($object instanceof Template) {
-        throw new RuntimeError('Accessing \Twig\Template attributes is forbidden.', $lineno, $source);
-    }
+                // skip get() and is() methods (in which case, $name is empty)
+                if ($name) {
+                    if (!isset($classCache[$name])) {
+                        $classCache[$name] = $method;
+                    }
+
+                    if (!isset($classCache[$lcName])) {
+                        $classCache[$lcName] = $method;
+                    }
+                }
+            }
+            $cache[$class] = $classCache;
+        }
 
-    // object property
-    if (/* Template::METHOD_CALL */ 'method' !== $type) {
-        if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) {
+        $call = false;
+        if (isset($cache[$class][$item])) {
+            $method = $cache[$class][$item];
+        } elseif (isset($cache[$class][$lcItem = strtr($item, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')])) {
+            $method = $cache[$class][$lcItem];
+        } elseif (isset($cache[$class]['__call'])) {
+            $method = $item;
+            $call = true;
+        } else {
             if ($isDefinedTest) {
-                return true;
+                return false;
             }
 
-            if ($sandboxed) {
-                $env->getExtension(SandboxExtension::class)->checkPropertyAllowed($object, $item, $lineno, $source);
+            if ($ignoreStrictCheck || !$env->isStrictVariables()) {
+                return;
             }
 
-            return $object->$item;
+            throw new RuntimeError(\sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source);
         }
-    }
 
-    static $cache = [];
-
-    $class = \get_class($object);
+        if ($isDefinedTest) {
+            return true;
+        }
 
-    // object method
-    // precedence: getXxx() > isXxx() > hasXxx()
-    if (!isset($cache[$class])) {
-        $methods = get_class_methods($object);
-        sort($methods);
-        $lcMethods = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, $methods);
-        $classCache = [];
-        foreach ($methods as $i => $method) {
-            $classCache[$method] = $method;
-            $classCache[$lcName = $lcMethods[$i]] = $method;
+        if ($sandboxed) {
+            $env->getExtension(SandboxExtension::class)->checkMethodAllowed($object, $method, $lineno, $source);
+        }
 
-            if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) {
-                $name = substr($method, 3);
-                $lcName = substr($lcName, 3);
-            } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) {
-                $name = substr($method, 2);
-                $lcName = substr($lcName, 2);
-            } elseif ('h' === $lcName[0] && 0 === strpos($lcName, 'has')) {
-                $name = substr($method, 3);
-                $lcName = substr($lcName, 3);
-                if (\in_array('is'.$lcName, $lcMethods)) {
-                    continue;
-                }
-            } else {
-                continue;
+        // Some objects throw exceptions when they have __call, and the method we try
+        // to call is not supported. If ignoreStrictCheck is true, we should return null.
+        try {
+            $ret = $object->$method(...$arguments);
+        } catch (\BadMethodCallException $e) {
+            if ($call && ($ignoreStrictCheck || !$env->isStrictVariables())) {
+                return;
             }
+            throw $e;
+        }
 
-            // skip get() and is() methods (in which case, $name is empty)
-            if ($name) {
-                if (!isset($classCache[$name])) {
-                    $classCache[$name] = $method;
-                }
+        return $ret;
+    }
 
-                if (!isset($classCache[$lcName])) {
-                    $classCache[$lcName] = $method;
-                }
-            }
+    /**
+     * Returns the values from a single column in the input array.
+     *
+     * <pre>
+     *  {% set items = [{ 'fruit' : 'apple'}, {'fruit' : 'orange' }] %}
+     *
+     *  {% set fruits = items|column('fruit') %}
+     *
+     *  {# fruits now contains ['apple', 'orange'] #}
+     * </pre>
+     *
+     * @param array|\Traversable $array An array
+     * @param int|string         $name  The column name
+     * @param int|string|null    $index The column to use as the index/keys for the returned array
+     *
+     * @return array The array of values
+     *
+     * @internal
+     */
+    public static function column($array, $name, $index = null): array
+    {
+        if ($array instanceof \Traversable) {
+            $array = iterator_to_array($array);
+        } elseif (!\is_array($array)) {
+            throw new RuntimeError(\sprintf('The column filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array)));
         }
-        $cache[$class] = $classCache;
+
+        return array_column($array, $name, $index);
     }
 
-    $call = false;
-    if (isset($cache[$class][$item])) {
-        $method = $cache[$class][$item];
-    } elseif (isset($cache[$class][$lcItem = strtr($item, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')])) {
-        $method = $cache[$class][$lcItem];
-    } elseif (isset($cache[$class]['__call'])) {
-        $method = $item;
-        $call = true;
-    } else {
-        if ($isDefinedTest) {
-            return false;
+    /**
+     * @internal
+     */
+    public static function filter(Environment $env, $array, $arrow)
+    {
+        if (!is_iterable($array)) {
+            throw new RuntimeError(\sprintf('The "filter" filter expects a sequence/mapping or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
         }
 
-        if ($ignoreStrictCheck || !$env->isStrictVariables()) {
-            return;
+        self::checkArrowInSandbox($env, $arrow, 'filter', 'filter');
+
+        if (\is_array($array)) {
+            return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
         }
 
-        throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source);
+        // the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator
+        return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
     }
 
-    if ($isDefinedTest) {
-        return true;
-    }
+    /**
+     * @internal
+     */
+    public static function find(Environment $env, $array, $arrow)
+    {
+        self::checkArrowInSandbox($env, $arrow, 'find', 'filter');
+
+        foreach ($array as $k => $v) {
+            if ($arrow($v, $k)) {
+                return $v;
+            }
+        }
 
-    if ($sandboxed) {
-        $env->getExtension(SandboxExtension::class)->checkMethodAllowed($object, $method, $lineno, $source);
+        return null;
     }
 
-    // Some objects throw exceptions when they have __call, and the method we try
-    // to call is not supported. If ignoreStrictCheck is true, we should return null.
-    try {
-        $ret = $object->$method(...$arguments);
-    } catch (\BadMethodCallException $e) {
-        if ($call && ($ignoreStrictCheck || !$env->isStrictVariables())) {
-            return;
+    /**
+     * @internal
+     */
+    public static function map(Environment $env, $array, $arrow)
+    {
+        if (!is_iterable($array)) {
+            throw new RuntimeError(\sprintf('The "map" filter expects a sequence/mapping or "Traversable", got "%s".', get_debug_type($array)));
         }
-        throw $e;
-    }
 
-    return $ret;
-}
+        self::checkArrowInSandbox($env, $arrow, 'map', 'filter');
 
-/**
- * Returns the values from a single column in the input array.
- *
- * <pre>
- *  {% set items = [{ 'fruit' : 'apple'}, {'fruit' : 'orange' }] %}
- *
- *  {% set fruits = items|column('fruit') %}
- *
- *  {# fruits now contains ['apple', 'orange'] #}
- * </pre>
- *
- * @param array|Traversable $array An array
- * @param mixed             $name  The column name
- * @param mixed             $index The column to use as the index/keys for the returned array
- *
- * @return array The array of values
- */
-function twig_array_column($array, $name, $index = null): array
-{
-    if ($array instanceof Traversable) {
-        $array = iterator_to_array($array);
-    } elseif (!\is_array($array)) {
-        throw new RuntimeError(sprintf('The column filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
+        $r = [];
+        foreach ($array as $k => $v) {
+            $r[$k] = $arrow($v, $k);
+        }
+
+        return $r;
     }
 
-    return array_column($array, $name, $index);
-}
+    /**
+     * @internal
+     */
+    public static function reduce(Environment $env, $array, $arrow, $initial = null)
+    {
+        self::checkArrowInSandbox($env, $arrow, 'reduce', 'filter');
 
-function twig_array_filter(Environment $env, $array, $arrow)
-{
-    if (!twig_test_iterable($array)) {
-        throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array)));
+        if (!\is_array($array) && !$array instanceof \Traversable) {
+            throw new RuntimeError(\sprintf('The "reduce" filter only works with sequences/mappings or "Traversable", got "%s" as first argument.', \gettype($array)));
+        }
+
+        $accumulator = $initial;
+        foreach ($array as $key => $value) {
+            $accumulator = $arrow($accumulator, $value, $key);
+        }
+
+        return $accumulator;
     }
 
-    twig_check_arrow_in_sandbox($env, $arrow, 'filter', 'filter');
+    /**
+     * @internal
+     */
+    public static function arraySome(Environment $env, $array, $arrow)
+    {
+        self::checkArrowInSandbox($env, $arrow, 'has some', 'operator');
+
+        foreach ($array as $k => $v) {
+            if ($arrow($v, $k)) {
+                return true;
+            }
+        }
 
-    if (\is_array($array)) {
-        return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH);
+        return false;
     }
 
-    // the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator
-    return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
-}
+    /**
+     * @internal
+     */
+    public static function arrayEvery(Environment $env, $array, $arrow)
+    {
+        self::checkArrowInSandbox($env, $arrow, 'has every', 'operator');
 
-function twig_array_map(Environment $env, $array, $arrow)
-{
-    twig_check_arrow_in_sandbox($env, $arrow, 'map', 'filter');
+        foreach ($array as $k => $v) {
+            if (!$arrow($v, $k)) {
+                return false;
+            }
+        }
 
-    $r = [];
-    foreach ($array as $k => $v) {
-        $r[$k] = $arrow($v, $k);
+        return true;
     }
 
-    return $r;
-}
+    /**
+     * @internal
+     */
+    public static function checkArrowInSandbox(Environment $env, $arrow, $thing, $type)
+    {
+        if (!$arrow instanceof \Closure && $env->hasExtension(SandboxExtension::class) && $env->getExtension(SandboxExtension::class)->isSandboxed()) {
+            throw new RuntimeError(\sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type));
+        }
+    }
 
-function twig_array_reduce(Environment $env, $array, $arrow, $initial = null)
-{
-    twig_check_arrow_in_sandbox($env, $arrow, 'reduce', 'filter');
+    /**
+     * @internal to be removed in Twig 4
+     */
+    public static function captureOutput(iterable $body): string
+    {
+        $level = ob_get_level();
+        ob_start();
+
+        try {
+            foreach ($body as $data) {
+                echo $data;
+            }
+        } catch (\Throwable $e) {
+            while (ob_get_level() > $level) {
+                ob_end_clean();
+            }
 
-    if (!\is_array($array)) {
-        if (!$array instanceof \Traversable) {
-            throw new RuntimeError(sprintf('The "reduce" filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array)));
+            throw $e;
         }
 
-        $array = iterator_to_array($array);
+        return ob_get_clean();
     }
 
-    return array_reduce($array, $arrow, $initial);
-}
+    /**
+     * @internal
+     */
+    public static function parseParentFunction(Parser $parser, Node $fakeNode, $args, int $line): AbstractExpression
+    {
+        if (!$blockName = $parser->peekBlockStack()) {
+            throw new SyntaxError('Calling the "parent" function outside of a block is forbidden.', $line, $parser->getStream()->getSourceContext());
+        }
 
-function twig_check_arrow_in_sandbox(Environment $env, $arrow, $thing, $type)
-{
-    if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) {
-        throw new RuntimeError(sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type));
+        if (!$parser->hasInheritance()) {
+            throw new SyntaxError('Calling the "parent" function on a template that does not call "extends" or "use" is forbidden.', $line, $parser->getStream()->getSourceContext());
+        }
+
+        return new ParentExpression($blockName, $line);
+    }
+
+    /**
+     * @internal
+     */
+    public static function parseBlockFunction(Parser $parser, Node $fakeNode, $args, int $line): AbstractExpression
+    {
+        $fakeFunction = new TwigFunction('block', fn ($name, $template = null) => null);
+        $args = (new CallableArgumentsExtractor($fakeNode, $fakeFunction))->extractArguments($args);
+
+        return new BlockReferenceExpression($args[0], $args[1] ?? null, $line);
+    }
+
+    /**
+     * @internal
+     */
+    public static function parseAttributeFunction(Parser $parser, Node $fakeNode, $args, int $line): AbstractExpression
+    {
+        $fakeFunction = new TwigFunction('attribute', fn ($variable, $attribute, $arguments = null) => null);
+        $args = (new CallableArgumentsExtractor($fakeNode, $fakeFunction))->extractArguments($args);
+
+        return new GetAttrExpression($args[0], $args[1], $args[2] ?? null, Template::ANY_CALL, $line);
     }
-}
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/DebugExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/DebugExtension.php
index bfb23d7b..dac21c31 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/DebugExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/DebugExtension.php
@@ -9,7 +9,11 @@
  * file that was distributed with this source code.
  */
 
-namespace Twig\Extension {
+namespace Twig\Extension;
+
+use Twig\Environment;
+use Twig\Template;
+use Twig\TemplateWrapper;
 use Twig\TwigFunction;
 
 final class DebugExtension extends AbstractExtension
@@ -18,47 +22,41 @@ final class DebugExtension extends AbstractExtension
     {
         // dump is safe if var_dump is overridden by xdebug
         $isDumpOutputHtmlSafe = \extension_loaded('xdebug')
-            // false means that it was not set (and the default is on) or it explicitly enabled
-            && (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
-            // false means that it was not set (and the default is on) or it explicitly enabled
-            // xdebug.overload_var_dump produces HTML only when html_errors is also enabled
-            && (false === ini_get('html_errors') || ini_get('html_errors'))
+            // Xdebug overloads var_dump in develop mode when html_errors is enabled
+            && str_contains(\ini_get('xdebug.mode'), 'develop')
+            && (false === \ini_get('html_errors') || \ini_get('html_errors'))
             || 'cli' === \PHP_SAPI
         ;
 
         return [
-            new TwigFunction('dump', 'twig_var_dump', ['is_safe' => $isDumpOutputHtmlSafe ? ['html'] : [], 'needs_context' => true, 'needs_environment' => true, 'is_variadic' => true]),
+            new TwigFunction('dump', [self::class, 'dump'], ['is_safe' => $isDumpOutputHtmlSafe ? ['html'] : [], 'needs_context' => true, 'needs_environment' => true, 'is_variadic' => true]),
         ];
     }
-}
-}
 
-namespace {
-use Twig\Environment;
-use Twig\Template;
-use Twig\TemplateWrapper;
-
-function twig_var_dump(Environment $env, $context, ...$vars)
-{
-    if (!$env->isDebug()) {
-        return;
-    }
+    /**
+     * @internal
+     */
+    public static function dump(Environment $env, $context, ...$vars)
+    {
+        if (!$env->isDebug()) {
+            return;
+        }
 
-    ob_start();
+        ob_start();
 
-    if (!$vars) {
-        $vars = [];
-        foreach ($context as $key => $value) {
-            if (!$value instanceof Template && !$value instanceof TemplateWrapper) {
-                $vars[$key] = $value;
+        if (!$vars) {
+            $vars = [];
+            foreach ($context as $key => $value) {
+                if (!$value instanceof Template && !$value instanceof TemplateWrapper) {
+                    $vars[$key] = $value;
+                }
             }
+
+            var_dump($vars);
+        } else {
+            var_dump(...$vars);
         }
 
-        var_dump($vars);
-    } else {
-        var_dump(...$vars);
+        return ob_get_clean();
     }
-
-    return ob_get_clean();
-}
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/EscaperExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/EscaperExtension.php
index 9d2251dc..52531c43 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/EscaperExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/EscaperExtension.php
@@ -9,22 +9,24 @@
  * file that was distributed with this source code.
  */
 
-namespace Twig\Extension {
+namespace Twig\Extension;
+
+use Twig\Environment;
 use Twig\FileExtensionEscapingStrategy;
+use Twig\Node\Expression\ConstantExpression;
+use Twig\Node\Expression\Filter\RawFilter;
+use Twig\Node\Node;
 use Twig\NodeVisitor\EscaperNodeVisitor;
+use Twig\Runtime\EscaperRuntime;
 use Twig\TokenParser\AutoEscapeTokenParser;
 use Twig\TwigFilter;
 
 final class EscaperExtension extends AbstractExtension
 {
-    private $defaultStrategy;
+    private $environment;
     private $escapers = [];
-
-    /** @internal */
-    public $safeClasses = [];
-
-    /** @internal */
-    public $safeLookup = [];
+    private $escaper;
+    private $defaultStrategy;
 
     /**
      * @param string|false|callable $defaultStrategy An escaping strategy
@@ -49,19 +51,43 @@ final class EscaperExtension extends AbstractExtension
     public function getFilters(): array
     {
         return [
-            new TwigFilter('escape', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
-            new TwigFilter('e', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']),
-            new TwigFilter('raw', 'twig_raw_filter', ['is_safe' => ['all']]),
+            new TwigFilter('escape', [EscaperRuntime::class, 'escape'], ['is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
+            new TwigFilter('e', [EscaperRuntime::class, 'escape'], ['is_safe_callback' => [self::class, 'escapeFilterIsSafe']]),
+            new TwigFilter('raw', null, ['is_safe' => ['all'], 'node_class' => RawFilter::class]),
         ];
     }
 
+    /**
+     * @deprecated since Twig 3.10
+     */
+    public function setEnvironment(Environment $environment): void
+    {
+        $triggerDeprecation = \func_num_args() > 1 ? func_get_arg(1) : true;
+        if ($triggerDeprecation) {
+            trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated and not needed if you are using methods from "Twig\Runtime\EscaperRuntime".', __METHOD__);
+        }
+
+        $this->environment = $environment;
+        $this->escaper = $environment->getRuntime(EscaperRuntime::class);
+    }
+
+    /**
+     * @deprecated since Twig 3.10
+     */
+    public function setEscaperRuntime(EscaperRuntime $escaper)
+    {
+        trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated and not needed if you are using methods from "Twig\Runtime\EscaperRuntime".', __METHOD__);
+
+        $this->escaper = $escaper;
+    }
+
     /**
      * Sets the default strategy to use when not defined by the user.
      *
      * The strategy can be a valid PHP callback that takes the template
      * name as an argument and returns the strategy to use.
      *
-     * @param string|false|callable $defaultStrategy An escaping strategy
+     * @param string|false|callable(string $templateName): string $defaultStrategy An escaping strategy
      */
     public function setDefaultStrategy($defaultStrategy): void
     {
@@ -93,324 +119,82 @@ final class EscaperExtension extends AbstractExtension
     /**
      * Defines a new escaper to be used via the escape filter.
      *
-     * @param string   $strategy The strategy name that should be used as a strategy in the escape call
-     * @param callable $callable A valid PHP callable
+     * @param string                                        $strategy The strategy name that should be used as a strategy in the escape call
+     * @param callable(Environment, string, string): string $callable A valid PHP callable
+     *
+     * @deprecated since Twig 3.10
      */
     public function setEscaper($strategy, callable $callable)
     {
+        trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::setEscaper()" method instead (be warned that Environment is not passed anymore to the callable).', __METHOD__);
+
+        if (!isset($this->environment)) {
+            throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
+        }
+
         $this->escapers[$strategy] = $callable;
+        $callable = function ($string, $charset) use ($callable) {
+            return $callable($this->environment, $string, $charset);
+        };
+
+        $this->escaper->setEscaper($strategy, $callable);
     }
 
     /**
      * Gets all defined escapers.
      *
-     * @return callable[] An array of escapers
+     * @return array<string, callable(Environment, string, string): string> An array of escapers
+     *
+     * @deprecated since Twig 3.10
      */
     public function getEscapers()
     {
+        trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::getEscaper()" method instead.', __METHOD__);
+
         return $this->escapers;
     }
 
+    /**
+     * @deprecated since Twig 3.10
+     */
     public function setSafeClasses(array $safeClasses = [])
     {
-        $this->safeClasses = [];
-        $this->safeLookup = [];
-        foreach ($safeClasses as $class => $strategies) {
-            $this->addSafeClass($class, $strategies);
-        }
-    }
+        trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::setSafeClasses()" method instead.', __METHOD__);
 
-    public function addSafeClass(string $class, array $strategies)
-    {
-        $class = ltrim($class, '\\');
-        if (!isset($this->safeClasses[$class])) {
-            $this->safeClasses[$class] = [];
+        if (!isset($this->escaper)) {
+            throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
         }
-        $this->safeClasses[$class] = array_merge($this->safeClasses[$class], $strategies);
 
-        foreach ($strategies as $strategy) {
-            $this->safeLookup[$strategy][$class] = true;
-        }
+        $this->escaper->setSafeClasses($safeClasses);
     }
-}
-}
 
-namespace {
-use Twig\Environment;
-use Twig\Error\RuntimeError;
-use Twig\Extension\EscaperExtension;
-use Twig\Markup;
-use Twig\Node\Expression\ConstantExpression;
-use Twig\Node\Node;
-
-/**
- * Marks a variable as being safe.
- *
- * @param string $string A PHP variable
- */
-function twig_raw_filter($string)
-{
-    return $string;
-}
-
-/**
- * Escapes a string.
- *
- * @param mixed  $string     The value to be escaped
- * @param string $strategy   The escaping strategy
- * @param string $charset    The charset
- * @param bool   $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
- *
- * @return string
- */
-function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
-{
-    if ($autoescape && $string instanceof Markup) {
-        return $string;
-    }
-
-    if (!\is_string($string)) {
-        if (\is_object($string) && method_exists($string, '__toString')) {
-            if ($autoescape) {
-                $c = \get_class($string);
-                $ext = $env->getExtension(EscaperExtension::class);
-                if (!isset($ext->safeClasses[$c])) {
-                    $ext->safeClasses[$c] = [];
-                    foreach (class_parents($string) + class_implements($string) as $class) {
-                        if (isset($ext->safeClasses[$class])) {
-                            $ext->safeClasses[$c] = array_unique(array_merge($ext->safeClasses[$c], $ext->safeClasses[$class]));
-                            foreach ($ext->safeClasses[$class] as $s) {
-                                $ext->safeLookup[$s][$c] = true;
-                            }
-                        }
-                    }
-                }
-                if (isset($ext->safeLookup[$strategy][$c]) || isset($ext->safeLookup['all'][$c])) {
-                    return (string) $string;
-                }
-            }
+    /**
+     * @deprecated since Twig 3.10
+     */
+    public function addSafeClass(string $class, array $strategies)
+    {
+        trigger_deprecation('twig/twig', '3.10', 'The "%s()" method is deprecated, use the "Twig\Runtime\EscaperRuntime::addSafeClass()" method instead.', __METHOD__);
 
-            $string = (string) $string;
-        } elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) {
-            return $string;
+        if (!isset($this->escaper)) {
+            throw new \LogicException(\sprintf('You must call "setEnvironment()" before calling "%s()".', __METHOD__));
         }
-    }
 
-    if ('' === $string) {
-        return '';
+        $this->escaper->addSafeClass($class, $strategies);
     }
 
-    if (null === $charset) {
-        $charset = $env->getCharset();
-    }
-
-    switch ($strategy) {
-        case 'html':
-            // see https://www.php.net/htmlspecialchars
-
-            // Using a static variable to avoid initializing the array
-            // each time the function is called. Moving the declaration on the
-            // top of the function slow downs other escaping strategies.
-            static $htmlspecialcharsCharsets = [
-                'ISO-8859-1' => true, 'ISO8859-1' => true,
-                'ISO-8859-15' => true, 'ISO8859-15' => true,
-                'utf-8' => true, 'UTF-8' => true,
-                'CP866' => true, 'IBM866' => true, '866' => true,
-                'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
-                '1251' => true,
-                'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
-                'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
-                'BIG5' => true, '950' => true,
-                'GB2312' => true, '936' => true,
-                'BIG5-HKSCS' => true,
-                'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
-                'EUC-JP' => true, 'EUCJP' => true,
-                'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
-            ];
-
-            if (isset($htmlspecialcharsCharsets[$charset])) {
-                return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
-            }
-
-            if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
-                // cache the lowercase variant for future iterations
-                $htmlspecialcharsCharsets[$charset] = true;
-
-                return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
-            }
-
-            $string = twig_convert_encoding($string, 'UTF-8', $charset);
-            $string = htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8');
-
-            return iconv('UTF-8', $charset, $string);
-
-        case 'js':
-            // escape all non-alphanumeric characters
-            // into their \x or \uHHHH representations
-            if ('UTF-8' !== $charset) {
-                $string = twig_convert_encoding($string, 'UTF-8', $charset);
-            }
-
-            if (!preg_match('//u', $string)) {
-                throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
-            }
-
-            $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', function ($matches) {
-                $char = $matches[0];
-
-                /*
-                 * A few characters have short escape sequences in JSON and JavaScript.
-                 * Escape sequences supported only by JavaScript, not JSON, are omitted.
-                 * \" is also supported but omitted, because the resulting string is not HTML safe.
-                 */
-                static $shortMap = [
-                    '\\' => '\\\\',
-                    '/' => '\\/',
-                    "\x08" => '\b',
-                    "\x0C" => '\f',
-                    "\x0A" => '\n',
-                    "\x0D" => '\r',
-                    "\x09" => '\t',
-                ];
-
-                if (isset($shortMap[$char])) {
-                    return $shortMap[$char];
-                }
-
-                $codepoint = mb_ord($char, 'UTF-8');
-                if (0x10000 > $codepoint) {
-                    return sprintf('\u%04X', $codepoint);
-                }
-
-                // Split characters outside the BMP into surrogate pairs
-                // https://tools.ietf.org/html/rfc2781.html#section-2.1
-                $u = $codepoint - 0x10000;
-                $high = 0xD800 | ($u >> 10);
-                $low = 0xDC00 | ($u & 0x3FF);
-
-                return sprintf('\u%04X\u%04X', $high, $low);
-            }, $string);
-
-            if ('UTF-8' !== $charset) {
-                $string = iconv('UTF-8', $charset, $string);
-            }
-
-            return $string;
-
-        case 'css':
-            if ('UTF-8' !== $charset) {
-                $string = twig_convert_encoding($string, 'UTF-8', $charset);
-            }
-
-            if (!preg_match('//u', $string)) {
-                throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
-            }
-
-            $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', function ($matches) {
-                $char = $matches[0];
-
-                return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : mb_ord($char, 'UTF-8'));
-            }, $string);
-
-            if ('UTF-8' !== $charset) {
-                $string = iconv('UTF-8', $charset, $string);
-            }
-
-            return $string;
-
-        case 'html_attr':
-            if ('UTF-8' !== $charset) {
-                $string = twig_convert_encoding($string, 'UTF-8', $charset);
-            }
-
-            if (!preg_match('//u', $string)) {
-                throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
-            }
-
-            $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', function ($matches) {
-                /**
-                 * This function is adapted from code coming from Zend Framework.
-                 *
-                 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com)
-                 * @license   https://framework.zend.com/license/new-bsd New BSD License
-                 */
-                $chr = $matches[0];
-                $ord = \ord($chr);
-
-                /*
-                 * The following replaces characters undefined in HTML with the
-                 * hex entity for the Unicode replacement character.
-                 */
-                if (($ord <= 0x1f && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7f && $ord <= 0x9f)) {
-                    return '&#xFFFD;';
-                }
-
-                /*
-                 * Check if the current character to escape has a name entity we should
-                 * replace it with while grabbing the hex value of the character.
-                 */
-                if (1 === \strlen($chr)) {
-                    /*
-                     * While HTML supports far more named entities, the lowest common denominator
-                     * has become HTML5's XML Serialisation which is restricted to the those named
-                     * entities that XML supports. Using HTML entities would result in this error:
-                     *     XML Parsing Error: undefined entity
-                     */
-                    static $entityMap = [
-                        34 => '&quot;', /* quotation mark */
-                        38 => '&amp;',  /* ampersand */
-                        60 => '&lt;',   /* less-than sign */
-                        62 => '&gt;',   /* greater-than sign */
-                    ];
-
-                    if (isset($entityMap[$ord])) {
-                        return $entityMap[$ord];
-                    }
-
-                    return sprintf('&#x%02X;', $ord);
-                }
-
-                /*
-                 * Per OWASP recommendations, we'll use hex entities for any other
-                 * characters where a named entity does not exist.
-                 */
-                return sprintf('&#x%04X;', mb_ord($chr, 'UTF-8'));
-            }, $string);
-
-            if ('UTF-8' !== $charset) {
-                $string = iconv('UTF-8', $charset, $string);
-            }
-
-            return $string;
-
-        case 'url':
-            return rawurlencode($string);
-
-        default:
-            $escapers = $env->getExtension(EscaperExtension::class)->getEscapers();
-            if (array_key_exists($strategy, $escapers)) {
-                return $escapers[$strategy]($env, $string, $charset);
+    /**
+     * @internal
+     */
+    public static function escapeFilterIsSafe(Node $filterArgs)
+    {
+        foreach ($filterArgs as $arg) {
+            if ($arg instanceof ConstantExpression) {
+                return [$arg->getAttribute('value')];
             }
 
-            $validStrategies = implode(', ', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($escapers)));
-
-            throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
-    }
-}
-
-/**
- * @internal
- */
-function twig_escape_filter_is_safe(Node $filterArgs)
-{
-    foreach ($filterArgs as $arg) {
-        if ($arg instanceof ConstantExpression) {
-            return [$arg->getAttribute('value')];
+            return [];
         }
 
-        return [];
+        return ['html'];
     }
-
-    return ['html'];
-}
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/ExtensionInterface.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/ExtensionInterface.php
index 75fa237e..10a42b6b 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/ExtensionInterface.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/ExtensionInterface.php
@@ -11,6 +11,8 @@
 
 namespace Twig\Extension;
 
+use Twig\ExpressionParser;
+use Twig\Node\Expression\AbstractExpression;
 use Twig\NodeVisitor\NodeVisitorInterface;
 use Twig\TokenParser\TokenParserInterface;
 use Twig\TwigFilter;
@@ -63,6 +65,11 @@ interface ExtensionInterface
      * Returns a list of operators to add to the existing list.
      *
      * @return array<array> First array of unary operators, second array of binary operators
+     *
+     * @psalm-return array{
+     *     array<string, array{precedence: int, class: class-string<AbstractExpression>}>,
+     *     array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}>
+     * }
      */
     public function getOperators();
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/GlobalsInterface.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/GlobalsInterface.php
index ec0c6829..d52cd107 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/GlobalsInterface.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/GlobalsInterface.php
@@ -12,14 +12,14 @@
 namespace Twig\Extension;
 
 /**
- * Enables usage of the deprecated Twig\Extension\AbstractExtension::getGlobals() method.
- *
- * Explicitly implement this interface if you really need to implement the
- * deprecated getGlobals() method in your extensions.
+ * Allows Twig extensions to add globals to the context.
  *
  * @author Fabien Potencier <[email protected]>
  */
 interface GlobalsInterface
 {
+    /**
+     * @return array<string, mixed>
+     */
     public function getGlobals(): array;
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/OptimizerExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/OptimizerExtension.php
index 965bfdb0..d3fe46a6 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/OptimizerExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/OptimizerExtension.php
@@ -15,11 +15,9 @@ use Twig\NodeVisitor\OptimizerNodeVisitor;
 
 final class OptimizerExtension extends AbstractExtension
 {
-    private $optimizers;
-
-    public function __construct(int $optimizers = -1)
-    {
-        $this->optimizers = $optimizers;
+    public function __construct(
+        private int $optimizers = -1,
+    ) {
     }
 
     public function getNodeVisitors(): array
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/SandboxExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/SandboxExtension.php
index c861159b..4e96760f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/SandboxExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/SandboxExtension.php
@@ -15,6 +15,7 @@ use Twig\NodeVisitor\SandboxNodeVisitor;
 use Twig\Sandbox\SecurityNotAllowedMethodError;
 use Twig\Sandbox\SecurityNotAllowedPropertyError;
 use Twig\Sandbox\SecurityPolicyInterface;
+use Twig\Sandbox\SourcePolicyInterface;
 use Twig\Source;
 use Twig\TokenParser\SandboxTokenParser;
 
@@ -23,11 +24,13 @@ final class SandboxExtension extends AbstractExtension
     private $sandboxedGlobally;
     private $sandboxed;
     private $policy;
+    private $sourcePolicy;
 
-    public function __construct(SecurityPolicyInterface $policy, $sandboxed = false)
+    public function __construct(SecurityPolicyInterface $policy, $sandboxed = false, ?SourcePolicyInterface $sourcePolicy = null)
     {
         $this->policy = $policy;
         $this->sandboxedGlobally = $sandboxed;
+        $this->sourcePolicy = $sourcePolicy;
     }
 
     public function getTokenParsers(): array
@@ -50,9 +53,9 @@ final class SandboxExtension extends AbstractExtension
         $this->sandboxed = false;
     }
 
-    public function isSandboxed(): bool
+    public function isSandboxed(?Source $source = null): bool
     {
-        return $this->sandboxedGlobally || $this->sandboxed;
+        return $this->sandboxedGlobally || $this->sandboxed || $this->isSourceSandboxed($source);
     }
 
     public function isSandboxedGlobally(): bool
@@ -60,6 +63,15 @@ final class SandboxExtension extends AbstractExtension
         return $this->sandboxedGlobally;
     }
 
+    private function isSourceSandboxed(?Source $source): bool
+    {
+        if (null === $source || null === $this->sourcePolicy) {
+            return false;
+        }
+
+        return $this->sourcePolicy->enableSandbox($source);
+    }
+
     public function setSecurityPolicy(SecurityPolicyInterface $policy)
     {
         $this->policy = $policy;
@@ -70,16 +82,16 @@ final class SandboxExtension extends AbstractExtension
         return $this->policy;
     }
 
-    public function checkSecurity($tags, $filters, $functions): void
+    public function checkSecurity($tags, $filters, $functions, ?Source $source = null): void
     {
-        if ($this->isSandboxed()) {
+        if ($this->isSandboxed($source)) {
             $this->policy->checkSecurity($tags, $filters, $functions);
         }
     }
 
-    public function checkMethodAllowed($obj, $method, int $lineno = -1, Source $source = null): void
+    public function checkMethodAllowed($obj, $method, int $lineno = -1, ?Source $source = null): void
     {
-        if ($this->isSandboxed()) {
+        if ($this->isSandboxed($source)) {
             try {
                 $this->policy->checkMethodAllowed($obj, $method);
             } catch (SecurityNotAllowedMethodError $e) {
@@ -91,9 +103,9 @@ final class SandboxExtension extends AbstractExtension
         }
     }
 
-    public function checkPropertyAllowed($obj, $property, int $lineno = -1, Source $source = null): void
+    public function checkPropertyAllowed($obj, $property, int $lineno = -1, ?Source $source = null): void
     {
-        if ($this->isSandboxed()) {
+        if ($this->isSandboxed($source)) {
             try {
                 $this->policy->checkPropertyAllowed($obj, $property);
             } catch (SecurityNotAllowedPropertyError $e) {
@@ -105,9 +117,9 @@ final class SandboxExtension extends AbstractExtension
         }
     }
 
-    public function ensureToStringAllowed($obj, int $lineno = -1, Source $source = null)
+    public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source = null)
     {
-        if ($this->isSandboxed() && \is_object($obj) && method_exists($obj, '__toString')) {
+        if ($this->isSandboxed($source) && $obj instanceof \Stringable) {
             try {
                 $this->policy->checkMethodAllowed($obj, '__toString');
             } catch (SecurityNotAllowedMethodError $e) {
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/StagingExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/StagingExtension.php
index 0ea47f90..59db2ca7 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/StagingExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/StagingExtension.php
@@ -35,7 +35,7 @@ final class StagingExtension extends AbstractExtension
     public function addFunction(TwigFunction $function): void
     {
         if (isset($this->functions[$function->getName()])) {
-            throw new \LogicException(sprintf('Function "%s" is already registered.', $function->getName()));
+            throw new \LogicException(\sprintf('Function "%s" is already registered.', $function->getName()));
         }
 
         $this->functions[$function->getName()] = $function;
@@ -49,7 +49,7 @@ final class StagingExtension extends AbstractExtension
     public function addFilter(TwigFilter $filter): void
     {
         if (isset($this->filters[$filter->getName()])) {
-            throw new \LogicException(sprintf('Filter "%s" is already registered.', $filter->getName()));
+            throw new \LogicException(\sprintf('Filter "%s" is already registered.', $filter->getName()));
         }
 
         $this->filters[$filter->getName()] = $filter;
@@ -73,7 +73,7 @@ final class StagingExtension extends AbstractExtension
     public function addTokenParser(TokenParserInterface $parser): void
     {
         if (isset($this->tokenParsers[$parser->getTag()])) {
-            throw new \LogicException(sprintf('Tag "%s" is already registered.', $parser->getTag()));
+            throw new \LogicException(\sprintf('Tag "%s" is already registered.', $parser->getTag()));
         }
 
         $this->tokenParsers[$parser->getTag()] = $parser;
@@ -87,7 +87,7 @@ final class StagingExtension extends AbstractExtension
     public function addTest(TwigTest $test): void
     {
         if (isset($this->tests[$test->getName()])) {
-            throw new \LogicException(sprintf('Test "%s" is already registered.', $test->getName()));
+            throw new \LogicException(\sprintf('Test "%s" is already registered.', $test->getName()));
         }
 
         $this->tests[$test->getName()] = $test;
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/StringLoaderExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/StringLoaderExtension.php
index 7b451471..698d181f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Extension/StringLoaderExtension.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/StringLoaderExtension.php
@@ -9,7 +9,10 @@
  * file that was distributed with this source code.
  */
 
-namespace Twig\Extension {
+namespace Twig\Extension;
+
+use Twig\Environment;
+use Twig\TemplateWrapper;
 use Twig\TwigFunction;
 
 final class StringLoaderExtension extends AbstractExtension
@@ -17,26 +20,21 @@ final class StringLoaderExtension extends AbstractExtension
     public function getFunctions(): array
     {
         return [
-            new TwigFunction('template_from_string', 'twig_template_from_string', ['needs_environment' => true]),
+            new TwigFunction('template_from_string', [self::class, 'templateFromString'], ['needs_environment' => true]),
         ];
     }
-}
-}
-
-namespace {
-use Twig\Environment;
-use Twig\TemplateWrapper;
 
-/**
- * Loads a template from a string.
- *
- *     {{ include(template_from_string("Hello {{ name }}")) }}
- *
- * @param string $template A template as a string or object implementing __toString()
- * @param string $name     An optional name of the template to be used in error messages
- */
-function twig_template_from_string(Environment $env, $template, string $name = null): TemplateWrapper
-{
-    return $env->createTemplate((string) $template, $name);
-}
+    /**
+     * Loads a template from a string.
+     *
+     *     {{ include(template_from_string("Hello {{ name }}")) }}
+     *
+     * @param string|null $name An optional name of the template to be used in error messages
+     *
+     * @internal
+     */
+    public static function templateFromString(Environment $env, string|\Stringable $template, ?string $name = null): TemplateWrapper
+    {
+        return $env->createTemplate((string) $template, $name);
+    }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Extension/YieldNotReadyExtension.php b/data/web/inc/lib/vendor/twig/twig/src/Extension/YieldNotReadyExtension.php
new file mode 100644
index 00000000..49dfb808
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Extension/YieldNotReadyExtension.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Extension;
+
+use Twig\NodeVisitor\YieldNotReadyNodeVisitor;
+
+/**
+ * @internal to be removed in Twig 4
+ */
+final class YieldNotReadyExtension extends AbstractExtension
+{
+    public function __construct(
+        private bool $useYield,
+    ) {
+    }
+
+    public function getNodeVisitors(): array
+    {
+        return [new YieldNotReadyNodeVisitor($this->useYield)];
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/ExtensionSet.php b/data/web/inc/lib/vendor/twig/twig/src/ExtensionSet.php
index 36e5bbc5..28d57a41 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/ExtensionSet.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/ExtensionSet.php
@@ -15,6 +15,9 @@ use Twig\Error\RuntimeError;
 use Twig\Extension\ExtensionInterface;
 use Twig\Extension\GlobalsInterface;
 use Twig\Extension\StagingExtension;
+use Twig\Node\Expression\AbstractExpression;
+use Twig\Node\Expression\Binary\AbstractBinary;
+use Twig\Node\Expression\Unary\AbstractUnary;
 use Twig\NodeVisitor\NodeVisitorInterface;
 use Twig\TokenParser\TokenParserInterface;
 
@@ -31,11 +34,23 @@ final class ExtensionSet
     private $staging;
     private $parsers;
     private $visitors;
+    /** @var array<string, TwigFilter> */
     private $filters;
+    /** @var array<string, TwigFilter> */
+    private $dynamicFilters;
+    /** @var array<string, TwigTest> */
     private $tests;
+    /** @var array<string, TwigTest> */
+    private $dynamicTests;
+    /** @var array<string, TwigFunction> */
     private $functions;
+    /** @var array<string, TwigFunction> */
+    private $dynamicFunctions;
+    /** @var array<string, array{precedence: int, class: class-string<AbstractExpression>}> */
     private $unaryOperators;
+    /** @var array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}> */
     private $binaryOperators;
+    /** @var array<string, mixed> */
     private $globals;
     private $functionCallbacks = [];
     private $filterCallbacks = [];
@@ -62,7 +77,7 @@ final class ExtensionSet
         $class = ltrim($class, '\\');
 
         if (!isset($this->extensions[$class])) {
-            throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class));
+            throw new RuntimeError(\sprintf('The "%s" extension is not enabled.', $class));
         }
 
         return $this->extensions[$class];
@@ -117,11 +132,11 @@ final class ExtensionSet
         $class = \get_class($extension);
 
         if ($this->initialized) {
-            throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
+            throw new \LogicException(\sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
         }
 
         if (isset($this->extensions[$class])) {
-            throw new \LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class));
+            throw new \LogicException(\sprintf('Unable to register extension "%s" as it is already registered.', $class));
         }
 
         $this->extensions[$class] = $extension;
@@ -130,7 +145,7 @@ final class ExtensionSet
     public function addFunction(TwigFunction $function): void
     {
         if ($this->initialized) {
-            throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
+            throw new \LogicException(\sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
         }
 
         $this->staging->addFunction($function);
@@ -158,14 +173,11 @@ final class ExtensionSet
             return $this->functions[$name];
         }
 
-        foreach ($this->functions as $pattern => $function) {
-            $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
-
-            if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
+        foreach ($this->dynamicFunctions as $pattern => $function) {
+            if (preg_match($pattern, $name, $matches)) {
                 array_shift($matches);
-                $function->setArguments($matches);
 
-                return $function;
+                return $function->withDynamicArguments($name, $function->getName(), $matches);
             }
         }
 
@@ -186,7 +198,7 @@ final class ExtensionSet
     public function addFilter(TwigFilter $filter): void
     {
         if ($this->initialized) {
-            throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
+            throw new \LogicException(\sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
         }
 
         $this->staging->addFilter($filter);
@@ -214,14 +226,11 @@ final class ExtensionSet
             return $this->filters[$name];
         }
 
-        foreach ($this->filters as $pattern => $filter) {
-            $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
-
-            if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) {
+        foreach ($this->dynamicFilters as $pattern => $filter) {
+            if (preg_match($pattern, $name, $matches)) {
                 array_shift($matches);
-                $filter->setArguments($matches);
 
-                return $filter;
+                return $filter->withDynamicArguments($name, $filter->getName(), $matches);
             }
         }
 
@@ -305,6 +314,9 @@ final class ExtensionSet
         $this->parserCallbacks[] = $callable;
     }
 
+    /**
+     * @return array<string, mixed>
+     */
     public function getGlobals(): array
     {
         if (null !== $this->globals) {
@@ -317,12 +329,7 @@ final class ExtensionSet
                 continue;
             }
 
-            $extGlobals = $extension->getGlobals();
-            if (!\is_array($extGlobals)) {
-                throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension)));
-            }
-
-            $globals = array_merge($globals, $extGlobals);
+            $globals = array_merge($globals, $extension->getGlobals());
         }
 
         if ($this->initialized) {
@@ -332,10 +339,15 @@ final class ExtensionSet
         return $globals;
     }
 
+    public function resetGlobals(): void
+    {
+        $this->globals = null;
+    }
+
     public function addTest(TwigTest $test): void
     {
         if ($this->initialized) {
-            throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
+            throw new \LogicException(\sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
         }
 
         $this->staging->addTest($test);
@@ -363,22 +375,20 @@ final class ExtensionSet
             return $this->tests[$name];
         }
 
-        foreach ($this->tests as $pattern => $test) {
-            $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
-
-            if ($count) {
-                if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
-                    array_shift($matches);
-                    $test->setArguments($matches);
+        foreach ($this->dynamicTests as $pattern => $test) {
+            if (preg_match($pattern, $name, $matches)) {
+                array_shift($matches);
 
-                    return $test;
-                }
+                return $test->withDynamicArguments($name, $test->getName(), $matches);
             }
         }
 
         return null;
     }
 
+    /**
+     * @return array<string, array{precedence: int, class: class-string<AbstractExpression>}>
+     */
     public function getUnaryOperators(): array
     {
         if (!$this->initialized) {
@@ -388,6 +398,9 @@ final class ExtensionSet
         return $this->unaryOperators;
     }
 
+    /**
+     * @return array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}>
+     */
     public function getBinaryOperators(): array
     {
         if (!$this->initialized) {
@@ -403,6 +416,9 @@ final class ExtensionSet
         $this->filters = [];
         $this->functions = [];
         $this->tests = [];
+        $this->dynamicFilters = [];
+        $this->dynamicFunctions = [];
+        $this->dynamicTests = [];
         $this->visitors = [];
         $this->unaryOperators = [];
         $this->binaryOperators = [];
@@ -419,17 +435,26 @@ final class ExtensionSet
     {
         // filters
         foreach ($extension->getFilters() as $filter) {
-            $this->filters[$filter->getName()] = $filter;
+            $this->filters[$name = $filter->getName()] = $filter;
+            if (str_contains($name, '*')) {
+                $this->dynamicFilters['#^'.str_replace('\\*', '(.*?)', preg_quote($name, '#')).'$#'] = $filter;
+            }
         }
 
         // functions
         foreach ($extension->getFunctions() as $function) {
-            $this->functions[$function->getName()] = $function;
+            $this->functions[$name = $function->getName()] = $function;
+            if (str_contains($name, '*')) {
+                $this->dynamicFunctions['#^'.str_replace('\\*', '(.*?)', preg_quote($name, '#')).'$#'] = $function;
+            }
         }
 
         // tests
         foreach ($extension->getTests() as $test) {
-            $this->tests[$test->getName()] = $test;
+            $this->tests[$name = $test->getName()] = $test;
+            if (str_contains($name, '*')) {
+                $this->dynamicTests['#^'.str_replace('\\*', '(.*?)', preg_quote($name, '#')).'$#'] = $test;
+            }
         }
 
         // token parsers
@@ -449,11 +474,11 @@ final class ExtensionSet
         // operators
         if ($operators = $extension->getOperators()) {
             if (!\is_array($operators)) {
-                throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators)));
+                throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators)));
             }
 
             if (2 !== \count($operators)) {
-                throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
+                throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
             }
 
             $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
diff --git a/data/web/inc/lib/vendor/twig/twig/src/FileExtensionEscapingStrategy.php b/data/web/inc/lib/vendor/twig/twig/src/FileExtensionEscapingStrategy.php
index 65198bbb..812071bf 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/FileExtensionEscapingStrategy.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/FileExtensionEscapingStrategy.php
@@ -37,7 +37,7 @@ class FileExtensionEscapingStrategy
             return 'html'; // return html for directories
         }
 
-        if ('.twig' === substr($name, -5)) {
+        if (str_ends_with($name, '.twig')) {
             $name = substr($name, 0, -5);
         }
 
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Lexer.php b/data/web/inc/lib/vendor/twig/twig/src/Lexer.php
index 9ff028c8..28feaa2c 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Lexer.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Lexer.php
@@ -19,6 +19,8 @@ use Twig\Error\SyntaxError;
  */
 class Lexer
 {
+    private $isInitialized = false;
+
     private $tokens;
     private $code;
     private $cursor;
@@ -48,6 +50,14 @@ class Lexer
     public const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
     public const PUNCTUATION = '()[]{}?:.,|';
 
+    private const SPECIAL_CHARS = [
+        'f' => "\f",
+        'n' => "\n",
+        'r' => "\r",
+        't' => "\t",
+        'v' => "\v",
+    ];
+
     public function __construct(Environment $env, array $options = [])
     {
         $this->env = $env;
@@ -61,6 +71,13 @@ class Lexer
             'whitespace_line_chars' => ' \t\0\x0B',
             'interpolation' => ['#{', '}'],
         ], $options);
+    }
+
+    private function initialize()
+    {
+        if ($this->isInitialized) {
+            return;
+        }
 
         // when PHP 7.3 is the min version, we will be able to remove the '#' part in preg_quote as it's part of the default
         $this->regexes = [
@@ -149,10 +166,14 @@ class Lexer
             'interpolation_start' => '{'.preg_quote($this->options['interpolation'][0], '#').'\s*}A',
             'interpolation_end' => '{\s*'.preg_quote($this->options['interpolation'][1], '#').'}A',
         ];
+
+        $this->isInitialized = true;
     }
 
     public function tokenize(Source $source): TokenStream
     {
+        $this->initialize();
+
         $this->source = $source;
         $this->code = str_replace(["\r\n", "\r"], "\n", $source->getCode());
         $this->cursor = 0;
@@ -194,11 +215,11 @@ class Lexer
             }
         }
 
-        $this->pushToken(/* Token::EOF_TYPE */ -1);
+        $this->pushToken(Token::EOF_TYPE);
 
         if (!empty($this->brackets)) {
-            list($expect, $lineno) = array_pop($this->brackets);
-            throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
+            [$expect, $lineno] = array_pop($this->brackets);
+            throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
         }
 
         return new TokenStream($this->tokens, $this->source);
@@ -208,7 +229,7 @@ class Lexer
     {
         // if no matches are left we return the rest of the template as simple text token
         if ($this->position == \count($this->positions[0]) - 1) {
-            $this->pushToken(/* Token::TEXT_TYPE */ 0, substr($this->code, $this->cursor));
+            $this->pushToken(Token::TEXT_TYPE, substr($this->code, $this->cursor));
             $this->cursor = $this->end;
 
             return;
@@ -237,7 +258,7 @@ class Lexer
                 $text = rtrim($text, " \t\0\x0B");
             }
         }
-        $this->pushToken(/* Token::TEXT_TYPE */ 0, $text);
+        $this->pushToken(Token::TEXT_TYPE, $text);
         $this->moveCursor($textContent.$position[0]);
 
         switch ($this->positions[1][$this->position][0]) {
@@ -255,14 +276,14 @@ class Lexer
                     $this->moveCursor($match[0]);
                     $this->lineno = (int) $match[1];
                 } else {
-                    $this->pushToken(/* Token::BLOCK_START_TYPE */ 1);
+                    $this->pushToken(Token::BLOCK_START_TYPE);
                     $this->pushState(self::STATE_BLOCK);
                     $this->currentVarBlockLine = $this->lineno;
                 }
                 break;
 
             case $this->options['tag_variable'][0]:
-                $this->pushToken(/* Token::VAR_START_TYPE */ 2);
+                $this->pushToken(Token::VAR_START_TYPE);
                 $this->pushState(self::STATE_VAR);
                 $this->currentVarBlockLine = $this->lineno;
                 break;
@@ -272,7 +293,7 @@ class Lexer
     private function lexBlock(): void
     {
         if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, 0, $this->cursor)) {
-            $this->pushToken(/* Token::BLOCK_END_TYPE */ 3);
+            $this->pushToken(Token::BLOCK_END_TYPE);
             $this->moveCursor($match[0]);
             $this->popState();
         } else {
@@ -283,7 +304,7 @@ class Lexer
     private function lexVar(): void
     {
         if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, 0, $this->cursor)) {
-            $this->pushToken(/* Token::VAR_END_TYPE */ 4);
+            $this->pushToken(Token::VAR_END_TYPE);
             $this->moveCursor($match[0]);
             $this->popState();
         } else {
@@ -298,23 +319,28 @@ class Lexer
             $this->moveCursor($match[0]);
 
             if ($this->cursor >= $this->end) {
-                throw new SyntaxError(sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
+                throw new SyntaxError(\sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source);
             }
         }
 
+        // spread operator
+        if ('.' === $this->code[$this->cursor] && ($this->cursor + 2 < $this->end) && '.' === $this->code[$this->cursor + 1] && '.' === $this->code[$this->cursor + 2]) {
+            $this->pushToken(Token::SPREAD_TYPE, '...');
+            $this->moveCursor('...');
+        }
         // arrow function
-        if ('=' === $this->code[$this->cursor] && '>' === $this->code[$this->cursor + 1]) {
+        elseif ('=' === $this->code[$this->cursor] && ($this->cursor + 1 < $this->end) && '>' === $this->code[$this->cursor + 1]) {
             $this->pushToken(Token::ARROW_TYPE, '=>');
             $this->moveCursor('=>');
         }
         // operators
         elseif (preg_match($this->regexes['operator'], $this->code, $match, 0, $this->cursor)) {
-            $this->pushToken(/* Token::OPERATOR_TYPE */ 8, preg_replace('/\s+/', ' ', $match[0]));
+            $this->pushToken(Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
             $this->moveCursor($match[0]);
         }
         // names
         elseif (preg_match(self::REGEX_NAME, $this->code, $match, 0, $this->cursor)) {
-            $this->pushToken(/* Token::NAME_TYPE */ 5, $match[0]);
+            $this->pushToken(Token::NAME_TYPE, $match[0]);
             $this->moveCursor($match[0]);
         }
         // numbers
@@ -323,33 +349,33 @@ class Lexer
             if (ctype_digit($match[0]) && $number <= \PHP_INT_MAX) {
                 $number = (int) $match[0]; // integers lower than the maximum
             }
-            $this->pushToken(/* Token::NUMBER_TYPE */ 6, $number);
+            $this->pushToken(Token::NUMBER_TYPE, $number);
             $this->moveCursor($match[0]);
         }
         // punctuation
-        elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
+        elseif (str_contains(self::PUNCTUATION, $this->code[$this->cursor])) {
             // opening bracket
-            if (false !== strpos('([{', $this->code[$this->cursor])) {
+            if (str_contains('([{', $this->code[$this->cursor])) {
                 $this->brackets[] = [$this->code[$this->cursor], $this->lineno];
             }
             // closing bracket
-            elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
+            elseif (str_contains(')]}', $this->code[$this->cursor])) {
                 if (empty($this->brackets)) {
-                    throw new SyntaxError(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
+                    throw new SyntaxError(\sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
                 }
 
-                list($expect, $lineno) = array_pop($this->brackets);
+                [$expect, $lineno] = array_pop($this->brackets);
                 if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
-                    throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
+                    throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
                 }
             }
 
-            $this->pushToken(/* Token::PUNCTUATION_TYPE */ 9, $this->code[$this->cursor]);
+            $this->pushToken(Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
             ++$this->cursor;
         }
         // strings
         elseif (preg_match(self::REGEX_STRING, $this->code, $match, 0, $this->cursor)) {
-            $this->pushToken(/* Token::STRING_TYPE */ 7, stripcslashes(substr($match[0], 1, -1)));
+            $this->pushToken(Token::STRING_TYPE, $this->stripcslashes(substr($match[0], 1, -1), substr($match[0], 0, 1)));
             $this->moveCursor($match[0]);
         }
         // opening double quoted string
@@ -360,8 +386,65 @@ class Lexer
         }
         // unlexable
         else {
-            throw new SyntaxError(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
+            throw new SyntaxError(\sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
+        }
+    }
+
+    private function stripcslashes(string $str, string $quoteType): string
+    {
+        $result = '';
+        $length = \strlen($str);
+
+        $i = 0;
+        while ($i < $length) {
+            if (false === $pos = strpos($str, '\\', $i)) {
+                $result .= substr($str, $i);
+                break;
+            }
+
+            $result .= substr($str, $i, $pos - $i);
+            $i = $pos + 1;
+
+            if ($i >= $length) {
+                $result .= '\\';
+                break;
+            }
+
+            $nextChar = $str[$i];
+
+            if (isset(self::SPECIAL_CHARS[$nextChar])) {
+                $result .= self::SPECIAL_CHARS[$nextChar];
+            } elseif ('\\' === $nextChar) {
+                $result .= $nextChar;
+            } elseif ("'" === $nextChar || '"' === $nextChar) {
+                if ($nextChar !== $quoteType) {
+                    trigger_deprecation('twig/twig', '3.12', 'Character "%s" at position %d should not be escaped; the "\" character is ignored in Twig v3 but will not be in v4. Please remove the extra "\" character.', $nextChar, $i + 1);
+                }
+                $result .= $nextChar;
+            } elseif ('#' === $nextChar && $i + 1 < $length && '{' === $str[$i + 1]) {
+                $result .= '#{';
+                ++$i;
+            } elseif ('x' === $nextChar && $i + 1 < $length && ctype_xdigit($str[$i + 1])) {
+                $hex = $str[++$i];
+                if ($i + 1 < $length && ctype_xdigit($str[$i + 1])) {
+                    $hex .= $str[++$i];
+                }
+                $result .= \chr(hexdec($hex));
+            } elseif (ctype_digit($nextChar) && $nextChar < '8') {
+                $octal = $nextChar;
+                while ($i + 1 < $length && ctype_digit($str[$i + 1]) && $str[$i + 1] < '8' && \strlen($octal) < 3) {
+                    $octal .= $str[++$i];
+                }
+                $result .= \chr(octdec($octal));
+            } else {
+                trigger_deprecation('twig/twig', '3.12', 'Character "%s" at position %d should not be escaped; the "\" character is ignored in Twig v3 but will not be in v4. Please remove the extra "\" character.', $nextChar, $i + 1);
+                $result .= $nextChar;
+            }
+
+            ++$i;
         }
+
+        return $result;
     }
 
     private function lexRawData(): void
@@ -385,7 +468,7 @@ class Lexer
             }
         }
 
-        $this->pushToken(/* Token::TEXT_TYPE */ 0, $text);
+        $this->pushToken(Token::TEXT_TYPE, $text);
     }
 
     private function lexComment(): void
@@ -401,23 +484,23 @@ class Lexer
     {
         if (preg_match($this->regexes['interpolation_start'], $this->code, $match, 0, $this->cursor)) {
             $this->brackets[] = [$this->options['interpolation'][0], $this->lineno];
-            $this->pushToken(/* Token::INTERPOLATION_START_TYPE */ 10);
+            $this->pushToken(Token::INTERPOLATION_START_TYPE);
             $this->moveCursor($match[0]);
             $this->pushState(self::STATE_INTERPOLATION);
-        } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, 0, $this->cursor) && \strlen($match[0]) > 0) {
-            $this->pushToken(/* Token::STRING_TYPE */ 7, stripcslashes($match[0]));
+        } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, 0, $this->cursor) && '' !== $match[0]) {
+            $this->pushToken(Token::STRING_TYPE, $this->stripcslashes($match[0], '"'));
             $this->moveCursor($match[0]);
         } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, 0, $this->cursor)) {
-            list($expect, $lineno) = array_pop($this->brackets);
+            [$expect, $lineno] = array_pop($this->brackets);
             if ('"' != $this->code[$this->cursor]) {
-                throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
+                throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source);
             }
 
             $this->popState();
             ++$this->cursor;
         } else {
             // unlexable
-            throw new SyntaxError(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
+            throw new SyntaxError(\sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source);
         }
     }
 
@@ -426,7 +509,7 @@ class Lexer
         $bracket = end($this->brackets);
         if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, 0, $this->cursor)) {
             array_pop($this->brackets);
-            $this->pushToken(/* Token::INTERPOLATION_END_TYPE */ 11);
+            $this->pushToken(Token::INTERPOLATION_END_TYPE);
             $this->moveCursor($match[0]);
             $this->popState();
         } else {
@@ -437,7 +520,7 @@ class Lexer
     private function pushToken($type, $value = ''): void
     {
         // do not push empty text tokens
-        if (/* Token::TEXT_TYPE */ 0 === $type && '' === $value) {
+        if (Token::TEXT_TYPE === $type && '' === $value) {
             return;
         }
 
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Loader/ArrayLoader.php b/data/web/inc/lib/vendor/twig/twig/src/Loader/ArrayLoader.php
index 5d726c35..2bb54b7a 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Loader/ArrayLoader.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Loader/ArrayLoader.php
@@ -28,14 +28,12 @@ use Twig\Source;
  */
 final class ArrayLoader implements LoaderInterface
 {
-    private $templates = [];
-
     /**
      * @param array $templates An array of templates (keys are the names, and values are the source code)
      */
-    public function __construct(array $templates = [])
-    {
-        $this->templates = $templates;
+    public function __construct(
+        private array $templates = [],
+    ) {
     }
 
     public function setTemplate(string $name, string $template): void
@@ -46,7 +44,7 @@ final class ArrayLoader implements LoaderInterface
     public function getSourceContext(string $name): Source
     {
         if (!isset($this->templates[$name])) {
-            throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
+            throw new LoaderError(\sprintf('Template "%s" is not defined.', $name));
         }
 
         return new Source($this->templates[$name], $name);
@@ -60,7 +58,7 @@ final class ArrayLoader implements LoaderInterface
     public function getCacheKey(string $name): string
     {
         if (!isset($this->templates[$name])) {
-            throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
+            throw new LoaderError(\sprintf('Template "%s" is not defined.', $name));
         }
 
         return $name.':'.$this->templates[$name];
@@ -69,7 +67,7 @@ final class ArrayLoader implements LoaderInterface
     public function isFresh(string $name, int $time): bool
     {
         if (!isset($this->templates[$name])) {
-            throw new LoaderError(sprintf('Template "%s" is not defined.', $name));
+            throw new LoaderError(\sprintf('Template "%s" is not defined.', $name));
         }
 
         return true;
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Loader/ChainLoader.php b/data/web/inc/lib/vendor/twig/twig/src/Loader/ChainLoader.php
index fbf4f3a0..6e4f9511 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Loader/ChainLoader.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Loader/ChainLoader.php
@@ -21,22 +21,28 @@ use Twig\Source;
  */
 final class ChainLoader implements LoaderInterface
 {
+    /**
+     * @var array<string, bool>
+     */
     private $hasSourceCache = [];
-    private $loaders = [];
 
     /**
-     * @param LoaderInterface[] $loaders
+     * @param iterable<LoaderInterface> $loaders
      */
-    public function __construct(array $loaders = [])
-    {
-        foreach ($loaders as $loader) {
-            $this->addLoader($loader);
-        }
+    public function __construct(
+        private iterable $loaders = [],
+    ) {
     }
 
     public function addLoader(LoaderInterface $loader): void
     {
-        $this->loaders[] = $loader;
+        $current = $this->loaders;
+
+        $this->loaders = (static function () use ($current, $loader): \Generator {
+            yield from $current;
+            yield $loader;
+        })();
+
         $this->hasSourceCache = [];
     }
 
@@ -45,13 +51,18 @@ final class ChainLoader implements LoaderInterface
      */
     public function getLoaders(): array
     {
+        if (!\is_array($this->loaders)) {
+            $this->loaders = iterator_to_array($this->loaders, false);
+        }
+
         return $this->loaders;
     }
 
     public function getSourceContext(string $name): Source
     {
         $exceptions = [];
-        foreach ($this->loaders as $loader) {
+
+        foreach ($this->getLoaders() as $loader) {
             if (!$loader->exists($name)) {
                 continue;
             }
@@ -63,7 +74,7 @@ final class ChainLoader implements LoaderInterface
             }
         }
 
-        throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
+        throw new LoaderError(\sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
     }
 
     public function exists(string $name): bool
@@ -72,7 +83,7 @@ final class ChainLoader implements LoaderInterface
             return $this->hasSourceCache[$name];
         }
 
-        foreach ($this->loaders as $loader) {
+        foreach ($this->getLoaders() as $loader) {
             if ($loader->exists($name)) {
                 return $this->hasSourceCache[$name] = true;
             }
@@ -84,7 +95,8 @@ final class ChainLoader implements LoaderInterface
     public function getCacheKey(string $name): string
     {
         $exceptions = [];
-        foreach ($this->loaders as $loader) {
+
+        foreach ($this->getLoaders() as $loader) {
             if (!$loader->exists($name)) {
                 continue;
             }
@@ -96,13 +108,14 @@ final class ChainLoader implements LoaderInterface
             }
         }
 
-        throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
+        throw new LoaderError(\sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
     }
 
     public function isFresh(string $name, int $time): bool
     {
         $exceptions = [];
-        foreach ($this->loaders as $loader) {
+
+        foreach ($this->getLoaders() as $loader) {
             if (!$loader->exists($name)) {
                 continue;
             }
@@ -114,6 +127,6 @@ final class ChainLoader implements LoaderInterface
             }
         }
 
-        throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
+        throw new LoaderError(\sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : ''));
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Loader/FilesystemLoader.php b/data/web/inc/lib/vendor/twig/twig/src/Loader/FilesystemLoader.php
index 62267a11..c60964f5 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Loader/FilesystemLoader.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Loader/FilesystemLoader.php
@@ -34,9 +34,9 @@ class FilesystemLoader implements LoaderInterface
      * @param string|array $paths    A path or an array of paths where to look for templates
      * @param string|null  $rootPath The root path common to all relative paths (null for getcwd())
      */
-    public function __construct($paths = [], string $rootPath = null)
+    public function __construct($paths = [], ?string $rootPath = null)
     {
-        $this->rootPath = (null === $rootPath ? getcwd() : $rootPath).\DIRECTORY_SEPARATOR;
+        $this->rootPath = ($rootPath ?? getcwd()).\DIRECTORY_SEPARATOR;
         if (null !== $rootPath && false !== ($realPath = realpath($rootPath))) {
             $this->rootPath = $realPath.\DIRECTORY_SEPARATOR;
         }
@@ -89,7 +89,7 @@ class FilesystemLoader implements LoaderInterface
 
         $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
         if (!is_dir($checkPath)) {
-            throw new LoaderError(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
+            throw new LoaderError(\sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
         }
 
         $this->paths[$namespace][] = rtrim($path, '/\\');
@@ -105,7 +105,7 @@ class FilesystemLoader implements LoaderInterface
 
         $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path;
         if (!is_dir($checkPath)) {
-            throw new LoaderError(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
+            throw new LoaderError(\sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath));
         }
 
         $path = rtrim($path, '/\\');
@@ -183,7 +183,7 @@ class FilesystemLoader implements LoaderInterface
         }
 
         try {
-            list($namespace, $shortname) = $this->parseName($name);
+            [$namespace, $shortname] = $this->parseName($name);
 
             $this->validateName($shortname);
         } catch (LoaderError $e) {
@@ -195,7 +195,7 @@ class FilesystemLoader implements LoaderInterface
         }
 
         if (!isset($this->paths[$namespace])) {
-            $this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
+            $this->errorCache[$name] = \sprintf('There are no registered paths for namespace "%s".', $namespace);
 
             if (!$throw) {
                 return null;
@@ -218,7 +218,7 @@ class FilesystemLoader implements LoaderInterface
             }
         }
 
-        $this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
+        $this->errorCache[$name] = \sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]));
 
         if (!$throw) {
             return null;
@@ -236,7 +236,7 @@ class FilesystemLoader implements LoaderInterface
     {
         if (isset($name[0]) && '@' == $name[0]) {
             if (false === $pos = strpos($name, '/')) {
-                throw new LoaderError(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
+                throw new LoaderError(\sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
             }
 
             $namespace = substr($name, 1, $pos - 1);
@@ -250,7 +250,7 @@ class FilesystemLoader implements LoaderInterface
 
     private function validateName(string $name): void
     {
-        if (false !== strpos($name, "\0")) {
+        if (str_contains($name, "\0")) {
             throw new LoaderError('A template name cannot contain NUL bytes.');
         }
 
@@ -265,7 +265,7 @@ class FilesystemLoader implements LoaderInterface
             }
 
             if ($level < 0) {
-                throw new LoaderError(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
+                throw new LoaderError(\sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
             }
         }
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Markup.php b/data/web/inc/lib/vendor/twig/twig/src/Markup.php
index 1788acc4..4fae779e 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Markup.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Markup.php
@@ -16,10 +16,10 @@ namespace Twig;
  *
  * @author Fabien Potencier <[email protected]>
  */
-class Markup implements \Countable, \JsonSerializable
+class Markup implements \Countable, \JsonSerializable, \Stringable
 {
     private $content;
-    private $charset;
+    private ?string $charset;
 
     public function __construct($content, $charset)
     {
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/AutoEscapeNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/AutoEscapeNode.php
index cd970411..ee806396 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/AutoEscapeNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/AutoEscapeNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -24,11 +25,12 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class AutoEscapeNode extends Node
 {
-    public function __construct($value, Node $body, int $lineno, string $tag = 'autoescape')
+    public function __construct($value, Node $body, int $lineno)
     {
-        parent::__construct(['body' => $body], ['value' => $value], $lineno, $tag);
+        parent::__construct(['body' => $body], ['value' => $value], $lineno);
     }
 
     public function compile(Compiler $compiler): void
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/BlockNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/BlockNode.php
index 0632ba74..b4f939cf 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/BlockNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/BlockNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -19,24 +20,29 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class BlockNode extends Node
 {
-    public function __construct(string $name, Node $body, int $lineno, string $tag = null)
+    public function __construct(string $name, Node $body, int $lineno)
     {
-        parent::__construct(['body' => $body], ['name' => $name], $lineno, $tag);
+        parent::__construct(['body' => $body], ['name' => $name], $lineno);
     }
 
     public function compile(Compiler $compiler): void
     {
         $compiler
             ->addDebugInfo($this)
-            ->write(sprintf("public function block_%s(\$context, array \$blocks = [])\n", $this->getAttribute('name')), "{\n")
+            ->write("/**\n")
+            ->write(" * @return iterable<null|scalar|\Stringable>\n")
+            ->write(" */\n")
+            ->write(\sprintf("public function block_%s(array \$context, array \$blocks = []): iterable\n", $this->getAttribute('name')), "{\n")
             ->indent()
             ->write("\$macros = \$this->macros;\n")
         ;
 
         $compiler
             ->subcompile($this->getNode('body'))
+            ->write("yield from [];\n")
             ->outdent()
             ->write("}\n\n")
         ;
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/BlockReferenceNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/BlockReferenceNode.php
index cc8af5b5..7c313a04 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/BlockReferenceNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/BlockReferenceNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -19,18 +20,19 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class BlockReferenceNode extends Node implements NodeOutputInterface
 {
-    public function __construct(string $name, int $lineno, string $tag = null)
+    public function __construct(string $name, int $lineno)
     {
-        parent::__construct([], ['name' => $name], $lineno, $tag);
+        parent::__construct([], ['name' => $name], $lineno);
     }
 
     public function compile(Compiler $compiler): void
     {
         $compiler
             ->addDebugInfo($this)
-            ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
+            ->write(\sprintf("yield from \$this->unwrap()->yieldBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
         ;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/BodyNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/BodyNode.php
index 041cbf68..08115b3b 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/BodyNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/BodyNode.php
@@ -11,11 +11,14 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
+
 /**
  * Represents a body node.
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class BodyNode extends Node
 {
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/CaptureNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/CaptureNode.php
new file mode 100644
index 00000000..3b7f0b6d
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/CaptureNode.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Node;
+
+use Twig\Attribute\YieldReady;
+use Twig\Compiler;
+
+/**
+ * Represents a node for which we need to capture the output.
+ *
+ * @author Fabien Potencier <[email protected]>
+ */
+#[YieldReady]
+class CaptureNode extends Node
+{
+    public function __construct(Node $body, int $lineno)
+    {
+        parent::__construct(['body' => $body], ['raw' => false], $lineno);
+    }
+
+    public function compile(Compiler $compiler): void
+    {
+        $useYield = $compiler->getEnvironment()->useYield();
+
+        if (!$this->getAttribute('raw')) {
+            $compiler->raw("('' === \$tmp = ");
+        }
+        $compiler
+            ->raw($useYield ? "implode('', iterator_to_array(" : '\\Twig\\Extension\\CoreExtension::captureOutput(')
+            ->raw("(function () use (&\$context, \$macros, \$blocks) {\n")
+            ->indent()
+            ->subcompile($this->getNode('body'))
+            ->write("yield from [];\n")
+            ->outdent()
+            ->write('})()')
+        ;
+        if ($useYield) {
+            $compiler->raw(', false))');
+        } else {
+            $compiler->raw(')');
+        }
+        if (!$this->getAttribute('raw')) {
+            $compiler->raw(") ? '' : new Markup(\$tmp, \$this->env->getCharset());");
+        } else {
+            $compiler->raw(';');
+        }
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityCallNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityCallNode.php
index a78a38d8..9c162d12 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityCallNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityCallNode.php
@@ -11,17 +11,19 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class CheckSecurityCallNode extends Node
 {
     public function compile(Compiler $compiler)
     {
         $compiler
-            ->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n")
+            ->write("\$this->sandbox = \$this->extensions[SandboxExtension::class];\n")
             ->write("\$this->checkSecurity();\n")
         ;
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityNode.php
index 47273279..6e591aad 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/CheckSecurityNode.php
@@ -11,17 +11,24 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class CheckSecurityNode extends Node
 {
     private $usedFilters;
     private $usedTags;
     private $usedFunctions;
 
+    /**
+     * @param array<string, int> $usedFilters
+     * @param array<string, int> $usedTags
+     * @param array<string, int> $usedFunctions
+     */
     public function __construct(array $usedFilters, array $usedTags, array $usedFunctions)
     {
         $this->usedFilters = $usedFilters;
@@ -33,32 +40,22 @@ class CheckSecurityNode extends Node
 
     public function compile(Compiler $compiler): void
     {
-        $tags = $filters = $functions = [];
-        foreach (['tags', 'filters', 'functions'] as $type) {
-            foreach ($this->{'used'.ucfirst($type)} as $name => $node) {
-                if ($node instanceof Node) {
-                    ${$type}[$name] = $node->getTemplateLine();
-                } else {
-                    ${$type}[$node] = null;
-                }
-            }
-        }
-
         $compiler
             ->write("\n")
             ->write("public function checkSecurity()\n")
             ->write("{\n")
             ->indent()
-            ->write('static $tags = ')->repr(array_filter($tags))->raw(";\n")
-            ->write('static $filters = ')->repr(array_filter($filters))->raw(";\n")
-            ->write('static $functions = ')->repr(array_filter($functions))->raw(";\n\n")
+            ->write('static $tags = ')->repr(array_filter($this->usedTags))->raw(";\n")
+            ->write('static $filters = ')->repr(array_filter($this->usedFilters))->raw(";\n")
+            ->write('static $functions = ')->repr(array_filter($this->usedFunctions))->raw(";\n\n")
             ->write("try {\n")
             ->indent()
             ->write("\$this->sandbox->checkSecurity(\n")
             ->indent()
-            ->write(!$tags ? "[],\n" : "['".implode("', '", array_keys($tags))."'],\n")
-            ->write(!$filters ? "[],\n" : "['".implode("', '", array_keys($filters))."'],\n")
-            ->write(!$functions ? "[]\n" : "['".implode("', '", array_keys($functions))."']\n")
+            ->write(!$this->usedTags ? "[],\n" : "['".implode("', '", array_keys($this->usedTags))."'],\n")
+            ->write(!$this->usedFilters ? "[],\n" : "['".implode("', '", array_keys($this->usedFilters))."'],\n")
+            ->write(!$this->usedFunctions ? "[],\n" : "['".implode("', '", array_keys($this->usedFunctions))."'],\n")
+            ->write("\$this->source\n")
             ->outdent()
             ->write(");\n")
             ->outdent()
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/CheckToStringNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/CheckToStringNode.php
index c7a9d698..937240c1 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/CheckToStringNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/CheckToStringNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 
@@ -24,11 +25,12 @@ use Twig\Node\Expression\AbstractExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class CheckToStringNode extends AbstractExpression
 {
     public function __construct(AbstractExpression $expr)
     {
-        parent::__construct(['expr' => $expr], [], $expr->getTemplateLine(), $expr->getNodeTag());
+        parent::__construct(['expr' => $expr], [], $expr->getTemplateLine());
     }
 
     public function compile(Compiler $compiler): void
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/DeprecatedNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/DeprecatedNode.php
index 5ff44307..0772adfc 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/DeprecatedNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/DeprecatedNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 use Twig\Node\Expression\ConstantExpression;
@@ -20,11 +21,12 @@ use Twig\Node\Expression\ConstantExpression;
  *
  * @author Yonel Ceruto <[email protected]>
  */
+#[YieldReady]
 class DeprecatedNode extends Node
 {
-    public function __construct(AbstractExpression $expr, int $lineno, string $tag = null)
+    public function __construct(AbstractExpression $expr, int $lineno)
     {
-        parent::__construct(['expr' => $expr], [], $lineno, $tag);
+        parent::__construct(['expr' => $expr], [], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -33,21 +35,39 @@ class DeprecatedNode extends Node
 
         $expr = $this->getNode('expr');
 
-        if ($expr instanceof ConstantExpression) {
-            $compiler->write('@trigger_error(')
-                ->subcompile($expr);
-        } else {
+        if (!$expr instanceof ConstantExpression) {
             $varName = $compiler->getVarName();
-            $compiler->write(sprintf('$%s = ', $varName))
+            $compiler
+                ->write(\sprintf('$%s = ', $varName))
                 ->subcompile($expr)
                 ->raw(";\n")
-                ->write(sprintf('@trigger_error($%s', $varName));
+            ;
+        }
+
+        $compiler->write('trigger_deprecation(');
+        if ($this->hasNode('package')) {
+            $compiler->subcompile($this->getNode('package'));
+        } else {
+            $compiler->raw("''");
+        }
+        $compiler->raw(', ');
+        if ($this->hasNode('version')) {
+            $compiler->subcompile($this->getNode('version'));
+        } else {
+            $compiler->raw("''");
+        }
+        $compiler->raw(', ');
+
+        if ($expr instanceof ConstantExpression) {
+            $compiler->subcompile($expr);
+        } else {
+            $compiler->write(\sprintf('$%s', $varName));
         }
 
         $compiler
             ->raw('.')
-            ->string(sprintf(' ("%s" at line %d).', $this->getTemplateName(), $this->getTemplateLine()))
-            ->raw(", E_USER_DEPRECATED);\n")
+            ->string(\sprintf(' in "%s" at line %d.', $this->getTemplateName(), $this->getTemplateLine()))
+            ->raw(");\n")
         ;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/DoNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/DoNode.php
index f7783d19..1593fd05 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/DoNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/DoNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 
@@ -19,11 +20,12 @@ use Twig\Node\Expression\AbstractExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class DoNode extends Node
 {
-    public function __construct(AbstractExpression $expr, int $lineno, string $tag = null)
+    public function __construct(AbstractExpression $expr, int $lineno)
     {
-        parent::__construct(['expr' => $expr], [], $lineno, $tag);
+        parent::__construct(['expr' => $expr], [], $lineno);
     }
 
     public function compile(Compiler $compiler): void
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/EmbedNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/EmbedNode.php
index 903c3f6c..4cd3b38f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/EmbedNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/EmbedNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 use Twig\Node\Expression\ConstantExpression;
@@ -20,12 +21,13 @@ use Twig\Node\Expression\ConstantExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class EmbedNode extends IncludeNode
 {
     // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
-    public function __construct(string $name, int $index, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno, string $tag = null)
+    public function __construct(string $name, int $index, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno)
     {
-        parent::__construct(new ConstantExpression('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
+        parent::__construct(new ConstantExpression('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno);
 
         $this->setAttribute('name', $name);
         $this->setAttribute('index', $index);
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/AbstractExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/AbstractExpression.php
index 42da0559..1692f567 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/AbstractExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/AbstractExpression.php
@@ -21,4 +21,8 @@ use Twig\Node\Node;
  */
 abstract class AbstractExpression extends Node
 {
+    public function isGenerator(): bool
+    {
+        return $this->hasAttribute('is_generator') && $this->getAttribute('is_generator');
+    }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrayExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrayExpression.php
index 0e25fe46..5f8b0f63 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrayExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrayExpression.php
@@ -55,7 +55,7 @@ class ArrayExpression extends AbstractExpression
         return false;
     }
 
-    public function addElement(AbstractExpression $value, AbstractExpression $key = null): void
+    public function addElement(AbstractExpression $value, ?AbstractExpression $key = null): void
     {
         if (null === $key) {
             $key = new ConstantExpression(++$this->index, $value->getTemplateLine());
@@ -66,20 +66,70 @@ class ArrayExpression extends AbstractExpression
 
     public function compile(Compiler $compiler): void
     {
+        $keyValuePairs = $this->getKeyValuePairs();
+        $needsArrayMergeSpread = \PHP_VERSION_ID < 80100 && $this->hasSpreadItem($keyValuePairs);
+
+        if ($needsArrayMergeSpread) {
+            $compiler->raw('CoreExtension::merge(');
+        }
         $compiler->raw('[');
         $first = true;
-        foreach ($this->getKeyValuePairs() as $pair) {
+        $reopenAfterMergeSpread = false;
+        $nextIndex = 0;
+        foreach ($keyValuePairs as $pair) {
+            if ($reopenAfterMergeSpread) {
+                $compiler->raw(', [');
+                $reopenAfterMergeSpread = false;
+            }
+
+            if ($needsArrayMergeSpread && $pair['value']->hasAttribute('spread')) {
+                $compiler->raw('], ')->subcompile($pair['value']);
+                $first = true;
+                $reopenAfterMergeSpread = true;
+                continue;
+            }
             if (!$first) {
                 $compiler->raw(', ');
             }
             $first = false;
 
-            $compiler
-                ->subcompile($pair['key'])
-                ->raw(' => ')
-                ->subcompile($pair['value'])
-            ;
+            if ($pair['value']->hasAttribute('spread') && !$needsArrayMergeSpread) {
+                $compiler->raw('...')->subcompile($pair['value']);
+                ++$nextIndex;
+            } else {
+                $key = $pair['key'] instanceof ConstantExpression ? $pair['key']->getAttribute('value') : null;
+
+                if ($nextIndex !== $key) {
+                    if (\is_int($key)) {
+                        $nextIndex = $key + 1;
+                    }
+                    $compiler
+                        ->subcompile($pair['key'])
+                        ->raw(' => ')
+                    ;
+                } else {
+                    ++$nextIndex;
+                }
+
+                $compiler->subcompile($pair['value']);
+            }
+        }
+        if (!$reopenAfterMergeSpread) {
+            $compiler->raw(']');
         }
-        $compiler->raw(']');
+        if ($needsArrayMergeSpread) {
+            $compiler->raw(')');
+        }
+    }
+
+    private function hasSpreadItem(array $pairs): bool
+    {
+        foreach ($pairs as $pair) {
+            if ($pair['value']->hasAttribute('spread')) {
+                return true;
+            }
+        }
+
+        return false;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php
index eaad03c9..2bae4edd 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php
@@ -21,9 +21,9 @@ use Twig\Node\Node;
  */
 class ArrowFunctionExpression extends AbstractExpression
 {
-    public function __construct(AbstractExpression $expr, Node $names, $lineno, $tag = null)
+    public function __construct(AbstractExpression $expr, Node $names, $lineno)
     {
-        parent::__construct(['expr' => $expr, 'names' => $names], [], $lineno, $tag);
+        parent::__construct(['expr' => $expr, 'names' => $names], [], $lineno);
     }
 
     public function compile(Compiler $compiler): void
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php
index c3516b85..a73a5608 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php
@@ -20,11 +20,11 @@ class EndsWithBinary extends AbstractBinary
         $left = $compiler->getVarName();
         $right = $compiler->getVarName();
         $compiler
-            ->raw(sprintf('(is_string($%s = ', $left))
+            ->raw(\sprintf('(is_string($%s = ', $left))
             ->subcompile($this->getNode('left'))
-            ->raw(sprintf(') && is_string($%s = ', $right))
+            ->raw(\sprintf(') && is_string($%s = ', $right))
             ->subcompile($this->getNode('right'))
-            ->raw(sprintf(') && (\'\' === $%2$s || $%2$s === substr($%1$s, -strlen($%2$s))))', $left, $right))
+            ->raw(\sprintf(') && str_ends_with($%1$s, $%2$s))', $left, $right))
         ;
     }
 
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php
index 6b48549e..5f423196 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php
@@ -24,7 +24,7 @@ class EqualBinary extends AbstractBinary
         }
 
         $compiler
-            ->raw('(0 === twig_compare(')
+            ->raw('(0 === CoreExtension::compare(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php
index e1dd0678..f42de3f8 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php
@@ -24,7 +24,7 @@ class GreaterBinary extends AbstractBinary
         }
 
         $compiler
-            ->raw('(1 === twig_compare(')
+            ->raw('(1 === CoreExtension::compare(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php
index df9bfcfb..0c4f43fd 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php
@@ -24,7 +24,7 @@ class GreaterEqualBinary extends AbstractBinary
         }
 
         $compiler
-            ->raw('(0 <= twig_compare(')
+            ->raw('(0 <= CoreExtension::compare(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php
new file mode 100644
index 00000000..c57bb20e
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Node\Expression\Binary;
+
+use Twig\Compiler;
+
+class HasEveryBinary extends AbstractBinary
+{
+    public function compile(Compiler $compiler): void
+    {
+        $compiler
+            ->raw('CoreExtension::arrayEvery($this->env, ')
+            ->subcompile($this->getNode('left'))
+            ->raw(', ')
+            ->subcompile($this->getNode('right'))
+            ->raw(')')
+        ;
+    }
+
+    public function operator(Compiler $compiler): Compiler
+    {
+        return $compiler->raw('');
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php
new file mode 100644
index 00000000..12293f84
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Node\Expression\Binary;
+
+use Twig\Compiler;
+
+class HasSomeBinary extends AbstractBinary
+{
+    public function compile(Compiler $compiler): void
+    {
+        $compiler
+            ->raw('CoreExtension::arraySome($this->env, ')
+            ->subcompile($this->getNode('left'))
+            ->raw(', ')
+            ->subcompile($this->getNode('right'))
+            ->raw(')')
+        ;
+    }
+
+    public function operator(Compiler $compiler): Compiler
+    {
+        return $compiler->raw('');
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php
index 6dbfa97f..68a98fe1 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php
@@ -18,7 +18,7 @@ class InBinary extends AbstractBinary
     public function compile(Compiler $compiler): void
     {
         $compiler
-            ->raw('twig_in_filter(')
+            ->raw('CoreExtension::inFilter(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php
index 598e6291..fb3264a2 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php
@@ -24,7 +24,7 @@ class LessBinary extends AbstractBinary
         }
 
         $compiler
-            ->raw('(-1 === twig_compare(')
+            ->raw('(-1 === CoreExtension::compare(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php
index e3c4af58..8f365389 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php
@@ -24,7 +24,7 @@ class LessEqualBinary extends AbstractBinary
         }
 
         $compiler
-            ->raw('(0 >= twig_compare(')
+            ->raw('(0 >= CoreExtension::compare(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php
index bc97292c..4669044e 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php
@@ -18,7 +18,7 @@ class MatchesBinary extends AbstractBinary
     public function compile(Compiler $compiler): void
     {
         $compiler
-            ->raw('preg_match(')
+            ->raw('CoreExtension::matches(')
             ->subcompile($this->getNode('right'))
             ->raw(', ')
             ->subcompile($this->getNode('left'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php
index db47a289..d137ef62 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php
@@ -24,7 +24,7 @@ class NotEqualBinary extends AbstractBinary
         }
 
         $compiler
-            ->raw('(0 !== twig_compare(')
+            ->raw('(0 !== CoreExtension::compare(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php
index fcba6cca..80c8755d 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php
@@ -18,7 +18,7 @@ class NotInBinary extends AbstractBinary
     public function compile(Compiler $compiler): void
     {
         $compiler
-            ->raw('!twig_in_filter(')
+            ->raw('!CoreExtension::inFilter(')
             ->subcompile($this->getNode('left'))
             ->raw(', ')
             ->subcompile($this->getNode('right'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php
index d0df1c4b..4519f30d 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php
@@ -20,11 +20,11 @@ class StartsWithBinary extends AbstractBinary
         $left = $compiler->getVarName();
         $right = $compiler->getVarName();
         $compiler
-            ->raw(sprintf('(is_string($%s = ', $left))
+            ->raw(\sprintf('(is_string($%s = ', $left))
             ->subcompile($this->getNode('left'))
-            ->raw(sprintf(') && is_string($%s = ', $right))
+            ->raw(\sprintf(') && is_string($%s = ', $right))
             ->subcompile($this->getNode('right'))
-            ->raw(sprintf(') && (\'\' === $%2$s || 0 === strpos($%1$s, $%2$s)))', $left, $right))
+            ->raw(\sprintf(') && str_starts_with($%1$s, $%2$s))', $left, $right))
         ;
     }
 
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php
index b1e2a8f7..acd231e1 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php
@@ -22,14 +22,14 @@ use Twig\Node\Node;
  */
 class BlockReferenceExpression extends AbstractExpression
 {
-    public function __construct(Node $name, ?Node $template, int $lineno, string $tag = null)
+    public function __construct(Node $name, ?Node $template, int $lineno)
     {
         $nodes = ['name' => $name];
         if (null !== $template) {
             $nodes['template'] = $template;
         }
 
-        parent::__construct($nodes, ['is_defined_test' => false, 'output' => false], $lineno, $tag);
+        parent::__construct($nodes, ['is_defined_test' => false, 'output' => false], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -40,8 +40,9 @@ class BlockReferenceExpression extends AbstractExpression
             if ($this->getAttribute('output')) {
                 $compiler->addDebugInfo($this);
 
+                $compiler->write('yield from ');
                 $this
-                    ->compileTemplateCall($compiler, 'displayBlock')
+                    ->compileTemplateCall($compiler, 'yieldBlock')
                     ->raw(";\n");
             } else {
                 $this->compileTemplateCall($compiler, 'renderBlock');
@@ -65,7 +66,7 @@ class BlockReferenceExpression extends AbstractExpression
             ;
         }
 
-        $compiler->raw(sprintf('->%s', $method));
+        $compiler->raw(\sprintf('->unwrap()->%s', $method));
 
         return $this->compileBlockArguments($compiler);
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/CallExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/CallExpression.php
index 28881066..6fc6f66e 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/CallExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/CallExpression.php
@@ -15,40 +15,49 @@ use Twig\Compiler;
 use Twig\Error\SyntaxError;
 use Twig\Extension\ExtensionInterface;
 use Twig\Node\Node;
+use Twig\TwigCallableInterface;
+use Twig\TwigFilter;
+use Twig\TwigFunction;
+use Twig\TwigTest;
+use Twig\Util\CallableArgumentsExtractor;
+use Twig\Util\ReflectionCallable;
 
 abstract class CallExpression extends AbstractExpression
 {
-    private $reflector;
+    private $reflector = null;
 
     protected function compileCallable(Compiler $compiler)
     {
-        $callable = $this->getAttribute('callable');
+        $twigCallable = $this->getTwigCallable();
+        $callable = $twigCallable->getCallable();
 
-        if (\is_string($callable) && false === strpos($callable, '::')) {
+        if (\is_string($callable) && !str_contains($callable, '::')) {
             $compiler->raw($callable);
         } else {
-            [$r, $callable] = $this->reflectCallable($callable);
+            $rc = $this->reflectCallable($twigCallable);
+            $r = $rc->getReflector();
+            $callable = $rc->getCallable();
 
             if (\is_string($callable)) {
                 $compiler->raw($callable);
             } elseif (\is_array($callable) && \is_string($callable[0])) {
                 if (!$r instanceof \ReflectionMethod || $r->isStatic()) {
-                    $compiler->raw(sprintf('%s::%s', $callable[0], $callable[1]));
+                    $compiler->raw(\sprintf('%s::%s', $callable[0], $callable[1]));
                 } else {
-                    $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1]));
+                    $compiler->raw(\sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1]));
                 }
             } elseif (\is_array($callable) && $callable[0] instanceof ExtensionInterface) {
                 $class = \get_class($callable[0]);
                 if (!$compiler->getEnvironment()->hasExtension($class)) {
                     // Compile a non-optimized call to trigger a \Twig\Error\RuntimeError, which cannot be a compile-time error
-                    $compiler->raw(sprintf('$this->env->getExtension(\'%s\')', $class));
+                    $compiler->raw(\sprintf('$this->env->getExtension(\'%s\')', $class));
                 } else {
-                    $compiler->raw(sprintf('$this->extensions[\'%s\']', ltrim($class, '\\')));
+                    $compiler->raw(\sprintf('$this->extensions[\'%s\']', ltrim($class, '\\')));
                 }
 
-                $compiler->raw(sprintf('->%s', $callable[1]));
+                $compiler->raw(\sprintf('->%s', $callable[1]));
             } else {
-                $compiler->raw(sprintf('$this->env->get%s(\'%s\')->getCallable()', ucfirst($this->getAttribute('type')), $this->getAttribute('name')));
+                $compiler->raw(\sprintf('$this->env->get%s(\'%s\')->getCallable()', ucfirst($this->getAttribute('type')), $twigCallable->getDynamicName()));
             }
         }
 
@@ -57,16 +66,30 @@ abstract class CallExpression extends AbstractExpression
 
     protected function compileArguments(Compiler $compiler, $isArray = false): void
     {
+        if (\func_num_args() >= 2) {
+            trigger_deprecation('twig/twig', '3.11', 'Passing a second argument to "%s()" is deprecated.', __METHOD__);
+        }
+
         $compiler->raw($isArray ? '[' : '(');
 
         $first = true;
 
-        if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
+        $twigCallable = $this->getAttribute('twig_callable');
+
+        if ($twigCallable->needsCharset()) {
+            $compiler->raw('$this->env->getCharset()');
+            $first = false;
+        }
+
+        if ($twigCallable->needsEnvironment()) {
+            if (!$first) {
+                $compiler->raw(', ');
+            }
             $compiler->raw('$this->env');
             $first = false;
         }
 
-        if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
+        if ($twigCallable->needsContext()) {
             if (!$first) {
                 $compiler->raw(', ');
             }
@@ -74,14 +97,12 @@ abstract class CallExpression extends AbstractExpression
             $first = false;
         }
 
-        if ($this->hasAttribute('arguments')) {
-            foreach ($this->getAttribute('arguments') as $argument) {
-                if (!$first) {
-                    $compiler->raw(', ');
-                }
-                $compiler->string($argument);
-                $first = false;
+        foreach ($twigCallable->getArguments() as $argument) {
+            if (!$first) {
+                $compiler->raw(', ');
             }
+            $compiler->string($argument);
+            $first = false;
         }
 
         if ($this->hasNode('node')) {
@@ -93,8 +114,7 @@ abstract class CallExpression extends AbstractExpression
         }
 
         if ($this->hasNode('arguments')) {
-            $callable = $this->getAttribute('callable');
-            $arguments = $this->getArguments($callable, $this->getNode('arguments'));
+            $arguments = (new CallableArgumentsExtractor($this, $this->getTwigCallable()))->extractArguments($this->getNode('arguments'));
             foreach ($arguments as $node) {
                 if (!$first) {
                     $compiler->raw(', ');
@@ -107,8 +127,13 @@ abstract class CallExpression extends AbstractExpression
         $compiler->raw($isArray ? ']' : ')');
     }
 
+    /**
+     * @deprecated since 3.12, use Twig\Util\CallableArgumentsExtractor::getArguments() instead
+     */
     protected function getArguments($callable, $arguments)
     {
+        trigger_deprecation('twig/twig', '3.12', 'The "%s()" method is deprecated, use Twig\Util\CallableArgumentsExtractor::getArguments() instead.', __METHOD__);
+
         $callType = $this->getAttribute('type');
         $callName = $this->getAttribute('name');
 
@@ -119,28 +144,28 @@ abstract class CallExpression extends AbstractExpression
                 $named = true;
                 $name = $this->normalizeName($name);
             } elseif ($named) {
-                throw new SyntaxError(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
+                throw new SyntaxError(\sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
             }
 
             $parameters[$name] = $node;
         }
 
-        $isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic');
+        $isVariadic = $this->getAttribute('twig_callable')->isVariadic();
         if (!$named && !$isVariadic) {
             return $parameters;
         }
 
         if (!$callable) {
             if ($named) {
-                $message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName);
+                $message = \sprintf('Named arguments are not supported for %s "%s".', $callType, $callName);
             } else {
-                $message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
+                $message = \sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
             }
 
             throw new \LogicException($message);
         }
 
-        list($callableParameters, $isPhpVariadic) = $this->getCallableParameters($callable, $isVariadic);
+        [$callableParameters, $isPhpVariadic] = $this->getCallableParameters($callable, $isVariadic);
         $arguments = [];
         $names = [];
         $missingArguments = [];
@@ -160,11 +185,11 @@ abstract class CallExpression extends AbstractExpression
 
             if (\array_key_exists($name, $parameters)) {
                 if (\array_key_exists($pos, $parameters)) {
-                    throw new SyntaxError(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
+                    throw new SyntaxError(\sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
                 }
 
                 if (\count($missingArguments)) {
-                    throw new SyntaxError(sprintf(
+                    throw new SyntaxError(\sprintf(
                         'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".',
                         $name, $callType, $callName, implode(', ', $names), \count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments)
                     ), $this->getTemplateLine(), $this->getSourceContext());
@@ -189,7 +214,7 @@ abstract class CallExpression extends AbstractExpression
                     $missingArguments[] = $name;
                 }
             } else {
-                throw new SyntaxError(sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
+                throw new SyntaxError(\sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
             }
         }
 
@@ -220,7 +245,7 @@ abstract class CallExpression extends AbstractExpression
             }
 
             throw new SyntaxError(
-                sprintf(
+                \sprintf(
                     'Unknown argument%s "%s" for %s "%s(%s)".',
                     \count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names)
                 ),
@@ -232,88 +257,106 @@ abstract class CallExpression extends AbstractExpression
         return $arguments;
     }
 
+    /**
+     * @deprecated since 3.12
+     */
     protected function normalizeName(string $name): string
     {
+        trigger_deprecation('twig/twig', '3.12', 'The "%s()" method is deprecated.', __METHOD__);
+
         return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], $name));
     }
 
+    // To be removed in 4.0
     private function getCallableParameters($callable, bool $isVariadic): array
     {
-        [$r, , $callableName] = $this->reflectCallable($callable);
+        $twigCallable = $this->getAttribute('twig_callable');
+        $rc = $this->reflectCallable($twigCallable);
+        $r = $rc->getReflector();
+        $callableName = $rc->getName();
 
         $parameters = $r->getParameters();
         if ($this->hasNode('node')) {
             array_shift($parameters);
         }
-        if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
+        if ($twigCallable->needsCharset()) {
             array_shift($parameters);
         }
-        if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
+        if ($twigCallable->needsEnvironment()) {
             array_shift($parameters);
         }
-        if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
-            foreach ($this->getAttribute('arguments') as $argument) {
-                array_shift($parameters);
-            }
+        if ($twigCallable->needsContext()) {
+            array_shift($parameters);
+        }
+        foreach ($twigCallable->getArguments() as $argument) {
+            array_shift($parameters);
         }
+
         $isPhpVariadic = false;
         if ($isVariadic) {
             $argument = end($parameters);
-            $isArray = $argument && $argument->hasType() && 'array' === $argument->getType()->getName();
+            $isArray = $argument && $argument->hasType() && $argument->getType() instanceof \ReflectionNamedType && 'array' === $argument->getType()->getName();
             if ($isArray && $argument->isDefaultValueAvailable() && [] === $argument->getDefaultValue()) {
                 array_pop($parameters);
             } elseif ($argument && $argument->isVariadic()) {
                 array_pop($parameters);
                 $isPhpVariadic = true;
             } else {
-                throw new \LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = []".', $callableName, $this->getAttribute('type'), $this->getAttribute('name')));
+                throw new \LogicException(\sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = []".', $callableName, $this->getAttribute('type'), $twigCallable->getName()));
             }
         }
 
         return [$parameters, $isPhpVariadic];
     }
 
-    private function reflectCallable($callable)
+    private function reflectCallable(TwigCallableInterface $callable): ReflectionCallable
     {
-        if (null !== $this->reflector) {
-            return $this->reflector;
-        }
-
-        if (\is_string($callable) && false !== $pos = strpos($callable, '::')) {
-            $callable = [substr($callable, 0, $pos), substr($callable, 2 + $pos)];
+        if (!$this->reflector) {
+            $this->reflector = new ReflectionCallable($callable);
         }
 
-        if (\is_array($callable) && method_exists($callable[0], $callable[1])) {
-            $r = new \ReflectionMethod($callable[0], $callable[1]);
-
-            return $this->reflector = [$r, $callable, $r->class.'::'.$r->name];
-        }
-
-        $checkVisibility = $callable instanceof \Closure;
-        try {
-            $closure = \Closure::fromCallable($callable);
-        } catch (\TypeError $e) {
-            throw new \LogicException(sprintf('Callback for %s "%s" is not callable in the current scope.', $this->getAttribute('type'), $this->getAttribute('name')), 0, $e);
-        }
-        $r = new \ReflectionFunction($closure);
-
-        if (false !== strpos($r->name, '{closure}')) {
-            return $this->reflector = [$r, $callable, 'Closure'];
-        }
-
-        if ($object = $r->getClosureThis()) {
-            $callable = [$object, $r->name];
-            $callableName = (\function_exists('get_debug_type') ? get_debug_type($object) : \get_class($object)).'::'.$r->name;
-        } elseif ($class = $r->getClosureScopeClass()) {
-            $callableName = (\is_array($callable) ? $callable[0] : $class->name).'::'.$r->name;
-        } else {
-            $callable = $callableName = $r->name;
-        }
-
-        if ($checkVisibility && \is_array($callable) && method_exists(...$callable) && !(new \ReflectionMethod(...$callable))->isPublic()) {
-            $callable = $r->getClosure();
-        }
+        return $this->reflector;
+    }
 
-        return $this->reflector = [$r, $callable, $callableName];
+    /**
+     * Overrides the Twig callable based on attributes (as potentially, attributes changed between the creation and the compilation of the node).
+     *
+     * To be removed in 4.0 and replace by $this->getAttribute('twig_callable').
+     */
+    private function getTwigCallable(): TwigCallableInterface
+    {
+        $current = $this->getAttribute('twig_callable');
+
+        $this->setAttribute('twig_callable', match ($this->getAttribute('type')) {
+            'test' => (new TwigTest(
+                $this->getAttribute('name'),
+                $this->hasAttribute('callable') ? $this->getAttribute('callable') : $current->getCallable(),
+                [
+                    'is_variadic' => $this->hasAttribute('is_variadic') ? $this->getAttribute('is_variadic') : $current->isVariadic(),
+                ],
+            ))->withDynamicArguments($this->getAttribute('name'), $this->hasAttribute('dynamic_name') ? $this->getAttribute('dynamic_name') : $current->getDynamicName(), $this->hasAttribute('arguments') ?: $current->getArguments()),
+            'function' => (new TwigFunction(
+                $this->hasAttribute('name') ? $this->getAttribute('name') : $current->getName(),
+                $this->hasAttribute('callable') ? $this->getAttribute('callable') : $current->getCallable(),
+                [
+                    'needs_environment' => $this->hasAttribute('needs_environment') ? $this->getAttribute('needs_environment') : $current->needsEnvironment(),
+                    'needs_context' => $this->hasAttribute('needs_context') ? $this->getAttribute('needs_context') : $current->needsContext(),
+                    'needs_charset' => $this->hasAttribute('needs_charset') ? $this->getAttribute('needs_charset') : $current->needsCharset(),
+                    'is_variadic' => $this->hasAttribute('is_variadic') ? $this->getAttribute('is_variadic') : $current->isVariadic(),
+                ],
+            ))->withDynamicArguments($this->getAttribute('name'), $this->hasAttribute('dynamic_name') ? $this->getAttribute('dynamic_name') : $current->getDynamicName(), $this->hasAttribute('arguments') ?: $current->getArguments()),
+            'filter' => (new TwigFilter(
+                $this->getAttribute('name'),
+                $this->hasAttribute('callable') ? $this->getAttribute('callable') : $current->getCallable(),
+                [
+                    'needs_environment' => $this->hasAttribute('needs_environment') ? $this->getAttribute('needs_environment') : $current->needsEnvironment(),
+                    'needs_context' => $this->hasAttribute('needs_context') ? $this->getAttribute('needs_context') : $current->needsContext(),
+                    'needs_charset' => $this->hasAttribute('needs_charset') ? $this->getAttribute('needs_charset') : $current->needsCharset(),
+                    'is_variadic' => $this->hasAttribute('is_variadic') ? $this->getAttribute('is_variadic') : $current->isVariadic(),
+                ],
+            ))->withDynamicArguments($this->getAttribute('name'), $this->hasAttribute('dynamic_name') ? $this->getAttribute('dynamic_name') : $current->getDynamicName(), $this->hasAttribute('arguments') ?: $current->getArguments()),
+        });
+
+        return $this->getAttribute('twig_callable');
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConditionalExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConditionalExpression.php
index 2c7bd0a2..d7db9935 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConditionalExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConditionalExpression.php
@@ -23,14 +23,23 @@ class ConditionalExpression extends AbstractExpression
 
     public function compile(Compiler $compiler): void
     {
-        $compiler
-            ->raw('((')
-            ->subcompile($this->getNode('expr1'))
-            ->raw(') ? (')
-            ->subcompile($this->getNode('expr2'))
-            ->raw(') : (')
-            ->subcompile($this->getNode('expr3'))
-            ->raw('))')
-        ;
+        // Ternary with no then uses Elvis operator
+        if ($this->getNode('expr1') === $this->getNode('expr2')) {
+            $compiler
+                ->raw('((')
+                ->subcompile($this->getNode('expr1'))
+                ->raw(') ?: (')
+                ->subcompile($this->getNode('expr3'))
+                ->raw('))');
+        } else {
+            $compiler
+                ->raw('((')
+                ->subcompile($this->getNode('expr1'))
+                ->raw(') ? (')
+                ->subcompile($this->getNode('expr2'))
+                ->raw(') : (')
+                ->subcompile($this->getNode('expr3'))
+                ->raw('))');
+        }
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConstantExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConstantExpression.php
index 7ddbcc6f..2a8909d5 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConstantExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ConstantExpression.php
@@ -14,6 +14,9 @@ namespace Twig\Node\Expression;
 
 use Twig\Compiler;
 
+/**
+ * @final
+ */
 class ConstantExpression extends AbstractExpression
 {
     public function __construct($value, int $lineno)
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php
index 6a572d48..75b6d18c 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php
@@ -11,7 +11,9 @@
 
 namespace Twig\Node\Expression\Filter;
 
+use Twig\Attribute\FirstClassTwigCallableReady;
 use Twig\Compiler;
+use Twig\Extension\CoreExtension;
 use Twig\Node\Expression\ConditionalExpression;
 use Twig\Node\Expression\ConstantExpression;
 use Twig\Node\Expression\FilterExpression;
@@ -19,6 +21,8 @@ use Twig\Node\Expression\GetAttrExpression;
 use Twig\Node\Expression\NameExpression;
 use Twig\Node\Expression\Test\DefinedTest;
 use Twig\Node\Node;
+use Twig\TwigFilter;
+use Twig\TwigTest;
 
 /**
  * Returns the value or the default value when it is undefined or empty.
@@ -29,20 +33,27 @@ use Twig\Node\Node;
  */
 class DefaultFilter extends FilterExpression
 {
-    public function __construct(Node $node, ConstantExpression $filterName, Node $arguments, int $lineno, string $tag = null)
+    #[FirstClassTwigCallableReady]
+    public function __construct(Node $node, TwigFilter|ConstantExpression $filter, Node $arguments, int $lineno)
     {
-        $default = new FilterExpression($node, new ConstantExpression('default', $node->getTemplateLine()), $arguments, $node->getTemplateLine());
+        if ($filter instanceof TwigFilter) {
+            $name = $filter->getName();
+            $default = new FilterExpression($node, $filter, $arguments, $node->getTemplateLine());
+        } else {
+            $name = $filter->getAttribute('value');
+            $default = new FilterExpression($node, new TwigFilter('default', [CoreExtension::class, 'default']), $arguments, $node->getTemplateLine());
+        }
 
-        if ('default' === $filterName->getAttribute('value') && ($node instanceof NameExpression || $node instanceof GetAttrExpression)) {
-            $test = new DefinedTest(clone $node, 'defined', new Node(), $node->getTemplateLine());
-            $false = \count($arguments) ? $arguments->getNode(0) : new ConstantExpression('', $node->getTemplateLine());
+        if ('default' === $name && ($node instanceof NameExpression || $node instanceof GetAttrExpression)) {
+            $test = new DefinedTest(clone $node, new TwigTest('defined'), new Node(), $node->getTemplateLine());
+            $false = \count($arguments) ? $arguments->getNode('0') : new ConstantExpression('', $node->getTemplateLine());
 
             $node = new ConditionalExpression($test, $default, $false, $node->getTemplateLine());
         } else {
             $node = $default;
         }
 
-        parent::__construct($node, $filterName, $arguments, $lineno, $tag);
+        parent::__construct($node, $filter, $arguments, $lineno);
     }
 
     public function compile(Compiler $compiler): void
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php
new file mode 100644
index 00000000..e115ab19
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Node\Expression\Filter;
+
+use Twig\Attribute\FirstClassTwigCallableReady;
+use Twig\Compiler;
+use Twig\Node\Expression\ConstantExpression;
+use Twig\Node\Expression\FilterExpression;
+use Twig\Node\Node;
+use Twig\TwigFilter;
+
+/**
+ * @author Fabien Potencier <[email protected]>
+ */
+class RawFilter extends FilterExpression
+{
+    #[FirstClassTwigCallableReady]
+    public function __construct(Node $node, TwigFilter|ConstantExpression|null $filter = null, ?Node $arguments = null, int $lineno = 0)
+    {
+        parent::__construct($node, $filter ?: new TwigFilter('raw', null, ['is_safe' => ['all']]), $arguments ?: new Node(), $lineno ?: $node->getTemplateLine());
+    }
+
+    public function compile(Compiler $compiler): void
+    {
+        $compiler->subcompile($this->getNode('node'));
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FilterExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FilterExpression.php
index 0fc15886..efc91193 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FilterExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FilterExpression.php
@@ -12,28 +12,61 @@
 
 namespace Twig\Node\Expression;
 
+use Twig\Attribute\FirstClassTwigCallableReady;
 use Twig\Compiler;
+use Twig\Node\NameDeprecation;
 use Twig\Node\Node;
+use Twig\TwigFilter;
 
 class FilterExpression extends CallExpression
 {
-    public function __construct(Node $node, ConstantExpression $filterName, Node $arguments, int $lineno, string $tag = null)
+    #[FirstClassTwigCallableReady]
+    public function __construct(Node $node, TwigFilter|ConstantExpression $filter, Node $arguments, int $lineno)
     {
-        parent::__construct(['node' => $node, 'filter' => $filterName, 'arguments' => $arguments], [], $lineno, $tag);
+        if ($filter instanceof TwigFilter) {
+            $name = $filter->getName();
+            $filterName = new ConstantExpression($name, $lineno);
+        } else {
+            $name = $filter->getAttribute('value');
+            $filterName = $filter;
+            trigger_deprecation('twig/twig', '3.12', 'Not passing an instance of "TwigFilter" when creating a "%s" filter of type "%s" is deprecated.', $name, static::class);
+        }
+
+        parent::__construct(['node' => $node, 'filter' => $filterName, 'arguments' => $arguments], ['name' => $name, 'type' => 'filter'], $lineno);
+
+        if ($filter instanceof TwigFilter) {
+            $this->setAttribute('twig_callable', $filter);
+        }
+
+        $this->deprecateNode('filter', new NameDeprecation('twig/twig', '3.12'));
+
+        $this->deprecateAttribute('needs_charset', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('needs_environment', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('needs_context', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('arguments', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('callable', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('is_variadic', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('dynamic_name', new NameDeprecation('twig/twig', '3.12'));
     }
 
     public function compile(Compiler $compiler): void
     {
-        $name = $this->getNode('filter')->getAttribute('value');
-        $filter = $compiler->getEnvironment()->getFilter($name);
-
-        $this->setAttribute('name', $name);
-        $this->setAttribute('type', 'filter');
-        $this->setAttribute('needs_environment', $filter->needsEnvironment());
-        $this->setAttribute('needs_context', $filter->needsContext());
-        $this->setAttribute('arguments', $filter->getArguments());
-        $this->setAttribute('callable', $filter->getCallable());
-        $this->setAttribute('is_variadic', $filter->isVariadic());
+        $name = $this->getNode('filter', false)->getAttribute('value');
+        if ($name !== $this->getAttribute('name')) {
+            trigger_deprecation('twig/twig', '3.11', 'Changing the value of a "filter" node in a NodeVisitor class is not supported anymore.');
+            $this->removeAttribute('twig_callable');
+        }
+        if ('raw' === $name) {
+            trigger_deprecation('twig/twig', '3.11', 'Creating the "raw" filter via "FilterExpression" is deprecated; use "RawFilter" instead.');
+
+            $compiler->subcompile($this->getNode('node'));
+
+            return;
+        }
+
+        if (!$this->hasAttribute('twig_callable')) {
+            $this->setAttribute('twig_callable', $compiler->getEnvironment()->getFilter($name));
+        }
 
         $this->compileCallable($compiler);
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionExpression.php
index 71269775..6215c6ab 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionExpression.php
@@ -11,32 +11,57 @@
 
 namespace Twig\Node\Expression;
 
+use Twig\Attribute\FirstClassTwigCallableReady;
 use Twig\Compiler;
+use Twig\Node\NameDeprecation;
 use Twig\Node\Node;
+use Twig\TwigFunction;
 
 class FunctionExpression extends CallExpression
 {
-    public function __construct(string $name, Node $arguments, int $lineno)
+    #[FirstClassTwigCallableReady]
+    public function __construct(TwigFunction|string $function, Node $arguments, int $lineno)
     {
-        parent::__construct(['arguments' => $arguments], ['name' => $name, 'is_defined_test' => false], $lineno);
+        if ($function instanceof TwigFunction) {
+            $name = $function->getName();
+        } else {
+            $name = $function;
+            trigger_deprecation('twig/twig', '3.12', 'Not passing an instance of "TwigFunction" when creating a "%s" function of type "%s" is deprecated.', $name, static::class);
+        }
+
+        parent::__construct(['arguments' => $arguments], ['name' => $name, 'type' => 'function', 'is_defined_test' => false], $lineno);
+
+        if ($function instanceof TwigFunction) {
+            $this->setAttribute('twig_callable', $function);
+        }
+
+        $this->deprecateAttribute('needs_charset', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('needs_environment', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('needs_context', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('arguments', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('callable', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('is_variadic', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('dynamic_name', new NameDeprecation('twig/twig', '3.12'));
     }
 
     public function compile(Compiler $compiler)
     {
         $name = $this->getAttribute('name');
-        $function = $compiler->getEnvironment()->getFunction($name);
-
-        $this->setAttribute('name', $name);
-        $this->setAttribute('type', 'function');
-        $this->setAttribute('needs_environment', $function->needsEnvironment());
-        $this->setAttribute('needs_context', $function->needsContext());
-        $this->setAttribute('arguments', $function->getArguments());
-        $callable = $function->getCallable();
+        if ($this->hasAttribute('twig_callable')) {
+            $name = $this->getAttribute('twig_callable')->getName();
+            if ($name !== $this->getAttribute('name')) {
+                trigger_deprecation('twig/twig', '3.12', 'Changing the value of a "function" node in a NodeVisitor class is not supported anymore.');
+                $this->removeAttribute('twig_callable');
+            }
+        }
+
+        if (!$this->hasAttribute('twig_callable')) {
+            $this->setAttribute('twig_callable', $compiler->getEnvironment()->getFunction($name));
+        }
+
         if ('constant' === $name && $this->getAttribute('is_defined_test')) {
-            $callable = 'twig_constant_is_defined';
+            $this->getNode('arguments')->setNode('checkDefined', new ConstantExpression(true, $this->getTemplateLine()));
         }
-        $this->setAttribute('callable', $callable);
-        $this->setAttribute('is_variadic', $function->isVariadic());
 
         $this->compileCallable($compiler);
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionNode/EnumCasesFunction.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionNode/EnumCasesFunction.php
new file mode 100644
index 00000000..7e5c25ff
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/FunctionNode/EnumCasesFunction.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Twig\Node\Expression\FunctionNode;
+
+use Twig\Compiler;
+use Twig\Error\SyntaxError;
+use Twig\Node\Expression\ConstantExpression;
+use Twig\Node\Expression\FunctionExpression;
+
+class EnumCasesFunction extends FunctionExpression
+{
+    public function compile(Compiler $compiler): void
+    {
+        $arguments = $this->getNode('arguments');
+        if ($arguments->hasNode('enum')) {
+            $firstArgument = $arguments->getNode('enum');
+        } elseif ($arguments->hasNode('0')) {
+            $firstArgument = $arguments->getNode('0');
+        } else {
+            $firstArgument = null;
+        }
+
+        if (!$firstArgument instanceof ConstantExpression || 1 !== \count($arguments)) {
+            parent::compile($compiler);
+
+            return;
+        }
+
+        $value = $firstArgument->getAttribute('value');
+
+        if (!\is_string($value)) {
+            throw new SyntaxError('The first argument of the "enum_cases" function must be a string.', $this->getTemplateLine(), $this->getSourceContext());
+        }
+
+        if (!enum_exists($value)) {
+            throw new SyntaxError(\sprintf('The first argument of the "enum_cases" function must be the name of an enum, "%s" given.', $value), $this->getTemplateLine(), $this->getSourceContext());
+        }
+
+        $compiler->raw(\sprintf('%s::cases()', $value));
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php
index e6a75ce9..29a446b8 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php
@@ -57,7 +57,7 @@ class GetAttrExpression extends AbstractExpression
             return;
         }
 
-        $compiler->raw('twig_get_attribute($this->env, $this->source, ');
+        $compiler->raw('CoreExtension::getAttribute($this->env, $this->source, ');
 
         if ($this->getAttribute('ignore_strict_check')) {
             $this->getNode('node')->setAttribute('ignore_strict_check', true);
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/InlinePrint.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/InlinePrint.php
index 1ad4751e..0a3c2e4f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/InlinePrint.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/InlinePrint.php
@@ -27,9 +27,8 @@ final class InlinePrint extends AbstractExpression
     public function compile(Compiler $compiler): void
     {
         $compiler
-            ->raw('print (')
+            ->raw('yield ')
             ->subcompile($this->getNode('node'))
-            ->raw(')')
         ;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php
index d5ec0b6e..01806f91 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php
@@ -39,14 +39,16 @@ class MethodCallExpression extends AbstractExpression
         }
 
         $compiler
-            ->raw('twig_call_macro($macros[')
+            ->raw('CoreExtension::callMacro($macros[')
             ->repr($this->getNode('node')->getAttribute('name'))
             ->raw('], ')
             ->repr($this->getAttribute('method'))
             ->raw(', [')
         ;
         $first = true;
-        foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
+        /** @var ArrayExpression */
+        $args = $this->getNode('arguments');
+        foreach ($args->getKeyValuePairs() as $pair) {
             if (!$first) {
                 $compiler->raw(', ');
             }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NameExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NameExpression.php
index c3563f01..286aa5ae 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NameExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NameExpression.php
@@ -34,7 +34,7 @@ class NameExpression extends AbstractExpression
         $compiler->addDebugInfo($this);
 
         if ($this->getAttribute('is_defined_test')) {
-            if ($this->isSpecial()) {
+            if (isset($this->specialVars[$name])) {
                 $compiler->repr(true);
             } elseif (\PHP_VERSION_ID >= 70400) {
                 $compiler
@@ -51,7 +51,7 @@ class NameExpression extends AbstractExpression
                     ->raw(', $context))')
                 ;
             }
-        } elseif ($this->isSpecial()) {
+        } elseif (isset($this->specialVars[$name])) {
             $compiler->raw($this->specialVars[$name]);
         } elseif ($this->getAttribute('always_defined')) {
             $compiler
@@ -85,13 +85,23 @@ class NameExpression extends AbstractExpression
         }
     }
 
+    /**
+     * @deprecated since Twig 3.11 (to be removed in 4.0)
+     */
     public function isSpecial()
     {
+        trigger_deprecation('twig/twig', '3.11', 'The "%s()" method is deprecated and will be removed in Twig 4.0.', __METHOD__);
+
         return isset($this->specialVars[$this->getAttribute('name')]);
     }
 
+    /**
+     * @deprecated since Twig 3.11 (to be removed in 4.0)
+     */
     public function isSimple()
     {
+        trigger_deprecation('twig/twig', '3.11', 'The "%s()" method is deprecated and will be removed in Twig 4.0.', __METHOD__);
+
         return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php
index a72bc4fc..98630f7f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php
@@ -17,17 +17,18 @@ use Twig\Node\Expression\Test\DefinedTest;
 use Twig\Node\Expression\Test\NullTest;
 use Twig\Node\Expression\Unary\NotUnary;
 use Twig\Node\Node;
+use Twig\TwigTest;
 
 class NullCoalesceExpression extends ConditionalExpression
 {
     public function __construct(Node $left, Node $right, int $lineno)
     {
-        $test = new DefinedTest(clone $left, 'defined', new Node(), $left->getTemplateLine());
+        $test = new DefinedTest(clone $left, new TwigTest('defined'), new Node(), $left->getTemplateLine());
         // for "block()", we don't need the null test as the return value is always a string
         if (!$left instanceof BlockReferenceExpression) {
             $test = new AndBinary(
                 $test,
-                new NotUnary(new NullTest($left, 'null', new Node(), $left->getTemplateLine()), $left->getTemplateLine()),
+                new NotUnary(new NullTest($left, new TwigTest('null'), new Node(), $left->getTemplateLine()), $left->getTemplateLine()),
                 $left->getTemplateLine()
             );
         }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ParentExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ParentExpression.php
index 25491971..22fe38f6 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ParentExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/ParentExpression.php
@@ -21,9 +21,9 @@ use Twig\Compiler;
  */
 class ParentExpression extends AbstractExpression
 {
-    public function __construct(string $name, int $lineno, string $tag = null)
+    public function __construct(string $name, int $lineno)
     {
-        parent::__construct([], ['output' => false, 'name' => $name], $lineno, $tag);
+        parent::__construct([], ['output' => false, 'name' => $name], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -31,7 +31,7 @@ class ParentExpression extends AbstractExpression
         if ($this->getAttribute('output')) {
             $compiler
                 ->addDebugInfo($this)
-                ->write('$this->displayParentBlock(')
+                ->write('yield from $this->yieldParentBlock(')
                 ->string($this->getAttribute('name'))
                 ->raw(", \$context, \$blocks);\n")
             ;
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/ConstantTest.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/ConstantTest.php
index 57e9319d..867fd095 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/ConstantTest.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/ConstantTest.php
@@ -33,16 +33,16 @@ class ConstantTest extends TestExpression
             ->raw(' === constant(')
         ;
 
-        if ($this->getNode('arguments')->hasNode(1)) {
+        if ($this->getNode('arguments')->hasNode('1')) {
             $compiler
                 ->raw('get_class(')
-                ->subcompile($this->getNode('arguments')->getNode(1))
+                ->subcompile($this->getNode('arguments')->getNode('1'))
                 ->raw(')."::".')
             ;
         }
 
         $compiler
-            ->subcompile($this->getNode('arguments')->getNode(0))
+            ->subcompile($this->getNode('arguments')->getNode('0'))
             ->raw('))')
         ;
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php
index 3953bbbe..24d3ee82 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node\Expression\Test;
 
+use Twig\Attribute\FirstClassTwigCallableReady;
 use Twig\Compiler;
 use Twig\Error\SyntaxError;
 use Twig\Node\Expression\ArrayExpression;
@@ -22,6 +23,7 @@ use Twig\Node\Expression\MethodCallExpression;
 use Twig\Node\Expression\NameExpression;
 use Twig\Node\Expression\TestExpression;
 use Twig\Node\Node;
+use Twig\TwigTest;
 
 /**
  * Checks if a variable is defined in the current context.
@@ -35,7 +37,8 @@ use Twig\Node\Node;
  */
 class DefinedTest extends TestExpression
 {
-    public function __construct(Node $node, string $name, ?Node $arguments, int $lineno)
+    #[FirstClassTwigCallableReady]
+    public function __construct(Node $node, TwigTest|string $name, ?Node $arguments, int $lineno)
     {
         if ($node instanceof NameExpression) {
             $node->setAttribute('is_defined_test', true);
@@ -54,6 +57,10 @@ class DefinedTest extends TestExpression
             throw new SyntaxError('The "defined" test only works with simple variables.', $lineno);
         }
 
+        if (\is_string($name) && 'defined' !== $name) {
+            trigger_deprecation('twig/twig', '3.12', 'Creating a "DefinedTest" instance with a test name that is not "defined" is deprecated.');
+        }
+
         parent::__construct($node, $name, $arguments, $lineno);
     }
 
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DivisiblebyTest.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DivisiblebyTest.php
index 4cb3ee09..90d58a49 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DivisiblebyTest.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/DivisiblebyTest.php
@@ -29,7 +29,7 @@ class DivisiblebyTest extends TestExpression
             ->raw('(0 == ')
             ->subcompile($this->getNode('node'))
             ->raw(' % ')
-            ->subcompile($this->getNode('arguments')->getNode(0))
+            ->subcompile($this->getNode('arguments')->getNode('0'))
             ->raw(')')
         ;
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/SameasTest.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/SameasTest.php
index c96d2bc0..f1e24db6 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/SameasTest.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/Test/SameasTest.php
@@ -27,7 +27,7 @@ class SameasTest extends TestExpression
             ->raw('(')
             ->subcompile($this->getNode('node'))
             ->raw(' === ')
-            ->subcompile($this->getNode('arguments')->getNode(0))
+            ->subcompile($this->getNode('arguments')->getNode('0'))
             ->raw(')')
         ;
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/TestExpression.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/TestExpression.php
index e518bd8f..080d85aa 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/TestExpression.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Expression/TestExpression.php
@@ -11,31 +11,55 @@
 
 namespace Twig\Node\Expression;
 
+use Twig\Attribute\FirstClassTwigCallableReady;
 use Twig\Compiler;
+use Twig\Node\NameDeprecation;
 use Twig\Node\Node;
+use Twig\TwigTest;
 
 class TestExpression extends CallExpression
 {
-    public function __construct(Node $node, string $name, ?Node $arguments, int $lineno)
+    #[FirstClassTwigCallableReady]
+    public function __construct(Node $node, string|TwigTest $test, ?Node $arguments, int $lineno)
     {
         $nodes = ['node' => $node];
         if (null !== $arguments) {
             $nodes['arguments'] = $arguments;
         }
 
-        parent::__construct($nodes, ['name' => $name], $lineno);
+        if ($test instanceof TwigTest) {
+            $name = $test->getName();
+        } else {
+            $name = $test;
+            trigger_deprecation('twig/twig', '3.12', 'Not passing an instance of "TwigTest" when creating a "%s" test of type "%s" is deprecated.', $name, static::class);
+        }
+
+        parent::__construct($nodes, ['name' => $name, 'type' => 'test'], $lineno);
+
+        if ($test instanceof TwigTest) {
+            $this->setAttribute('twig_callable', $test);
+        }
+
+        $this->deprecateAttribute('arguments', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('callable', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('is_variadic', new NameDeprecation('twig/twig', '3.12'));
+        $this->deprecateAttribute('dynamic_name', new NameDeprecation('twig/twig', '3.12'));
     }
 
     public function compile(Compiler $compiler): void
     {
         $name = $this->getAttribute('name');
-        $test = $compiler->getEnvironment()->getTest($name);
+        if ($this->hasAttribute('twig_callable')) {
+            $name = $this->getAttribute('twig_callable')->getName();
+            if ($name !== $this->getAttribute('name')) {
+                trigger_deprecation('twig/twig', '3.12', 'Changing the value of a "test" node in a NodeVisitor class is not supported anymore.');
+                $this->removeAttribute('twig_callable');
+            }
+        }
 
-        $this->setAttribute('name', $name);
-        $this->setAttribute('type', 'test');
-        $this->setAttribute('arguments', $test->getArguments());
-        $this->setAttribute('callable', $test->getCallable());
-        $this->setAttribute('is_variadic', $test->isVariadic());
+        if (!$this->hasAttribute('twig_callable')) {
+            $this->setAttribute('twig_callable', $compiler->getEnvironment()->getTest($this->getAttribute('name')));
+        }
 
         $this->compileCallable($compiler);
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/FlushNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/FlushNode.php
index fa50a88e..ff3bd1cf 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/FlushNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/FlushNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -18,18 +19,22 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class FlushNode extends Node
 {
-    public function __construct(int $lineno, string $tag)
+    public function __construct(int $lineno)
     {
-        parent::__construct([], [], $lineno, $tag);
+        parent::__construct([], [], $lineno);
     }
 
     public function compile(Compiler $compiler): void
     {
-        $compiler
-            ->addDebugInfo($this)
-            ->write("flush();\n")
-        ;
+        $compiler->addDebugInfo($this);
+
+        if ($compiler->getEnvironment()->useYield()) {
+            $compiler->write("yield '';\n");
+        }
+
+        $compiler->write("flush();\n");
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/ForLoopNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/ForLoopNode.php
index d5ce845a..1f0a4f32 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/ForLoopNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/ForLoopNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -18,11 +19,12 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class ForLoopNode extends Node
 {
-    public function __construct(int $lineno, string $tag = null)
+    public function __construct(int $lineno)
     {
-        parent::__construct([], ['with_loop' => false, 'ifexpr' => false, 'else' => false], $lineno, $tag);
+        parent::__construct([], ['with_loop' => false, 'ifexpr' => false, 'else' => false], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -36,7 +38,7 @@ class ForLoopNode extends Node
                 ->write("++\$context['loop']['index0'];\n")
                 ->write("++\$context['loop']['index'];\n")
                 ->write("\$context['loop']['first'] = false;\n")
-                ->write("if (isset(\$context['loop']['length'])) {\n")
+                ->write("if (isset(\$context['loop']['revindex0'], \$context['loop']['revindex'])) {\n")
                 ->indent()
                 ->write("--\$context['loop']['revindex0'];\n")
                 ->write("--\$context['loop']['revindex'];\n")
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/ForNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/ForNode.php
index 04addfbf..2fc01479 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/ForNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/ForNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 use Twig\Node\Expression\AssignNameExpression;
@@ -21,20 +22,21 @@ use Twig\Node\Expression\AssignNameExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class ForNode extends Node
 {
     private $loop;
 
-    public function __construct(AssignNameExpression $keyTarget, AssignNameExpression $valueTarget, AbstractExpression $seq, ?Node $ifexpr, Node $body, ?Node $else, int $lineno, string $tag = null)
+    public function __construct(AssignNameExpression $keyTarget, AssignNameExpression $valueTarget, AbstractExpression $seq, ?Node $ifexpr, Node $body, ?Node $else, int $lineno)
     {
-        $body = new Node([$body, $this->loop = new ForLoopNode($lineno, $tag)]);
+        $body = new Node([$body, $this->loop = new ForLoopNode($lineno)]);
 
         $nodes = ['key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body];
         if (null !== $else) {
             $nodes['else'] = $else;
         }
 
-        parent::__construct($nodes, ['with_loop' => true], $lineno, $tag);
+        parent::__construct($nodes, ['with_loop' => true], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -42,7 +44,7 @@ class ForNode extends Node
         $compiler
             ->addDebugInfo($this)
             ->write("\$context['_parent'] = \$context;\n")
-            ->write("\$context['_seq'] = twig_ensure_traversable(")
+            ->write("\$context['_seq'] = CoreExtension::ensureTraversable(")
             ->subcompile($this->getNode('seq'))
             ->raw(");\n")
         ;
@@ -99,7 +101,14 @@ class ForNode extends Node
         $compiler->write("\$_parent = \$context['_parent'];\n");
 
         // remove some "private" loop variables (needed for nested loops)
-        $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
+        $compiler->write('unset($context[\'_seq\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\']');
+        if ($this->hasNode('else')) {
+            $compiler->raw(', $context[\'_iterated\']');
+        }
+        if ($this->getAttribute('with_loop')) {
+            $compiler->raw(', $context[\'loop\']');
+        }
+        $compiler->raw(");\n");
 
         // keep the values set in the inner context for variables defined in the outer context
         $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/IfNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/IfNode.php
index 5fa20082..2af48fa8 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/IfNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/IfNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -19,16 +20,17 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class IfNode extends Node
 {
-    public function __construct(Node $tests, ?Node $else, int $lineno, string $tag = null)
+    public function __construct(Node $tests, ?Node $else, int $lineno)
     {
         $nodes = ['tests' => $tests];
         if (null !== $else) {
             $nodes['else'] = $else;
         }
 
-        parent::__construct($nodes, [], $lineno, $tag);
+        parent::__construct($nodes, [], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -47,11 +49,14 @@ class IfNode extends Node
             }
 
             $compiler
-                ->subcompile($this->getNode('tests')->getNode($i))
+                ->subcompile($this->getNode('tests')->getNode((string) $i))
                 ->raw(") {\n")
                 ->indent()
-                ->subcompile($this->getNode('tests')->getNode($i + 1))
             ;
+            // The node might not exists if the content is empty
+            if ($this->getNode('tests')->hasNode((string) ($i + 1))) {
+                $compiler->subcompile($this->getNode('tests')->getNode((string) ($i + 1)));
+            }
         }
 
         if ($this->hasNode('else')) {
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/ImportNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/ImportNode.php
index 5378d799..9a6033f2 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/ImportNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/ImportNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 use Twig\Node\Expression\NameExpression;
@@ -20,11 +21,22 @@ use Twig\Node\Expression\NameExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class ImportNode extends Node
 {
-    public function __construct(AbstractExpression $expr, AbstractExpression $var, int $lineno, string $tag = null, bool $global = true)
+    /**
+     * @param bool $global
+     */
+    public function __construct(AbstractExpression $expr, AbstractExpression $var, int $lineno, $global = true)
     {
-        parent::__construct(['expr' => $expr, 'var' => $var], ['global' => $global], $lineno, $tag);
+        if (null === $global || \is_string($global)) {
+            trigger_deprecation('twig/twig', '3.12', 'Passing a tag to %s() is deprecated.', __METHOD__);
+            $global = \func_num_args() > 4 ? func_get_arg(4) : true;
+        } elseif (!\is_bool($global)) {
+            throw new \TypeError(\sprintf('Argument 4 passed to "%s()" must be a boolean, "%s" given.', __METHOD__, get_debug_type($global)));
+        }
+
+        parent::__construct(['expr' => $expr, 'var' => $var], ['global' => $global], $lineno);
     }
 
     public function compile(Compiler $compiler): void
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/IncludeNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/IncludeNode.php
index d540d6b2..1c18292c 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/IncludeNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/IncludeNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 
@@ -20,16 +21,17 @@ use Twig\Node\Expression\AbstractExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class IncludeNode extends Node implements NodeOutputInterface
 {
-    public function __construct(AbstractExpression $expr, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno, string $tag = null)
+    public function __construct(AbstractExpression $expr, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno)
     {
         $nodes = ['expr' => $expr];
         if (null !== $variables) {
             $nodes['variables'] = $variables;
         }
 
-        parent::__construct($nodes, ['only' => $only, 'ignore_missing' => $ignoreMissing], $lineno, $tag);
+        parent::__construct($nodes, ['only' => $only, 'ignore_missing' => $ignoreMissing], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -40,10 +42,10 @@ class IncludeNode extends Node implements NodeOutputInterface
             $template = $compiler->getVarName();
 
             $compiler
-                ->write(sprintf("$%s = null;\n", $template))
+                ->write(\sprintf("$%s = null;\n", $template))
                 ->write("try {\n")
                 ->indent()
-                ->write(sprintf('$%s = ', $template))
+                ->write(\sprintf('$%s = ', $template))
             ;
 
             $this->addGetTemplate($compiler);
@@ -56,10 +58,11 @@ class IncludeNode extends Node implements NodeOutputInterface
                 ->write("// ignore missing template\n")
                 ->outdent()
                 ->write("}\n")
-                ->write(sprintf("if ($%s) {\n", $template))
+                ->write(\sprintf("if ($%s) {\n", $template))
                 ->indent()
-                ->write(sprintf('$%s->display(', $template))
+                ->write(\sprintf('yield from $%s->unwrap()->yield(', $template))
             ;
+
             $this->addTemplateArguments($compiler);
             $compiler
                 ->raw(");\n")
@@ -67,8 +70,9 @@ class IncludeNode extends Node implements NodeOutputInterface
                 ->write("}\n")
             ;
         } else {
+            $compiler->write('yield from ');
             $this->addGetTemplate($compiler);
-            $compiler->raw('->display(');
+            $compiler->raw('->unwrap()->yield(');
             $this->addTemplateArguments($compiler);
             $compiler->raw(");\n");
         }
@@ -93,12 +97,12 @@ class IncludeNode extends Node implements NodeOutputInterface
             $compiler->raw(false === $this->getAttribute('only') ? '$context' : '[]');
         } elseif (false === $this->getAttribute('only')) {
             $compiler
-                ->raw('twig_array_merge($context, ')
+                ->raw('CoreExtension::merge($context, ')
                 ->subcompile($this->getNode('variables'))
                 ->raw(')')
             ;
         } else {
-            $compiler->raw('twig_to_array(');
+            $compiler->raw('CoreExtension::toArray(');
             $compiler->subcompile($this->getNode('variables'));
             $compiler->raw(')');
         }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/MacroNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/MacroNode.php
index 7f1b24d5..5a2543a9 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/MacroNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/MacroNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Error\SyntaxError;
 
@@ -19,26 +20,34 @@ use Twig\Error\SyntaxError;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class MacroNode extends Node
 {
     public const VARARGS_NAME = 'varargs';
 
-    public function __construct(string $name, Node $body, Node $arguments, int $lineno, string $tag = null)
+    /**
+     * @param BodyNode $body
+     */
+    public function __construct(string $name, Node $body, Node $arguments, int $lineno)
     {
+        if (!$body instanceof BodyNode) {
+            trigger_deprecation('twig/twig', '3.12', \sprintf('Not passing a "%s" instance as the "body" argument of the "%s" constructor is deprecated.', BodyNode::class, static::class));
+        }
+
         foreach ($arguments as $argumentName => $argument) {
             if (self::VARARGS_NAME === $argumentName) {
-                throw new SyntaxError(sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments.', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getTemplateLine(), $argument->getSourceContext());
+                throw new SyntaxError(\sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments.', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getTemplateLine(), $argument->getSourceContext());
             }
         }
 
-        parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name], $lineno, $tag);
+        parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name], $lineno);
     }
 
     public function compile(Compiler $compiler): void
     {
         $compiler
             ->addDebugInfo($this)
-            ->write(sprintf('public function macro_%s(', $this->getAttribute('name')))
+            ->write(\sprintf('public function macro_%s(', $this->getAttribute('name')))
         ;
 
         $count = \count($this->getNode('arguments'));
@@ -64,7 +73,7 @@ class MacroNode extends Node
             ->write("{\n")
             ->indent()
             ->write("\$macros = \$this->macros;\n")
-            ->write("\$context = \$this->env->mergeGlobals([\n")
+            ->write("\$context = [\n")
             ->indent()
         ;
 
@@ -77,35 +86,19 @@ class MacroNode extends Node
             ;
         }
 
+        $node = new CaptureNode($this->getNode('body'), $this->getNode('body')->lineno);
+
         $compiler
             ->write('')
             ->string(self::VARARGS_NAME)
             ->raw(' => ')
-        ;
-
-        $compiler
             ->raw("\$__varargs__,\n")
             ->outdent()
-            ->write("]);\n\n")
+            ->write("] + \$this->env->getGlobals();\n\n")
             ->write("\$blocks = [];\n\n")
-        ;
-        if ($compiler->getEnvironment()->isDebug()) {
-            $compiler->write("ob_start();\n");
-        } else {
-            $compiler->write("ob_start(function () { return ''; });\n");
-        }
-        $compiler
-            ->write("try {\n")
-            ->indent()
-            ->subcompile($this->getNode('body'))
+            ->write('return ')
+            ->subcompile($node)
             ->raw("\n")
-            ->write("return ('' === \$tmp = ob_get_contents()) ? '' : new Markup(\$tmp, \$this->env->getCharset());\n")
-            ->outdent()
-            ->write("} finally {\n")
-            ->indent()
-            ->write("ob_end_clean();\n")
-            ->outdent()
-            ->write("}\n")
             ->outdent()
             ->write("}\n\n")
         ;
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/ModuleNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/ModuleNode.php
index e972b6ba..d2fb216b 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/ModuleNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/ModuleNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 use Twig\Node\Expression\ConstantExpression;
@@ -20,16 +21,24 @@ use Twig\Source;
 /**
  * Represents a module node.
  *
- * Consider this class as being final. If you need to customize the behavior of
- * the generated class, consider adding nodes to the following nodes: display_start,
- * display_end, constructor_start, constructor_end, and class_end.
+ * If you need to customize the behavior of the generated class, add nodes to
+ * the following nodes: display_start, display_end, constructor_start,
+ * constructor_end, and class_end.
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 final class ModuleNode extends Node
 {
+    /**
+     * @param BodyNode $body
+     */
     public function __construct(Node $body, ?AbstractExpression $parent, Node $blocks, Node $macros, Node $traits, $embeddedTemplates, Source $source)
     {
+        if (!$body instanceof BodyNode) {
+            trigger_deprecation('twig/twig', '3.12', \sprintf('Not passing a "%s" instance as the "body" argument of the "%s" constructor is deprecated.', BodyNode::class, static::class));
+        }
+
         $nodes = [
             'body' => $body,
             'blocks' => $blocks,
@@ -106,7 +115,7 @@ final class ModuleNode extends Node
         $parent = $this->getNode('parent');
 
         $compiler
-            ->write("protected function doGetParent(array \$context)\n", "{\n")
+            ->write("protected function doGetParent(array \$context): bool|string|Template|TemplateWrapper\n", "{\n")
             ->indent()
             ->addDebugInfo($parent)
             ->write('return ')
@@ -143,6 +152,7 @@ final class ModuleNode extends Node
                 ->write("use Twig\Environment;\n")
                 ->write("use Twig\Error\LoaderError;\n")
                 ->write("use Twig\Error\RuntimeError;\n")
+                ->write("use Twig\Extension\CoreExtension;\n")
                 ->write("use Twig\Extension\SandboxExtension;\n")
                 ->write("use Twig\Markup;\n")
                 ->write("use Twig\Sandbox\SecurityError;\n")
@@ -150,7 +160,9 @@ final class ModuleNode extends Node
                 ->write("use Twig\Sandbox\SecurityNotAllowedFilterError;\n")
                 ->write("use Twig\Sandbox\SecurityNotAllowedFunctionError;\n")
                 ->write("use Twig\Source;\n")
-                ->write("use Twig\Template;\n\n")
+                ->write("use Twig\Template;\n")
+                ->write("use Twig\TemplateWrapper;\n")
+                ->write("\n")
             ;
         }
         $compiler
@@ -160,8 +172,11 @@ final class ModuleNode extends Node
             ->raw(" extends Template\n")
             ->write("{\n")
             ->indent()
-            ->write("private \$source;\n")
-            ->write("private \$macros = [];\n\n")
+            ->write("private Source \$source;\n")
+            ->write("/**\n")
+            ->write(" * @var array<string, Template>\n")
+            ->write(" */\n")
+            ->write("private array \$macros = [];\n\n")
         ;
     }
 
@@ -188,14 +203,14 @@ final class ModuleNode extends Node
 
                 $compiler
                     ->addDebugInfo($node)
-                    ->write(sprintf('$_trait_%s = $this->loadTemplate(', $i))
+                    ->write(\sprintf('$_trait_%s = $this->loadTemplate(', $i))
                     ->subcompile($node)
                     ->raw(', ')
                     ->repr($node->getTemplateName())
                     ->raw(', ')
                     ->repr($node->getTemplateLine())
                     ->raw(");\n")
-                    ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
+                    ->write(\sprintf("if (!\$_trait_%s->unwrap()->isTraitable()) {\n", $i))
                     ->indent()
                     ->write("throw new RuntimeError('Template \"'.")
                     ->subcompile($trait->getNode('template'))
@@ -204,12 +219,12 @@ final class ModuleNode extends Node
                     ->raw(", \$this->source);\n")
                     ->outdent()
                     ->write("}\n")
-                    ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
+                    ->write(\sprintf("\$_trait_%s_blocks = \$_trait_%s->unwrap()->getBlocks();\n\n", $i, $i))
                 ;
 
                 foreach ($trait->getNode('targets') as $key => $value) {
                     $compiler
-                        ->write(sprintf('if (!isset($_trait_%s_blocks[', $i))
+                        ->write(\sprintf('if (!isset($_trait_%s_blocks[', $i))
                         ->string($key)
                         ->raw("])) {\n")
                         ->indent()
@@ -223,11 +238,11 @@ final class ModuleNode extends Node
                         ->outdent()
                         ->write("}\n\n")
 
-                        ->write(sprintf('$_trait_%s_blocks[', $i))
+                        ->write(\sprintf('$_trait_%s_blocks[', $i))
                         ->subcompile($value)
-                        ->raw(sprintf('] = $_trait_%s_blocks[', $i))
+                        ->raw(\sprintf('] = $_trait_%s_blocks[', $i))
                         ->string($key)
-                        ->raw(sprintf(']; unset($_trait_%s_blocks[', $i))
+                        ->raw(\sprintf(']; unset($_trait_%s_blocks[', $i))
                         ->string($key)
                         ->raw("]);\n\n")
                     ;
@@ -242,7 +257,7 @@ final class ModuleNode extends Node
 
                 for ($i = 0; $i < $countTraits; ++$i) {
                     $compiler
-                        ->write(sprintf('$_trait_%s_blocks'.($i == $countTraits - 1 ? '' : ',')."\n", $i))
+                        ->write(\sprintf('$_trait_%s_blocks'.($i == $countTraits - 1 ? '' : ',')."\n", $i))
                     ;
                 }
 
@@ -275,7 +290,7 @@ final class ModuleNode extends Node
 
         foreach ($this->getNode('blocks') as $name => $node) {
             $compiler
-                ->write(sprintf("'%s' => [\$this, 'block_%s'],\n", $name, $name))
+                ->write(\sprintf("'%s' => [\$this, 'block_%s'],\n", $name, $name))
             ;
         }
 
@@ -303,7 +318,7 @@ final class ModuleNode extends Node
     protected function compileDisplay(Compiler $compiler)
     {
         $compiler
-            ->write("protected function doDisplay(array \$context, array \$blocks = [])\n", "{\n")
+            ->write("protected function doDisplay(array \$context, array \$blocks = []): iterable\n", "{\n")
             ->indent()
             ->write("\$macros = \$this->macros;\n")
             ->subcompile($this->getNode('display_start'))
@@ -324,15 +339,24 @@ final class ModuleNode extends Node
                     ->repr($parent->getTemplateLine())
                     ->raw(");\n")
                 ;
-                $compiler->write('$this->parent');
+            }
+            $compiler->write('yield from ');
+
+            if ($parent instanceof ConstantExpression) {
+                $compiler->raw('$this->parent');
             } else {
-                $compiler->write('$this->getParent($context)');
+                $compiler->raw('$this->getParent($context)');
             }
-            $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
+            $compiler->raw("->unwrap()->yield(\$context, array_merge(\$this->blocks, \$blocks));\n");
+        }
+
+        $compiler->subcompile($this->getNode('display_end'));
+
+        if (!$this->hasNode('parent')) {
+            $compiler->write("yield from [];\n");
         }
 
         $compiler
-            ->subcompile($this->getNode('display_end'))
             ->outdent()
             ->write("}\n\n")
         ;
@@ -355,7 +379,10 @@ final class ModuleNode extends Node
     protected function compileGetTemplateName(Compiler $compiler)
     {
         $compiler
-            ->write("public function getTemplateName()\n", "{\n")
+            ->write("/**\n")
+            ->write(" * @codeCoverageIgnore\n")
+            ->write(" */\n")
+            ->write("public function getTemplateName(): string\n", "{\n")
             ->indent()
             ->write('return ')
             ->repr($this->getSourceContext()->getName())
@@ -377,7 +404,7 @@ final class ModuleNode extends Node
         $traitable = !$this->hasNode('parent') && 0 === \count($this->getNode('macros'));
         if ($traitable) {
             if ($this->getNode('body') instanceof BodyNode) {
-                $nodes = $this->getNode('body')->getNode(0);
+                $nodes = $this->getNode('body')->getNode('0');
             } else {
                 $nodes = $this->getNode('body');
             }
@@ -391,14 +418,6 @@ final class ModuleNode extends Node
                     continue;
                 }
 
-                if ($node instanceof TextNode && ctype_space($node->getAttribute('data'))) {
-                    continue;
-                }
-
-                if ($node instanceof BlockReferenceNode) {
-                    continue;
-                }
-
                 $traitable = false;
                 break;
             }
@@ -409,9 +428,12 @@ final class ModuleNode extends Node
         }
 
         $compiler
-            ->write("public function isTraitable()\n", "{\n")
+            ->write("/**\n")
+            ->write(" * @codeCoverageIgnore\n")
+            ->write(" */\n")
+            ->write("public function isTraitable(): bool\n", "{\n")
             ->indent()
-            ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
+            ->write("return false;\n")
             ->outdent()
             ->write("}\n\n")
         ;
@@ -420,9 +442,12 @@ final class ModuleNode extends Node
     protected function compileDebugInfo(Compiler $compiler)
     {
         $compiler
-            ->write("public function getDebugInfo()\n", "{\n")
+            ->write("/**\n")
+            ->write(" * @codeCoverageIgnore\n")
+            ->write(" */\n")
+            ->write("public function getDebugInfo(): array\n", "{\n")
             ->indent()
-            ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
+            ->write(\sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
             ->outdent()
             ->write("}\n\n")
         ;
@@ -431,7 +456,7 @@ final class ModuleNode extends Node
     protected function compileGetSourceContext(Compiler $compiler)
     {
         $compiler
-            ->write("public function getSourceContext()\n", "{\n")
+            ->write("public function getSourceContext(): Source\n", "{\n")
             ->indent()
             ->write('return new Source(')
             ->string($compiler->getEnvironment()->isDebug() ? $this->getSourceContext()->getCode() : '')
@@ -449,7 +474,7 @@ final class ModuleNode extends Node
     {
         if ($node instanceof ConstantExpression) {
             $compiler
-                ->write(sprintf('%s = $this->loadTemplate(', $var))
+                ->write(\sprintf('%s = $this->loadTemplate(', $var))
                 ->subcompile($node)
                 ->raw(', ')
                 ->repr($node->getTemplateName())
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/NameDeprecation.php b/data/web/inc/lib/vendor/twig/twig/src/Node/NameDeprecation.php
new file mode 100644
index 00000000..63ab2857
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/NameDeprecation.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Node;
+
+/**
+ * Represents a deprecation for a named node or attribute on a Node.
+ *
+ * @author Fabien Potencier <[email protected]>
+ */
+class NameDeprecation
+{
+    private $package;
+    private $version;
+    private $newName;
+
+    public function __construct(string $package = '', string $version = '', string $newName = '')
+    {
+        $this->package = $package;
+        $this->version = $version;
+        $this->newName = $newName;
+    }
+
+    public function getPackage(): string
+    {
+        return $this->package;
+    }
+
+    public function getVersion(): string
+    {
+        return $this->version;
+    }
+
+    public function getNewName(): string
+    {
+        return $this->newName;
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/Node.php b/data/web/inc/lib/vendor/twig/twig/src/Node/Node.php
index c0558b9a..2ccbcf61 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/Node.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/Node.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Source;
 
@@ -20,61 +21,82 @@ use Twig\Source;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class Node implements \Countable, \IteratorAggregate
 {
+    /**
+     * @var array<string|int, Node>
+     */
     protected $nodes;
     protected $attributes;
     protected $lineno;
     protected $tag;
 
-    private $name;
     private $sourceContext;
+    /** @var array<string, NameDeprecation> */
+    private $nodeNameDeprecations = [];
+    /** @var array<string, NameDeprecation> */
+    private $attributeNameDeprecations = [];
 
     /**
-     * @param array  $nodes      An array of named nodes
-     * @param array  $attributes An array of attributes (should not be nodes)
-     * @param int    $lineno     The line number
-     * @param string $tag        The tag name associated with the Node
+     * @param array<string|int, Node> $nodes      An array of named nodes
+     * @param array                   $attributes An array of attributes (should not be nodes)
+     * @param int                     $lineno     The line number
      */
-    public function __construct(array $nodes = [], array $attributes = [], int $lineno = 0, string $tag = null)
+    public function __construct(array $nodes = [], array $attributes = [], int $lineno = 0)
     {
         foreach ($nodes as $name => $node) {
             if (!$node instanceof self) {
-                throw new \InvalidArgumentException(sprintf('Using "%s" for the value of node "%s" of "%s" is not supported. You must pass a \Twig\Node\Node instance.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, static::class));
+                throw new \InvalidArgumentException(\sprintf('Using "%s" for the value of node "%s" of "%s" is not supported. You must pass a \Twig\Node\Node instance.', \is_object($node) ? $node::class : (null === $node ? 'null' : \gettype($node)), $name, static::class));
             }
         }
         $this->nodes = $nodes;
         $this->attributes = $attributes;
         $this->lineno = $lineno;
-        $this->tag = $tag;
+
+        if (\func_num_args() > 3) {
+            trigger_deprecation('twig/twig', '3.12', \sprintf('The "tag" constructor argument of the "%s" class is deprecated and ignored (check which TokenParser class set it to "%s"), the tag is now automatically set by the Parser when needed.', static::class, func_get_arg(3) ?: 'null'));
+        }
     }
 
     public function __toString()
     {
+        $repr = static::class;
+
+        if ($this->tag) {
+            $repr .= \sprintf("\n  tag: %s", $this->tag);
+        }
+
         $attributes = [];
         foreach ($this->attributes as $name => $value) {
-            $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
+            if (\is_callable($value)) {
+                $v = '\Closure';
+            } elseif ($value instanceof \Stringable) {
+                $v = (string) $value;
+            } else {
+                $v = str_replace("\n", '', var_export($value, true));
+            }
+            $attributes[] = \sprintf('%s: %s', $name, $v);
         }
 
-        $repr = [static::class.'('.implode(', ', $attributes)];
+        if ($attributes) {
+            $repr .= \sprintf("\n  attributes:\n    %s", implode("\n    ", $attributes));
+        }
 
         if (\count($this->nodes)) {
+            $repr .= "\n  nodes:";
             foreach ($this->nodes as $name => $node) {
-                $len = \strlen($name) + 4;
+                $len = \strlen($name) + 6;
                 $noderepr = [];
                 foreach (explode("\n", (string) $node) as $line) {
                     $noderepr[] = str_repeat(' ', $len).$line;
                 }
 
-                $repr[] = sprintf('  %s: %s', $name, ltrim(implode("\n", $noderepr)));
+                $repr .= \sprintf("\n    %s: %s", $name, ltrim(implode("\n", $noderepr)));
             }
-
-            $repr[] = ')';
-        } else {
-            $repr[0] .= ')';
         }
 
-        return implode("\n", $repr);
+        return $repr;
     }
 
     /**
@@ -83,7 +105,7 @@ class Node implements \Countable, \IteratorAggregate
     public function compile(Compiler $compiler)
     {
         foreach ($this->nodes as $node) {
-            $node->compile($compiler);
+            $compiler->subcompile($node);
         }
     }
 
@@ -97,6 +119,18 @@ class Node implements \Countable, \IteratorAggregate
         return $this->tag;
     }
 
+    /**
+     * @internal
+     */
+    public function setNodeTag(string $tag): void
+    {
+        if ($this->tag) {
+            throw new \LogicException('The tag of a node can only be set once.');
+        }
+
+        $this->tag = $tag;
+    }
+
     public function hasAttribute(string $name): bool
     {
         return \array_key_exists($name, $this->attributes);
@@ -105,7 +139,17 @@ class Node implements \Countable, \IteratorAggregate
     public function getAttribute(string $name)
     {
         if (!\array_key_exists($name, $this->attributes)) {
-            throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, static::class));
+            throw new \LogicException(\sprintf('Attribute "%s" does not exist for Node "%s".', $name, static::class));
+        }
+
+        $triggerDeprecation = \func_num_args() > 1 ? func_get_arg(1) : true;
+        if ($triggerDeprecation && isset($this->attributeNameDeprecations[$name])) {
+            $dep = $this->attributeNameDeprecations[$name];
+            if ($dep->getNewName()) {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting attribute "%s" on a "%s" class is deprecated, get the "%s" attribute instead.', $name, static::class, $dep->getNewName());
+            } else {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting attribute "%s" on a "%s" class is deprecated.', $name, static::class);
+            }
         }
 
         return $this->attributes[$name];
@@ -113,38 +157,96 @@ class Node implements \Countable, \IteratorAggregate
 
     public function setAttribute(string $name, $value): void
     {
+        $triggerDeprecation = \func_num_args() > 2 ? func_get_arg(2) : true;
+        if ($triggerDeprecation && isset($this->attributeNameDeprecations[$name])) {
+            $dep = $this->attributeNameDeprecations[$name];
+            if ($dep->getNewName()) {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting attribute "%s" on a "%s" class is deprecated, set the "%s" attribute instead.', $name, static::class, $dep->getNewName());
+            } else {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting attribute "%s" on a "%s" class is deprecated.', $name, static::class);
+            }
+        }
+
         $this->attributes[$name] = $value;
     }
 
+    public function deprecateAttribute(string $name, NameDeprecation $dep): void
+    {
+        $this->attributeNameDeprecations[$name] = $dep;
+    }
+
     public function removeAttribute(string $name): void
     {
         unset($this->attributes[$name]);
     }
 
+    /**
+     * @param string|int $name
+     */
     public function hasNode(string $name): bool
     {
         return isset($this->nodes[$name]);
     }
 
+    /**
+     * @param string|int $name
+     */
     public function getNode(string $name): self
     {
         if (!isset($this->nodes[$name])) {
-            throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, static::class));
+            throw new \LogicException(\sprintf('Node "%s" does not exist for Node "%s".', $name, static::class));
+        }
+
+        $triggerDeprecation = \func_num_args() > 1 ? func_get_arg(1) : true;
+        if ($triggerDeprecation && isset($this->nodeNameDeprecations[$name])) {
+            $dep = $this->nodeNameDeprecations[$name];
+            if ($dep->getNewName()) {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting node "%s" on a "%s" class is deprecated, get the "%s" node instead.', $name, static::class, $dep->getNewName());
+            } else {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Getting node "%s" on a "%s" class is deprecated.', $name, static::class);
+            }
         }
 
         return $this->nodes[$name];
     }
 
+    /**
+     * @param string|int $name
+     */
     public function setNode(string $name, self $node): void
     {
+        $triggerDeprecation = \func_num_args() > 2 ? func_get_arg(2) : true;
+        if ($triggerDeprecation && isset($this->nodeNameDeprecations[$name])) {
+            $dep = $this->nodeNameDeprecations[$name];
+            if ($dep->getNewName()) {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting node "%s" on a "%s" class is deprecated, set the "%s" node instead.', $name, static::class, $dep->getNewName());
+            } else {
+                trigger_deprecation($dep->getPackage(), $dep->getVersion(), 'Setting node "%s" on a "%s" class is deprecated.', $name, static::class);
+            }
+        }
+
+        if (null !== $this->sourceContext) {
+            $node->setSourceContext($this->sourceContext);
+        }
         $this->nodes[$name] = $node;
     }
 
+    /**
+     * @param string|int $name
+     */
     public function removeNode(string $name): void
     {
         unset($this->nodes[$name]);
     }
 
+    /**
+     * @param string|int $name
+     */
+    public function deprecateNode(string $name, NameDeprecation $dep): void
+    {
+        $this->nodeNameDeprecations[$name] = $dep;
+    }
+
     /**
      * @return int
      */
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/PrintNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/PrintNode.php
index 60386d29..e3c23bbf 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/PrintNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/PrintNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\AbstractExpression;
 
@@ -20,19 +21,23 @@ use Twig\Node\Expression\AbstractExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class PrintNode extends Node implements NodeOutputInterface
 {
-    public function __construct(AbstractExpression $expr, int $lineno, string $tag = null)
+    public function __construct(AbstractExpression $expr, int $lineno)
     {
-        parent::__construct(['expr' => $expr], [], $lineno, $tag);
+        parent::__construct(['expr' => $expr], [], $lineno);
     }
 
     public function compile(Compiler $compiler): void
     {
+        /** @var AbstractExpression */
+        $expr = $this->getNode('expr');
+
         $compiler
             ->addDebugInfo($this)
-            ->write('echo ')
-            ->subcompile($this->getNode('expr'))
+            ->write($expr->isGenerator() ? 'yield from ' : 'yield ')
+            ->subcompile($expr)
             ->raw(";\n")
         ;
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/SandboxNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/SandboxNode.php
index 4d5666bf..d51cea44 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/SandboxNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/SandboxNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -18,11 +19,12 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class SandboxNode extends Node
 {
-    public function __construct(Node $body, int $lineno, string $tag = null)
+    public function __construct(Node $body, int $lineno)
     {
-        parent::__construct(['body' => $body], [], $lineno, $tag);
+        parent::__construct(['body' => $body], [], $lineno);
     }
 
     public function compile(Compiler $compiler): void
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/SetNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/SetNode.php
index 96b6bd8b..67725104 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/SetNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/SetNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Expression\ConstantExpression;
 
@@ -19,26 +20,28 @@ use Twig\Node\Expression\ConstantExpression;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class SetNode extends Node implements NodeCaptureInterface
 {
-    public function __construct(bool $capture, Node $names, Node $values, int $lineno, string $tag = null)
+    public function __construct(bool $capture, Node $names, Node $values, int $lineno)
     {
-        parent::__construct(['names' => $names, 'values' => $values], ['capture' => $capture, 'safe' => false], $lineno, $tag);
-
         /*
          * Optimizes the node when capture is used for a large block of text.
          *
          * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig\Markup("foo");
          */
-        if ($this->getAttribute('capture')) {
-            $this->setAttribute('safe', true);
-
-            $values = $this->getNode('values');
+        $safe = false;
+        if ($capture) {
+            $safe = true;
             if ($values instanceof TextNode) {
-                $this->setNode('values', new ConstantExpression($values->getAttribute('data'), $values->getTemplateLine()));
-                $this->setAttribute('capture', false);
+                $values = new ConstantExpression($values->getAttribute('data'), $values->getTemplateLine());
+                $capture = false;
+            } else {
+                $values = new CaptureNode($values, $values->getTemplateLine());
             }
         }
+
+        parent::__construct(['names' => $names, 'values' => $values], ['capture' => $capture, 'safe' => $safe], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -46,7 +49,7 @@ class SetNode extends Node implements NodeCaptureInterface
         $compiler->addDebugInfo($this);
 
         if (\count($this->getNode('names')) > 1) {
-            $compiler->write('list(');
+            $compiler->write('[');
             foreach ($this->getNode('names') as $idx => $node) {
                 if ($idx) {
                     $compiler->raw(', ');
@@ -54,29 +57,15 @@ class SetNode extends Node implements NodeCaptureInterface
 
                 $compiler->subcompile($node);
             }
-            $compiler->raw(')');
+            $compiler->raw(']');
         } else {
-            if ($this->getAttribute('capture')) {
-                if ($compiler->getEnvironment()->isDebug()) {
-                    $compiler->write("ob_start();\n");
-                } else {
-                    $compiler->write("ob_start(function () { return ''; });\n");
-                }
-                $compiler
-                    ->subcompile($this->getNode('values'))
-                ;
-            }
-
             $compiler->subcompile($this->getNode('names'), false);
-
-            if ($this->getAttribute('capture')) {
-                $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Markup(\$tmp, \$this->env->getCharset())");
-            }
         }
+        $compiler->raw(' = ');
 
-        if (!$this->getAttribute('capture')) {
-            $compiler->raw(' = ');
-
+        if ($this->getAttribute('capture')) {
+            $compiler->subcompile($this->getNode('values'));
+        } else {
             if (\count($this->getNode('names')) > 1) {
                 $compiler->write('[');
                 foreach ($this->getNode('values') as $idx => $value) {
@@ -98,8 +87,10 @@ class SetNode extends Node implements NodeCaptureInterface
                     $compiler->subcompile($this->getNode('values'));
                 }
             }
+
+            $compiler->raw(';');
         }
 
-        $compiler->raw(";\n");
+        $compiler->raw("\n");
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/TextNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/TextNode.php
index d74ebe63..fae65fb2 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/TextNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/TextNode.php
@@ -12,6 +12,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -19,6 +20,7 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class TextNode extends Node implements NodeOutputInterface
 {
     public function __construct(string $data, int $lineno)
@@ -28,9 +30,10 @@ class TextNode extends Node implements NodeOutputInterface
 
     public function compile(Compiler $compiler): void
     {
+        $compiler->addDebugInfo($this);
+
         $compiler
-            ->addDebugInfo($this)
-            ->write('echo ')
+            ->write('yield ')
             ->string($this->getAttribute('data'))
             ->raw(";\n")
         ;
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/TypesNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/TypesNode.php
new file mode 100644
index 00000000..ebb304d4
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/TypesNode.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Twig\Node;
+
+use Twig\Attribute\YieldReady;
+use Twig\Compiler;
+
+/**
+ * Represents a types node.
+ *
+ * @author Jeroen Versteeg <[email protected]>
+ */
+#[YieldReady]
+class TypesNode extends Node
+{
+    /**
+     * @param array<string, array{type: string, optional: bool}> $types
+     */
+    public function __construct(array $types, int $lineno)
+    {
+        parent::__construct([], ['mapping' => $types], $lineno);
+    }
+
+    public function compile(Compiler $compiler)
+    {
+        // Don't compile anything.
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Node/WithNode.php b/data/web/inc/lib/vendor/twig/twig/src/Node/WithNode.php
index 56a33449..487e2800 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Node/WithNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Node/WithNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 
 /**
@@ -18,16 +19,17 @@ use Twig\Compiler;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class WithNode extends Node
 {
-    public function __construct(Node $body, ?Node $variables, bool $only, int $lineno, string $tag = null)
+    public function __construct(Node $body, ?Node $variables, bool $only, int $lineno)
     {
         $nodes = ['body' => $body];
         if (null !== $variables) {
             $nodes['variables'] = $variables;
         }
 
-        parent::__construct($nodes, ['only' => $only], $lineno, $tag);
+        parent::__construct($nodes, ['only' => $only], $lineno);
     }
 
     public function compile(Compiler $compiler): void
@@ -36,35 +38,35 @@ class WithNode extends Node
 
         $parentContextName = $compiler->getVarName();
 
-        $compiler->write(sprintf("\$%s = \$context;\n", $parentContextName));
+        $compiler->write(\sprintf("\$%s = \$context;\n", $parentContextName));
 
         if ($this->hasNode('variables')) {
             $node = $this->getNode('variables');
             $varsName = $compiler->getVarName();
             $compiler
-                ->write(sprintf('$%s = ', $varsName))
+                ->write(\sprintf('$%s = ', $varsName))
                 ->subcompile($node)
                 ->raw(";\n")
-                ->write(sprintf("if (!twig_test_iterable(\$%s)) {\n", $varsName))
+                ->write(\sprintf("if (!is_iterable(\$%s)) {\n", $varsName))
                 ->indent()
-                ->write("throw new RuntimeError('Variables passed to the \"with\" tag must be a hash.', ")
+                ->write("throw new RuntimeError('Variables passed to the \"with\" tag must be a mapping.', ")
                 ->repr($node->getTemplateLine())
                 ->raw(", \$this->getSourceContext());\n")
                 ->outdent()
                 ->write("}\n")
-                ->write(sprintf("\$%s = twig_to_array(\$%s);\n", $varsName, $varsName))
+                ->write(\sprintf("\$%s = CoreExtension::toArray(\$%s);\n", $varsName, $varsName))
             ;
 
             if ($this->getAttribute('only')) {
                 $compiler->write("\$context = [];\n");
             }
 
-            $compiler->write(sprintf("\$context = \$this->env->mergeGlobals(array_merge(\$context, \$%s));\n", $varsName));
+            $compiler->write(\sprintf("\$context = \$%s + \$context + \$this->env->getGlobals();\n", $varsName));
         }
 
         $compiler
             ->subcompile($this->getNode('body'))
-            ->write(sprintf("\$context = \$%s;\n", $parentContextName))
+            ->write(\sprintf("\$context = \$%s;\n", $parentContextName))
         ;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/AbstractNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/AbstractNodeVisitor.php
index d7036ae5..5de35fd0 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/AbstractNodeVisitor.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/AbstractNodeVisitor.php
@@ -17,9 +17,9 @@ use Twig\Node\Node;
 /**
  * Used to make node visitors compatible with Twig 1.x and 2.x.
  *
- * To be removed in Twig 3.1.
- *
  * @author Fabien Potencier <[email protected]>
+ *
+ * @deprecated since 3.9 (to be removed in 4.0)
  */
 abstract class AbstractNodeVisitor implements NodeVisitorInterface
 {
diff --git a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php
index fe56ea30..32f49ab1 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php
@@ -57,7 +57,7 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
         } elseif ($node instanceof AutoEscapeNode) {
             $this->statusStack[] = $node->getAttribute('value');
         } elseif ($node instanceof BlockNode) {
-            $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env);
+            $this->statusStack[] = $this->blocks[$node->getAttribute('name')] ?? $this->needEscaping();
         } elseif ($node instanceof ImportNode) {
             $this->safeVars[] = $node->getNode('var')->getAttribute('name');
         }
@@ -73,7 +73,7 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
             $this->blocks = [];
         } elseif ($node instanceof FilterExpression) {
             return $this->preEscapeFilterNode($node, $env);
-        } elseif ($node instanceof PrintNode && false !== $type = $this->needEscaping($env)) {
+        } elseif ($node instanceof PrintNode && false !== $type = $this->needEscaping()) {
             $expression = $node->getNode('expr');
             if ($expression instanceof ConditionalExpression && $this->shouldUnwrapConditional($expression, $env, $type)) {
                 return new DoNode($this->unwrapConditional($expression, $env, $type), $expression->getTemplateLine());
@@ -85,7 +85,7 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
         if ($node instanceof AutoEscapeNode || $node instanceof BlockNode) {
             array_pop($this->statusStack);
         } elseif ($node instanceof BlockReferenceNode) {
-            $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env);
+            $this->blocks[$node->getAttribute('name')] = $this->needEscaping();
         }
 
         return $node;
@@ -126,15 +126,11 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
             return $node;
         }
 
-        return new InlinePrint($this->getEscaperFilter($type, $expression), $node->getTemplateLine());
+        return new InlinePrint($this->getEscaperFilter($env, $type, $expression), $node->getTemplateLine());
     }
 
     private function escapePrintNode(PrintNode $node, Environment $env, string $type): Node
     {
-        if (false === $type) {
-            return $node;
-        }
-
         $expression = $node->getNode('expr');
 
         if ($this->isSafeFor($type, $expression, $env)) {
@@ -143,14 +139,19 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
 
         $class = \get_class($node);
 
-        return new $class($this->getEscaperFilter($type, $expression), $node->getTemplateLine());
+        return new $class($this->getEscaperFilter($env, $type, $expression), $node->getTemplateLine());
     }
 
     private function preEscapeFilterNode(FilterExpression $filter, Environment $env): FilterExpression
     {
-        $name = $filter->getNode('filter')->getAttribute('value');
+        if ($filter->hasAttribute('twig_callable')) {
+            $type = $filter->getAttribute('twig_callable')->getPreEscape();
+        } else {
+            // legacy
+            $name = $filter->getNode('filter', false)->getAttribute('value');
+            $type = $env->getFilter($name)->getPreEscape();
+        }
 
-        $type = $env->getFilter($name)->getPreEscape();
         if (null === $type) {
             return $filter;
         }
@@ -160,7 +161,7 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
             return $filter;
         }
 
-        $filter->setNode('node', $this->getEscaperFilter($type, $node));
+        $filter->setNode('node', $this->getEscaperFilter($env, $type, $node));
 
         return $filter;
     }
@@ -183,22 +184,22 @@ final class EscaperNodeVisitor implements NodeVisitorInterface
         return \in_array($type, $safe) || \in_array('all', $safe);
     }
 
-    private function needEscaping(Environment $env)
+    private function needEscaping()
     {
         if (\count($this->statusStack)) {
             return $this->statusStack[\count($this->statusStack) - 1];
         }
 
-        return $this->defaultStrategy ? $this->defaultStrategy : false;
+        return $this->defaultStrategy ?: false;
     }
 
-    private function getEscaperFilter(string $type, Node $node): FilterExpression
+    private function getEscaperFilter(Environment $env, string $type, Node $node): FilterExpression
     {
         $line = $node->getTemplateLine();
-        $name = new ConstantExpression('escape', $line);
+        $filter = $env->getFilter('escape');
         $args = new Node([new ConstantExpression($type, $line), new ConstantExpression(null, $line), new ConstantExpression(true, $line)]);
 
-        return new FilterExpression($node, $name, $args, $line);
+        return new FilterExpression($node, $filter, $args, $line);
     }
 
     public function getPriority(): int
diff --git a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/MacroAutoImportNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/MacroAutoImportNodeVisitor.php
index af477e65..01d5a997 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/MacroAutoImportNodeVisitor.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/MacroAutoImportNodeVisitor.php
@@ -46,14 +46,14 @@ final class MacroAutoImportNodeVisitor implements NodeVisitorInterface
         if ($node instanceof ModuleNode) {
             $this->inAModule = false;
             if ($this->hasMacroCalls) {
-                $node->getNode('constructor_end')->setNode('_auto_macro_import', new ImportNode(new NameExpression('_self', 0), new AssignNameExpression('_self', 0), 0, 'import', true));
+                $node->getNode('constructor_end')->setNode('_auto_macro_import', new ImportNode(new NameExpression('_self', 0), new AssignNameExpression('_self', 0), 0, true));
             }
         } elseif ($this->inAModule) {
             if (
-                $node instanceof GetAttrExpression &&
-                $node->getNode('node') instanceof NameExpression &&
-                '_self' === $node->getNode('node')->getAttribute('name') &&
-                $node->getNode('attribute') instanceof ConstantExpression
+                $node instanceof GetAttrExpression
+                && $node->getNode('node') instanceof NameExpression
+                && '_self' === $node->getNode('node')->getAttribute('name')
+                && $node->getNode('attribute') instanceof ConstantExpression
             ) {
                 $this->hasMacroCalls = true;
 
diff --git a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php
index 7ac75e41..a943f45c 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php
@@ -15,7 +15,6 @@ use Twig\Environment;
 use Twig\Node\BlockReferenceNode;
 use Twig\Node\Expression\BlockReferenceExpression;
 use Twig\Node\Expression\ConstantExpression;
-use Twig\Node\Expression\FilterExpression;
 use Twig\Node\Expression\FunctionExpression;
 use Twig\Node\Expression\GetAttrExpression;
 use Twig\Node\Expression\NameExpression;
@@ -24,6 +23,7 @@ use Twig\Node\ForNode;
 use Twig\Node\IncludeNode;
 use Twig\Node\Node;
 use Twig\Node\PrintNode;
+use Twig\Node\TextNode;
 
 /**
  * Tries to optimize the AST.
@@ -43,27 +43,34 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
     public const OPTIMIZE_NONE = 0;
     public const OPTIMIZE_FOR = 2;
     public const OPTIMIZE_RAW_FILTER = 4;
+    public const OPTIMIZE_TEXT_NODES = 8;
 
     private $loops = [];
     private $loopsTargets = [];
-    private $optimizers;
 
     /**
      * @param int $optimizers The optimizer mode
      */
-    public function __construct(int $optimizers = -1)
-    {
-        if ($optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER)) {
-            throw new \InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
+    public function __construct(
+        private int $optimizers = -1,
+    ) {
+        if ($optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_TEXT_NODES)) {
+            throw new \InvalidArgumentException(\sprintf('Optimizer mode "%s" is not valid.', $optimizers));
+        }
+
+        if (-1 !== $optimizers && self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $optimizers)) {
+            trigger_deprecation('twig/twig', '3.11', 'The "Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_RAW_FILTER" option is deprecated and does nothing.');
         }
 
-        $this->optimizers = $optimizers;
+        if (-1 !== $optimizers && self::OPTIMIZE_TEXT_NODES === (self::OPTIMIZE_TEXT_NODES & $optimizers)) {
+            trigger_deprecation('twig/twig', '3.12', 'The "Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_TEXT_NODES" option is deprecated and does nothing.');
+        }
     }
 
     public function enterNode(Node $node, Environment $env): Node
     {
         if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
-            $this->enterOptimizeFor($node, $env);
+            $this->enterOptimizeFor($node);
         }
 
         return $node;
@@ -72,14 +79,10 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
     public function leaveNode(Node $node, Environment $env): ?Node
     {
         if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
-            $this->leaveOptimizeFor($node, $env);
+            $this->leaveOptimizeFor($node);
         }
 
-        if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
-            $node = $this->optimizeRawFilter($node, $env);
-        }
-
-        $node = $this->optimizePrintNode($node, $env);
+        $node = $this->optimizePrintNode($node);
 
         return $node;
     }
@@ -91,16 +94,21 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
      *
      *   * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
      */
-    private function optimizePrintNode(Node $node, Environment $env): Node
+    private function optimizePrintNode(Node $node): Node
     {
         if (!$node instanceof PrintNode) {
             return $node;
         }
 
         $exprNode = $node->getNode('expr');
+
+        if ($exprNode instanceof ConstantExpression && \is_string($exprNode->getAttribute('value'))) {
+            return new TextNode($exprNode->getAttribute('value'), $exprNode->getTemplateLine());
+        }
+
         if (
-            $exprNode instanceof BlockReferenceExpression ||
-            $exprNode instanceof ParentExpression
+            $exprNode instanceof BlockReferenceExpression
+            || $exprNode instanceof ParentExpression
         ) {
             $exprNode->setAttribute('output', true);
 
@@ -110,22 +118,10 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
         return $node;
     }
 
-    /**
-     * Removes "raw" filters.
-     */
-    private function optimizeRawFilter(Node $node, Environment $env): Node
-    {
-        if ($node instanceof FilterExpression && 'raw' == $node->getNode('filter')->getAttribute('value')) {
-            return $node->getNode('node');
-        }
-
-        return $node;
-    }
-
     /**
      * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
      */
-    private function enterOptimizeFor(Node $node, Environment $env): void
+    private function enterOptimizeFor(Node $node): void
     {
         if ($node instanceof ForNode) {
             // disable the loop variable by default
@@ -166,7 +162,7 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
             && 'include' === $node->getAttribute('name')
             && (!$node->getNode('arguments')->hasNode('with_context')
                  || false !== $node->getNode('arguments')->getNode('with_context')->getAttribute('value')
-               )
+            )
         ) {
             $this->addLoopToAll();
         }
@@ -175,12 +171,12 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
         elseif ($node instanceof GetAttrExpression
             && (!$node->getNode('attribute') instanceof ConstantExpression
                 || 'parent' === $node->getNode('attribute')->getAttribute('value')
-               )
+            )
             && (true === $this->loops[0]->getAttribute('with_loop')
-                || ($node->getNode('node') instanceof NameExpression
-                    && 'loop' === $node->getNode('node')->getAttribute('name')
-                   )
-               )
+             || ($node->getNode('node') instanceof NameExpression
+                 && 'loop' === $node->getNode('node')->getAttribute('name')
+             )
+            )
         ) {
             $this->addLoopToAll();
         }
@@ -189,7 +185,7 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
     /**
      * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
      */
-    private function leaveOptimizeFor(Node $node, Environment $env): void
+    private function leaveOptimizeFor(Node $node): void
     {
         if ($node instanceof ForNode) {
             array_shift($this->loops);
diff --git a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php
index 90d6f2e0..07672164 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php
@@ -96,10 +96,15 @@ final class SafeAnalysisNodeVisitor implements NodeVisitorInterface
             $this->setSafe($node, $safe);
         } elseif ($node instanceof FilterExpression) {
             // filter expression is safe when the filter is safe
-            $name = $node->getNode('filter')->getAttribute('value');
-            $args = $node->getNode('arguments');
-            if ($filter = $env->getFilter($name)) {
-                $safe = $filter->getSafe($args);
+            if ($node->hasAttribute('twig_callable')) {
+                $filter = $node->getAttribute('twig_callable');
+            } else {
+                // legacy
+                $filter = $env->getFilter($node->getAttribute('name'));
+            }
+
+            if ($filter) {
+                $safe = $filter->getSafe($node->getNode('arguments'));
                 if (null === $safe) {
                     $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety());
                 }
@@ -109,10 +114,15 @@ final class SafeAnalysisNodeVisitor implements NodeVisitorInterface
             }
         } elseif ($node instanceof FunctionExpression) {
             // function expression is safe when the function is safe
-            $name = $node->getAttribute('name');
-            $args = $node->getNode('arguments');
-            if ($function = $env->getFunction($name)) {
-                $this->setSafe($node, $function->getSafe($args));
+            if ($node->hasAttribute('twig_callable')) {
+                $function = $node->getAttribute('twig_callable');
+            } else {
+                // legacy
+                $function = $env->getFunction($node->getAttribute('name'));
+            }
+
+            if ($function) {
+                $this->setSafe($node, $function->getSafe($node->getNode('arguments')));
             } else {
                 $this->setSafe($node, []);
             }
@@ -136,7 +146,7 @@ final class SafeAnalysisNodeVisitor implements NodeVisitorInterface
         return $node;
     }
 
-    private function intersectSafe(array $a = null, array $b = null): array
+    private function intersectSafe(?array $a = null, ?array $b = null): array
     {
         if (null === $a || null === $b) {
             return [];
diff --git a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php
index 1446cee6..37e184a3 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php
@@ -34,8 +34,11 @@ use Twig\Node\SetNode;
 final class SandboxNodeVisitor implements NodeVisitorInterface
 {
     private $inAModule = false;
+    /** @var array<string, int> */
     private $tags;
+    /** @var array<string, int> */
     private $filters;
+    /** @var array<string, int> */
     private $functions;
     private $needsToStringWrap = false;
 
@@ -51,22 +54,22 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
         } elseif ($this->inAModule) {
             // look for tags
             if ($node->getNodeTag() && !isset($this->tags[$node->getNodeTag()])) {
-                $this->tags[$node->getNodeTag()] = $node;
+                $this->tags[$node->getNodeTag()] = $node->getTemplateLine();
             }
 
             // look for filters
-            if ($node instanceof FilterExpression && !isset($this->filters[$node->getNode('filter')->getAttribute('value')])) {
-                $this->filters[$node->getNode('filter')->getAttribute('value')] = $node;
+            if ($node instanceof FilterExpression && !isset($this->filters[$node->getAttribute('name')])) {
+                $this->filters[$node->getAttribute('name')] = $node->getTemplateLine();
             }
 
             // look for functions
             if ($node instanceof FunctionExpression && !isset($this->functions[$node->getAttribute('name')])) {
-                $this->functions[$node->getAttribute('name')] = $node;
+                $this->functions[$node->getAttribute('name')] = $node->getTemplateLine();
             }
 
             // the .. operator is equivalent to the range() function
             if ($node instanceof RangeBinary && !isset($this->functions['range'])) {
-                $this->functions['range'] = $node;
+                $this->functions['range'] = $node->getTemplateLine();
             }
 
             if ($node instanceof PrintNode) {
@@ -116,7 +119,7 @@ final class SandboxNodeVisitor implements NodeVisitorInterface
     private function wrapNode(Node $node, string $name): void
     {
         $expr = $node->getNode($name);
-        if ($expr instanceof NameExpression || $expr instanceof GetAttrExpression) {
+        if (($expr instanceof NameExpression || $expr instanceof GetAttrExpression) && !$expr->isGenerator()) {
             $node->setNode($name, new CheckToStringNode($expr));
         }
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php
new file mode 100644
index 00000000..4b190b41
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\NodeVisitor;
+
+use Twig\Attribute\YieldReady;
+use Twig\Environment;
+use Twig\Node\Expression\AbstractExpression;
+use Twig\Node\Node;
+
+/**
+ * @internal to be removed in Twig 4
+ */
+final class YieldNotReadyNodeVisitor implements NodeVisitorInterface
+{
+    private $yieldReadyNodes = [];
+
+    public function __construct(
+        private bool $useYield,
+    ) {
+    }
+
+    public function enterNode(Node $node, Environment $env): Node
+    {
+        $class = \get_class($node);
+
+        if ($node instanceof AbstractExpression || isset($this->yieldReadyNodes[$class])) {
+            return $node;
+        }
+
+        if (!$this->yieldReadyNodes[$class] = (bool) (new \ReflectionClass($class))->getAttributes(YieldReady::class)) {
+            if ($this->useYield) {
+                throw new \LogicException(\sprintf('You cannot enable the "use_yield" option of Twig as node "%s" is not marked as ready for it; please make it ready and then flag it with the #[YieldReady] attribute.', $class));
+            }
+
+            trigger_deprecation('twig/twig', '3.9', 'Twig node "%s" is not marked as ready for using "yield" instead of "echo"; please make it ready and then flag it with the #[YieldReady] attribute.', $class);
+        }
+
+        return $node;
+    }
+
+    public function leaveNode(Node $node, Environment $env): ?Node
+    {
+        return $node;
+    }
+
+    public function getPriority(): int
+    {
+        return 255;
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Parser.php b/data/web/inc/lib/vendor/twig/twig/src/Parser.php
index 4428208f..40370bb1 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Parser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Parser.php
@@ -25,6 +25,7 @@ use Twig\Node\NodeOutputInterface;
 use Twig\Node\PrintNode;
 use Twig\Node\TextNode;
 use Twig\TokenParser\TokenParserInterface;
+use Twig\Util\ReflectionCallable;
 
 /**
  * @author Fabien Potencier <[email protected]>
@@ -39,20 +40,19 @@ class Parser
     private $blocks;
     private $blockStack;
     private $macros;
-    private $env;
     private $importedSymbols;
     private $traits;
     private $embeddedTemplates = [];
     private $varNameSalt = 0;
 
-    public function __construct(Environment $env)
-    {
-        $this->env = $env;
+    public function __construct(
+        private Environment $env,
+    ) {
     }
 
     public function getVarName(): string
     {
-        return sprintf('__internal_parse_%d', $this->varNameSalt++);
+        return \sprintf('__internal_parse_%d', $this->varNameSalt++);
     }
 
     public function parse(TokenStream $stream, $test = null, bool $dropNeedle = false): ModuleNode
@@ -91,7 +91,7 @@ class Parser
             }
 
             if (!$e->getTemplateLine()) {
-                $e->setTemplateLine($this->stream->getCurrent()->getLine());
+                $e->setTemplateLine($this->getCurrentToken()->getLine());
             }
 
             throw $e;
@@ -101,6 +101,9 @@ class Parser
 
         $traverser = new NodeTraverser($this->env, $this->visitors);
 
+        /**
+         * @var ModuleNode $node
+         */
         $node = $traverser->traverse($node);
 
         // restore previous stack so previous parse() call can resume working
@@ -117,23 +120,23 @@ class Parser
         $rv = [];
         while (!$this->stream->isEOF()) {
             switch ($this->getCurrentToken()->getType()) {
-                case /* Token::TEXT_TYPE */ 0:
+                case Token::TEXT_TYPE:
                     $token = $this->stream->next();
                     $rv[] = new TextNode($token->getValue(), $token->getLine());
                     break;
 
-                case /* Token::VAR_START_TYPE */ 2:
+                case Token::VAR_START_TYPE:
                     $token = $this->stream->next();
                     $expr = $this->expressionParser->parseExpression();
-                    $this->stream->expect(/* Token::VAR_END_TYPE */ 4);
+                    $this->stream->expect(Token::VAR_END_TYPE);
                     $rv[] = new PrintNode($expr, $token->getLine());
                     break;
 
-                case /* Token::BLOCK_START_TYPE */ 1:
+                case Token::BLOCK_START_TYPE:
                     $this->stream->next();
                     $token = $this->getCurrentToken();
 
-                    if (/* Token::NAME_TYPE */ 5 !== $token->getType()) {
+                    if (Token::NAME_TYPE !== $token->getType()) {
                         throw new SyntaxError('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext());
                     }
 
@@ -151,13 +154,14 @@ class Parser
 
                     if (!$subparser = $this->env->getTokenParser($token->getValue())) {
                         if (null !== $test) {
-                            $e = new SyntaxError(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
+                            $e = new SyntaxError(\sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
 
-                            if (\is_array($test) && isset($test[0]) && $test[0] instanceof TokenParserInterface) {
-                                $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno));
+                            $callable = (new ReflectionCallable(new TwigTest('decision', $test)))->getCallable();
+                            if (\is_array($callable) && $callable[0] instanceof TokenParserInterface) {
+                                $e->appendMessage(\sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $callable[0]->getTag(), $lineno));
                             }
                         } else {
-                            $e = new SyntaxError(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
+                            $e = new SyntaxError(\sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
                             $e->addSuggestions($token->getValue(), array_keys($this->env->getTokenParsers()));
                         }
 
@@ -168,13 +172,16 @@ class Parser
 
                     $subparser->setParser($this);
                     $node = $subparser->parse($token);
-                    if (null !== $node) {
+                    if (!$node) {
+                        trigger_deprecation('twig/twig', '3.12', 'Returning "null" from "%s" is deprecated and forbidden by "TokenParserInterface".', $subparser::class);
+                    } else {
+                        $node->setNodeTag($subparser->getTag());
                         $rv[] = $node;
                     }
                     break;
 
                 default:
-                    throw new SyntaxError('Lexer or parser ended up in unsupported state.', $this->getCurrentToken()->getLine(), $this->stream->getSourceContext());
+                    throw new SyntaxError('The lexer or the parser ended up in an unsupported state.', $this->getCurrentToken()->getLine(), $this->stream->getSourceContext());
             }
         }
 
@@ -187,6 +194,8 @@ class Parser
 
     public function getBlockStack(): array
     {
+        trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
+
         return $this->blockStack;
     }
 
@@ -207,21 +216,31 @@ class Parser
 
     public function hasBlock(string $name): bool
     {
+        trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
+
         return isset($this->blocks[$name]);
     }
 
     public function getBlock(string $name): Node
     {
+        trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
+
         return $this->blocks[$name];
     }
 
     public function setBlock(string $name, BlockNode $value): void
     {
+        if (isset($this->blocks[$name])) {
+            throw new SyntaxError(\sprintf("The block '%s' has already been defined line %d.", $name, $this->blocks[$name]->getTemplateLine()), $this->getCurrentToken()->getLine(), $this->blocks[$name]->getSourceContext());
+        }
+
         $this->blocks[$name] = new BodyNode([$value], [], $value->getTemplateLine());
     }
 
     public function hasMacro(string $name): bool
     {
+        trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
+
         return isset($this->macros[$name]);
     }
 
@@ -237,6 +256,8 @@ class Parser
 
     public function hasTraits(): bool
     {
+        trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
+
         return \count($this->traits) > 0;
     }
 
@@ -247,7 +268,7 @@ class Parser
         $this->embeddedTemplates[] = $template;
     }
 
-    public function addImportedSymbol(string $type, string $alias, string $name = null, AbstractExpression $node = null): void
+    public function addImportedSymbol(string $type, string $alias, ?string $name = null, ?AbstractExpression $node = null): void
     {
         $this->importedSymbols[0][$type][$alias] = ['name' => $name, 'node' => $node];
     }
@@ -280,11 +301,26 @@ class Parser
 
     public function getParent(): ?Node
     {
+        trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__);
+
         return $this->parent;
     }
 
+    public function hasInheritance()
+    {
+        return $this->parent || 0 < \count($this->traits);
+    }
+
     public function setParent(?Node $parent): void
     {
+        if (null === $parent) {
+            trigger_deprecation('twig/twig', '3.12', 'Passing "null" to "%s()" is deprecated.', __METHOD__);
+        }
+
+        if (null !== $this->parent) {
+            throw new SyntaxError('Multiple extends tags are forbidden.', $parent->getTemplateLine(), $parent->getSourceContext());
+        }
+
         $this->parent = $parent;
     }
 
@@ -303,10 +339,9 @@ class Parser
         // check that the body does not contain non-empty output nodes
         if (
             ($node instanceof TextNode && !ctype_space($node->getAttribute('data')))
-            ||
-            (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && $node instanceof NodeOutputInterface)
+            || (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && $node instanceof NodeOutputInterface)
         ) {
-            if (false !== strpos((string) $node, \chr(0xEF).\chr(0xBB).\chr(0xBF))) {
+            if (str_contains((string) $node, \chr(0xEF).\chr(0xBB).\chr(0xBF))) {
                 $t = substr($node->getAttribute('data'), 3);
                 if ('' === $t || ctype_space($t)) {
                     // bypass empty nodes starting with a BOM
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BaseDumper.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BaseDumper.php
index 4da43e47..267718c1 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BaseDumper.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BaseDumper.php
@@ -50,7 +50,7 @@ abstract class BaseDumper
         if ($profile->getDuration() * 1000 < 1) {
             $str = $start."\n";
         } else {
-            $str = sprintf("%s %s\n", $start, $this->formatTime($profile, $percent));
+            $str = \sprintf("%s %s\n", $start, $this->formatTime($profile, $percent));
         }
 
         $nCount = \count($profile->getProfiles());
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BlackfireDumper.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BlackfireDumper.php
index 03abe0fa..bb3fbb52 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BlackfireDumper.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/BlackfireDumper.php
@@ -24,7 +24,7 @@ final class BlackfireDumper
         $this->dumpProfile('main()', $profile, $data);
         $this->dumpChildren('main()', $profile, $data);
 
-        $start = sprintf('%f', microtime(true));
+        $start = \sprintf('%f', microtime(true));
         $str = <<<EOF
 file-format: BlackfireProbe
 cost-dimensions: wt mu pmu
@@ -46,9 +46,9 @@ EOF;
             if ($p->isTemplate()) {
                 $name = $p->getTemplate();
             } else {
-                $name = sprintf('%s::%s(%s)', $p->getTemplate(), $p->getType(), $p->getName());
+                $name = \sprintf('%s::%s(%s)', $p->getTemplate(), $p->getType(), $p->getName());
             }
-            $this->dumpProfile(sprintf('%s==>%s', $parent, $name), $p, $data);
+            $this->dumpProfile(\sprintf('%s==>%s', $parent, $name), $p, $data);
             $this->dumpChildren($name, $p, $data);
         }
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/HtmlDumper.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/HtmlDumper.php
index 1f2433b4..cdab2de5 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/HtmlDumper.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/HtmlDumper.php
@@ -32,16 +32,16 @@ final class HtmlDumper extends BaseDumper
 
     protected function formatTemplate(Profile $profile, $prefix): string
     {
-        return sprintf('%sâ”” <span style="background-color: %s">%s</span>', $prefix, self::$colors['template'], $profile->getTemplate());
+        return \sprintf('%sâ”” <span style="background-color: %s">%s</span>', $prefix, self::$colors['template'], $profile->getTemplate());
     }
 
     protected function formatNonTemplate(Profile $profile, $prefix): string
     {
-        return sprintf('%sâ”” %s::%s(<span style="background-color: %s">%s</span>)', $prefix, $profile->getTemplate(), $profile->getType(), isset(self::$colors[$profile->getType()]) ? self::$colors[$profile->getType()] : 'auto', $profile->getName());
+        return \sprintf('%sâ”” %s::%s(<span style="background-color: %s">%s</span>)', $prefix, $profile->getTemplate(), $profile->getType(), self::$colors[$profile->getType()] ?? 'auto', $profile->getName());
     }
 
     protected function formatTime(Profile $profile, $percent): string
     {
-        return sprintf('<span style="color: %s">%.2fms/%.0f%%</span>', $percent > 20 ? self::$colors['big'] : 'auto', $profile->getDuration() * 1000, $percent);
+        return \sprintf('<span style="color: %s">%.2fms/%.0f%%</span>', $percent > 20 ? self::$colors['big'] : 'auto', $profile->getDuration() * 1000, $percent);
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/TextDumper.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/TextDumper.php
index 31561c46..1c1f77e9 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/TextDumper.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Dumper/TextDumper.php
@@ -20,16 +20,16 @@ final class TextDumper extends BaseDumper
 {
     protected function formatTemplate(Profile $profile, $prefix): string
     {
-        return sprintf('%sâ”” %s', $prefix, $profile->getTemplate());
+        return \sprintf('%sâ”” %s', $prefix, $profile->getTemplate());
     }
 
     protected function formatNonTemplate(Profile $profile, $prefix): string
     {
-        return sprintf('%sâ”” %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), $profile->getName());
+        return \sprintf('%sâ”” %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), $profile->getName());
     }
 
     protected function formatTime(Profile $profile, $percent): string
     {
-        return sprintf('%.2fms/%.0f%%', $profile->getDuration() * 1000, $percent);
+        return \sprintf('%.2fms/%.0f%%', $profile->getDuration() * 1000, $percent);
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/EnterProfileNode.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/EnterProfileNode.php
index 1494baf4..4d8e504d 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/EnterProfileNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/EnterProfileNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Profiler\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Node;
 
@@ -19,6 +20,7 @@ use Twig\Node\Node;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class EnterProfileNode extends Node
 {
     public function __construct(string $extensionName, string $type, string $name, string $varName)
@@ -29,10 +31,10 @@ class EnterProfileNode extends Node
     public function compile(Compiler $compiler): void
     {
         $compiler
-            ->write(sprintf('$%s = $this->extensions[', $this->getAttribute('var_name')))
+            ->write(\sprintf('$%s = $this->extensions[', $this->getAttribute('var_name')))
             ->repr($this->getAttribute('extension_name'))
             ->raw("];\n")
-            ->write(sprintf('$%s->enter($%s = new \Twig\Profiler\Profile($this->getTemplateName(), ', $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof'))
+            ->write(\sprintf('$%s->enter($%s = new \Twig\Profiler\Profile($this->getTemplateName(), ', $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof'))
             ->repr($this->getAttribute('type'))
             ->raw(', ')
             ->repr($this->getAttribute('name'))
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/LeaveProfileNode.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/LeaveProfileNode.php
index 94cebbaa..bd9227e5 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/LeaveProfileNode.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Node/LeaveProfileNode.php
@@ -11,6 +11,7 @@
 
 namespace Twig\Profiler\Node;
 
+use Twig\Attribute\YieldReady;
 use Twig\Compiler;
 use Twig\Node\Node;
 
@@ -19,6 +20,7 @@ use Twig\Node\Node;
  *
  * @author Fabien Potencier <[email protected]>
  */
+#[YieldReady]
 class LeaveProfileNode extends Node
 {
     public function __construct(string $varName)
@@ -30,7 +32,7 @@ class LeaveProfileNode extends Node
     {
         $compiler
             ->write("\n")
-            ->write(sprintf("\$%s->leave(\$%s);\n\n", $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof'))
+            ->write(\sprintf("\$%s->leave(\$%s);\n\n", $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof'))
         ;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.php
index 91abee80..1458bc5f 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.php
@@ -27,13 +27,12 @@ use Twig\Profiler\Profile;
  */
 final class ProfilerNodeVisitor implements NodeVisitorInterface
 {
-    private $extensionName;
     private $varName;
 
-    public function __construct(string $extensionName)
-    {
-        $this->extensionName = $extensionName;
-        $this->varName = sprintf('__internal_%s', hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $extensionName));
+    public function __construct(
+        private string $extensionName,
+    ) {
+        $this->varName = \sprintf('__internal_%s', hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $extensionName));
     }
 
     public function enterNode(Node $node, Environment $env): Node
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Profile.php b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Profile.php
index 252ca9b0..2928e164 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Profiler/Profile.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Profiler/Profile.php
@@ -20,19 +20,16 @@ final class Profile implements \IteratorAggregate, \Serializable
     public const BLOCK = 'block';
     public const TEMPLATE = 'template';
     public const MACRO = 'macro';
-
-    private $template;
-    private $name;
-    private $type;
     private $starts = [];
     private $ends = [];
     private $profiles = [];
 
-    public function __construct(string $template = 'main', string $type = self::ROOT, string $name = 'main')
-    {
-        $this->template = $template;
-        $this->type = $type;
-        $this->name = 0 === strpos($name, '__internal_') ? 'INTERNAL' : $name;
+    public function __construct(
+        private string $template = 'main',
+        private string $type = self::ROOT,
+        private string $name = 'main',
+    ) {
+        $this->name = str_starts_with($name, '__internal_') ? 'INTERNAL' : $name;
         $this->enter();
     }
 
@@ -176,6 +173,6 @@ final class Profile implements \IteratorAggregate, \Serializable
      */
     public function __unserialize(array $data): void
     {
-        list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = $data;
+        [$this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles] = $data;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Resources/core.php b/data/web/inc/lib/vendor/twig/twig/src/Resources/core.php
new file mode 100644
index 00000000..6e2fcfb0
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Resources/core.php
@@ -0,0 +1,541 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Twig\Environment;
+use Twig\Extension\CoreExtension;
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_cycle($values, $position)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::cycle($values, $position);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_random(Environment $env, $values = null, $max = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::random($env->getCharset(), $values, $max);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_date_format_filter(Environment $env, $date, $format = null, $timezone = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return $env->getExtension(CoreExtension::class)->formatDate($date, $format, $timezone);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_date_modify_filter(Environment $env, $date, $modifier)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return $env->getExtension(CoreExtension::class)->modifyDate($date, $modifier);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_sprintf($format, ...$values)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::sprintf($format, ...$values);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_date_converter(Environment $env, $date = null, $timezone = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return $env->getExtension(CoreExtension::class)->convertDate($date, $timezone);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_replace_filter($str, $from)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::replace($str, $from);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_round($value, $precision = 0, $method = 'common')
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::round($value, $precision, $method);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_number_format_filter(Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return $env->getExtension(CoreExtension::class)->formatNumber($number, $decimal, $decimalPoint, $thousandSep);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_urlencode_filter($url)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::urlencode($url);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_merge(...$arrays)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::merge(...$arrays);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_slice(Environment $env, $item, $start, $length = null, $preserveKeys = false)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::slice($env->getCharset(), $item, $start, $length, $preserveKeys);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_first(Environment $env, $item)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::first($env->getCharset(), $item);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_last(Environment $env, $item)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::last($env->getCharset(), $item);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_join_filter($value, $glue = '', $and = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::join($value, $glue, $and);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_split_filter(Environment $env, $value, $delimiter, $limit = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::split($env->getCharset(), $value, $delimiter, $limit);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_get_array_keys_filter($array)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::keys($array);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_reverse_filter(Environment $env, $item, $preserveKeys = false)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::reverse($env->getCharset(), $item, $preserveKeys);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_sort_filter(Environment $env, $array, $arrow = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::sort($env, $array, $arrow);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_matches(string $regexp, ?string $str)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::matches($regexp, $str);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_trim_filter($string, $characterMask = null, $side = 'both')
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::trim($string, $characterMask, $side);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_nl2br($string)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::nl2br($string);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_spaceless($content)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::spaceless($content);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_convert_encoding($string, $to, $from)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::convertEncoding($string, $to, $from);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_length_filter(Environment $env, $thing)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::length($env->getCharset(), $thing);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_upper_filter(Environment $env, $string)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::upper($env->getCharset(), $string);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_lower_filter(Environment $env, $string)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::lower($env->getCharset(), $string);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_striptags($string, $allowable_tags = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::striptags($string, $allowable_tags);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_title_string_filter(Environment $env, $string)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::titleCase($env->getCharset(), $string);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_capitalize_string_filter(Environment $env, $string)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::capitalize($env->getCharset(), $string);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_test_empty($value)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::testEmpty($value);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_test_iterable($value)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return is_iterable($value);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_include(Environment $env, $context, $template, $variables = [], $withContext = true, $ignoreMissing = false, $sandboxed = false)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::include($env, $context, $template, $variables, $withContext, $ignoreMissing, $sandboxed);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_source(Environment $env, $name, $ignoreMissing = false)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::source($env, $name, $ignoreMissing);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_constant($constant, $object = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::constant($constant, $object);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_constant_is_defined($constant, $object = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::constant($constant, $object, true);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_batch($items, $size, $fill = null, $preserveKeys = true)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::batch($items, $size, $fill, $preserveKeys);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_column($array, $name, $index = null): array
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::column($array, $name, $index);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_filter(Environment $env, $array, $arrow)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::filter($env, $array, $arrow);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_map(Environment $env, $array, $arrow)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::map($env, $array, $arrow);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_reduce(Environment $env, $array, $arrow, $initial = null)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::reduce($env, $array, $arrow, $initial);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_some(Environment $env, $array, $arrow)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::arraySome($env, $array, $arrow);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_array_every(Environment $env, $array, $arrow)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::arrayEvery($env, $array, $arrow);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_check_arrow_in_sandbox(Environment $env, $arrow, $thing, $type)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return CoreExtension::checkArrowInSandbox($env, $arrow, $thing, $type);
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Resources/debug.php b/data/web/inc/lib/vendor/twig/twig/src/Resources/debug.php
new file mode 100644
index 00000000..104b4f4e
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Resources/debug.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Twig\Environment;
+use Twig\Extension\DebugExtension;
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_var_dump(Environment $env, $context, ...$vars)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    DebugExtension::dump($env, $context, ...$vars);
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Resources/escaper.php b/data/web/inc/lib/vendor/twig/twig/src/Resources/escaper.php
new file mode 100644
index 00000000..a2ee8e7a
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Resources/escaper.php
@@ -0,0 +1,51 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Twig\Environment;
+use Twig\Extension\EscaperExtension;
+use Twig\Node\Node;
+use Twig\Runtime\EscaperRuntime;
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_raw_filter($string)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return $string;
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return $env->getRuntime(EscaperRuntime::class)->escape($string, $strategy, $charset, $autoescape);
+}
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_escape_filter_is_safe(Node $filterArgs)
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return EscaperExtension::escapeFilterIsSafe($filterArgs);
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Resources/string_loader.php b/data/web/inc/lib/vendor/twig/twig/src/Resources/string_loader.php
new file mode 100644
index 00000000..8f0e6492
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Resources/string_loader.php
@@ -0,0 +1,26 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Twig\Environment;
+use Twig\Extension\StringLoaderExtension;
+use Twig\TemplateWrapper;
+
+/**
+ * @internal
+ *
+ * @deprecated since Twig 3.9
+ */
+function twig_template_from_string(Environment $env, $template, ?string $name = null): TemplateWrapper
+{
+    trigger_deprecation('twig/twig', '3.9', 'Using the internal "%s" function is deprecated.', __FUNCTION__);
+
+    return StringLoaderExtension::templateFromString($env, $template, $name);
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Runtime/EscaperRuntime.php b/data/web/inc/lib/vendor/twig/twig/src/Runtime/EscaperRuntime.php
new file mode 100644
index 00000000..a3ce1714
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Runtime/EscaperRuntime.php
@@ -0,0 +1,327 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Runtime;
+
+use Twig\Error\RuntimeError;
+use Twig\Extension\RuntimeExtensionInterface;
+use Twig\Markup;
+
+final class EscaperRuntime implements RuntimeExtensionInterface
+{
+    /** @var array<string, callable(string $string, string $charset): string> */
+    private $escapers = [];
+
+    /** @internal */
+    public $safeClasses = [];
+
+    /** @internal */
+    public $safeLookup = [];
+
+    public function __construct(
+        private $charset = 'UTF-8',
+    ) {
+    }
+
+    /**
+     * Defines a new escaper to be used via the escape filter.
+     *
+     * @param string                                            $strategy The strategy name that should be used as a strategy in the escape call
+     * @param callable(string $string, string $charset): string $callable A valid PHP callable
+     */
+    public function setEscaper($strategy, callable $callable)
+    {
+        $this->escapers[$strategy] = $callable;
+    }
+
+    /**
+     * Gets all defined escapers.
+     *
+     * @return array<string, callable(string $string, string $charset): string> An array of escapers
+     */
+    public function getEscapers()
+    {
+        return $this->escapers;
+    }
+
+    public function setSafeClasses(array $safeClasses = [])
+    {
+        $this->safeClasses = [];
+        $this->safeLookup = [];
+        foreach ($safeClasses as $class => $strategies) {
+            $this->addSafeClass($class, $strategies);
+        }
+    }
+
+    public function addSafeClass(string $class, array $strategies)
+    {
+        $class = ltrim($class, '\\');
+        if (!isset($this->safeClasses[$class])) {
+            $this->safeClasses[$class] = [];
+        }
+        $this->safeClasses[$class] = array_merge($this->safeClasses[$class], $strategies);
+
+        foreach ($strategies as $strategy) {
+            $this->safeLookup[$strategy][$class] = true;
+        }
+    }
+
+    /**
+     * Escapes a string.
+     *
+     * @param mixed       $string     The value to be escaped
+     * @param string      $strategy   The escaping strategy
+     * @param string|null $charset    The charset
+     * @param bool        $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
+     *
+     * @throws RuntimeError
+     */
+    public function escape($string, string $strategy = 'html', ?string $charset = null, bool $autoescape = false)
+    {
+        if ($autoescape && $string instanceof Markup) {
+            return $string;
+        }
+
+        if (!\is_string($string)) {
+            if ($string instanceof \Stringable) {
+                if ($autoescape) {
+                    $c = \get_class($string);
+                    if (!isset($this->safeClasses[$c])) {
+                        $this->safeClasses[$c] = [];
+                        foreach (class_parents($string) + class_implements($string) as $class) {
+                            if (isset($this->safeClasses[$class])) {
+                                $this->safeClasses[$c] = array_unique(array_merge($this->safeClasses[$c], $this->safeClasses[$class]));
+                                foreach ($this->safeClasses[$class] as $s) {
+                                    $this->safeLookup[$s][$c] = true;
+                                }
+                            }
+                        }
+                    }
+                    if (isset($this->safeLookup[$strategy][$c]) || isset($this->safeLookup['all'][$c])) {
+                        return (string) $string;
+                    }
+                }
+
+                $string = (string) $string;
+            } elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) {
+                // we return the input as is (which can be of any type)
+                return $string;
+            }
+        }
+
+        if ('' === $string) {
+            return '';
+        }
+
+        $charset = $charset ?: $this->charset;
+
+        switch ($strategy) {
+            case 'html':
+                // see https://www.php.net/htmlspecialchars
+
+                // Using a static variable to avoid initializing the array
+                // each time the function is called. Moving the declaration on the
+                // top of the function slow downs other escaping strategies.
+                static $htmlspecialcharsCharsets = [
+                    'ISO-8859-1' => true, 'ISO8859-1' => true,
+                    'ISO-8859-15' => true, 'ISO8859-15' => true,
+                    'utf-8' => true, 'UTF-8' => true,
+                    'CP866' => true, 'IBM866' => true, '866' => true,
+                    'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
+                    '1251' => true,
+                    'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
+                    'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
+                    'BIG5' => true, '950' => true,
+                    'GB2312' => true, '936' => true,
+                    'BIG5-HKSCS' => true,
+                    'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
+                    'EUC-JP' => true, 'EUCJP' => true,
+                    'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
+                ];
+
+                if (isset($htmlspecialcharsCharsets[$charset])) {
+                    return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
+                }
+
+                if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
+                    // cache the lowercase variant for future iterations
+                    $htmlspecialcharsCharsets[$charset] = true;
+
+                    return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset);
+                }
+
+                $string = $this->convertEncoding($string, 'UTF-8', $charset);
+                $string = htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8');
+
+                return iconv('UTF-8', $charset, $string);
+
+            case 'js':
+                // escape all non-alphanumeric characters
+                // into their \x or \uHHHH representations
+                if ('UTF-8' !== $charset) {
+                    $string = $this->convertEncoding($string, 'UTF-8', $charset);
+                }
+
+                if (!preg_match('//u', $string)) {
+                    throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
+                }
+
+                $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', function ($matches) {
+                    $char = $matches[0];
+
+                    /*
+                    * A few characters have short escape sequences in JSON and JavaScript.
+                    * Escape sequences supported only by JavaScript, not JSON, are omitted.
+                    * \" is also supported but omitted, because the resulting string is not HTML safe.
+                    */
+                    static $shortMap = [
+                        '\\' => '\\\\',
+                        '/' => '\\/',
+                        "\x08" => '\b',
+                        "\x0C" => '\f',
+                        "\x0A" => '\n',
+                        "\x0D" => '\r',
+                        "\x09" => '\t',
+                    ];
+
+                    if (isset($shortMap[$char])) {
+                        return $shortMap[$char];
+                    }
+
+                    $codepoint = mb_ord($char, 'UTF-8');
+                    if (0x10000 > $codepoint) {
+                        return \sprintf('\u%04X', $codepoint);
+                    }
+
+                    // Split characters outside the BMP into surrogate pairs
+                    // https://tools.ietf.org/html/rfc2781.html#section-2.1
+                    $u = $codepoint - 0x10000;
+                    $high = 0xD800 | ($u >> 10);
+                    $low = 0xDC00 | ($u & 0x3FF);
+
+                    return \sprintf('\u%04X\u%04X', $high, $low);
+                }, $string);
+
+                if ('UTF-8' !== $charset) {
+                    $string = iconv('UTF-8', $charset, $string);
+                }
+
+                return $string;
+
+            case 'css':
+                if ('UTF-8' !== $charset) {
+                    $string = $this->convertEncoding($string, 'UTF-8', $charset);
+                }
+
+                if (!preg_match('//u', $string)) {
+                    throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
+                }
+
+                $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', function ($matches) {
+                    $char = $matches[0];
+
+                    return \sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : mb_ord($char, 'UTF-8'));
+                }, $string);
+
+                if ('UTF-8' !== $charset) {
+                    $string = iconv('UTF-8', $charset, $string);
+                }
+
+                return $string;
+
+            case 'html_attr':
+                if ('UTF-8' !== $charset) {
+                    $string = $this->convertEncoding($string, 'UTF-8', $charset);
+                }
+
+                if (!preg_match('//u', $string)) {
+                    throw new RuntimeError('The string to escape is not a valid UTF-8 string.');
+                }
+
+                $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', function ($matches) {
+                    /**
+                     * This function is adapted from code coming from Zend Framework.
+                     *
+                     * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com)
+                     * @license   https://framework.zend.com/license/new-bsd New BSD License
+                     */
+                    $chr = $matches[0];
+                    $ord = \ord($chr);
+
+                    /*
+                    * The following replaces characters undefined in HTML with the
+                    * hex entity for the Unicode replacement character.
+                    */
+                    if (($ord <= 0x1F && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7F && $ord <= 0x9F)) {
+                        return '&#xFFFD;';
+                    }
+
+                    /*
+                    * Check if the current character to escape has a name entity we should
+                    * replace it with while grabbing the hex value of the character.
+                    */
+                    if (1 === \strlen($chr)) {
+                        /*
+                        * While HTML supports far more named entities, the lowest common denominator
+                        * has become HTML5's XML Serialisation which is restricted to the those named
+                        * entities that XML supports. Using HTML entities would result in this error:
+                        *     XML Parsing Error: undefined entity
+                        */
+                        static $entityMap = [
+                            34 => '&quot;', /* quotation mark */
+                            38 => '&amp;',  /* ampersand */
+                            60 => '&lt;',   /* less-than sign */
+                            62 => '&gt;',   /* greater-than sign */
+                        ];
+
+                        if (isset($entityMap[$ord])) {
+                            return $entityMap[$ord];
+                        }
+
+                        return \sprintf('&#x%02X;', $ord);
+                    }
+
+                    /*
+                    * Per OWASP recommendations, we'll use hex entities for any other
+                    * characters where a named entity does not exist.
+                    */
+                    return \sprintf('&#x%04X;', mb_ord($chr, 'UTF-8'));
+                }, $string);
+
+                if ('UTF-8' !== $charset) {
+                    $string = iconv('UTF-8', $charset, $string);
+                }
+
+                return $string;
+
+            case 'url':
+                return rawurlencode($string);
+
+            default:
+                if (\array_key_exists($strategy, $this->escapers)) {
+                    return $this->escapers[$strategy]($string, $charset);
+                }
+
+                $validStrategies = implode('", "', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($this->escapers)));
+
+                throw new RuntimeError(\sprintf('Invalid escaping strategy "%s" (valid ones: "%s").', $strategy, $validStrategies));
+        }
+    }
+
+    private function convertEncoding(string $string, string $to, string $from)
+    {
+        if (!\function_exists('iconv')) {
+            throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
+        }
+
+        return iconv($from, $to, $string);
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.php b/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.php
index b360d7be..05106680 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.php
@@ -23,11 +23,9 @@ use Psr\Container\ContainerInterface;
  */
 class ContainerRuntimeLoader implements RuntimeLoaderInterface
 {
-    private $container;
-
-    public function __construct(ContainerInterface $container)
-    {
-        $this->container = $container;
+    public function __construct(
+        private ContainerInterface $container,
+    ) {
     }
 
     public function load(string $class)
diff --git a/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.php b/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.php
index 13064839..5d4e70b9 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.php
@@ -18,14 +18,12 @@ namespace Twig\RuntimeLoader;
  */
 class FactoryRuntimeLoader implements RuntimeLoaderInterface
 {
-    private $map;
-
     /**
      * @param array $map An array where keys are class names and values factory callables
      */
-    public function __construct(array $map = [])
-    {
-        $this->map = $map;
+    public function __construct(
+        private array $map = [],
+    ) {
     }
 
     public function load(string $class)
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Sandbox/SecurityPolicy.php b/data/web/inc/lib/vendor/twig/twig/src/Sandbox/SecurityPolicy.php
index 2fc0d013..988e3721 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Sandbox/SecurityPolicy.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Sandbox/SecurityPolicy.php
@@ -68,19 +68,25 @@ final class SecurityPolicy implements SecurityPolicyInterface
     {
         foreach ($tags as $tag) {
             if (!\in_array($tag, $this->allowedTags)) {
-                throw new SecurityNotAllowedTagError(sprintf('Tag "%s" is not allowed.', $tag), $tag);
+                if ('extends' === $tag) {
+                    trigger_deprecation('twig/twig', '3.12', 'The "extends" tag is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed.');
+                } elseif ('use' === $tag) {
+                    trigger_deprecation('twig/twig', '3.12', 'The "use" tag is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed.');
+                } else {
+                    throw new SecurityNotAllowedTagError(\sprintf('Tag "%s" is not allowed.', $tag), $tag);
+                }
             }
         }
 
         foreach ($filters as $filter) {
             if (!\in_array($filter, $this->allowedFilters)) {
-                throw new SecurityNotAllowedFilterError(sprintf('Filter "%s" is not allowed.', $filter), $filter);
+                throw new SecurityNotAllowedFilterError(\sprintf('Filter "%s" is not allowed.', $filter), $filter);
             }
         }
 
         foreach ($functions as $function) {
             if (!\in_array($function, $this->allowedFunctions)) {
-                throw new SecurityNotAllowedFunctionError(sprintf('Function "%s" is not allowed.', $function), $function);
+                throw new SecurityNotAllowedFunctionError(\sprintf('Function "%s" is not allowed.', $function), $function);
             }
         }
     }
@@ -94,16 +100,15 @@ final class SecurityPolicy implements SecurityPolicyInterface
         $allowed = false;
         $method = strtr($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
         foreach ($this->allowedMethods as $class => $methods) {
-            if ($obj instanceof $class) {
-                $allowed = \in_array($method, $methods);
-
+            if ($obj instanceof $class && \in_array($method, $methods)) {
+                $allowed = true;
                 break;
             }
         }
 
         if (!$allowed) {
             $class = \get_class($obj);
-            throw new SecurityNotAllowedMethodError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method);
+            throw new SecurityNotAllowedMethodError(\sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method);
         }
     }
 
@@ -111,16 +116,15 @@ final class SecurityPolicy implements SecurityPolicyInterface
     {
         $allowed = false;
         foreach ($this->allowedProperties as $class => $properties) {
-            if ($obj instanceof $class) {
-                $allowed = \in_array($property, \is_array($properties) ? $properties : [$properties]);
-
+            if ($obj instanceof $class && \in_array($property, \is_array($properties) ? $properties : [$properties])) {
+                $allowed = true;
                 break;
             }
         }
 
         if (!$allowed) {
             $class = \get_class($obj);
-            throw new SecurityNotAllowedPropertyError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property);
+            throw new SecurityNotAllowedPropertyError(\sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property);
         }
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Sandbox/SourcePolicyInterface.php b/data/web/inc/lib/vendor/twig/twig/src/Sandbox/SourcePolicyInterface.php
new file mode 100644
index 00000000..b952f1ea
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Sandbox/SourcePolicyInterface.php
@@ -0,0 +1,24 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Sandbox;
+
+use Twig\Source;
+
+/**
+ * Interface for a class that can optionally enable the sandbox mode based on a template's Twig\Source.
+ *
+ * @author Yaakov Saxon
+ */
+interface SourcePolicyInterface
+{
+    public function enableSandbox(Source $source): bool;
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Source.php b/data/web/inc/lib/vendor/twig/twig/src/Source.php
index 3cb02403..0f626b62 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Source.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Source.php
@@ -18,20 +18,16 @@ namespace Twig;
  */
 final class Source
 {
-    private $code;
-    private $name;
-    private $path;
-
     /**
      * @param string $code The template source code
      * @param string $name The template logical name
      * @param string $path The filesystem path of the template if any
      */
-    public function __construct(string $code, string $name, string $path = '')
-    {
-        $this->code = $code;
-        $this->name = $name;
-        $this->path = $path;
+    public function __construct(
+        private string $code,
+        private string $name,
+        private string $path = '',
+    ) {
     }
 
     public function getCode(): string
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Template.php b/data/web/inc/lib/vendor/twig/twig/src/Template.php
index e04bd04a..7b3ce816 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Template.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Template.php
@@ -35,38 +35,36 @@ abstract class Template
 
     protected $parent;
     protected $parents = [];
-    protected $env;
     protected $blocks = [];
     protected $traits = [];
     protected $extensions = [];
     protected $sandbox;
 
-    public function __construct(Environment $env)
-    {
-        $this->env = $env;
+    private $useYield;
+
+    public function __construct(
+        protected Environment $env,
+    ) {
+        $this->useYield = $env->useYield();
         $this->extensions = $env->getExtensions();
     }
 
     /**
      * Returns the template name.
-     *
-     * @return string The template name
      */
-    abstract public function getTemplateName();
+    abstract public function getTemplateName(): string;
 
     /**
      * Returns debug information about the template.
      *
-     * @return array Debug information
+     * @return array<int, int> Debug information
      */
-    abstract public function getDebugInfo();
+    abstract public function getDebugInfo(): array;
 
     /**
      * Returns information about the original template source code.
-     *
-     * @return Source
      */
-    abstract public function getSourceContext();
+    abstract public function getSourceContext(): Source;
 
     /**
      * Returns the parent template.
@@ -74,18 +72,16 @@ abstract class Template
      * This method is for internal use only and should never be called
      * directly.
      *
-     * @return Template|TemplateWrapper|false The parent template or false if there is no parent
+     * @return self|TemplateWrapper|false The parent template or false if there is no parent
      */
-    public function getParent(array $context)
+    public function getParent(array $context): self|TemplateWrapper|false
     {
         if (null !== $this->parent) {
             return $this->parent;
         }
 
         try {
-            $parent = $this->doGetParent($context);
-
-            if (false === $parent) {
+            if (!$parent = $this->doGetParent($context)) {
                 return false;
             }
 
@@ -106,12 +102,12 @@ abstract class Template
         return $this->parents[$parent];
     }
 
-    protected function doGetParent(array $context)
+    protected function doGetParent(array $context): bool|string|self|TemplateWrapper
     {
         return false;
     }
 
-    public function isTraitable()
+    public function isTraitable(): bool
     {
         return true;
     }
@@ -126,14 +122,10 @@ abstract class Template
      * @param array  $context The context
      * @param array  $blocks  The current set of blocks
      */
-    public function displayParentBlock($name, array $context, array $blocks = [])
+    public function displayParentBlock($name, array $context, array $blocks = []): void
     {
-        if (isset($this->traits[$name])) {
-            $this->traits[$name][0]->displayBlock($name, $context, $blocks, false);
-        } elseif (false !== $parent = $this->getParent($context)) {
-            $parent->displayBlock($name, $context, $blocks, false);
-        } else {
-            throw new RuntimeError(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext());
+        foreach ($this->yieldParentBlock($name, $context, $blocks) as $data) {
+            echo $data;
         }
     }
 
@@ -148,51 +140,10 @@ abstract class Template
      * @param array  $blocks    The current set of blocks
      * @param bool   $useBlocks Whether to use the current set of blocks
      */
-    public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true, self $templateContext = null)
+    public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true, ?self $templateContext = null): void
     {
-        if ($useBlocks && isset($blocks[$name])) {
-            $template = $blocks[$name][0];
-            $block = $blocks[$name][1];
-        } elseif (isset($this->blocks[$name])) {
-            $template = $this->blocks[$name][0];
-            $block = $this->blocks[$name][1];
-        } else {
-            $template = null;
-            $block = null;
-        }
-
-        // avoid RCEs when sandbox is enabled
-        if (null !== $template && !$template instanceof self) {
-            throw new \LogicException('A block must be a method on a \Twig\Template instance.');
-        }
-
-        if (null !== $template) {
-            try {
-                $template->$block($context, $blocks);
-            } catch (Error $e) {
-                if (!$e->getSourceContext()) {
-                    $e->setSourceContext($template->getSourceContext());
-                }
-
-                // this is mostly useful for \Twig\Error\LoaderError exceptions
-                // see \Twig\Error\LoaderError
-                if (-1 === $e->getTemplateLine()) {
-                    $e->guess();
-                }
-
-                throw $e;
-            } catch (\Exception $e) {
-                $e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e);
-                $e->guess();
-
-                throw $e;
-            }
-        } elseif (false !== $parent = $this->getParent($context)) {
-            $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false, $templateContext ?? $this);
-        } elseif (isset($blocks[$name])) {
-            throw new RuntimeError(sprintf('Block "%s" should not call parent() in "%s" as the block does not exist in the parent template "%s".', $name, $blocks[$name][0]->getTemplateName(), $this->getTemplateName()), -1, $blocks[$name][0]->getSourceContext());
-        } else {
-            throw new RuntimeError(sprintf('Block "%s" on template "%s" does not exist.', $name, $this->getTemplateName()), -1, ($templateContext ?? $this)->getSourceContext());
+        foreach ($this->yieldBlock($name, $context, $blocks, $useBlocks, $templateContext) as $data) {
+            echo $data;
         }
     }
 
@@ -208,16 +159,25 @@ abstract class Template
      *
      * @return string The rendered block
      */
-    public function renderParentBlock($name, array $context, array $blocks = [])
+    public function renderParentBlock($name, array $context, array $blocks = []): string
     {
-        if ($this->env->isDebug()) {
-            ob_start();
-        } else {
-            ob_start(function () { return ''; });
+        if (!$this->useYield) {
+            if ($this->env->isDebug()) {
+                ob_start();
+            } else {
+                ob_start(function () { return ''; });
+            }
+            $this->displayParentBlock($name, $context, $blocks);
+
+            return ob_get_clean();
         }
-        $this->displayParentBlock($name, $context, $blocks);
 
-        return ob_get_clean();
+        $content = '';
+        foreach ($this->yieldParentBlock($name, $context, $blocks) as $data) {
+            $content .= $data;
+        }
+
+        return $content;
     }
 
     /**
@@ -233,16 +193,34 @@ abstract class Template
      *
      * @return string The rendered block
      */
-    public function renderBlock($name, array $context, array $blocks = [], $useBlocks = true)
+    public function renderBlock($name, array $context, array $blocks = [], $useBlocks = true): string
     {
-        if ($this->env->isDebug()) {
-            ob_start();
-        } else {
-            ob_start(function () { return ''; });
+        if (!$this->useYield) {
+            $level = ob_get_level();
+            if ($this->env->isDebug()) {
+                ob_start();
+            } else {
+                ob_start(function () { return ''; });
+            }
+            try {
+                $this->displayBlock($name, $context, $blocks, $useBlocks);
+            } catch (\Throwable $e) {
+                while (ob_get_level() > $level) {
+                    ob_end_clean();
+                }
+
+                throw $e;
+            }
+
+            return ob_get_clean();
         }
-        $this->displayBlock($name, $context, $blocks, $useBlocks);
 
-        return ob_get_clean();
+        $content = '';
+        foreach ($this->yieldBlock($name, $context, $blocks, $useBlocks) as $data) {
+            $content .= $data;
+        }
+
+        return $content;
     }
 
     /**
@@ -257,7 +235,7 @@ abstract class Template
      *
      * @return bool true if the block exists, false otherwise
      */
-    public function hasBlock($name, array $context, array $blocks = [])
+    public function hasBlock($name, array $context, array $blocks = []): bool
     {
         if (isset($blocks[$name])) {
             return $blocks[$name][0] instanceof self;
@@ -267,7 +245,7 @@ abstract class Template
             return true;
         }
 
-        if (false !== $parent = $this->getParent($context)) {
+        if ($parent = $this->getParent($context)) {
             return $parent->hasBlock($name, $context);
         }
 
@@ -283,13 +261,13 @@ abstract class Template
      * @param array $context The context
      * @param array $blocks  The current set of blocks
      *
-     * @return array An array of block names
+     * @return array<string> An array of block names
      */
-    public function getBlockNames(array $context, array $blocks = [])
+    public function getBlockNames(array $context, array $blocks = []): array
     {
         $names = array_merge(array_keys($blocks), array_keys($this->blocks));
 
-        if (false !== $parent = $this->getParent($context)) {
+        if ($parent = $this->getParent($context)) {
             $names = array_merge($names, $parent->getBlockNames($context));
         }
 
@@ -297,16 +275,22 @@ abstract class Template
     }
 
     /**
-     * @return Template|TemplateWrapper
+     * @param string|TemplateWrapper|array<string|TemplateWrapper> $template
      */
-    protected function loadTemplate($template, $templateName = null, $line = null, $index = null)
+    protected function loadTemplate($template, $templateName = null, $line = null, $index = null): self|TemplateWrapper
     {
         try {
             if (\is_array($template)) {
                 return $this->env->resolveTemplate($template);
             }
 
-            if ($template instanceof self || $template instanceof TemplateWrapper) {
+            if ($template instanceof TemplateWrapper) {
+                return $template;
+            }
+
+            if ($template instanceof self) {
+                trigger_deprecation('twig/twig', '3.9', 'Passing a "%s" instance to "%s" is deprecated.', self::class, __METHOD__);
+
                 return $template;
             }
 
@@ -341,10 +325,8 @@ abstract class Template
 
     /**
      * @internal
-     *
-     * @return Template
      */
-    public function unwrap()
+    public function unwrap(): self
     {
         return $this;
     }
@@ -357,41 +339,58 @@ abstract class Template
      *
      * @return array An array of blocks
      */
-    public function getBlocks()
+    public function getBlocks(): array
     {
         return $this->blocks;
     }
 
-    public function display(array $context, array $blocks = [])
+    public function display(array $context, array $blocks = []): void
     {
-        $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks));
+        foreach ($this->yield($context, $blocks) as $data) {
+            echo $data;
+        }
     }
 
-    public function render(array $context)
+    public function render(array $context): string
     {
-        $level = ob_get_level();
-        if ($this->env->isDebug()) {
-            ob_start();
-        } else {
-            ob_start(function () { return ''; });
-        }
-        try {
-            $this->display($context);
-        } catch (\Throwable $e) {
-            while (ob_get_level() > $level) {
-                ob_end_clean();
+        if (!$this->useYield) {
+            $level = ob_get_level();
+            if ($this->env->isDebug()) {
+                ob_start();
+            } else {
+                ob_start(function () { return ''; });
             }
+            try {
+                $this->display($context);
+            } catch (\Throwable $e) {
+                while (ob_get_level() > $level) {
+                    ob_end_clean();
+                }
 
-            throw $e;
+                throw $e;
+            }
+
+            return ob_get_clean();
+        }
+
+        $content = '';
+        foreach ($this->yield($context) as $data) {
+            $content .= $data;
         }
 
-        return ob_get_clean();
+        return $content;
     }
 
-    protected function displayWithErrorHandling(array $context, array $blocks = [])
+    /**
+     * @return iterable<scalar|\Stringable|null>
+     */
+    public function yield(array $context, array $blocks = []): iterable
     {
+        $context += $this->env->getGlobals();
+        $blocks = array_merge($this->blocks, $blocks);
+
         try {
-            $this->doDisplay($context, $blocks);
+            yield from $this->doDisplay($context, $blocks);
         } catch (Error $e) {
             if (!$e->getSourceContext()) {
                 $e->setSourceContext($this->getSourceContext());
@@ -404,19 +403,95 @@ abstract class Template
             }
 
             throw $e;
-        } catch (\Exception $e) {
-            $e = new RuntimeError(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e);
+        } catch (\Throwable $e) {
+            $e = new RuntimeError(\sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e);
             $e->guess();
 
             throw $e;
         }
     }
 
+    /**
+     * @return iterable<scalar|\Stringable|null>
+     */
+    public function yieldBlock($name, array $context, array $blocks = [], $useBlocks = true, ?self $templateContext = null): iterable
+    {
+        if ($useBlocks && isset($blocks[$name])) {
+            $template = $blocks[$name][0];
+            $block = $blocks[$name][1];
+        } elseif (isset($this->blocks[$name])) {
+            $template = $this->blocks[$name][0];
+            $block = $this->blocks[$name][1];
+        } else {
+            $template = null;
+            $block = null;
+        }
+
+        // avoid RCEs when sandbox is enabled
+        if (null !== $template && !$template instanceof self) {
+            throw new \LogicException('A block must be a method on a \Twig\Template instance.');
+        }
+
+        if (null !== $template) {
+            try {
+                yield from $template->$block($context, $blocks);
+            } catch (Error $e) {
+                if (!$e->getSourceContext()) {
+                    $e->setSourceContext($template->getSourceContext());
+                }
+
+                // this is mostly useful for \Twig\Error\LoaderError exceptions
+                // see \Twig\Error\LoaderError
+                if (-1 === $e->getTemplateLine()) {
+                    $e->guess();
+                }
+
+                throw $e;
+            } catch (\Throwable $e) {
+                $e = new RuntimeError(\sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e);
+                $e->guess();
+
+                throw $e;
+            }
+        } elseif ($parent = $this->getParent($context)) {
+            yield from $parent->unwrap()->yieldBlock($name, $context, array_merge($this->blocks, $blocks), false, $templateContext ?? $this);
+        } elseif (isset($blocks[$name])) {
+            throw new RuntimeError(\sprintf('Block "%s" should not call parent() in "%s" as the block does not exist in the parent template "%s".', $name, $blocks[$name][0]->getTemplateName(), $this->getTemplateName()), -1, $blocks[$name][0]->getSourceContext());
+        } else {
+            throw new RuntimeError(\sprintf('Block "%s" on template "%s" does not exist.', $name, $this->getTemplateName()), -1, ($templateContext ?? $this)->getSourceContext());
+        }
+    }
+
+    /**
+     * Yields a parent block.
+     *
+     * This method is for internal use only and should never be called
+     * directly.
+     *
+     * @param string $name    The block name to display from the parent
+     * @param array  $context The context
+     * @param array  $blocks  The current set of blocks
+     *
+     * @return iterable<scalar|\Stringable|null>
+     */
+    public function yieldParentBlock($name, array $context, array $blocks = []): iterable
+    {
+        if (isset($this->traits[$name])) {
+            yield from $this->traits[$name][0]->yieldBlock($name, $context, $blocks, false);
+        } elseif ($parent = $this->getParent($context)) {
+            yield from $parent->unwrap()->yieldBlock($name, $context, $blocks, false);
+        } else {
+            throw new RuntimeError(\sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext());
+        }
+    }
+
     /**
      * Auto-generated method to display the template with the given context.
      *
      * @param array $context An array of parameters to pass to the template
      * @param array $blocks  An array of blocks to pass to the template
+     *
+     * @return iterable<scalar|\Stringable|null>
      */
-    abstract protected function doDisplay(array $context, array $blocks = []);
+    abstract protected function doDisplay(array $context, array $blocks = []): iterable;
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TemplateWrapper.php b/data/web/inc/lib/vendor/twig/twig/src/TemplateWrapper.php
index c9c6b07c..135c5918 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TemplateWrapper.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TemplateWrapper.php
@@ -18,26 +18,21 @@ namespace Twig;
  */
 final class TemplateWrapper
 {
-    private $env;
-    private $template;
-
     /**
      * This method is for internal use only and should never be called
      * directly (use Twig\Environment::load() instead).
      *
      * @internal
      */
-    public function __construct(Environment $env, Template $template)
-    {
-        $this->env = $env;
-        $this->template = $template;
+    public function __construct(
+        private Environment $env,
+        private Template $template,
+    ) {
     }
 
     public function render(array $context = []): string
     {
-        // using func_get_args() allows to not expose the blocks argument
-        // as it should only be used by internal code
-        return $this->template->render($context, \func_get_args()[1] ?? []);
+        return $this->template->render($context);
     }
 
     public function display(array $context = [])
@@ -62,29 +57,15 @@ final class TemplateWrapper
 
     public function renderBlock(string $name, array $context = []): string
     {
-        $context = $this->env->mergeGlobals($context);
-        $level = ob_get_level();
-        if ($this->env->isDebug()) {
-            ob_start();
-        } else {
-            ob_start(function () { return ''; });
-        }
-        try {
-            $this->template->displayBlock($name, $context);
-        } catch (\Throwable $e) {
-            while (ob_get_level() > $level) {
-                ob_end_clean();
-            }
-
-            throw $e;
-        }
-
-        return ob_get_clean();
+        return $this->template->renderBlock($name, $context + $this->env->getGlobals());
     }
 
     public function displayBlock(string $name, array $context = [])
     {
-        $this->template->displayBlock($name, $this->env->mergeGlobals($context));
+        $context += $this->env->getGlobals();
+        foreach ($this->template->yieldBlock($name, $context) as $data) {
+            echo $data;
+        }
     }
 
     public function getSourceContext(): Source
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Test/IntegrationTestCase.php b/data/web/inc/lib/vendor/twig/twig/src/Test/IntegrationTestCase.php
index 307302bb..8690a809 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Test/IntegrationTestCase.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Test/IntegrationTestCase.php
@@ -30,9 +30,19 @@ use Twig\TwigTest;
 abstract class IntegrationTestCase extends TestCase
 {
     /**
+     * @deprecated since Twig 3.13, use getFixturesDirectory() instead.
+     *
      * @return string
      */
-    abstract protected function getFixturesDir();
+    protected function getFixturesDir()
+    {
+        throw new \BadMethodCallException('Not implemented.');
+    }
+
+    protected static function getFixturesDirectory(): string
+    {
+        throw new \BadMethodCallException('Not implemented.');
+    }
 
     /**
      * @return RuntimeLoaderInterface[]
@@ -84,6 +94,7 @@ abstract class IntegrationTestCase extends TestCase
 
     /**
      * @dataProvider getLegacyTests
+     *
      * @group legacy
      */
     public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '')
@@ -91,9 +102,19 @@ abstract class IntegrationTestCase extends TestCase
         $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation);
     }
 
+    /**
+     * @final since Twig 3.13
+     */
     public function getTests($name, $legacyTests = false)
     {
-        $fixturesDir = realpath($this->getFixturesDir());
+        try {
+            $fixturesDir = static::getFixturesDirectory();
+        } catch (\BadMethodCallException) {
+            trigger_deprecation('twig/twig', '3.13', 'Not overriding "%s::getFixturesDirectory()" in "%s" is deprecated. This method will be abstract in 4.0.', self::class, static::class);
+            $fixturesDir = $this->getFixturesDir();
+        }
+
+        $fixturesDir = realpath($fixturesDir);
         $tests = [];
 
         foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($fixturesDir), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
@@ -101,7 +122,7 @@ abstract class IntegrationTestCase extends TestCase
                 continue;
             }
 
-            if ($legacyTests xor false !== strpos($file->getRealpath(), '.legacy.test')) {
+            if ($legacyTests xor str_contains($file->getRealpath(), '.legacy.test')) {
                 continue;
             }
 
@@ -122,7 +143,7 @@ abstract class IntegrationTestCase extends TestCase
                 $exception = false;
                 preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, \PREG_SET_ORDER);
             } else {
-                throw new \InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file)));
+                throw new \InvalidArgumentException(\sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file)));
             }
 
             $tests[] = [str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs, $deprecation];
@@ -136,6 +157,9 @@ abstract class IntegrationTestCase extends TestCase
         return $tests;
     }
 
+    /**
+     * @final since Twig 3.13
+     */
     public function getLegacyTests()
     {
         return $this->getTests('testLegacyIntegration', true);
@@ -148,19 +172,23 @@ abstract class IntegrationTestCase extends TestCase
         }
 
         if ($condition) {
+            $ret = '';
             eval('$ret = '.$condition.';');
             if (!$ret) {
                 $this->markTestSkipped($condition);
             }
         }
 
-        $loader = new ArrayLoader($templates);
-
         foreach ($outputs as $i => $match) {
             $config = array_merge([
                 'cache' => false,
                 'strict_variables' => true,
             ], $match[2] ? eval($match[2].';') : []);
+            // make sure that template are always compiled even if they are the same (useful when testing with more than one data/expect sections)
+            foreach ($templates as $j => $template) {
+                $templates[$j] = $template.str_repeat(' ', $i);
+            }
+            $loader = new ArrayLoader($templates);
             $twig = new Environment($loader, $config);
             $twig->addGlobal('global', 'global');
             foreach ($this->getRuntimeLoaders() as $runtimeLoader) {
@@ -183,11 +211,6 @@ abstract class IntegrationTestCase extends TestCase
                 $twig->addFunction($function);
             }
 
-            // avoid using the same PHP class name for different cases
-            $p = new \ReflectionProperty($twig, 'templateClassPrefix');
-            $p->setAccessible(true);
-            $p->setValue($twig, '__TwigTemplate_'.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', uniqid(mt_rand(), true), false).'_');
-
             $deprecations = [];
             try {
                 $prevHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$deprecations, &$prevHandler) {
@@ -204,14 +227,14 @@ abstract class IntegrationTestCase extends TestCase
             } catch (\Exception $e) {
                 if (false !== $exception) {
                     $message = $e->getMessage();
-                    $this->assertSame(trim($exception), trim(sprintf('%s: %s', \get_class($e), $message)));
+                    $this->assertSame(trim($exception), trim(\sprintf('%s: %s', \get_class($e), $message)));
                     $last = substr($message, \strlen($message) - 1);
                     $this->assertTrue('.' === $last || '?' === $last, 'Exception message must end with a dot or a question mark.');
 
                     return;
                 }
 
-                throw new Error(sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e);
+                throw new Error(\sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e);
             } finally {
                 restore_error_handler();
             }
@@ -222,18 +245,18 @@ abstract class IntegrationTestCase extends TestCase
                 $output = trim($template->render(eval($match[1].';')), "\n ");
             } catch (\Exception $e) {
                 if (false !== $exception) {
-                    $this->assertSame(trim($exception), trim(sprintf('%s: %s', \get_class($e), $e->getMessage())));
+                    $this->assertSame(trim($exception), trim(\sprintf('%s: %s', \get_class($e), $e->getMessage())));
 
                     return;
                 }
 
-                $e = new Error(sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e);
+                $e = new Error(\sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e);
 
-                $output = trim(sprintf('%s: %s', \get_class($e), $e->getMessage()));
+                $output = trim(\sprintf('%s: %s', \get_class($e), $e->getMessage()));
             }
 
             if (false !== $exception) {
-                list($class) = explode(':', $exception);
+                [$class] = explode(':', $exception);
                 $constraintClass = class_exists('PHPUnit\Framework\Constraint\Exception') ? 'PHPUnit\Framework\Constraint\Exception' : 'PHPUnit_Framework_Constraint_Exception';
                 $this->assertThat(null, new $constraintClass($class));
             }
@@ -257,7 +280,7 @@ abstract class IntegrationTestCase extends TestCase
         $templates = [];
         preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, \PREG_SET_ORDER);
         foreach ($matches as $match) {
-            $templates[($match[1] ?: 'index.twig')] = $match[2];
+            $templates[$match[1] ?: 'index.twig'] = $match[2];
         }
 
         return $templates;
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Test/NodeTestCase.php b/data/web/inc/lib/vendor/twig/twig/src/Test/NodeTestCase.php
index 3b8b2c86..bac0ea6d 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Test/NodeTestCase.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Test/NodeTestCase.php
@@ -11,6 +11,8 @@
 
 namespace Twig\Test;
 
+use PHPUnit\Framework\Attributes\BeforeClass;
+use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\TestCase;
 use Twig\Compiler;
 use Twig\Environment;
@@ -19,17 +21,37 @@ use Twig\Node\Node;
 
 abstract class NodeTestCase extends TestCase
 {
-    abstract public function getTests();
+    /**
+     * @var Environment
+     */
+    private $currentEnv;
+
+    public function getTests()
+    {
+        return [];
+    }
+
+    /**
+     * @return iterable<array{0: Node, 1: string, 2?: Environment|null, 3?: bool}>
+     */
+    public static function provideTests(): iterable
+    {
+        trigger_deprecation('twig/twig', '3.13', 'Not implementing "%s()" in "%s" is deprecated. This method will be abstract in 4.0.', __METHOD__, static::class);
+
+        return [];
+    }
 
     /**
      * @dataProvider getTests
+     * @dataProvider provideTests
      */
+    #[DataProvider('getTests'), DataProvider('provideTests')]
     public function testCompile($node, $source, $environment = null, $isPattern = false)
     {
         $this->assertNodeCompilation($source, $node, $environment, $isPattern);
     }
 
-    public function assertNodeCompilation($source, Node $node, Environment $environment = null, $isPattern = false)
+    public function assertNodeCompilation($source, Node $node, ?Environment $environment = null, $isPattern = false)
     {
         $compiler = $this->getCompiler($environment);
         $compiler->compile($node);
@@ -41,25 +63,63 @@ abstract class NodeTestCase extends TestCase
         }
     }
 
-    protected function getCompiler(Environment $environment = null)
+    protected function getCompiler(?Environment $environment = null)
     {
-        return new Compiler(null === $environment ? $this->getEnvironment() : $environment);
+        return new Compiler($environment ?? $this->getEnvironment());
     }
 
+    /**
+     * @final since Twig 3.13
+     */
     protected function getEnvironment()
     {
-        return new Environment(new ArrayLoader([]));
+        return $this->currentEnv ??= static::createEnvironment();
+    }
+
+    protected static function createEnvironment(): Environment
+    {
+        return new Environment(new ArrayLoader());
     }
 
+    /**
+     * @deprecated since Twig 3.13, use createVariableGetter() instead.
+     */
     protected function getVariableGetter($name, $line = false)
+    {
+        trigger_deprecation('twig/twig', '3.13', 'Method "%s()" is deprecated, use "createVariableGetter()" instead.', __METHOD__);
+
+        return self::createVariableGetter($name, $line);
+    }
+
+    final protected static function createVariableGetter(string $name, bool $line = false): string
     {
         $line = $line > 0 ? "// line $line\n" : '';
 
-        return sprintf('%s($context["%s"] ?? null)', $line, $name);
+        return \sprintf('%s($context["%s"] ?? null)', $line, $name);
     }
 
+    /**
+     * @deprecated since Twig 3.13, use createAttributeGetter() instead.
+     */
     protected function getAttributeGetter()
     {
-        return 'twig_get_attribute($this->env, $this->source, ';
+        trigger_deprecation('twig/twig', '3.13', 'Method "%s()" is deprecated, use "createAttributeGetter()" instead.', __METHOD__);
+
+        return self::createAttributeGetter();
+    }
+
+    final protected static function createAttributeGetter(): string
+    {
+        return 'CoreExtension::getAttribute($this->env, $this->source, ';
+    }
+
+    /** @beforeClass */
+    #[BeforeClass]
+    final public static function checkDataProvider(): void
+    {
+        $r = new \ReflectionMethod(static::class, 'getTests');
+        if (self::class !== $r->getDeclaringClass()->getName()) {
+            trigger_deprecation('twig/twig', '3.13', 'Implementing "%s::getTests()" in "%s" is deprecated, implement "provideTests()" instead.', self::class, static::class);
+        }
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Token.php b/data/web/inc/lib/vendor/twig/twig/src/Token.php
index 53a6cafc..237634ad 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Token.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Token.php
@@ -17,10 +17,6 @@ namespace Twig;
  */
 final class Token
 {
-    private $value;
-    private $type;
-    private $lineno;
-
     public const EOF_TYPE = -1;
     public const TEXT_TYPE = 0;
     public const BLOCK_START_TYPE = 1;
@@ -35,17 +31,18 @@ final class Token
     public const INTERPOLATION_START_TYPE = 10;
     public const INTERPOLATION_END_TYPE = 11;
     public const ARROW_TYPE = 12;
+    public const SPREAD_TYPE = 13;
 
-    public function __construct(int $type, $value, int $lineno)
-    {
-        $this->type = $type;
-        $this->value = $value;
-        $this->lineno = $lineno;
+    public function __construct(
+        private int $type,
+        private $value,
+        private int $lineno,
+    ) {
     }
 
     public function __toString()
     {
-        return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value);
+        return \sprintf('%s(%s)', self::typeToString($this->type, true), $this->value);
     }
 
     /**
@@ -67,9 +64,9 @@ final class Token
         }
 
         return ($this->type === $type) && (
-            null === $values ||
-            (\is_array($values) && \in_array($this->value, $values)) ||
-            $this->value == $values
+            null === $values
+            || (\is_array($values) && \in_array($this->value, $values))
+            || $this->value == $values
         );
     }
 
@@ -133,8 +130,11 @@ final class Token
             case self::ARROW_TYPE:
                 $name = 'ARROW_TYPE';
                 break;
+            case self::SPREAD_TYPE:
+                $name = 'SPREAD_TYPE';
+                break;
             default:
-                throw new \LogicException(sprintf('Token of type "%s" does not exist.', $type));
+                throw new \LogicException(\sprintf('Token of type "%s" does not exist.', $type));
         }
 
         return $short ? $name : 'Twig\Token::'.$name;
@@ -171,8 +171,10 @@ final class Token
                 return 'end of string interpolation';
             case self::ARROW_TYPE:
                 return 'arrow function';
+            case self::SPREAD_TYPE:
+                return 'spread operator';
             default:
-                throw new \LogicException(sprintf('Token of type "%s" does not exist.', $type));
+                throw new \LogicException(\sprintf('Token of type "%s" does not exist.', $type));
         }
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php
index 4dbf3040..0a6c1afb 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php
@@ -36,16 +36,16 @@ final class ApplyTokenParser extends AbstractTokenParser
         $ref = new TempNameExpression($name, $lineno);
         $ref->setAttribute('always_defined', true);
 
-        $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag());
+        $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref);
 
         $this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
         $body = $this->parser->subparse([$this, 'decideApplyEnd'], true);
         $this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
 
         return new Node([
-            new SetNode(true, $ref, $body, $lineno, $this->getTag()),
-            new PrintNode($filter, $lineno, $this->getTag()),
-        ]);
+            new SetNode(true, $ref, $body, $lineno),
+            new PrintNode($filter, $lineno),
+        ], [], $lineno);
     }
 
     public function decideApplyEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php
index b674bea4..b50b29e6 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php
@@ -29,7 +29,7 @@ final class AutoEscapeTokenParser extends AbstractTokenParser
         $lineno = $token->getLine();
         $stream = $this->parser->getStream();
 
-        if ($stream->test(/* Token::BLOCK_END_TYPE */ 3)) {
+        if ($stream->test(Token::BLOCK_END_TYPE)) {
             $value = 'html';
         } else {
             $expr = $this->parser->getExpressionParser()->parseExpression();
@@ -39,11 +39,11 @@ final class AutoEscapeTokenParser extends AbstractTokenParser
             $value = $expr->getAttribute('value');
         }
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
         $body = $this->parser->subparse([$this, 'decideBlockEnd'], true);
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
-        return new AutoEscapeNode($value, $body, $lineno, $this->getTag());
+        return new AutoEscapeNode($value, $body, $lineno);
     }
 
     public function decideBlockEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/BlockTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/BlockTokenParser.php
index 5878131b..81d675db 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/BlockTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/BlockTokenParser.php
@@ -35,21 +35,18 @@ final class BlockTokenParser extends AbstractTokenParser
     {
         $lineno = $token->getLine();
         $stream = $this->parser->getStream();
-        $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
-        if ($this->parser->hasBlock($name)) {
-            throw new SyntaxError(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getTemplateLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext());
-        }
+        $name = $stream->expect(Token::NAME_TYPE)->getValue();
         $this->parser->setBlock($name, $block = new BlockNode($name, new Node([]), $lineno));
         $this->parser->pushLocalScope();
         $this->parser->pushBlockStack($name);
 
-        if ($stream->nextIf(/* Token::BLOCK_END_TYPE */ 3)) {
+        if ($stream->nextIf(Token::BLOCK_END_TYPE)) {
             $body = $this->parser->subparse([$this, 'decideBlockEnd'], true);
-            if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) {
+            if ($token = $stream->nextIf(Token::NAME_TYPE)) {
                 $value = $token->getValue();
 
                 if ($value != $name) {
-                    throw new SyntaxError(sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext());
+                    throw new SyntaxError(\sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext());
                 }
             }
         } else {
@@ -57,13 +54,13 @@ final class BlockTokenParser extends AbstractTokenParser
                 new PrintNode($this->parser->getExpressionParser()->parseExpression(), $lineno),
             ]);
         }
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
         $block->setNode('body', $body);
         $this->parser->popBlockStack();
         $this->parser->popLocalScope();
 
-        return new BlockReferenceNode($name, $lineno, $this->getTag());
+        return new BlockReferenceNode($name, $lineno);
     }
 
     public function decideBlockEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php
index 31416c79..164ef26e 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php
@@ -11,6 +11,7 @@
 
 namespace Twig\TokenParser;
 
+use Twig\Error\SyntaxError;
 use Twig\Node\DeprecatedNode;
 use Twig\Node\Node;
 use Twig\Token;
@@ -21,6 +22,8 @@ use Twig\Token;
  *    {% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' %}
  *    {% extends 'layout.html.twig' %}
  *
+ *    {% deprecated 'The "base.twig" template is deprecated, use "layout.twig" instead.' package="foo/bar" version="1.1" %}
+ *
  * @author Yonel Ceruto <[email protected]>
  *
  * @internal
@@ -29,11 +32,31 @@ final class DeprecatedTokenParser extends AbstractTokenParser
 {
     public function parse(Token $token): Node
     {
-        $expr = $this->parser->getExpressionParser()->parseExpression();
+        $stream = $this->parser->getStream();
+        $expressionParser = $this->parser->getExpressionParser();
+        $expr = $expressionParser->parseExpression();
+        $node = new DeprecatedNode($expr, $token->getLine());
+
+        while ($stream->test(Token::NAME_TYPE)) {
+            $k = $stream->getCurrent()->getValue();
+            $stream->next();
+            $stream->expect(Token::OPERATOR_TYPE, '=');
+
+            switch ($k) {
+                case 'package':
+                    $node->setNode('package', $expressionParser->parseExpression());
+                    break;
+                case 'version':
+                    $node->setNode('version', $expressionParser->parseExpression());
+                    break;
+                default:
+                    throw new SyntaxError(\sprintf('Unknown "%s" option.', $k), $stream->getCurrent()->getLine(), $stream->getSourceContext());
+            }
+        }
 
-        $this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
-        return new DeprecatedNode($expr, $token->getLine(), $this->getTag());
+        return $node;
     }
 
     public function getTag(): string
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DoTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DoTokenParser.php
index 32c8f12f..8afd4855 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DoTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/DoTokenParser.php
@@ -26,9 +26,9 @@ final class DoTokenParser extends AbstractTokenParser
     {
         $expr = $this->parser->getExpressionParser()->parseExpression();
 
-        $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
 
-        return new DoNode($expr, $token->getLine(), $this->getTag());
+        return new DoNode($expr, $token->getLine());
     }
 
     public function getTag(): string
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php
index 64b4f296..7bf3233e 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php
@@ -30,21 +30,21 @@ final class EmbedTokenParser extends IncludeTokenParser
 
         $parent = $this->parser->getExpressionParser()->parseExpression();
 
-        list($variables, $only, $ignoreMissing) = $this->parseArguments();
+        [$variables, $only, $ignoreMissing] = $this->parseArguments();
 
-        $parentToken = $fakeParentToken = new Token(/* Token::STRING_TYPE */ 7, '__parent__', $token->getLine());
+        $parentToken = $fakeParentToken = new Token(Token::STRING_TYPE, '__parent__', $token->getLine());
         if ($parent instanceof ConstantExpression) {
-            $parentToken = new Token(/* Token::STRING_TYPE */ 7, $parent->getAttribute('value'), $token->getLine());
+            $parentToken = new Token(Token::STRING_TYPE, $parent->getAttribute('value'), $token->getLine());
         } elseif ($parent instanceof NameExpression) {
-            $parentToken = new Token(/* Token::NAME_TYPE */ 5, $parent->getAttribute('name'), $token->getLine());
+            $parentToken = new Token(Token::NAME_TYPE, $parent->getAttribute('name'), $token->getLine());
         }
 
         // inject a fake parent to make the parent() function work
         $stream->injectTokens([
-            new Token(/* Token::BLOCK_START_TYPE */ 1, '', $token->getLine()),
-            new Token(/* Token::NAME_TYPE */ 5, 'extends', $token->getLine()),
+            new Token(Token::BLOCK_START_TYPE, '', $token->getLine()),
+            new Token(Token::NAME_TYPE, 'extends', $token->getLine()),
             $parentToken,
-            new Token(/* Token::BLOCK_END_TYPE */ 3, '', $token->getLine()),
+            new Token(Token::BLOCK_END_TYPE, '', $token->getLine()),
         ]);
 
         $module = $this->parser->parse($stream, [$this, 'decideBlockEnd'], true);
@@ -56,9 +56,9 @@ final class EmbedTokenParser extends IncludeTokenParser
 
         $this->parser->embedTemplate($module);
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
-        return new EmbedNode($module->getTemplateName(), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
+        return new EmbedNode($module->getTemplateName(), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine());
     }
 
     public function decideBlockEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php
index 0ca46dd2..86ddfdfb 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php
@@ -35,14 +35,11 @@ final class ExtendsTokenParser extends AbstractTokenParser
             throw new SyntaxError('Cannot use "extend" in a macro.', $token->getLine(), $stream->getSourceContext());
         }
 
-        if (null !== $this->parser->getParent()) {
-            throw new SyntaxError('Multiple extends tags are forbidden.', $token->getLine(), $stream->getSourceContext());
-        }
         $this->parser->setParent($this->parser->getExpressionParser()->parseExpression());
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
-        return new Node();
+        return new Node([], [], $token->getLine());
     }
 
     public function getTag(): string
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FlushTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FlushTokenParser.php
index 02c74aa1..0d238874 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FlushTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FlushTokenParser.php
@@ -26,9 +26,9 @@ final class FlushTokenParser extends AbstractTokenParser
 {
     public function parse(Token $token): Node
     {
-        $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
 
-        return new FlushNode($token->getLine(), $this->getTag());
+        return new FlushNode($token->getLine());
     }
 
     public function getTag(): string
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ForTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ForTokenParser.php
index bac8ba2d..cf655f84 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ForTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ForTokenParser.php
@@ -35,30 +35,30 @@ final class ForTokenParser extends AbstractTokenParser
         $lineno = $token->getLine();
         $stream = $this->parser->getStream();
         $targets = $this->parser->getExpressionParser()->parseAssignmentExpression();
-        $stream->expect(/* Token::OPERATOR_TYPE */ 8, 'in');
+        $stream->expect(Token::OPERATOR_TYPE, 'in');
         $seq = $this->parser->getExpressionParser()->parseExpression();
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
         $body = $this->parser->subparse([$this, 'decideForFork']);
         if ('else' == $stream->next()->getValue()) {
-            $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+            $stream->expect(Token::BLOCK_END_TYPE);
             $else = $this->parser->subparse([$this, 'decideForEnd'], true);
         } else {
             $else = null;
         }
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
         if (\count($targets) > 1) {
-            $keyTarget = $targets->getNode(0);
+            $keyTarget = $targets->getNode('0');
             $keyTarget = new AssignNameExpression($keyTarget->getAttribute('name'), $keyTarget->getTemplateLine());
-            $valueTarget = $targets->getNode(1);
+            $valueTarget = $targets->getNode('1');
         } else {
             $keyTarget = new AssignNameExpression('_key', $lineno);
-            $valueTarget = $targets->getNode(0);
+            $valueTarget = $targets->getNode('0');
         }
         $valueTarget = new AssignNameExpression($valueTarget->getAttribute('name'), $valueTarget->getTemplateLine());
 
-        return new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, $lineno, $this->getTag());
+        return new ForNode($keyTarget, $valueTarget, $seq, null, $body, $else, $lineno);
     }
 
     public function decideForFork(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FromTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FromTokenParser.php
index 35098c26..2ccff5fb 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FromTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/FromTokenParser.php
@@ -29,28 +29,28 @@ final class FromTokenParser extends AbstractTokenParser
     {
         $macro = $this->parser->getExpressionParser()->parseExpression();
         $stream = $this->parser->getStream();
-        $stream->expect(/* Token::NAME_TYPE */ 5, 'import');
+        $stream->expect(Token::NAME_TYPE, 'import');
 
         $targets = [];
-        do {
-            $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
+        while (true) {
+            $name = $stream->expect(Token::NAME_TYPE)->getValue();
 
             $alias = $name;
             if ($stream->nextIf('as')) {
-                $alias = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
+                $alias = $stream->expect(Token::NAME_TYPE)->getValue();
             }
 
             $targets[$name] = $alias;
 
-            if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
+            if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) {
                 break;
             }
-        } while (true);
+        }
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
         $var = new AssignNameExpression($this->parser->getVarName(), $token->getLine());
-        $node = new ImportNode($macro, $var, $token->getLine(), $this->getTag(), $this->parser->isMainScope());
+        $node = new ImportNode($macro, $var, $token->getLine(), $this->parser->isMainScope());
 
         foreach ($targets as $name => $alias) {
             $this->parser->addImportedSymbol('function', $alias, 'macro_'.$name, $var);
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IfTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IfTokenParser.php
index c0fe6df0..4ea6f3df 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IfTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IfTokenParser.php
@@ -37,7 +37,7 @@ final class IfTokenParser extends AbstractTokenParser
         $lineno = $token->getLine();
         $expr = $this->parser->getExpressionParser()->parseExpression();
         $stream = $this->parser->getStream();
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
         $body = $this->parser->subparse([$this, 'decideIfFork']);
         $tests = [$expr, $body];
         $else = null;
@@ -46,13 +46,13 @@ final class IfTokenParser extends AbstractTokenParser
         while (!$end) {
             switch ($stream->next()->getValue()) {
                 case 'else':
-                    $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+                    $stream->expect(Token::BLOCK_END_TYPE);
                     $else = $this->parser->subparse([$this, 'decideIfEnd']);
                     break;
 
                 case 'elseif':
                     $expr = $this->parser->getExpressionParser()->parseExpression();
-                    $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+                    $stream->expect(Token::BLOCK_END_TYPE);
                     $body = $this->parser->subparse([$this, 'decideIfFork']);
                     $tests[] = $expr;
                     $tests[] = $body;
@@ -63,13 +63,13 @@ final class IfTokenParser extends AbstractTokenParser
                     break;
 
                 default:
-                    throw new SyntaxError(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d).', $lineno), $stream->getCurrent()->getLine(), $stream->getSourceContext());
+                    throw new SyntaxError(\sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d).', $lineno), $stream->getCurrent()->getLine(), $stream->getSourceContext());
             }
         }
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
-        return new IfNode(new Node($tests), $else, $lineno, $this->getTag());
+        return new IfNode(new Node($tests), $else, $lineno);
     }
 
     public function decideIfFork(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ImportTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ImportTokenParser.php
index 44cb4dad..f20f35ab 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ImportTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/ImportTokenParser.php
@@ -28,13 +28,13 @@ final class ImportTokenParser extends AbstractTokenParser
     public function parse(Token $token): Node
     {
         $macro = $this->parser->getExpressionParser()->parseExpression();
-        $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5, 'as');
-        $var = new AssignNameExpression($this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5)->getValue(), $token->getLine());
-        $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $this->parser->getStream()->expect(Token::NAME_TYPE, 'as');
+        $var = new AssignNameExpression($this->parser->getStream()->expect(Token::NAME_TYPE)->getValue(), $token->getLine());
+        $this->parser->getStream()->expect(Token::BLOCK_END_TYPE);
 
         $this->parser->addImportedSymbol('template', $var->getAttribute('name'));
 
-        return new ImportNode($macro, $var, $token->getLine(), $this->getTag(), $this->parser->isMainScope());
+        return new ImportNode($macro, $var, $token->getLine(), $this->parser->isMainScope());
     }
 
     public function getTag(): string
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php
index 28beb8ae..466f2288 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php
@@ -31,9 +31,9 @@ class IncludeTokenParser extends AbstractTokenParser
     {
         $expr = $this->parser->getExpressionParser()->parseExpression();
 
-        list($variables, $only, $ignoreMissing) = $this->parseArguments();
+        [$variables, $only, $ignoreMissing] = $this->parseArguments();
 
-        return new IncludeNode($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag());
+        return new IncludeNode($expr, $variables, $only, $ignoreMissing, $token->getLine());
     }
 
     protected function parseArguments()
@@ -41,23 +41,23 @@ class IncludeTokenParser extends AbstractTokenParser
         $stream = $this->parser->getStream();
 
         $ignoreMissing = false;
-        if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'ignore')) {
-            $stream->expect(/* Token::NAME_TYPE */ 5, 'missing');
+        if ($stream->nextIf(Token::NAME_TYPE, 'ignore')) {
+            $stream->expect(Token::NAME_TYPE, 'missing');
 
             $ignoreMissing = true;
         }
 
         $variables = null;
-        if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'with')) {
+        if ($stream->nextIf(Token::NAME_TYPE, 'with')) {
             $variables = $this->parser->getExpressionParser()->parseExpression();
         }
 
         $only = false;
-        if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'only')) {
+        if ($stream->nextIf(Token::NAME_TYPE, 'only')) {
             $only = true;
         }
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
         return [$variables, $only, $ignoreMissing];
     }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/MacroTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/MacroTokenParser.php
index f584927e..c7762075 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/MacroTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/MacroTokenParser.php
@@ -32,26 +32,26 @@ final class MacroTokenParser extends AbstractTokenParser
     {
         $lineno = $token->getLine();
         $stream = $this->parser->getStream();
-        $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
+        $name = $stream->expect(Token::NAME_TYPE)->getValue();
 
         $arguments = $this->parser->getExpressionParser()->parseArguments(true, true);
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
         $this->parser->pushLocalScope();
         $body = $this->parser->subparse([$this, 'decideBlockEnd'], true);
-        if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) {
+        if ($token = $stream->nextIf(Token::NAME_TYPE)) {
             $value = $token->getValue();
 
             if ($value != $name) {
-                throw new SyntaxError(sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext());
+                throw new SyntaxError(\sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext());
             }
         }
         $this->parser->popLocalScope();
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
-        $this->parser->setMacro($name, new MacroNode($name, new BodyNode([$body]), $arguments, $lineno, $this->getTag()));
+        $this->parser->setMacro($name, new MacroNode($name, new BodyNode([$body]), $arguments, $lineno));
 
-        return new Node();
+        return new Node([], [], $lineno);
     }
 
     public function decideBlockEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SandboxTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SandboxTokenParser.php
index c919556e..70869fbc 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SandboxTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SandboxTokenParser.php
@@ -34,9 +34,9 @@ final class SandboxTokenParser extends AbstractTokenParser
     public function parse(Token $token): Node
     {
         $stream = $this->parser->getStream();
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
         $body = $this->parser->subparse([$this, 'decideBlockEnd'], true);
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
         // in a sandbox tag, only include tags are allowed
         if (!$body instanceof IncludeNode) {
@@ -51,7 +51,7 @@ final class SandboxTokenParser extends AbstractTokenParser
             }
         }
 
-        return new SandboxNode($body, $token->getLine(), $this->getTag());
+        return new SandboxNode($body, $token->getLine());
     }
 
     public function decideBlockEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SetTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SetTokenParser.php
index 2fbdfe09..bb43907b 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SetTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/SetTokenParser.php
@@ -37,10 +37,10 @@ final class SetTokenParser extends AbstractTokenParser
         $names = $this->parser->getExpressionParser()->parseAssignmentExpression();
 
         $capture = false;
-        if ($stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) {
+        if ($stream->nextIf(Token::OPERATOR_TYPE, '=')) {
             $values = $this->parser->getExpressionParser()->parseMultitargetExpression();
 
-            $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+            $stream->expect(Token::BLOCK_END_TYPE);
 
             if (\count($names) !== \count($values)) {
                 throw new SyntaxError('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
@@ -52,13 +52,13 @@ final class SetTokenParser extends AbstractTokenParser
                 throw new SyntaxError('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
             }
 
-            $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+            $stream->expect(Token::BLOCK_END_TYPE);
 
             $values = $this->parser->subparse([$this, 'decideBlockEnd'], true);
-            $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+            $stream->expect(Token::BLOCK_END_TYPE);
         }
 
-        return new SetNode($capture, $names, $values, $lineno, $this->getTag());
+        return new SetNode($capture, $names, $values, $lineno);
     }
 
     public function decideBlockEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/TypesTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/TypesTokenParser.php
new file mode 100644
index 00000000..2e0850e7
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/TypesTokenParser.php
@@ -0,0 +1,86 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\TokenParser;
+
+use Twig\Error\SyntaxError;
+use Twig\Node\Node;
+use Twig\Node\TypesNode;
+use Twig\Token;
+use Twig\TokenStream;
+
+/**
+ * Declare variable types.
+ *
+ *  {% types {foo: 'int', bar?: 'string'} %}
+ *
+ * @author Jeroen Versteeg <[email protected]>
+ *
+ * @internal
+ */
+final class TypesTokenParser extends AbstractTokenParser
+{
+    public function parse(Token $token): Node
+    {
+        $stream = $this->parser->getStream();
+
+        $types = $this->parseSimpleMappingExpression($stream);
+
+        $stream->expect(Token::BLOCK_END_TYPE);
+
+        return new TypesNode($types, $token->getLine());
+    }
+
+    /**
+     * @return array<string, array{type: string, optional: bool}>
+     *
+     * @throws SyntaxError
+     */
+    private function parseSimpleMappingExpression(TokenStream $stream): array
+    {
+        $stream->expect(Token::PUNCTUATION_TYPE, '{', 'A mapping element was expected');
+
+        $types = [];
+
+        $first = true;
+        while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) {
+            if (!$first) {
+                $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A type string must be followed by a comma');
+
+                // trailing ,?
+                if ($stream->test(Token::PUNCTUATION_TYPE, '}')) {
+                    break;
+                }
+            }
+            $first = false;
+
+            $nameToken = $stream->expect(Token::NAME_TYPE);
+            $isOptional = null !== $stream->nextIf(Token::PUNCTUATION_TYPE, '?');
+
+            $stream->expect(Token::PUNCTUATION_TYPE, ':', 'A type name must be followed by a colon (:)');
+
+            $valueToken = $stream->expect(Token::STRING_TYPE);
+
+            $types[$nameToken->getValue()] = [
+                'type' => $valueToken->getValue(),
+                'optional' => $isOptional,
+            ];
+        }
+        $stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened mapping is not properly closed');
+
+        return $types;
+    }
+
+    public function getTag(): string
+    {
+        return 'types';
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/UseTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/UseTokenParser.php
index d0a2de41..1b96b404 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/UseTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/UseTokenParser.php
@@ -43,27 +43,27 @@ final class UseTokenParser extends AbstractTokenParser
 
         $targets = [];
         if ($stream->nextIf('with')) {
-            do {
-                $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
+            while (true) {
+                $name = $stream->expect(Token::NAME_TYPE)->getValue();
 
                 $alias = $name;
                 if ($stream->nextIf('as')) {
-                    $alias = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue();
+                    $alias = $stream->expect(Token::NAME_TYPE)->getValue();
                 }
 
                 $targets[$name] = new ConstantExpression($alias, -1);
 
-                if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) {
+                if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) {
                     break;
                 }
-            } while (true);
+            }
         }
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
         $this->parser->addTrait(new Node(['template' => $template, 'targets' => new Node($targets)]));
 
-        return new Node();
+        return new Node([], [], $token->getLine());
     }
 
     public function getTag(): string
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/WithTokenParser.php b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/WithTokenParser.php
index 7d8cbe26..8ce4f02b 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenParser/WithTokenParser.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenParser/WithTokenParser.php
@@ -30,18 +30,18 @@ final class WithTokenParser extends AbstractTokenParser
 
         $variables = null;
         $only = false;
-        if (!$stream->test(/* Token::BLOCK_END_TYPE */ 3)) {
+        if (!$stream->test(Token::BLOCK_END_TYPE)) {
             $variables = $this->parser->getExpressionParser()->parseExpression();
-            $only = (bool) $stream->nextIf(/* Token::NAME_TYPE */ 5, 'only');
+            $only = (bool) $stream->nextIf(Token::NAME_TYPE, 'only');
         }
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
         $body = $this->parser->subparse([$this, 'decideWithEnd'], true);
 
-        $stream->expect(/* Token::BLOCK_END_TYPE */ 3);
+        $stream->expect(Token::BLOCK_END_TYPE);
 
-        return new WithNode($body, $variables, $only, $token->getLine(), $this->getTag());
+        return new WithNode($body, $variables, $only, $token->getLine());
     }
 
     public function decideWithEnd(Token $token): bool
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TokenStream.php b/data/web/inc/lib/vendor/twig/twig/src/TokenStream.php
index 1eac11a0..c91701bf 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TokenStream.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TokenStream.php
@@ -21,13 +21,12 @@ use Twig\Error\SyntaxError;
  */
 final class TokenStream
 {
-    private $tokens;
     private $current = 0;
-    private $source;
 
-    public function __construct(array $tokens, Source $source = null)
-    {
-        $this->tokens = $tokens;
+    public function __construct(
+        private array $tokens,
+        private ?Source $source = null,
+    ) {
         $this->source = $source ?: new Source('', '');
     }
 
@@ -60,24 +59,22 @@ final class TokenStream
      */
     public function nextIf($primary, $secondary = null)
     {
-        if ($this->tokens[$this->current]->test($primary, $secondary)) {
-            return $this->next();
-        }
+        return $this->tokens[$this->current]->test($primary, $secondary) ? $this->next() : null;
     }
 
     /**
      * Tests a token and returns it or throws a syntax error.
      */
-    public function expect($type, $value = null, string $message = null): Token
+    public function expect($type, $value = null, ?string $message = null): Token
     {
         $token = $this->tokens[$this->current];
         if (!$token->test($type, $value)) {
             $line = $token->getLine();
-            throw new SyntaxError(sprintf('%sUnexpected token "%s"%s ("%s" expected%s).',
+            throw new SyntaxError(\sprintf('%sUnexpected token "%s"%s ("%s" expected%s).',
                 $message ? $message.'. ' : '',
                 Token::typeToEnglish($token->getType()),
-                $token->getValue() ? sprintf(' of value "%s"', $token->getValue()) : '',
-                Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''),
+                $token->getValue() ? \sprintf(' of value "%s"', $token->getValue()) : '',
+                Token::typeToEnglish($type), $value ? \sprintf(' with value "%s"', $value) : ''),
                 $line,
                 $this->source
             );
@@ -112,7 +109,7 @@ final class TokenStream
      */
     public function isEOF(): bool
     {
-        return /* Token::EOF_TYPE */ -1 === $this->tokens[$this->current]->getType();
+        return Token::EOF_TYPE === $this->tokens[$this->current]->getType();
     }
 
     public function getCurrent(): Token
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TwigCallableInterface.php b/data/web/inc/lib/vendor/twig/twig/src/TwigCallableInterface.php
new file mode 100644
index 00000000..2a8ff611
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/TwigCallableInterface.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig;
+
+/**
+ * @author Fabien Potencier <[email protected]>
+ */
+interface TwigCallableInterface extends \Stringable
+{
+    public function getName(): string;
+
+    public function getType(): string;
+
+    public function getDynamicName(): string;
+
+    /**
+     * @return callable|array{class-string, string}|null
+     */
+    public function getCallable();
+
+    public function getNodeClass(): string;
+
+    public function needsCharset(): bool;
+
+    public function needsEnvironment(): bool;
+
+    public function needsContext(): bool;
+
+    public function withDynamicArguments(string $name, string $dynamicName, array $arguments): self;
+
+    public function getArguments(): array;
+
+    public function isVariadic(): bool;
+
+    public function isDeprecated(): bool;
+
+    public function getDeprecatingPackage(): string;
+
+    public function getDeprecatedVersion(): string;
+
+    public function getAlternative(): ?string;
+
+    public function getMinimalNumberOfRequiredArguments(): int;
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TwigFilter.php b/data/web/inc/lib/vendor/twig/twig/src/TwigFilter.php
index 94e5f9b0..70b1f8f3 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TwigFilter.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TwigFilter.php
@@ -21,72 +21,27 @@ use Twig\Node\Node;
  *
  * @see https://twig.symfony.com/doc/templates.html#filters
  */
-final class TwigFilter
+final class TwigFilter extends AbstractTwigCallable
 {
-    private $name;
-    private $callable;
-    private $options;
-    private $arguments = [];
-
     /**
-     * @param callable|null $callable A callable implementing the filter. If null, you need to overwrite the "node_class" option to customize compilation.
+     * @param callable|array{class-string, string}|null $callable A callable implementing the filter. If null, you need to overwrite the "node_class" option to customize compilation.
      */
     public function __construct(string $name, $callable = null, array $options = [])
     {
-        $this->name = $name;
-        $this->callable = $callable;
+        parent::__construct($name, $callable, $options);
+
         $this->options = array_merge([
-            'needs_environment' => false,
-            'needs_context' => false,
-            'is_variadic' => false,
             'is_safe' => null,
             'is_safe_callback' => null,
             'pre_escape' => null,
             'preserves_safety' => null,
             'node_class' => FilterExpression::class,
-            'deprecated' => false,
-            'alternative' => null,
-        ], $options);
-    }
-
-    public function getName(): string
-    {
-        return $this->name;
-    }
-
-    /**
-     * Returns the callable to execute for this filter.
-     *
-     * @return callable|null
-     */
-    public function getCallable()
-    {
-        return $this->callable;
-    }
-
-    public function getNodeClass(): string
-    {
-        return $this->options['node_class'];
-    }
-
-    public function setArguments(array $arguments): void
-    {
-        $this->arguments = $arguments;
+        ], $this->options);
     }
 
-    public function getArguments(): array
+    public function getType(): string
     {
-        return $this->arguments;
-    }
-
-    public function needsEnvironment(): bool
-    {
-        return $this->options['needs_environment'];
-    }
-
-    public function needsContext(): bool
-    {
-        return $this->options['needs_context'];
+        return 'filter';
     }
 
     public function getSafe(Node $filterArgs): ?array
@@ -112,23 +67,8 @@ final class TwigFilter
         return $this->options['pre_escape'];
     }
 
-    public function isVariadic(): bool
-    {
-        return $this->options['is_variadic'];
-    }
-
-    public function isDeprecated(): bool
-    {
-        return (bool) $this->options['deprecated'];
-    }
-
-    public function getDeprecatedVersion(): string
-    {
-        return \is_bool($this->options['deprecated']) ? '' : $this->options['deprecated'];
-    }
-
-    public function getAlternative(): ?string
+    public function getMinimalNumberOfRequiredArguments(): int
     {
-        return $this->options['alternative'];
+        return parent::getMinimalNumberOfRequiredArguments() + 1;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TwigFunction.php b/data/web/inc/lib/vendor/twig/twig/src/TwigFunction.php
index 494d45b0..4a10df95 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TwigFunction.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TwigFunction.php
@@ -21,70 +21,31 @@ use Twig\Node\Node;
  *
  * @see https://twig.symfony.com/doc/templates.html#functions
  */
-final class TwigFunction
+final class TwigFunction extends AbstractTwigCallable
 {
-    private $name;
-    private $callable;
-    private $options;
-    private $arguments = [];
-
     /**
-     * @param callable|null $callable A callable implementing the function. If null, you need to overwrite the "node_class" option to customize compilation.
+     * @param callable|array{class-string, string}|null $callable A callable implementing the function. If null, you need to overwrite the "node_class" option to customize compilation.
      */
     public function __construct(string $name, $callable = null, array $options = [])
     {
-        $this->name = $name;
-        $this->callable = $callable;
+        parent::__construct($name, $callable, $options);
+
         $this->options = array_merge([
-            'needs_environment' => false,
-            'needs_context' => false,
-            'is_variadic' => false,
             'is_safe' => null,
             'is_safe_callback' => null,
             'node_class' => FunctionExpression::class,
-            'deprecated' => false,
-            'alternative' => null,
-        ], $options);
-    }
-
-    public function getName(): string
-    {
-        return $this->name;
-    }
-
-    /**
-     * Returns the callable to execute for this function.
-     *
-     * @return callable|null
-     */
-    public function getCallable()
-    {
-        return $this->callable;
-    }
-
-    public function getNodeClass(): string
-    {
-        return $this->options['node_class'];
-    }
-
-    public function setArguments(array $arguments): void
-    {
-        $this->arguments = $arguments;
+            'parser_callable' => null,
+        ], $this->options);
     }
 
-    public function getArguments(): array
+    public function getType(): string
     {
-        return $this->arguments;
+        return 'function';
     }
 
-    public function needsEnvironment(): bool
+    public function getParserCallable(): ?callable
     {
-        return $this->options['needs_environment'];
-    }
-
-    public function needsContext(): bool
-    {
-        return $this->options['needs_context'];
+        return $this->options['parser_callable'];
     }
 
     public function getSafe(Node $functionArgs): ?array
@@ -99,24 +60,4 @@ final class TwigFunction
 
         return [];
     }
-
-    public function isVariadic(): bool
-    {
-        return (bool) $this->options['is_variadic'];
-    }
-
-    public function isDeprecated(): bool
-    {
-        return (bool) $this->options['deprecated'];
-    }
-
-    public function getDeprecatedVersion(): string
-    {
-        return \is_bool($this->options['deprecated']) ? '' : $this->options['deprecated'];
-    }
-
-    public function getAlternative(): ?string
-    {
-        return $this->options['alternative'];
-    }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/TwigTest.php b/data/web/inc/lib/vendor/twig/twig/src/TwigTest.php
index 4c18632f..5e58ad8b 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/TwigTest.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/TwigTest.php
@@ -20,81 +20,48 @@ use Twig\Node\Expression\TestExpression;
  *
  * @see https://twig.symfony.com/doc/templates.html#test-operator
  */
-final class TwigTest
+final class TwigTest extends AbstractTwigCallable
 {
-    private $name;
-    private $callable;
-    private $options;
-    private $arguments = [];
-
     /**
-     * @param callable|null $callable A callable implementing the test. If null, you need to overwrite the "node_class" option to customize compilation.
+     * @param callable|array{class-string, string}|null $callable A callable implementing the test. If null, you need to overwrite the "node_class" option to customize compilation.
      */
     public function __construct(string $name, $callable = null, array $options = [])
     {
-        $this->name = $name;
-        $this->callable = $callable;
+        parent::__construct($name, $callable, $options);
+
         $this->options = array_merge([
-            'is_variadic' => false,
             'node_class' => TestExpression::class,
-            'deprecated' => false,
-            'alternative' => null,
             'one_mandatory_argument' => false,
-        ], $options);
-    }
-
-    public function getName(): string
-    {
-        return $this->name;
-    }
-
-    /**
-     * Returns the callable to execute for this test.
-     *
-     * @return callable|null
-     */
-    public function getCallable()
-    {
-        return $this->callable;
+        ], $this->options);
     }
 
-    public function getNodeClass(): string
+    public function getType(): string
     {
-        return $this->options['node_class'];
+        return 'test';
     }
 
-    public function setArguments(array $arguments): void
+    public function needsCharset(): bool
     {
-        $this->arguments = $arguments;
+        return false;
     }
 
-    public function getArguments(): array
+    public function needsEnvironment(): bool
     {
-        return $this->arguments;
+        return false;
     }
 
-    public function isVariadic(): bool
+    public function needsContext(): bool
     {
-        return (bool) $this->options['is_variadic'];
+        return false;
     }
 
-    public function isDeprecated(): bool
-    {
-        return (bool) $this->options['deprecated'];
-    }
-
-    public function getDeprecatedVersion(): string
-    {
-        return \is_bool($this->options['deprecated']) ? '' : $this->options['deprecated'];
-    }
-
-    public function getAlternative(): ?string
+    public function hasOneMandatoryArgument(): bool
     {
-        return $this->options['alternative'];
+        return (bool) $this->options['one_mandatory_argument'];
     }
 
-    public function hasOneMandatoryArgument(): bool
+    public function getMinimalNumberOfRequiredArguments(): int
     {
-        return (bool) $this->options['one_mandatory_argument'];
+        return parent::getMinimalNumberOfRequiredArguments() + 1;
     }
 }
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Util/CallableArgumentsExtractor.php b/data/web/inc/lib/vendor/twig/twig/src/Util/CallableArgumentsExtractor.php
new file mode 100644
index 00000000..8811ca9c
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Util/CallableArgumentsExtractor.php
@@ -0,0 +1,204 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Util;
+
+use Twig\Error\SyntaxError;
+use Twig\Node\Expression\ArrayExpression;
+use Twig\Node\Expression\ConstantExpression;
+use Twig\Node\Expression\VariadicExpression;
+use Twig\Node\Node;
+use Twig\TwigCallableInterface;
+
+/**
+ * @author Fabien Potencier <[email protected]>
+ *
+ * @internal
+ */
+final class CallableArgumentsExtractor
+{
+    private ReflectionCallable $rc;
+
+    public function __construct(
+        private Node $node,
+        private TwigCallableInterface $twigCallable,
+    ) {
+        $this->rc = new ReflectionCallable($twigCallable);
+    }
+
+    /**
+     * @return array<Node>
+     */
+    public function extractArguments(Node $arguments): array
+    {
+        $extractedArguments = [];
+        $named = false;
+        foreach ($arguments as $name => $node) {
+            if (!\is_int($name)) {
+                $named = true;
+                $name = $this->normalizeName($name);
+            } elseif ($named) {
+                throw new SyntaxError(\sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->twigCallable->getType(), $this->twigCallable->getName()), $this->node->getTemplateLine(), $this->node->getSourceContext());
+            }
+
+            $extractedArguments[$name] = $node;
+        }
+
+        if (!$named && !$this->twigCallable->isVariadic()) {
+            $min = $this->twigCallable->getMinimalNumberOfRequiredArguments();
+            if (\count($extractedArguments) < $this->rc->getReflector()->getNumberOfRequiredParameters() - $min) {
+                throw new SyntaxError(\sprintf('Value for argument "%s" is required for %s "%s".', $this->rc->getReflector()->getParameters()[$min + \count($extractedArguments)]->getName(), $this->twigCallable->getType(), $this->twigCallable->getName()), $this->node->getTemplateLine(), $this->node->getSourceContext());
+            }
+
+            return $extractedArguments;
+        }
+
+        if (!$callable = $this->twigCallable->getCallable()) {
+            if ($named) {
+                throw new SyntaxError(\sprintf('Named arguments are not supported for %s "%s".', $this->twigCallable->getType(), $this->twigCallable->getName()));
+            }
+
+            throw new SyntaxError(\sprintf('Arbitrary positional arguments are not supported for %s "%s".', $this->twigCallable->getType(), $this->twigCallable->getName()));
+        }
+
+        [$callableParameters, $isPhpVariadic] = $this->getCallableParameters();
+        $arguments = [];
+        $names = [];
+        $missingArguments = [];
+        $optionalArguments = [];
+        $pos = 0;
+        foreach ($callableParameters as $callableParameter) {
+            $name = $this->normalizeName($callableParameter->name);
+            if (\PHP_VERSION_ID >= 80000 && 'range' === $callable) {
+                if ('start' === $name) {
+                    $name = 'low';
+                } elseif ('end' === $name) {
+                    $name = 'high';
+                }
+            }
+
+            $names[] = $name;
+
+            if (\array_key_exists($name, $extractedArguments)) {
+                if (\array_key_exists($pos, $extractedArguments)) {
+                    throw new SyntaxError(\sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->twigCallable->getType(), $this->twigCallable->getName()), $this->node->getTemplateLine(), $this->node->getSourceContext());
+                }
+
+                if (\count($missingArguments)) {
+                    throw new SyntaxError(\sprintf(
+                        'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".',
+                        $name, $this->twigCallable->getType(), $this->twigCallable->getName(), implode(', ', $names), \count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments)
+                    ), $this->node->getTemplateLine(), $this->node->getSourceContext());
+                }
+
+                $arguments = array_merge($arguments, $optionalArguments);
+                $arguments[] = $extractedArguments[$name];
+                unset($extractedArguments[$name]);
+                $optionalArguments = [];
+            } elseif (\array_key_exists($pos, $extractedArguments)) {
+                $arguments = array_merge($arguments, $optionalArguments);
+                $arguments[] = $extractedArguments[$pos];
+                unset($extractedArguments[$pos]);
+                $optionalArguments = [];
+                ++$pos;
+            } elseif ($callableParameter->isDefaultValueAvailable()) {
+                $optionalArguments[] = new ConstantExpression($callableParameter->getDefaultValue(), $this->node->getTemplateLine());
+            } elseif ($callableParameter->isOptional()) {
+                if (!$extractedArguments) {
+                    break;
+                }
+
+                $missingArguments[] = $name;
+            } else {
+                throw new SyntaxError(\sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->twigCallable->getType(), $this->twigCallable->getName()), $this->node->getTemplateLine(), $this->node->getSourceContext());
+            }
+        }
+
+        if ($this->twigCallable->isVariadic()) {
+            $arbitraryArguments = $isPhpVariadic ? new VariadicExpression([], $this->node->getTemplateLine()) : new ArrayExpression([], $this->node->getTemplateLine());
+            foreach ($extractedArguments as $key => $value) {
+                if (\is_int($key)) {
+                    $arbitraryArguments->addElement($value);
+                } else {
+                    $arbitraryArguments->addElement($value, new ConstantExpression($key, $this->node->getTemplateLine()));
+                }
+                unset($extractedArguments[$key]);
+            }
+
+            if ($arbitraryArguments->count()) {
+                $arguments = array_merge($arguments, $optionalArguments);
+                $arguments[] = $arbitraryArguments;
+            }
+        }
+
+        if ($extractedArguments) {
+            $unknownArgument = null;
+            foreach ($extractedArguments as $extractedArgument) {
+                if ($extractedArgument instanceof Node) {
+                    $unknownArgument = $extractedArgument;
+                    break;
+                }
+            }
+
+            throw new SyntaxError(
+                \sprintf(
+                    'Unknown argument%s "%s" for %s "%s(%s)".',
+                    \count($extractedArguments) > 1 ? 's' : '', implode('", "', array_keys($extractedArguments)), $this->twigCallable->getType(), $this->twigCallable->getName(), implode(', ', $names)
+                ),
+                $unknownArgument ? $unknownArgument->getTemplateLine() : $this->node->getTemplateLine(),
+                $unknownArgument ? $unknownArgument->getSourceContext() : $this->node->getSourceContext()
+            );
+        }
+
+        return $arguments;
+    }
+
+    private function normalizeName(string $name): string
+    {
+        return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], $name));
+    }
+
+    private function getCallableParameters(): array
+    {
+        $parameters = $this->rc->getReflector()->getParameters();
+        if ($this->node->hasNode('node')) {
+            array_shift($parameters);
+        }
+        if ($this->twigCallable->needsCharset()) {
+            array_shift($parameters);
+        }
+        if ($this->twigCallable->needsEnvironment()) {
+            array_shift($parameters);
+        }
+        if ($this->twigCallable->needsContext()) {
+            array_shift($parameters);
+        }
+        foreach ($this->twigCallable->getArguments() as $argument) {
+            array_shift($parameters);
+        }
+
+        $isPhpVariadic = false;
+        if ($this->twigCallable->isVariadic()) {
+            $argument = end($parameters);
+            $isArray = $argument && $argument->hasType() && $argument->getType() instanceof \ReflectionNamedType && 'array' === $argument->getType()->getName();
+            if ($isArray && $argument->isDefaultValueAvailable() && [] === $argument->getDefaultValue()) {
+                array_pop($parameters);
+            } elseif ($argument && $argument->isVariadic()) {
+                array_pop($parameters);
+                $isPhpVariadic = true;
+            } else {
+                throw new SyntaxError(\sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = []".', $this->rc->getName(), $this->twigCallable->getType(), $this->twigCallable->getName()));
+            }
+        }
+
+        return [$parameters, $isPhpVariadic];
+    }
+}
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Util/DeprecationCollector.php b/data/web/inc/lib/vendor/twig/twig/src/Util/DeprecationCollector.php
index 378b666b..0ea26ed4 100644
--- a/data/web/inc/lib/vendor/twig/twig/src/Util/DeprecationCollector.php
+++ b/data/web/inc/lib/vendor/twig/twig/src/Util/DeprecationCollector.php
@@ -20,11 +20,9 @@ use Twig\Source;
  */
 final class DeprecationCollector
 {
-    private $twig;
-
-    public function __construct(Environment $twig)
-    {
-        $this->twig = $twig;
+    public function __construct(
+        private Environment $twig,
+    ) {
     }
 
     /**
@@ -60,6 +58,8 @@ final class DeprecationCollector
             if (\E_USER_DEPRECATED === $type) {
                 $deprecations[] = $msg;
             }
+
+            return false;
         });
 
         foreach ($iterator as $name => $contents) {
diff --git a/data/web/inc/lib/vendor/twig/twig/src/Util/ReflectionCallable.php b/data/web/inc/lib/vendor/twig/twig/src/Util/ReflectionCallable.php
new file mode 100644
index 00000000..16734d9d
--- /dev/null
+++ b/data/web/inc/lib/vendor/twig/twig/src/Util/ReflectionCallable.php
@@ -0,0 +1,92 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Twig\Util;
+
+use Twig\TwigCallableInterface;
+
+/**
+ * @author Fabien Potencier <[email protected]>
+ *
+ * @internal
+ */
+final class ReflectionCallable
+{
+    private $reflector;
+    private $callable;
+    private $name;
+
+    public function __construct(
+        TwigCallableInterface $twigCallable,
+    ) {
+        $callable = $twigCallable->getCallable();
+        if (\is_string($callable) && false !== $pos = strpos($callable, '::')) {
+            $callable = [substr($callable, 0, $pos), substr($callable, 2 + $pos)];
+        }
+
+        if (\is_array($callable) && method_exists($callable[0], $callable[1])) {
+            $this->reflector = $r = new \ReflectionMethod($callable[0], $callable[1]);
+            $this->callable = $callable;
+            $this->name = $r->class.'::'.$r->name;
+
+            return;
+        }
+
+        $checkVisibility = $callable instanceof \Closure;
+        try {
+            $closure = \Closure::fromCallable($callable);
+        } catch (\TypeError $e) {
+            throw new \LogicException(\sprintf('Callback for %s "%s" is not callable in the current scope.', $twigCallable->getType(), $twigCallable->getName()), 0, $e);
+        }
+        $this->reflector = $r = new \ReflectionFunction($closure);
+
+        if (str_contains($r->name, '{closure')) {
+            $this->callable = $callable;
+            $this->name = 'Closure';
+
+            return;
+        }
+
+        if ($object = $r->getClosureThis()) {
+            $callable = [$object, $r->name];
+            $this->name = get_debug_type($object).'::'.$r->name;
+        } elseif (\PHP_VERSION_ID >= 80111 && $class = $r->getClosureCalledClass()) {
+            $callable = [$class->name, $r->name];
+            $this->name = $class->name.'::'.$r->name;
+        } elseif (\PHP_VERSION_ID < 80111 && $class = $r->getClosureScopeClass()) {
+            $callable = [\is_array($callable) ? $callable[0] : $class->name, $r->name];
+            $this->name = (\is_array($callable) ? $callable[0] : $class->name).'::'.$r->name;
+        } else {
+            $callable = $this->name = $r->name;
+        }
+
+        if ($checkVisibility && \is_array($callable) && method_exists(...$callable) && !(new \ReflectionMethod(...$callable))->isPublic()) {
+            $callable = $r->getClosure();
+        }
+
+        $this->callable = $callable;
+    }
+
+    public function getReflector(): \ReflectionFunctionAbstract
+    {
+        return $this->reflector;
+    }
+
+    public function getCallable()
+    {
+        return $this->callable;
+    }
+
+    public function getName(): string
+    {
+        return $this->name;
+    }
+}