diff --git a/composer.json b/composer.json
index d84889e1841de013a80316c5c295b2fa6aefe881..fdb70b8e51f01c04d3ca07deca595ac44d041b1c 100644
--- a/composer.json
+++ b/composer.json
@@ -117,15 +117,15 @@
         "drupal/entity_browser": "2.8",
         "drupal/entity_clone": "1.0.0-beta7",
         "drupal/entity_embed": "1.3",
-        "drupal/entity_reference_revisions": "1.9",
+        "drupal/entity_reference_revisions": "1.10",
         "drupal/exif_orientation": "^1.1",
         "drupal/externalauth": "1.4",
-        "drupal/field_group": "3.3",
-        "drupal/field_permissions": "1.1",
+        "drupal/field_group": "3.4",
+        "drupal/field_permissions": "1.2",
         "drupal/file_browser": "1.3",
         "drupal/focal_point": "1.5",
         "drupal/google_analytics": "^4.0",
-        "drupal/google_tag": "1.4",
+        "drupal/google_tag": "1.5",
         "drupal/honeypot": "2.1.2",
         "drupal/inline_entity_form": "1.0-rc9",
         "drupal/libraries": "3.0-beta1",
diff --git a/composer.lock b/composer.lock
index 52bbed877f75930e2c73f1bf940227249b6bf33b..9f77354148422507b345157c7ec0d5e1b573994d 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "9dc87a1389d83c78b818424bc14b49fd",
+    "content-hash": "34725321c1b77f13acdd41e96c52fb5d",
     "packages": [
         {
             "name": "alchemy/zippy",
@@ -2285,26 +2285,26 @@
         },
         {
             "name": "drupal/bootstrap",
-            "version": "3.23.0",
+            "version": "3.25.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/bootstrap.git",
-                "reference": "8.x-3.23"
+                "reference": "8.x-3.25"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/bootstrap-8.x-3.23.zip",
-                "reference": "8.x-3.23",
-                "shasum": "9849be667cc678a91ad29f77c2baea2cf16878bc"
+                "url": "https://ftp.drupal.org/files/projects/bootstrap-8.x-3.25.zip",
+                "reference": "8.x-3.25",
+                "shasum": "1334aad091973f53ddc4d7b426ee85e7428a3684"
             },
             "require": {
-                "drupal/core": "^8 || ^9"
+                "drupal/core": "^9.3 || ^10"
             },
             "type": "drupal-theme",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.23",
-                    "datestamp": "1592175762",
+                    "version": "8.x-3.25",
+                    "datestamp": "1654873483",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -2330,6 +2330,11 @@
                     "name": "Fabiano Sant'Ana (wundo)",
                     "homepage": "https://www.drupal.org/u/wundo",
                     "role": "Co-maintainer"
+                },
+                {
+                    "name": "Shelane French (shelane)",
+                    "homepage": "https://www.drupal.org/u/shelane",
+                    "role": "Co-maintainer"
                 }
             ],
             "description": "Built to use Bootstrap, a sleek, intuitive, and powerful front-end framework for faster and easier web development.",
@@ -4166,20 +4171,20 @@
         },
         {
             "name": "drupal/entity_reference_revisions",
-            "version": "1.9.0",
+            "version": "1.10.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/entity_reference_revisions.git",
-                "reference": "8.x-1.9"
+                "reference": "8.x-1.10"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/entity_reference_revisions-8.x-1.9.zip",
-                "reference": "8.x-1.9",
-                "shasum": "e1c51bdea495eb3b458130d6f0a00c347f5637df"
+                "url": "https://ftp.drupal.org/files/projects/entity_reference_revisions-8.x-1.10.zip",
+                "reference": "8.x-1.10",
+                "shasum": "edd23b91c4a34db65ea22c4db54b7458edc7513b"
             },
             "require": {
-                "drupal/core": "^8.7.7 || ^9"
+                "drupal/core": "^9 || ^10"
             },
             "require-dev": {
                 "drupal/diff": "1.x-dev"
@@ -4187,12 +4192,17 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.9",
-                    "datestamp": "1614805871",
+                    "version": "8.x-1.10",
+                    "datestamp": "1660664712",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
                     }
+                },
+                "drush": {
+                    "services": {
+                        "drush.services.yml": "^9 || ^10 || ^11"
+                    }
                 }
             },
             "notification-url": "https://packages.drupal.org/8/downloads",
@@ -4325,29 +4335,26 @@
         },
         {
             "name": "drupal/field_group",
-            "version": "3.3.0",
+            "version": "3.4.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/field_group.git",
-                "reference": "8.x-3.3"
+                "reference": "8.x-3.4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.3.zip",
-                "reference": "8.x-3.3",
-                "shasum": "c7a423b1d7643ee40dd1543d72fa04e8ac1756e4"
+                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.4.zip",
+                "reference": "8.x-3.4",
+                "shasum": "80b937e1a11f8b29c69d853fc4bf798c057c6f94"
             },
             "require": {
-                "drupal/core": "^8.8 || ^9"
-            },
-            "require-dev": {
-                "drupal/jquery_ui_accordion": "^1.0"
+                "drupal/core": "^9.2 || ^10"
             },
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.3",
-                    "datestamp": "1663516404",
+                    "version": "8.x-3.4",
+                    "datestamp": "1667241979",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -4389,26 +4396,26 @@
         },
         {
             "name": "drupal/field_permissions",
-            "version": "1.1.0",
+            "version": "1.2.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/field_permissions.git",
-                "reference": "8.x-1.1"
+                "reference": "8.x-1.2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.1.zip",
-                "reference": "8.x-1.1",
-                "shasum": "11e31db94999e6871ad7633455315bc27989a7ea"
+                "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.2.zip",
+                "reference": "8.x-1.2",
+                "shasum": "0b1a5edfac518fe6005d015b3781774b41cdec76"
             },
             "require": {
-                "drupal/core": "^8 || ^9"
+                "drupal/core": ">=8.9 <11"
             },
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.1",
-                    "datestamp": "1598646882",
+                    "version": "8.x-1.2",
+                    "datestamp": "1658941749",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -4631,17 +4638,17 @@
         },
         {
             "name": "drupal/google_tag",
-            "version": "1.4.0",
+            "version": "1.5.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/google_tag.git",
-                "reference": "8.x-1.4"
+                "reference": "8.x-1.5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.4.zip",
-                "reference": "8.x-1.4",
-                "shasum": "1bdc6f93d1c79c27738320597f2185f5de37432f"
+                "url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.5.zip",
+                "reference": "8.x-1.5",
+                "shasum": "b2929a517cc86bb3e54dded127556f18236a8628"
             },
             "require": {
                 "drupal/core": "^8.8 || ^9"
@@ -4649,8 +4656,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.4",
-                    "datestamp": "1593179846",
+                    "version": "8.x-1.5",
+                    "datestamp": "1648569365",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 8b1b270136c1ebec852c0480c7d18c3d3ba149fe..ffdd21e44532e2cbfd39d705b77904f4e5d20bf4 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -2355,27 +2355,27 @@
         },
         {
             "name": "drupal/bootstrap",
-            "version": "3.23.0",
-            "version_normalized": "3.23.0.0",
+            "version": "3.25.0",
+            "version_normalized": "3.25.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/bootstrap.git",
-                "reference": "8.x-3.23"
+                "reference": "8.x-3.25"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/bootstrap-8.x-3.23.zip",
-                "reference": "8.x-3.23",
-                "shasum": "9849be667cc678a91ad29f77c2baea2cf16878bc"
+                "url": "https://ftp.drupal.org/files/projects/bootstrap-8.x-3.25.zip",
+                "reference": "8.x-3.25",
+                "shasum": "1334aad091973f53ddc4d7b426ee85e7428a3684"
             },
             "require": {
-                "drupal/core": "^8 || ^9"
+                "drupal/core": "^9.3 || ^10"
             },
             "type": "drupal-theme",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.23",
-                    "datestamp": "1592175762",
+                    "version": "8.x-3.25",
+                    "datestamp": "1654873483",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -2402,6 +2402,11 @@
                     "name": "Fabiano Sant'Ana (wundo)",
                     "homepage": "https://www.drupal.org/u/wundo",
                     "role": "Co-maintainer"
+                },
+                {
+                    "name": "Shelane French (shelane)",
+                    "homepage": "https://www.drupal.org/u/shelane",
+                    "role": "Co-maintainer"
                 }
             ],
             "description": "Built to use Bootstrap, a sleek, intuitive, and powerful front-end framework for faster and easier web development.",
@@ -4299,21 +4304,21 @@
         },
         {
             "name": "drupal/entity_reference_revisions",
-            "version": "1.9.0",
-            "version_normalized": "1.9.0.0",
+            "version": "1.10.0",
+            "version_normalized": "1.10.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/entity_reference_revisions.git",
-                "reference": "8.x-1.9"
+                "reference": "8.x-1.10"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/entity_reference_revisions-8.x-1.9.zip",
-                "reference": "8.x-1.9",
-                "shasum": "e1c51bdea495eb3b458130d6f0a00c347f5637df"
+                "url": "https://ftp.drupal.org/files/projects/entity_reference_revisions-8.x-1.10.zip",
+                "reference": "8.x-1.10",
+                "shasum": "edd23b91c4a34db65ea22c4db54b7458edc7513b"
             },
             "require": {
-                "drupal/core": "^8.7.7 || ^9"
+                "drupal/core": "^9 || ^10"
             },
             "require-dev": {
                 "drupal/diff": "1.x-dev"
@@ -4321,12 +4326,17 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.9",
-                    "datestamp": "1614805871",
+                    "version": "8.x-1.10",
+                    "datestamp": "1660664712",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
                     }
+                },
+                "drush": {
+                    "services": {
+                        "drush.services.yml": "^9 || ^10 || ^11"
+                    }
                 }
             },
             "installation-source": "dist",
@@ -4467,30 +4477,27 @@
         },
         {
             "name": "drupal/field_group",
-            "version": "3.3.0",
-            "version_normalized": "3.3.0.0",
+            "version": "3.4.0",
+            "version_normalized": "3.4.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/field_group.git",
-                "reference": "8.x-3.3"
+                "reference": "8.x-3.4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.3.zip",
-                "reference": "8.x-3.3",
-                "shasum": "c7a423b1d7643ee40dd1543d72fa04e8ac1756e4"
+                "url": "https://ftp.drupal.org/files/projects/field_group-8.x-3.4.zip",
+                "reference": "8.x-3.4",
+                "shasum": "80b937e1a11f8b29c69d853fc4bf798c057c6f94"
             },
             "require": {
-                "drupal/core": "^8.8 || ^9"
-            },
-            "require-dev": {
-                "drupal/jquery_ui_accordion": "^1.0"
+                "drupal/core": "^9.2 || ^10"
             },
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-3.3",
-                    "datestamp": "1663516404",
+                    "version": "8.x-3.4",
+                    "datestamp": "1667241979",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -4534,27 +4541,27 @@
         },
         {
             "name": "drupal/field_permissions",
-            "version": "1.1.0",
-            "version_normalized": "1.1.0.0",
+            "version": "1.2.0",
+            "version_normalized": "1.2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/field_permissions.git",
-                "reference": "8.x-1.1"
+                "reference": "8.x-1.2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.1.zip",
-                "reference": "8.x-1.1",
-                "shasum": "11e31db94999e6871ad7633455315bc27989a7ea"
+                "url": "https://ftp.drupal.org/files/projects/field_permissions-8.x-1.2.zip",
+                "reference": "8.x-1.2",
+                "shasum": "0b1a5edfac518fe6005d015b3781774b41cdec76"
             },
             "require": {
-                "drupal/core": "^8 || ^9"
+                "drupal/core": ">=8.9 <11"
             },
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.1",
-                    "datestamp": "1598646882",
+                    "version": "8.x-1.2",
+                    "datestamp": "1658941749",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
@@ -4570,10 +4577,6 @@
                 "GPL-2.0-or-later"
             ],
             "authors": [
-                {
-                    "name": "RobLoach",
-                    "homepage": "https://www.drupal.org/user/61114"
-                },
                 {
                     "name": "japerry",
                     "homepage": "https://www.drupal.org/user/45640"
@@ -4589,6 +4592,10 @@
                 {
                     "name": "markus_petrux",
                     "homepage": "https://www.drupal.org/user/39593"
+                },
+                {
+                    "name": "RobLoach",
+                    "homepage": "https://www.drupal.org/user/61114"
                 }
             ],
             "description": "The Field Permissions module allows site administrators to set field-level permissions to edit, view and create fields on any entity.",
@@ -4784,18 +4791,18 @@
         },
         {
             "name": "drupal/google_tag",
-            "version": "1.4.0",
-            "version_normalized": "1.4.0.0",
+            "version": "1.5.0",
+            "version_normalized": "1.5.0.0",
             "source": {
                 "type": "git",
                 "url": "https://git.drupalcode.org/project/google_tag.git",
-                "reference": "8.x-1.4"
+                "reference": "8.x-1.5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.4.zip",
-                "reference": "8.x-1.4",
-                "shasum": "1bdc6f93d1c79c27738320597f2185f5de37432f"
+                "url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.5.zip",
+                "reference": "8.x-1.5",
+                "shasum": "b2929a517cc86bb3e54dded127556f18236a8628"
             },
             "require": {
                 "drupal/core": "^8.8 || ^9"
@@ -4803,8 +4810,8 @@
             "type": "drupal-module",
             "extra": {
                 "drupal": {
-                    "version": "8.x-1.4",
-                    "datestamp": "1591383264",
+                    "version": "8.x-1.5",
+                    "datestamp": "1648569365",
                     "security-coverage": {
                         "status": "covered",
                         "message": "Covered by Drupal's security advisory policy"
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index 39935a758fb11e52f335ffa0788f0f6934536af9..bddb3ca2ac92d546f00cc08684d0b9f8400d93b0 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -3,7 +3,7 @@
         'name' => 'osu-asc-webservices/d8-upstream',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => '94cc3b822d657cc885a015bf9c535fc1673b5084',
+        'reference' => '429f72e15c8ceea994931b8d1abf14e67c0e8c20',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -368,9 +368,9 @@
             'dev_requirement' => false,
         ),
         'drupal/bootstrap' => array(
-            'pretty_version' => '3.23.0',
-            'version' => '3.23.0.0',
-            'reference' => '8.x-3.23',
+            'pretty_version' => '3.25.0',
+            'version' => '3.25.0.0',
+            'reference' => '8.x-3.25',
             'type' => 'drupal-theme',
             'install_path' => __DIR__ . '/../../web/themes/bootstrap',
             'aliases' => array(),
@@ -767,9 +767,9 @@
             'dev_requirement' => false,
         ),
         'drupal/entity_reference_revisions' => array(
-            'pretty_version' => '1.9.0',
-            'version' => '1.9.0.0',
-            'reference' => '8.x-1.9',
+            'pretty_version' => '1.10.0',
+            'version' => '1.10.0.0',
+            'reference' => '8.x-1.10',
             'type' => 'drupal-module',
             'install_path' => __DIR__ . '/../../web/modules/entity_reference_revisions',
             'aliases' => array(),
@@ -794,18 +794,18 @@
             'dev_requirement' => false,
         ),
         'drupal/field_group' => array(
-            'pretty_version' => '3.3.0',
-            'version' => '3.3.0.0',
-            'reference' => '8.x-3.3',
+            'pretty_version' => '3.4.0',
+            'version' => '3.4.0.0',
+            'reference' => '8.x-3.4',
             'type' => 'drupal-module',
             'install_path' => __DIR__ . '/../../web/modules/field_group',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'drupal/field_permissions' => array(
-            'pretty_version' => '1.1.0',
-            'version' => '1.1.0.0',
-            'reference' => '8.x-1.1',
+            'pretty_version' => '1.2.0',
+            'version' => '1.2.0.0',
+            'reference' => '8.x-1.2',
             'type' => 'drupal-module',
             'install_path' => __DIR__ . '/../../web/modules/field_permissions',
             'aliases' => array(),
@@ -839,9 +839,9 @@
             'dev_requirement' => false,
         ),
         'drupal/google_tag' => array(
-            'pretty_version' => '1.4.0',
-            'version' => '1.4.0.0',
-            'reference' => '8.x-1.4',
+            'pretty_version' => '1.5.0',
+            'version' => '1.5.0.0',
+            'reference' => '8.x-1.5',
             'type' => 'drupal-module',
             'install_path' => __DIR__ . '/../../web/modules/google_tag',
             'aliases' => array(),
@@ -1594,7 +1594,7 @@
         'osu-asc-webservices/d8-upstream' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => '94cc3b822d657cc885a015bf9c535fc1673b5084',
+            'reference' => '429f72e15c8ceea994931b8d1abf14e67c0e8c20',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
diff --git a/web/modules/entity_reference_revisions/composer.json b/web/modules/entity_reference_revisions/composer.json
index 793e16e23a0fb297906125786332c2c580f3a2b3..04f444fbd7c25a624c0864353a08522ef4db1c62 100644
--- a/web/modules/entity_reference_revisions/composer.json
+++ b/web/modules/entity_reference_revisions/composer.json
@@ -4,9 +4,16 @@
   "type": "drupal-module",
   "license": "GPL-2.0-or-later",
   "require": {
-    "drupal/core": "^8.7.7 || ^9"
+    "drupal/core": "^9 || ^10"
   },
   "require-dev": {
     "drupal/diff": "1.x-dev"
+  },
+  "extra": {
+    "drush": {
+      "services": {
+        "drush.services.yml": "^9 || ^10 || ^11"
+      }
+    }
   }
 }
diff --git a/web/modules/entity_reference_revisions/entity_reference_revisions.info.yml b/web/modules/entity_reference_revisions/entity_reference_revisions.info.yml
index 0549cb09b017f77ffd6310062f40a788f465db6a..c2976c338cc08c1aa267248e10f32249422ada03 100644
--- a/web/modules/entity_reference_revisions/entity_reference_revisions.info.yml
+++ b/web/modules/entity_reference_revisions/entity_reference_revisions.info.yml
@@ -1,12 +1,12 @@
 name: Entity Reference Revisions
 type: module
 description: Adds a Entity Reference field type with revision support.
-core_version_requirement: ^8.7.7 || ^9
+core_version_requirement: ^9 || ^10
 package: Field types
 dependencies:
   - drupal:field
 
-# Information added by Drupal.org packaging script on 2021-03-03
-version: '8.x-1.9'
+# Information added by Drupal.org packaging script on 2022-08-16
+version: '8.x-1.10'
 project: 'entity_reference_revisions'
-datestamp: 1614805875
+datestamp: 1660664714
diff --git a/web/modules/entity_reference_revisions/entity_reference_revisions.module b/web/modules/entity_reference_revisions/entity_reference_revisions.module
index fa24f77eab5fe6092919d721786c36778a016370..82c3cd73a820dc47b7769b4100151a37e5947f63 100644
--- a/web/modules/entity_reference_revisions/entity_reference_revisions.module
+++ b/web/modules/entity_reference_revisions/entity_reference_revisions.module
@@ -333,6 +333,7 @@ function entity_reference_revisions_entity_delete(EntityInterface $entity) {
           ->condition($parent_type_field, $entity->getEntityTypeId())
           ->condition($parent_id_field, $entity->id())
           ->condition($parent_name_field, $field_name)
+          ->accessCheck(FALSE)
           ->execute();
 
         if (empty($entity_ids)) {
diff --git a/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsFieldItemList.php b/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsFieldItemList.php
index 983e7be2697e036570f1756cf5a9795bedb3d12a..956fc5e24c3015f6da7d8bfd59a9a8fd1ca69358 100644
--- a/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsFieldItemList.php
+++ b/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsFieldItemList.php
@@ -69,6 +69,7 @@ public static function processDefaultValue($default_value, FieldableEntityInterf
         $target_type = $definition->getSetting('target_type');
         $entity_ids = \Drupal::entityQuery($target_type)
           ->condition('uuid', $uuids, 'IN')
+          ->accessCheck(TRUE)
           ->execute();
         $entities = \Drupal::entityTypeManager()
           ->getStorage($target_type)
diff --git a/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsServiceProvider.php b/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsServiceProvider.php
index 65db78508ebb96fba45e6c6bd288c044503db77b..453b02ca57c5240e1618bea1c3d0fdad17fa0881 100644
--- a/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsServiceProvider.php
+++ b/web/modules/entity_reference_revisions/src/EntityReferenceRevisionsServiceProvider.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\ServiceProviderBase;
+use Drupal\entity_reference_revisions\Normalizer\EntityReferenceRevisionItemNormalizer;
 use Symfony\Component\DependencyInjection\Definition;
 use Symfony\Component\DependencyInjection\Reference;
 
@@ -19,16 +20,20 @@ public function alter(ContainerBuilder $container) {
     $modules = $container->getParameter('container.modules');
     if (isset($modules['hal'])) {
       // Hal module is enabled, add our new normalizer for entity reference
-      // revision items.
-      $service_definition = new Definition('Drupal\entity_reference_revisions\Normalizer\EntityReferenceRevisionItemNormalizer', array(
-        new Reference('hal.link_manager'),
-        new Reference('serializer.entity_resolver'),
-      ));
-      // The priority must be higher than that of
-      // serializer.normalizer.entity_reference_item.hal in
-      // hal.services.yml.
-      $service_definition->addTag('normalizer', array('priority' => 20));
-      $container->setDefinition('serializer.normalizer.entity_reference_revision_item', $service_definition);
+      // revision items. For Drupal 10, the normalizer has been moved to the
+      // hal contrib module.
+      if (version_compare(\Drupal::VERSION, '10', '<')) {
+        $service_definition = new Definition(EntityReferenceRevisionItemNormalizer::class, array(
+          new Reference('hal.link_manager'),
+          new Reference('serializer.entity_resolver'),
+        ));
+        // The priority must be higher than that of
+        // serializer.normalizer.entity_reference_item.hal in
+        // hal.services.yml.
+        $service_definition->setPublic(TRUE);
+        $service_definition->addTag('normalizer', array('priority' => 20));
+        $container->setDefinition('serializer.normalizer.entity_reference_revision_item', $service_definition);
+      }
     }
   }
 
diff --git a/web/modules/entity_reference_revisions/tests/modules/entity_composite_relationship_test/entity_composite_relationship_test.info.yml b/web/modules/entity_reference_revisions/tests/modules/entity_composite_relationship_test/entity_composite_relationship_test.info.yml
index fe3a5aacc2954c5235d039f1581453c589f972b9..a46c4ed8cca37eaa8963c661ea18b5d7ee8986d0 100644
--- a/web/modules/entity_reference_revisions/tests/modules/entity_composite_relationship_test/entity_composite_relationship_test.info.yml
+++ b/web/modules/entity_reference_revisions/tests/modules/entity_composite_relationship_test/entity_composite_relationship_test.info.yml
@@ -2,13 +2,12 @@ name: 'ERR Composite relationship test'
 type: module
 description: 'Entity with parent type and ID.'
 package: Testing
-core_version_requirement: ^8.7.7 || ^9
 
 dependencies:
  - entity_reference_revisions:entity_reference_revisions
  - drupal:entity_test
 
-# Information added by Drupal.org packaging script on 2021-03-03
-version: '8.x-1.9'
+# Information added by Drupal.org packaging script on 2022-08-16
+version: '8.x-1.10'
 project: 'entity_reference_revisions'
-datestamp: 1614805875
+datestamp: 1660664714
diff --git a/web/modules/entity_reference_revisions/tests/modules/entity_host_relationship_test/entity_host_relationship_test.info.yml b/web/modules/entity_reference_revisions/tests/modules/entity_host_relationship_test/entity_host_relationship_test.info.yml
index 5a32314affc06bbbe5ec3aa65758afa28d9cee0e..14eb6037cf500f0cf2884b44bf739964cc758670 100644
--- a/web/modules/entity_reference_revisions/tests/modules/entity_host_relationship_test/entity_host_relationship_test.info.yml
+++ b/web/modules/entity_reference_revisions/tests/modules/entity_host_relationship_test/entity_host_relationship_test.info.yml
@@ -2,12 +2,11 @@ name: 'Entity Host Base Field ERR'
 type: module
 description: 'Entity host with base field definition using entity_reference_revisions.'
 package: Testing
-core_version_requirement: ^8.7.7 || ^9
 
 dependencies:
   - entity_composite_relationship_test:entity_composite_relationship_test
 
-# Information added by Drupal.org packaging script on 2021-03-03
-version: '8.x-1.9'
+# Information added by Drupal.org packaging script on 2022-08-16
+version: '8.x-1.10'
 project: 'entity_reference_revisions'
-datestamp: 1614805875
+datestamp: 1660664714
diff --git a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAdminTest.php b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAdminTest.php
index e26f480dce37347dbdc73fb15df99a918d508a50..9dadafd472b15b383caa64841a98210178c67908 100644
--- a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAdminTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAdminTest.php
@@ -20,7 +20,7 @@ class EntityReferenceRevisionsAdminTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'node',
     'field',
     'entity_reference_revisions',
@@ -36,7 +36,7 @@ class EntityReferenceRevisionsAdminTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create paragraphs and article content types.
     $this->drupalCreateContentType(array('type' => 'entity_revisions', 'name' => 'Entity revisions'));
@@ -47,6 +47,7 @@ protected function setUp() {
       'administer site configuration',
       'administer nodes',
       'create article content',
+      'create entity_revisions content',
       'administer content types',
       'administer node fields',
       'administer node display',
@@ -78,7 +79,7 @@ public function testEntityReferenceRevisions() {
     ];
     static::fieldUIAddNewField('admin/structure/types/manage/entity_revisions', 'entity_reference_revisions', 'Entity reference revisions', 'entity_reference_revisions', $storage_edit, $field_edit);
     \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
-    $this->assertText('Saved Entity reference revisions configuration.');
+    $this->assertSession()->pageTextContains('Saved Entity reference revisions configuration.');
 
     // Resave the target node, so that the default revision is not the one we
     // want to use.
@@ -96,24 +97,24 @@ public function testEntityReferenceRevisions() {
     );
     $this->drupalGet('node/add/article');
     $this->submitForm($edit, 'Save');
-    $this->assertText($title);
-    $this->assertText('Revision 1');
+    $this->assertSession()->pageTextContains($title);
+    $this->assertSession()->pageTextContains('Revision 1');
     $node = $this->drupalGetNodeByTitle($title);
 
     // Check if when creating an entity revisions content the default entity
     // reference is set, add also the above article as a new reference.
     $this->drupalGet('node/add/entity_revisions');
-    $this->assertFieldByName('field_entity_reference_revisions[0][target_id]', $node_target->label() . ' (' . $node_target->id() . ')');
+    $this->assertSession()->fieldValueEquals('field_entity_reference_revisions[0][target_id]', $node_target->label() . ' (' . $node_target->id() . ')');
     $edit = [
       'title[0][value]' => 'Entity reference revision content',
       'field_entity_reference_revisions[1][target_id]' => $node->label() . ' (' . $node->id() . ')',
     ];
     $this->submitForm($edit, 'Save');
-    $this->assertLinkByHref('node/' . $node_target->id());
-    $this->assertText('Entity revisions Entity reference revision content has been created.');
-    $this->assertText('Entity reference revision content');
-    $this->assertText($title);
-    $this->assertText('Revision 1');
+    $this->assertSession()->linkByHrefExists('node/' . $node_target->id());
+    $this->assertSession()->pageTextContains('Entity revisions Entity reference revision content has been created.');
+    $this->assertSession()->pageTextContains('Entity reference revision content');
+    $this->assertSession()->pageTextContains($title);
+    $this->assertSession()->pageTextContains('Revision 1');
 
     // Create 2nd revision of the article.
     $edit = array(
@@ -122,15 +123,15 @@ public function testEntityReferenceRevisions() {
     );
     $this->drupalGet('node/' . $node->id() . '/edit');
     $this->submitForm($edit, 'Save');
-    $this->assertText($title);
-    $this->assertText('Revision 2');
+    $this->assertSession()->pageTextContains($title);
+    $this->assertSession()->pageTextContains('Revision 2');
 
     // View the Entity reference content and make sure it still has revision 1.
     $node = $this->drupalGetNodeByTitle('Entity reference revision content');
     $this->drupalGet('node/' . $node->id());
-    $this->assertText($title);
-    $this->assertText('Revision 1');
-    $this->assertNoText('Revision 2');
+    $this->assertSession()->pageTextContains($title);
+    $this->assertSession()->pageTextContains('Revision 1');
+    $this->assertSession()->pageTextNotContains('Revision 2');
 
     // Make sure the non-revisionable entities are not selectable as referenced
     // entities.
@@ -141,18 +142,18 @@ public function testEntityReferenceRevisions() {
     );
     $this->drupalGet('admin/structure/types/manage/entity_revisions/fields/add-field');
     $this->submitForm($edit, 'Save and continue');
-    $this->assertNoOption('edit-settings-target-type', 'user');
-    $this->assertOption('edit-settings-target-type', 'node');
+    $this->assertSession()->optionNotExists('edit-settings-target-type', 'user');
+    $this->assertSession()->optionExists('edit-settings-target-type', 'node');
 
     // Check ERR default value and property definitions label are set properly.
     $field_definition = $node->getFieldDefinition('field_entity_reference_revisions');
     $default_value = $field_definition->toArray()['default_value'];
-    $this->assertEqual($default_value[0]['target_uuid'], $node_target->uuid());
-    $this->assertEqual($default_value[0]['target_revision_id'], $revision_id);
+    $this->assertEquals($node_target->uuid(), $default_value[0]['target_uuid']);
+    $this->assertEquals($revision_id, $default_value[0]['target_revision_id']);
     $properties = $field_definition->getFieldStorageDefinition()->getPropertyDefinitions();
-    $this->assertEqual((string) $properties['target_revision_id']->getLabel(), 'Content revision ID');
-    $this->assertEqual((string) $properties['target_id']->getLabel(), 'Content ID');
-    $this->assertEqual((string) $properties['entity']->getLabel(), 'Content');
+    $this->assertEquals('Content revision ID', (string) $properties['target_revision_id']->getLabel());
+    $this->assertEquals('Content ID', (string) $properties['target_id']->getLabel());
+    $this->assertEquals('Content', (string) $properties['entity']->getLabel());
   }
 
   /**
@@ -185,7 +186,7 @@ public function testMultipleTargetBundles() {
     // that bundle's body field. Test that there is no second field that will
     // be deleted.
     $this->drupalGet('/admin/structure/types/manage/' . $target_types[0]->id() . '/delete');
-    $this->assertNoFieldByXPath('(//details[@id="edit-entity-deletes"]//ul[@data-drupal-selector="edit-field-config"]/li)[2]');
+    $this->xpath('(//details[@id="edit-entity-deletes"]//ul[@data-drupal-selector="edit-field-config"]/li)[2]');
   }
 
 }
diff --git a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAutocompleteTest.php b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAutocompleteTest.php
index 602fff55a077ea4b4f4870850ff01a38b1e9a042..9bd0c5342d89799ead7843b6b3f967cde853dc93 100644
--- a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAutocompleteTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsAutocompleteTest.php
@@ -22,7 +22,7 @@ class EntityReferenceRevisionsAutocompleteTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'block_content',
     'node',
     'field',
@@ -38,7 +38,7 @@ class EntityReferenceRevisionsAutocompleteTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create article content type.
     $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
@@ -99,8 +99,8 @@ public function testEntityReferenceRevisionsAutocompleteProcessing() {
     );
     $this->drupalGet('node/add/article');
     $this->submitForm($edit, 'Save');
-    $this->assertText($title);
-    $this->assertText(Html::escape($block_content));
+    $this->assertSession()->pageTextContains($title);
+    $this->assertSession()->responseContains(Html::escape($block_content));
 
     // Check if the block content is not deleted since there is no composite
     // relationship.
@@ -148,7 +148,7 @@ function createBlockContentType($parameters) {
     );
     $this->drupalGet('admin/structure/block/block-content/types/add');
     $this->submitForm($edit, 'Save');
-    $this->assertText($label);
+    $this->assertSession()->pageTextContains($label);
   }
 
 }
diff --git a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsDiffTest.php b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsDiffTest.php
index f924f3f15eb448bbd21292fec8863a105871c26e..c47ff8c360ee623e0ddbced1e531d25be09f0d1a 100644
--- a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsDiffTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsDiffTest.php
@@ -21,7 +21,7 @@ class EntityReferenceRevisionsDiffTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'block_content',
     'node',
     'field',
@@ -38,7 +38,7 @@ class EntityReferenceRevisionsDiffTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create article content type.
     $this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
@@ -57,6 +57,7 @@ protected function setUp() {
       'administer node form display',
       'view all revisions',
       'edit any article content',
+      'create article content',
     ]);
     $this->drupalLogin($admin_user);
     $this->drupalPlaceBlock('system_breadcrumb_block');
@@ -123,8 +124,8 @@ public function testEntityReferenceRevisionsDiff() {
     $this->submitForm([], 'Compare selected revisions');
 
     // Assert the field changes.
-    $this->assertRaw('class="diff-context diff-deletedline">' . $title_node_1);
-    $this->assertRaw('class="diff-context diff-addedline">' . $title_node_2);
+    $this->assertSession()->responseContains('class="diff-context diff-deletedline">' . $title_node_1);
+    $this->assertSession()->responseContains('class="diff-context diff-addedline">' . $title_node_2);
   }
 
 }
diff --git a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsNormalizerTest.php b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsNormalizerTest.php
index 9abae19a64763aca65e53d1e9b0a19122ce161bf..179f656c05b657cfa3462827135a808a1b384fd5 100644
--- a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsNormalizerTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsNormalizerTest.php
@@ -10,6 +10,7 @@
  * Tests the entity_reference_revisions configuration.
  *
  * @group entity_reference_revisions
+ * @requires module hal
  */
 class EntityReferenceRevisionsNormalizerTest extends BrowserTestBase {
 
@@ -20,7 +21,7 @@ class EntityReferenceRevisionsNormalizerTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'node',
     'field',
     'entity_reference_revisions',
@@ -39,7 +40,7 @@ class EntityReferenceRevisionsNormalizerTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create paragraphs and article content types.
     $this->drupalCreateContentType(array('type' => 'entity_revisions', 'name' => 'Entity revisions'));
@@ -52,10 +53,16 @@ protected function setUp() {
    * Tests the entity reference revisions configuration.
    */
   public function testEntityReferenceRevisions() {
+
+    if (version_compare(\Drupal::VERSION, '10', '>=')) {
+      $this->markTestSkipped('HAL support has been moved to hal module');
+    }
+
     $admin_user = $this->drupalCreateUser(array(
       'administer site configuration',
       'administer nodes',
       'create article content',
+      'create entity_revisions content',
       'administer content types',
       'administer node fields',
       'administer node display',
@@ -65,7 +72,7 @@ public function testEntityReferenceRevisions() {
     $this->drupalLogin($admin_user);
     // Create entity reference revisions field.
     static::fieldUIAddNewField('admin/structure/types/manage/entity_revisions', 'entity_reference_revisions', 'Entity reference revisions', 'entity_reference_revisions', array('settings[target_type]' => 'node', 'cardinality' => '-1'), array('settings[handler_settings][target_bundles][article]' => TRUE));
-    $this->assertText('Saved Entity reference revisions configuration.');
+    $this->assertSession()->pageTextContains('Saved Entity reference revisions configuration.');
 
     // Create an article.
     $title = $this->randomMachineName();
@@ -75,8 +82,8 @@ public function testEntityReferenceRevisions() {
     );
     $this->drupalGet('node/add/article');
     $this->submitForm($edit, 'Save');
-    $this->assertText($title);
-    $this->assertText('Revision 1');
+    $this->assertSession()->pageTextContains($title);
+    $this->assertSession()->pageTextContains('Revision 1');
     $node = $this->drupalGetNodeByTitle($title);
 
     // Create entity revisions content that includes the above article.
@@ -87,12 +94,12 @@ public function testEntityReferenceRevisions() {
     );
     $this->drupalGet('node/add/entity_revisions');
     $this->submitForm($edit, 'Save');
-    $this->assertText('Entity revisions Entity reference revision content has been created.');
+    $this->assertSession()->pageTextContains('Entity revisions Entity reference revision content has been created.');
     $err_node = $this->drupalGetNodeByTitle($err_title);
 
-    $this->assertText($err_title);
-    $this->assertText($title);
-    $this->assertText('Revision 1');
+    $this->assertSession()->pageTextContains($err_title);
+    $this->assertSession()->pageTextContains($title);
+    $this->assertSession()->pageTextContains('Revision 1');
 
     // Create 2nd revision of the article.
     $edit = array(
@@ -105,9 +112,9 @@ public function testEntityReferenceRevisions() {
     $normalized = $serializer->normalize($err_node, 'hal_json');
     $request = \Drupal::request();
     $link_domain = $request->getSchemeAndHttpHost() . $request->getBasePath();
-    $this->assertEqual($err_node->field_entity_reference_revisions->target_revision_id, $normalized['_embedded'][$link_domain . '/rest/relation/node/entity_revisions/field_entity_reference_revisions'][0]['target_revision_id']);
+    $this->assertEquals($err_node->field_entity_reference_revisions->target_revision_id, $normalized['_embedded'][$link_domain . '/rest/relation/node/entity_revisions/field_entity_reference_revisions'][0]['target_revision_id']);
     $new_err_node = $serializer->denormalize($normalized, Node::class, 'hal_json');
-    $this->assertEqual($err_node->field_entity_reference_revisions->target_revision_id, $new_err_node->field_entity_reference_revisions->target_revision_id);
+    $this->assertEquals($err_node->field_entity_reference_revisions->target_revision_id, $new_err_node->field_entity_reference_revisions->target_revision_id);
   }
 
 }
diff --git a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalForBaseFieldDefinitionTest.php b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalForBaseFieldDefinitionTest.php
index 364bdfed443c2e35bd53ba32c481d5cd75189014..0630f9eb6e96e86abff9695448006491f16e5ba3 100644
--- a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalForBaseFieldDefinitionTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalForBaseFieldDefinitionTest.php
@@ -24,7 +24,7 @@ class EntityReferenceRevisionsOrphanRemovalForBaseFieldDefinitionTest extends En
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'field',
     'entity_reference_revisions',
diff --git a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalTest.php b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalTest.php
index 3fa8798747c4e1aa92bbe1bfcfb685c0a48a0a90..2eabb59778b85a2477810d0c785aad64d6a45667 100644
--- a/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Functional/EntityReferenceRevisionsOrphanRemovalTest.php
@@ -28,7 +28,7 @@ class EntityReferenceRevisionsOrphanRemovalTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'field',
     'entity_reference_revisions',
@@ -43,7 +43,7 @@ class EntityReferenceRevisionsOrphanRemovalTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
     $this->adminUser = $this->drupalCreateUser([
       'delete orphan revisions',
@@ -141,6 +141,7 @@ protected function assertRevisionCount($expected, $entity_type_id, $entity_id) {
       ->condition($id_field, $entity_id)
       ->allRevisions()
       ->count()
+      ->accessCheck(TRUE)
       ->execute();
     $this->assertEquals($expected, $revision_count);
   }
diff --git a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
index ac226fa193e83e102522b04907517d2e336f683d..6be1424cef47e566423ab9ff8349815af53c7ab8 100644
--- a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTest.php
@@ -27,7 +27,7 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'node',
     'field',
     'entity_reference_revisions',
@@ -60,7 +60,7 @@ class EntityReferenceRevisionsCompositeTest extends EntityKernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
 
     $this->installEntitySchema('entity_test_composite');
@@ -106,7 +106,12 @@ public function testEntityReferenceRevisionsCompositeRelationship() {
     $composite->save();
 
     // Assert that there is only 1 revision of the composite entity.
-    $composite_revisions_count = \Drupal::entityQuery('entity_test_composite')->condition('uuid', $composite->uuid())->allRevisions()->count()->execute();
+    $composite_revisions_count = \Drupal::entityQuery('entity_test_composite')
+      ->condition('uuid', $composite->uuid())
+      ->allRevisions()
+      ->count()
+      ->accessCheck(TRUE)
+      ->execute();
     $this->assertEquals(1, $composite_revisions_count);
 
     // Create a node with a reference to the test composite entity.
@@ -121,10 +126,20 @@ public function testEntityReferenceRevisionsCompositeRelationship() {
     $node->save();
 
     // Assert that there is only 1 revision when creating a node.
-    $node_revisions_count = \Drupal::entityQuery('node')->condition('nid', $node->id())->allRevisions()->count()->execute();
+    $node_revisions_count = \Drupal::entityQuery('node')
+      ->condition('nid', $node->id())
+      ->allRevisions()
+      ->count()
+      ->accessCheck(TRUE)
+      ->execute();
     $this->assertEquals(1, $node_revisions_count);
     // Assert there is no new composite revision after creating a host entity.
-    $composite_revisions_count = \Drupal::entityQuery('entity_test_composite')->condition('uuid', $composite->uuid())->allRevisions()->count()->execute();
+    $composite_revisions_count = \Drupal::entityQuery('entity_test_composite')
+      ->condition('uuid', $composite->uuid())
+      ->allRevisions()
+      ->count()
+      ->accessCheck(TRUE)
+      ->execute();
     $this->assertEquals(1, $composite_revisions_count);
 
     // Verify the value of parent type and id after create a node.
@@ -144,7 +159,12 @@ public function testEntityReferenceRevisionsCompositeRelationship() {
     $this->assertNotEquals($original_composite_revision, $node->composite_reference[0]->target_revision_id, 'Composite entity got new revision when its host did.');
 
     // Make sure that there are only 2 revisions.
-    $node_revisions_count = \Drupal::entityQuery('node')->condition('nid', $node->id())->allRevisions()->count()->execute();
+    $node_revisions_count = \Drupal::entityQuery('node')
+      ->condition('nid', $node->id())
+      ->allRevisions()
+      ->count()
+      ->accessCheck(TRUE)
+      ->execute();
     $this->assertEquals(2,$node_revisions_count);
 
     // Revert to first revision of the node.
@@ -180,13 +200,24 @@ public function testEntityReferenceRevisionsCompositeRelationship() {
     $this->assertEquals('Changing composite reference', $node->get('composite_reference')->entity->getName());
 
     // Make sure the node has 4 revisions.
-    $node_revisions_count = $node_storage->getQuery()->condition('nid', $nid)->allRevisions()->count()->execute();
-    $this->assertEqual($node_revisions_count, 4);
+    $node_revisions_count = $node_storage->getQuery()
+      ->condition('nid', $nid)
+      ->allRevisions()
+      ->count()
+      ->accessCheck(TRUE)
+      ->execute();
+    $this->assertEquals(4, $node_revisions_count);
 
     // Make sure the node has no revision with revision translation affected
     // flag set to NULL.
-    $node_revisions_count = $node_storage->getQuery()->condition('nid', $nid)->allRevisions()->condition('revision_translation_affected', NULL, 'IS NULL')->count()->execute();
-    $this->assertEqual($node_revisions_count, 0, 'Node has a revision with revision translation affected set to NULL');
+    $node_revisions_count = $node_storage->getQuery()
+      ->condition('nid', $nid)
+      ->allRevisions()
+      ->condition('revision_translation_affected', NULL, 'IS NULL')
+      ->accessCheck(TRUE)
+      ->count()
+      ->execute();
+    $this->assertEquals(0, $node_revisions_count, 'Node has a revision with revision translation affected set to NULL');
 
     // Revert the changes to avoid interfering with the delete test.
     $node->set('composite_reference', $composite);
@@ -680,6 +711,7 @@ protected function assertRevisionCount($expected, $entity_type_id, $entity_id) {
       ->condition($id_field, $entity_id)
       ->allRevisions()
       ->count()
+      ->accessCheck(TRUE)
       ->execute();
     $this->assertEquals($expected, $revision_count);
   }
diff --git a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslatableFieldTest.php b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslatableFieldTest.php
index 4e261bfcf4385ea6fc5314eb529df414f70304a1..d0f0335920b41962c2873779b407009d6c36610f 100644
--- a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslatableFieldTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslatableFieldTest.php
@@ -27,7 +27,7 @@ class EntityReferenceRevisionsCompositeTranslatableFieldTest extends EntityKerne
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'node',
     'field',
     'entity_reference_revisions',
@@ -54,7 +54,7 @@ class EntityReferenceRevisionsCompositeTranslatableFieldTest extends EntityKerne
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
 
     ConfigurableLanguage::createFromLangcode('de')->save();
@@ -344,6 +344,7 @@ protected function assertRevisionCount($expected, $entity_type_id, $entity_id) {
       ->condition($id_field, $entity_id)
       ->allRevisions()
       ->count()
+      ->accessCheck(TRUE)
       ->execute();
     $this->assertEquals($expected, $revision_count);
   }
diff --git a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php
index 2a406176ae35ef6e75ddaee7838a1ce2bf0d05b9..6f0103d3c79615fc8be73a5778f728421642c862 100644
--- a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsCompositeTranslationTest.php
@@ -29,7 +29,7 @@ class EntityReferenceRevisionsCompositeTranslationTest extends EntityKernelTestB
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'field',
     'entity_reference_revisions',
@@ -56,7 +56,7 @@ class EntityReferenceRevisionsCompositeTranslationTest extends EntityKernelTestB
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
 
     ConfigurableLanguage::createFromLangcode('de')->save();
@@ -616,6 +616,7 @@ protected function assertAffectedRevisionCount($expected, EntityInterface $entit
       ->condition($entity_type->getKey('revision_translation_affected'), 1)
       ->allRevisions()
       ->count()
+      ->accessCheck(TRUE)
       ->execute();
 
     $this->assertEquals($expected, $affected_revisions_count);
@@ -634,6 +635,7 @@ protected function assertRevisionCount($expected, EntityInterface $entity) {
       ->condition($entity->getEntityType()->getKey('id'), $entity->id())
       ->allRevisions()
       ->count()
+      ->accessCheck(TRUE)
       ->execute();
     $this->assertEquals($expected, $node_revisions_count);
   }
diff --git a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsFormatterTest.php b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsFormatterTest.php
index f65e0745d8339bd2f355cdfd95591d95256cad86..9bc647f4866cce6183b48ba25880c32833d9e043 100644
--- a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsFormatterTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsFormatterTest.php
@@ -23,7 +23,7 @@ class EntityReferenceRevisionsFormatterTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'user',
     'system',
@@ -35,7 +35,7 @@ class EntityReferenceRevisionsFormatterTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create article content type.
     $values = ['type' => 'article', 'name' => 'Article'];
diff --git a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsSaveTest.php b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsSaveTest.php
index 2b66a63058d9197152193f37a3226d8dc107ff80..57582b79ff752f3bc878c4407f594cef6c364694 100644
--- a/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsSaveTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Kernel/EntityReferenceRevisionsSaveTest.php
@@ -21,7 +21,7 @@ class EntityReferenceRevisionsSaveTest extends KernelTestBase {
    *
    * @var array
    */
-  public static $modules = array(
+  protected static $modules = array(
     'node',
     'user',
     'system',
@@ -33,7 +33,7 @@ class EntityReferenceRevisionsSaveTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     // Create article content type.
     $values = ['type' => 'article', 'name' => 'Article'];
diff --git a/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/Derivative/EntityReferenceRevisionsDeriverTest.php b/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/Derivative/EntityReferenceRevisionsDeriverTest.php
index 86c49a1ffb431f3cef56023cbf6799002124f112..2552336c837bc1765fd72f25a05b87bfeb08562b 100644
--- a/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/Derivative/EntityReferenceRevisionsDeriverTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/Derivative/EntityReferenceRevisionsDeriverTest.php
@@ -17,12 +17,12 @@ class EntityReferenceRevisionsDeriverTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['migrate', 'entity_reference_revisions', 'entity_composite_relationship_test'];
+  protected static $modules = ['migrate', 'entity_reference_revisions', 'entity_composite_relationship_test'];
 
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->installConfig(static::$modules);
   }
diff --git a/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php b/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php
index a9a26a4095f12c46ea247efe388839464332af07..8e145b6db42b1f8d847a3b6adfac8f88ca37e0b7 100644
--- a/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php
+++ b/web/modules/entity_reference_revisions/tests/src/Kernel/Plugin/migrate/destination/EntityReferenceRevisionsDestinationTest.php
@@ -28,7 +28,7 @@ class EntityReferenceRevisionsDestinationTest extends KernelTestBase implements
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'migrate',
     'entity_reference_revisions',
     'entity_composite_relationship_test',
@@ -40,7 +40,7 @@ class EntityReferenceRevisionsDestinationTest extends KernelTestBase implements
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->installEntitySchema('entity_test_composite');
     $this->installSchema('system', ['sequences']);
@@ -63,8 +63,12 @@ public function testGetEntityTypeId(array $definition, $expected) {
     $destination = $migration->getDestinationPlugin();
 
     /** @var \Drupal\Core\Entity\EntityStorageBase $storage */
-    $storage = $this->readAttribute($destination, 'storage');
-    $actual = $this->readAttribute($storage, 'entityTypeId');
+    $reflected_storage = new \ReflectionProperty($destination, 'storage');
+    $reflected_storage->setAccessible(TRUE);
+    $storage = $reflected_storage->getValue($destination);
+    $reflected_entity_type_id = new \ReflectionProperty($storage, 'entityTypeId');
+    $reflected_entity_type_id->setAccessible(TRUE);
+    $actual = $reflected_entity_type_id->getValue($storage);
 
     $this->assertEquals($expected, $actual);
   }
@@ -96,7 +100,9 @@ public function testGetEntity(array $definition, array $expected) {
     $migration = $this->migrationPluginManager->createStubMigration($definition);
     $migrationExecutable = (new MigrateExecutable($migration, $this));
     /** @var \Drupal\Core\Entity\EntityStorageBase $storage */
-    $storage = $this->readAttribute($migration->getDestinationPlugin(), 'storage');
+    $reflected_storage = new \ReflectionProperty($migration->getDestinationPlugin(), 'storage');
+    $reflected_storage->setAccessible(TRUE);
+    $storage = $reflected_storage->getValue($migration->getDestinationPlugin());
     // Test inserting and updating by looping twice.
     for ($i = 0; $i < 2; $i++) {
       $migrationExecutable->import();
@@ -250,7 +256,9 @@ public function testGetEntityForceRevision(array $definition, array $expected) {
     $migration = $this->migrationPluginManager->createStubMigration($definition);
     $migrationExecutable = (new MigrateExecutable($migration, $this));
     /** @var \Drupal\Core\Entity\EntityStorageBase $storage */
-    $storage = $this->readAttribute($migration->getDestinationPlugin(), 'storage');
+    $reflected_storage = new \ReflectionProperty($migration->getDestinationPlugin(), 'storage');
+    $reflected_storage->setAccessible(TRUE);
+    $storage = $reflected_storage->getValue($migration->getDestinationPlugin());
     // Test inserting and updating by looping twice.
     for ($i = 0; $i < 2; $i++) {
       $migrationExecutable->import();
@@ -415,7 +423,9 @@ public function testDestinationFieldMapping(array $data) {
       $migration = $this->migrationPluginManager->createInstance($datum['definition']['id']);
       $migrationExecutable = (new MigrateExecutable($migration, $this));
       /** @var \Drupal\Core\Entity\EntityStorageBase $storage */
-      $storage = $this->readAttribute($migration->getDestinationPlugin(), 'storage');
+      $reflected_storage = new \ReflectionProperty($migration->getDestinationPlugin(), 'storage');
+      $reflected_storage->setAccessible(TRUE);
+      $storage = $reflected_storage->getValue($migration->getDestinationPlugin());
       $migrationExecutable->import();
       foreach ($datum['expected'] as $expected) {
         $entity = $storage->loadRevision($expected['id']);
diff --git a/web/modules/field_group/composer.json b/web/modules/field_group/composer.json
index 47b16e766fe2d25cdf334515fddd00a5122c8c53..7a980b54c8c83f3bdad610ccf2247e55b5918e82 100644
--- a/web/modules/field_group/composer.json
+++ b/web/modules/field_group/composer.json
@@ -5,10 +5,7 @@
     "license": "GPL-2.0-or-later",
     "minimum-stability": "dev",
     "require": {
-        "drupal/core": "^8.8 || ^9"
-    },
-    "require-dev": {
-        "drupal/jquery_ui_accordion": "^1.0"
+        "drupal/core": "^9.2 || ^10"
     },
     "support": {
         "issues": "https://www.drupal.org/project/issues/field_group",
diff --git a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
index 68e9e9544f362e7226e66ac629cbc7cbb90f191d..bb99b478e9242d4c2b379d4e3b3594f696cbbd74 100644
--- a/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
+++ b/web/modules/field_group/contrib/field_group_migrate/field_group_migrate.info.yml
@@ -2,11 +2,11 @@ name: 'Field Group Migrate'
 type: module
 description: 'Provides the ability to migrate field groups from D6/D7 to D8.'
 package: Migration
-core_version_requirement: ^8.8 || ^9
+core_version_requirement: ^9.2 || ^10
 dependencies:
   - field_group:field_group
 
-# Information added by Drupal.org packaging script on 2022-09-18
-version: '8.x-3.3'
+# Information added by Drupal.org packaging script on 2022-10-31
+version: '8.x-3.4'
 project: 'field_group'
-datestamp: 1663516405
+datestamp: 1667241980
diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Functional/MigrateUiFieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Functional/MigrateUiFieldGroupTest.php
index d4859cb7afad48ae439211d067c2251abcb6ae4c..0a8808c9ca6ffc26a289c5dbb92cb756c54c0710 100644
--- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Functional/MigrateUiFieldGroupTest.php
+++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Functional/MigrateUiFieldGroupTest.php
@@ -29,17 +29,26 @@ class MigrateUiFieldGroupTest extends MigrateUpgradeTestBase {
    * {@inheritdoc}
    */
   protected function getSourceBasePath() {
-    return drupal_get_path('module', 'migrate_drupal_ui') . '/tests/src/Functional/d7/files';
+    return \Drupal::service('extension.list.module')
+      ->getPath('migrate_drupal_ui') . '/tests/src/Functional/d7/files';
   }
 
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
+
+    $extension_list_module = \Drupal::service('extension.list.module');
+
+    $migrate_drupal_path = $extension_list_module
+      ->getPath('migrate_drupal') . '/tests/fixtures/drupal7.php';
+    $field_group_migrate = $extension_list_module
+      ->getPath('field_group_migrate') . '/tests/fixtures/drupal7.php';
+
     // Field Group's migration database fixture extends Drupal core's fixture.
-    $this->loadFixture(drupal_get_path('module', 'migrate_drupal') . '/tests/fixtures/drupal7.php');
-    $this->loadFixture(drupal_get_path('module', 'field_group_migrate') . '/tests/fixtures/drupal7.php');
+    $this->loadFixture($migrate_drupal_path);
+    $this->loadFixture($field_group_migrate);
   }
 
   /**
@@ -115,7 +124,7 @@ protected function submitMigrateUpgradeSourceConnectionForm() {
     $session = $this->assertSession();
     $session->responseContains("Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal");
 
-    $this->drupalPostForm(NULL, [], 'Continue');
+    $this->submitForm([], 'Continue');
     $session->pageTextContains('Provide credentials for the database of the Drupal site you want to upgrade.');
 
     $driver = $connection_options['driver'];
@@ -138,7 +147,7 @@ protected function submitMigrateUpgradeSourceConnectionForm() {
     }
     $edits = $this->translatePostValues($edit);
 
-    $this->drupalPostForm(NULL, $edits, 'Review upgrade');
+    $this->submitForm($edits, 'Review upgrade');
   }
 
   /**
@@ -154,13 +163,13 @@ protected function executeMigrateUpgradeViaUi() {
     // @see https://www.drupal.org/node/2928118
     // @see https://www.drupal.org/node/3105503
     if ($this->getSession()->getPage()->findButton('I acknowledge I may lose data. Continue anyway.')) {
-      $this->drupalPostForm(NULL, [], 'I acknowledge I may lose data. Continue anyway.');
+      $this->submitForm([], 'I acknowledge I may lose data. Continue anyway.');
       $assert_session->statusCodeEquals(200);
     }
 
     // Perform the upgrade.
-    $this->drupalPostForm(NULL, [], 'Perform upgrade');
-    $this->assertText('Congratulations, you upgraded Drupal!');
+    $this->submitForm([], 'Perform upgrade');
+    $this->assertSession()->pageTextContains('Congratulations, you upgraded Drupal!');
 
     // Have to reset all the statics after migration to ensure entities are
     // loadable.
diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
index 3557802702b794ae5f2cb2627998eefa03b59228..72cd7bf0f09696a9dac3d23e9daab33342531930 100644
--- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
+++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Kernel/Migrate/d7/MigrateFieldGroupTest.php
@@ -37,7 +37,7 @@ class MigrateFieldGroupTest extends MigrateDrupal7TestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     parent::setUp();
     $this->loadFixture(__DIR__ . '/../../../../fixtures/drupal7.php');
 
diff --git a/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php b/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php
index 84d72670c9688c8f1f27d03fba9b0a6bb97f91cc..ef75d5fc90f7d60427074a73c989612e82a7fe41 100644
--- a/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php
+++ b/web/modules/field_group/contrib/field_group_migrate/tests/src/Unit/Migrate/d7/FieldGroupTest.php
@@ -92,7 +92,7 @@ class FieldGroupTest extends MigrateSqlSourceTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function setUp() {
+  protected function setUp(): void {
     $this->databaseContents['field_group'] = $this->expectedResults;
     parent::setUp();
   }
diff --git a/web/modules/field_group/field_group.info.yml b/web/modules/field_group/field_group.info.yml
index 59e05bd1c9bbdd3ff2ec8cea7be958076e0a6ab9..62e20206c4efd9c3fd765e994854e679e94f709e 100644
--- a/web/modules/field_group/field_group.info.yml
+++ b/web/modules/field_group/field_group.info.yml
@@ -2,11 +2,11 @@ name: 'Field Group'
 type: module
 description: 'Provides the ability to group your fields on both form and display.'
 package : Fields
-core_version_requirement: ^8.8 || ^9
+core_version_requirement: ^9.2 || ^10
 dependencies:
   - drupal:field
 
-# Information added by Drupal.org packaging script on 2022-09-18
-version: '8.x-3.3'
+# Information added by Drupal.org packaging script on 2022-10-31
+version: '8.x-3.4'
 project: 'field_group'
-datestamp: 1663516405
+datestamp: 1667241980
diff --git a/web/modules/field_group/field_group.libraries.yml b/web/modules/field_group/field_group.libraries.yml
index 553640f5b7784ea193010e2591179137aaded51d..bf6661f584a4812fa631918fcaf720a10005a4d8 100644
--- a/web/modules/field_group/field_group.libraries.yml
+++ b/web/modules/field_group/field_group.libraries.yml
@@ -6,7 +6,7 @@ field_ui:
       css/field_group.field_ui.css: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
     - core/drupal
     - core/drupalSettings
 
@@ -15,7 +15,7 @@ core:
     js/field_group.js: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
     - core/drupal
     - core/drupalSettings
 
@@ -24,7 +24,7 @@ formatter.accordion:
     formatters/accordion/accordion.js: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
     - jquery_ui_accordion/accordion
 
 formatter.html_element:
@@ -32,14 +32,14 @@ formatter.html_element:
     formatters/html_element/html-element.js: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
 
 formatter.fieldset:
   js:
     formatters/fieldset/fieldset.js: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
 
 formatter.details:
   js:
@@ -52,7 +52,7 @@ formatter.tabs:
     formatters/tabs/tabs.js: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
     - core/modernizr
 
 element.horizontal_tabs:
@@ -64,6 +64,6 @@ element.horizontal_tabs:
       formatters/tabs/horizontal-tabs.css: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
     - core/drupal.collapse
     - core/modernizr
diff --git a/web/modules/field_group/field_group.module b/web/modules/field_group/field_group.module
index 6008cb85bc9322119aff13e0d13f385883189f0e..9fc9c8527041b5176b249a0a333cc32ba65d7fc5 100644
--- a/web/modules/field_group/field_group.module
+++ b/web/modules/field_group/field_group.module
@@ -51,14 +51,11 @@ function field_group_module_implements_alter(&$implementations, $hook) {
  * Implements hook_library_info_alter().
  */
 function field_group_library_info_alter(&$libraries, $extension) {
-  // Swap jQuery.ui library if available.
+  // Remove jquery_ui_accordion dependency if not available.
   // See https://www.drupal.org/project/field_group/issues/3109552 for more
   // background on the logic.
   if ($extension == 'field_group') {
-    if (\Drupal::moduleHandler()->moduleExists('jquery_ui_accordion')) {
-      $libraries['formatter.accordion']['dependencies'] = ['jquery_ui_accordion/accordion'];
-    }
-    elseif (version_compare(\Drupal::VERSION, 9) > 0) {
+    if (!\Drupal::moduleHandler()->moduleExists('jquery_ui_accordion')) {
       $libraries['formatter.accordion']['js'] = [];
       $libraries['formatter.accordion']['dependencies'] = [];
     }
@@ -841,12 +838,21 @@ function field_group_pre_render(array &$element, $group, &$rendering_object) {
 
   // Let modules define their wrapping element.
   // Note that the group element has no properties, only elements.
-  foreach (Drupal::moduleHandler()->getImplementations('field_group_pre_render') as $module) {
-    // The intention here is to have the opportunity to alter the
-    // elements, as defined in hook_field_group_formatter_info.
-    // Note, implement $element by reference!
-    $function = $module . '_field_group_pre_render';
-    $function($element, $group, $rendering_object);
+  // The intention here is to have the opportunity to alter the
+  // elements, as defined in hook_field_group_formatter_info.
+  // Note, implement $element by reference!
+  if (method_exists(Drupal::moduleHandler(), 'invokeAllWith')) {
+    // On Drupal >= 9.4 use the new method.
+    Drupal::moduleHandler()->invokeAllWith('field_group_pre_render', function (callable $hook) use (&$element, &$group, &$rendering_object) {
+      $hook($element, $group, $rendering_object);
+    });
+  }
+  else {
+    // @phpstan-ignore-next-line
+    foreach (Drupal::moduleHandler()->getImplementations('field_group_pre_render') as $module) {
+      $function = $module . '_field_group_pre_render';
+      $function($element, $group, $rendering_object);
+    }
   }
 
   // Allow others to alter the pre_render.
diff --git a/web/modules/field_group/formatters/accordion/accordion.js b/web/modules/field_group/formatters/accordion/accordion.js
index 9551a0c00f6661cff73eae574367fbc3d468c12d..e34cc3577b12bbdf163d4c2ebd365e9bcf61ecc6 100644
--- a/web/modules/field_group/formatters/accordion/accordion.js
+++ b/web/modules/field_group/formatters/accordion/accordion.js
@@ -15,7 +15,7 @@
    */
   Drupal.FieldGroup.Effects.processAccordion = {
     execute: function (context, settings, group_info) {
-      $('div.field-group-accordion-wrapper', context).once('fieldgroup-effects').each(function () {
+      $(once('fieldgroup-effects', 'div.field-group-accordion-wrapper', context)).each(function () {
         var wrapper = $(this);
 
         // Get the index to set active.
diff --git a/web/modules/field_group/formatters/details/details.js b/web/modules/field_group/formatters/details/details.js
index 5df3f511b4af1251dabcda431e337efead1e12bd..e63073c91d33c9cb2953a058af2f702aac05c831 100644
--- a/web/modules/field_group/formatters/details/details.js
+++ b/web/modules/field_group/formatters/details/details.js
@@ -15,7 +15,7 @@
    */
   Drupal.behaviors.fieldGroupDetails = {
     attach: function (context) {
-      $(context).find('.field-group-details').once('field-group-details').each(function () {
+      $(once('field-group-details', '.field-group-details', context)).each(function () {
         var $this = $(this);
 
         if ($this.is('.required-fields') && ($this.find('[required]').length > 0 || $this.find('.form-required').length > 0)) {
diff --git a/web/modules/field_group/formatters/fieldset/fieldset.js b/web/modules/field_group/formatters/fieldset/fieldset.js
index b0f0085715e2d7e5d2344c9124dfad9120b3d011..edf9fae5856d701912f18c3178de36e4e37832ef 100644
--- a/web/modules/field_group/formatters/fieldset/fieldset.js
+++ b/web/modules/field_group/formatters/fieldset/fieldset.js
@@ -16,7 +16,7 @@
   Drupal.behaviors.fieldGroupFieldset = {
     attach: function (context) {
 
-      $(context).find('.field-group-fieldset').once('field-group-fieldset').each(function () {
+      $(once('field-group-fieldset', '.field-group-fieldset', context)).each(function () {
         var $this = $(this);
 
         if ($this.is('.required-fields') && ($this.find('[required]').length > 0 || $this.find('.form-required').length > 0)) {
diff --git a/web/modules/field_group/formatters/html_element/html-element.js b/web/modules/field_group/formatters/html_element/html-element.js
index 9dd89462c4e4a2a0f4362e890fb3287caa066a27..29f19beed029011643dccfda92b74d86d0e6ba54 100644
--- a/web/modules/field_group/formatters/html_element/html-element.js
+++ b/web/modules/field_group/formatters/html_element/html-element.js
@@ -16,7 +16,7 @@
   Drupal.FieldGroup.Effects.processHtml_element = {
     execute: function (context, settings, group_info) {
 
-      $('.field-group-html-element', context).once('fieldgroup-effects').each(function () {
+      $(once('fieldgroup-effects', '.field-group-html-element', context)).each(function () {
         var $wrapper = $(this);
 
         if ($wrapper.hasClass('fieldgroup-collapsible')) {
diff --git a/web/modules/field_group/formatters/tabs/horizontal-tabs.css b/web/modules/field_group/formatters/tabs/horizontal-tabs.css
index fe320e7d55cb650b50411a812d6b9855b574995f..2f640598e3244cbeed13a11191d4f094cb3d9403 100644
--- a/web/modules/field_group/formatters/tabs/horizontal-tabs.css
+++ b/web/modules/field_group/formatters/tabs/horizontal-tabs.css
@@ -107,9 +107,6 @@
 
 .horizontal-tab-button .summary {
   display: block;
-}
-
-.horizontal-tab-button .summary {
   line-height: normal;
   margin-bottom: 0;
 }
diff --git a/web/modules/field_group/formatters/tabs/horizontal-tabs.js b/web/modules/field_group/formatters/tabs/horizontal-tabs.js
index 083a55ac03fdda130d018b97ee59516d00aa5406..2a65da51d473496ca01d8ef350b935c3e0fb588e 100644
--- a/web/modules/field_group/formatters/tabs/horizontal-tabs.js
+++ b/web/modules/field_group/formatters/tabs/horizontal-tabs.js
@@ -29,7 +29,7 @@
         return;
       }
 
-      $(context).find('[data-horizontal-tabs]').once('horizontal-tabs').each(function () {
+      $(once('horizontal-tabs', '[data-horizontal-tabs]', context)).each(function () {
         var horizontal_tabs_clearfix = this;
         $(this).find('> [data-horizontal-tabs-panes]').each(function () {
           var $this = $(this).addClass('horizontal-tabs-panes');
@@ -42,10 +42,6 @@
             return;
           }
 
-          // If collapse.js did not do his work yet, call it directly.
-          if (!$($details[0]).hasClass('.collapse-processed')) {
-            Drupal.behaviors.collapse.attach(context);
-          }
           // Find the tab column.
           var tab_list = $(horizontal_tabs_clearfix).find('> [data-horizontal-tabs-list]');
           tab_list.removeClass('visually-hidden')
diff --git a/web/modules/field_group/formatters/tabs/tabs.js b/web/modules/field_group/formatters/tabs/tabs.js
index 50fb8ad7bb0baf433139d50928efb3b0327c2166..f83668c308daa9746c5ae87a3e49f4f53df4feab 100644
--- a/web/modules/field_group/formatters/tabs/tabs.js
+++ b/web/modules/field_group/formatters/tabs/tabs.js
@@ -22,7 +22,7 @@
         var direction = group_info.settings.direction;
         $(context).find('[data-' + direction + '-tabs-panes]').each(function () {
           var errorFocussed = false;
-          $(this).find('> details').once('fieldgroup-effects').each(function () {
+          $(once('fieldgroup-effects', $(this).find('> details'))).each(function () {
             var $this = $(this);
             if (typeof $this.data(direction + 'Tab') !== 'undefined') {
 
diff --git a/web/modules/field_group/includes/field_ui.inc b/web/modules/field_group/includes/field_ui.inc
index d6ee0e8427687aa7a83a22315f144fa6d89e811f..16b18c2ab3b95a1e4ede345f8f808db414bdec76 100644
--- a/web/modules/field_group/includes/field_ui.inc
+++ b/web/modules/field_group/includes/field_ui.inc
@@ -500,10 +500,10 @@ function field_group_field_overview_submit(array $form, FormStateInterface $form
         $group->format_settings += $manager->getDefaultSettings($group->format_type, $context);
       }
 
-      /** @var EntityFormInterface $entity_form */
+      /** @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
       $entity_form = $form_state->getFormObject();
 
-      /** @var EntityDisplayInterface $display */
+      /** @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
       $display = $entity_form->getEntity();
 
       field_group_group_save($group, $display);
@@ -604,12 +604,7 @@ function field_group_format_settings_summary($group_name, $group) {
     'group' => $group,
   ]);
 
-  if ($plugin) {
-    $summary = $plugin->settingsSummary();
-  }
-  else {
-    $summary = '';
-  }
+ $summary = !empty($plugin) ? $plugin->settingsSummary() : [];
 
   return [
     '#markup' => '<div class="field-plugin-summary">' . implode('<br />', $summary) . '</div>',
diff --git a/web/modules/field_group/js/field_group.field_ui.js b/web/modules/field_group/js/field_group.field_ui.js
index d02626751e794b997718917a44b53fdd4589e37a..1d7d551e48abec936919dc7f77dbcdd9765ef52b 100644
--- a/web/modules/field_group/js/field_group.field_ui.js
+++ b/web/modules/field_group/js/field_group.field_ui.js
@@ -8,8 +8,8 @@
   'use strict';
   Drupal.behaviors.fieldUIFieldsOverview = {
     attach: function (context, settings) {
-      $('table#field-overview', context).once('field-field-overview', function () {
-        Drupal.fieldUIOverview.attach(this, settings.fieldUIRowsData, Drupal.fieldUIFieldOverview);
+      once('field-field-overview', 'table#field-overview', context).forEach(function (table) {
+        Drupal.fieldUIOverview.attach(table, settings.fieldUIRowsData, Drupal.fieldUIFieldOverview);
       });
     }
   };
diff --git a/web/modules/field_group/src/FormatterHelper.php b/web/modules/field_group/src/FormatterHelper.php
index 469b4a6bce6549bb42e587b1a5c0aa783b69d4df..2c01c242c08fb17fdbeb640a6795daf2aa620c42 100644
--- a/web/modules/field_group/src/FormatterHelper.php
+++ b/web/modules/field_group/src/FormatterHelper.php
@@ -93,11 +93,13 @@ public static function formProcess(array &$element, FormStateInterface $form_sta
         $parents[] = $group_name;
         $element[$group_name]['#parents'] = $parents;
         $group_children_parent_group = implode('][', $parents);
-        foreach ($group->children as $child) {
-          if (!empty($element[$child]['#field_group_ignore'])) {
-            continue;
+        if (isset($group->children)) {
+          foreach ($group->children as $child) {
+            if (!empty($element[$child]['#field_group_ignore'])) {
+              continue;
+            }
+            $element[$child]['#group'] = $group_children_parent_group;
           }
-          $element[$child]['#group'] = $group_children_parent_group;
         }
       }
 
@@ -106,12 +108,21 @@ public static function formProcess(array &$element, FormStateInterface $form_sta
 
         // Let modules define their wrapping element.
         // Note that the group element has no properties, only elements.
-        foreach (Drupal::moduleHandler()->getImplementations('field_group_form_process') as $module) {
-          // The intention here is to have the opportunity to alter the
-          // elements, as defined in hook_field_group_formatter_info.
-          // Note, implement $element by reference!
-          $function = $module . '_field_group_form_process';
-          $function($field_group_element, $group, $element);
+        // The intention here is to have the opportunity to alter the
+        // elements, as defined in hook_field_group_formatter_info.
+        // Note, implement $element by reference!
+        if (method_exists(Drupal::moduleHandler(), 'invokeAllWith')) {
+          // On Drupal >= 9.4 use the new method.
+          Drupal::moduleHandler()->invokeAllWith('field_group_form_process', function (callable $hook) use (&$field_group_element, &$group, &$element) {
+            $hook($field_group_element, $group, $element);
+          });
+        }
+        else {
+          // @phpstan-ignore-next-line
+          foreach (Drupal::moduleHandler()->getImplementations('field_group_form_process') as $module) {
+            $function = $module . '_field_group_form_process';
+            $function($field_group_element, $group, $element);
+          }
         }
 
         // Allow others to alter the pre_render.
@@ -141,7 +152,7 @@ public static function formGroupPreRender(array $element) {
         $closed = isset($element[$fieldgroup->group_name]['#open']) && !$element[$fieldgroup->group_name]['#open'];
         if ($closed) {
           foreach ($fieldgroup->children as $child) {
-            if (static::groupElementsContainErrors($element[$child])) {
+            if (isset($element[$child]) && static::groupElementsContainErrors($element[$child])) {
               $element[$fieldgroup->group_name]['#open'] = TRUE;
               break;
             }
diff --git a/web/modules/field_group/src/Routing/RouteSubscriber.php b/web/modules/field_group/src/Routing/RouteSubscriber.php
index bae6a2c3a08d4f54b447a355077a92c20e71696a..7a12f40c907f3e6a99b853b1c9d556420e5544dd 100644
--- a/web/modules/field_group/src/Routing/RouteSubscriber.php
+++ b/web/modules/field_group/src/Routing/RouteSubscriber.php
@@ -151,7 +151,7 @@ protected function alterRoutes(RouteCollection $collection) {
   /**
    * {@inheritdoc}
    */
-  public static function getSubscribedEvents() {
+  public static function getSubscribedEvents(): array {
     // $events = parent::getSubscribedEvents();
     // Come after field_ui, config_translation.
     $events[RoutingEvents::ALTER] = ['onAlterRoutes', -210];
diff --git a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
index ec32cb7cd5ffd135e7d221de24814b8451aa81aa..37348be4deb366d028bf11d7fb997adf66272d06 100644
--- a/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
+++ b/web/modules/field_group/tests/modules/field_group_test/field_group_test.info.yml
@@ -1,11 +1,10 @@
 name: 'Field Group Test'
 description: 'Test module for Field Group'
-core_version_requirement: ^8.8 || ^9
-package: 'Fields'
+package: Testing
 type: module
 hidden: TRUE
 
-# Information added by Drupal.org packaging script on 2022-09-18
-version: '8.x-3.3'
+# Information added by Drupal.org packaging script on 2022-10-31
+version: '8.x-3.4'
 project: 'field_group'
-datestamp: 1663516405
+datestamp: 1667241980
diff --git a/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php b/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php
index df2920c6d177012e5f65da224abc8dd6dc1397e7..e9e089f301bc3997268827e120b81892cca674f0 100644
--- a/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php
+++ b/web/modules/field_group/tests/src/Functional/EntityDisplayTest.php
@@ -18,7 +18,7 @@ class EntityDisplayTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'field_test',
     'field_ui',
@@ -43,12 +43,12 @@ class EntityDisplayTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected $defaultTheme = 'classy';
+  protected $defaultTheme = 'starterkit_theme';
 
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
 
     // Create test user.
diff --git a/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php b/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php
index 4c443882be7d184c5ddd28ee718f9bcd4477956d..4ab31f8e60fce3d5b3c0bcc61f787f31680ca46d 100644
--- a/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php
+++ b/web/modules/field_group/tests/src/Functional/FieldGroupWithoutFieldUiTest.php
@@ -15,7 +15,7 @@ class FieldGroupWithoutFieldUiTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['field_group', 'block'];
+  protected static $modules = ['field_group', 'block'];
 
   /**
    * {@inheritdoc}
diff --git a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
index bedec3633ca4cbd4fb473ccb873705892f60687c..0930ea564411d7a6e86fd94d3f5066f0f24553b0 100644
--- a/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
+++ b/web/modules/field_group/tests/src/Functional/ManageDisplayTest.php
@@ -16,7 +16,7 @@ class ManageDisplayTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['node', 'field_ui', 'field_group'];
+  protected static $modules = ['node', 'field_ui', 'field_group'];
 
   /**
    * Content type id.
@@ -33,7 +33,7 @@ class ManageDisplayTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
 
     // Create test user.
@@ -132,11 +132,6 @@ public function testDeleteGroup() {
     $loaded_group = field_group_load_field_group($group->group_name, 'node', $this->type, 'form', 'default');
     $this->assertNull($loaded_group, 'Group not found after deleting');
 
-    $data = [
-      'format_type' => 'fieldset',
-      'label' => 'testing',
-    ];
-
     $group = $this->createGroup('node', $this->type, 'view', 'default', $data);
 
     $this->drupalGet('admin/structure/types/manage/' . $this->type . '/display/' . $group->group_name . '/delete');
diff --git a/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php b/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php
index a650aeb4fe47ca88c17fe032f445e6203a2ba7c8..f4986c79ba6b12950d856807f9835f5e81cf8705 100644
--- a/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php
+++ b/web/modules/field_group/tests/src/FunctionalJavascript/FieldGroupUiTest.php
@@ -21,7 +21,7 @@ class FieldGroupUiTest extends WebDriverTestBase {
    *
    * @var array
    */
-  public static $modules = ['node', 'field_ui', 'field_group'];
+  protected static $modules = ['node', 'field_ui', 'field_group'];
 
   /**
    * The current tested node type.
@@ -38,7 +38,7 @@ class FieldGroupUiTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
 
     // Create test user.
diff --git a/web/modules/field_group/tests/src/FunctionalJavascript/HorizontalTabsLabelsTest.php b/web/modules/field_group/tests/src/FunctionalJavascript/HorizontalTabsLabelsTest.php
index 8c6701fc17332c7693adc0226078c529943f8636..a40015512e59f2c73217e787789832d1b2a100d7 100644
--- a/web/modules/field_group/tests/src/FunctionalJavascript/HorizontalTabsLabelsTest.php
+++ b/web/modules/field_group/tests/src/FunctionalJavascript/HorizontalTabsLabelsTest.php
@@ -21,14 +21,14 @@ class HorizontalTabsLabelsTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  protected $defaultTheme = 'stark';
+  protected $defaultTheme = 'starterkit_theme';
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = [
+  protected static $modules = [
     'block',
     'field_group',
     'node',
@@ -41,11 +41,8 @@ class HorizontalTabsLabelsTest extends WebDriverTestBase {
    * @var string[]
    */
   protected $themeList = [
-    'bartik',
     'claro',
-    'classy',
-    'seven',
-    'stable',
+    'olivero',
     'stable9',
     'stark',
   ];
@@ -83,7 +80,7 @@ class HorizontalTabsLabelsTest extends WebDriverTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
 
     $this->assertSession = $this->assertSession();
@@ -191,11 +188,11 @@ public function testHorizontalTabsLabels(string $theme_name) {
       $theme_installer = \Drupal::service('theme_installer');
       assert($theme_installer instanceof ThemeInstallerInterface);
       try {
-        $theme_installer->install([$theme_name], TRUE);
+        $theme_installer->install([$theme_name]);
       }
       catch (UnknownExtensionException $ex) {
-        // Themes might be missing, e.g Drupal 8.x does not have stable9 theme.
-        $this->pass("The $theme_name theme does not exist in the current test environment.");
+        // Themes might be missing, e.g Drupal 10 does not have stable theme.
+        $this->markTestSkipped("The $theme_name theme does not exist in the current test environment.");
         return;
       }
       \Drupal::configFactory()
@@ -234,7 +231,7 @@ public function testHorizontalTabsLabels(string $theme_name) {
     // Create a node.
     $this->page->fillField('title[0][value]', 'Field Group Horizontal Tabs Test Node');
     $this->page->fillField('Test label', 'Test label');
-    $this->assertNotNull($tab2 = $this->page->find('css', '.js .field-group-tabs-wrapper a[href="#edit-group-tab2"]'));
+    $this->assertNotNull($tab2 = $this->page->find('css', '.field-group-tabs-wrapper a[href="#edit-group-tab2"]'));
     $tab2->click();
     $this->assertSession->waitForElementVisible('css', '[name="body[0][value]"]');
     $this->page->fillField('body[0][value]', 'Donec laoreet imperdiet.');
@@ -262,11 +259,11 @@ public function testHorizontalTabsLabels(string $theme_name) {
    * Asserts the horizontal tabs labels.
    */
   protected function assertHorizontalTabsLabels() {
-    $this->assertSession->waitForElement('css', '.js .field-group-tabs-wrapper a[href="#edit-group-tab1"]');
-    $this->assertSession->waitForElement('css', '.js .field-group-tabs-wrapper a[href="#edit-group-tab2"]');
-    $this->assertNotNull($tab1 = $this->page->find('css', '.js .field-group-tabs-wrapper a[href="#edit-group-tab1"]'));
+    $this->assertSession->waitForElement('css', '.field-group-tabs-wrapper a[href="#edit-group-tab1"]');
+    $this->assertSession->waitForElement('css', '.field-group-tabs-wrapper a[href="#edit-group-tab2"]');
+    $this->assertNotNull($tab1 = $this->page->find('css', '.field-group-tabs-wrapper a[href="#edit-group-tab1"]'));
     $this->assertStringContainsString('Tab1', $tab1->getText());
-    $this->assertNotNull($tab2 = $this->page->find('css', '.js .field-group-tabs-wrapper a[href="#edit-group-tab2"]'));
+    $this->assertNotNull($tab2 = $this->page->find('css', '.field-group-tabs-wrapper a[href="#edit-group-tab2"]'));
     $this->assertStringContainsString('Tab2', $tab2->getText());
   }
 
diff --git a/web/modules/field_permissions/field_permissions.info.yml b/web/modules/field_permissions/field_permissions.info.yml
index b9d6093beae8ef957373887d81ddb5e209e2613d..09dfc1814fcfcb73459876f33e11fd73360faf15 100644
--- a/web/modules/field_permissions/field_permissions.info.yml
+++ b/web/modules/field_permissions/field_permissions.info.yml
@@ -3,10 +3,10 @@ type: module
 description: 'Set field-level permissions to create, update or view fields.'
 configure: field_permissions.reports
 package: field
-core: '8.x'
-core_version_requirement: ^8 || ^9
-
-# Information added by Drupal.org packaging script on 2020-08-28
-version: '8.x-1.1'
+core_version_requirement: '>=8.9 <11'
+dependencies:
+  - drupal:field
+# Information added by Drupal.org packaging script on 2022-07-27
+version: '8.x-1.2'
 project: 'field_permissions'
-datestamp: 1598646884
+datestamp: 1658941753
diff --git a/web/modules/field_permissions/field_permissions.module b/web/modules/field_permissions/field_permissions.module
index 036d8c362c896df62585ab9940cdc42b6eaf8cee..352de92c9446f1c758e0f4194ba92c94617f80be 100644
--- a/web/modules/field_permissions/field_permissions.module
+++ b/web/modules/field_permissions/field_permissions.module
@@ -157,3 +157,21 @@ function field_permission_field_config_edit_form_submit(array &$form, FormStateI
   }
 
 }
+
+/**
+ * Implements hook_migration_plugins_alter().
+ *
+ * Adds process plugin to insert field_permissions as third party settings.
+ */
+function field_permissions_migration_plugins_alter(array &$migrations) {
+  $field_migrations = array_filter(
+    $migrations,
+    function ($definition) {
+      return $definition['id'] === 'd7_field';
+    }
+  );
+
+  foreach (array_keys($field_migrations) as $plugin_id) {
+    $migrations[$plugin_id]['process']['third_party_settings/field_permissions']['plugin'] = 'd7_field_permission_settings';
+  }
+}
diff --git a/web/modules/field_permissions/src/Controller/FieldPermissionsController.php b/web/modules/field_permissions/src/Controller/FieldPermissionsController.php
index 49239d7456bdb353454bbe814b6aad22a156a17e..83b76ca3312af92494be95f27cc92c1f6d6c5e95 100644
--- a/web/modules/field_permissions/src/Controller/FieldPermissionsController.php
+++ b/web/modules/field_permissions/src/Controller/FieldPermissionsController.php
@@ -14,7 +14,7 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Define FieldPermissionsController.
+ * Field Permissions Controller/Page.
  */
 class FieldPermissionsController extends ControllerBase {
 
@@ -142,7 +142,7 @@ protected function buildRow(FieldStorageConfigInterface $field_storage) {
     }
     $row[1]['data'] = $field_storage->getType();
     $row[2]['data'] = $field_storage->getTargetEntityTypeId();
-    $row[3]['data'] = implode(",", $field_storage->getBundles());
+    $row[3]['data'] = implode(", ", $field_storage->getBundles());
 
     $default_type = $this->fieldPermissions->fieldGetPermissionType($field_storage);
     $field_permissions = $this->fieldPermissions->getPermissionsByRole();
diff --git a/web/modules/field_permissions/src/FieldPermissionsService.php b/web/modules/field_permissions/src/FieldPermissionsService.php
index ed06c81a51427c91f90a3786191cc5129f275342..8341eceea3386cfdfc063bdb41eaa77b4006095e 100644
--- a/web/modules/field_permissions/src/FieldPermissionsService.php
+++ b/web/modules/field_permissions/src/FieldPermissionsService.php
@@ -177,7 +177,7 @@ public function getFieldAccess($operation, FieldItemListInterface $items, Accoun
   /**
    * Determines if the given account may view the field, regardless of entity.
    *
-   * This should only return TRUE if
+   * This should only return TRUE if:
    * @code
    * $this->getFieldAccess('view', $items, $account, $field_definition);
    * @endcode
diff --git a/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php b/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php
index 5989427c720cd4db3cfedb7d8c16737722dc7423..9cd6414b4e1829e5fb10a86bf460697f3aa542e6 100644
--- a/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php
+++ b/web/modules/field_permissions/src/Plugin/FieldPermissionType/Base.php
@@ -67,7 +67,7 @@ public function getDescription() {
   /**
    * Determines if the given account may view the field, regardless of entity.
    *
-   * This should only return TRUE if
+   * This should only return TRUE if:
    * @code
    * $this->hasFieldAccess('view', $entity, $account);
    * @endcode
@@ -85,4 +85,5 @@ public function getDescription() {
   public function hasFieldViewAccessForEveryEntity(AccountInterface $account) {
     return FALSE;
   }
+
 }
diff --git a/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php b/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php
index b322a9a7391e31a9a5309945e186ae0d45cce945..70b43f848f40b3017cc4bedfa784adbcc1f78c0a 100644
--- a/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php
+++ b/web/modules/field_permissions/src/Plugin/migrate/process/FieldPermissionSettings.php
@@ -21,6 +21,9 @@ class FieldPermissionSettings extends ProcessPluginBase {
    */
   public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
     $value = $row->getSourceProperty('field_permissions');
+    if ($value === NULL) {
+      return ['permission_type' => FieldPermissionTypeInterface::ACCESS_PUBLIC];
+    }
     switch ($value['type']) {
       case 0:
         $permission_type = FieldPermissionTypeInterface::ACCESS_PUBLIC;
@@ -34,7 +37,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
         $permission_type = FieldPermissionTypeInterface::ACCESS_CUSTOM;
         break;
     }
-    return ['field_permissions' => ['permission_type' => $permission_type]];
+    return ['permission_type' => $permission_type];
   }
 
 }
diff --git a/web/modules/field_permissions/tests/fixtures/drupal7.php b/web/modules/field_permissions/tests/fixtures/drupal7.php
new file mode 100644
index 0000000000000000000000000000000000000000..8eafc820379c3872ae5263cad9387594e1e77068
--- /dev/null
+++ b/web/modules/field_permissions/tests/fixtures/drupal7.php
@@ -0,0 +1,389 @@
+<?php
+// phpcs:ignoreFile
+/**
+ * @file
+ * A database agnostic dump for testing purposes.
+ *
+ * This file was generated by the Drupal 9.2.9 db-tools.php script.
+ */
+
+use Drupal\Core\Database\Database;
+
+$connection = Database::getConnection();
+
+$connection->schema()->createTable('system', array(
+  'fields' => array(
+    'filename' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '255',
+      'default' => '',
+    ),
+    'name' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '255',
+      'default' => '',
+    ),
+    'type' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '12',
+      'default' => '',
+    ),
+    'owner' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '255',
+      'default' => '',
+    ),
+    'status' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'default' => '0',
+    ),
+    'bootstrap' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'default' => '0',
+    ),
+    'schema_version' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'small',
+      'default' => '-1',
+    ),
+    'weight' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'default' => '0',
+    ),
+    'info' => array(
+      'type' => 'blob',
+      'not null' => FALSE,
+      'size' => 'normal',
+    ),
+  ),
+  'primary key' => array(
+    'filename',
+  ),
+  'indexes' => array(
+    'system_list' => array(
+      'status',
+      'bootstrap',
+      'type',
+      'weight',
+      'name',
+    ),
+    'type_name' => array(
+      'type',
+      'name',
+    ),
+  ),
+  'mysql_character_set' => 'utf8mb3',
+));
+
+$connection->insert('system')
+->fields(array(
+  'filename',
+  'name',
+  'type',
+  'owner',
+  'status',
+  'bootstrap',
+  'schema_version',
+  'weight',
+  'info',
+))
+  ->values(array(
+  'filename' => 'modules/system/system.module',
+  'name' => 'system',
+  'type' => 'module',
+  'owner' => '',
+  'status' => '1',
+  'bootstrap' => '0',
+  'schema_version' => '7084',
+  'weight' => '0',
+  'info' => 'a:14:{s:4:"name";s:6:"System";s:11:"description";s:54:"Handles general site configuration for administrators.";s:7:"package";s:4:"Core";s:7:"version";s:4:"7.82";s:4:"core";s:3:"7.x";s:5:"files";a:6:{i:0;s:19:"system.archiver.inc";i:1;s:15:"system.mail.inc";i:2;s:16:"system.queue.inc";i:3;s:14:"system.tar.inc";i:4;s:18:"system.updater.inc";i:5;s:11:"system.test";}s:8:"required";b:1;s:9:"configure";s:19:"admin/config/system";s:7:"project";s:6:"drupal";s:9:"datestamp";s:10:"1626883669";s:5:"mtime";i:1626883669;s:12:"dependencies";a:0:{}s:3:"php";s:5:"5.2.4";s:9:"bootstrap";i:0;}',
+))
+->values(array(
+  'filename' => 'modules/field/field.module',
+  'name' => 'field',
+  'type' => 'module',
+  'owner' => '',
+  'status' => '1',
+  'bootstrap' => '0',
+  'schema_version' => '7004',
+  'weight' => '0',
+  'info' => 'a:14:{s:4:"name";s:5:"Field";s:11:"description";s:57:"Field API to add fields to entities like nodes and users.";s:7:"package";s:4:"Core";s:7:"version";s:4:"7.82";s:4:"core";s:3:"7.x";s:5:"files";a:4:{i:0;s:12:"field.module";i:1;s:16:"field.attach.inc";i:2;s:20:"field.info.class.inc";i:3;s:16:"tests/field.test";}s:12:"dependencies";a:1:{i:0;s:17:"field_sql_storage";}s:8:"required";b:1;s:11:"stylesheets";a:1:{s:3:"all";a:1:{s:15:"theme/field.css";s:29:"modules/field/theme/field.css";}}s:7:"project";s:6:"drupal";s:9:"datestamp";s:10:"1626883669";s:5:"mtime";i:1626883669;s:3:"php";s:5:"5.2.4";s:9:"bootstrap";i:0;}',
+))
+->values(array(
+  'filename' => 'modules/field/modules/field_sql_storage/field_sql_storage.module',
+  'name' => 'field_sql_storage',
+  'type' => 'module',
+  'owner' => '',
+  'status' => '1',
+  'bootstrap' => '0',
+  'schema_version' => '7002',
+  'weight' => '0',
+  'info' => 'a:13:{s:4:"name";s:17:"Field SQL storage";s:11:"description";s:37:"Stores field data in an SQL database.";s:7:"package";s:4:"Core";s:7:"version";s:4:"7.82";s:4:"core";s:3:"7.x";s:12:"dependencies";a:1:{i:0;s:5:"field";}s:5:"files";a:1:{i:0;s:22:"field_sql_storage.test";}s:8:"required";b:1;s:7:"project";s:6:"drupal";s:9:"datestamp";s:10:"1626883669";s:5:"mtime";i:1626883669;s:3:"php";s:5:"5.2.4";s:9:"bootstrap";i:0;}',
+))
+->values(array(
+  'filename' => 'modules/node/node.module',
+  'name' => 'node',
+  'type' => 'module',
+  'owner' => '',
+  'status' => '1',
+  'bootstrap' => '0',
+  'schema_version' => '7016',
+  'weight' => '0',
+  'info' => 'a:15:{s:4:"name";s:4:"Node";s:11:"description";s:66:"Allows content to be submitted to the site and displayed on pages.";s:7:"package";s:4:"Core";s:7:"version";s:4:"7.82";s:4:"core";s:3:"7.x";s:5:"files";a:2:{i:0;s:11:"node.module";i:1;s:9:"node.test";}s:8:"required";b:1;s:9:"configure";s:21:"admin/structure/types";s:11:"stylesheets";a:1:{s:3:"all";a:1:{s:8:"node.css";s:21:"modules/node/node.css";}}s:7:"project";s:6:"drupal";s:9:"datestamp";s:10:"1626883669";s:5:"mtime";i:1626883669;s:12:"dependencies";a:0:{}s:3:"php";s:5:"5.2.4";s:9:"bootstrap";i:0;}',
+))
+->execute();
+
+$connection->schema()->createTable('field_config', array(
+  'fields' => array(
+    'id' => array(
+      'type' => 'serial',
+      'not null' => TRUE,
+      'size' => 'normal',
+    ),
+    'field_name' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '32',
+    ),
+    'type' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+    ),
+    'module' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+      'default' => '',
+    ),
+    'active' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+    'storage_type' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+    ),
+    'storage_module' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+      'default' => '',
+    ),
+    'storage_active' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+    'locked' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+    'data' => array(
+      'type' => 'blob',
+      'not null' => TRUE,
+      'size' => 'big',
+    ),
+    'cardinality' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+    'translatable' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+    'deleted' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+  ),
+  'primary key' => array(
+    'id',
+  ),
+  'indexes' => array(
+    'field_name' => array(
+      'field_name',
+    ),
+    'active' => array(
+      'active',
+    ),
+    'storage_active' => array(
+      'storage_active',
+    ),
+    'deleted' => array(
+      'deleted',
+    ),
+    'module' => array(
+      'module',
+    ),
+    'storage_module' => array(
+      'storage_module',
+    ),
+    'type' => array(
+      'type',
+    ),
+    'storage_type' => array(
+      'storage_type',
+    ),
+  ),
+  'mysql_character_set' => 'utf8mb3',
+));
+
+$connection->insert('field_config')
+->fields(array(
+  'id',
+  'field_name',
+  'type',
+  'module',
+  'active',
+  'storage_type',
+  'storage_module',
+  'storage_active',
+  'locked',
+  'data',
+  'cardinality',
+  'translatable',
+  'deleted',
+))
+->values(array(
+  'id' => '2',
+  'field_name' => 'body',
+  'type' => 'text_with_summary',
+  'module' => 'text',
+  'active' => '1',
+  'storage_type' => 'field_sql_storage',
+  'storage_module' => 'field_sql_storage',
+  'storage_active' => '1',
+  'locked' => '0',
+  'data' => 'a:8:{s:12:"entity_types";a:1:{i:0;s:4:"node";}s:12:"translatable";s:1:"0";s:8:"settings";a:0:{}s:7:"storage";a:5:{s:4:"type";s:17:"field_sql_storage";s:8:"settings";a:0:{}s:6:"module";s:17:"field_sql_storage";s:6:"active";s:1:"1";s:7:"details";a:1:{s:3:"sql";a:2:{s:18:"FIELD_LOAD_CURRENT";a:1:{s:15:"field_data_body";a:3:{s:5:"value";s:10:"body_value";s:7:"summary";s:12:"body_summary";s:6:"format";s:11:"body_format";}}s:19:"FIELD_LOAD_REVISION";a:1:{s:19:"field_revision_body";a:3:{s:5:"value";s:10:"body_value";s:7:"summary";s:12:"body_summary";s:6:"format";s:11:"body_format";}}}}}s:12:"foreign keys";a:1:{s:6:"format";a:2:{s:5:"table";s:13:"filter_format";s:7:"columns";a:1:{s:6:"format";s:6:"format";}}}s:7:"indexes";a:1:{s:6:"format";a:1:{i:0;s:6:"format";}}s:2:"id";s:1:"2";s:17:"field_permissions";a:1:{s:4:"type";s:1:"2";}}',
+  'cardinality' => '1',
+  'translatable' => '0',
+  'deleted' => '0',
+))
+->values(array(
+  'id' => '5',
+  'field_name' => 'body1',
+  'type' => 'text_with_summary',
+  'module' => 'text',
+  'active' => '1',
+  'storage_type' => 'field_sql_storage',
+  'storage_module' => 'field_sql_storage',
+  'storage_active' => '1',
+  'locked' => '0',
+  'data' => 'a:7:{s:12:"entity_types";a:1:{i:0;s:4:"node";}s:12:"translatable";s:1:"0";s:8:"settings";a:0:{}s:7:"storage";a:5:{s:4:"type";s:17:"field_sql_storage";s:8:"settings";a:0:{}s:6:"module";s:17:"field_sql_storage";s:6:"active";s:1:"1";s:7:"details";a:1:{s:3:"sql";a:2:{s:18:"FIELD_LOAD_CURRENT";a:1:{s:15:"field_data_body";a:3:{s:5:"value";s:10:"body_value";s:7:"summary";s:12:"body_summary";s:6:"format";s:11:"body_format";}}s:19:"FIELD_LOAD_REVISION";a:1:{s:19:"field_revision_body";a:3:{s:5:"value";s:10:"body_value";s:7:"summary";s:12:"body_summary";s:6:"format";s:11:"body_format";}}}}}s:12:"foreign keys";a:1:{s:6:"format";a:2:{s:5:"table";s:13:"filter_format";s:7:"columns";a:1:{s:6:"format";s:6:"format";}}}s:7:"indexes";a:1:{s:6:"format";a:1:{i:0;s:6:"format";}}s:2:"id";s:1:"2";}',
+  'cardinality' => '1',
+  'translatable' => '0',
+  'deleted' => '0',
+))
+->execute();
+
+$connection->schema()->createTable('field_config_instance', array(
+  'fields' => array(
+    'id' => array(
+      'type' => 'serial',
+      'not null' => TRUE,
+      'size' => 'normal',
+    ),
+    'field_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+    ),
+    'field_name' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '32',
+      'default' => '',
+    ),
+    'entity_type' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '32',
+      'default' => '',
+    ),
+    'bundle' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+      'default' => '',
+    ),
+    'data' => array(
+      'type' => 'blob',
+      'not null' => TRUE,
+      'size' => 'big',
+    ),
+    'deleted' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+  ),
+  'primary key' => array(
+    'id',
+  ),
+  'indexes' => array(
+    'field_name_bundle' => array(
+      'field_name',
+      'entity_type',
+      'bundle',
+    ),
+    'deleted' => array(
+      'deleted',
+    ),
+  ),
+  'mysql_character_set' => 'utf8mb3',
+));
+
+$connection->insert('field_config_instance')
+->fields(array(
+  'id',
+  'field_id',
+  'field_name',
+  'entity_type',
+  'bundle',
+  'data',
+  'deleted',
+))
+->values(array(
+  'id' => '4',
+  'field_id' => '2',
+  'field_name' => 'body',
+  'entity_type' => 'node',
+  'bundle' => 'article',
+  'data' => 'a:6:{s:5:"label";s:4:"Body";s:6:"widget";a:4:{s:4:"type";s:26:"text_textarea_with_summary";s:8:"settings";a:2:{s:4:"rows";i:20;s:12:"summary_rows";i:5;}s:6:"weight";s:1:"3";s:6:"module";s:4:"text";}s:8:"settings";a:3:{s:15:"display_summary";b:1;s:15:"text_processing";i:1;s:18:"user_register_form";b:0;}s:7:"display";a:2:{s:7:"default";a:5:{s:5:"label";s:6:"hidden";s:4:"type";s:12:"text_default";s:6:"weight";s:1:"1";s:8:"settings";a:0:{}s:6:"module";s:4:"text";}s:6:"teaser";a:5:{s:5:"label";s:6:"hidden";s:4:"type";s:23:"text_summary_or_trimmed";s:8:"settings";a:1:{s:11:"trim_length";i:600;}s:6:"module";s:4:"text";s:6:"weight";i:0;}}s:8:"required";b:0;s:11:"description";s:0:"";}',
+  'deleted' => '0',
+))
+->values(array(
+  'id' => '7',
+  'field_id' => '5',
+  'field_name' => 'body1',
+  'entity_type' => 'node',
+  'bundle' => 'article',
+  'data' => 'a:6:{s:5:"label";s:4:"Body";s:6:"widget";a:4:{s:4:"type";s:26:"text_textarea_with_summary";s:8:"settings";a:2:{s:4:"rows";i:20;s:12:"summary_rows";i:5;}s:6:"weight";s:1:"3";s:6:"module";s:4:"text";}s:8:"settings";a:3:{s:15:"display_summary";b:1;s:15:"text_processing";i:1;s:18:"user_register_form";b:0;}s:7:"display";a:2:{s:7:"default";a:5:{s:5:"label";s:6:"hidden";s:4:"type";s:12:"text_default";s:6:"weight";s:1:"1";s:8:"settings";a:0:{}s:6:"module";s:4:"text";}s:6:"teaser";a:5:{s:5:"label";s:6:"hidden";s:4:"type";s:23:"text_summary_or_trimmed";s:8:"settings";a:1:{s:11:"trim_length";i:600;}s:6:"module";s:4:"text";s:6:"weight";i:0;}}s:8:"required";b:0;s:11:"description";s:0:"";}',
+  'deleted' => '0',
+))
+->execute();
diff --git a/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml b/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml
index 2de9be576b602ba4a347921fcb9b21d15ac42943..8e5322dd72be6b8e4e0e1de00a44b186dc4271db 100644
--- a/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml
+++ b/web/modules/field_permissions/tests/modules/field_permissions_test/field_permissions_test.info.yml
@@ -5,7 +5,7 @@ package: Testing
 dependencies:
   - field_permissions:field_permissions
 
-# Information added by Drupal.org packaging script on 2020-08-28
-version: '8.x-1.1'
+# Information added by Drupal.org packaging script on 2022-07-27
+version: '8.x-1.2'
 project: 'field_permissions'
-datestamp: 1598646884
+datestamp: 1658941753
diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php
index d400780b79e6ef9b8f887d872ec4d4ffab23de37..7c89433bbe64d7c8b586243cb838d3287f0b26ae 100644
--- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php
+++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsCommentTest.php
@@ -15,7 +15,7 @@ class FieldPermissionsCommentTest extends FieldPermissionsTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = ['comment'];
+  protected static $modules = ['comment'];
 
   /**
    * Test comment subject.
@@ -34,7 +34,7 @@ class FieldPermissionsCommentTest extends FieldPermissionsTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     // Add comment permissions to authenticated user.
@@ -175,11 +175,11 @@ protected function setCommentFieldPermissions($perm, array $custom_permission, $
     $this->drupalGet($path);
     if ($perm === FieldPermissionTypeInterface::ACCESS_PUBLIC || $perm === FieldPermissionTypeInterface::ACCESS_PRIVATE) {
       $edit = ['type' => $perm];
-      $this->drupalPostForm(NULL, $edit, t('Save settings'));
+      $this->submitForm($edit, 'Save settings');
     }
     elseif ($perm === FieldPermissionTypeInterface::ACCESS_CUSTOM && !empty($custom_permission)) {
       $custom_permission['type'] = $perm;
-      $this->drupalPostForm(NULL, $custom_permission, t('Save settings'));
+      $this->submitForm($custom_permission, 'Save settings');
     }
   }
 
@@ -196,7 +196,7 @@ protected function checkBaseCommentFieldFunctionality() {
     // Add comment to node.
     $edit['subject[0][value]'] = $this->commentSubject;
     $edit[$this->fieldName . '[0][value]'] = $this->fieldText;
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $this->node->id());
     $this->assertSession()->assertEscaped($this->fieldText);
     $this->assertSession()->assertEscaped($this->commentSubject);
@@ -211,7 +211,7 @@ protected function checkBaseCommentFieldFunctionality() {
     $edit = [];
     $edit['subject[0][value]'] = 'Limit User comment subject';
     $edit[$this->fieldName . '[0][value]'] = 'Limit User comment body';
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet('node/' . $this->node->id());
     // Test visibility second comment by limituser..
     $this->assertSession()->pageTextContains('Limit User comment subject');
diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php
index e56b9483a52f11979991454ef9bcf2929ccbdf24..3c9cf1b4a8b16fba7fb6ff4fae4d3d0d2e5db686 100644
--- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php
+++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsNodeTest.php
@@ -15,7 +15,7 @@ class FieldPermissionsNodeTest extends FieldPermissionsTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     // Grant the web user permission to administer node fields.
@@ -56,11 +56,11 @@ protected function setNodeFieldPermissions($perm, array $custom_permission = [])
     $this->drupalGet('admin/structure/types/manage/article/fields/node.article.body');
     if ($perm === FieldPermissionTypeInterface::ACCESS_PUBLIC || $perm === FieldPermissionTypeInterface::ACCESS_PRIVATE) {
       $edit = ['type' => $perm];
-      $this->drupalPostForm(NULL, $edit, t('Save settings'));
+      $this->submitForm($edit, 'Save settings');
     }
     elseif ($perm === FieldPermissionTypeInterface::ACCESS_CUSTOM && !empty($custom_permission)) {
       $custom_permission['type'] = $perm;
-      $this->drupalPostForm(NULL, $custom_permission, t('Save settings'));
+      $this->submitForm($custom_permission, 'Save settings');
     }
     if ($current_user) {
       $this->drupalLogin($current_user);
@@ -87,7 +87,7 @@ protected function addNodeUi() {
     $node_name = $this->randomMachineName();
     $edit['body[0][value]'] = $this->randomString();
     $edit['title[0][value]'] = $node_name;
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->assertSession()->pageTextContains(t('Article @name has been created.', ['@name' => $node_name]));
   }
 
diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php
index 1e185430d0740b72e01cb6a8fd3fa9efe0750ce5..72d083d8292f2217e9a4cb6eea698af3007942d5 100644
--- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php
+++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsTestBase.php
@@ -76,7 +76,7 @@ abstract class FieldPermissionsTestBase extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'node',
     'field',
     'field_ui',
@@ -92,7 +92,7 @@ abstract class FieldPermissionsTestBase extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     // Create node type.
diff --git a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php
index c866e6d83ae406768f555aa7cfd67b5f379028da..a09df886db470a544b86aae317c82ff9c3b4ea2e 100644
--- a/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php
+++ b/web/modules/field_permissions/tests/src/Functional/FieldPermissionsUserTest.php
@@ -24,7 +24,7 @@ class FieldPermissionsUserTest extends FieldPermissionsTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
     $this->fieldName = mb_strtolower($this->randomMachineName());
     // Remove the '@' symbol so it isn't converted to an email link.
@@ -105,7 +105,7 @@ protected function checkUserFieldEdit(UserInterface $account) {
     $this->assertSession()->pageTextContains('Textfield');
     $edit = [];
     $edit[$this->fieldName . '[0][value]'] = $this->fieldText;
-    $this->drupalPostForm(NULL, $edit, t('Save'));
+    $this->submitForm($edit, 'Save');
     $this->drupalGet($account->toUrl());
     $this->assertSession()->assertEscaped($this->fieldText);
   }
@@ -170,11 +170,11 @@ private function setUserFieldPermission($perm, array $custom_permission = []) {
     $this->drupalGet('admin/config/people/accounts/fields/user.user.' . $this->fieldName);
     if ($perm === FieldPermissionTypeInterface::ACCESS_PUBLIC || $perm === FieldPermissionTypeInterface::ACCESS_PRIVATE) {
       $edit = ['type' => $perm];
-      $this->drupalPostForm(NULL, $edit, t('Save settings'));
+      $this->submitForm($edit, 'Save settings');
     }
     elseif ($perm === FieldPermissionTypeInterface::ACCESS_CUSTOM && !empty($custom_permission)) {
       $custom_permission['type'] = $perm;
-      $this->drupalPostForm(NULL, $custom_permission, t('Save settings'));
+      $this->submitForm($custom_permission, 'Save settings');
     }
     if ($current_user) {
       $this->drupalLogin($current_user);
diff --git a/web/modules/field_permissions/tests/src/Functional/FieldReportTest.php b/web/modules/field_permissions/tests/src/Functional/FieldReportTest.php
index 75517eefdad93dd5daa0265fe5f8a2f64233c977..891c2ffa13dbde3c0aa66332f264d465a01ccc5f 100644
--- a/web/modules/field_permissions/tests/src/Functional/FieldReportTest.php
+++ b/web/modules/field_permissions/tests/src/Functional/FieldReportTest.php
@@ -19,7 +19,7 @@ class FieldReportTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'field_permissions',
     'entity_test',
     'field_ui',
@@ -41,7 +41,7 @@ class FieldReportTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     $admin = $this->drupalCreateUser([
@@ -100,7 +100,7 @@ public function testReportPage() {
       $role = $this->container->get('entity_type.manager')
         ->getStorage('user_role')
         ->load($role_id);
-      $role->grantPermission('view_field_test')->save();
+      $role->grantPermission('view field_test')->save();
     }
     $this->drupalGet(Url::fromRoute('field_permissions.reports'));
     $this->assertSession()->statusCodeEquals(200);
diff --git a/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php b/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php
index 1e7315b759f9392c6b337344b6a8e2ffa3eceb7a..fffb3e050ae0e5c518141f91dda440b46c4d7221 100644
--- a/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php
+++ b/web/modules/field_permissions/tests/src/Kernel/Plugin/FieldPermissionType/ManagerTest.php
@@ -21,7 +21,7 @@ class ManagerTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'entity_test',
     'field',
     'field_permissions',
@@ -47,7 +47,7 @@ class ManagerTest extends KernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     $this->installSchema('system', ['sequences']);
diff --git a/web/modules/field_permissions/tests/src/Kernel/ViewsFieldAccessTest.php b/web/modules/field_permissions/tests/src/Kernel/ViewsFieldAccessTest.php
index d503c34edfc489c246bff9a9a6d3e4f2bbb0411c..0e2b26fa9fa0126803dc167d7542ab58c2dc4439 100644
--- a/web/modules/field_permissions/tests/src/Kernel/ViewsFieldAccessTest.php
+++ b/web/modules/field_permissions/tests/src/Kernel/ViewsFieldAccessTest.php
@@ -56,7 +56,7 @@ class ViewsFieldAccessTest extends ViewsKernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $modules = [
+  protected static $modules = [
     'field_permissions',
     'entity_test',
     'text',
@@ -88,7 +88,7 @@ class ViewsFieldAccessTest extends ViewsKernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public function setUp($import_test_views = TRUE) {
+  public function setUp($import_test_views = TRUE):void {
     parent::setUp($import_test_views);
 
     $this->installEntitySchema('entity_test');
@@ -114,6 +114,7 @@ public function setUp($import_test_views = TRUE) {
     // revoke permissions as needed.
     $role_with_access = Role::create([
       'id' => 'with_access',
+      'label' => $this->randomString(),
       'permissions' => ['view test entity'],
     ]);
     $role_with_access->save();
@@ -121,6 +122,7 @@ public function setUp($import_test_views = TRUE) {
 
     $role_without_access = Role::create([
       'id' => 'without_access',
+      'label' => $this->randomString(),
       'permissions' => ['view test entity'],
     ]);
     $role_without_access->save();
@@ -224,7 +226,7 @@ protected function assertFieldAccess() {
     $this->setRawContent($renderer->renderRoot($build));
 
     $this->assertText($field_content);
-    $this->assertTrue(isset($executable->field[$field_name]));
+    $this->assertArrayHasKey($field_name, $executable->field);
 
     $account_switcher->switchTo($this->userWithoutAccess);
     $executable = Views::getView($view_id);
diff --git a/web/modules/field_permissions/tests/src/Kernel/migrate/FieldPermissionsMigrationTest.php b/web/modules/field_permissions/tests/src/Kernel/migrate/FieldPermissionsMigrationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..556fdf8fee16cbb9616e0ead64fbf0a2623fa2ba
--- /dev/null
+++ b/web/modules/field_permissions/tests/src/Kernel/migrate/FieldPermissionsMigrationTest.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\Tests\field_permissions\Kernel\migrate;
+
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
+
+/**
+ * Tests Field Permissions migration.
+ *
+ * @group field_permissions.
+ */
+class FieldPermissionsMigrationTest extends MigrateDrupal7TestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'field_permissions',
+    'node',
+    'text',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getFixtureFilePath() {
+    return implode(DIRECTORY_SEPARATOR, [
+      \Drupal::service('extension.list.module')->getPath('field_permissions'),
+      'tests',
+      'fixtures',
+      'drupal7.php',
+    ]);
+  }
+
+  /**
+   * Tests field_permissions migration.
+   */
+  public function testFieldPermissionsMigration() {
+    $this->executeMigrations(['d7_field']);
+    $storage_after_permission_set = FieldStorageConfig::loadByName('node', 'body');
+    $this->assertSame([
+      'field_permissions' => [
+        'permission_type' => 'custom',
+      ],
+    ], $storage_after_permission_set->get('third_party_settings'));
+    // When field_permissions is not set.
+    $storage_after_permission_not_set = FieldStorageConfig::loadByName('node', 'body1');
+    $this->assertSame([
+      'field_permissions' => [
+        'permission_type' => 'public',
+      ],
+    ], $storage_after_permission_not_set->get('third_party_settings'));
+  }
+
+}
diff --git a/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php b/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php
index ccab25ae8efd0cbf84610e9db739ee5d5ab75a03..a978698df61e4f90fc6aae0212f2a345bd44a542 100644
--- a/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php
+++ b/web/modules/field_permissions/tests/src/Unit/FieldPermissionsServiceTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\field_permissions\Unit;
 
+use Prophecy\PhpUnit\ProphecyTrait;
 use Drupal\comment\CommentManagerInterface;
 use Drupal\Core\DependencyInjection\Container;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -24,6 +25,7 @@
  */
 class FieldPermissionsServiceTest extends UnitTestCase {
 
+  use ProphecyTrait;
   /**
    * Mock entity type manager.
    *
@@ -48,7 +50,7 @@ class FieldPermissionsServiceTest extends UnitTestCase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
diff --git a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php
index 41b41e7ed20e92236453a5d3203718a450010faf..993ad1635c8385e097855f1fa96fb2b73bf1607c 100644
--- a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php
+++ b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/CustomAccessTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\field_permissions\Unit\Plugin\FieldPermissionType;
 
+use Prophecy\PhpUnit\ProphecyTrait;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\field\FieldStorageConfigInterface;
@@ -19,6 +20,7 @@
  */
 class CustomAccessTest extends UnitTestCase {
 
+  use ProphecyTrait;
   /**
    * The custom access plugin.
    *
@@ -29,7 +31,7 @@ class CustomAccessTest extends UnitTestCase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     $storage = $this->prophesize(FieldStorageConfigInterface::class);
diff --git a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php
index 3839f968730d7edb86c99744cd9664c1d7f0bfaf..5eaf1a97e4c627b1b21bb781132e13cb75cbec21 100644
--- a/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php
+++ b/web/modules/field_permissions/tests/src/Unit/Plugin/FieldPermissionType/PrivateAccessTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\field_permissions\Unit\Plugin\FieldPermissionType;
 
+use Prophecy\PhpUnit\ProphecyTrait;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\field\FieldStorageConfigInterface;
@@ -19,6 +20,7 @@
  */
 class PrivateAccessTest extends UnitTestCase {
 
+  use ProphecyTrait;
   /**
    * The private access plugin.
    *
@@ -29,7 +31,7 @@ class PrivateAccessTest extends UnitTestCase {
   /**
    * {@inheritdoc}
    */
-  public function setUp() {
+  public function setUp():void {
     parent::setUp();
 
     $storage = $this->prophesize(FieldStorageConfigInterface::class);
diff --git a/web/modules/google_tag/google_tag.info.yml b/web/modules/google_tag/google_tag.info.yml
index 9b15fbf6a8a9f3c86caa05d172259f525323f272..032639ce7ebf5943b7b88643583c308e7395e174 100644
--- a/web/modules/google_tag/google_tag.info.yml
+++ b/web/modules/google_tag/google_tag.info.yml
@@ -5,7 +5,7 @@ package: 'Statistics'
 core_version_requirement: ^8.8 || ^9
 configure: google_tag.settings_form
 
-# Information added by Drupal.org packaging script on 2020-06-05
-version: '8.x-1.4'
+# Information added by Drupal.org packaging script on 2022-03-29
+version: '8.x-1.5'
 project: 'google_tag'
-datestamp: 1591383266
+datestamp: 1648569368
diff --git a/web/modules/google_tag/google_tag.services.yml b/web/modules/google_tag/google_tag.services.yml
index b0b7d42701c9b0e195323b510a10d92807c512df..b5b5251962cc2d9172e0f53a980115e5fc58bc19 100644
--- a/web/modules/google_tag/google_tag.services.yml
+++ b/web/modules/google_tag/google_tag.services.yml
@@ -1,4 +1,4 @@
 services:
   google_tag.container_manager:
     class: Drupal\google_tag\Entity\ContainerManager
-    arguments: ['@entity_type.manager', '@module_handler', '@file_system', '@messenger', '@logger.factory']
+    arguments: ['@entity_type.manager', '@config.factory', '@file_system', '@cache.data', '@messenger', '@logger.factory']
diff --git a/web/modules/google_tag/src/Entity/Container.php b/web/modules/google_tag/src/Entity/Container.php
index 8b5f113674d81c7ac774175dea09379cb5bcdd38..5ab83755fb899feaa68f9bf250c9d71a5e4d3e4e 100644
--- a/web/modules/google_tag/src/Entity/Container.php
+++ b/web/modules/google_tag/src/Entity/Container.php
@@ -256,7 +256,6 @@ public function snippets() {
    */
   protected function scriptSnippet() {
     // Gather data.
-    $compact = \Drupal::config('google_tag.settings')->get('compact_snippet');
     $container_id = $this->variableClean('container_id');
     $data_layer = $this->variableClean('data_layer');
     $query = $this->environmentQuery();
@@ -264,7 +263,6 @@ protected function scriptSnippet() {
     // Build script snippet.
     $script = <<<EOS
 (function(w,d,s,l,i){
-
   w[l]=w[l]||[];
   w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});
   var f=d.getElementsByTagName(s)[0];
@@ -273,13 +271,9 @@ protected function scriptSnippet() {
   j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl+'$query';
   j.async=true;
   f.parentNode.insertBefore(j,f);
-
 })(window,document,'script','$data_layer','$container_id');
 EOS;
-    if ($compact) {
-      $script = str_replace(["\n", '  '], '', $script);
-    }
-    return $script;
+    return $this->compactSnippet($script);
   }
 
   /**
@@ -290,7 +284,6 @@ protected function scriptSnippet() {
    */
   protected function noscriptSnippet() {
     // Gather data.
-    $compact = \Drupal::config('google_tag.settings')->get('compact_snippet');
     $container_id = $this->variableClean('container_id');
     $query = $this->environmentQuery();
 
@@ -299,10 +292,7 @@ protected function noscriptSnippet() {
 <noscript aria-hidden="true"><iframe src="https://www.googletagmanager.com/ns.html?id=$container_id$query"
  height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
 EOS;
-    if ($compact) {
-      $noscript = str_replace("\n", '', $noscript);
-    }
-    return $noscript;
+    return $this->compactSnippet($noscript, ["\n"]);
   }
 
   /**
@@ -333,8 +323,14 @@ protected function dataLayerSnippet() {
 
     if ($classes) {
       // Build data layer snippet.
-      $script = "var $data_layer = [" . json_encode($classes) . '];';
-      return $script;
+      $classes = json_encode($classes);
+      $script = <<<EOS
+(function(w,l){
+  w[l]=w[l]||[];
+  w[l].push($classes);
+})(window,'$data_layer');
+EOS;
+      return $this->compactSnippet($script);
     }
   }
 
@@ -370,6 +366,22 @@ public function variableClean($variable) {
     return trim(json_encode($this->get($variable)), '"');
   }
 
+  /**
+   * Returns the compacted snippet.
+   *
+   * @param string $snippet
+   *   The JavaScript snippet.
+   * @param array $search
+   *   The array of strings to replace with blank.
+   *
+   * @return string
+   *   The compacted snippet.
+   */
+  protected function compactSnippet($snippet, array $search = ["\n", '  ']) {
+    $compact = \Drupal::config('google_tag.settings')->get('compact_snippet');
+    return $compact ? str_replace($search, '', $snippet) : $snippet;
+  }
+
   /**
    * Determines whether to insert the snippet on the response.
    *
@@ -517,6 +529,19 @@ public function snippetURI($type) {
     return $this->snippetDirectory() . "/google_tag.$type.js";
   }
 
+  /**
+   * Returns the snippet cache ID for a snippet type.
+   *
+   * @param string $type
+   *   The snippet type.
+   *
+   * @return string
+   *   The snippet cache ID.
+   */
+  public function snippetCid($type) {
+    return "google_tag:$type:{$this->id()}";
+  }
+
   /**
    * Returns tag array for the snippet type.
    *
@@ -530,7 +555,14 @@ public function snippetURI($type) {
    */
   public function fileTag($type, $weight) {
     $uri = $this->snippetURI($type);
-    $url = file_url_transform_relative(file_create_url($uri));
+    // Remove the if-else when core_version_requirement >= 9.3 for this module.
+    if (\Drupal::hasService('file_url_generator')) {
+      $generator = \Drupal::service('file_url_generator');
+      $url = $generator->transformRelative($generator->generateAbsoluteString($uri));
+    }
+    else {
+      $url = file_url_transform_relative(file_create_url($uri));
+    }
     $query_string = \Drupal::state()->get('system.css_js_query_string') ?: '0';
     $attachment = [
       [
@@ -556,9 +588,7 @@ public function fileTag($type, $weight) {
    *   The tag array.
    */
   public function inlineTag($type, $weight) {
-    $uri = $this->snippetURI($type);
-    $url = \Drupal::service('file_system')->realpath($uri);
-    $contents = @file_get_contents($url);
+    $contents = $this->getSnippetContents($type);
     $attachment = [
       $contents ? [
         '#type' => 'html_tag',
@@ -594,9 +624,7 @@ public function noscriptTag($type = 'noscript', $weight = -10) {
     // As markup, core removes the 'style' attribute from the noscript snippet.
     // With the inline template type, core does not alter the noscript snippet.
 
-    $uri = $this->snippetURI($type);
-    $url = \Drupal::service('file_system')->realpath($uri);
-    $contents = @file_get_contents($url);
+    $contents = $this->getSnippetContents($type);
     $attachment = $contents ? [
       "google_tag_{$type}_tag__{$this->id()}" => [
         '#type' => 'inline_template',
@@ -607,6 +635,20 @@ public function noscriptTag($type = 'noscript', $weight = -10) {
     return $attachment;
   }
 
+  /**
+   * Returns the snippet contents for the snippet type.
+   *
+   * @param string $type
+   *   The snippet type.
+   *
+   * @return string
+   *   The snippet contents.
+   */
+  public function getSnippetContents($type) {
+    $cache = \Drupal::service('cache.data')->get($this->snippetCid($type));
+    return $cache ? $cache->data : '';
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/web/modules/google_tag/src/Entity/ContainerManager.php b/web/modules/google_tag/src/Entity/ContainerManager.php
index f266d285ccfd4d0a0142d308bec5c95b5411ccf0..80fe83e30d7f62edda633e555c3bc85ec6c7d610 100644
--- a/web/modules/google_tag/src/Entity/ContainerManager.php
+++ b/web/modules/google_tag/src/Entity/ContainerManager.php
@@ -3,9 +3,10 @@
 namespace Drupal\google_tag\Entity;
 
 // use Drupal\google_tag\Entity\ContainerManagerInterface;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 use Drupal\Core\Messenger\MessengerInterface;
@@ -26,11 +27,11 @@ class ContainerManager implements ContainerManagerInterface {
   protected $entityTypeManager;
 
   /**
-   * The module handler.
+   * The module configuration.
    *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
    */
-  protected $moduleHandler;
+  protected $config;
 
   /**
    * The file system.
@@ -39,6 +40,13 @@ class ContainerManager implements ContainerManagerInterface {
    */
   protected $fileSystem;
 
+  /**
+   * The cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cache;
+
   /**
    * The messenger.
    *
@@ -56,10 +64,11 @@ class ContainerManager implements ContainerManagerInterface {
   /**
    * {@inheritdoc}
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, FileSystemInterface $file_system, MessengerInterface $messenger, LoggerChannelFactoryInterface $logger_factory) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, FileSystemInterface $file_system, CacheBackendInterface $cache, MessengerInterface $messenger, LoggerChannelFactoryInterface $logger_factory) {
     $this->entityTypeManager = $entity_type_manager;
-    $this->moduleHandler = $module_handler;
+    $this->config = $config_factory->get('google_tag.settings');
     $this->fileSystem = $file_system;
+    $this->cache = $cache;
     $this->messenger = $messenger;
     $this->logger = $logger_factory->get('google_tag');
   }
@@ -68,6 +77,11 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Mod
    * {@inheritdoc}
    */
   public function createAssets(ConfigEntityInterface $container) {
+    $include_script_as_file = $this->config->get('include_file');
+    if (!$include_script_as_file) {
+      return $this->saveSnippets($container);
+    }
+
     $result = TRUE;
     $directory = $container->snippetDirectory();
     if (!is_dir($directory) || !_google_tag_is_writable($directory) || !_google_tag_is_executable($directory)) {
@@ -89,13 +103,22 @@ public function createAssets(ConfigEntityInterface $container) {
    * {@inheritdoc}
    */
   public function saveSnippets(ConfigEntityInterface $container) {
+    $include_script_as_file = $this->config->get('include_file');
     // Save the altered snippets after hook_google_tag_snippets_alter().
     $result = TRUE;
     $snippets = $container->snippets();
     foreach ($snippets as $type => $snippet) {
-      $uri = $container->snippetURI($type);
-      $path = $this->fileSystem->saveData($snippet, $uri, FileSystemInterface::EXISTS_REPLACE);
-      $result = !$path ? FALSE : $result;
+      if ($include_script_as_file && $type != 'noscript') {
+        // Write to file.
+        $uri = $container->snippetURI($type);
+        $path = $this->fileSystem->saveData($snippet, $uri, FileSystemInterface::EXISTS_REPLACE);
+        $result = !$path ? FALSE : $result;
+      }
+      else {
+        // Write to cache (noscript is always inline).
+        $cid = $container->snippetCid($type);
+        $this->cache->set($cid, $snippet, CacheBackendInterface::CACHE_PERMANENT, $container->getCacheTags());
+      }
     }
     $args = ['@count' => count($snippets), '%container' => $container->get('label')];
     if (!$result) {
@@ -161,7 +184,7 @@ public function getScriptAttachments(array &$attachments) {
       }
 
       static $weight = 9;
-      $include_script_as_file = \Drupal::config('google_tag.settings')->get('include_file');
+      $include_script_as_file = $this->config->get('include_file');
       $include_classes = $container->get('include_classes');
       // @todo Only want one data_layer snippet even with multiple containers.
       // If user sorts containers such that the first does not define the data
@@ -170,20 +193,9 @@ public function getScriptAttachments(array &$attachments) {
       $types = $include_classes ? ['data_layer', 'script'] : ['script'];
 
       // Add data_layer and script snippets to head (no longer by default).
-      if ($include_script_as_file) {
-        foreach ($types as $type) {
-          // @todo Will it matter if file is empty?
-          // @todo Check config for the whitelist and blacklist classes before adding.
-          $attachments['#attached']['html_head'][] = $container->fileTag($type, $weight++);
-        }
-      }
-      else {
-        foreach ($types as $type) {
-          // @see drupal_get_js() in 7.x core.
-          // For inline JavaScript to validate as XHTML, all JavaScript containing
-          // XHTML needs to be wrapped in CDATA.
-          $attachments['#attached']['html_head'][] = $container->inlineTag($type, $weight++);
-        }
+      $function = $include_script_as_file ? 'fileTag' : 'inlineTag';
+      foreach ($types as $type) {
+        $attachments['#attached']['html_head'][] = $container->$function($type, $weight++);
       }
     }
   }
@@ -224,8 +236,8 @@ public function createAllAssets() {
    * {@inheritdoc}
    */
   public function deleteAllAssets() {
-    if (\Drupal::config('google_tag.settings')->get('flush_snippets')) {
-      $directory = \Drupal::config('google_tag.settings')->get('uri');
+    if ($this->config->get('flush_snippets')) {
+      $directory = $this->config->get('uri');
       if (!empty($directory)) {
         // Remove any stale files (e.g. module update or machine name change).
         return $this->fileSystem->deleteRecursive($directory . '/google_tag');
@@ -252,7 +264,10 @@ public function deleteAssets(ConfigEntityInterface $container) {
     $include_classes = $container->get('include_classes');
     $types = $include_classes ? ['data_layer', 'script', 'noscript'] : ['script', 'noscript'];
     $directory = $container->snippetDirectory();
-    $result = $this->fileSystem->deleteRecursive($directory);
+    $result = TRUE;
+    if (!empty($directory) && is_dir($directory)) {
+      $result = $this->fileSystem->deleteRecursive($directory);
+    }
 
     $args = ['@count' => count($types), '%container' => $container->get('label')];
     if (!$result) {
@@ -275,14 +290,24 @@ public function deleteAssets(ConfigEntityInterface $container) {
    * {@inheritdoc}
    */
   public function findAssets(ConfigEntityInterface $container) {
+    $include_script_as_file = $this->config->get('include_file');
     $include_classes = $container->get('include_classes');
     $types = $include_classes ? ['data_layer', 'script', 'noscript'] : ['script', 'noscript'];
-    $result = TRUE;
+
     foreach ($types as $type) {
-      $uri = $container->snippetURI($type);
-      $result = !is_file($uri) ? FALSE : $result;
+      if ($include_script_as_file && $type != 'noscript') {
+        $uri = $container->snippetURI($type);
+        if (!is_file($uri)) {
+          return FALSE;
+        }
+      }
+      else {
+        if (!$cache = $this->cache->get($container->snippetCid($type))) {
+          return FALSE;
+        }
+      }
     }
-    return $result;
+    return TRUE;
   }
 
 }
diff --git a/web/modules/google_tag/src/Entity/ContainerManagerInterface.php b/web/modules/google_tag/src/Entity/ContainerManagerInterface.php
index 0dd0ec0b7d28ad3f3410ba8170efb979077dda33..6068cb992d0c0eda5cd55f1516fd85f052f488c5 100644
--- a/web/modules/google_tag/src/Entity/ContainerManagerInterface.php
+++ b/web/modules/google_tag/src/Entity/ContainerManagerInterface.php
@@ -2,9 +2,10 @@
 
 namespace Drupal\google_tag\Entity;
 
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\Logger\LoggerChannelFactoryInterface;
 use Drupal\Core\Messenger\MessengerInterface;
@@ -19,16 +20,18 @@ interface ContainerManagerInterface {
    *
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    *   The entity type manager.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
    * @param \Drupal\Core\File\FileSystemInterface $file_system
    *   The file system.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   The cache backend.
    * @param \Drupal\Core\Messenger\MessengerInterface $messenger
    *   The messenger.
    * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
    *   The logger factory.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, FileSystemInterface $file_system, MessengerInterface $messenger, LoggerChannelFactoryInterface $logger_factory);
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, FileSystemInterface $file_system, CacheBackendInterface $cache, MessengerInterface $messenger, LoggerChannelFactoryInterface $logger_factory);
 
   /**
    * Prepares directory for and saves snippet files for a container.
diff --git a/web/modules/google_tag/src/Form/ContainerForm.php b/web/modules/google_tag/src/Form/ContainerForm.php
index 5b5a5964661e1e0875c41fb80ee7057b16b3b6bb..446a42c8db2bf8665e07f539e8b1da643453a9c9 100644
--- a/web/modules/google_tag/src/Form/ContainerForm.php
+++ b/web/modules/google_tag/src/Form/ContainerForm.php
@@ -82,7 +82,7 @@ public function form(array $form, FormStateInterface $form_state) {
     // Build form elements.
     $form['label'] = [
       '#type' => 'textfield',
-      '#title' => 'Label',
+      '#title' => $this->t('Label'),
       '#default_value' => $container->label(),
       '#required' => TRUE,
     ];
@@ -160,7 +160,7 @@ public function generalFieldset(FormStateInterface &$form_state) {
 
     $fieldset['weight'] = [
       '#type' => 'weight',
-      '#title' => 'Weight',
+      '#title' => $this->t('Weight'),
       '#default_value' => $container->get('weight'),
     ];
 
diff --git a/web/modules/google_tag/tests/src/Functional/GTMMultipleTest.php b/web/modules/google_tag/tests/src/Functional/GTMMultipleTest.php
index ce03c5fcbf6c789138488017cd9f2521cc7c5164..6acd621b286d9582fdeaf90c9bef84460bb3deb5 100644
--- a/web/modules/google_tag/tests/src/Functional/GTMMultipleTest.php
+++ b/web/modules/google_tag/tests/src/Functional/GTMMultipleTest.php
@@ -49,13 +49,13 @@ protected function createData() {
   /**
    * {@inheritdoc}
    */
-  protected function checkSnippetFiles() {
+  protected function checkSnippetContents() {
     foreach ($this->variables as $key => $variables) {
       $message = "Start on container $key";
       parent::assertTrue(TRUE, $message);
       foreach ($this->types as $type) {
-        $url = "$this->basePath/google_tag/{$key}/google_tag.$type.js";
-        $contents = @file_get_contents($url);
+        $function = $type == 'noscript' ? 'getSnippetFromCache' : 'getSnippetFromFile';
+        $contents = $this->$function($key, $type);
         $function = "verify{$type}Snippet";
         $this->$function($contents, $this->variables[$key]);
       }
@@ -68,17 +68,48 @@ protected function checkSnippetFiles() {
   protected function checkPageResponse() {
     parent::checkPageResponse();
 
+    $include_file = $this->config('google_tag.settings')->get('include_file');
+    $include_file ? $this->checkPageResponseFile() : $this->checkPageResponseInline();
+  }
+
+  /**
+   * Inspect the page response (based on file source).
+   */
+  protected function checkPageResponseFile() {
     foreach ($this->variables as $key => $variables) {
       $this->drupalGet('');
       $message = "Start on container $key";
       parent::assertTrue(TRUE, $message);
       foreach ($this->types as $type) {
         $uri = "$this->basePath/google_tag/{$key}/google_tag.$type.js";
-        $url = file_url_transform_relative(file_create_url($uri));
+        // Remove the if-else when core_version_requirement >= 9.3 for this module.
+        if (\Drupal::hasService('file_url_generator')) {
+          $generator = \Drupal::service('file_url_generator');
+          $url = $generator->transformRelative($generator->generateAbsoluteString($uri));
+        }
+        else {
+          $url = file_url_transform_relative(file_create_url($uri));
+        }
         $function = "verify{$type}Tag";
         $this->$function($url, $this->variables[$key]);
       }
     }
   }
 
+  /**
+   * Inspect the page response (based on inline snippet).
+   */
+  protected function checkPageResponseInline() {
+    foreach ($this->variables as $key => $variables) {
+      $this->drupalGet('');
+      $message = "Start on container $key";
+      parent::assertTrue(TRUE, $message);
+      foreach ($this->types as $type) {
+        $contents = $this->getSnippetFromCache($key, $type);
+        $function = "verify{$type}TagInline";
+        $this->$function($this->variables[$key], $contents);
+      }
+    }
+  }
+
 }
diff --git a/web/modules/google_tag/tests/src/Functional/GTMTestBase.php b/web/modules/google_tag/tests/src/Functional/GTMTestBase.php
index 3743f9995f12d0c3ce446b53d202e8c22f79eb55..22e5a130934d4931264da9e39b8b3061cc8461ec 100644
--- a/web/modules/google_tag/tests/src/Functional/GTMTestBase.php
+++ b/web/modules/google_tag/tests/src/Functional/GTMTestBase.php
@@ -77,13 +77,16 @@ public function testModule() {
       // Create containers in code.
       $this->createData();
       $this->saveContainers();
-      $this->checkSnippetFiles();
+      $this->checkSnippetContents();
       $this->checkPageResponse();
       // Delete containers.
       $this->deleteContainers();
       // Create containers in user interface.
       $this->submitContainers();
-      $this->checkSnippetFiles();
+      $this->checkSnippetContents();
+      $this->checkPageResponse();
+      // Switch to inline snippets.
+      $this->modifySettings(FALSE);
       $this->checkPageResponse();
     }
     catch (\Exception $e) {
@@ -97,13 +100,17 @@ public function testModule() {
 
   /**
    * Modify settings for test purposes.
+   *
+   * @param bool $include_file
+   *   The include_file module setting.
    */
-  protected function modifySettings() {
+  protected function modifySettings($include_file = TRUE) {
     // Modify default settings.
     // These should propagate to each container created in test.
     $config = $this->config('google_tag.settings');
     $settings = $config->get();
     unset($settings['_core']);
+    $settings['include_file'] = $include_file;
     $settings['flush_snippets'] = 1;
     $settings['debug_output'] = 1;
     $settings['_default_container']['role_toggle'] = 'include listed';
@@ -183,7 +190,7 @@ protected function deleteContainers() {
 
     // Confirm no snippet files.
     $message = 'No snippet files found after delete';
-    parent::assertTrue(!is_dir($directory . '/google_tag'), $message);
+    parent::assertDirectoryNotExists($directory . '/google_tag', $message);
   }
 
   /**
@@ -194,7 +201,8 @@ protected function submitContainers() {
 
     foreach ($this->variables as $key => $variables) {
       $edit = (array) $variables;
-      $this->drupalPostForm('/admin/config/system/google-tag/add', $edit, 'Save');
+      $this->drupalGet('/admin/config/system/google-tag/add');
+      $this->submitForm($edit, 'Save');
 
       $text = 'Created @count snippet files for %container container based on configuration.';
       $args = ['@count' => 3, '%container' => $variables->label];
@@ -209,9 +217,26 @@ protected function submitContainers() {
   }
 
   /**
-   * Inspect the snippet files.
+   * Returns the snippet contents.
+   */
+  protected function getSnippetFromFile($key, $type) {
+    $url = "$this->basePath/google_tag/{$key}/google_tag.$type.js";
+    return @file_get_contents($url);
+  }
+
+  /**
+   * Returns the snippet contents.
+   */
+  protected function getSnippetFromCache($key, $type) {
+    $cid = "google_tag:$type:$key";
+    $cache = $this->container->get('cache.data')->get($cid);
+    return $cache ? $cache->data : '';
+  }
+
+  /**
+   * Inspect the snippet contents.
    */
-  protected function checkSnippetFiles() {
+  protected function checkSnippetContents() {
   }
 
   /**
@@ -232,19 +257,19 @@ protected function verifyScriptSnippet($contents, $variables) {
   }
 
   /**
-   * Verify the snippet file contents.
+   * Verify the snippet cache contents.
    */
   protected function verifyNoScriptSnippet($contents, $variables) {
     $status = strpos($contents, "id=$variables->container_id") !== FALSE;
-    $message = 'Found in noscript snippet file: container_id';
+    $message = 'Found in noscript snippet cache: container_id';
     parent::assertTrue($status, $message);
 
     $status = strpos($contents, "gtm_preview=$variables->environment_id") !== FALSE;
-    $message = 'Found in noscript snippet file: environment_id';
+    $message = 'Found in noscript snippet cache: environment_id';
     parent::assertTrue($status, $message);
 
     $status = strpos($contents, "gtm_auth=$variables->environment_token") !== FALSE;
-    $message = 'Found in noscript snippet file: environment_token';
+    $message = 'Found in noscript snippet cache: environment_token';
     parent::assertTrue($status, $message);
   }
 
@@ -279,7 +304,38 @@ protected function verifyScriptTag($realpath) {
   /**
    * Verify the tag in page response.
    */
-  protected function verifyNoScriptTag($realpath, $variables) {
+  protected function verifyScriptTagInline($variables, $cache) {
+    $id = $variables->container_id;
+    $xpath = "//script[contains(text(), '$id')]";
+    $elements = $this->xpath($xpath);
+    if (!is_array($elements) || count($elements) > 1) {
+      $message = 'Found only one script tag';
+      parent::assertFalse($status, $message);
+      return;
+    }
+
+    $contents = $elements[0]->getHtml();
+
+    $status = strpos($contents, "(window,document,'script','dataLayer','$id')") !== FALSE;
+    $message = 'Found in script tag: container_id and data data_layer';
+    parent::assertTrue($status, $message);
+
+    $status = strpos($contents, "gtm_preview=$variables->environment_id") !== FALSE;
+    $message = 'Found in script tag: environment_id';
+    parent::assertTrue($status, $message);
+
+    $status = strpos($contents, "gtm_auth=$variables->environment_token") !== FALSE;
+    $message = 'Found in script tag: environment_token';
+    parent::assertTrue($status, $message);
+
+    $message = 'Contents of script tag matches cache';
+    parent::assertTrue($contents == $cache, $message);
+  }
+
+  /**
+   * Verify the tag in page response.
+   */
+  protected function verifyNoScriptTag($realpath, $variables, $cache = '') {
     // The tags are sorted by weight.
     $index = isset($variables->weight) ? $variables->weight - 1 : 0;
     $xpath = '//noscript//iframe';
@@ -297,6 +353,18 @@ protected function verifyNoScriptTag($realpath, $variables) {
     $status = strpos($contents, "gtm_auth=$variables->environment_token") !== FALSE;
     $message = 'Found in noscript tag: environment_token';
     parent::assertTrue($status, $message);
+
+    if ($cache) {
+      $message = 'Contents of noscript tag matches cache';
+      parent::assertTrue(strpos($cache, $contents) !== FALSE, $message);
+    }
+  }
+
+  /**
+   * Verify the tag in page response.
+   */
+  protected function verifyNoScriptTagInline($variables, $cache) {
+    $this->verifyNoScriptTag('', $variables, $cache);
   }
 
 }
diff --git a/web/themes/bootstrap/bootstrap.info.yml b/web/themes/bootstrap/bootstrap.info.yml
index 3e73fc7b52508e21dac4cd70d71ba897f9551c78..e694d2052221cbe36e3597c5bca5ae3caf033e45 100644
--- a/web/themes/bootstrap/bootstrap.info.yml
+++ b/web/themes/bootstrap/bootstrap.info.yml
@@ -1,7 +1,6 @@
 type: theme
 base theme: false
-core: 8.x
-core_version_requirement: ^8 || ^9
+core_version_requirement: ^9.3 || ^10
 
 name: 'Bootstrap'
 description: 'Built to use Bootstrap, a sleek, intuitive, and powerful front-end framework for faster and easier web development.'
@@ -78,7 +77,7 @@ libraries-override:
       theme:
         css/node.preview.css: false
 
-# Information added by Drupal.org packaging script on 2020-06-14
-version: '8.x-3.23'
+# Information added by Drupal.org packaging script on 2022-06-10
+version: '8.x-3.25'
 project: 'bootstrap'
-datestamp: 1592175698
+datestamp: 1654873487
diff --git a/web/themes/bootstrap/bootstrap.libraries.yml b/web/themes/bootstrap/bootstrap.libraries.yml
index bb5440eb263ffc57a5223d3838f18965ea83ead1..6759f1c3814ae603fc101b255325e40bc5f41cbc 100644
--- a/web/themes/bootstrap/bootstrap.libraries.yml
+++ b/web/themes/bootstrap/bootstrap.libraries.yml
@@ -49,7 +49,7 @@ theme-settings:
     js/theme-settings.js: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
     - core/drupal
     - core/drupalSettings
 
@@ -101,6 +101,8 @@ drupal.autocomplete:
 drupal.dialog.ajax:
   js:
     js/misc/dialog.ajax.js: {}
+  dependencies:
+    - bootstrap/drupal.bootstrap
 
 drupal.form:
   js:
@@ -144,7 +146,7 @@ drupal.batch:
     - bootstrap/theme
     - core/drupal.ajax
     - core/drupal.progress
-    - core/jquery.once
+    - core/once
 
 drupal.filter:
   version: VERSION
@@ -153,14 +155,14 @@ drupal.filter:
   dependencies:
     - core/jquery
     - core/drupal
-    - core/jquery.once
+    - core/once
 
 drupal.text:
   js:
     js/text/text.js: {}
   dependencies:
     - core/jquery
-    - core/jquery.once
+    - core/once
     - core/drupal
 
 drupal.vertical-tabs:
@@ -168,5 +170,5 @@ drupal.vertical-tabs:
     js/misc/vertical-tabs.js: {}
   dependencies:
     - bootstrap/theme
-    - core/jquery.once
+    - core/once
     - core/drupal.form
diff --git a/web/themes/bootstrap/composer.json b/web/themes/bootstrap/composer.json
index a343af92320ecc320637374f1d7c0c047a269357..e7f08a2267d9fbdb95900d48174da3b8ffb2871c 100644
--- a/web/themes/bootstrap/composer.json
+++ b/web/themes/bootstrap/composer.json
@@ -19,7 +19,12 @@
       "name": "Fabiano Sant'Ana (wundo)",
       "homepage": "https://www.drupal.org/u/wundo",
       "role": "Co-maintainer"
-    }
+    },
+      {
+          "name": "Shelane French (shelane)",
+          "homepage": "https://www.drupal.org/u/shelane",
+          "role": "Co-maintainer"
+      }
   ],
   "support": {
     "docs": "https://drupal-bootstrap.org",
@@ -28,6 +33,6 @@
     "source": "https://git.drupalcode.org/project/bootstrap"
   },
   "require": {
-    "drupal/core": "^8 || ^9"
+    "drupal/core": "^9.3 || ^10"
   }
 }
diff --git a/web/themes/bootstrap/docs/Sub-Theming.md b/web/themes/bootstrap/docs/Sub-Theming.md
index ddf2185aa85cc5c39399da3b186b38f03dad72e4..bb38079f2930e2dcd0d2276e193c912fac6da1a6 100644
--- a/web/themes/bootstrap/docs/Sub-Theming.md
+++ b/web/themes/bootstrap/docs/Sub-Theming.md
@@ -25,8 +25,9 @@ you've done that, you can override CSS, templates, and theme processing.
 ## Using the Starterkit {#starterkit}
 
 The starterkit provided by this base-theme supplies the basic file structure on
-how to construct a proper Bootstrap based sub-theme for use with a [CDN Provider]
-(like [jsDelivr]) or for use with compiling [Bootstrap Framework] source files.
+how to construct a proper Bootstrap based sub-theme for use with a [CDN
+Provider] (like [jsDelivr]) or for use with compiling [Bootstrap Framework]
+source files.
 
 {.alert.alert-info} **NOTE:** Using a [CDN Provider] is the preferred method
 for loading the [Bootstrap Framework] CSS and JS on simpler sites that do not
@@ -56,15 +57,16 @@ will be superseded by any enabled [CDN Provider]; **do not use both**.
    to suite your needs. Make sure to rename the library extension name as
    well: `THEMENAME/framework`.
 3. Rename `./themes/THEMENAME/THEMENAME.libraries.yml`.
-   * (Optional) If you plan on using a local precompiler (i.e. [Less] or [Sass])
-     then uncomment the appropriate JavaScript entries inside this file to
-     enable the assets provided by the [Bootstrap Framework].
+   * (Optional) If you plan on using a local precompiler (i.e., [Less] or
+     [Sass]) then uncomment the appropriate JavaScript entries inside this file
+     to enable the assets provided by the [Bootstrap Framework].
 4. Rename `./themes/THEMENAME/THEMENAME.theme`.
 5. Rename `./themes/THEMENAME/config/schema/THEMENAME.schema.yml`
-   * Open this file and rename `- THEMENAME.settings:` and `'THEMETITLE settings'`
+   * Open this file and rename `- THEMENAME.settings:` and `'THEMETITLE
+   settings'`
 6. Rename `./themes/THEMENAME/config/install/THEMENAME.settings.yml`
-   * (Optional) If you plan on using a local precompiler (i.e. [Less] or [Sass])
-     then you will need to disable the `cdn_provider`
+   * (Optional) If you plan on using a local precompiler (i.e., [Less] or
+     [Sass]) then you will need to disable the `cdn_provider`
      [`cdn_provider` theme setting](<!-- @url theme_settings#cdn_provider -->).
      You can do this several different ways, but it's recommended that you
      uncomment the following line in this file so the [CDN Provider] is
@@ -94,16 +96,16 @@ developer, to figure out which solution is best for your particular needs.
 ### LESS {#less}
 - You must understand the basic concept of using the [Less] CSS pre-processor.
 - You must use a **[local Less compiler](https://www.google.com/search?q=less+compiler)**.
-- You must use the latest `3.x.x` version of [Bootstrap Framework LESS Source Files]
-  ending in the `.less` extension, not files ending in `.css`.
+- You must use the latest `3.x.x` version of [Bootstrap Framework LESS Source
+Files] ending in the `.less` extension, not files ending in `.css`.
 - You must download a copy of [Drupal Bootstrap Styles] and copy over the `less`
   folder located at `./drupal-bootstrap-styles/src/3.x.x/8.x-3.x/less`.
 
 ### SASS {#sass}
 - You must understand the basic concept of using the [Sass] CSS pre-processor.
 - You must use a **[local Sass compiler](https://www.google.com/search?q=sass+compiler)**.
-- You must use the latest `3.x.x` version of [Bootstrap Framework SASS Source Files]
-  ending in the `.scss` extension, not files ending in `.css`.
+- You must use the latest `3.x.x` version of [Bootstrap Framework SASS Source
+Files] ending in the `.scss` extension, not files ending in `.css`.
 - You must download a copy of [Drupal Bootstrap Styles] and copy over the `scss`
   folder located at `./drupal-bootstrap-styles/src/3.x.x/8.x-3.x/scss`.
 
@@ -140,12 +142,12 @@ set default` link next to your newly created sub-theme. Now that you've
 enabled your starterkit, please refer to the starterkit's documentation page
 to customize.
 
-[Drupal Bootstrap]: https://www.drupal.org/project/bootstrap
-[Drupal Bootstrap Styles]: https://github.com/unicorn-fail/drupal-bootstrap-styles
-[Bootstrap Framework]: https://getbootstrap.com/docs/3.4/
-[Bootstrap Framework LESS Source Files]: https://github.com/twbs/bootstrap/releases
-[Bootstrap Framework SASS Source Files]: https://github.com/twbs/bootstrap-sass
-[jsDelivr]: http://www.jsdelivr.com
-[Less]: http://lesscss.org
-[Sass]: http://sass-lang.com
-[CDN Provider]: <!-- @url plugins_provider -->
+[Drupal Bootstrap](https://www.drupal.org/project/bootstrap)
+[Drupal Bootstrap Styles](https://github.com/unicorn-fail/drupal-bootstrap-styles)
+[Bootstrap Framework](https://getbootstrap.com/docs/3.4/)
+[Bootstrap Framework LESS Source Files](https://github.com/twbs/bootstrap/releases)
+[Bootstrap Framework SASS Source Files](https://github.com/twbs/bootstrap-sass)
+[jsDelivr](http://www.jsdelivr.com)
+[Less](http://lesscss.org)
+[Sass](http://sass-lang.com)
+[CDN Provider](<!-- @url plugins_provider -->)
diff --git a/web/themes/bootstrap/js/misc/dialog.ajax.js b/web/themes/bootstrap/js/misc/dialog.ajax.js
index c0fceed28e6ab1e17ede972dcfbde155ebd1fbe7..d4045aed611f6475765c1057375a13c8717d7f41 100644
--- a/web/themes/bootstrap/js/misc/dialog.ajax.js
+++ b/web/themes/bootstrap/js/misc/dialog.ajax.js
@@ -44,7 +44,7 @@
    */
   Drupal.behaviors.dialog.ajaxUpdateButtons = function (reset) {
     if (this.ajaxCurrentButton && this.ajaxOriginalButton) {
-      this.ajaxCurrentButton.html(this.ajaxOriginalButton.html());
+      this.ajaxCurrentButton.html(this.ajaxOriginalButton.html() || this.ajaxOriginalButton.attr('value'));
       this.ajaxCurrentButton.prop('disabled', this.ajaxOriginalButton.prop('disabled'));
     }
     if (reset) {
@@ -89,7 +89,7 @@
         // Strip all HTML from the actual text value. This value is escaped.
         // It actual HTML value will be synced with the original button's HTML
         // below in the "create" method.
-        text: Bootstrap.stripHtml($originalButton),
+        text: Bootstrap.stripHtml($originalButton) || $originalButton.attr('value'),
         class: $originalButton.attr('class').replace('use-ajax-submit', ''),
         click: function click(e) {
           e.preventDefault();
diff --git a/web/themes/bootstrap/js/misc/tabledrag.js b/web/themes/bootstrap/js/misc/tabledrag.js
index ac41c8f6bd1b9e80f67334a266acc1512e668bb7..c2e36e38563236ca245c03aab6e6ca07567d9b2d 100644
--- a/web/themes/bootstrap/js/misc/tabledrag.js
+++ b/web/themes/bootstrap/js/misc/tabledrag.js
@@ -121,6 +121,11 @@
      */
     this.windowHeight = 0;
 
+    /**
+     * @type {?HTMLElement}
+     */
+    this.$toggleWeightButton = null;
+
     /**
      * Check this table's settings to see if there are parent relationships in
      * this table. For efficiency, large sections of code can be skipped if we
@@ -173,21 +178,24 @@
     $table.find('> tr.draggable, > tbody > tr.draggable').each(function () { self.makeDraggable(this); });
 
     // Add a link before the table for users to show or hide weight columns.
-    var $button = $(Drupal.theme('btn-sm', {
+    self.$toggleWeightButton = $(Drupal.theme('btn-sm', {
       'class': ['tabledrag-toggle-weight'],
+      'data-drupal-selector': ['tabledrag-toggle-weight'],
       title: Drupal.t('Re-order rows by numerical weight instead of dragging.'),
       'data-toggle': 'tooltip'
     }));
 
-    $button
+    self.$toggleWeightButton = $('[data-drupal-selector="tabledrag-toggle-weight"]');
+
+    self.$toggleWeightButton
       .on('click', $.proxy(function (e) {
         e.preventDefault();
         this.toggleColumns();
       }, this))
       .wrap('<div class="tabledrag-toggle-weight-wrapper"></div>')
-      .parent()
-    ;
-    $table.before($button);
+      .parent();
+
+    $table.before(self.$toggleWeightButton);
 
     // Initialize the specified columns (for example, weight or parent columns)
     // to show or hide according to user preference. This aids accessibility
diff --git a/web/themes/bootstrap/scripts/bootstrap.php b/web/themes/bootstrap/scripts/bootstrap.php
index fe98786afb255fe01a00421131122cfa1b25cc31..c5c99384442fc97b03bb6e7bbeca82ec08823934 100644
--- a/web/themes/bootstrap/scripts/bootstrap.php
+++ b/web/themes/bootstrap/scripts/bootstrap.php
@@ -13,11 +13,14 @@
   return \Drupal::service('kernel');
 }
 
+/**
+ *
+ */
 function _find_autoloader($dir) {
   if (file_exists($autoloadFile = $dir . '/autoload.php') || file_exists($autoloadFile = $dir . '/vendor/autoload.php')) {
-    return include_once($autoloadFile);
+    return include_once $autoloadFile;
   }
-  else if (empty($dir) || $dir === DIRECTORY_SEPARATOR) {
+  elseif (empty($dir) || $dir === DIRECTORY_SEPARATOR) {
     return FALSE;
   }
   return _find_autoloader(dirname($dir));
diff --git a/web/themes/bootstrap/src/Bootstrap.php b/web/themes/bootstrap/src/Bootstrap.php
index 7c683e31549f1e920bf76e5165c18f36d0f485d3..769773520c104148259e1c75f327726e21dd20c5 100644
--- a/web/themes/bootstrap/src/Bootstrap.php
+++ b/web/themes/bootstrap/src/Bootstrap.php
@@ -105,7 +105,7 @@ class Bootstrap {
    *
    * @todo Enable constant once PHP 5.5 is no longer supported.
    */
-//  const PROJECT_API_SEARCH_URL = self::PROJECT_DOCUMENTATION . '/api/bootstrap/' . self::PROJECT_BRANCH . '/search/@query';
+  // Const PROJECT_API_SEARCH_URL = self::PROJECT_DOCUMENTATION . '/api/bootstrap/' . self::PROJECT_BRANCH . '/search/@query';.
 
   /**
    * The Drupal Bootstrap project page.
@@ -234,13 +234,13 @@ public static function alter($function, &$data, &$context1 = NULL, &$context2 =
       $drupal_static_fast['form_managers'] = &drupal_static(__METHOD__ . '__formManagers', []);
     }
 
-    /* @var \Drupal\bootstrap\Plugin\AlterManager[] $alter_managers */
+    /** @var \Drupal\bootstrap\Plugin\AlterManager[] $alter_managers */
     $alter_managers = &$drupal_static_fast['alter_managers'];
     if (!isset($alter_managers[$theme_name])) {
       $alter_managers[$theme_name] = new AlterManager($theme);
     }
 
-    /* @var \Drupal\bootstrap\Plugin\FormManager[] $form_managers */
+    /** @var \Drupal\bootstrap\Plugin\FormManager[] $form_managers */
     $form_managers = &$drupal_static_fast['form_managers'];
     if (!isset($form_managers[$theme_name])) {
       $form_managers[$theme_name] = new FormManager($theme);
@@ -548,7 +548,7 @@ public static function cssClassFromString(&$value, $default = '') {
             break;
 
           case 'contains':
-            if (strpos(Unicode::strtolower($string), Unicode::strtolower($text)) !== FALSE) {
+            if (strpos(mb_strtolower($string), mb_strtolower($text)) !== FALSE) {
               return $class;
             }
             break;
@@ -602,7 +602,7 @@ public static function deprecated($caller = NULL, $show_message = NULL, Translat
     }
 
     if ($show_message || (!isset($show_message) && static::isAdmin() && !static::getTheme()->getSetting('suppress_deprecated_warnings', FALSE))) {
-      static::message($message, 'warning');
+      \Drupal::messenger()->addMessage($message, 'warning');
     }
 
     // Log message and accompanying backtrace.
@@ -900,7 +900,7 @@ public static function glyphiconFromString(&$value, array $default = []) {
             break;
 
           case 'contains':
-            if (strpos(Unicode::strtolower($string), Unicode::strtolower($text)) !== FALSE) {
+            if (strpos(mb_strtolower($string), mb_strtolower($text)) !== FALSE) {
               return self::glyphicon($icon, $default);
             }
             break;
@@ -1336,7 +1336,7 @@ public static function isFront() {
    *   supported:
    *   - 'status'
    *   - 'warning'
-   *   - 'error'
+   *   - 'error'.
    * @param bool $repeat
    *   (optional) If this is FALSE and the message is already set, then the
    *   message won't be repeated. Defaults to FALSE.
@@ -1383,7 +1383,7 @@ public static function preprocess(array &$variables, $hook, array $info) {
       $drupal_static_fast['theme_info'] = &drupal_static(__METHOD__ . '__themeInfo', []);
     }
 
-    /* @var \Drupal\bootstrap\Plugin\PreprocessManager[] $preprocess_managers */
+    /** @var \Drupal\bootstrap\Plugin\PreprocessManager[] $preprocess_managers */
     $preprocess_managers = &$drupal_static_fast['preprocess_managers'];
     if (!isset($preprocess_managers[$theme_name])) {
       $preprocess_managers[$theme_name] = new PreprocessManager($theme);
diff --git a/web/themes/bootstrap/src/Plugin/Alter/ThemeRegistry.php b/web/themes/bootstrap/src/Plugin/Alter/ThemeRegistry.php
index 36f64b50f4ce90657a85e45b088e7b70c0dde36b..9961519e59c6969b14ec6211c62abe807260e7d5 100644
--- a/web/themes/bootstrap/src/Plugin/Alter/ThemeRegistry.php
+++ b/web/themes/bootstrap/src/Plugin/Alter/ThemeRegistry.php
@@ -42,7 +42,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
     }
     $this->currentTheme = $configuration['theme'];
     parent::__construct(
-      \Drupal::service('app.root'),
+      \Drupal::root(),
       \Drupal::service('cache.default'),
       \Drupal::service('lock'),
       \Drupal::service('module_handler'),
diff --git a/web/themes/bootstrap/src/Plugin/Alter/ThemeSuggestions.php b/web/themes/bootstrap/src/Plugin/Alter/ThemeSuggestions.php
index db96e669956e99f7b4c84d442271dd9c3801aee4..50983cc983c8eb3c83fcf765caf013fefa3add19 100644
--- a/web/themes/bootstrap/src/Plugin/Alter/ThemeSuggestions.php
+++ b/web/themes/bootstrap/src/Plugin/Alter/ThemeSuggestions.php
@@ -4,7 +4,6 @@
 
 use Drupal\bootstrap\Bootstrap;
 use Drupal\bootstrap\Plugin\PluginBase;
-use Drupal\bootstrap\Utility\Unicode;
 use Drupal\bootstrap\Utility\Variables;
 use Drupal\Core\Entity\EntityInterface;
 
diff --git a/web/themes/bootstrap/src/Plugin/Preprocess/BootstrapDropdown.php b/web/themes/bootstrap/src/Plugin/Preprocess/BootstrapDropdown.php
index 532f348c28797e21eaa3e34c5a25ddbfdf50f2e8..cba2d20839aaacabd69e9b7ca48f761cffacf1f7 100644
--- a/web/themes/bootstrap/src/Plugin/Preprocess/BootstrapDropdown.php
+++ b/web/themes/bootstrap/src/Plugin/Preprocess/BootstrapDropdown.php
@@ -4,7 +4,6 @@
 
 use Drupal\bootstrap\Utility\Crypt;
 use Drupal\bootstrap\Utility\Element;
-use Drupal\bootstrap\Utility\Unicode;
 use Drupal\bootstrap\Utility\Variables;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\NestedArray;
@@ -50,8 +49,8 @@ protected function preprocessVariables(Variables $variables) {
    */
   protected function preprocessLinks(Variables $variables) {
     // Convert "dropbutton" theme suggestion variables.
-    if (Unicode::strpos($variables->theme_hook_original, 'links__dropbutton') !== FALSE && !empty($variables->links)) {
-      $operations = !!Unicode::strpos($variables->theme_hook_original, 'operations');
+    if (mb_strpos($variables->theme_hook_original, 'links__dropbutton') !== FALSE && !empty($variables->links)) {
+      $operations = !!mb_strpos($variables->theme_hook_original, 'operations');
 
       // Normal dropbutton links are not actually render arrays, convert them.
       foreach ($variables->links as &$element) {
diff --git a/web/themes/bootstrap/src/Plugin/Preprocess/Breadcrumb.php b/web/themes/bootstrap/src/Plugin/Preprocess/Breadcrumb.php
index bb4008077488158bd90ede474ae8d0e55e4ce006..511714f4388c27185f0d9a2f2b9a91e0bd58b640 100644
--- a/web/themes/bootstrap/src/Plugin/Preprocess/Breadcrumb.php
+++ b/web/themes/bootstrap/src/Plugin/Preprocess/Breadcrumb.php
@@ -52,7 +52,7 @@ public function preprocessVariables(Variables $variables) {
     }
 
     // Add cache context based on url.
-    $variables->addCacheContexts(['url']);
+    $variables->addCacheContexts(['route', 'url.path', 'languages']);
   }
 
 }
diff --git a/web/themes/bootstrap/src/Plugin/Preprocess/FileLink.php b/web/themes/bootstrap/src/Plugin/Preprocess/FileLink.php
index df0ba6e7627e79f61e38ea3b88b73b5f8e62720c..62af1fc8339b25834a9f7ad1f96e062bb7c5a792 100644
--- a/web/themes/bootstrap/src/Plugin/Preprocess/FileLink.php
+++ b/web/themes/bootstrap/src/Plugin/Preprocess/FileLink.php
@@ -27,7 +27,7 @@ public function preprocessVariables(Variables $variables) {
     $options = [];
 
     $file = ($variables['file'] instanceof File) ? $variables['file'] : File::load($variables['file']->fid);
-    $url = file_create_url($file->getFileUri());
+    $url = \Drupal::service('file_url_generator')->generateAbsoluteString($file->getFileUri());
 
     $file_size = $file->getSize();
     $mime_type = $file->getMimeType();
diff --git a/web/themes/bootstrap/src/Plugin/Preprocess/ForumList.php b/web/themes/bootstrap/src/Plugin/Preprocess/ForumList.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c9f172013fa30e1c4a9efae7b0b6e3aa942a9f4
--- /dev/null
+++ b/web/themes/bootstrap/src/Plugin/Preprocess/ForumList.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Drupal\bootstrap\Plugin\Preprocess;
+
+/**
+ * Pre-processes variables for the "forum_list" theme hook.
+ *
+ * @ingroup plugins_preprocess
+ *
+ * @BootstrapPreprocess("forum_list")
+ */
+class ForumList extends Table {}
diff --git a/web/themes/bootstrap/src/Plugin/Preprocess/Menu.php b/web/themes/bootstrap/src/Plugin/Preprocess/Menu.php
index f51b027a34ea7886593ec12eeec0859990692879..877d60ff35b46059b2b2fd0ee26d51216468914e 100644
--- a/web/themes/bootstrap/src/Plugin/Preprocess/Menu.php
+++ b/web/themes/bootstrap/src/Plugin/Preprocess/Menu.php
@@ -40,7 +40,7 @@ protected function convertAttributes(array &$items) {
         $wrapperAttributes->setAttributes($item['url']->getOption('wrapper_attributes') ?: []);
         $wrapperAttributes->setAttributes($item['url']->getOption('container_attributes') ?: []);
         $linkAttributes->setAttributes($item['url']->getOption('attributes') ?: []);
-        
+
         // If URL isn't a link, it's rendered as a <span> element. Add the
         // "navbar-text" class so it doesn't disrupt the navbar items.
         // @see https://www.drupal.org/project/bootstrap/issues/3053464
@@ -54,7 +54,7 @@ protected function convertAttributes(array &$items) {
       // around this, just rewrap attributes in core's native Attribute class.
       $item['attributes'] = new Attribute($wrapperAttributes->getArrayCopy());
       $item['link_attributes'] = new Attribute($linkAttributes->getArrayCopy());
-      if ($item['below']) {
+      if (!empty($item['below']) && is_array($item['below'])) {
         $this->convertAttributes($item['below']);
       }
     }
diff --git a/web/themes/bootstrap/src/Plugin/Prerender/PrerenderBase.php b/web/themes/bootstrap/src/Plugin/Prerender/PrerenderBase.php
index 1e368ac533f706c5e592056b649467144812a044..4299047d04bd7260bd1ace2564ef1865fa0c2294 100644
--- a/web/themes/bootstrap/src/Plugin/Prerender/PrerenderBase.php
+++ b/web/themes/bootstrap/src/Plugin/Prerender/PrerenderBase.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\bootstrap\Plugin\Prerender;
 
-use Drupal\bootstrap\BcSupport\TrustedCallbackInterface;
+use Drupal\Core\Security\TrustedCallbackInterface;
 use Drupal\bootstrap\Utility\Element;
 
 /**
diff --git a/web/themes/bootstrap/src/Plugin/PrerenderManager.php b/web/themes/bootstrap/src/Plugin/PrerenderManager.php
index f453d71205a2d7129a1a54f5f8b7e48776695f6e..890b0f9f86fb028ece33cc5cd8773201eef07489 100644
--- a/web/themes/bootstrap/src/Plugin/PrerenderManager.php
+++ b/web/themes/bootstrap/src/Plugin/PrerenderManager.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\bootstrap\Plugin;
 
-use Drupal\bootstrap\BcSupport\TrustedCallbackInterface;
+use Drupal\Core\Security\TrustedCallbackInterface;
 use Drupal\bootstrap\Theme;
 use Drupal\bootstrap\Utility\Element;
 
diff --git a/web/themes/bootstrap/src/Plugin/Provider/Broken.php b/web/themes/bootstrap/src/Plugin/Provider/Broken.php
index 6e22f0804b5496a4324cca84de48e05b7d07d105..833d5611d08c5094115e76759b0ac20c8c48e722 100644
--- a/web/themes/bootstrap/src/Plugin/Provider/Broken.php
+++ b/web/themes/bootstrap/src/Plugin/Provider/Broken.php
@@ -94,9 +94,7 @@ public function supportsVersions() {
   }
 
   /****************************************************************************
-   *
-   * Deprecated methods
-   *
+   * Deprecated methods.
    ***************************************************************************/
 
   /**
diff --git a/web/themes/bootstrap/src/Plugin/Provider/ProviderBase.php b/web/themes/bootstrap/src/Plugin/Provider/ProviderBase.php
index c9ca1041e7baa16486aa36bc231525491399de51..8c9425426aa5dd35f2f627699bf2f76bbf2058a8 100644
--- a/web/themes/bootstrap/src/Plugin/Provider/ProviderBase.php
+++ b/web/themes/bootstrap/src/Plugin/Provider/ProviderBase.php
@@ -586,9 +586,7 @@ public function trackCdnExceptions(callable $callable) {
   }
 
   /****************************************************************************
-   *
-   * Deprecated methods
-   *
+   * Deprecated methods.
    ***************************************************************************/
 
   /**
diff --git a/web/themes/bootstrap/src/Plugin/Provider/ProviderInterface.php b/web/themes/bootstrap/src/Plugin/Provider/ProviderInterface.php
index 10f52f08a158a7b34d189cd9fe152442336d1bcc..4a19861689674508537f3c08fd92375da27df39d 100644
--- a/web/themes/bootstrap/src/Plugin/Provider/ProviderInterface.php
+++ b/web/themes/bootstrap/src/Plugin/Provider/ProviderInterface.php
@@ -237,9 +237,7 @@ public function supportsVersions();
   public function trackCdnExceptions(callable $callable);
 
   /****************************************************************************
-   *
-   * Deprecated methods
-   *
+   * Deprecated methods.
    ***************************************************************************/
 
   /**
diff --git a/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProvider.php b/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProvider.php
index 7d0d213c87abc9e64cd87be5ab2be3761ecd4ac8..5ad58bb711d4f7e846ecb6f56ec594b763c1ea69 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProvider.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProvider.php
@@ -216,17 +216,14 @@ public static function validateFormElement(Element $form, FormStateInterface $fo
    * @todo Import functionality is deprecated, remove in a future release.
    */
   protected function importProviderData(Element $group, FormStateInterface $form_state) {
-    if ($form_state->getValue('clicked_button') === t('Save provider data')->render()) {
+    if ($form_state->getValue('clicked_button') === $this->t('Save provider data')->render()) {
       $provider_path = ProviderManager::FILE_PATH;
 
       // FILE_CREATE_DIRECTORY = 1 | FILE_MODIFY_PERMISSIONS = 2.
       $options = 1 | 2;
-      if ($fileSystem = Bootstrap::fileSystem('prepareDirectory')) {
+      if ($fileSystem = \Drupal::service('file_system')) {
         $fileSystem->prepareDirectory($provider_path, $options);
       }
-      else {
-        file_prepare_directory($provider_path, $options);
-      }
 
       $provider = $form_state->getValue('cdn_provider', $this->theme->getSetting('cdn_provider'));
       $file = "$provider_path/$provider.json";
@@ -234,20 +231,14 @@ protected function importProviderData(Element $group, FormStateInterface $form_s
       if ($import_data = $form_state->getValue('cdn_provider_import_data', FALSE)) {
         // FILE_EXISTS_REPLACE = 1.
         $replace = 1;
-        if ($fileSystem = Bootstrap::fileSystem('saveData')) {
+        if ($fileSystem = \Drupal::service('file_system')) {
           $fileSystem->saveData($import_data, $file, $replace);
         }
-        else {
-          file_unmanaged_save_data($import_data, $file, $replace);
-        }
       }
       elseif ($file && file_exists($file)) {
-        if ($fileSystem = Bootstrap::fileSystem('delete')) {
+        if ($fileSystem = \Drupal::service('file_system')) {
           $fileSystem->delete($file);
         }
-        else {
-          file_unmanaged_delete($file);
-        }
       }
 
       // Clear the cached definitions so they can get rebuilt.
@@ -289,8 +280,8 @@ protected function importProviderData(Element $group, FormStateInterface $form_s
 
       $group->import = [
         '#type' => 'details',
-        '#title' => t('Imported @title data', ['@title' => $provider->getLabel()]),
-        '#description' => t('The provider will attempt to parse the data entered here each time it is saved. If no data has been entered, any saved files associated with this provider will be removed and the provider will again attempt to request the API data normally through the following URL: <a href=":provider_api" target="_blank">:provider_api</a>.', [
+        '#title' => $this->t('Imported @title data', ['@title' => $provider->getLabel()]),
+        '#description' => $this->t('The provider will attempt to parse the data entered here each time it is saved. If no data has been entered, any saved files associated with this provider will be removed and the provider will again attempt to request the API data normally through the following URL: <a href=":provider_api" target="_blank">:provider_api</a>.', [
           ':provider_api' => $provider->getPluginDefinition()['api'],
         ]),
         '#weight' => 10,
@@ -304,7 +295,7 @@ protected function importProviderData(Element $group, FormStateInterface $form_s
 
       $group->import->submit = $this->setCdnProvidersAjax([
         '#type' => 'submit',
-        '#value' => t('Save provider data'),
+        '#value' => $this->t('Save provider data'),
         '#executes_submit_callback' => FALSE,
       ]);
     }
diff --git a/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProviderBase.php b/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProviderBase.php
index 94eda0ea92c30a8822687dafc6aa3679421d689c..3b7d703dcaa3092b332fc21ead7e7a846ac03dec 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProviderBase.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/Advanced/Cdn/CdnProviderBase.php
@@ -68,7 +68,7 @@ public function alterForm(array &$form, FormStateInterface $form_state, $form_id
   protected static function checkCdnExceptions(ProviderInterface $provider, $reset = TRUE) {
     $exceptions = $provider->getCdnExceptions($reset);
     if ($exceptions) {
-      Bootstrap::message(t('Unable to parse @provider data. <a href=":logs">Check the logs for more details.</a> If your issues are network related, consider using the "custom" CDN Provider instead to statically set the URLs that should be used.', [
+      \Drupal::messenger()->addMessage(t('Unable to parse @provider data. <a href=":logs">Check the logs for more details.</a> If your issues are network related, consider using the "custom" CDN Provider instead to statically set the URLs that should be used.', [
         ':logs' => Url::fromRoute('dblog.overview')->toString(),
         '@provider' => $provider->getLabel(),
       ]), 'error');
diff --git a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalAnimation.php b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalAnimation.php
index bf9f5901df51a7e752caa335e8705e86665eb1cb..6ac57029a21552cb15803219fa6ab21cd5f930e2 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalAnimation.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalAnimation.php
@@ -37,7 +37,7 @@ public function alterFormElement(Element $form, FormStateInterface $form_state,
       '#weight' => -1,
       '#attributes' => ['class' => ['alert', 'alert-info', 'alert-sm']],
       0 => [
-        '#markup' => t('<strong>Note:</strong> jQuery UI dialog options will be mapped to Bootstrap modal options whenever possible, however they always take precedent over any global Bootstrap modal options set here for compatibility reasons.'),
+        '#markup' => $this->t('<strong>Note:</strong> jQuery UI dialog options will be mapped to Bootstrap modal options whenever possible, however they always take precedent over any global Bootstrap modal options set here for compatibility reasons.'),
       ],
       '#states' => [
         'visible' => [
@@ -46,7 +46,7 @@ public function alterFormElement(Element $form, FormStateInterface $form_state,
         ],
       ],
     ];
-    $group->setProperty('description', t('These are global options. Each modal can independently override desired settings by appending the option name to <code>data-</code>. Example: <code>data-backdrop="false"</code>.'));
+    $group->setProperty('description', $this->t('These are global options. Each modal can independently override desired settings by appending the option name to <code>data-</code>. Example: <code>data-backdrop="false"</code>.'));
     $group->setProperty('states', [
       'visible' => [
         ':input[name="modal_enabled"]' => ['checked' => TRUE],
diff --git a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalEnabled.php b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalEnabled.php
index 57002e25b9d924dfca9715989b7c7c089846528f..516e8f6a16b9dd8fbb55002f269390ff89b8f25f 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalEnabled.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Modals/ModalEnabled.php
@@ -31,7 +31,7 @@ class ModalEnabled extends SettingBase {
   public function alterFormElement(Element $form, FormStateInterface $form_state, $form_id = NULL) {
     parent::alterFormElement($form, $form_state, $form_id);
     $group = $this->getGroupElement($form, $form_state);
-    $group->setProperty('description', t('Modals are streamlined, but flexible, dialog prompts with the minimum required functionality and smart defaults. See <a href=":url" target="_blank">Bootstrap Modals</a> for more documentation.', [
+    $group->setProperty('description', $this->t('Modals are streamlined, but flexible, dialog prompts with the minimum required functionality and smart defaults. See <a href=":url" target="_blank">Bootstrap Modals</a> for more documentation.', [
       ':url' => 'https://getbootstrap.com/docs/3.4/javascript/#modals',
     ]));
   }
diff --git a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverAnimation.php b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverAnimation.php
index 475d906872db82dc0b628ee32f3ed52faa26ced2..d8c1dd451ea62f6d60979d63ec1e501a280e939e 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverAnimation.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverAnimation.php
@@ -33,7 +33,7 @@ public function alterFormElement(Element $form, FormStateInterface $form_state,
     parent::alterFormElement($form, $form_state, $form_id);
 
     $group = $this->getGroupElement($form, $form_state);
-    $group->setProperty('description', t('These are global options. Each popover can independently override desired settings by appending the option name to <code>data-</code>. Example: <code>data-animation="false"</code>.'));
+    $group->setProperty('description', $this->t('These are global options. Each popover can independently override desired settings by appending the option name to <code>data-</code>. Example: <code>data-animation="false"</code>.'));
     $group->setProperty('states', [
       'visible' => [
         ':input[name="popover_enabled"]' => ['checked' => TRUE],
diff --git a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverEnabled.php b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverEnabled.php
index 186e66b2b0096ad8a44e9df3760977602a107645..29d35611605257cc4d052da4031109034905a76b 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverEnabled.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Popovers/PopoverEnabled.php
@@ -33,7 +33,7 @@ public function alterFormElement(Element $form, FormStateInterface $form_state,
     parent::alterFormElement($form, $form_state, $form_id);
 
     $group = $this->getGroupElement($form, $form_state);
-    $group->setProperty('description', t('Add small overlays of content, like those on the iPad, to any element for housing secondary information.'));
+    $group->setProperty('description', $this->t('Add small overlays of content, like those on the iPad, to any element for housing secondary information.'));
   }
 
   /**
diff --git a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipAnimation.php b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipAnimation.php
index ac4b1671924497dd26134f2e777df34e77ad90fd..bbf3dfc505b4c3ad35a2f44cda549ad331f5bf57 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipAnimation.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipAnimation.php
@@ -33,7 +33,7 @@ public function alterFormElement(Element $form, FormStateInterface $form_state,
     parent::alterFormElement($form, $form_state, $form_id);
 
     $group = $this->getGroupElement($form, $form_state);
-    $group->setProperty('description', t('These are global options. Each tooltip can independently override desired settings by appending the option name to <code>data-</code>. Example: <code>data-animation="false"</code>.'));
+    $group->setProperty('description', $this->t('These are global options. Each tooltip can independently override desired settings by appending the option name to <code>data-</code>. Example: <code>data-animation="false"</code>.'));
     $group->setProperty('states', [
       'visible' => [
         ':input[name="tooltip_enabled"]' => ['checked' => TRUE],
diff --git a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipEnabled.php b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipEnabled.php
index a0003397cf66be56354e79c928d3bb0e87bdcccc..a3b75732aac5bda34fc1aa9b5a94e546d689e417 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipEnabled.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/JavaScript/Tooltips/TooltipEnabled.php
@@ -33,7 +33,7 @@ public function alterFormElement(Element $form, FormStateInterface $form_state,
     parent::alterFormElement($form, $form_state, $form_id);
 
     $group = $this->getGroupElement($form, $form_state);
-    $group->setProperty('description', t('Inspired by the excellent jQuery.tipsy plugin written by Jason Frame; Tooltips are an updated version, which don\'t rely on images, use CSS3 for animations, and data-attributes for local title storage. See <a href=":url" target="_blank">Bootstrap tooltips</a> for more documentation.', [
+    $group->setProperty('description', $this->t('Inspired by the excellent jQuery.tipsy plugin written by Jason Frame; Tooltips are an updated version, which don\'t rely on images, use CSS3 for animations, and data-attributes for local title storage. See <a href=":url" target="_blank">Bootstrap tooltips</a> for more documentation.', [
       ':url' => 'https://getbootstrap.com/docs/3.4/javascript/#tooltips',
     ]));
   }
diff --git a/web/themes/bootstrap/src/Plugin/Setting/Schemas.php b/web/themes/bootstrap/src/Plugin/Setting/Schemas.php
index cbbc56e48e049a8c4b8c0e2ec0d048232f7278d5..69f8b797979dcfe94ffbf385a8c483579ce822c6 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/Schemas.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/Schemas.php
@@ -200,7 +200,7 @@ public static function batchFinished($success, array $results, $operations) {
         '#items' => $results['success'],
         '#context' => ['type' => 'success'],
       ]);
-      Bootstrap::message(new FormattableMarkup('@message' . $list->renderPlain(), [
+      \Drupal::messenger()->addMessage(new FormattableMarkup('@message' . $list->renderPlain(), [
         '@message' => t('Successfully completed the following theme updates:'),
       ]));
     }
@@ -212,7 +212,7 @@ public static function batchFinished($success, array $results, $operations) {
         '#items' => $results['errors'],
         '#context' => ['type' => 'errors'],
       ]);
-      Bootstrap::message(new FormattableMarkup('@message' . $list->renderPlain(), [
+      \Drupal::messenger()->addMessage(new FormattableMarkup('@message' . $list->renderPlain(), [
         '@message' => t('The following theme updates could not be completed:'),
       ]), 'error');
     }
diff --git a/web/themes/bootstrap/src/Plugin/Setting/SettingBase.php b/web/themes/bootstrap/src/Plugin/Setting/SettingBase.php
index 8860c487e7655546aa5bc62cfa7bb63bbdbde3e2..3a488027218357903f52f87fbe54fa97c956bb67 100644
--- a/web/themes/bootstrap/src/Plugin/Setting/SettingBase.php
+++ b/web/themes/bootstrap/src/Plugin/Setting/SettingBase.php
@@ -211,7 +211,7 @@ public function getSettingElement(Element $form, FormStateInterface $form_state)
       }
       if (!empty($links)) {
         $description .= '<br>';
-        $description .= t('See also:');
+        $description .= $this->t('See also:');
         $description .= ' ' . implode(', ', $links);
         $group->$plugin_id->setProperty('description', $description);
       }
diff --git a/web/themes/bootstrap/src/Theme.php b/web/themes/bootstrap/src/Theme.php
index 71358b016143740a7f3efac5af33476c206273ce..2b42588a93a8c84e01dffced399161fe35e9c2ef 100644
--- a/web/themes/bootstrap/src/Theme.php
+++ b/web/themes/bootstrap/src/Theme.php
@@ -351,12 +351,9 @@ public function fileScan($mask, $subdir = NULL, array $options = []) {
     $hash = Crypt::generateBase64HashIdentifier($options, [$mask, $path]);
 
     if (!$cache->has($hash)) {
-      if ($fileSystem = Bootstrap::fileSystem('scanDirectory')) {
+      if ($fileSystem = \Drupal::service('file_system')) {
         $files = $fileSystem->scanDirectory($path, $mask, $options);
       }
-      else {
-        $files = file_scan_directory($path, $mask, $options);
-      }
       $cache->set($hash, $files);
     }
     return $cache->get($hash, []);
@@ -667,7 +664,7 @@ public function includeOnce($file, $path = 'includes') {
     if (!isset($includes[$include])) {
       $includes[$include] = !!@include_once $include;
       if (!$includes[$include]) {
-        Bootstrap::message(t('Could not include file: @include', ['@include' => $include]), 'error');
+        \Drupal::messenger()->addMessage(t('Could not include file: @include', ['@include' => $include]), 'error');
       }
     }
     return $includes[$include];
@@ -774,9 +771,7 @@ public function subthemeOf($theme) {
   }
 
   /****************************************************************************
-   *
-   * Deprecated methods
-   *
+   * Deprecated methods.
    ***************************************************************************/
 
   /**
diff --git a/web/themes/bootstrap/src/ThemeSettings.php b/web/themes/bootstrap/src/ThemeSettings.php
index bee5249b19b702a0e9ef3f15aeaeac4023f7659e..64da9471c186b2e542b5f7374d9916d0e0167f3c 100644
--- a/web/themes/bootstrap/src/ThemeSettings.php
+++ b/web/themes/bootstrap/src/ThemeSettings.php
@@ -3,7 +3,6 @@
 namespace Drupal\bootstrap;
 
 use Drupal\bootstrap\Plugin\Setting\DeprecatedSettingInterface;
-use Drupal\bootstrap\Plugin\Setting\SettingInterface;
 use Drupal\Core\Theme\ThemeSettings as CoreThemeSettings;
 use Drupal\Component\Utility\DiffArray;
 use Drupal\Component\Utility\NestedArray;
@@ -246,6 +245,8 @@ public function getOriginal($key = '', $apply_overrides = TRUE) {
    */
   public function getThemeConfig(Theme $theme, $active_theme = FALSE) {
     $config = new CoreThemeSettings($theme->getName());
+    /** @var \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator */
+    $file_url_generator = \Drupal::service('file_url_generator');
 
     // Retrieve configured theme-specific settings, if any.
     try {
@@ -276,7 +277,7 @@ public function getThemeConfig(Theme $theme, $active_theme = FALSE) {
       $logo_url = FALSE;
       foreach (['svg', 'png', 'jpg'] as $type) {
         if (file_exists($theme->getPath() . "/logo.$type")) {
-          $logo_url = file_create_url($theme->getPath() . "/logo.$type");
+          $logo_url = $file_url_generator->generateString($theme->getPath() . "/logo.$type");
           break;
         }
       }
@@ -284,18 +285,21 @@ public function getThemeConfig(Theme $theme, $active_theme = FALSE) {
         $config->set('logo.url', $logo_url);
       }
       elseif (($logo_path = $config->get('logo.path')) && file_exists($logo_path)) {
-        $config->set('logo.url', file_create_url($logo_path));
+        $config->set('logo.url', $file_url_generator->generateString($logo_path));
       }
     }
 
     // Generate the path to the favicon.
     if ($config->get('features.favicon')) {
       $favicon_url = $theme->getPath() . '/favicon.ico';
-      if ($config->get('favicon.use_default') && file_exists($favicon_url)) {
-        $config->set('favicon.url', file_create_url($favicon_url));
+      if ($favicon_url && $config->get('favicon.use_default') && file_exists($favicon_url)) {
+        $config->set('favicon.url', $file_url_generator->generateString($favicon_url));
       }
-      elseif ($favicon_path = $config->get('favicon.path')) {
-        $config->set('favicon.url', file_create_url($favicon_path));
+      else {
+        $favicon_path = $config->get('favicon.path');
+        if (file_exists($favicon_path)) {
+          $config->set('favicon.url', $file_url_generator->generateString($favicon_path));
+        }
       }
     }
 
@@ -305,10 +309,14 @@ public function getThemeConfig(Theme $theme, $active_theme = FALSE) {
     // Retrieve a diff of settings that override the defaults.
     $diff = DiffArray::diffAssocRecursive($data, $this->defaults);
 
-    // Ensure core features are always present in the diff. The theme settings
-    // form will not work properly otherwise.
+    // Ensure core features and complex (array) settings are always present in
+    // the diff. The theme settings form will not work properly otherwise.
     // @todo Just rebuild the features section of the form?
-    foreach (['favicon', 'features', 'logo'] as $key) {
+    $core_settings = ['favicon', 'features', 'logo'];
+    $complex_settings = array_keys(array_filter($diff, 'is_array'));
+    $all_complex_settings = array_unique(array_merge($core_settings, $complex_settings));
+
+    foreach ($all_complex_settings as $key) {
       $arrays = [];
       $arrays[] = isset($this->defaults[$key]) ? $this->defaults[$key] : [];
       $arrays[] = isset($data[$key]) ? $data[$key] : [];
diff --git a/web/themes/bootstrap/src/Utility/ArrayObject.php b/web/themes/bootstrap/src/Utility/ArrayObject.php
index 5d646503f30d4f9b0b6455a279b87b208de9f917..11d39638eba4d2b3adadbb0f2964fb4bd4dd3476 100644
--- a/web/themes/bootstrap/src/Utility/ArrayObject.php
+++ b/web/themes/bootstrap/src/Utility/ArrayObject.php
@@ -166,6 +166,7 @@ public function bubbleRenderArray(array $build) {
    * @return int
    *   The count.
    */
+  #[\ReturnTypeWillChange]
   public function count() {
     return count($this->array);
   }
@@ -238,6 +239,7 @@ public function getCacheMaxAge() {
    * @return \ArrayIterator
    *   An array iterator.
    */
+  #[\ReturnTypeWillChange]
   public function getIterator() {
     return new \ArrayIterator($this->array);
   }
@@ -297,6 +299,7 @@ public function natsort() {
    * @return bool
    *   TRUE or FALSE
    */
+  #[\ReturnTypeWillChange]
   public function offsetExists($key) {
     return isset($this->array[$key]);
   }
@@ -312,6 +315,7 @@ public function offsetExists($key) {
    * @return mixed
    *   The value.
    */
+  #[\ReturnTypeWillChange]
   public function &offsetGet($key, $default = NULL) {
     if (!$this->offsetExists($key)) {
       $this->array[$key] = $default;
@@ -328,6 +332,7 @@ public function &offsetGet($key, $default = NULL) {
    * @param mixed $value
    *   A value.
    */
+  #[\ReturnTypeWillChange]
   public function offsetSet($key, $value) {
     $this->array[$key] = $value;
   }
@@ -338,6 +343,7 @@ public function offsetSet($key, $value) {
    * @param mixed $key
    *   A key.
    */
+  #[\ReturnTypeWillChange]
   public function offsetUnset($key) {
     if ($this->offsetExists($key)) {
       unset($this->array[$key]);
@@ -354,6 +360,15 @@ public function serialize() {
     return serialize(get_object_vars($this));
   }
 
+  /**
+   * Serialize an ArrayObject.
+   *
+   * @return array
+   */
+  public function __serialize() {
+    return get_object_vars($this);
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -397,4 +412,13 @@ public function unserialize($data) {
     $this->exchangeArray($data['array']);
   }
 
+  /**
+   * Unserialize an ArrayObject.
+   *
+   * @param array $data
+   */
+  public function __unserialize(array $data) {
+    $this->exchangeArray($data['array']);
+  }
+
 }
diff --git a/web/themes/bootstrap/src/Utility/Attributes.php b/web/themes/bootstrap/src/Utility/Attributes.php
index 6b1e35814e6c8bc12b6d1230d8183cb47f15235c..6edd048b97f3341905ffffbe57a4de8432b993a9 100644
--- a/web/themes/bootstrap/src/Utility/Attributes.php
+++ b/web/themes/bootstrap/src/Utility/Attributes.php
@@ -63,6 +63,11 @@ public function &getAttribute($name, $default = NULL) {
    */
   public function &getClasses() {
     $classes = &$this->offsetGet('class', []);
+    if(is_array($classes)) {
+      $classes = array_unique($classes);
+    } else {
+      $classes = array($classes);
+	  }
     $classes = array_unique($classes);
     return $classes;
   }
diff --git a/web/themes/bootstrap/src/Utility/Crypt.php b/web/themes/bootstrap/src/Utility/Crypt.php
index 54d0e4b9e3d41ebc239c5cc1bd42e4698a58f99b..70c7435a5a99d5108b3730033c4a8e3491e23533 100644
--- a/web/themes/bootstrap/src/Utility/Crypt.php
+++ b/web/themes/bootstrap/src/Utility/Crypt.php
@@ -8,7 +8,7 @@
 /**
  * Extends \Drupal\Component\Utility\Crypt.
  *
- * @ingroup utility
+ * @ingroup utility crypt functions.
  */
 class Crypt extends CoreCrypt {
 
@@ -165,10 +165,9 @@ public static function parseSriIntegrity($integrity) {
   }
 
   /****************************************************************************
-   *
-   * Deprecated methods
-   *
-   ***************************************************************************/
+   * Deprecated methods.
+   * ***************************************************************************.
+   */
 
   /**
    * Generates a unique hash name.
@@ -179,9 +178,9 @@ public static function parseSriIntegrity($integrity) {
    * @return string
    *   The generated hash identifier.
    *
-   * @deprecated since 8.x-3.18. Will be removed in a future release.
-   *
-   * @see \Drupal\bootstrap\Utility\Crypt::generateBase64HashIdentifier()
+   * @deprecated in 8.x-3.18 and is removed from project:5.0.0. Use
+   *   \Drupal\bootstrap\Utility\Crypt::generateBase64HashIdentifier() instead.
+   * @see
    */
   public static function generateHash() {
     Bootstrap::deprecated();
diff --git a/web/themes/bootstrap/src/Utility/Element.php b/web/themes/bootstrap/src/Utility/Element.php
index 06cb647ee27d6b7f7b4efec40595626aee9ff458..cd34d7f7f0bc99d007f3862be16b01dd3a898a8b 100644
--- a/web/themes/bootstrap/src/Utility/Element.php
+++ b/web/themes/bootstrap/src/Utility/Element.php
@@ -682,7 +682,7 @@ public function setError($message = '', FormStateInterface $form_state = NULL) {
       $form_state->setError($this->array, $message);
     }
     else {
-      Bootstrap::message($message, 'error');
+      \Drupal::messenger()->addMessage($message, 'error');
     }
     return $this;
   }
@@ -831,7 +831,7 @@ public function smartDescription(&$target_element = NULL, $input_only = TRUE, $l
       || $target->hasAttribute('data-toggle')
 
       // Ignore if the target element is #disabled.
-      || $target->hasProperty('disabled')
+      || ($target->hasProperty('disabled') && $target->getProperty('disabled') === TRUE)
 
       // Ignore if either the actual element or target element has an explicit
       // #smart_description property set to FALSE.
diff --git a/web/themes/bootstrap/src/Utility/Storage.php b/web/themes/bootstrap/src/Utility/Storage.php
index 36a54e1a0d08009f6dd877cb8f047651bee07c62..cce2f1cc48e72afa360e2a2b5fead35907c9de0e 100644
--- a/web/themes/bootstrap/src/Utility/Storage.php
+++ b/web/themes/bootstrap/src/Utility/Storage.php
@@ -104,6 +104,7 @@ public function changed() {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function current() {
     return current($this->data);
   }
@@ -160,6 +161,7 @@ public function isEmpty() {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function key() {
     return key($this->data);
   }
@@ -167,6 +169,7 @@ public function key() {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function next() {
     return next($this->data);
   }
@@ -182,6 +185,7 @@ public function rename($key, $new_key) {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function rewind() {
     return reset($this->data);
   }
@@ -243,6 +247,7 @@ public function setMultiple(array $data) {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function valid() {
     return key($this->data) !== NULL;
   }
diff --git a/web/themes/bootstrap/src/Utility/StorageItem.php b/web/themes/bootstrap/src/Utility/StorageItem.php
index f281669ad2621affe98705c0c8778b7ed91559ce..841fe4fea4d7b9fa58ee80478c0ae9a90bbb67c3 100644
--- a/web/themes/bootstrap/src/Utility/StorageItem.php
+++ b/web/themes/bootstrap/src/Utility/StorageItem.php
@@ -54,6 +54,7 @@ public function changed() {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function current() {
     return current($this->data);
   }
@@ -95,6 +96,7 @@ public function isEmpty() {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function key() {
     return key($this->data);
   }
@@ -102,6 +104,7 @@ public function key() {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function next() {
     return next($this->data);
   }
@@ -117,6 +120,7 @@ public function rename($key, $new_key) {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function rewind() {
     return reset($this->data);
   }
@@ -152,6 +156,7 @@ public function setMultiple(array $data) {
   /**
    * {@inheritdoc}
    */
+  #[\ReturnTypeWillChange]
   public function valid() {
     return key($this->data) !== NULL;
   }
diff --git a/web/themes/bootstrap/src/Utility/Unicode.php b/web/themes/bootstrap/src/Utility/Unicode.php
index b2ce0b93758f8e415b506c4b1956e6e6bc8af819..22d3b953db6d8924a86a527129a2507a8b6ca9dd 100644
--- a/web/themes/bootstrap/src/Utility/Unicode.php
+++ b/web/themes/bootstrap/src/Utility/Unicode.php
@@ -82,9 +82,9 @@ public static function convertCallback($callback, $array = FALSE) {
       $callback = implode('::', $callback);
     }
     if ($callback[0] === '\\') {
-      $callback = static::substr($callback, 1);
+      $callback = mb_substr($callback, 1);
     }
-    if ($array && static::strpos($callback, '::') !== FALSE) {
+    if ($array && mb_substr($callback, '::') !== FALSE) {
       $callback = explode('::', $callback);
     }
     return $callback;
@@ -288,7 +288,8 @@ public static function substr($text, $start, $length = NULL) {
       if ($start > 0) {
         // Count all the characters except continuation bytes from the start
         // until we have found $start characters or the end of the string.
-        $bytes = -1; $chars = -1;
+        $bytes = -1;
+        $chars = -1;
         while ($bytes < $strlen - 1 && $chars < $start) {
           $bytes++;
           $c = ord($text[$bytes]);
@@ -301,7 +302,8 @@ public static function substr($text, $start, $length = NULL) {
         // Count all the characters except continuation bytes from the end
         // until we have found abs($start) characters.
         $start = abs($start);
-        $bytes = $strlen; $chars = 0;
+        $bytes = $strlen;
+        $chars = 0;
         while ($bytes > 0 && $chars < $start) {
           $bytes--;
           $c = ord($text[$bytes]);
@@ -342,7 +344,8 @@ public static function substr($text, $start, $length = NULL) {
         // Count all the characters except continuation bytes from the end
         // until we have found abs($start) characters, then backtrace one byte.
         $length = abs($length);
-        $iend = $strlen; $chars = 0;
+        $iend = $strlen;
+        $chars = 0;
         while ($iend > 0 && $chars < $length) {
           $iend--;
           $c = ord($text[$iend]);
diff --git a/web/themes/bootstrap/templates/bootstrap/item-list--dropdown.html.twig b/web/themes/bootstrap/templates/bootstrap/item-list--dropdown.html.twig
index a9cee12ab03046f89389134f65ae44685a2f52ae..de30d3376f541a3db7d1fa8702fae6b73e54f29b 100644
--- a/web/themes/bootstrap/templates/bootstrap/item-list--dropdown.html.twig
+++ b/web/themes/bootstrap/templates/bootstrap/item-list--dropdown.html.twig
@@ -33,7 +33,7 @@
   {%- if items -%}
     <{{ list_type }}{{ attributes.addClass(classes) }} role="menu">
       {%- for item in items -%}
-        <li{{ item.attributes }}>{{ item.value }}</li>
+        <li{{ item.attributes }} role="menuitem">{{ item.value }}</li>
       {%- endfor -%}
     </{{ list_type }}>
   {%- else -%}
diff --git a/web/themes/bootstrap/templates/file/file-link.html.twig b/web/themes/bootstrap/templates/file/file-link.html.twig
index 54ae38b437ce5a089e6269c5e7e8970b423d7d9c..e5c87aae6ce22d8930174bc3a200656258b42f1f 100644
--- a/web/themes/bootstrap/templates/file/file-link.html.twig
+++ b/web/themes/bootstrap/templates/file/file-link.html.twig
@@ -15,7 +15,7 @@
  * @see \Drupal\bootstrap\Plugin\Preprocess\FileLink::preprocessVariables
  */
 #}
-{% spaceless %}
+{% apply spaceless %}
   {%
     set classes = [
       icon_only ? 'icon-only',
@@ -37,4 +37,4 @@
       {% endif %}
     {% endif %}
   </span>
-{% endspaceless %}
+{% endapply %}
diff --git a/web/themes/bootstrap/templates/forum/forum-list.html.twig b/web/themes/bootstrap/templates/forum/forum-list.html.twig
new file mode 100644
index 0000000000000000000000000000000000000000..6059f3d431784af0e45bb4b1dc4d9c95bb6aef03
--- /dev/null
+++ b/web/themes/bootstrap/templates/forum/forum-list.html.twig
@@ -0,0 +1,100 @@
+{#
+/**
+ * @file
+ * Default theme implementation to display a list of forums and containers.
+ *
+ * Available variables:
+ * - forums: A collection of forums and containers to display. It is keyed to
+ *   the numeric IDs of all child forums and containers. Each forum in forums
+ *   contains:
+ *   - is_container: A flag indicating if the forum can contain other
+ *     forums. Otherwise, the forum can only contain topics.
+ *   - depth: How deep the forum is in the current hierarchy.
+ *   - zebra: 'even' or 'odd', used for row class.
+ *   - icon_class: 'default' or 'new', used for forum icon class.
+ *   - icon_title: Text alternative for the forum icon.
+ *   - name: The name of the forum.
+ *   - link: The URL to link to this forum.
+ *   - description: The description field for the forum, containing:
+ *     - value: The descriptive text for the forum.
+ *   - new_topics: A flag indicating if the forum contains unread posts.
+ *   - new_url: A URL to the forum's unread posts.
+ *   - new_text: Text for the above URL, which tells how many new posts.
+ *   - old_topics: A count of posts that have already been read.
+ *   - num_posts: The total number of posts in the forum.
+ *   - last_reply: Text representing the last time a forum was posted or
+ *     commented in.
+ * - forum_id: Forum ID for the current forum. Parent to all items within the
+ *   forums array.
+ * - bordered: Flag indicating whether or not the table should be bordered.
+ * - condensed: Flag indicating whether or not the table should be condensed.
+ * - hover: Flag indicating whether or not table rows should be hoverable.
+ * - striped: Flag indicating whether or not table rows should be striped.
+ * - responsive: Flag indicating whether or not the table should be wrapped to
+ *   be responsive (using the Bootstrap Framework .table-responsive wrapper).
+ *
+ * @see template_preprocess_forum_list()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if responsive %}
+  <div class="table-responsive">
+{% endif %}
+{% set table_attributes = create_attribute() %}
+{%
+  set table_classes = [
+  'table',
+  bordered ? 'table-bordered',
+  condensed ? 'table-condensed',
+  hover ? 'table-hover',
+  striped ? 'table-striped',
+  sticky ? 'sticky-enabled',
+]
+%}
+<table{{ table_attributes.addClass(table_classes) }}>
+  <thead>
+    <tr>
+      <th>{{ 'Forum'|t }}</th>
+      <th>{{ 'Topics'|t }}</th>
+      <th>{{ 'Posts'|t }}</th>
+      <th>{{ 'Last post'|t }}</th>
+    </tr>
+  </thead>
+  <tbody>
+  {% for child_id, forum in forums %}
+    <tr>
+      <td{% if forum.is_container == true %} colspan="4"{% endif %}>
+        {#
+          Enclose the contents of this cell with X divs, where X is the
+          depth this forum resides at. This will allow us to use CSS
+          left-margin for indenting.
+        #}
+        {% if forum.depth > 0 %}{% for i in 1..forum.depth %}<div class="indent">{% endfor %}{% endif %}
+          <div title="{{ forum.icon_title }}">
+            <span class="visually-hidden">{{ forum.icon_title }}</span>
+          </div>
+          <div><a href="{{ forum.link }}">{{ forum.label }}</a></div>
+          {% if forum.description.value %}
+            <div>{{ forum.description.value }}</div>
+          {% endif %}
+        {% if forum.depth > 0 %}{% for i in 1..forum.depth %}</div>{% endfor %}{% endif %}
+      </td>
+      {% if forum.is_container == false %}
+        <td>
+          {{ forum.num_topics }}
+          {% if forum.new_topics == true %}
+            <br />
+            <a href="{{ forum.new_url }}">{{ forum.new_text }}</a>
+          {% endif %}
+        </td>
+        <td>{{ forum.num_posts }}</td>
+        <td>{{ forum.last_reply }}</td>
+      {% endif %}
+    </tr>
+  {% endfor %}
+  </tbody>
+</table>
+{% if responsive %}
+  </div>
+{% endif %}
diff --git a/web/themes/bootstrap/templates/input/input--button--split.html.twig b/web/themes/bootstrap/templates/input/input--button--split.html.twig
index c7d6f0107679bcee184c0bc174fbe0ef7091ebd1..dfef5f579dc255203d565827ab7e35d27cafd3e9 100644
--- a/web/themes/bootstrap/templates/input/input--button--split.html.twig
+++ b/web/themes/bootstrap/templates/input/input--button--split.html.twig
@@ -22,15 +22,15 @@
  * @see template_preprocess_input()
  */
 #}
-{% spaceless %}
-  {%
-    set classes = [
+
+  {% block input %}{% apply spaceless %}
+    {%
+      set classes = [
       'btn',
       type == 'submit' ? 'js-form-submit',
       icon and icon_position and not icon_only ? 'icon-' ~ icon_position,
     ]
-  %}
-  {% block input %}
+    %}
     {% if icon_only %}
       <button{{ attributes.addClass(classes, 'icon-only') }}>
         <span class="sr-only">{{ label }}</span>
@@ -54,5 +54,5 @@
       <span class="sr-only">{{ 'Toggle Dropdown'|t }}</span>
     </button>
     {{ children }}
-  {% endblock %}
-{% endspaceless %}
+  {% endapply %}{% endblock %}
+
diff --git a/web/themes/bootstrap/templates/input/input--button.html.twig b/web/themes/bootstrap/templates/input/input--button.html.twig
index 7166b1a56e4ed542ea8350c69752b3428a88bae9..2885226bfdf280359b217818668d2b5324d3c47c 100644
--- a/web/themes/bootstrap/templates/input/input--button.html.twig
+++ b/web/themes/bootstrap/templates/input/input--button.html.twig
@@ -22,15 +22,14 @@
  * @see template_preprocess_input()
  */
 #}
-{% spaceless %}
-  {%
-    set classes = [
+  {% block input %}{% apply spaceless %}
+    {%
+      set classes = [
       'btn',
       type == 'submit' ? 'js-form-submit',
       icon and icon_position and not icon_only ? 'icon-' ~ icon_position,
     ]
-  %}
-  {% block input %}
+    %}
     {% if icon and icon_only %}
       <button{{ attributes.addClass(classes, 'icon-only') }}>
         <span class="sr-only">{{ label }}</span>
@@ -44,5 +43,5 @@
       {% endif %}
     {% endif %}
     {{ children }}
-  {% endblock %}
-{% endspaceless %}
+  {% endapply %}{% endblock %}
+
diff --git a/web/themes/bootstrap/templates/input/input--form-control.html.twig b/web/themes/bootstrap/templates/input/input--form-control.html.twig
index 5694480c1396bf1f9de3e7e0d76be564a37685f7..a5b235d35cdc0e0f6bc4222121d38a29922067ef 100644
--- a/web/themes/bootstrap/templates/input/input--form-control.html.twig
+++ b/web/themes/bootstrap/templates/input/input--form-control.html.twig
@@ -20,13 +20,13 @@
  * @see template_preprocess_input()
  */
 #}
-{% spaceless %}
-  {%
-    set classes = [
+
+  {% block input %}{% apply spaceless %}
+    {%
+      set classes = [
       'form-control',
     ]
-  %}
-  {% block input %}
+    %}
     <input{{ attributes.addClass(classes) }} />
-  {% endblock %}
-{% endspaceless %}
+  {% endapply %}{% endblock %}
+
diff --git a/web/themes/bootstrap/templates/input/input.html.twig b/web/themes/bootstrap/templates/input/input.html.twig
index 662a6abc7e01a3108a836a4b087e8215edb7b854..7ecf9edf919023a2735f1af781155d2b37ea4528 100644
--- a/web/themes/bootstrap/templates/input/input.html.twig
+++ b/web/themes/bootstrap/templates/input/input.html.twig
@@ -19,7 +19,7 @@
  * @see template_preprocess_input()
  */
 #}
-{% spaceless %}
+{% apply spaceless %}
   {% if input_group %}
     <div class="input-group">
   {% endif %}
@@ -41,4 +41,4 @@
   {% endif %}
 
   {{ children }}
-{% endspaceless %}
+{% endapply %}
diff --git a/web/themes/bootstrap/templates/input/select.html.twig b/web/themes/bootstrap/templates/input/select.html.twig
index 8d75f0ef989ba633dfe3f1f7f5ddbe2f78be339d..99e14b3695f9ec6e6def4e3a1fb6c343bcd99143 100644
--- a/web/themes/bootstrap/templates/input/select.html.twig
+++ b/web/themes/bootstrap/templates/input/select.html.twig
@@ -15,7 +15,7 @@
  * @see template_preprocess_select()
  */
 #}
-{% spaceless %}
+{% apply spaceless %}
   {% if input_group %}
     <div class="input-group">
   {% endif %}
@@ -58,4 +58,4 @@
   {% if input_group %}
     </div>
   {% endif %}
-{% endspaceless %}
+{% endapply %}
diff --git a/web/themes/bootstrap/templates/system/page.html.twig b/web/themes/bootstrap/templates/system/page.html.twig
index 70f8c1d9f9fe4b836a2c3c9a45b93b5dbb27452e..3c362574bcee4120fdfdf9fbe79ef6930a33cdc6 100644
--- a/web/themes/bootstrap/templates/system/page.html.twig
+++ b/web/themes/bootstrap/templates/system/page.html.twig
@@ -70,7 +70,7 @@
         {{ page.navigation }}
         {# .btn-navbar is used as the toggle for collapsed navbar content #}
         {% if page.navigation_collapsible %}
-          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
             <span class="sr-only">{{ 'Toggle navigation'|t }}</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
diff --git a/web/themes/bootstrap/templates/system/pager.html.twig b/web/themes/bootstrap/templates/system/pager.html.twig
index 5e5bb287c354a5b7bf3aa2283f1f48bf851e932e..6a7258c78cd0aadfa0c23d259c9e4f1c07ccae29 100644
--- a/web/themes/bootstrap/templates/system/pager.html.twig
+++ b/web/themes/bootstrap/templates/system/pager.html.twig
@@ -56,6 +56,11 @@
         </li>
       {% endif %}
 
+      {# Add an ellipsis if there are further previous pages. #}
+      {% if ellipses.previous %}
+        <li class="page-item" role="presentation"><span class="page-link">&hellip;</span></li>
+      {% endif %}
+
       {# Now generate the actual pager piece. #}
       {% for key, item in items.pages %}
         <li class="pager__item{{ current == key ? ' is-active active' : '' }}">
@@ -73,6 +78,11 @@
         </li>
       {% endfor %}
 
+      {# Add an ellipsis if there are further next pages. #}
+      {% if ellipses.next %}
+        <li class="page-item" role="presentation"><span class="page-link">&hellip;</span></li>
+      {% endif %}
+
       {# Print next item if we are not on the last page. #}
       {% if items.next %}
         <li class="pager__item pager__item--next">